campfire-bot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/.autotest +11 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +57 -0
  5. data/README.textile +52 -0
  6. data/TODO +72 -0
  7. data/bin/bot +13 -0
  8. data/campfire-bot.gemspec +27 -0
  9. data/cfbot-stop.sh +8 -0
  10. data/config.example.yml +31 -0
  11. data/lib/bot.rb +194 -0
  12. data/lib/event.rb +114 -0
  13. data/lib/message.rb +30 -0
  14. data/lib/plugin.rb +77 -0
  15. data/lib/version.rb +3 -0
  16. data/plugins/accountability.rb +45 -0
  17. data/plugins/austin.rb +29 -0
  18. data/plugins/basecamp.rb +48 -0
  19. data/plugins/beer.rb +214 -0
  20. data/plugins/beijing_tally.rb +30 -0
  21. data/plugins/boop.rb +127 -0
  22. data/plugins/bruce.rb +15 -0
  23. data/plugins/bugzilla.rb +198 -0
  24. data/plugins/calvin.rb +43 -0
  25. data/plugins/chuck.rb +23 -0
  26. data/plugins/dilbert.rb +51 -0
  27. data/plugins/excuse.rb +478 -0
  28. data/plugins/fail.rb +16 -0
  29. data/plugins/figlet.rb +10 -0
  30. data/plugins/fun.rb +95 -0
  31. data/plugins/garfield.rb +43 -0
  32. data/plugins/generic_search.rb +66 -0
  33. data/plugins/help.rb +13 -0
  34. data/plugins/infobot.rb +58 -0
  35. data/plugins/insult.rb +87 -0
  36. data/plugins/jira.rb +197 -0
  37. data/plugins/lolcats.rb +17 -0
  38. data/plugins/our_quotes.rb +195 -0
  39. data/plugins/quote.rb +31 -0
  40. data/plugins/schneier.rb +28 -0
  41. data/plugins/seen.rb +88 -0
  42. data/plugins/signal_filter.rb +9 -0
  43. data/plugins/svn.rb +167 -0
  44. data/plugins/twitter_echo.rb +54 -0
  45. data/plugins/unfuddle.rb +69 -0
  46. data/plugins/weather.rb +25 -0
  47. data/plugins/xkcd.rb +43 -0
  48. data/spec/beer_spec.rb +224 -0
  49. data/spec/bugzilla_spec.rb +90 -0
  50. data/spec/command_spec.rb +96 -0
  51. data/spec/jira_spec.rb +264 -0
  52. data/spec/our_quotes_spec.rb +186 -0
  53. data/spec/plugin_spec.rb +43 -0
  54. data/spec/spec.opts +1 -0
  55. data/vendor/escape/ChangeLog +30 -0
  56. data/vendor/escape/Makefile +5 -0
  57. data/vendor/escape/README +81 -0
  58. data/vendor/escape/VERSION +1 -0
  59. data/vendor/escape/escape.rb +302 -0
  60. data/vendor/escape/install.rb +109 -0
  61. data/vendor/escape/misc/README.erb +85 -0
  62. data/vendor/escape/rdoc/classes/Escape.html +427 -0
  63. data/vendor/escape/rdoc/classes/Escape.src/M000022.html +19 -0
  64. data/vendor/escape/rdoc/classes/Escape.src/M000023.html +32 -0
  65. data/vendor/escape/rdoc/classes/Escape.src/M000024.html +24 -0
  66. data/vendor/escape/rdoc/classes/Escape.src/M000025.html +19 -0
  67. data/vendor/escape/rdoc/classes/Escape.src/M000026.html +48 -0
  68. data/vendor/escape/rdoc/classes/Escape.src/M000027.html +19 -0
  69. data/vendor/escape/rdoc/classes/Escape.src/M000028.html +19 -0
  70. data/vendor/escape/rdoc/classes/Escape/HTMLAttrValue.html +113 -0
  71. data/vendor/escape/rdoc/classes/Escape/HTMLEscaped.html +113 -0
  72. data/vendor/escape/rdoc/classes/Escape/PercentEncoded.html +113 -0
  73. data/vendor/escape/rdoc/classes/Escape/ShellEscaped.html +113 -0
  74. data/vendor/escape/rdoc/classes/Escape/StringWrapper.html +242 -0
  75. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000029.html +18 -0
  76. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000030.html +18 -0
  77. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000031.html +18 -0
  78. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000032.html +18 -0
  79. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000033.html +18 -0
  80. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000035.html +18 -0
  81. data/vendor/escape/rdoc/classes/TestEscapeHTML.html +182 -0
  82. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000008.html +18 -0
  83. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000009.html +18 -0
  84. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000010.html +18 -0
  85. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000011.html +18 -0
  86. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.html +182 -0
  87. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000012.html +18 -0
  88. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000013.html +19 -0
  89. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000014.html +20 -0
  90. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000015.html +22 -0
  91. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.html +167 -0
  92. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000016.html +18 -0
  93. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000017.html +20 -0
  94. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000018.html +20 -0
  95. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.html +167 -0
  96. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000019.html +20 -0
  97. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000020.html +24 -0
  98. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000021.html +22 -0
  99. data/vendor/escape/rdoc/files/escape_rb.html +136 -0
  100. data/vendor/escape/rdoc/files/install_rb.html +250 -0
  101. data/vendor/escape/rdoc/files/install_rb.src/M000001.html +23 -0
  102. data/vendor/escape/rdoc/files/install_rb.src/M000002.html +31 -0
  103. data/vendor/escape/rdoc/files/install_rb.src/M000003.html +27 -0
  104. data/vendor/escape/rdoc/files/install_rb.src/M000004.html +27 -0
  105. data/vendor/escape/rdoc/files/install_rb.src/M000005.html +21 -0
  106. data/vendor/escape/rdoc/files/install_rb.src/M000006.html +23 -0
  107. data/vendor/escape/rdoc/files/install_rb.src/M000007.html +21 -0
  108. data/vendor/escape/rdoc/files/test/test-escape_rb.html +109 -0
  109. data/vendor/escape/rdoc/fr_class_index.html +36 -0
  110. data/vendor/escape/rdoc/fr_file_index.html +29 -0
  111. data/vendor/escape/rdoc/fr_method_index.html +61 -0
  112. data/vendor/escape/rdoc/index.html +24 -0
  113. data/vendor/escape/rdoc/rdoc-style.css +208 -0
  114. data/vendor/escape/test/test-escape.rb +90 -0
  115. metadata +259 -0
