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.
- data/COPYING +674 -0
- data/GEM_DESCRIPTION +10 -0
- data/History.txt +4 -0
- data/Manifest.txt +156 -0
- data/PostInstall.txt +20 -0
- data/README.rdoc +141 -0
- data/Rakefile +28 -0
- data/bin/carps +123 -0
- data/bin/carps_init +29 -0
- data/bin/carps_ipc_test +44 -0
- data/bin/carps_mod_saver_test +71 -0
- data/bin/carps_mod_test +62 -0
- data/config/website.yml +2 -0
- data/features/character_sheet.feature +40 -0
- data/features/crash.feature +15 -0
- data/features/crypt.feature +22 -0
- data/features/dice.feature +173 -0
- data/features/dm.feature +36 -0
- data/features/dmll.feature +51 -0
- data/features/edit.feature +10 -0
- data/features/email.feature +29 -0
- data/features/interface.feature +17 -0
- data/features/ipc.feature +10 -0
- data/features/mailbox.feature +33 -0
- data/features/mod.feature +31 -0
- data/features/parser.feature +9 -0
- data/features/persistent_protocol.feature +14 -0
- data/features/player.feature +22 -0
- data/features/player_turn.feature +29 -0
- data/features/random.feature +15 -0
- data/features/rule.feature +19 -0
- data/features/safety.feature +13 -0
- data/features/sessions.feature +16 -0
- data/features/start_dm.feature +18 -0
- data/features/start_player.feature +8 -0
- data/features/step_definitions/common_steps.rb +170 -0
- data/features/steps/character_sheet.rb +89 -0
- data/features/steps/crash.rb +27 -0
- data/features/steps/crypt.rb +166 -0
- data/features/steps/dice.rb +91 -0
- data/features/steps/dm.rb +147 -0
- data/features/steps/dmll.rb +47 -0
- data/features/steps/edit.rb +7 -0
- data/features/steps/email.rb +108 -0
- data/features/steps/general.rb +5 -0
- data/features/steps/interface.rb +64 -0
- data/features/steps/ipc.rb +22 -0
- data/features/steps/mailbox.rb +126 -0
- data/features/steps/mod.rb +25 -0
- data/features/steps/parser.rb +23 -0
- data/features/steps/persistent_protocol.rb +29 -0
- data/features/steps/player.rb +82 -0
- data/features/steps/player_turn.rb +56 -0
- data/features/steps/random.rb +47 -0
- data/features/steps/rule.rb +53 -0
- data/features/steps/safety.rb +17 -0
- data/features/steps/sessions.rb +37 -0
- data/features/steps/start_dm.rb +46 -0
- data/features/steps/start_player.rb +65 -0
- data/features/steps/timeout.rb +32 -0
- data/features/steps/type_verification.rb +36 -0
- data/features/steps/wizard.rb +123 -0
- data/features/support/common.rb +29 -0
- data/features/support/env.rb +14 -0
- data/features/support/matchers.rb +11 -0
- data/features/timeout.feature +11 -0
- data/features/type_verification.feature +48 -0
- data/features/wizard.feature +50 -0
- data/lib/carps/crypt/accept_handshake.rb +40 -0
- data/lib/carps/crypt/default_messages.rb +29 -0
- data/lib/carps/crypt/handshake.rb +41 -0
- data/lib/carps/crypt/mailbox.rb +265 -0
- data/lib/carps/crypt/mailer.rb +220 -0
- data/lib/carps/crypt/peer.rb +123 -0
- data/lib/carps/crypt/public_key.rb +60 -0
- data/lib/carps/crypt.rb +23 -0
- data/lib/carps/email/config.rb +122 -0
- data/lib/carps/email/imap.rb +156 -0
- data/lib/carps/email/smtp.rb +119 -0
- data/lib/carps/email/string.rb +30 -0
- data/lib/carps/email.rb +21 -0
- data/lib/carps/mod/action.rb +36 -0
- data/lib/carps/mod/answers.rb +76 -0
- data/lib/carps/mod/client_turn.rb +88 -0
- data/lib/carps/mod/dice.rb +360 -0
- data/lib/carps/mod/dm/interface.rb +160 -0
- data/lib/carps/mod/dm/mod.rb +409 -0
- data/lib/carps/mod/dm/reporter.rb +112 -0
- data/lib/carps/mod/dm/resource.rb +88 -0
- data/lib/carps/mod/dm/room.rb +33 -0
- data/lib/carps/mod/interface.rb +73 -0
- data/lib/carps/mod/launch.rb +108 -0
- data/lib/carps/mod/mod.rb +52 -0
- data/lib/carps/mod/player/interface.rb +76 -0
- data/lib/carps/mod/player/mod.rb +109 -0
- data/lib/carps/mod/question.rb +63 -0
- data/lib/carps/mod/rule.rb +112 -0
- data/lib/carps/mod/sheet/character.rb +82 -0
- data/lib/carps/mod/sheet/editor.rb +97 -0
- data/lib/carps/mod/sheet/new_sheet.rb +71 -0
- data/lib/carps/mod/sheet/schema.rb +84 -0
- data/lib/carps/mod/sheet/type.rb +161 -0
- data/lib/carps/mod/sheet/verifier.rb +41 -0
- data/lib/carps/mod/status_report.rb +51 -0
- data/lib/carps/mod.rb +40 -0
- data/lib/carps/protocol/keyword.rb +104 -0
- data/lib/carps/protocol/message.rb +138 -0
- data/lib/carps/protocol.rb +19 -0
- data/lib/carps/service/client_parser.rb +34 -0
- data/lib/carps/service/dm/config.rb +76 -0
- data/lib/carps/service/dm/mailer.rb +70 -0
- data/lib/carps/service/dm/new_game.rb +101 -0
- data/lib/carps/service/dm/start.rb +47 -0
- data/lib/carps/service/game.rb +101 -0
- data/lib/carps/service/interface.rb +174 -0
- data/lib/carps/service/invite.rb +79 -0
- data/lib/carps/service/mod.rb +43 -0
- data/lib/carps/service/player/config.rb +78 -0
- data/lib/carps/service/player/mailer.rb +49 -0
- data/lib/carps/service/player/start.rb +60 -0
- data/lib/carps/service/server_parser.rb +33 -0
- data/lib/carps/service/session.rb +96 -0
- data/lib/carps/service/start/config.rb +71 -0
- data/lib/carps/service/start/interface.rb +101 -0
- data/lib/carps/service/start/mailer.rb +46 -0
- data/lib/carps/service.rb +35 -0
- data/lib/carps/test.rb +34 -0
- data/lib/carps/ui/colour.rb +28 -0
- data/lib/carps/ui/error.rb +39 -0
- data/lib/carps/ui/highlight.rb +32 -0
- data/lib/carps/ui/question.rb +63 -0
- data/lib/carps/ui/warn.rb +37 -0
- data/lib/carps/ui.rb +21 -0
- data/lib/carps/util/config.rb +162 -0
- data/lib/carps/util/editor.rb +147 -0
- data/lib/carps/util/error.rb +75 -0
- data/lib/carps/util/files.rb +48 -0
- data/lib/carps/util/init.rb +93 -0
- data/lib/carps/util/process.rb +150 -0
- data/lib/carps/util/timeout.rb +31 -0
- data/lib/carps/util/windows.rb +29 -0
- data/lib/carps/util.rb +24 -0
- data/lib/carps/wizard/dm.rb +41 -0
- data/lib/carps/wizard/player.rb +40 -0
- data/lib/carps/wizard/steps.rb +494 -0
- data/lib/carps/wizard/wizard.rb +126 -0
- data/lib/carps/wizard.rb +21 -0
- data/lib/carps.rb +45 -0
- data/permission +16 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/tasks/readme_site.rake +28 -0
- data/test/test_carps.rb +11 -0
- data/test/test_helper.rb +3 -0
- data/website/index.html +271 -0
- 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
|