listen 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen::File do
4
+ let(:record) { double(Listen::Record, async: double(set_path: true, unset_path: true)) }
5
+ let(:path) { Pathname.new(Dir.pwd) }
6
+ around { |example| fixtures { |path| example.run } }
7
+ before { Celluloid::Actor.stub(:[]).with(:listen_record) { record } }
8
+
9
+ describe "#change" do
10
+ let(:file_path) { path.join('file.rb') }
11
+ let(:file) { Listen::File.new(file_path) }
12
+ let(:expected_data) {
13
+ if darwin?
14
+ { type: 'File', mtime: kind_of(Float), mode: kind_of(Integer), md5: kind_of(String) }
15
+ else
16
+ { type: 'File', mtime: kind_of(Float), mode: kind_of(Integer) }
17
+ end
18
+ }
19
+
20
+ context "path present in record" do
21
+ let(:record_mtime) { nil }
22
+ let(:record_md5) { nil }
23
+ let(:record_mode) { nil }
24
+ let(:record_data) { { type: 'File', mtime: record_mtime, md5: record_md5, mode: record_mode } }
25
+ before { record.stub_chain(:future, :file_data) { double(value: record_data) } }
26
+
27
+ context "non-existing path" do
28
+ it "returns added" do
29
+ expect(file.change).to eq :removed
30
+ end
31
+ it "sets path in record" do
32
+ expect(record.async).to receive(:unset_path).with(file_path)
33
+ file.change
34
+ end
35
+ end
36
+
37
+ context "existing path" do
38
+ around { |example| touch file_path; example.run }
39
+
40
+ context "old record path mtime" do
41
+ let(:record_mtime) { (Time.now - 1).to_f }
42
+
43
+ it "returns modified" do
44
+ expect(file.change).to eq :modified
45
+ end
46
+
47
+ it "sets path in record with expected data" do
48
+ expect(record.async).to receive(:set_path).with(file_path, expected_data)
49
+ file.change
50
+ end
51
+ end
52
+
53
+ context "same record path mtime" do
54
+ let(:record_mtime) { ::File.lstat(file_path).mtime.to_f }
55
+ let(:record_mode) { ::File.lstat(file_path).mode }
56
+ let(:record_md5) { Digest::MD5.file(file_path).digest }
57
+
58
+ context "same record path mode" do
59
+ it "returns nil" do
60
+ expect(file.change).to be_nil
61
+ end
62
+ end
63
+
64
+ context "diferent record path mode" do
65
+ let(:record_mode) { 'foo' }
66
+
67
+ it "returns modified" do
68
+ expect(file.change).to eq :modified
69
+ end
70
+ end
71
+
72
+ context "same record path md5" do
73
+ it "returns nil" do
74
+ expect(file.change).to be_nil
75
+ end
76
+ end
77
+
78
+ context "different record path md5" do
79
+ let(:record_md5) { 'foo' }
80
+
81
+ it "returns modified" do
82
+ expect(file.change).to eq :modified
83
+ end
84
+ it "sets path in record with expected data" do
85
+ expect(record.async).to receive(:set_path).with(file_path, expected_data)
86
+ file.change
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
94
+ context "path not present in record" do
95
+ before { record.stub_chain(:future, :file_data) { double(value: {}) } }
96
+
97
+ context "existing path" do
98
+ around { |example| touch file_path; example.run }
99
+
100
+ it "returns added" do
101
+ expect(file.change).to eq :added
102
+ end
103
+
104
+ it "sets path in record with expected data" do
105
+ expect(record.async).to receive(:set_path).with(file_path, expected_data)
106
+ file.change
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,269 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen::Listener do
4
+ let(:listener) { Listen::Listener.new(options) }
5
+ let(:options) { {} }
6
+ let(:record) { double(Listen::Record, terminate: true, build: true) }
7
+ let(:silencer) { double(Listen::Silencer, terminate: true) }
8
+ let(:adapter) { double(Listen::Adapter::Base) }
9
+ let(:change_pool) { double(Listen::Change, terminate: true) }
10
+ let(:change_pool_async) { double('ChangePoolAsync') }
11
+ before {
12
+ Celluloid::Actor.stub(:[]).with(:listen_silencer) { silencer }
13
+ Celluloid::Actor.stub(:[]).with(:listen_adapter) { adapter }
14
+ Celluloid::Actor.stub(:[]).with(:listen_record) { record }
15
+ Celluloid::Actor.stub(:[]).with(:listen_change_pool) { change_pool }
16
+ }
17
+
18
+ describe "initialize" do
19
+ it "sets paused to false" do
20
+ expect(listener).not_to be_paused
21
+ end
22
+
23
+ it "sets block" do
24
+ block = Proc.new { |modified, added, removed| }
25
+ listener = Listen::Listener.new('lib', &block)
26
+ expect(listener.block).not_to be_nil
27
+ end
28
+
29
+ it "sets directories with realpath" do
30
+ listener = Listen::Listener.new('lib', 'spec')
31
+ expect(listener.directories).to eq [Pathname.new("#{Dir.pwd}/lib"), Pathname.new("#{Dir.pwd}/spec")]
32
+ end
33
+ end
34
+
35
+ describe "options" do
36
+ it "sets default options" do
37
+ expect(listener.options).to eq({
38
+ debug: false,
39
+ latency: nil,
40
+ force_polling: false,
41
+ polling_fallback_message: nil })
42
+ end
43
+
44
+ it "sets new options on initialize" do
45
+ listener = Listen::Listener.new('lib', latency: 1.234)
46
+ expect(listener.options).to eq({
47
+ debug: false,
48
+ latency: 1.234,
49
+ force_polling: false,
50
+ polling_fallback_message: nil })
51
+ end
52
+ end
53
+
54
+ describe "#start" do
55
+ before {
56
+ Listen::Silencer.stub(:new)
57
+ Listen::Change.stub(:pool)
58
+ Listen::Adapter.stub(:new)
59
+ Listen::Record.stub(:new)
60
+ Celluloid::Actor.stub(:[]=)
61
+ Celluloid.stub(:cores) { 1 }
62
+ adapter.stub_chain(:async, :start)
63
+ }
64
+
65
+ it "traps INT signal" do
66
+ expect(Signal).to receive(:trap).with('INT')
67
+ listener.start
68
+ end
69
+
70
+ it "registers silencer" do
71
+ expect(Listen::Silencer).to receive(:new).with(listener.options) { silencer }
72
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_silencer, silencer)
73
+ listener.start
74
+ end
75
+
76
+ it "registers change_pool" do
77
+ expect(Listen::Change).to receive(:pool).with(args: listener) { change_pool }
78
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_change_pool, change_pool)
79
+ listener.start
80
+ end
81
+
82
+ it "registers adaper" do
83
+ expect(Listen::Adapter).to receive(:new).with(listener) { adapter }
84
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_adapter, adapter)
85
+ listener.start
86
+ end
87
+
88
+ it "registers record" do
89
+ expect(Listen::Record).to receive(:new).with(listener) { record }
90
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_record, record)
91
+ listener.start
92
+ end
93
+
94
+ it "builds record" do
95
+ expect(record).to receive(:build)
96
+ listener.start
97
+ end
98
+
99
+ it "sets paused to false" do
100
+ listener.start
101
+ expect(listener.paused).to be_false
102
+ end
103
+
104
+ it "starts adapter asynchronously" do
105
+ async_stub = double
106
+ expect(adapter).to receive(:async) { async_stub }
107
+ expect(async_stub).to receive(:start)
108
+ listener.start
109
+ end
110
+
111
+ it "starts adapter asynchronously" do
112
+ async_stub = double
113
+ expect(adapter).to receive(:async) { async_stub }
114
+ expect(async_stub).to receive(:start)
115
+ listener.start
116
+ end
117
+
118
+ it "calls block on changes" do
119
+ listener.changes = [{ modified: 'foo' }]
120
+ block_stub = double('block')
121
+ listener.block = block_stub
122
+ expect(block_stub).to receive(:call).with(['foo'], [], [])
123
+ listener.start
124
+ sleep 0.01
125
+ end
126
+ end
127
+
128
+ describe "#stop" do
129
+ let(:thread) { double(kill: true) }
130
+ before {
131
+ Celluloid::Actor.stub(:kill)
132
+ listener.stub(:thread) { thread }
133
+ }
134
+
135
+ it "kills thread" do
136
+ expect(thread).to receive(:kill)
137
+ listener.stop
138
+ end
139
+
140
+ it "terminates silencer" do
141
+ expect(silencer).to receive(:terminate)
142
+ listener.stop
143
+ end
144
+
145
+ it "kills adapter" do
146
+ expect(Celluloid::Actor).to receive(:kill).with(adapter)
147
+ listener.stop
148
+ end
149
+
150
+ it "terminates change_pool" do
151
+ expect(change_pool).to receive(:terminate)
152
+ listener.stop
153
+ end
154
+
155
+ it "terminates record" do
156
+ expect(record).to receive(:terminate)
157
+ listener.stop
158
+ end
159
+ end
160
+
161
+ describe "#pause" do
162
+ it "sets paused to true" do
163
+ listener.pause
164
+ expect(listener.paused).to be_true
165
+ end
166
+ end
167
+
168
+ describe "#unpause" do
169
+ it "builds record" do
170
+ expect(record).to receive(:build)
171
+ listener.unpause
172
+ end
173
+
174
+ it "sets paused to false" do
175
+ record.stub(:build)
176
+ listener.unpause
177
+ expect(listener.paused).to be_false
178
+ end
179
+ end
180
+
181
+ describe "#paused?" do
182
+ it "returns true when paused" do
183
+ listener.paused = true
184
+ expect(listener).to be_paused
185
+ end
186
+ it "returns false when not paused (nil)" do
187
+ listener.paused = nil
188
+ expect(listener).not_to be_paused
189
+ end
190
+ it "returns false when not paused (false)" do
191
+ listener.paused = false
192
+ expect(listener).not_to be_paused
193
+ end
194
+ end
195
+
196
+ describe "#paused?" do
197
+ it "returns true when not paused (false)" do
198
+ listener.paused = false
199
+ expect(listener.listen?).to be_true
200
+ end
201
+ it "returns false when not paused (nil)" do
202
+ listener.paused = nil
203
+ expect(listener.listen?).to be_false
204
+ end
205
+ it "returns false when paused" do
206
+ listener.paused = true
207
+ expect(listener.listen?).to be_false
208
+ end
209
+ end
210
+
211
+ describe "#ignore" do
212
+ let(:new_silencer) { double(Listen::Silencer) }
213
+ before { Celluloid::Actor.stub(:[]=) }
214
+
215
+ it "resets silencer actor with new pattern" do
216
+ expect(Listen::Silencer).to receive(:new).with(hash_including(ignore: [nil, /foo/])) { new_silencer }
217
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_silencer, new_silencer)
218
+ listener.ignore(/foo/)
219
+ end
220
+
221
+ context "with existing ignore options" do
222
+ let(:options) { { ignore: /bar/ } }
223
+
224
+ it "adds up to existing ignore options" do
225
+ expect(Listen::Silencer).to receive(:new).with(hash_including(ignore: [/bar/, /foo/]))
226
+ listener.ignore(/foo/)
227
+ end
228
+ end
229
+
230
+ context "with existing ignore options (array)" do
231
+ let(:options) { { ignore: [/bar/] } }
232
+
233
+ it "adds up to existing ignore options" do
234
+ expect(Listen::Silencer).to receive(:new).with(hash_including(ignore: [[/bar/], /foo/]))
235
+ listener.ignore(/foo/)
236
+ end
237
+ end
238
+ end
239
+
240
+ describe "#ignore!" do
241
+ let(:new_silencer) { double(Listen::Silencer) }
242
+ before { Celluloid::Actor.stub(:[]=) }
243
+
244
+ it "resets silencer actor with new pattern" do
245
+ expect(Listen::Silencer).to receive(:new).with(hash_including(ignore!: /foo/)) { new_silencer }
246
+ expect(Celluloid::Actor).to receive(:[]=).with(:listen_silencer, new_silencer)
247
+ listener.ignore!(/foo/)
248
+ end
249
+
250
+ context "with existing ignore! options" do
251
+ let(:options) { { ignore!: /bar/ } }
252
+
253
+ it "overwrites existing ignore options" do
254
+ expect(Listen::Silencer).to receive(:new).with(hash_including(ignore!: [/foo/]))
255
+ listener.ignore!([/foo/])
256
+ end
257
+ end
258
+
259
+ context "with existing ignore options" do
260
+ let(:options) { { ignore: /bar/ } }
261
+
262
+ it "deletes ignore options" do
263
+ expect(Listen::Silencer).to receive(:new).with(hash_not_including(ignore: /bar/))
264
+ listener.ignore!([/foo/])
265
+ end
266
+ end
267
+ end
268
+
269
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe Listen::Record do
4
+ let(:listener) { double(Listen::Listener, options: {}) }
5
+ let(:record) { Listen::Record.new(listener) }
6
+ let(:path) { '/dir/path/file.rb' }
7
+ let(:data) { { type: 'File' } }
8
+
9
+ describe "#set_path" do
10
+ it "sets path by spliting direname and basename" do
11
+ record.set_path(path, data)
12
+ expect(record.paths).to eq({ '/dir/path' => { 'file.rb' => data } })
13
+ end
14
+
15
+ it "sets path and keeps old data not overwritten" do
16
+ record.set_path(path, data.merge(foo: 1, bar: 2))
17
+ record.set_path(path, data.merge(foo: 3))
18
+ expect(record.paths).to eq({ '/dir/path' => { 'file.rb' => data.merge(foo: 3, bar: 2) } })
19
+ end
20
+ end
21
+
22
+ describe "#unset_path" do
23
+ context "path is present" do
24
+ before { record.set_path(path, data) }
25
+
26
+ it "unsets path" do
27
+ record.unset_path(path)
28
+ expect(record.paths).to eq({ '/dir/path' => {} })
29
+ end
30
+ end
31
+
32
+ context "path not present" do
33
+ it "unsets path" do
34
+ record.unset_path(path)
35
+ expect(record.paths).to eq({ '/dir/path' => {} })
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#file_data" do
41
+ context "path is present" do
42
+ before { record.set_path(path, data) }
43
+
44
+ it "returns file data" do
45
+ expect(record.file_data(path)).to eq data
46
+ end
47
+ end
48
+
49
+ context "path not present" do
50
+ it "return empty hash" do
51
+ expect(record.file_data(path)).to be_empty
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "#dir_entries" do
57
+ context "path is present" do
58
+ before { record.set_path(path, data) }
59
+
60
+ it "returns file path" do
61
+ expect(record.dir_entries('/dir/path')).to eq({ 'file.rb' => data })
62
+ end
63
+ end
64
+
65
+ context "path not present" do
66
+ it "unsets path" do
67
+ expect(record.dir_entries('/dir/path')).to eq({})
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "#build" do
73
+ let(:directories) { ['dir_path'] }
74
+ let(:change_pool) { double(Listen::Change, terminate: true) }
75
+ before {
76
+ change_pool.stub(:change)
77
+ Celluloid::Actor.stub(:[]).with(:listen_change_pool) { change_pool }
78
+ listener.stub(:directories) { directories }
79
+ }
80
+
81
+ it "re-inits paths" do
82
+ record.set_path(path, data)
83
+ record.build
84
+ expect(record.file_data(path)).to be_empty
85
+ end
86
+
87
+ it "calls change asynchronously on all directories to build record" do
88
+ expect(change_pool).to receive(:change).with('dir_path', type: 'Dir', recursive: true, silence: true)
89
+ record.build
90
+ end
91
+ end
92
+ end