carps 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. data/COPYING +674 -0
  2. data/GEM_DESCRIPTION +10 -0
  3. data/History.txt +4 -0
  4. data/Manifest.txt +156 -0
  5. data/PostInstall.txt +20 -0
  6. data/README.rdoc +141 -0
  7. data/Rakefile +28 -0
  8. data/bin/carps +123 -0
  9. data/bin/carps_init +29 -0
  10. data/bin/carps_ipc_test +44 -0
  11. data/bin/carps_mod_saver_test +71 -0
  12. data/bin/carps_mod_test +62 -0
  13. data/config/website.yml +2 -0
  14. data/features/character_sheet.feature +40 -0
  15. data/features/crash.feature +15 -0
  16. data/features/crypt.feature +22 -0
  17. data/features/dice.feature +173 -0
  18. data/features/dm.feature +36 -0
  19. data/features/dmll.feature +51 -0
  20. data/features/edit.feature +10 -0
  21. data/features/email.feature +29 -0
  22. data/features/interface.feature +17 -0
  23. data/features/ipc.feature +10 -0
  24. data/features/mailbox.feature +33 -0
  25. data/features/mod.feature +31 -0
  26. data/features/parser.feature +9 -0
  27. data/features/persistent_protocol.feature +14 -0
  28. data/features/player.feature +22 -0
  29. data/features/player_turn.feature +29 -0
  30. data/features/random.feature +15 -0
  31. data/features/rule.feature +19 -0
  32. data/features/safety.feature +13 -0
  33. data/features/sessions.feature +16 -0
  34. data/features/start_dm.feature +18 -0
  35. data/features/start_player.feature +8 -0
  36. data/features/step_definitions/common_steps.rb +170 -0
  37. data/features/steps/character_sheet.rb +89 -0
  38. data/features/steps/crash.rb +27 -0
  39. data/features/steps/crypt.rb +166 -0
  40. data/features/steps/dice.rb +91 -0
  41. data/features/steps/dm.rb +147 -0
  42. data/features/steps/dmll.rb +47 -0
  43. data/features/steps/edit.rb +7 -0
  44. data/features/steps/email.rb +108 -0
  45. data/features/steps/general.rb +5 -0
  46. data/features/steps/interface.rb +64 -0
  47. data/features/steps/ipc.rb +22 -0
  48. data/features/steps/mailbox.rb +126 -0
  49. data/features/steps/mod.rb +25 -0
  50. data/features/steps/parser.rb +23 -0
  51. data/features/steps/persistent_protocol.rb +29 -0
  52. data/features/steps/player.rb +82 -0
  53. data/features/steps/player_turn.rb +56 -0
  54. data/features/steps/random.rb +47 -0
  55. data/features/steps/rule.rb +53 -0
  56. data/features/steps/safety.rb +17 -0
  57. data/features/steps/sessions.rb +37 -0
  58. data/features/steps/start_dm.rb +46 -0
  59. data/features/steps/start_player.rb +65 -0
  60. data/features/steps/timeout.rb +32 -0
  61. data/features/steps/type_verification.rb +36 -0
  62. data/features/steps/wizard.rb +123 -0
  63. data/features/support/common.rb +29 -0
  64. data/features/support/env.rb +14 -0
  65. data/features/support/matchers.rb +11 -0
  66. data/features/timeout.feature +11 -0
  67. data/features/type_verification.feature +48 -0
  68. data/features/wizard.feature +50 -0
  69. data/lib/carps/crypt/accept_handshake.rb +40 -0
  70. data/lib/carps/crypt/default_messages.rb +29 -0
  71. data/lib/carps/crypt/handshake.rb +41 -0
  72. data/lib/carps/crypt/mailbox.rb +265 -0
  73. data/lib/carps/crypt/mailer.rb +220 -0
  74. data/lib/carps/crypt/peer.rb +123 -0
  75. data/lib/carps/crypt/public_key.rb +60 -0
  76. data/lib/carps/crypt.rb +23 -0
  77. data/lib/carps/email/config.rb +122 -0
  78. data/lib/carps/email/imap.rb +156 -0
  79. data/lib/carps/email/smtp.rb +119 -0
  80. data/lib/carps/email/string.rb +30 -0
  81. data/lib/carps/email.rb +21 -0
  82. data/lib/carps/mod/action.rb +36 -0
  83. data/lib/carps/mod/answers.rb +76 -0
  84. data/lib/carps/mod/client_turn.rb +88 -0
  85. data/lib/carps/mod/dice.rb +360 -0
  86. data/lib/carps/mod/dm/interface.rb +160 -0
  87. data/lib/carps/mod/dm/mod.rb +409 -0
  88. data/lib/carps/mod/dm/reporter.rb +112 -0
  89. data/lib/carps/mod/dm/resource.rb +88 -0
  90. data/lib/carps/mod/dm/room.rb +33 -0
  91. data/lib/carps/mod/interface.rb +73 -0
  92. data/lib/carps/mod/launch.rb +108 -0
  93. data/lib/carps/mod/mod.rb +52 -0
  94. data/lib/carps/mod/player/interface.rb +76 -0
  95. data/lib/carps/mod/player/mod.rb +109 -0
  96. data/lib/carps/mod/question.rb +63 -0
  97. data/lib/carps/mod/rule.rb +112 -0
  98. data/lib/carps/mod/sheet/character.rb +82 -0
  99. data/lib/carps/mod/sheet/editor.rb +97 -0
  100. data/lib/carps/mod/sheet/new_sheet.rb +71 -0
  101. data/lib/carps/mod/sheet/schema.rb +84 -0
  102. data/lib/carps/mod/sheet/type.rb +161 -0
  103. data/lib/carps/mod/sheet/verifier.rb +41 -0
  104. data/lib/carps/mod/status_report.rb +51 -0
  105. data/lib/carps/mod.rb +40 -0
  106. data/lib/carps/protocol/keyword.rb +104 -0
  107. data/lib/carps/protocol/message.rb +138 -0
  108. data/lib/carps/protocol.rb +19 -0
  109. data/lib/carps/service/client_parser.rb +34 -0
  110. data/lib/carps/service/dm/config.rb +76 -0
  111. data/lib/carps/service/dm/mailer.rb +70 -0
  112. data/lib/carps/service/dm/new_game.rb +101 -0
  113. data/lib/carps/service/dm/start.rb +47 -0
  114. data/lib/carps/service/game.rb +101 -0
  115. data/lib/carps/service/interface.rb +174 -0
  116. data/lib/carps/service/invite.rb +79 -0
  117. data/lib/carps/service/mod.rb +43 -0
  118. data/lib/carps/service/player/config.rb +78 -0
  119. data/lib/carps/service/player/mailer.rb +49 -0
  120. data/lib/carps/service/player/start.rb +60 -0
  121. data/lib/carps/service/server_parser.rb +33 -0
  122. data/lib/carps/service/session.rb +96 -0
  123. data/lib/carps/service/start/config.rb +71 -0
  124. data/lib/carps/service/start/interface.rb +101 -0
  125. data/lib/carps/service/start/mailer.rb +46 -0
  126. data/lib/carps/service.rb +35 -0
  127. data/lib/carps/test.rb +34 -0
  128. data/lib/carps/ui/colour.rb +28 -0
  129. data/lib/carps/ui/error.rb +39 -0
  130. data/lib/carps/ui/highlight.rb +32 -0
  131. data/lib/carps/ui/question.rb +63 -0
  132. data/lib/carps/ui/warn.rb +37 -0
  133. data/lib/carps/ui.rb +21 -0
  134. data/lib/carps/util/config.rb +162 -0
  135. data/lib/carps/util/editor.rb +147 -0
  136. data/lib/carps/util/error.rb +75 -0
  137. data/lib/carps/util/files.rb +48 -0
  138. data/lib/carps/util/init.rb +93 -0
  139. data/lib/carps/util/process.rb +150 -0
  140. data/lib/carps/util/timeout.rb +31 -0
  141. data/lib/carps/util/windows.rb +29 -0
  142. data/lib/carps/util.rb +24 -0
  143. data/lib/carps/wizard/dm.rb +41 -0
  144. data/lib/carps/wizard/player.rb +40 -0
  145. data/lib/carps/wizard/steps.rb +494 -0
  146. data/lib/carps/wizard/wizard.rb +126 -0
  147. data/lib/carps/wizard.rb +21 -0
  148. data/lib/carps.rb +45 -0
  149. data/permission +16 -0
  150. data/script/console +10 -0
  151. data/script/destroy +14 -0
  152. data/script/generate +14 -0
  153. data/tasks/readme_site.rake +28 -0
  154. data/test/test_carps.rb +11 -0
  155. data/test/test_helper.rb +3 -0
  156. data/website/index.html +271 -0
  157. metadata +304 -0
