newton 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.md +189 -0
- data/Rakefile +6 -0
- data/examples/autovoice.rb +45 -0
- data/examples/echo_bot.rb +22 -0
- data/examples/excess_flood.rb +23 -0
- data/examples/memo.rb +50 -0
- data/examples/schema.rb +41 -0
- data/examples/secure_eval.rb +46 -0
- data/lib/newton/ban.rb +40 -0
- data/lib/newton/bot.rb +361 -0
- data/lib/newton/callback.rb +24 -0
- data/lib/newton/channel.rb +362 -0
- data/lib/newton/constants.rb +123 -0
- data/lib/newton/exceptions.rb +25 -0
- data/lib/newton/formatted_logger.rb +64 -0
- data/lib/newton/irc.rb +261 -0
- data/lib/newton/isupport.rb +96 -0
- data/lib/newton/mask.rb +46 -0
- data/lib/newton/message.rb +162 -0
- data/lib/newton/message_queue.rb +62 -0
- data/lib/newton/rubyext/infinity.rb +1 -0
- data/lib/newton/rubyext/module.rb +18 -0
- data/lib/newton/rubyext/queue.rb +19 -0
- data/lib/newton/rubyext/string.rb +24 -0
- data/lib/newton/syncable.rb +55 -0
- data/lib/newton/user.rb +226 -0
- data/lib/newton.rb +1 -0
- data/test/helper.rb +60 -0
- data/test/test_commands.rb +85 -0
- data/test/test_events.rb +89 -0
- data/test/test_helpers.rb +14 -0
- data/test/test_irc.rb +38 -0
- data/test/test_message.rb +117 -0
- data/test/test_parse.rb +153 -0
- data/test/test_queue.rb +49 -0
- data/test/tests.rb +9 -0
- metadata +100 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Newton
|
2
|
+
module Syncable
|
3
|
+
# Blocks until the object is synced.
|
4
|
+
#
|
5
|
+
# @return [void]
|
6
|
+
def wait_until_synced(attr)
|
7
|
+
attr = attr.to_sym
|
8
|
+
while true
|
9
|
+
return if @synced_attributes.include?(attr)
|
10
|
+
sleep 0.1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
# @return [void]
|
16
|
+
def sync(attribute, value, data = false)
|
17
|
+
if data
|
18
|
+
@data[attribute] = value
|
19
|
+
else
|
20
|
+
instance_variable_set("@#{attribute}", value)
|
21
|
+
end
|
22
|
+
@synced_attributes << attribute
|
23
|
+
end
|
24
|
+
|
25
|
+
def synced?(attribute)
|
26
|
+
@synced_attributes.include?(attribute)
|
27
|
+
end
|
28
|
+
|
29
|
+
def unsync(attribute)
|
30
|
+
@synced_attributes.delete(attribute)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
def attr(attribute, data = false, unsync = false)
|
35
|
+
unless unsync
|
36
|
+
if @when_requesting_synced_attribute
|
37
|
+
@when_requesting_synced_attribute.call(attribute)
|
38
|
+
end
|
39
|
+
wait_until_synced(attribute)
|
40
|
+
end
|
41
|
+
|
42
|
+
if data
|
43
|
+
return @data[attribute]
|
44
|
+
else
|
45
|
+
return instance_variable_get("@#{attribute}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
# @return [void]
|
51
|
+
def mark_as_synced(attribute)
|
52
|
+
@synced_attributes << attribute
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/newton/user.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Newton
|
3
|
+
class User
|
4
|
+
include Syncable
|
5
|
+
|
6
|
+
@users = {}
|
7
|
+
class << self
|
8
|
+
|
9
|
+
# @overload find_ensured(nick, bot)
|
10
|
+
# Finds or creates a user based on his nick.
|
11
|
+
#
|
12
|
+
# @param [String] nick The user's nickname
|
13
|
+
# @param [Bot] bot An instance of Bot
|
14
|
+
# @overload find_ensured(user, nick, host, bot)
|
15
|
+
# Finds or creates a user based on his nick but already
|
16
|
+
# setting user and host.
|
17
|
+
#
|
18
|
+
# @param [String] user The username
|
19
|
+
# @param [String] nick The nickname
|
20
|
+
# @param [String] host The user's hostname
|
21
|
+
# @param [Bot] bot An instance of bot
|
22
|
+
#
|
23
|
+
# @return [User]
|
24
|
+
def find_ensured(*args)
|
25
|
+
# FIXME CASEMAPPING
|
26
|
+
case args.size
|
27
|
+
when 2
|
28
|
+
nick = args.first
|
29
|
+
bargs = [args.first]
|
30
|
+
bot = args.last
|
31
|
+
when 4
|
32
|
+
nick = args[1]
|
33
|
+
bot = args.pop
|
34
|
+
bargs = args
|
35
|
+
else
|
36
|
+
raise ArgumentError
|
37
|
+
end
|
38
|
+
downcased_nick = nick.irc_downcase(bot.irc.isupport["CASEMAPPING"])
|
39
|
+
@users[downcased_nick] ||= new(*bargs, bot)
|
40
|
+
@users[downcased_nick]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Finds a user.
|
44
|
+
#
|
45
|
+
# @param [String] nick nick of a user
|
46
|
+
# @return [User, nil]
|
47
|
+
def find(nick)
|
48
|
+
@users[nick]
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Array<User>] Returns all users
|
52
|
+
def all
|
53
|
+
@users.values
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# @return [String]
|
59
|
+
attr_accessor :nick
|
60
|
+
# @return [Bot]
|
61
|
+
attr_accessor :bot
|
62
|
+
# @return [Boolean]
|
63
|
+
attr_accessor :synced
|
64
|
+
|
65
|
+
# By default, you can use methods like User#user, User#host and
|
66
|
+
# alike – If you however fear that another thread might change
|
67
|
+
# data while you're using it and if this means a critical issue to
|
68
|
+
# your code, you can store the result of this method and work with
|
69
|
+
# that instead.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# on :channel do
|
73
|
+
# data = user.data
|
74
|
+
# do_something_with(data.user)
|
75
|
+
# do_something_with(data.host)
|
76
|
+
# end
|
77
|
+
# @return [Hash]
|
78
|
+
attr_accessor :data
|
79
|
+
def initialize(*args)
|
80
|
+
@data = {
|
81
|
+
:user => nil,
|
82
|
+
:host => nil,
|
83
|
+
:realname => nil,
|
84
|
+
:authname => nil,
|
85
|
+
:idle => 0,
|
86
|
+
:signed_on_at => nil,
|
87
|
+
:unknown? => false,
|
88
|
+
:channels => [],
|
89
|
+
:secure? => false,
|
90
|
+
}
|
91
|
+
case args.size
|
92
|
+
when 2
|
93
|
+
@nick, @bot = args
|
94
|
+
when 4
|
95
|
+
@data[:user], @nick, @data[:host], @bot = args
|
96
|
+
else
|
97
|
+
raise ArgumentError
|
98
|
+
end
|
99
|
+
|
100
|
+
@synced_attributes = Set.new
|
101
|
+
|
102
|
+
@when_requesting_synced_attribute = lambda {|attr|
|
103
|
+
unless @synced
|
104
|
+
unsync attr
|
105
|
+
whois
|
106
|
+
end
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# Checks if the user is identified. Currently officially supports
|
111
|
+
# Quakenet and Freenode.
|
112
|
+
#
|
113
|
+
# @return [Boolean] true if the user is identified
|
114
|
+
def authed?
|
115
|
+
@data[:authname]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Queries the IRC server for information on the user. This will
|
119
|
+
# set the User's state to not synced. After all information are
|
120
|
+
# received, the object will be set back to synced.
|
121
|
+
#
|
122
|
+
# @return [void]
|
123
|
+
def whois
|
124
|
+
@synced = false
|
125
|
+
@data.keys.each do |attr|
|
126
|
+
unsync attr
|
127
|
+
end
|
128
|
+
@bot.raw "WHOIS #@nick #@nick"
|
129
|
+
end
|
130
|
+
|
131
|
+
# Send a message to the user.
|
132
|
+
#
|
133
|
+
# @param [String] message the message
|
134
|
+
# @return [void]
|
135
|
+
def send(message)
|
136
|
+
@bot.msg(@nick, message)
|
137
|
+
end
|
138
|
+
alias_method :privmsg, :send
|
139
|
+
|
140
|
+
# Send a CTCP to the user.
|
141
|
+
#
|
142
|
+
# @param [String] message the ctcp message
|
143
|
+
# @return [void]
|
144
|
+
def ctcp(message)
|
145
|
+
send "\001#{message}\001"
|
146
|
+
end
|
147
|
+
|
148
|
+
# Send an action (/me) to the user.
|
149
|
+
#
|
150
|
+
# @param [String] message the message
|
151
|
+
# @return [void]
|
152
|
+
def action(message)
|
153
|
+
@bot.action(@name, message)
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [String]
|
157
|
+
def to_s
|
158
|
+
@nick
|
159
|
+
end
|
160
|
+
|
161
|
+
# @return [String]
|
162
|
+
def inspect
|
163
|
+
"#<User nick=#{@nick.inspect}>"
|
164
|
+
end
|
165
|
+
|
166
|
+
# Generates a mask for the user.
|
167
|
+
#
|
168
|
+
# @param [String] s a pattern for generating the mask. %n =
|
169
|
+
# nickname – %u = username – %h = host – %r = realname – %a =
|
170
|
+
# authname
|
171
|
+
#
|
172
|
+
# @return [Mask]
|
173
|
+
def mask(s = "%n!%u@%h")
|
174
|
+
s = s.gsub(/%(.)/) {
|
175
|
+
case $1
|
176
|
+
when "n"
|
177
|
+
@nick
|
178
|
+
when "u"
|
179
|
+
self.user
|
180
|
+
when "h"
|
181
|
+
self.host
|
182
|
+
when "r"
|
183
|
+
self.realname
|
184
|
+
when "a"
|
185
|
+
self.authname
|
186
|
+
end
|
187
|
+
}
|
188
|
+
|
189
|
+
Mask.new(s)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Provides synced access to user attributes.
|
193
|
+
def method_missing(m, *args)
|
194
|
+
if m.to_s =~ /^(.+)_unsynced$/
|
195
|
+
m = $1.to_sym
|
196
|
+
unsync = true
|
197
|
+
end
|
198
|
+
|
199
|
+
if @data.has_key?(m)
|
200
|
+
attr(m, true, unsync = false)
|
201
|
+
else
|
202
|
+
super
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# @return [Boolean]
|
207
|
+
def ==(other)
|
208
|
+
return case other
|
209
|
+
when self.class
|
210
|
+
@nick == other.nick
|
211
|
+
when String
|
212
|
+
self.to_s == other
|
213
|
+
when Bot
|
214
|
+
self.nick == other.config.nick
|
215
|
+
else
|
216
|
+
false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
alias_method :eql?, "=="
|
220
|
+
|
221
|
+
# @return [Fixnum]
|
222
|
+
def hash
|
223
|
+
@nick.hash
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/newton.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'newton/bot'
|
data/test/helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
require 'newton'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'contest'
|
6
|
+
require 'rr'
|
7
|
+
require 'timeout'
|
8
|
+
begin
|
9
|
+
require 'ruby-debug'
|
10
|
+
rescue LoadError; end
|
11
|
+
|
12
|
+
module Test::Unit::Assertions
|
13
|
+
def assert_empty_buffer(io)
|
14
|
+
assert_raise(Errno::EAGAIN) { io.read_nonblock 1 }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MockSocket
|
19
|
+
def self.pipe
|
20
|
+
socket1, socket2 = new, new
|
21
|
+
socket1.in, socket2.out = IO.pipe
|
22
|
+
socket2.in, socket1.out = IO.pipe
|
23
|
+
[socket1, socket2]
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :in, :out
|
27
|
+
def gets()
|
28
|
+
Timeout.timeout(1) {@in.gets}
|
29
|
+
end
|
30
|
+
def puts(m) @out.puts(m) end
|
31
|
+
def print(m) @out.print(m) end
|
32
|
+
def eof?() @in.eof? end
|
33
|
+
def empty?
|
34
|
+
begin
|
35
|
+
@in.read_nonblock(1)
|
36
|
+
false
|
37
|
+
rescue Errno::EAGAIN
|
38
|
+
true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Test::Unit::TestCase
|
44
|
+
include RR::Adapters::TestUnit
|
45
|
+
|
46
|
+
def mock_bot(&b)
|
47
|
+
@socket, @server = MockSocket.pipe
|
48
|
+
stub(TCPSocket).open(anything, anything) {@socket}
|
49
|
+
bot = Newton::Bot.new(&b)
|
50
|
+
bot.config.environment = :test
|
51
|
+
Thread.start { bot.start }
|
52
|
+
bot
|
53
|
+
end
|
54
|
+
|
55
|
+
def bot_is_connected
|
56
|
+
assert_equal "NICK isaac\r\n", @server.gets
|
57
|
+
assert_equal "USER isaac 0 * :Isaac\r\n", @server.gets
|
58
|
+
1.upto(4) {|i| @server.print ":localhost 00#{i}\r\n"}
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestCommands < Test::Unit::TestCase
|
4
|
+
test "raw messages can be send" do
|
5
|
+
bot = mock_bot {}
|
6
|
+
bot_is_connected
|
7
|
+
|
8
|
+
bot.raw "PRIVMSG foo :bar baz"
|
9
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
10
|
+
end
|
11
|
+
|
12
|
+
test "messages are sent to recipient" do
|
13
|
+
bot = mock_bot {}
|
14
|
+
bot_is_connected
|
15
|
+
|
16
|
+
bot.msg "foo", "bar baz"
|
17
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
18
|
+
end
|
19
|
+
|
20
|
+
test "actions are sent to recipient" do
|
21
|
+
bot = mock_bot {}
|
22
|
+
bot_is_connected
|
23
|
+
|
24
|
+
bot.action "foo", "bar"
|
25
|
+
assert_equal "PRIVMSG foo :\001ACTION bar\001\r\n", @server.gets
|
26
|
+
end
|
27
|
+
|
28
|
+
test "channels are joined" do
|
29
|
+
bot = mock_bot {}
|
30
|
+
bot_is_connected
|
31
|
+
|
32
|
+
bot.join "#foo", "#bar"
|
33
|
+
assert_equal "JOIN #foo\r\n", @server.gets
|
34
|
+
assert_equal "JOIN #bar\r\n", @server.gets
|
35
|
+
end
|
36
|
+
|
37
|
+
test "channels are parted" do
|
38
|
+
bot = mock_bot {}
|
39
|
+
bot_is_connected
|
40
|
+
|
41
|
+
bot.part "#foo", "#bar"
|
42
|
+
assert_equal "PART #foo\r\n", @server.gets
|
43
|
+
assert_equal "PART #bar\r\n", @server.gets
|
44
|
+
end
|
45
|
+
|
46
|
+
test "topic is set" do
|
47
|
+
bot = mock_bot {}
|
48
|
+
bot_is_connected
|
49
|
+
|
50
|
+
bot.topic "#foo", "bar baz"
|
51
|
+
assert_equal "TOPIC #foo :bar baz\r\n", @server.gets
|
52
|
+
end
|
53
|
+
|
54
|
+
test "modes can be set" do
|
55
|
+
bot = mock_bot {}
|
56
|
+
bot_is_connected
|
57
|
+
|
58
|
+
bot.mode "#foo", "+o"
|
59
|
+
assert_equal "MODE #foo +o\r\n", @server.gets
|
60
|
+
end
|
61
|
+
|
62
|
+
test "can kick users" do
|
63
|
+
bot = mock_bot {}
|
64
|
+
bot_is_connected
|
65
|
+
|
66
|
+
bot.kick "foo", "bar", "bein' a baz"
|
67
|
+
assert_equal "KICK foo bar :bein' a baz\r\n", @server.gets
|
68
|
+
end
|
69
|
+
|
70
|
+
test "quits" do
|
71
|
+
bot = mock_bot {}
|
72
|
+
bot_is_connected
|
73
|
+
|
74
|
+
bot.quit
|
75
|
+
assert_equal "QUIT\r\n", @server.gets
|
76
|
+
end
|
77
|
+
|
78
|
+
test "quits with message" do
|
79
|
+
bot = mock_bot {}
|
80
|
+
bot_is_connected
|
81
|
+
|
82
|
+
bot.quit "I'm outta here!"
|
83
|
+
assert_equal "QUIT :I'm outta here!\r\n", @server.gets
|
84
|
+
end
|
85
|
+
end
|
data/test/test_events.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestEvents < Test::Unit::TestCase
|
4
|
+
# This is stupid, but it's just there to make it easier to transform to the new
|
5
|
+
# Message class. Should be fixed.
|
6
|
+
def dispatch(type, env)
|
7
|
+
msg = Newton::Message.new(":john!doe@example.com PRIVMSG #foo :#{env[:message]}")
|
8
|
+
@bot.dispatch(type, msg)
|
9
|
+
end
|
10
|
+
|
11
|
+
test "events are registered" do
|
12
|
+
@bot = mock_bot {
|
13
|
+
on(:channel, /Hello/) {msg "foo", "yr formal!"}
|
14
|
+
on(:channel, /Hey/) {msg "foo", "bar baz"}
|
15
|
+
}
|
16
|
+
bot_is_connected
|
17
|
+
|
18
|
+
dispatch(:channel, :message => "Hey")
|
19
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
20
|
+
end
|
21
|
+
|
22
|
+
test "catch-all events" do
|
23
|
+
@bot = mock_bot {
|
24
|
+
on(:channel) {msg "foo", "bar baz"}
|
25
|
+
}
|
26
|
+
bot_is_connected
|
27
|
+
|
28
|
+
dispatch(:channel, :message => "lolcat")
|
29
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
30
|
+
end
|
31
|
+
|
32
|
+
test "event can be halted" do
|
33
|
+
@bot = mock_bot {
|
34
|
+
on(:channel, /Hey/) { halt; msg "foo", "bar baz" }
|
35
|
+
}
|
36
|
+
bot_is_connected
|
37
|
+
|
38
|
+
dispatch(:channel, :message => "Hey")
|
39
|
+
assert @server.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
test "connect-event is dispatched at connection" do
|
43
|
+
@bot = mock_bot {
|
44
|
+
on(:connect) {msg "foo", "bar baz"}
|
45
|
+
}
|
46
|
+
bot_is_connected
|
47
|
+
|
48
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
49
|
+
end
|
50
|
+
|
51
|
+
test "regular expression match is accessible" do
|
52
|
+
@bot = mock_bot {
|
53
|
+
on(:channel, /foo (bar)/) {msg "foo", match[0]}
|
54
|
+
}
|
55
|
+
bot_is_connected
|
56
|
+
|
57
|
+
dispatch(:channel, :message => "foo bar")
|
58
|
+
|
59
|
+
assert_equal "PRIVMSG foo :bar\r\n", @server.gets
|
60
|
+
end
|
61
|
+
|
62
|
+
test "regular expression matches are handed to block arguments" do
|
63
|
+
@bot = mock_bot {
|
64
|
+
on :channel, /(foo) (bar)/ do |a,b|
|
65
|
+
raw "#{a}"
|
66
|
+
raw "#{b}"
|
67
|
+
end
|
68
|
+
}
|
69
|
+
bot_is_connected
|
70
|
+
|
71
|
+
dispatch(:channel, :message => "foo bar")
|
72
|
+
|
73
|
+
assert_equal "foo\r\n", @server.gets
|
74
|
+
assert_equal "bar\r\n", @server.gets
|
75
|
+
end
|
76
|
+
|
77
|
+
test "only specified number of captures are handed to block args" do
|
78
|
+
@bot = mock_bot {
|
79
|
+
on :channel, /(foo) (bar)/ do |a|
|
80
|
+
raw "#{a}"
|
81
|
+
end
|
82
|
+
}
|
83
|
+
bot_is_connected
|
84
|
+
|
85
|
+
dispatch(:channel, :message => "foo bar")
|
86
|
+
|
87
|
+
assert_equal "foo\r\n", @server.gets
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestHelpers < Test::Unit::TestCase
|
4
|
+
test "helpers are registered" do
|
5
|
+
bot = mock_bot {
|
6
|
+
helpers { def foo; msg "foo", "bar baz"; end }
|
7
|
+
on(:private, //) {foo}
|
8
|
+
}
|
9
|
+
bot_is_connected
|
10
|
+
|
11
|
+
bot.irc.parse ":johnny!john@doe.com PRIVMSG isaac :hello, you!"
|
12
|
+
assert_equal "PRIVMSG foo :bar baz\r\n", @server.gets
|
13
|
+
end
|
14
|
+
end
|
data/test/test_irc.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestIrc < Test::Unit::TestCase
|
4
|
+
test "a new bot connects to IRC" do
|
5
|
+
bot = mock_bot {}
|
6
|
+
|
7
|
+
assert_equal "NICK isaac\r\n", @server.gets
|
8
|
+
assert_equal "USER isaac 0 * :#{bot.config.realname}\r\n", @server.gets
|
9
|
+
end
|
10
|
+
|
11
|
+
test "password is sent if specified" do
|
12
|
+
bot = mock_bot {
|
13
|
+
configure {|c| c.password = "foo"}
|
14
|
+
}
|
15
|
+
assert_equal "PASS foo\r\n", @server.gets
|
16
|
+
end
|
17
|
+
|
18
|
+
test "no messages are sent when registration isn't complete" do
|
19
|
+
bot = mock_bot {
|
20
|
+
on(:connect) {raw "Connected!"}
|
21
|
+
}
|
22
|
+
2.times { @server.gets } # NICK / USER
|
23
|
+
bot.dispatch :connect
|
24
|
+
|
25
|
+
assert @server.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
test "no messages are sent until registration is complete" do
|
29
|
+
bot = mock_bot {
|
30
|
+
on(:connect) {raw "Connected!"}
|
31
|
+
}
|
32
|
+
2.times { @server.gets } # NICK / USER
|
33
|
+
bot.dispatch :connect
|
34
|
+
|
35
|
+
1.upto(4) {|i| @server.puts ":localhost 00#{i}"}
|
36
|
+
assert_equal "Connected!\r\n", @server.gets
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestMessage < Test::Unit::TestCase
|
4
|
+
include Newton
|
5
|
+
|
6
|
+
test "host prefix" do
|
7
|
+
msg = Message.new(":jeff!spicoli@beach.com QUIT")
|
8
|
+
assert_equal "jeff!spicoli@beach.com", msg.prefix
|
9
|
+
assert_equal "jeff", msg.nick
|
10
|
+
assert_equal "spicoli", msg.user
|
11
|
+
assert_equal "beach.com", msg.host
|
12
|
+
assert_nil msg.server
|
13
|
+
end
|
14
|
+
|
15
|
+
test "server prefix" do
|
16
|
+
msg = Message.new(":some.server.com PING")
|
17
|
+
assert_equal "some.server.com", msg.prefix
|
18
|
+
assert_equal "some.server.com", msg.server
|
19
|
+
assert_nil msg.nick
|
20
|
+
assert_nil msg.user
|
21
|
+
assert_nil msg.host
|
22
|
+
end
|
23
|
+
|
24
|
+
test "without prefix" do
|
25
|
+
msg = Message.new("PING foo.bar")
|
26
|
+
assert_nil msg.prefix
|
27
|
+
assert_nil msg.nick
|
28
|
+
assert_nil msg.host
|
29
|
+
end
|
30
|
+
|
31
|
+
test "command" do
|
32
|
+
msg = Message.new("PING foo.bar")
|
33
|
+
assert_equal "PING", msg.command
|
34
|
+
end
|
35
|
+
|
36
|
+
test "numeric reply" do
|
37
|
+
msg = Message.new("409")
|
38
|
+
assert msg.numeric_reply?
|
39
|
+
assert_equal "409", msg.command
|
40
|
+
end
|
41
|
+
|
42
|
+
test "single param" do
|
43
|
+
msg = Message.new("PING foo.bar")
|
44
|
+
assert_equal 1, msg.params.size
|
45
|
+
assert_equal "foo.bar", msg.params[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
test "multiple params" do
|
49
|
+
msg = Message.new("FOO bar baz")
|
50
|
+
assert_equal 2, msg.params.size
|
51
|
+
assert_equal ["bar", "baz"], msg.params
|
52
|
+
end
|
53
|
+
|
54
|
+
test "single param with whitespace" do
|
55
|
+
msg = Message.new("FOO :bar baz")
|
56
|
+
assert_equal 1, msg.params.size
|
57
|
+
assert_equal "bar baz", msg.params[0]
|
58
|
+
end
|
59
|
+
|
60
|
+
test "single param with whitespace and colon" do
|
61
|
+
msg = Message.new("FOO :bar :baz")
|
62
|
+
assert_equal 1, msg.params.size
|
63
|
+
assert_equal "bar :baz", msg.params[0]
|
64
|
+
end
|
65
|
+
|
66
|
+
test "multiple params with whitespace" do
|
67
|
+
msg = Message.new("FOO bar :lol cat")
|
68
|
+
assert_equal 2, msg.params.size
|
69
|
+
assert_equal "bar", msg.params[0]
|
70
|
+
assert_equal "lol cat", msg.params[1]
|
71
|
+
end
|
72
|
+
|
73
|
+
test "multiple params with whitespace and colon" do
|
74
|
+
msg = Message.new("FOO bar :lol :cat")
|
75
|
+
assert_equal 2, msg.params.size
|
76
|
+
assert_equal "bar", msg.params[0]
|
77
|
+
assert_equal "lol :cat", msg.params[1]
|
78
|
+
end
|
79
|
+
|
80
|
+
test "error" do
|
81
|
+
msg = Message.new("200")
|
82
|
+
assert_equal false, msg.error?
|
83
|
+
assert_nil msg.error
|
84
|
+
|
85
|
+
msg = Message.new("400")
|
86
|
+
assert_equal true, msg.error?
|
87
|
+
assert_equal 400, msg.error
|
88
|
+
end
|
89
|
+
|
90
|
+
test "if error, #message has the error code string" do
|
91
|
+
msg = Message.new("400")
|
92
|
+
assert_equal "400", msg.message
|
93
|
+
end
|
94
|
+
|
95
|
+
test "channel has channel name" do
|
96
|
+
msg = Message.new(":foo!bar@baz.com PRIVMSG #awesome :lol cat")
|
97
|
+
assert_equal true, msg.channel?
|
98
|
+
assert_equal "#awesome", msg.channel
|
99
|
+
end
|
100
|
+
|
101
|
+
test "channel has nothing when receiver is a nick" do
|
102
|
+
msg = Message.new(":foo!bar@baz.com PRIVMSG john :wazzup boy?")
|
103
|
+
assert_equal false, msg.channel?
|
104
|
+
assert_equal nil, msg.channel
|
105
|
+
end
|
106
|
+
|
107
|
+
test "privmsg has #message" do
|
108
|
+
msg = Message.new(":foo!bar@baz.com PRIVMSG #awesome :lol cat")
|
109
|
+
assert_equal "lol cat", msg.message
|
110
|
+
end
|
111
|
+
|
112
|
+
# test "non-privmsg doesn't have #message" do
|
113
|
+
# msg = Message.new("PING :foo bar")
|
114
|
+
# p msg.message
|
115
|
+
# assert_nil msg.message
|
116
|
+
# end
|
117
|
+
end
|