autumn 3.1.8
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/AUTHORS +11 -0
- data/CHANGELOG +567 -0
- data/MANIFEST +110 -0
- data/README +1114 -0
- data/README.textile +1153 -0
- data/Rakefile +75 -0
- data/autumn.gemspec +44 -0
- data/bin/autumn +11 -0
- data/lib/autumn.rb +8 -0
- data/lib/autumn/authentication.rb +238 -0
- data/lib/autumn/channel_leaf.rb +107 -0
- data/lib/autumn/coder.rb +166 -0
- data/lib/autumn/console_boot.rb +10 -0
- data/lib/autumn/ctcp.rb +250 -0
- data/lib/autumn/daemon.rb +207 -0
- data/lib/autumn/datamapper_hacks.rb +290 -0
- data/lib/autumn/foliater.rb +231 -0
- data/lib/autumn/formatting.rb +236 -0
- data/lib/autumn/generator.rb +231 -0
- data/lib/autumn/genesis.rb +190 -0
- data/lib/autumn/inheritable_attributes.rb +162 -0
- data/lib/autumn/leaf.rb +738 -0
- data/lib/autumn/log_facade.rb +49 -0
- data/lib/autumn/misc.rb +87 -0
- data/lib/autumn/resources/daemons/Anothernet.yml +3 -0
- data/lib/autumn/resources/daemons/AustHex.yml +29 -0
- data/lib/autumn/resources/daemons/Bahamut.yml +67 -0
- data/lib/autumn/resources/daemons/Dancer.yml +3 -0
- data/lib/autumn/resources/daemons/GameSurge.yml +3 -0
- data/lib/autumn/resources/daemons/IRCnet.yml +3 -0
- data/lib/autumn/resources/daemons/Ithildin.yml +7 -0
- data/lib/autumn/resources/daemons/KineIRCd.yml +56 -0
- data/lib/autumn/resources/daemons/PTlink.yml +6 -0
- data/lib/autumn/resources/daemons/QuakeNet.yml +20 -0
- data/lib/autumn/resources/daemons/RFC1459.yml +158 -0
- data/lib/autumn/resources/daemons/RFC2811.yml +16 -0
- data/lib/autumn/resources/daemons/RFC2812.yml +36 -0
- data/lib/autumn/resources/daemons/RatBox.yml +25 -0
- data/lib/autumn/resources/daemons/Ultimate.yml +24 -0
- data/lib/autumn/resources/daemons/Undernet.yml +6 -0
- data/lib/autumn/resources/daemons/Unreal.yml +110 -0
- data/lib/autumn/resources/daemons/_Other.yml +7 -0
- data/lib/autumn/resources/daemons/aircd.yml +33 -0
- data/lib/autumn/resources/daemons/bdq-ircd.yml +3 -0
- data/lib/autumn/resources/daemons/hybrid.yml +38 -0
- data/lib/autumn/resources/daemons/ircu.yml +67 -0
- data/lib/autumn/resources/daemons/tr-ircd.yml +8 -0
- data/lib/autumn/script.rb +74 -0
- data/lib/autumn/speciator.rb +165 -0
- data/lib/autumn/stem.rb +919 -0
- data/lib/autumn/stem_facade.rb +176 -0
- data/lib/autumn/tool/bin.rb +301 -0
- data/lib/autumn/tool/create.rb +48 -0
- data/lib/autumn/tool/project_creator.rb +110 -0
- data/lib/autumn/version.rb +3 -0
- data/lib/skel/Rakefile +163 -0
- data/lib/skel/config/global.yml +2 -0
- data/lib/skel/config/seasons/testing/database.yml +4 -0
- data/lib/skel/config/seasons/testing/leaves.yml +9 -0
- data/lib/skel/config/seasons/testing/season.yml +2 -0
- data/lib/skel/config/seasons/testing/stems.yml +10 -0
- data/lib/skel/leaves/administrator/README +20 -0
- data/lib/skel/leaves/administrator/controller.rb +67 -0
- data/lib/skel/leaves/administrator/views/autumn.txt.erb +1 -0
- data/lib/skel/leaves/administrator/views/reload.txt.erb +11 -0
- data/lib/skel/leaves/insulter/README +17 -0
- data/lib/skel/leaves/insulter/controller.rb +65 -0
- data/lib/skel/leaves/insulter/views/about.txt.erb +1 -0
- data/lib/skel/leaves/insulter/views/help.txt.erb +1 -0
- data/lib/skel/leaves/insulter/views/insult.txt.erb +1 -0
- data/lib/skel/leaves/scorekeeper/README +34 -0
- data/lib/skel/leaves/scorekeeper/config.yml +2 -0
- data/lib/skel/leaves/scorekeeper/controller.rb +104 -0
- data/lib/skel/leaves/scorekeeper/helpers/general.rb +64 -0
- data/lib/skel/leaves/scorekeeper/models/channel.rb +12 -0
- data/lib/skel/leaves/scorekeeper/models/person.rb +14 -0
- data/lib/skel/leaves/scorekeeper/models/pseudonym.rb +11 -0
- data/lib/skel/leaves/scorekeeper/models/score.rb +14 -0
- data/lib/skel/leaves/scorekeeper/tasks/stats.rake +17 -0
- data/lib/skel/leaves/scorekeeper/views/about.txt.erb +1 -0
- data/lib/skel/leaves/scorekeeper/views/change.txt.erb +5 -0
- data/lib/skel/leaves/scorekeeper/views/history.txt.erb +11 -0
- data/lib/skel/leaves/scorekeeper/views/points.txt.erb +5 -0
- data/lib/skel/leaves/scorekeeper/views/usage.txt.erb +1 -0
- data/lib/skel/log/README +1 -0
- data/lib/skel/script/console +28 -0
- data/lib/skel/script/destroy +48 -0
- data/lib/skel/script/generate +48 -0
- data/lib/skel/shared/README +1 -0
- data/lib/skel/tmp/README +1 -0
- data/spec/authentication_spec.rb +328 -0
- data/spec/channel_leaf_spec.rb +142 -0
- data/spec/coder_spec.rb +146 -0
- data/spec/ctcp_spec.rb +222 -0
- data/spec/daemon_spec.rb +202 -0
- data/spec/datamapper_hacks_spec.rb +164 -0
- data/tasks/authors.rake +30 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/copyright.rake +21 -0
- data/tasks/doc.rake +7 -0
- data/tasks/gem.rake +23 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/install_dependencies.rake +6 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +23 -0
- data/tasks/release.rake +52 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +24 -0
- data/tasks/spec.rake +7 -0
- data/tasks/yard.rake +4 -0
- metadata +188 -0
data/spec/coder_spec.rb
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'facets/array'
|
|
3
|
+
require 'facets/string'
|
|
4
|
+
|
|
5
|
+
require "autumn/coder"
|
|
6
|
+
|
|
7
|
+
describe Autumn::Coder do
|
|
8
|
+
before :each do
|
|
9
|
+
@coder = Autumn::Coder.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should start with an indent of 0" do
|
|
13
|
+
@coder << "test string"
|
|
14
|
+
@coder.output.should eql("test string\n")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should indent by two spaces" do
|
|
18
|
+
@coder.indent!
|
|
19
|
+
@coder << "test string"
|
|
20
|
+
@coder.unindent!
|
|
21
|
+
@coder.output.should eql(" test string\n")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should indent each line of a multi-line string" do
|
|
25
|
+
@coder.indent!
|
|
26
|
+
@coder << "line 1\nline 2"
|
|
27
|
+
@coder.unindent!
|
|
28
|
+
@coder.output.should eql(" line 1\n line 2\n")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should insert a newline between consecutive calls to <<" do
|
|
32
|
+
@coder << "first string"
|
|
33
|
+
@coder << "second string"
|
|
34
|
+
@coder.output.should eql("first string\nsecond string\n")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should unindent by two spaces" do
|
|
38
|
+
@coder.indent!
|
|
39
|
+
@coder << "first string"
|
|
40
|
+
@coder.unindent!
|
|
41
|
+
@coder << "second string"
|
|
42
|
+
@coder.output.should eql(" first string\nsecond string\n")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should add newlines when given the newline! message" do
|
|
46
|
+
@coder << "first line"
|
|
47
|
+
@coder.newline!
|
|
48
|
+
@coder << "second line"
|
|
49
|
+
@coder.output.should eql("first line\n\nsecond line\n")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should generate a basic class template" do
|
|
53
|
+
@coder.klass('TestClass')
|
|
54
|
+
@coder.output.should eql("class TestClass\nend\n")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should generate a subclass template" do
|
|
58
|
+
@coder.klass('Subclass', 'Superclass')
|
|
59
|
+
@coder.output.should eql("class Subclass < Superclass\nend\n")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should indent the contents of a class" do
|
|
63
|
+
@coder.klass('TestClass') { |klass| klass << "content" }
|
|
64
|
+
@coder.output.should eql("class TestClass\n content\nend\n")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should generate a basic method template" do
|
|
68
|
+
@coder.method('test_method')
|
|
69
|
+
@coder.output.should eql("def test_method\nend\n")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should indent the contents of a method" do
|
|
73
|
+
@coder.method('test_method') { |meth| meth << "content" }
|
|
74
|
+
@coder.output.should eql("def test_method\n content\nend\n")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should properly generate a one-parameter method" do
|
|
78
|
+
@coder.method('test_method', :arg)
|
|
79
|
+
@coder.output.should eql("def test_method(arg)\nend\n")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "should properly generate a multi-parameter method" do
|
|
83
|
+
@coder.method('test_method', :arg1, :arg2)
|
|
84
|
+
@coder.output.should eql("def test_method(arg1, arg2)\nend\n")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should properly generate optional parameters" do
|
|
88
|
+
@coder.method('test_method', { :arg => nil })
|
|
89
|
+
@coder.output.should eql("def test_method(arg=nil)\nend\n")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should properly generate multiple optional and required parameters" do
|
|
93
|
+
@coder.method('test_method', :req1, :req2, { :opt1 => '' }, { :opt2 => Array.new })
|
|
94
|
+
@coder.output.should eql(%{def test_method(req1, req2, opt1="", opt2=[])\nend\n})
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should raise an exception for empty parameter names" do
|
|
98
|
+
lambda { @coder.method('test_method', '') }.should raise_error(ArgumentError)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should raise an exception for empty optional parameter names" do
|
|
102
|
+
lambda { @coder.method('test_method', { '' => nil }) }.should raise_error(ArgumentError)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe Autumn::TemplateCoder do
|
|
107
|
+
before :each do
|
|
108
|
+
@coder = Autumn::TemplateCoder.new
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "should generate a proper leaf template" do
|
|
112
|
+
@coder.leaf('test_leaf')
|
|
113
|
+
|
|
114
|
+
# HACK extlib and facets both define String#margin to do different things;
|
|
115
|
+
# we need a way to un-require the dm-core gem once we've run the DM
|
|
116
|
+
# specs. For now, we're forced to redefine String#margin
|
|
117
|
+
String.class_eval do
|
|
118
|
+
def margin(n=0)
|
|
119
|
+
#d = /\A.*\n\s*(.)/.match( self )[1]
|
|
120
|
+
#d = /\A\s*(.)/.match( self)[1] unless d
|
|
121
|
+
d = ((/\A.*\n\s*(.)/.match(self)) ||
|
|
122
|
+
(/\A\s*(.)/.match(self)))[1]
|
|
123
|
+
return '' unless d
|
|
124
|
+
if n == 0
|
|
125
|
+
gsub(/\n\s*\Z/,'').gsub(/^\s*[#{d}]/, '')
|
|
126
|
+
else
|
|
127
|
+
gsub(/\n\s*\Z/,'').gsub(/^\s*[#{d}]/, ' ' * n)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
@coder.output.should eql(%{
|
|
133
|
+
|# Controller for the TestLeaf leaf.
|
|
134
|
+
|
|
|
135
|
+
|class Controller < Autumn::Leaf
|
|
136
|
+
|
|
|
137
|
+
| # Typing "!about" displays some basic information about this leaf.
|
|
138
|
+
|
|
|
139
|
+
| def about_command(stem, sender, reply_to, msg)
|
|
140
|
+
| # This method renders the file "about.txt.erb"
|
|
141
|
+
| end
|
|
142
|
+
|end
|
|
143
|
+
|
|
|
144
|
+
}.margin)
|
|
145
|
+
end
|
|
146
|
+
end
|
data/spec/ctcp_spec.rb
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'facets/array'
|
|
4
|
+
require 'facets/enumerable'
|
|
5
|
+
require 'facets/kernel'
|
|
6
|
+
require 'facets/string'
|
|
7
|
+
require 'anise'
|
|
8
|
+
|
|
9
|
+
require 'autumn/misc'
|
|
10
|
+
require 'autumn/stem_facade'
|
|
11
|
+
require 'autumn/daemon'
|
|
12
|
+
require 'autumn/stem'
|
|
13
|
+
require 'autumn/ctcp'
|
|
14
|
+
|
|
15
|
+
describe Autumn::CTCP do
|
|
16
|
+
before :each do
|
|
17
|
+
@ctcp = Autumn::CTCP.new
|
|
18
|
+
@sender_hash = { :user => 'TestUser', :nick => 'TestNick', :host => 'ca.testhost.org' }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "with a mock stem" do
|
|
22
|
+
before :each do
|
|
23
|
+
@stem = mock('stem')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should parse CTCP requests in PRIVMSGs and broadcast two request-received methods" do
|
|
27
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_request, @ctcp, @stem, @sender_hash, [])
|
|
28
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_request_received, :test, @ctcp, @stem, @sender_hash, [])
|
|
29
|
+
@ctcp.irc_privmsg_event @stem, @sender_hash, :message => "\01TEST\01"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should parse unencoded arguments in CTCP requests" do
|
|
33
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_request, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg2' ])
|
|
34
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_request_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg2' ])
|
|
35
|
+
@ctcp.irc_privmsg_event @stem, @sender_hash, :message => "\01TEST arg1 arg2\01"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should parse encoded arguments in CTCP requests" do
|
|
39
|
+
Autumn::CTCP::ENCODED_COMMANDS << 'TEST'
|
|
40
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_request, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg 2' ])
|
|
41
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_request_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg 2' ])
|
|
42
|
+
@ctcp.irc_privmsg_event @stem, @sender_hash, :message => "\01TEST arg1 arg\\@2\01"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should correctly unescape all magic characters in its response" do
|
|
46
|
+
Autumn::CTCP::ENCODED_COMMANDS << 'TEST'
|
|
47
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_request, @ctcp, @stem, @sender_hash, [ "\000\001\n\r \\" ])
|
|
48
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_request_received, :test, @ctcp, @stem, @sender_hash, [ "\000\001\n\r \\" ])
|
|
49
|
+
@ctcp.irc_privmsg_event @stem, @sender_hash, :message => "\01TEST \\0\\1\\n\\r\\@\\\\\01"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should not parse space escapes in unencoded arguments in CTCP requests" do
|
|
53
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_request, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg\@2' ])
|
|
54
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_request_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg\@2' ])
|
|
55
|
+
@ctcp.irc_privmsg_event @stem, @sender_hash, :message => "\01TEST arg1 arg\\@2\01"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should parse CTCP responses in NOTICEs and broadcast two response-received methods" do
|
|
59
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_response, @ctcp, @stem, @sender_hash, [])
|
|
60
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_response_received, :test, @ctcp, @stem, @sender_hash, [])
|
|
61
|
+
@ctcp.irc_notice_event @stem, @sender_hash, :message => "\01TEST\01"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should parse unencoded arguments in CTCP responses" do
|
|
65
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_response, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg2' ])
|
|
66
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_response_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg2' ])
|
|
67
|
+
@ctcp.irc_notice_event @stem, @sender_hash, :message => "\01TEST arg1 arg2\01"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should parse encoded arguments in CTCP responses" do
|
|
71
|
+
Autumn::CTCP::ENCODED_COMMANDS << 'TEST'
|
|
72
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_response, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg 2' ])
|
|
73
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_response_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg 2' ])
|
|
74
|
+
@ctcp.irc_notice_event @stem, @sender_hash, :message => "\01TEST arg1 arg\\@2\01"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "should not parse space escapes in unencoded arguments in CTCP responses" do
|
|
78
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_test_response, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg\@2' ])
|
|
79
|
+
@stem.should_receive(:broadcast).once.with(:ctcp_response_received, :test, @ctcp, @stem, @sender_hash, [ 'arg1', 'arg\@2' ])
|
|
80
|
+
@ctcp.irc_notice_event @stem, @sender_hash, :message => "\01TEST arg1 arg\\@2\01"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "with an actual stem" do
|
|
85
|
+
before :each do
|
|
86
|
+
@ctcp.instance_variable_set(:@reply_queue, Hash.new { |h,k| h[k] = Array.new })
|
|
87
|
+
|
|
88
|
+
@stem = Autumn::Stem.new('irc.example.com', 'Example', :channel => '#example')
|
|
89
|
+
#TODO proper way to stub this?
|
|
90
|
+
@stem.instance_eval do
|
|
91
|
+
def privmsg(*args)
|
|
92
|
+
args
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
@stem.add_listener @ctcp
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should set the @ctcp variable in a stem when it's added as a listener to that stem" do
|
|
99
|
+
@stem.instance_variable_get(:@ctcp).should eql(@ctcp)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should add a method of the form ctcp_* to the stem" do
|
|
103
|
+
lambda { @stem.ctcp_action("#example") }.should_not raise_error(NoMethodError)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "... which replies with a CTCP message" do
|
|
107
|
+
@stem.ctcp_action("#example").should eql([ "#example", "\001ACTION\001" ])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "... ... that properly encodes arguments when appropriate" do
|
|
111
|
+
@stem.ctcp_ping("#example", 'arg1', 'arg 2').should eql([ "#example", "\001PING arg1 arg\\@2\001" ])
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "... ... ... escaping all magic characters" do
|
|
115
|
+
@stem.ctcp_ping("#example", "\n\r \\\000\001").should eql([ "#example", "\001PING " + '\n\r\@\\\\\0\1' + "\001" ])
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "... ... that does not encode arguments when appropriate" do
|
|
119
|
+
@stem.ctcp_action("#example", "ABC 123").should eql([ "#example", "\001ACTION ABC 123\001" ])
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "should add a method of the form ctcp_reply_* to the stem" do
|
|
123
|
+
lambda { @stem.ctcp_reply_ping("Pinger") }.should_not raise_error(NoMethodError)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "... which replies with a CTCP response" do
|
|
127
|
+
@stem.ctcp_reply_ping("Pinger")
|
|
128
|
+
reply_queue(@ctcp, @stem).shift.should == { :recipient => "Pinger", :message => "\001PING\001" }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "... ... that properly encodes arguments when appropriate" do
|
|
132
|
+
@stem.ctcp_reply_ping("Pinger", 'arg1', 'arg 2')
|
|
133
|
+
reply_queue(@ctcp, @stem).shift.should == { :recipient => "Pinger", :message => "\001PING arg1 arg\\@2\001" }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "... ... ... escaping all magic characters" do
|
|
137
|
+
@stem.ctcp_reply_ping("Pinger", "\n\r \\\000\001")
|
|
138
|
+
reply_queue(@ctcp, @stem).shift.should == { :recipient => "Pinger", :message => "\001PING " + '\n\r\@\\\\\0\1' + "\001" }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "... ... that does not encode arguments when appropriate" do
|
|
142
|
+
@stem.ctcp_reply_example("Tester", "ABC 123")
|
|
143
|
+
reply_queue(@ctcp, @stem).shift.should == { :recipient => "Tester", :message => "\001EXAMPLE ABC 123\001" }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
describe "with a mock stem that records message intervals" do
|
|
148
|
+
before :each do
|
|
149
|
+
@stem = Object.new
|
|
150
|
+
class << @stem
|
|
151
|
+
attr :received
|
|
152
|
+
|
|
153
|
+
def notice(*args)
|
|
154
|
+
@received ||= Array.new
|
|
155
|
+
@received << Time.now
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def privmsg(*args)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def average_interval
|
|
162
|
+
times = Array.new
|
|
163
|
+
@received.each_by { |a, b| times << b - a if a and b }
|
|
164
|
+
return times.sum/times.size.to_f
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
@ctcp.added @stem
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "should queue replies and fire them at the default interval of 0.25 seconds" do
|
|
172
|
+
10.times { @stem.ctcp_reply_ping "Pinger", "ABC123" }
|
|
173
|
+
sleep 3
|
|
174
|
+
@stem.average_interval.should be_close(0.25, 0.05)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "should drop replies from the queue when the default maximum of 10 is exceeded" do
|
|
178
|
+
Thread.exclusive { 15.times { @stem.ctcp_reply_ping "Pinger", "ABC123" } }
|
|
179
|
+
sleep 4
|
|
180
|
+
@stem.received.size.should be_close(10, 1.5)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
describe "with custom CTCP reply rate and queue length values" do
|
|
184
|
+
before :each do
|
|
185
|
+
@ctcp = Autumn::CTCP.new(:reply_rate => 0.5, :reply_queue_size => 5)
|
|
186
|
+
@ctcp.added @stem
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "should queue replies and fire them at a custom interval" do
|
|
190
|
+
5.times { @stem.ctcp_reply_ping "Pinger", "ABC123" }
|
|
191
|
+
sleep 3
|
|
192
|
+
@stem.average_interval.should be_close(0.5, 0.05)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "should drop replies from the queue when a custom maximum is exceeded" do
|
|
196
|
+
15.times { @stem.ctcp_reply_ping "Pinger", "ABC123" }
|
|
197
|
+
sleep 4
|
|
198
|
+
@stem.received.size.should be_close(5, 1.5)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "should respond to CTCP VERSION requests" do
|
|
204
|
+
@ctcp.should respond_to(:ctcp_version_request)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "should respond to CTCP PING requests" do
|
|
208
|
+
@ctcp.should respond_to(:ctcp_ping_request)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should respond to CTCP TIME requests" do
|
|
212
|
+
@ctcp.should respond_to(:ctcp_time_request)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
after :each do
|
|
216
|
+
Autumn::CTCP::ENCODED_COMMANDS.delete 'TEST'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def reply_queue(ctcp, stem)
|
|
220
|
+
ctcp.instance_variable_get(:@reply_queue)[stem]
|
|
221
|
+
end
|
|
222
|
+
end
|
data/spec/daemon_spec.rb
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'facets/array'
|
|
4
|
+
require 'facets/string'
|
|
5
|
+
|
|
6
|
+
require 'autumn/misc'
|
|
7
|
+
require 'autumn/daemon'
|
|
8
|
+
|
|
9
|
+
describe Autumn::Daemon do
|
|
10
|
+
it "should not allow the creation of a default Daemon" do
|
|
11
|
+
lambda { Autumn::Daemon.new nil, nil }.should raise_error
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "(the default daemon)" do
|
|
15
|
+
it "should exist" do
|
|
16
|
+
Autumn::Daemon.default.should_not be_nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should parrot unknown properties" do
|
|
20
|
+
Autumn::Daemon.default.usermode['~'].should eql('~')
|
|
21
|
+
Autumn::Daemon.default.privilege['~'].should eql('~')
|
|
22
|
+
Autumn::Daemon.default.user_prefix['('].should eql('(')
|
|
23
|
+
Autumn::Daemon.default.channel_prefix['('].should eql('(')
|
|
24
|
+
Autumn::Daemon.default.channel_mode['~'].should eql('~')
|
|
25
|
+
Autumn::Daemon.default.server_mode['~'].should eql('~')
|
|
26
|
+
Autumn::Daemon.default.event[123].should eql(123)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "with some standard options" do
|
|
31
|
+
before :each do
|
|
32
|
+
@daemon = Autumn::Daemon.new 'daemon', {
|
|
33
|
+
'usermode' => { 'f' => :first_usermode, 's' => :second_usermode },
|
|
34
|
+
'privilege' => { 'f' => :first_priv, 's' => :second_priv },
|
|
35
|
+
'user_prefix' => { '+' => :first_priv, '-' => :second_priv },
|
|
36
|
+
'channel_prefix' => { '#' => :first_chantype, '&' => :second_chantype },
|
|
37
|
+
'channel_mode' => { 'c' => :first_chanmode, 'd' => :second_chanmode },
|
|
38
|
+
'server_mode' => { 'F' => :first_srvrmode, 'S' => :second_srvrmode },
|
|
39
|
+
'event' => { 998 => :first_event, 997 => :second_event }
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should associate a Daemon with its name" do
|
|
44
|
+
Autumn::Daemon['daemon'].should equal(@daemon)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should update the default Daemon with its properties" do
|
|
48
|
+
Autumn::Daemon.default.usermode['f'].should eql(:first_usermode)
|
|
49
|
+
Autumn::Daemon.default.privilege['f'].should eql(:first_priv)
|
|
50
|
+
Autumn::Daemon.default.user_prefix['+'].should eql(:first_priv)
|
|
51
|
+
Autumn::Daemon.default.channel_prefix['#'].should eql(:first_chantype)
|
|
52
|
+
Autumn::Daemon.default.channel_mode['c'].should eql(:first_chanmode)
|
|
53
|
+
Autumn::Daemon.default.server_mode['F'].should eql(:first_srvrmode)
|
|
54
|
+
Autumn::Daemon.default.event[998].should eql(:first_event)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should return hashes merged with the default" do
|
|
58
|
+
Autumn::Daemon.default.usermode['b'] = :new_usermode
|
|
59
|
+
Autumn::Daemon.default.privilege['b'] = :new_priv
|
|
60
|
+
Autumn::Daemon.default.user_prefix['$'] = :new_uprefix
|
|
61
|
+
Autumn::Daemon.default.channel_prefix['%'] = :new_cprefix
|
|
62
|
+
Autumn::Daemon.default.channel_mode['b'] = :new_chanmode
|
|
63
|
+
Autumn::Daemon.default.server_mode['B'] = :new_srvmode
|
|
64
|
+
Autumn::Daemon.default.event[100] = :new_event
|
|
65
|
+
|
|
66
|
+
@daemon.usermode['b'].should eql(:new_usermode)
|
|
67
|
+
@daemon.privilege['b'].should eql(:new_priv)
|
|
68
|
+
@daemon.user_prefix['$'].should eql(:new_uprefix)
|
|
69
|
+
@daemon.channel_prefix['%'].should eql(:new_cprefix)
|
|
70
|
+
@daemon.channel_mode['b'].should eql(:new_chanmode)
|
|
71
|
+
@daemon.server_mode['B'].should eql(:new_srvmode)
|
|
72
|
+
@daemon.event[100].should eql(:new_event)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should parrot unknown properties" do
|
|
76
|
+
@daemon.usermode['~'].should eql('~')
|
|
77
|
+
@daemon.privilege['~'].should eql('~')
|
|
78
|
+
@daemon.user_prefix['('].should eql('(')
|
|
79
|
+
@daemon.channel_prefix['('].should eql('(')
|
|
80
|
+
@daemon.channel_mode['~'].should eql('~')
|
|
81
|
+
@daemon.server_mode['~'].should eql('~')
|
|
82
|
+
@daemon.event[123].should eql(123)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should recognize a change in user privilege as such" do
|
|
86
|
+
@daemon.privilege_mode?('+f').should be_true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should recognize a change in channel mode as such" do
|
|
90
|
+
@daemon.privilege_mode?('+c').should be_false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should raise an exception when privilege_mode? is called with an invalid mode string" do
|
|
94
|
+
lambda { @daemon.privilege_mode?('invalid') }.should raise_error
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should recognize when a nick is prefixed" do
|
|
98
|
+
@daemon.nick_prefixed?('+Nick').should be_true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should recognize when a nick is not prefixed" do
|
|
102
|
+
@daemon.nick_prefixed?('Nick').should be_false
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "should be able to strip a nick of prefix characters" do
|
|
106
|
+
@daemon.just_nick('+Nick').should eql('Nick')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should, when asked to strip a nick with no prefix characters, return that same nick" do
|
|
110
|
+
@daemon.just_nick('Nick').should eql('Nick')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should give the privilege of a nick with no prefixes as :unvoiced" do
|
|
114
|
+
@daemon.nick_privilege('Nick').should eql(:unvoiced)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "should correctly give the privilege of a nick with one prefix" do
|
|
118
|
+
@daemon.nick_privilege('+Nick').should eql(:first_priv)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should correctly give the privileges of a nick with multiple prefixes" do
|
|
122
|
+
@daemon.nick_privilege('+-Nick').should == [ :first_priv, :second_priv ].to_set
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should add predicate methods for each hash which return true for known values" do
|
|
126
|
+
@daemon.usermode?('f').should be_true
|
|
127
|
+
@daemon.privilege?('f').should be_true
|
|
128
|
+
@daemon.user_prefix?('+').should be_true
|
|
129
|
+
@daemon.channel_prefix?('#').should be_true
|
|
130
|
+
@daemon.channel_mode?('c').should be_true
|
|
131
|
+
@daemon.server_mode?('F').should be_true
|
|
132
|
+
@daemon.event?(998).should be_true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "... and return false for unknown values" do
|
|
136
|
+
@daemon.usermode?('~').should be_false
|
|
137
|
+
@daemon.privilege?('~').should be_false
|
|
138
|
+
@daemon.user_prefix?('(').should be_false
|
|
139
|
+
@daemon.channel_prefix?('(').should be_false
|
|
140
|
+
@daemon.channel_mode?('~').should be_false
|
|
141
|
+
@daemon.server_mode?('~').should be_false
|
|
142
|
+
@daemon.event?(123).should be_false
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "... and should work with numeric prefix characters" do
|
|
146
|
+
@daemon.user_prefix?(?+).should be_true
|
|
147
|
+
@daemon.channel_prefix?(?#).should be_true
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "... and should return values in the default daemon as well" do
|
|
151
|
+
Autumn::Daemon.default.usermode['b'] = :new_usermode
|
|
152
|
+
Autumn::Daemon.default.privilege['b'] = :new_priv
|
|
153
|
+
Autumn::Daemon.default.user_prefix['$'] = :new_uprefix
|
|
154
|
+
Autumn::Daemon.default.channel_prefix['%'] = :new_cprefix
|
|
155
|
+
Autumn::Daemon.default.channel_mode['b'] = :new_chanmode
|
|
156
|
+
Autumn::Daemon.default.server_mode['B'] = :new_srvmode
|
|
157
|
+
Autumn::Daemon.default.event[100] = :new_event
|
|
158
|
+
|
|
159
|
+
@daemon.usermode?('b').should be_true
|
|
160
|
+
@daemon.privilege?('b').should be_true
|
|
161
|
+
@daemon.user_prefix?('$').should be_true
|
|
162
|
+
@daemon.channel_prefix?('%').should be_true
|
|
163
|
+
@daemon.channel_mode?('b').should be_true
|
|
164
|
+
@daemon.server_mode?('B').should be_true
|
|
165
|
+
@daemon.event?(100).should be_true
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "initialized along with a second Daemon with some duplicate properties" do
|
|
169
|
+
before :each do
|
|
170
|
+
@daemon2 = Autumn::Daemon.new 'daemon2', {
|
|
171
|
+
'usermode' => { 'f' => :first_usermode, 's' => :other_usermode },
|
|
172
|
+
'privilege' => { 'f' => :first_priv, 's' => :other_priv },
|
|
173
|
+
'user_prefix' => { '+' => :first_priv, '-' => :other_priv },
|
|
174
|
+
'channel_prefix' => { '#' => :first_chantype, '&' => :other_chantype },
|
|
175
|
+
'channel_mode' => { 'c' => :first_chanmode, 'd' => :other_chanmode },
|
|
176
|
+
'server_mode' => { 'F' => :first_srvrmode, 'S' => :other_srvrmode },
|
|
177
|
+
'event' => { 998 => :first_event, 997 => :other_event }
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "should not remove the duplicate properties with identical values from the default Daemon" do
|
|
182
|
+
Autumn::Daemon.default.usermode['f'].should eql(:first_usermode)
|
|
183
|
+
Autumn::Daemon.default.privilege['f'].should eql(:first_priv)
|
|
184
|
+
Autumn::Daemon.default.user_prefix['+'].should eql(:first_priv)
|
|
185
|
+
Autumn::Daemon.default.channel_prefix['#'].should eql(:first_chantype)
|
|
186
|
+
Autumn::Daemon.default.channel_mode['c'].should eql(:first_chanmode)
|
|
187
|
+
Autumn::Daemon.default.server_mode['F'].should eql(:first_srvrmode)
|
|
188
|
+
Autumn::Daemon.default.event[998].should eql(:first_event)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "should remove the duplicate properties with different values from the default Daemon" do
|
|
192
|
+
Autumn::Daemon.default.usermode['s'].should eql('s')
|
|
193
|
+
Autumn::Daemon.default.privilege['s'].should eql('s')
|
|
194
|
+
Autumn::Daemon.default.user_prefix['-'].should eql('-')
|
|
195
|
+
Autumn::Daemon.default.channel_prefix['&'].should eql('&')
|
|
196
|
+
Autumn::Daemon.default.channel_mode['d'].should eql('d')
|
|
197
|
+
Autumn::Daemon.default.server_mode['S'].should eql('S')
|
|
198
|
+
Autumn::Daemon.default.event[997].should eql(997)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|