@@ -0,0 +1,170 @@
1
+ include CARPS
2
+
3
+ Given /^this project is active project folder/ do
4
+ @active_project_folder = File.expand_path(File.dirname(__FILE__) + "/../..")
5
+ end
6
+
7
+ Given /^env variable \$([\w_]+) set to "(.*)"/ do |env_var, value|
8
+ ENV[env_var] = value
9
+ end
10
+
11
+ Given /"(.*)" folder is deleted/ do |folder|
12
+ in_project_folder { FileUtils.rm_rf folder }
13
+ end
14
+
15
+ When /^I invoke "(.*)" generator with arguments "(.*)"$/ do |generator, arguments|
16
+ @stdout = StringIO.new
17
+ in_project_folder do
18
+ if Object.const_defined?("APP_ROOT")
19
+ APP_ROOT.replace(FileUtils.pwd)
20
+ else
21
+ APP_ROOT = FileUtils.pwd
22
+ end
23
+ run_generator(generator, arguments.split(' '), SOURCES, :stdout => @stdout)
24
+ end
25
+ File.open(File.join(@tmp_root, "generator.out"), "w") do |f|
26
+ @stdout.rewind
27
+ f << @stdout.read
28
+ end
29
+ end
30
+
31
+ When /^I run executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
32
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
33
+ in_project_folder do
34
+ system "#{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
35
+ end
36
+ end
37
+
38
+ When /^I run project executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
39
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
40
+ in_project_folder do
41
+ system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
42
+ end
43
+ end
44
+
45
+ When /^I run local executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
46
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
47
+ executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin", executable))
48
+ in_project_folder do
49
+ system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
50
+ end
51
+ end
52
+
53
+ When /^I invoke task "rake (.*)"/ do |task|
54
+ @stdout = File.expand_path(File.join(@tmp_root, "tests.out"))
55
+ in_project_folder do
56
+ system "rake #{task} --trace > #{@stdout} 2> #{@stdout}"
57
+ end
58
+ end
59
+
60
+ Then /^folder "(.*)" (is|is not) created/ do |folder, is|
61
+ in_project_folder do
62
+ File.exists?(folder).should(is == 'is' ? be_true : be_false)
63
+ end
64
+ end
65
+
66
+ Then /^file "(.*)" (is|is not) created/ do |file, is|
67
+ in_project_folder do
68
+ File.exists?(file).should(is == 'is' ? be_true : be_false)
69
+ end
70
+ end
71
+
72
+ Then /^file with name matching "(.*)" is created/ do |pattern|
73
+ in_project_folder do
74
+ Dir[pattern].should_not be_empty
75
+ end
76
+ end
77
+
78
+ Then /^file "(.*)" contents (does|does not) match \/(.*)\// do |file, does, regex|
79
+ in_project_folder do
80
+ actual_output = File.read(file)
81
+ (does == 'does') ?
82
+ actual_output.should(match(/#{regex}/)) :
83
+ actual_output.should_not(match(/#{regex}/))
84
+ end
85
+ end
86
+
87
+ Then /gem file "(.*)" and generated file "(.*)" should be the same/ do |gem_file, project_file|
88
+ File.exists?(gem_file).should be_true
89
+ File.exists?(project_file).should be_true
90
+ gem_file_contents = File.read(File.dirname(__FILE__) + "/../../#{gem_file}")
91
+ project_file_contents = File.read(File.join(@active_project_folder, project_file))
92
+ project_file_contents.should == gem_file_contents
93
+ end
94
+
95
+ Then /^(does|does not) invoke generator "(.*)"$/ do |does_invoke, generator|
96
+ actual_output = File.read(@stdout)
97
+ does_invoke == "does" ?
98
+ actual_output.should(match(/dependency\s+#{generator}/)) :
99
+ actual_output.should_not(match(/dependency\s+#{generator}/))
100
+ end
101
+
102
+ Then /help options "(.*)" and "(.*)" are displayed/ do |opt1, opt2|
103
+ actual_output = File.read(@stdout)
104
+ actual_output.should match(/#{opt1}/)
105
+ actual_output.should match(/#{opt2}/)
106
+ end
107
+
108
+ Then /^I should see "([^\"]*)"$/ do |text|
109
+ actual_output = File.read(@stdout)
110
+ actual_output.should contain(text)
111
+ end
112
+
113
+ Then /^I should see$/ do |text|
114
+ actual_output = File.read(@stdout)
115
+ actual_output.should contain(text)
116
+ end
117
+
118
+ Then /^I should not see$/ do |text|
119
+ actual_output = File.read(@stdout)
120
+ actual_output.should_not contain(text)
121
+ end
122
+
123
+ Then /^I should see exactly$/ do |text|
124
+ actual_output = File.read(@stdout)
125
+ actual_output.should == text
126
+ end
127
+
128
+ Then /^I should see all (\d+) tests pass/ do |expected_test_count|
129
+ expected = %r{^#{expected_test_count} tests, \d+ assertions, 0 failures, 0 errors}
130
+ actual_output = File.read(@stdout)
131
+ actual_output.should match(expected)
132
+ end
133
+
134
+ Then /^I should see all (\d+) examples pass/ do |expected_test_count|
135
+ expected = %r{^#{expected_test_count} examples?, 0 failures}
136
+ actual_output = File.read(@stdout)
137
+ actual_output.should match(expected)
138
+ end
139
+
140
+ Then /^yaml file "(.*)" contains (\{.*\})/ do |file, yaml|
141
+ in_project_folder do
142
+ yaml = eval yaml
143
+ YAML.load(File.read(file)).should == yaml
144
+ end
145
+ end
146
+
147
+ Then /^Rakefile can display tasks successfully/ do
148
+ @stdout = File.expand_path(File.join(@tmp_root, "rakefile.out"))
149
+ in_project_folder do
150
+ system "rake -T > #{@stdout} 2> #{@stdout}"
151
+ end
152
+ actual_output = File.read(@stdout)
153
+ actual_output.should match(/^rake\s+\w+\s+#\s.*/)
154
+ end
155
+
156
+ Then /^task "rake (.*)" is executed successfully/ do |task|
157
+ @stdout.should_not be_nil
158
+ actual_output = File.read(@stdout)
159
+ actual_output.should_not match(/^Don't know how to build task '#{task}'/)
160
+ actual_output.should_not match(/Error/i)
161
+ end
162
+
163
+ Then /^gem spec key "(.*)" contains \/(.*)\// do |key, regex|
164
+ in_project_folder do
165
+ gem_file = Dir["pkg/*.gem"].first
166
+ gem_spec = Gem::Specification.from_yaml(`gem spec #{gem_file}`)
167
+ spec_value = gem_spec.send(key.to_sym)
168
+ spec_value.to_s.should match(/#{regex}/)
169
+ end
170
+ end
@@ -0,0 +1,89 @@
1
+ require "carps/mod"
2
+
3
+ Given /^a character sheet schema$/ do
4
+ $schema =Sheet::Schema.new(
5
+ {"name" => "text",
6
+ "fruit" => "text",
7
+ "days old" => "integer"
8
+ })
9
+ end
10
+
11
+ Given /^a sheet editor$/ do
12
+ $editor = Sheet::Editor.new $schema, Sheet::UserVerifier.new
13
+ end
14
+
15
+ Then /^fill in the character sheet$/ do
16
+ $sheet = Sheet::Character.new
17
+ $editor.fill $sheet
18
+ end
19
+
20
+ Then /^edit the character sheet again$/ do
21
+ $editor.fill $sheet
22
+ end
23
+
24
+ When /^a valid sheet is provided$/ do
25
+ $sheet = Sheet::Character.new({"name" => "billy", "fruit" => "apple", "days old" => 11})
26
+ end
27
+
28
+ When /^an invalid sheet is provided$/ do
29
+ $sheet = Sheet::Character.new({"name" => "billy", "fruit" => "apple", "days old" => "many"})
30
+ end
31
+
32
+
33
+ Then /^do not accept the invalid sheet$/ do
34
+ valid = $editor.valid? $sheet
35
+ if valid
36
+ raise StandardError, "Passed invalid sheet"
37
+ end
38
+ end
39
+
40
+ When /^an parsable sheet is provided$/ do
41
+ stats = <<-END
42
+ Name: A
43
+ Biography:
44
+ The Readies: 0
45
+ The Old Grey Matter: 0
46
+ The Outer Crust: 0
47
+ Vim & Vigour: 0
48
+ Luck: 0
49
+ Chances: 0
50
+ Romantic Resistance: 0
51
+ Tolerance for Alcohol: 0
52
+ Conscience: 0
53
+ Etiquette: 0
54
+ Gentleman's Gentleman:
55
+ Sports Car:
56
+ Student of the Turf: false
57
+ Specialist Interest:
58
+ Connections:
59
+ Difficult Relation:
60
+ Good Sportsman:
61
+ END
62
+ $input = V.character_sheet stats
63
+ end
64
+
65
+ Then /^parse the sheet$/ do
66
+ sheet, blob = Sheet::NewSheet.parse $input
67
+ puts "Parsed:"
68
+ sheet.display
69
+ end
70
+
71
+ When /^an unparsable sheet is provided$/ do
72
+ $input = V.character_sheet "a: a: a"
73
+ end
74
+
75
+ Then /^do not parse the sheet$/ do
76
+ begin
77
+ Sheet::NewSheet.parse $input
78
+ raise Exception, "Parsed the sheet!"
79
+ rescue Expected => e
80
+ puts e.message
81
+ end
82
+ end
83
+
84
+ Then /^accept the valid sheet$/ do
85
+ valid = $editor.valid? $sheet
86
+ unless valid
87
+ raise StandardError, "Failed valid sheet."
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ require "carps/util"
2
+
3
+ Given /^a proc that won't crash$/ do
4
+ $proc = lambda {}
5
+ end
6
+
7
+ Then /^the crash reporter won't report a crash$/ do
8
+ CARPS::with_crash_report do
9
+ $proc.call
10
+ end
11
+ end
12
+
13
+ Given /^a proc that will crash$/ do
14
+ $proc = lambda do
15
+ raise StandardError, "This is a delibrate crash caused for testing purposes."
16
+ end
17
+ end
18
+
19
+ Then /^the crash reporter will report a crash$/ do
20
+ begin
21
+ CARPS::with_crash_report true do
22
+ $proc.call
23
+ end
24
+ rescue SystemExit => e
25
+ puts "Recovered from system exit."
26
+ end
27
+ end
@@ -0,0 +1,166 @@
1
+ # Test cryptography mechanism
2
+
3
+ require "carps/service"
4
+
5
+ require "carps/crypt/mailer"
6
+ require "carps/crypt/mailbox"
7
+ require "carps/crypt/default_messages"
8
+
9
+ require "carps/protocol/message"
10
+
11
+ require "carps/util/init"
12
+
13
+ require "carps/service/session"
14
+
15
+ require "fileutils"
16
+
17
+ require "thread"
18
+
19
+ class EvilMessage < Message
20
+
21
+ def emit
22
+ "EVIL"
23
+ end
24
+
25
+ def EvilMessage.parse blob
26
+ if blob.match(/EVIL/)
27
+ return [EvilMessage.new, ""]
28
+ else
29
+ raise Expected, "Could not parse evil message."
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ class TwistedMailbox < Mailbox
36
+ def forget person
37
+ @peers.delete person
38
+ end
39
+ end
40
+
41
+ class TwistedMailer < Mailer
42
+
43
+ # Expect someone else will begin the handshake
44
+ #
45
+ # British stereotype?
46
+ def expect_handshake
47
+ handshake = @mailbox.insecure_read Handshake
48
+ handle_handshake handshake
49
+ end
50
+
51
+ # Send an evil message. The recipent should drop this.
52
+ def evil to, message
53
+ text = message.emit
54
+ # Sign the message
55
+ digest = Digest::MD5.digest text
56
+ puts "sent digest (as part of an evil scheme): " + digest
57
+ new_key = OpenSSL::PKey::DSA.new 2048
58
+ sig = new_key.syssign digest
59
+ mail = (V.addr @addr) + (V.sig sig) + (V.session "") + text + K.end
60
+ @mailbox.send to, mail
61
+ puts "Message sent to " + to
62
+ end
63
+
64
+ def forget person
65
+ @mailbox.forget person
66
+ end
67
+ end
68
+
69
+ class TestSender
70
+
71
+ def send to, message
72
+ @receiver.receive message
73
+ end
74
+
75
+ def send_to receiver
76
+ @receiver = receiver
77
+ end
78
+
79
+ end
80
+
81
+ class TestReceiver
82
+
83
+ def receive message
84
+ @message = message
85
+ end
86
+
87
+ def connect
88
+ puts "Pretending to connect."
89
+ end
90
+
91
+ def read
92
+ until @message
93
+ sleep 1
94
+ end
95
+ message = @message
96
+ @message = nil
97
+ [message]
98
+ end
99
+
100
+ end
101
+
102
+ def delete_keys
103
+ path = $CONFIG + "/.peers/"
104
+ paths = files path
105
+ paths.each do |path|
106
+ FileUtils.rm path
107
+ end
108
+ end
109
+
110
+ Given /^two peers, Alice and Bob$/ do
111
+ receive_alice = TestReceiver.new
112
+ receive_bob = TestReceiver.new
113
+ send_bob = TestSender.new
114
+ send_bob.send_to receive_alice
115
+ send_alice = TestSender.new
116
+ send_alice.send_to receive_bob
117
+
118
+ $alice_address = "alice"
119
+ $bob_address = "bob"
120
+
121
+ # Alice's stuff
122
+ CARPS::init 0, "test/server"
123
+ delete_keys
124
+ $alice_box = Mailbox.new send_bob, receive_bob, MessageParser.new(default_messages), SessionManager.new
125
+ $alice = TwistedMailer.new $alice_address, $alice_box
126
+
127
+ # Bob's stuff
128
+ CARPS::init 0, "test/client"
129
+ delete_keys
130
+ $bob_box = TwistedMailbox.new send_alice, receive_alice, MessageParser.new(default_messages.push EvilMessage), SessionManager.new
131
+ $bob = TwistedMailer.new $bob_address, $bob_box
132
+ end
133
+
134
+ Then /^Alice initiates a handshake request and Bob accepts$/ do
135
+ Thread.fork { $alice.handshake $bob_address }
136
+ $bob.expect_handshake
137
+ end
138
+
139
+ Then /^bob tries to receive the message$/ do
140
+ thrd = Thread.fork do
141
+ loop do
142
+ $bob.check EvilMessage
143
+ sleep 1
144
+ end
145
+ end
146
+ UI::highlight "PRESS ENTER TO STOP CHECKING BOB'S MAIL"
147
+ UI::question ""
148
+ thrd.kill
149
+ end
150
+
151
+ Then /^a hacker pretending to be Alice sends a nefarious message to Bob$/ do
152
+ $alice.evil $bob_address, EvilMessage.new
153
+ end
154
+
155
+ Then /^a spoofer pretending to be Bob tries to make a handshake with Alice$/ do
156
+ $bob.forget $alice_address
157
+ Thread.fork { $bob.handshake $alice_address }
158
+ $alice.expect_handshake
159
+ end
160
+
161
+ When /^the user presses enter, threading stops$/ do
162
+ UI::highlight "PRESS ENTER TO STOP"
163
+ UI::question ""
164
+ $bob.shutdown
165
+ $alice.shutdown
166
+ end
@@ -0,0 +1,91 @@
1
+ require "carps/mod"
2
+
3
+ include CARPS::Dice
4
+
5
+ Then /^show the odds$/ do
6
+ $odds = $dice.odds
7
+ puts $odds
8
+ end
9
+
10
+ Given /^a d(\d+)$/ do |sides|
11
+ $dice = d sides.to_i
12
+ end
13
+
14
+ Then /^multiply by (\d+)$/ do |n|
15
+ $dice * n.to_i
16
+ end
17
+
18
+ Then /^multiply by (\d+) \/ (\d+)$/ do |num, den|
19
+ $dice * (num.to_f / den.to_f)
20
+ end
21
+
22
+ Then /^add (\d+)$/ do |n|
23
+ $dice + n.to_i
24
+ end
25
+
26
+ Then /^add a d(\d+)$/ do |sides|
27
+ $dice + CARPS::Dice::d(sides.to_i)
28
+ end
29
+
30
+ Then /^subtract a d(\d+)$/ do |sides|
31
+ $dice - CARPS::Dice::d(sides.to_i)
32
+ end
33
+
34
+ Then /^divide by (\d+)$/ do |n|
35
+ $dice / n.to_i
36
+ end
37
+
38
+ Then /^if it's greater or equal to (\d+), and less than or equal to (\d+), the result is (\d+)$/ do |gte, lte, out|
39
+ $dice.in_range gte.to_i..lte.to_i, out.to_i
40
+ end
41
+
42
+ Then /^if it's greater than (\d+), the result is (\d+)$/ do |compare, result|
43
+ $dice.is :>, compare.to_i, result.to_i
44
+ end
45
+
46
+ Then /^multiply by a d(\d+)$/ do |sides|
47
+ $dice * CARPS::Dice::d(sides.to_i)
48
+ end
49
+
50
+ Then /^divide by a d(\d+)$/ do |sides|
51
+ $dice / CARPS::Dice::d(sides.to_i)
52
+ end
53
+
54
+ Then /^if it's greater or equal to (\d+), and less than or equal to (\d+), the result is a d(\d+)$/ do |gte, lte, sides|
55
+ $dice.in_range gte.to_i..lte.to_i, CARPS::Dice::d(sides.to_i)
56
+ end
57
+
58
+ Then /^result (\d+) must be (\d+)$/ do |index, expect|
59
+ results = $odds.keys.sort
60
+ unless results[index.to_i] == expect.to_i
61
+ raise StandardError, "Unexpected result!"
62
+ end
63
+ end
64
+
65
+ Then /^each of the odds must be (\d+) \/ (\d+)$/ do |num, den|
66
+ odds = $odds.values
67
+ odds.each do |odd|
68
+ unless odd == num.to_f / den.to_f
69
+ raise StandardError, "Unexpected odds"
70
+ end
71
+ end
72
+ end
73
+
74
+ Then /^odd (\d+) must be (\d+) \/ (\d+)$/ do |index, num, den|
75
+ results = $odds.keys.sort
76
+ odds = results.map {|result| $odds[result]}
77
+ unless odds[index.to_i] == num.to_f / den.to_f
78
+ raise StandardError, "Unexpected odd"
79
+ end
80
+ end
81
+
82
+ Then /^result (\d+) must be \-(\d+)$/ do |index, expect|
83
+ results = $odds.keys.sort
84
+ unless results[index.to_i] == - expect.to_i
85
+ raise StandardError, "Unexpected result!"
86
+ end
87
+ end
88
+
89
+ Then /^roll the dice$/ do
90
+ puts "The dice roll reads: #{$dice.roll}"
91
+ end
@@ -0,0 +1,147 @@
1
+ require "carps/mod"
2
+
3
+ require "carps/service"
4
+
5
+ require "yaml"
6
+
7
+ class TestMod < DM::Mod
8
+ def schema
9
+ $schema
10
+ end
11
+
12
+ def update_barry status
13
+ @reporter.update_player "barry", status
14
+ end
15
+
16
+ end
17
+
18
+ class TestMailer < DM::Mailer
19
+
20
+ def initialize
21
+ @dm = "johnny"
22
+ @about = "game description"
23
+ @session = "123"
24
+ @mod = "cool"
25
+ end
26
+
27
+ def relay addr, mail
28
+ puts "Sending to #{addr}:"
29
+ puts mail.emit
30
+ end
31
+
32
+ def save mod
33
+ puts "Saving: #{mod.to_yaml}"
34
+ end
35
+
36
+ def barry
37
+ @sheet = Sheet::NewSheet.new({"name" => "bob", "fruit" => "kumquat", "days old" => 12})
38
+ @sheet.from = "barry"
39
+ end
40
+
41
+ def read klass, from=nil
42
+ msg = nil
43
+ until msg
44
+ msg = check
45
+ sleep 1
46
+ end
47
+ msg
48
+ end
49
+
50
+ def check klass, from=nil
51
+ if @sheet
52
+ sheet = @sheet
53
+ @sheet = nil
54
+ return sheet
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ Given /^a DM mod$/ do
61
+ resource = Resource.new "resource"
62
+ $mailer = TestMailer.new
63
+ $mod = TestMod.new resource
64
+ $mod.mailer = $mailer
65
+ end
66
+
67
+ $email = "barry@doodah.xxx"
68
+
69
+ When /^(.+) joins the mod$/ do |name|
70
+ $mailer.barry
71
+ end
72
+
73
+ Then /^set (.+)'s status conditionally$/ do |name|
74
+ player = $mod.player_stats(name)
75
+ $mod.update_barry "You are a #{player["fruit"]}"
76
+ end
77
+
78
+ Then /^preview player turns$/ do
79
+ $mod.inspect_reports
80
+ end
81
+
82
+ Then /^check barry's sheet$/ do
83
+ received = false
84
+ until received
85
+ received = $mod.check_mail
86
+ sleep 1
87
+ end
88
+ end
89
+
90
+ Given /^a DM interface$/ do
91
+ $interface = DM::Interface.new $mod
92
+ end
93
+
94
+ Then /^test all inputs to interface$/ do
95
+ commands = []
96
+ commands.push [:invite, "carps@killersmurf.com"]
97
+ commands.push [:mail]
98
+ commands.push [:done]
99
+ commands.push [:players]
100
+ commands.push [:npcs]
101
+ commands.push [:describe, "bob"]
102
+ commands.push [:describe, "barry"]
103
+ commands.push [:spawn, "orange", "dick"]
104
+ commands.push [:describe, "dick"]
105
+ commands.push [:describe, "bob"]
106
+ commands.push [:npcs]
107
+ commands.push [:players]
108
+ commands.push [:done]
109
+ commands.push [:warp, "cave"]
110
+ commands.push [:warp, "hello"]
111
+ commands.push [:decree]
112
+ commands.push [:tell, "barry"]
113
+ commands.push [:tell, "bob"]
114
+ commands.push [:census]
115
+ commands.push [:edit, "bob"]
116
+ commands.push [:edit, "bob"]
117
+ commands.push [:edit, "barry"]
118
+ commands.push [:edit, "dick"]
119
+ commands.push [:survey]
120
+ commands.push [:ask, "bob"]
121
+ commands.push [:ask, "barry"]
122
+ commands.push [:inspect, "bob"]
123
+ commands.push [:inspect, "barry"]
124
+ commands.push [:nuke]
125
+ commands.push [:silence]
126
+ commands.push [:futile]
127
+ commands.push [:remit, "bob"]
128
+ commands.push [:remit, "barry"]
129
+ commands.push [:supress, "bob"]
130
+ commands.push [:supress, "barry"]
131
+ commands.push [:done]
132
+ commands.push [:save]
133
+ test_interface $interface, commands
134
+ end
135
+
136
+ Then /^present a user interface to the DM$/ do
137
+ $interface.run
138
+ end
139
+
140
+ Then /^create an NPC called (.+) of type (.+)$/ do |name, type|
141
+ $mod.new_npc type, name
142
+ end
143
+
144
+ Then /^report the strength of the NPC (.+) to (.+)$/ do |npc_name, name|
145
+ npc = $mod.npc_stats npc_name
146
+ $mod.update_player name, "#{npc_name}'s strength is #{npc["strength"]}"
147
+ end