@@ -0,0 +1,54 @@
1
+ require 'hpricot'
2
+ require 'open-uri'
3
+ require 'ostruct'
4
+ require 'time'
5
+ require 'htmlentities'
6
+
7
+ # The workings of this plugin are based on http://github.com/paulca/twitter2campfire
8
+ # Thanks to Paul Campbell and Contrast! <http://www.contrast.ie/>
9
+
10
+ class TwitterEcho < CampfireBot::Plugin
11
+
12
+ at_interval 2.minutes, :echo_tweets
13
+
14
+ def initialize
15
+ @feed = bot.config['twitter_feed']
16
+ @hide_replies = bot.config.key?('twitter_hide_replies') ? bot.config['twitter_hide_replies'] : false
17
+ @latest = Time.now
18
+ end
19
+
20
+ def echo_tweets(msg = nil)
21
+ recent_tweets.reverse.each do |tweet|
22
+ msg.speak("#{coder.decode(tweet.from)}: #{coder.decode(tweet.text)} #{tweet.link}") unless (tweet.text =~ /^@/ && @hide_replies)
23
+ end
24
+ @latest = latest_tweet.date # next time, only print tweets newer than this
25
+ @doc = nil # reset the feed so that next time we can actually any new tweets
26
+ end
27
+
28
+ protected
29
+
30
+ def raw_feed
31
+ @doc ||= Hpricot(open(@feed))
32
+ end
33
+
34
+ def all_tweets
35
+ (raw_feed/'entry').map { |e| OpenStruct.new(
36
+ :from => (e/'name').inner_html,
37
+ :text => (e/'title').inner_html,
38
+ :link => (e/'link').first['href'],
39
+ :date => Time.parse((e/'published').inner_html)
40
+ )}
41
+ end
42
+
43
+ def latest_tweet
44
+ all_tweets.first
45
+ end
46
+
47
+ def recent_tweets
48
+ all_tweets.reject { |e| e.date.to_i <= @latest.to_i }
49
+ end
50
+
51
+ def coder
52
+ HTMLEntities.new
53
+ end
54
+ end
@@ -0,0 +1,69 @@
1
+ # Unfuddle RSS echo plugin. Uses the following config.yml settings:
2
+ #
3
+ # unfuddle:
4
+ # domain: you.unfuddle.com
5
+ # rss_path: "/account/activity.rss?aak=aaaaaaaaaaaaabbbbbbbbccccccccddddddeeee0000"
6
+ # port: 443
7
+ # msg_filters:
8
+ # - reassigned
9
+ # - closed
10
+ # - commented
11
+ # - resolved
12
+
13
+ require 'rubygems'
14
+ require 'simple-rss'
15
+ require 'net/https'
16
+
17
+ class Unfuddle < CampfireBot::Plugin
18
+ at_interval 2.minutes, :fetch_rss
19
+ on_command 'unfuddle', :fetch_rss
20
+
21
+ def initialize
22
+ @last_item = 12.hours.ago
23
+ @http = Net::HTTP.new(bot.config['unfuddle']['domain'], bot.config['unfuddle']['port'])
24
+
25
+ if bot.config['unfuddle']['port'] == 443
26
+ @http.use_ssl = true
27
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
28
+ end
29
+ end
30
+
31
+ def fetch_rss(msg)
32
+ feed = SimpleRSS.parse(@http.get(bot.config['unfuddle']['rss_path']).body)
33
+
34
+ feed.items.each do |item|
35
+ msg.speak "#{item.title} #{item.link}" if published?(item) && !filtered?(item.title)
36
+ end
37
+
38
+ @last_item = feed.items.first.pubDate
39
+ rescue => e
40
+ msg.speak e
41
+ end
42
+
43
+ def published?(item)
44
+ item.pubDate > @last_item
45
+ end
46
+
47
+ def filtered?(title)
48
+ bot.config['unfuddle']['msg_filters'].each do |msg_filter|
49
+ return true if send("#{msg_filter}?", title)
50
+ end
51
+ return false
52
+ end
53
+
54
+ def closed?(title)
55
+ (title =~ /Closed Ticket:/) != nil
56
+ end
57
+
58
+ def reassigned?(title)
59
+ (title =~ /Reassigned Ticket:/) != nil
60
+ end
61
+
62
+ def commented?(title)
63
+ (title =~ /Created Ticket Comment:/) != nil
64
+ end
65
+
66
+ def resolved?(title)
67
+ (title =~ /Resolved Ticket:/) != nil
68
+ end
69
+ end
@@ -0,0 +1,25 @@
1
+ require 'yahoo-weather'
2
+
3
+ class Weather < CampfireBot::Plugin
4
+ on_command 'weather', :weather
5
+
6
+ def weather(msg)
7
+ cities = {
8
+ 'adelaide' => '1099805',
9
+ 'brisbane' => '1100661',
10
+ 'canberra' => '1100968',
11
+ 'darwin' => '1101597',
12
+ 'hobart' => '1102670',
13
+ 'melbourne' => '1103816',
14
+ 'perth' => '1098081',
15
+ 'sydney' => '1105779'
16
+ }
17
+
18
+ city_id = cities[(msg[:message]).downcase] # select city, or
19
+ city_id ||= cities['canberra'] # use default if no matches
20
+
21
+ data = YahooWeather::Client.new.lookup_by_woeid(city_id, 'c')
22
+
23
+ msg.speak("#{data.title} - #{data.condition.text}, #{data.condition.temp} deg C (high #{data.forecasts.first.high}, low #{data.forecasts.first.low})")
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ require 'open-uri'
2
+ require 'hpricot'
3
+ require 'tempfile'
4
+
5
+ class Xkcd < CampfireBot::Plugin
6
+ BASE_URL = 'http://xkcd.com/'
7
+
8
+ on_command 'xkcd', :xkcd
9
+
10
+ def xkcd(msg)
11
+ # Get the comic info
12
+ comic = case msg[:message].split(/\s+/)[0]
13
+ when 'latest'
14
+ fetch_latest
15
+ when 'random'
16
+ fetch_random
17
+ when /d+/
18
+ fetch_comic(msg[:message].split(/\s+/)[0])
19
+ else
20
+ fetch_random
21
+ end
22
+
23
+ msg.speak comic['src']
24
+ msg.speak comic['title']
25
+ end
26
+
27
+ private
28
+
29
+ def fetch_latest
30
+ fetch_comic
31
+ end
32
+
33
+ def fetch_random
34
+ # Fetch the latest page and then find the link to the previous comic.
35
+ # This will give us a number to work with (that of the penultimate strip).
36
+ fetch_comic(rand((Hpricot(open(BASE_URL))/'//*[@accesskey="p"]').first['href'].gsub(/\D/, '').to_i + 1))
37
+ end
38
+
39
+ def fetch_comic(id = nil)
40
+ # Rely on the comic being the last image on the page with a title attribute
41
+ (Hpricot(open("#{BASE_URL}#{id.to_s + '/' if id}"))/'img[@title]').last
42
+ end
43
+ end
@@ -0,0 +1,224 @@
1
+ require 'spec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'test'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ require "#{BOT_ROOT}/plugins/beer.rb"
7
+
8
+
9
+ class SpecMessage < CampfireBot::Message
10
+ attr_reader :response
11
+
12
+ #overwrite message.speak method so that we can expose the output
13
+ def speak(msg)
14
+ # puts "specmessage.speak(#{msg})"
15
+ @response = msg
16
+ end
17
+
18
+ end
19
+
20
+ class SpecBeer < CampfireBot::Plugin::Beer
21
+ attr_accessor :balances
22
+ end
23
+
24
+ # send a message to the room and return the response
25
+ def sendmsg(msg)
26
+ # puts "sendmsg(#{msg})"
27
+ @message[:message] = msg
28
+ @message[:type] = "TextMessage"
29
+ @message[:room] = mock('room', :name => 'test')
30
+ # bot.send(:handle_message, @message)
31
+ %w(commands speakers messages).each do |type|
32
+ CampfireBot::Plugin.send("registered_#{type}").each do |handler|
33
+ handler.run(@message)
34
+ end
35
+ end
36
+ # puts "sendmsg returns #{@message.response}"
37
+ @message.response
38
+ end
39
+
40
+ # instantiate the bot and the plugin fresh
41
+ def setup
42
+ bot = CampfireBot::Bot.instance
43
+ bot.stub!(:config).and_return({'nickname' => 'Bot'})
44
+ @beer = SpecBeer.new()
45
+ CampfireBot::Plugin.registered_plugins['Beer'] = @beer
46
+ @message = SpecMessage.new(:person => 'Josh')
47
+ @beer.balances = {}
48
+ @beer.stub!(:init).and_return(@beer.balances)
49
+ @beer.stub!(:write)
50
+ puts @beer.balances
51
+ @message = SpecMessage.new(:person => 'Josh')
52
+ end
53
+
54
+ describe "giving beer" do
55
+ before(:each) do
56
+ setup
57
+ end
58
+
59
+ # it "should respond to the command !give_beer" do
60
+ # @beer.should_receive(:give_beer)
61
+ # sendmsg "!give_beer"
62
+ # end
63
+
64
+
65
+ it "should increase my balance with Foo" do
66
+ bal = 0
67
+ sendmsg '!give_beer Foo'
68
+ @beer.balance('Josh', 'Foo').should eql(bal + 1)
69
+ end
70
+
71
+
72
+ it "should say back to me what my balance is" do
73
+
74
+ sendmsg('!give_beer bruce').should =~ /1/
75
+ end
76
+
77
+ it "should accept an argument of the number of beers to credit" do
78
+ bal = 2
79
+ sendmsg('!give_beer harvey 2')
80
+ @beer.balance('Josh', 'harvey').should eql(bal)
81
+ end
82
+
83
+ it "should handle nicely names with spaces in them with no argument" do
84
+ bal = 1
85
+ sendmsg('!give_beer harvey A.')
86
+ @beer.balance('Josh', 'harvey A.').should eql(bal)
87
+ end
88
+
89
+ it "should handle nicely names with spaces in them and an argument" do
90
+ bal = 2
91
+ sendmsg('!give_beer harvey D. 2')
92
+ @beer.balance('Josh', 'harvey D.').should eql(bal)
93
+ end
94
+
95
+ it "should not accept negative numbers as an argument" do
96
+ sendmsg('!give_beer harvey -2').should =~ /negative number/
97
+ end
98
+
99
+ end
100
+
101
+ describe "demanding beer" do
102
+
103
+ before(:each) do
104
+ setup
105
+ end
106
+
107
+ it "should respond to the command !demand_beer" do
108
+ @beer.should_receive(:demand_beer)
109
+ sendmsg("!demand_beer albert")
110
+ end
111
+
112
+ it "should decrease my balance with the opposite party" do
113
+ bal = 0
114
+ # p "initial bal is #{bal}"
115
+ sendmsg '!demand_beer Foo'
116
+ puts @beer.balance('Josh', 'Foo')
117
+ @beer.balance('Josh', 'Foo').should eql(bal - 1)
118
+ end
119
+
120
+ end
121
+
122
+ describe "redeeming beer" do
123
+ before(:each) do
124
+ setup
125
+ end
126
+
127
+ it "should respond to the command !redeem_beer" do
128
+ @beer.should_receive(:redeem_beer)
129
+ sendmsg('!redeem_beer Foo')
130
+
131
+ end
132
+
133
+ it "should increase my balance with the opposite party (redeeming is the same as giving)" do
134
+ sendmsg '!demand_beer albert'
135
+ sendmsg '!demand_beer albert'
136
+ bal = @beer.balance('Josh', 'albert')
137
+ # puts "------ #{bal}"
138
+ sendmsg '!redeem_beer albert'
139
+ @beer.balance('Josh', 'albert').should eql(bal + 1)
140
+ end
141
+
142
+ it "should not increase my balance if it is already zero" do
143
+ @beer.should_receive('balance').with('Josh', 'bill').and_return(0)
144
+ sendmsg("!redeem_beer bill").should =~ /to begin with/
145
+ # @beer.balance('Josh', 'bill').should eql(bal)
146
+ end
147
+ end
148
+
149
+
150
+ describe "should have the correct reply for" do
151
+
152
+ before(:each) do
153
+ setup
154
+ end
155
+
156
+ it "negative balances (I owe beers)" do
157
+ @beer.should_receive('balance').with('Josh', 'james').and_return(1)
158
+ sendmsg("!give_beer james").should =~ /you now owe james .* beer/
159
+ end
160
+
161
+ it "positive balances (I am owed beers)" do
162
+ @beer.balances['albert'] = {}
163
+ @beer.balances['albert']['Josh'] = 1
164
+ sendmsg("!demand_beer albert").should =~ /albert now owes you .* beer/
165
+ end
166
+
167
+ it "zero balance (all even)" do
168
+ @beer.should_receive('balance').with('Josh', 'albert').and_return(0)
169
+ sendmsg("!give_beer albert").should =~ /albert .* even/
170
+ end
171
+
172
+ it "missing all arguments" do
173
+ sendmsg("!give_beer").should =~ /don't know whom/
174
+ end
175
+
176
+ # it "non-integer 2nd arg" do
177
+ # sendmsg("!give_beer albert non-int").should =~ /I don't accept non-integer amounts/
178
+ # end
179
+
180
+ end
181
+
182
+ describe "!balance command" do
183
+ before(:each) do
184
+ setup
185
+ end
186
+
187
+ it "should respond to the !balance command" do
188
+ @beer.should_receive(:balance_cmd)
189
+ sendmsg("!balance")
190
+ end
191
+
192
+ it "should require an argument of a user" do
193
+ sendmsg("!balance").should be_nil
194
+ end
195
+
196
+ describe "should return the correct balance for" do
197
+ it "negative balances" do
198
+ sendmsg("!demand_beer maxim 2")
199
+ # @beer.balance('Josh', 'max').should eql(-2)
200
+ # @beer.should_receive('balance').with('Josh', 'Foo').and_return(-1)
201
+ sendmsg("!balance maxim").should =~ /owes you 2 beers/
202
+ end
203
+
204
+ it "positive balances" do
205
+ sendmsg("!give_beer maximo 9")
206
+ # @beer.balance('Josh', 'max').should eql(7)
207
+ # @beer.should_receive('balance').with('Josh', 'Foo').and_return(1)
208
+ sendmsg("!balance maximo").should =~ /You owe .* 9 beers/
209
+ end
210
+
211
+ it "non-existent balances" do
212
+ sendmsg("!balance Fsdfsdfsdfsdfsdfoo").should =~ /transactions/
213
+ end
214
+
215
+ end
216
+ end
217
+
218
+ describe "beer_transactiona and balance" do
219
+ it "should handle equivalent transactions equivalently" do
220
+ pending
221
+ end
222
+
223
+
224
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'test'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ bot = CampfireBot::Bot.instance
7
+ require "#{BOT_ROOT}/plugins/bugzilla.rb"
8
+
9
+ describe "Bugzilla plugin" do
10
+ before(:each) do
11
+ require 'shorturl'
12
+ ShortURL.stub!(:shorten).
13
+ with("https://bugzilla/show_bug.cgi?id=1234").
14
+ and_return("http://rubyurl.com/xyz")
15
+ @bot = CampfireBot::Bot.instance
16
+ @bot.stub!(:config).and_return('nickname' => 'Bot'
17
+ #,'bugzilla_debug_enabled' => true
18
+ )
19
+ @bugzilla = Bugzilla.new
20
+ @bugzilla.stub!(:http_fetch_body).
21
+ with("https://bugzilla/show_bug.cgi?id=1234").
22
+ and_return(
23
+ "<html>
24
+ <head>
25
+ <title>Bug 1234 - Fix widget behavior</title>
26
+ </head>
27
+ </html>")
28
+ CampfireBot::Plugin.registered_plugins['Bugzilla'] = @bugzilla
29
+ @message = CampfireBot::Message.new(:room => Tinder::Room.new(42, "Main"),
30
+ :person => 'Josh')
31
+ end
32
+
33
+ after(:each) do
34
+ if File.exist? @bugzilla.data_file
35
+ File.unlink(@bugzilla.data_file)
36
+ end
37
+ end
38
+
39
+ it "should respond to the command !bug" do
40
+ @bugzilla.should_receive(:describe_command)
41
+ @message[:message] = "!bug"
42
+ @bot.send(:handle_message, @message)
43
+ end
44
+
45
+ it "should respond to !bug with a bug title" do
46
+ @message.should_receive(:speak).
47
+ with("Bug 1234 - Fix widget behavior (http://rubyurl.com/xyz)")
48
+ @message[:message] = "!bug 1234"
49
+ @bot.send(:handle_message, @message)
50
+ end
51
+
52
+ it "should overhear mentions of 'bug NNNN' and offer the title" do
53
+ @message.should_receive(:speak).
54
+ with("Bug 1234 - Fix widget behavior (http://rubyurl.com/xyz)")
55
+ @message[:message] = "What about bug 1234?"
56
+ @bot.send(:handle_message, @message)
57
+ end
58
+
59
+ it "should not repeat a bug title twice in a short time when overhearing" do
60
+ @message.should_receive(:speak).
61
+ with("Bug 1234 - Fix widget behavior (http://rubyurl.com/xyz)")
62
+ @message[:message] = "What about bug 1234?"
63
+ @bot.send(:handle_message, @message)
64
+
65
+ @message2 = CampfireBot::Message.new(:room => Tinder::Room.new(42, "Main"),
66
+ :person => 'Josh')
67
+ @message2.should_not_receive(:speak)
68
+ @message2[:message] = "I fixed bug 1234, too."
69
+ @bot.send(:handle_message, @message2)
70
+ end
71
+ end
72
+
73
+ describe "http_fetch_body method" do
74
+ before(:each) do
75
+ end
76
+ # Probably this method should live elsewhere, and in that location be
77
+ # broken down into smaller methods to facilitate testing.
78
+ it "should return the body of an HTTP response" do
79
+ pending
80
+ end
81
+ it "should raise an exception for non-success status" do
82
+ pending
83
+ end
84
+ it "should use netrc credentials when possible" do
85
+ pending
86
+ end
87
+ it "should support https when necessary" do
88
+ pending
89
+ end
90
+ end