rita 0.1.0 → 5.0.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +19 -0
  3. data/.rubocop.yml +51 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +16 -0
  6. data/CONTRIBUTING.md +18 -0
  7. data/Gemfile +5 -0
  8. data/{LICENSE.txt → LICENSE} +1 -3
  9. data/README.md +17 -24
  10. data/Rakefile +5 -5
  11. data/bin/lita +7 -0
  12. data/lib/lita/adapter.rb +147 -0
  13. data/lib/lita/adapters/shell.rb +126 -0
  14. data/lib/lita/adapters/test.rb +62 -0
  15. data/lib/lita/authorization.rb +112 -0
  16. data/lib/lita/callback.rb +39 -0
  17. data/lib/lita/cli.rb +218 -0
  18. data/lib/lita/configurable.rb +47 -0
  19. data/lib/lita/configuration_builder.rb +247 -0
  20. data/lib/lita/configuration_validator.rb +95 -0
  21. data/lib/lita/default_configuration.rb +122 -0
  22. data/lib/lita/errors.rb +25 -0
  23. data/lib/lita/handler/chat_router.rb +141 -0
  24. data/lib/lita/handler/common.rb +208 -0
  25. data/lib/lita/handler/event_router.rb +84 -0
  26. data/lib/lita/handler/http_router.rb +31 -0
  27. data/lib/lita/handler.rb +15 -0
  28. data/lib/lita/handlers/authorization.rb +129 -0
  29. data/lib/lita/handlers/help.rb +171 -0
  30. data/lib/lita/handlers/info.rb +66 -0
  31. data/lib/lita/handlers/room.rb +36 -0
  32. data/lib/lita/handlers/users.rb +37 -0
  33. data/lib/lita/http_callback.rb +46 -0
  34. data/lib/lita/http_route.rb +83 -0
  35. data/lib/lita/logger.rb +43 -0
  36. data/lib/lita/message.rb +124 -0
  37. data/lib/lita/middleware_registry.rb +39 -0
  38. data/lib/lita/namespace.rb +29 -0
  39. data/lib/lita/plugin_builder.rb +43 -0
  40. data/lib/lita/rack_app.rb +100 -0
  41. data/lib/lita/registry.rb +164 -0
  42. data/lib/lita/response.rb +65 -0
  43. data/lib/lita/robot.rb +273 -0
  44. data/lib/lita/room.rb +119 -0
  45. data/lib/lita/route_validator.rb +82 -0
  46. data/lib/lita/rspec/handler.rb +127 -0
  47. data/lib/lita/rspec/matchers/chat_route_matcher.rb +53 -0
  48. data/lib/lita/rspec/matchers/event_route_matcher.rb +29 -0
  49. data/lib/lita/rspec/matchers/http_route_matcher.rb +34 -0
  50. data/lib/lita/rspec.rb +48 -0
  51. data/lib/lita/source.rb +81 -0
  52. data/lib/lita/store.rb +23 -0
  53. data/lib/lita/target.rb +3 -0
  54. data/lib/lita/template.rb +71 -0
  55. data/lib/lita/template_resolver.rb +52 -0
  56. data/lib/lita/timer.rb +49 -0
  57. data/lib/lita/user.rb +157 -0
  58. data/lib/lita/util.rb +31 -0
  59. data/lib/lita/version.rb +6 -0
  60. data/lib/lita.rb +166 -0
  61. data/lib/rita.rb +2 -7
  62. data/rita.gemspec +50 -0
  63. data/spec/lita/adapter_spec.rb +54 -0
  64. data/spec/lita/adapters/shell_spec.rb +99 -0
  65. data/spec/lita/authorization_spec.rb +122 -0
  66. data/spec/lita/configuration_builder_spec.rb +247 -0
  67. data/spec/lita/configuration_validator_spec.rb +114 -0
  68. data/spec/lita/default_configuration_spec.rb +242 -0
  69. data/spec/lita/handler/chat_router_spec.rb +236 -0
  70. data/spec/lita/handler/common_spec.rb +289 -0
  71. data/spec/lita/handler/event_router_spec.rb +121 -0
  72. data/spec/lita/handler/http_router_spec.rb +155 -0
  73. data/spec/lita/handler_spec.rb +62 -0
  74. data/spec/lita/handlers/authorization_spec.rb +111 -0
  75. data/spec/lita/handlers/help_spec.rb +124 -0
  76. data/spec/lita/handlers/info_spec.rb +67 -0
  77. data/spec/lita/handlers/room_spec.rb +24 -0
  78. data/spec/lita/handlers/users_spec.rb +35 -0
  79. data/spec/lita/logger_spec.rb +28 -0
  80. data/spec/lita/message_spec.rb +178 -0
  81. data/spec/lita/plugin_builder_spec.rb +41 -0
  82. data/spec/lita/response_spec.rb +62 -0
  83. data/spec/lita/robot_spec.rb +285 -0
  84. data/spec/lita/room_spec.rb +136 -0
  85. data/spec/lita/rspec/handler_spec.rb +33 -0
  86. data/spec/lita/rspec_spec.rb +162 -0
  87. data/spec/lita/source_spec.rb +68 -0
  88. data/spec/lita/store_spec.rb +23 -0
  89. data/spec/lita/template_resolver_spec.rb +42 -0
  90. data/spec/lita/template_spec.rb +52 -0
  91. data/spec/lita/timer_spec.rb +32 -0
  92. data/spec/lita/user_spec.rb +167 -0
  93. data/spec/lita/util_spec.rb +18 -0
  94. data/spec/lita_spec.rb +227 -0
  95. data/spec/spec_helper.rb +35 -0
  96. data/spec/templates/basic.erb +1 -0
  97. data/spec/templates/basic.irc.erb +1 -0
  98. data/spec/templates/helpers.erb +1 -0
  99. data/spec/templates/interpolated.erb +1 -0
  100. data/templates/locales/en.yml +137 -0
  101. data/templates/plugin/Gemfile +5 -0
  102. data/templates/plugin/README.tt +29 -0
  103. data/templates/plugin/Rakefile +8 -0
  104. data/templates/plugin/gemspec.tt +27 -0
  105. data/templates/plugin/gitignore +18 -0
  106. data/templates/plugin/lib/lita/plugin_type/plugin.tt +19 -0
  107. data/templates/plugin/lib/plugin.tt +16 -0
  108. data/templates/plugin/locales/en.yml.tt +4 -0
  109. data/templates/plugin/spec/lita/plugin_type/plugin_spec.tt +6 -0
  110. data/templates/plugin/spec/spec_helper.tt +8 -0
  111. data/templates/plugin/templates/gitkeep +0 -0
  112. data/templates/robot/Gemfile +5 -0
  113. data/templates/robot/lita_config.rb +28 -0
  114. metadata +386 -20
  115. data/.standard.yml +0 -3
  116. data/CHANGELOG.md +0 -5
  117. data/CODE_OF_CONDUCT.md +0 -132
  118. data/lib/rita/version.rb +0 -5
  119. data/sig/rita.rbs +0 -4
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Lita::Message do
6
+ let(:mention_name) { "LitaBot" }
7
+
8
+ let(:robot) do
9
+ instance_double("Lita::Robot", name: "Lita", mention_name: mention_name, alias: ".")
10
+ end
11
+
12
+ let(:source) { instance_double("Lita::Source") }
13
+
14
+ subject do
15
+ described_class.new(robot, "Hello", source)
16
+ end
17
+
18
+ it "has a body" do
19
+ expect(subject.body).to eq("Hello")
20
+ end
21
+
22
+ it "has a source" do
23
+ expect(subject.source).to eq(source)
24
+ end
25
+
26
+ describe "#extensions" do
27
+ it "can be populated with arbitrary data" do
28
+ subject.extensions[:foo] = :bar
29
+
30
+ expect(subject.extensions[:foo]).to eq(:bar)
31
+ end
32
+ end
33
+
34
+ describe "#args" do
35
+ it "returns an array of the 2nd through nth word in the message" do
36
+ subject = described_class.new(robot, "args foo bar", source)
37
+ expect(subject.args).to eq(%w[foo bar])
38
+ end
39
+
40
+ it "escapes messages that have mismatched quotes" do
41
+ subject = described_class.new(robot, "args it's working", source)
42
+ expect(subject.args).to eq(%w[it's working])
43
+ end
44
+ end
45
+
46
+ describe "#command!" do
47
+ it "marks a message as a command" do
48
+ subject.command!
49
+ expect(subject).to be_a_command
50
+ end
51
+ end
52
+
53
+ describe "#command?" do
54
+ context "when the message is addressed to the robot" do
55
+ subject { described_class.new(robot, "#{robot.mention_name}: hello", source) }
56
+
57
+ it "is true" do
58
+ expect(subject).to be_a_command
59
+ end
60
+ end
61
+
62
+ context "when the message is addressed to the robot with different capitalization" do
63
+ subject { described_class.new(robot, "#{robot.mention_name.upcase}: hello", source) }
64
+
65
+ it "is true" do
66
+ expect(subject).to be_a_command
67
+ end
68
+ end
69
+
70
+ context "when the message is addressed to the robot with a comma" do
71
+ subject { described_class.new(robot, "#{robot.mention_name.upcase}, hello", source) }
72
+
73
+ it "is true" do
74
+ expect(subject).to be_a_command
75
+ end
76
+ end
77
+
78
+ context "when the message is addressed to the robot with no trailing punctuation" do
79
+ subject { described_class.new(robot, "#{robot.mention_name.upcase} hello", source) }
80
+
81
+ it "is true" do
82
+ expect(subject).to be_a_command
83
+ end
84
+ end
85
+
86
+ context "when the message is addressed to the bot via alias with no space after it" do
87
+ subject { described_class.new(robot, "#{robot.alias}hello", source) }
88
+
89
+ it "is true" do
90
+ expect(subject).to be_a_command
91
+ end
92
+ end
93
+
94
+ context "when the message is addressed to the bot via alias with space after it" do
95
+ subject { described_class.new(robot, "#{robot.alias} hello", source) }
96
+
97
+ it "is true" do
98
+ expect(subject).to be_a_command
99
+ end
100
+ end
101
+
102
+ context "when the message incidentally starts with the mention name" do
103
+ let(:mention_name) { "sa" }
104
+
105
+ subject { described_class.new(robot, "salmon", source) }
106
+
107
+ it "is false" do
108
+ expect(subject).not_to be_a_command
109
+ end
110
+
111
+ it "does not affect the message body" do
112
+ expect(subject.body).to eq("salmon")
113
+ end
114
+ end
115
+
116
+ context "when a multi-line message contains a command past the beginning of the message" do
117
+ subject { described_class.new(robot, "```\n#{robot.mention_name}: hello\n```", source) }
118
+
119
+ it "is false" do
120
+ expect(subject).not_to be_a_command
121
+ end
122
+ end
123
+
124
+ it "is false when the message is not addressed to the Robot" do
125
+ expect(subject).not_to be_a_command
126
+ end
127
+ end
128
+
129
+ describe "#user" do
130
+ it "delegates to #source" do
131
+ expect(subject.source).to receive(:user)
132
+ subject.user
133
+ end
134
+ end
135
+
136
+ describe "#room_object" do
137
+ it "delegates to #source" do
138
+ expect(subject.source).to receive(:room_object)
139
+ subject.room_object
140
+ end
141
+ end
142
+
143
+ describe "#private_message?" do
144
+ it "delegates to #source" do
145
+ expect(subject.source).to receive(:private_message?)
146
+ subject.private_message?
147
+ end
148
+ end
149
+
150
+ describe "#reply" do
151
+ it "sends strings back to the source through the robot" do
152
+ expect(robot).to receive(:send_messages).with(source, "foo", "bar")
153
+ subject.reply("foo", "bar")
154
+ end
155
+ end
156
+
157
+ describe "#reply_privately" do
158
+ it "sends strings directly to the source user" do
159
+ subject = described_class.new(
160
+ robot,
161
+ "Hello",
162
+ Lita::Source.new(user: "Carl", room: "#room")
163
+ )
164
+ expect(robot).to receive(:send_messages) do |source, *strings|
165
+ expect(source).to be_a_private_message
166
+ expect(strings).to eq(%w[foo bar])
167
+ end
168
+ subject.reply_privately("foo", "bar")
169
+ end
170
+ end
171
+
172
+ describe "#reply_with_mention" do
173
+ it "prefixes strings with a user mention and sends them back to the source" do
174
+ expect(robot).to receive(:send_messages_with_mention).with(source, "foo", "bar")
175
+ subject.reply_with_mention("foo", "bar")
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Lita::PluginBuilder, lita: true do
6
+ let(:robot) { instance_double("Lita::Robot") }
7
+ subject { plugin.new(robot) }
8
+
9
+ describe "#build_adapter" do
10
+ let(:builder) do
11
+ described_class.new(:test_adapter) do
12
+ def run
13
+ self.class.namespace
14
+ end
15
+ end
16
+ end
17
+
18
+ let(:plugin) { builder.build_adapter }
19
+
20
+ it "builds an adapter" do
21
+ expect(subject.run).to eq("test_adapter")
22
+ end
23
+ end
24
+
25
+ describe "#build_handler" do
26
+ builder = described_class.new(:test_handler) do
27
+ route(/namespace/) { |response| response.reply(self.class.namespace) }
28
+ end
29
+
30
+ plugin = builder.build_handler
31
+
32
+ describe plugin, lita_handler: true do
33
+ before { registry.register_handler(plugin) }
34
+
35
+ it "builds a handler from a block" do
36
+ send_message("namespace")
37
+ expect(replies.last).to eq("test_handler")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Lita::Response do
6
+ subject { described_class.new(message, instance_double("Regexp")) }
7
+
8
+ let(:message) { instance_double("Lita::Message").as_null_object }
9
+
10
+ %i[args reply reply_privately reply_with_mention user command?].each do |method|
11
+ it "delegates :#{method} to #message" do
12
+ expect(message).to receive(method)
13
+ subject.public_send(method)
14
+ end
15
+ end
16
+
17
+ describe "#matches" do
18
+ it "matches the pattern against the message" do
19
+ expect(message).to receive(:match).with(subject.pattern)
20
+ subject.matches
21
+ end
22
+ end
23
+
24
+ describe "#match_data" do
25
+ let(:body) { instance_double("String") }
26
+
27
+ it "matches the message body against the pattern" do
28
+ allow(message).to receive(:body).and_return(body)
29
+ expect(subject.pattern).to receive(:match).with(message.body)
30
+ subject.match_data
31
+ end
32
+ end
33
+
34
+ describe "#extensions" do
35
+ it "can be populated with arbitrary data" do
36
+ subject.extensions[:foo] = :bar
37
+
38
+ expect(subject.extensions[:foo]).to eq(:bar)
39
+ end
40
+ end
41
+
42
+ describe "#user" do
43
+ it "delegates to #message" do
44
+ expect(subject.message).to receive(:user)
45
+ subject.user
46
+ end
47
+ end
48
+
49
+ describe "#room" do
50
+ it "delegates to #message" do
51
+ expect(subject.message).to receive(:room_object)
52
+ subject.room
53
+ end
54
+ end
55
+
56
+ describe "#private_message?" do
57
+ it "delegates to #message" do
58
+ expect(subject.message).to receive(:private_message?)
59
+ subject.private_message?
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,285 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Lita::Robot, lita: true do
6
+ subject { described_class.new(registry) }
7
+
8
+ before { registry.register_adapter(:shell, Lita::Adapters::Shell) }
9
+
10
+ it "triggers a loaded event after initialization" do
11
+ expect_any_instance_of(described_class).to receive(:trigger).with(:loaded, room_ids: [])
12
+ subject
13
+ end
14
+
15
+ context "when there are previously persisted rooms" do
16
+ before { %w[#foo #bar].each { |id| Lita.redis.sadd("persisted_rooms", id) } }
17
+
18
+ it "receives the room_ids in the payload" do
19
+ expect_any_instance_of(described_class).to receive(:trigger).with(
20
+ :loaded,
21
+ room_ids: %w[#foo #bar].sort,
22
+ )
23
+ subject
24
+ end
25
+ end
26
+
27
+ it "can have its name changed" do
28
+ subject.name = "Bongo"
29
+
30
+ expect(subject.name).to eq("Bongo")
31
+ end
32
+
33
+ it "can have its mention name changed" do
34
+ subject.mention_name = "wongo"
35
+
36
+ expect(subject.mention_name).to eq("wongo")
37
+ end
38
+
39
+ it "exposes Adapter#mention_format" do
40
+ expect(subject.mention_format(subject.mention_name)).to eq("Lita:")
41
+ end
42
+
43
+ it "exposes Adapter#roster" do
44
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:roster)
45
+
46
+ subject.roster(instance_double("Lita::Room"))
47
+ end
48
+
49
+ it "exposes Adapter#chat_service" do
50
+ expect { subject.chat_service }.not_to raise_error
51
+ end
52
+
53
+ context "with registered handlers" do
54
+ let(:handler_1) { Class.new(Lita::Handler) { namespace :test } }
55
+ let(:handler_2) { Class.new(Lita::Handler) { namespace :test } }
56
+
57
+ before do
58
+ registry.register_handler(handler_1)
59
+ registry.register_handler(handler_2)
60
+ end
61
+
62
+ describe "#receive" do
63
+ it "dispatches messages to every registered handler" do
64
+ expect(handler_1).to receive(:dispatch).with(subject, "foo")
65
+ expect(handler_2).to receive(:dispatch).with(subject, "foo")
66
+ subject.receive("foo")
67
+ end
68
+ end
69
+
70
+ describe "#trigger" do
71
+ it "triggers the supplied event on all registered handlers" do
72
+ expect(handler_1).to receive(:trigger).with(subject, :foo, bar: "baz")
73
+ expect(handler_2).to receive(:trigger).with(subject, :foo, bar: "baz")
74
+ subject.trigger(:foo, bar: "baz")
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#run" do
80
+ let(:thread) { instance_double("Thread", :abort_on_exception= => true, join: nil) }
81
+
82
+ before do
83
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:run)
84
+ allow_any_instance_of(Puma::Server).to receive(:run)
85
+ allow_any_instance_of(Puma::Server).to receive(:add_tcp_listener)
86
+
87
+ allow(Thread).to receive(:new) do |&block|
88
+ block.call
89
+ thread
90
+ end
91
+ end
92
+
93
+ it "starts the adapter" do
94
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:run)
95
+ subject.run
96
+ end
97
+
98
+ it "starts the web server" do
99
+ expect_any_instance_of(Puma::Server).to receive(:run)
100
+ subject.run
101
+ end
102
+
103
+ it "rescues interrupts and calls #shut_down" do
104
+ allow_any_instance_of(
105
+ Lita::Adapters::Shell
106
+ ).to receive(:run).and_raise(Interrupt)
107
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:shut_down)
108
+ subject.run
109
+ end
110
+
111
+ it "logs and quits if the specified adapter can't be found" do
112
+ registry.config.robot.adapter = :does_not_exist
113
+ expect(subject.logger).to receive(:fatal).with(/Unknown adapter/)
114
+ expect { subject.run }.to raise_error(SystemExit)
115
+ end
116
+
117
+ it "logs and aborts if the web server's port is in use" do
118
+ allow_any_instance_of(Puma::Server).to receive(:add_tcp_listener).and_raise(Errno::EADDRINUSE)
119
+
120
+ expect(subject.logger).to receive(:fatal).with(/web server/)
121
+ expect { subject.run }.to raise_error(SystemExit)
122
+ end
123
+
124
+ it "logs and aborts if the web server's port is privileged" do
125
+ allow_any_instance_of(Puma::Server).to receive(:add_tcp_listener).and_raise(Errno::EACCES)
126
+
127
+ expect(subject.logger).to receive(:fatal).with(/web server/)
128
+ expect { subject.run }.to raise_error(SystemExit)
129
+ end
130
+ end
131
+
132
+ describe "#join" do
133
+ before do
134
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:join)
135
+ end
136
+
137
+ context "when a Room object exists" do
138
+ let!(:room) { Lita::Room.create_or_update(1, name: "#lita.io") }
139
+
140
+ it "passes the room ID to the adapter when a string argument is provided" do
141
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:join).with("1")
142
+
143
+ subject.join("#lita.io")
144
+ end
145
+
146
+ it "passes the room ID to the adapter when a Room argument is provided" do
147
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:join).with("1")
148
+
149
+ subject.join(room)
150
+ end
151
+
152
+ it "adds the room ID to the persisted list" do
153
+ subject.join("#lita.io")
154
+
155
+ expect(subject.persisted_rooms).to include("1")
156
+ end
157
+ end
158
+
159
+ context "when no Room object exists" do
160
+ it "delegates to the adapter with the raw argument" do
161
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:join).with("#lita.io")
162
+
163
+ subject.join("#lita.io")
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "#part" do
169
+ before do
170
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:join)
171
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:part)
172
+ end
173
+
174
+ context "when a Room object exists" do
175
+ let!(:room) { Lita::Room.create_or_update(1, name: "#lita.io") }
176
+
177
+ it "passes the room ID to the adapter when a string argument is provided" do
178
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:part).with("1")
179
+
180
+ subject.part("#lita.io")
181
+ end
182
+
183
+ it "passes the room ID to the adapter when a Room argument is provided" do
184
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:part).with("1")
185
+
186
+ subject.part(room)
187
+ end
188
+
189
+ it "removes the room ID from the persisted list" do
190
+ subject.join("#lita.io")
191
+
192
+ subject.part("#lita.io")
193
+
194
+ expect(subject.persisted_rooms).not_to include("1")
195
+ end
196
+ end
197
+
198
+ context "when no Room object exists" do
199
+ it "delegates to the adapter with the raw argument" do
200
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:part).with("#lita.io")
201
+
202
+ subject.part("#lita.io")
203
+ end
204
+ end
205
+ end
206
+
207
+ describe "#send_message" do
208
+ let(:source) { instance_double("Lita::Source") }
209
+
210
+ it "delegates to the adapter" do
211
+ expect_any_instance_of(
212
+ Lita::Adapters::Shell
213
+ ).to receive(:send_messages).with(
214
+ source, %w[foo bar]
215
+ )
216
+ subject.send_messages(source, "foo", "bar")
217
+ end
218
+ end
219
+
220
+ describe "#send_message_with_mention" do
221
+ let(:user) { instance_double("Lita::User", mention_name: "carl") }
222
+ let(:source) { instance_double("Lita::Source", private_message?: false, user: user) }
223
+
224
+ it "calls #send_message with the strings, prefixed with the user's mention name" do
225
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:mention_format).with(
226
+ "carl"
227
+ ).and_return("carl:")
228
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:send_messages).with(
229
+ source,
230
+ ["carl: foo", "carl: bar"]
231
+ )
232
+
233
+ subject.send_messages_with_mention(source, "foo", "bar")
234
+ end
235
+
236
+ it "strips whitespace from both sides of the formatted mention name" do
237
+ allow_any_instance_of(Lita::Adapters::Shell).to receive(:mention_format).with(
238
+ "carl"
239
+ ).and_return(" carl: ")
240
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:send_messages).with(
241
+ source,
242
+ ["carl: foo", "carl: bar"]
243
+ )
244
+
245
+ subject.send_messages_with_mention(source, "foo", "bar")
246
+ end
247
+
248
+ it "calls #send_message directly if the original message was sent privately" do
249
+ allow(source).to receive(:private_message?).and_return(true)
250
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:send_messages).with(
251
+ source,
252
+ %w[foo bar]
253
+ )
254
+
255
+ subject.send_messages_with_mention(source, "foo", "bar")
256
+ end
257
+ end
258
+
259
+ describe "#set_topic" do
260
+ let(:source) { instance_double("Lita::Source") }
261
+
262
+ it "delegates to the adapter" do
263
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:set_topic).with(
264
+ source,
265
+ "New topic"
266
+ )
267
+ subject.set_topic(source, "New topic")
268
+ end
269
+ end
270
+
271
+ describe "#shut_down" do
272
+ before { allow_any_instance_of(Lita::Adapters::Shell).to receive(:puts) }
273
+
274
+ it "gracefully stops the adapter" do
275
+ expect_any_instance_of(Lita::Adapters::Shell).to receive(:shut_down)
276
+ subject.shut_down
277
+ end
278
+
279
+ it "triggers events for shut_down_started and shut_down_complete" do
280
+ expect(subject).to receive(:trigger).with(:shut_down_started).ordered
281
+ expect(subject).to receive(:trigger).with(:shut_down_complete).ordered
282
+ subject.shut_down
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Lita::Room, lita: true do
6
+ describe ".create_or_update" do
7
+ subject { described_class.find_by_id(1) }
8
+
9
+ context "when no room with the given ID already exists" do
10
+ it "creates the room" do
11
+ described_class.create_or_update(1, name: "foo")
12
+
13
+ expect(subject.name).to eq("foo")
14
+ end
15
+ end
16
+
17
+ context "when a room with the given ID already exists" do
18
+ before { described_class.create_or_update(1, name: "foo") }
19
+
20
+ it "merges in new metadata" do
21
+ described_class.create_or_update(1, foo: "bar")
22
+
23
+ expect(subject.name).to eq("foo")
24
+ expect(subject.metadata["foo"]).to eq("bar")
25
+ end
26
+ end
27
+ end
28
+
29
+ describe ".find_by_id" do
30
+ context "when a matching room exists" do
31
+ before { described_class.new(1).save }
32
+
33
+ it "is found by ID" do
34
+ expect(described_class.find_by_id(1).id).to eq("1")
35
+ end
36
+ end
37
+
38
+ context "when no matching room exists" do
39
+ it "is not found" do
40
+ expect(described_class.find_by_id(1)).to be_nil
41
+ end
42
+ end
43
+ end
44
+
45
+ describe ".find_by_name" do
46
+ context "when a matching room exists" do
47
+ before { described_class.new(1, name: "foo").save }
48
+
49
+ it "is found by name" do
50
+ expect(described_class.find_by_name("foo").id).to eq("1")
51
+ end
52
+ end
53
+
54
+ context "when no matching room exists" do
55
+ it "is not found" do
56
+ expect(described_class.find_by_name("foo")).to be_nil
57
+ end
58
+ end
59
+ end
60
+
61
+ describe ".fuzzy_find" do
62
+ context "when a matching room exists" do
63
+ before { described_class.new(1, name: "foo").save }
64
+
65
+ it "is found by ID" do
66
+ expect(described_class.fuzzy_find(1).id).to eq("1")
67
+ end
68
+
69
+ it "is found by name" do
70
+ expect(described_class.fuzzy_find("foo").id).to eq("1")
71
+ end
72
+ end
73
+
74
+ context "when no matching room exists" do
75
+ it "is not found by ID" do
76
+ expect(described_class.fuzzy_find(1)).to be_nil
77
+ end
78
+
79
+ it "is not found by name" do
80
+ expect(described_class.fuzzy_find("foo")).to be_nil
81
+ end
82
+ end
83
+ end
84
+
85
+ context "with only an ID" do
86
+ subject { described_class.new(1) }
87
+
88
+ it "has a string ID" do
89
+ expect(subject.id).to eq("1")
90
+ end
91
+
92
+ it "is named with its ID" do
93
+ expect(subject.name).to eq("1")
94
+ end
95
+ end
96
+
97
+ context "with metadata" do
98
+ subject { described_class.new(1, foo: :bar) }
99
+
100
+ it "stores the metadata with string keys" do
101
+ expect(subject.metadata["foo"]).to eq(:bar)
102
+ end
103
+ end
104
+
105
+ describe "#==" do
106
+ subject { described_class.new(1) }
107
+
108
+ context "when the other room has the same ID" do
109
+ let(:other) { described_class.new(1) }
110
+
111
+ it "is equal" do
112
+ expect(subject).to eq(other)
113
+ end
114
+ end
115
+
116
+ context "when the other room has a different ID" do
117
+ let(:other) { described_class.new(2) }
118
+
119
+ it "is not equal" do
120
+ expect(subject).not_to eq(other)
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "#save" do
126
+ context "with metadata not including name" do
127
+ subject { described_class.new(1, {}) }
128
+
129
+ it "adds the name to the metadata" do
130
+ subject.save
131
+
132
+ expect(subject.metadata["name"]).to eq("1")
133
+ end
134
+ end
135
+ end
136
+ end