listen 2.8.4 → 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -11
  3. data/lib/listen/adapter/base.rb +8 -4
  4. data/lib/listen/adapter/bsd.rb +8 -25
  5. data/lib/listen/adapter/tcp.rb +2 -1
  6. data/lib/listen/internals/logging.rb +12 -8
  7. data/lib/listen/listener.rb +1 -1
  8. data/lib/listen/version.rb +1 -1
  9. metadata +4 -121
  10. data/.gitignore +0 -28
  11. data/.hound.yml +0 -3
  12. data/.rspec +0 -2
  13. data/.rubocop.yml +0 -20
  14. data/.rubocop_todo.yml +0 -33
  15. data/.travis.yml +0 -15
  16. data/.yardopts +0 -11
  17. data/Gemfile +0 -48
  18. data/Guardfile +0 -16
  19. data/Rakefile +0 -151
  20. data/TROUBLESHOOTING.md +0 -139
  21. data/listen.gemspec +0 -33
  22. data/spec/acceptance/listen_spec.rb +0 -230
  23. data/spec/acceptance/tcp_spec.rb +0 -139
  24. data/spec/lib/listen/adapter/base_spec.rb +0 -31
  25. data/spec/lib/listen/adapter/bsd_spec.rb +0 -14
  26. data/spec/lib/listen/adapter/darwin_spec.rb +0 -145
  27. data/spec/lib/listen/adapter/linux_spec.rb +0 -93
  28. data/spec/lib/listen/adapter/polling_spec.rb +0 -48
  29. data/spec/lib/listen/adapter/tcp_spec.rb +0 -129
  30. data/spec/lib/listen/adapter/windows_spec.rb +0 -14
  31. data/spec/lib/listen/adapter_spec.rb +0 -75
  32. data/spec/lib/listen/change_spec.rb +0 -104
  33. data/spec/lib/listen/directory_spec.rb +0 -180
  34. data/spec/lib/listen/file_spec.rb +0 -252
  35. data/spec/lib/listen/listener_spec.rb +0 -482
  36. data/spec/lib/listen/record_spec.rb +0 -377
  37. data/spec/lib/listen/silencer_spec.rb +0 -100
  38. data/spec/lib/listen/tcp/broadcaster_spec.rb +0 -124
  39. data/spec/lib/listen/tcp/listener_spec.rb +0 -104
  40. data/spec/lib/listen/tcp/message_spec.rb +0 -138
  41. data/spec/lib/listen_spec.rb +0 -52
  42. data/spec/spec_helper.rb +0 -52
  43. data/spec/support/acceptance_helper.rb +0 -275
  44. data/spec/support/fixtures_helper.rb +0 -30
  45. data/spec/support/platform_helper.rb +0 -15
  46. data/vendor/hound/config/style_guides/ruby.yml +0 -259
@@ -1,180 +0,0 @@
1
- require 'spec_helper'
2
-
3
- include Listen
4
-
5
- describe Directory do
6
- let(:dir) { double(:dir) }
7
- let(:file) { double(:file, directory?: false) }
8
- let(:file2) { double(:file2, directory?: false) }
9
- let(:subdir) { double(:subdir, directory?: true) }
10
-
11
- let(:queue) { instance_double(Change, change: nil) }
12
-
13
- let(:async_record) do
14
- instance_double(Record, add_dir: true, unset_path: true)
15
- end
16
-
17
- let(:record) do
18
- instance_double(Record, async: async_record, dir_entries: record_entries)
19
- end
20
-
21
- before do
22
- allow(dir).to receive(:+).with('.') { dir }
23
- allow(dir).to receive(:+).with('file.rb') { file }
24
- allow(dir).to receive(:+).with('subdir') { subdir }
25
-
26
- allow(file).to receive(:relative_path_from).with(dir) { 'file.rb' }
27
- allow(file2).to receive(:relative_path_from).with(dir) { 'file2.rb' }
28
- allow(subdir).to receive(:relative_path_from).with(dir) { 'subdir' }
29
- end
30
-
31
- context '#scan with recursive off' do
32
- let(:options) { { recursive: false } }
33
-
34
- context 'with file & subdir in record' do
35
- let(:record_entries) do
36
- { 'file.rb' => { mtime: 1.1 }, 'subdir' => {} }
37
- end
38
-
39
- context 'with empty dir' do
40
- before { allow(dir).to receive(:children) { [] } }
41
-
42
- it 'sets record dir path' do
43
- expect(async_record).to receive(:add_dir).with(dir, '.')
44
- described_class.scan(queue, record, dir, '.', options)
45
- end
46
-
47
- it "queues changes for file path and dir that doesn't exist" do
48
- expect(queue).to receive(:change).with(:file, dir, 'file.rb')
49
-
50
- expect(queue).to receive(:change).
51
- with(:dir, dir, 'subdir', recursive: false)
52
-
53
- described_class.scan(queue, record, dir, '.', options)
54
- end
55
- end
56
-
57
- context 'with only file2.rb in dir' do
58
- before { allow(dir).to receive(:children) { [file2] } }
59
-
60
- it 'notices file & file2 and no longer existing dir' do
61
- expect(queue).to receive(:change).with(:file, dir, 'file.rb')
62
- expect(queue).to receive(:change).with(:file, dir, 'file2.rb')
63
-
64
- expect(queue).to receive(:change).
65
- with(:dir, dir, 'subdir', recursive: false)
66
-
67
- described_class.scan(queue, record, dir, '.', options)
68
- end
69
- end
70
- end
71
-
72
- context 'with empty record' do
73
- let(:record_entries) { {} }
74
-
75
- context 'with non-existing dir path' do
76
- before { allow(dir).to receive(:children) { fail Errno::ENOENT } }
77
-
78
- it 'reports no changes' do
79
- expect(queue).to_not receive(:change)
80
- described_class.scan(queue, record, dir, '.', options)
81
- end
82
-
83
- it 'unsets record dir path' do
84
- expect(async_record).to receive(:unset_path).with(dir, '.')
85
- described_class.scan(queue, record, dir, '.', options)
86
- end
87
- end
88
-
89
- context 'with file.rb in dir' do
90
- before { allow(dir).to receive(:children) { [file] } }
91
-
92
- it 'queues changes for file & file2 paths' do
93
- expect(queue).to receive(:change).with(:file, dir, 'file.rb')
94
- expect(queue).to_not receive(:change).with(:file, dir, 'file2.rb')
95
-
96
- expect(queue).to_not receive(:change).
97
- with(:dir, dir, 'subdir', recursive: false)
98
-
99
- described_class.scan(queue, record, dir, '.', options)
100
- end
101
- end
102
- end
103
- end
104
-
105
- context '#scan with recursive on' do
106
- let(:options) { { recursive: true } }
107
-
108
- context 'with file.rb & subdir in record' do
109
- let(:record_entries) do
110
- { 'file.rb' => { mtime: 1.1 }, 'subdir' => {} }
111
- end
112
-
113
- context 'with empty dir' do
114
- before do
115
- allow(dir).to receive(:children) { [] }
116
- end
117
-
118
- it 'queues changes for file & subdir path' do
119
- expect(queue).to receive(:change).with(:file, dir, 'file.rb')
120
-
121
- expect(queue).to receive(:change).
122
- with(:dir, dir, 'subdir', recursive: true)
123
-
124
- described_class.scan(queue, record, dir, '.', options)
125
- end
126
- end
127
-
128
- context 'with subdir2 path present in dir' do
129
- let(:subdir2) { double(:subdir2, directory?: true, children: []) }
130
-
131
- before do
132
- allow(dir).to receive(:children) { [subdir2] }
133
- allow(subdir2).to receive(:relative_path_from).with(dir) { 'subdir2' }
134
- end
135
-
136
- it 'queues changes for file, file2 & subdir paths' do
137
- expect(queue).to receive(:change).with(:file, dir, 'file.rb')
138
-
139
- expect(queue).to receive(:change).
140
- with(:dir, dir, 'subdir', recursive: true)
141
-
142
- expect(queue).to receive(:change).
143
- with(:dir, dir, 'subdir2', recursive: true)
144
-
145
- described_class.scan(queue, record, dir, '.', options)
146
- end
147
- end
148
- end
149
-
150
- context 'with empty record' do
151
- let(:record_entries) { {} }
152
-
153
- context 'with non-existing dir' do
154
- before do
155
- allow(dir).to receive(:children) { fail Errno::ENOENT }
156
- end
157
-
158
- it 'reports no changes' do
159
- expect(queue).to_not receive(:change)
160
- described_class.scan(queue, record, dir, '.', options)
161
- end
162
- end
163
-
164
- context 'with subdir present in dir' do
165
-
166
- before do
167
- allow(dir).to receive(:children) { [subdir] }
168
- allow(subdir).to receive(:children) { [] }
169
- end
170
-
171
- it 'queues changes for subdir' do
172
- expect(queue).to receive(:change).
173
- with(:dir, dir, 'subdir', recursive: true)
174
-
175
- described_class.scan(queue, record, dir, '.', options)
176
- end
177
- end
178
- end
179
- end
180
- end
@@ -1,252 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Listen::File do
4
- let(:async_record) do
5
- instance_double(
6
- Listen::Record,
7
- add_dir: true,
8
- update_file: true,
9
- unset_path: true
10
- )
11
- end
12
-
13
- let(:record) do
14
- instance_double(
15
- Listen::Record,
16
- async: async_record,
17
- file_data: record_data
18
- )
19
- end
20
-
21
- let(:path) { Pathname.pwd }
22
- let(:subject) { described_class.change(record, path, 'file.rb') }
23
-
24
- around { |example| fixtures { example.run } }
25
-
26
- before { allow(::File).to receive(:lstat) { fail 'Not stubbed!' } }
27
-
28
- describe '#change' do
29
- let(:expected_data) do
30
- { mtime: kind_of(Float), mode: kind_of(Integer) }
31
- end
32
-
33
- context 'with file record' do
34
- let(:record_mtime) { nil }
35
- let(:record_md5) { nil }
36
- let(:record_mode) { nil }
37
-
38
- let(:record_data) do
39
- { mtime: record_mtime, md5: record_md5, mode: record_mode }
40
- end
41
-
42
- context 'with non-existing file' do
43
- before { allow(::File).to receive(:lstat) { fail Errno::ENOENT } }
44
-
45
- it { should be :removed }
46
-
47
- it 'sets path in record' do
48
- expect(async_record).to receive(:unset_path).with(path, 'file.rb')
49
- subject
50
- end
51
- end
52
-
53
- context 'with existing file' do
54
- let(:stat_mtime) { Time.now.to_f - 1234.567 }
55
- let(:stat_ctime) { Time.now.to_f - 1234.567 }
56
- let(:stat_atime) { Time.now.to_f - 1234.567 }
57
- let(:stat_mode) { 0640 }
58
- let(:md5) { fail 'stub me (md5)' }
59
-
60
- let(:stat) do
61
- instance_double(
62
- File::Stat,
63
- mtime: stat_mtime,
64
- atime: stat_atime,
65
- ctime: stat_ctime,
66
- mode: stat_mode
67
- )
68
- end
69
-
70
- before do
71
- allow(::File).to receive(:lstat) { stat }
72
- allow(Digest::MD5).to receive(:file) { double(:md5, digest: md5) }
73
- end
74
-
75
- context 'with different mode in record' do
76
- let(:record_mode) { 0722 }
77
-
78
- it { should be :modified }
79
-
80
- it 'sets path in record with expected data' do
81
- expect(async_record).to receive(:update_file).
82
- with(path, 'file.rb', expected_data)
83
- subject
84
- end
85
- end
86
-
87
- context 'with same mode in record' do
88
- let(:record_mode) { stat_mode }
89
-
90
- # e.g. file was overwritten by earlier copy
91
- context 'with earlier mtime than in record' do
92
- let(:record_mtime) { stat_mtime.to_f - 123.45 }
93
-
94
- it { should be :modified }
95
-
96
- it 'sets path in record with expected data' do
97
- expect(async_record).to receive(:update_file).
98
- with(path, 'file.rb', expected_data)
99
- subject
100
- end
101
- end
102
-
103
- context 'with later mtime than in record' do
104
- let(:record_mtime) { stat_mtime.to_f + 123.45 }
105
-
106
- it { should be :modified }
107
-
108
- it 'sets path in record with expected data' do
109
- expect(async_record).to receive(:update_file).
110
- with(path, 'file.rb', expected_data)
111
- subject
112
- end
113
- end
114
-
115
- context 'with indentical mtime in record' do
116
- let(:record_mtime) { stat_mtime.to_f }
117
-
118
- context 'with accurate stat times' do
119
- let(:stat_mtime) { Time.at(1_401_235_714.123) }
120
- let(:stat_atime) { Time.at(1_401_235_714.123) }
121
- let(:stat_ctime) { Time.at(1_401_235_714.123) }
122
- let(:record_mtime) { stat_mtime.to_f }
123
- it { should be_nil }
124
- end
125
-
126
- context 'with inaccurate stat times' do
127
- let(:stat_mtime) { Time.at(1_401_235_714.0) }
128
- let(:stat_atime) { Time.at(1_401_235_714.0) }
129
- let(:stat_ctime) { Time.at(1_401_235_714.0) }
130
-
131
- let(:record_mtime) { stat_mtime.to_f }
132
-
133
- context 'with real mtime barely not within last second' do
134
- before { allow(Time).to receive(:now) { now } }
135
-
136
- # NOTE: if real mtime is ???14.99, the
137
- # saved mtime is ???14.0
138
- let(:now) { Time.at(1_401_235_716.00) }
139
- it { should be_nil }
140
- end
141
-
142
- context 'with real mtime barely within last second' do
143
- # NOTE: real mtime is in range (???14.0 .. ???14.999),
144
- # so saved mtime at ???14.0 means it could be
145
- # ???14.999, so ???15.999 could still be within 1 second
146
- # range
147
- let(:now) { Time.at(1_401_235_715.999999) }
148
-
149
- before { allow(Time).to receive(:now) { now } }
150
-
151
- context 'without available md5' do
152
- let(:md5) { fail Errno::ENOENT }
153
-
154
- # Treat it as a removed file, because chances are ...
155
- # whatever is listening for changes won't be able to deal
156
- # with the file either (e.g. because of permissions)
157
- it { should be :removed }
158
-
159
- it 'should not unset record' do
160
- expect(async_record).to_not receive(:unset_path)
161
- end
162
- end
163
-
164
- context 'with available md5' do
165
- let(:md5) { 'd41d8cd98f00b204e9800998ecf8427e' }
166
-
167
- context 'with same md5 in record' do
168
- let(:record_md5) { md5 }
169
- it { should be_nil }
170
- end
171
-
172
- context 'with no md5 in record' do
173
- let(:record_md5) { nil }
174
- it { should be_nil }
175
- end
176
-
177
- context 'with different md5 in record' do
178
- let(:record_md5) { 'foo' }
179
- it { should be :modified }
180
-
181
- it 'sets path in record with expected data' do
182
- expect(async_record).to receive(:update_file).
183
- with(path, 'file.rb', expected_data. merge(md5: md5))
184
- subject
185
- end
186
- end
187
- end
188
- end
189
- end
190
- end
191
- end
192
- end
193
- end
194
-
195
- context 'with empty record' do
196
- let(:record_data) { {} }
197
-
198
- context 'with existing path' do
199
- let(:stat) do
200
- instance_double(
201
- File::Stat,
202
- mtime: 1234,
203
- mode: 0645
204
- )
205
- end
206
-
207
- before do
208
- allow(::File).to receive(:lstat) { stat }
209
- end
210
-
211
- it 'returns added' do
212
- expect(subject).to eq :added
213
- end
214
-
215
- it 'sets path in record with expected data' do
216
- expect(async_record).to receive(:update_file).
217
- with(path, 'file.rb', expected_data)
218
- subject
219
- end
220
- end
221
- end
222
- end
223
-
224
- describe '#inaccurate_mac_time?' do
225
- let(:stat) do
226
- instance_double(File::Stat, mtime: mtime, atime: atime, ctime: ctime)
227
- end
228
-
229
- subject { Listen::File.inaccurate_mac_time?(stat) }
230
-
231
- context 'with no accurate times' do
232
- let(:mtime) { Time.at(1_234_567.0) }
233
- let(:atime) { Time.at(1_234_567.0) }
234
- let(:ctime) { Time.at(1_234_567.0) }
235
- it { should be_truthy }
236
- end
237
-
238
- context 'with all accurate times' do
239
- let(:mtime) { Time.at(1_234_567.89) }
240
- let(:atime) { Time.at(1_234_567.89) }
241
- let(:ctime) { Time.at(1_234_567.89) }
242
- it { should be_falsey }
243
- end
244
-
245
- context 'with one accurate time' do
246
- let(:mtime) { Time.at(1_234_567.0) }
247
- let(:atime) { Time.at(1_234_567.89) }
248
- let(:ctime) { Time.at(1_234_567.0) }
249
- it { should be_falsey }
250
- end
251
- end
252
- end
@@ -1,482 +0,0 @@
1
- require 'spec_helper'
2
-
3
- include Listen
4
-
5
- describe Listener do
6
- subject { described_class.new(options) }
7
- let(:options) { {} }
8
- let(:registry) { instance_double(Celluloid::Registry) }
9
-
10
- let(:supervisor) do
11
- instance_double(Celluloid::SupervisionGroup, add: true, pool: true)
12
- end
13
-
14
- let(:record) { instance_double(Record, terminate: true, build: true) }
15
- let(:silencer) { instance_double(Silencer, configure: nil) }
16
- let(:adapter) { instance_double(Adapter::Base, start: nil) }
17
-
18
- before do
19
- allow(Listen::Silencer).to receive(:new) { silencer }
20
-
21
- allow(Celluloid::Registry).to receive(:new) { registry }
22
- allow(Celluloid::SupervisionGroup).to receive(:run!) { supervisor }
23
- allow(registry).to receive(:[]).with(:adapter) { adapter }
24
- allow(registry).to receive(:[]).with(:record) { record }
25
- end
26
-
27
- describe 'initialize' do
28
- it { should_not be_paused }
29
-
30
- context 'with a block' do
31
- describe 'block' do
32
- subject { described_class.new('lib', &(proc {})) }
33
- specify { expect(subject.block).to_not be_nil }
34
- end
35
- end
36
-
37
- context 'with directories' do
38
- describe 'directories' do
39
- subject { described_class.new('lib', 'spec') }
40
- expected = %w(lib spec).map { |dir| Pathname.pwd + dir }
41
- specify { expect(subject.directories).to eq expected }
42
- end
43
- end
44
- end
45
-
46
- describe 'options' do
47
- context 'default options' do
48
- it 'sets default options' do
49
- expect(subject.options).
50
- to eq(
51
- debug: false,
52
- latency: nil,
53
- wait_for_delay: 0.1,
54
- force_polling: false,
55
- polling_fallback_message: nil)
56
- end
57
- end
58
-
59
- context 'custom options' do
60
- subject do
61
- described_class.new('lib', latency: 1.234, wait_for_delay: 0.85)
62
- end
63
-
64
- it 'sets new options on initialize' do
65
- expect(subject.options).
66
- to eq(
67
- debug: false,
68
- latency: 1.234,
69
- wait_for_delay: 0.85,
70
- force_polling: false,
71
- polling_fallback_message: nil)
72
- end
73
- end
74
- end
75
-
76
- describe '#start' do
77
- before do
78
- allow(subject).to receive(:_start_adapter)
79
- allow(silencer).to receive(:silenced?) { false }
80
- end
81
-
82
- it 'supervises change_pool' do
83
- expect(supervisor).to receive(:pool).
84
- with(Change, as: :change_pool, args: subject)
85
-
86
- subject.start
87
- end
88
-
89
- it 'supervises adapter' do
90
- allow(Adapter).to receive(:select) { Adapter::Polling }
91
- options = [mq: subject, directories: []]
92
- expect(supervisor).to receive(:add).
93
- with(Adapter::Polling, as: :adapter, args: options)
94
-
95
- subject.start
96
- end
97
-
98
- it 'supervises record' do
99
- expect(supervisor).to receive(:add).
100
- with(Record, as: :record, args: subject)
101
-
102
- subject.start
103
- end
104
-
105
- it 'builds record' do
106
- expect(record).to receive(:build)
107
- subject.start
108
- end
109
-
110
- it 'sets paused to false' do
111
- subject.start
112
- expect(subject).to_not be_paused
113
- end
114
-
115
- it 'starts adapter' do
116
- expect(subject).to receive(:_start_adapter)
117
- subject.start
118
- end
119
-
120
- it 'calls block on changes' do
121
- foo = instance_double(Pathname, to_s: 'foo', exist?: true)
122
-
123
- dir = instance_double(Pathname)
124
- allow(dir).to receive(:+).with('foo') { foo }
125
-
126
- block_stub = instance_double(Proc)
127
- subject.block = block_stub
128
- expect(block_stub).to receive(:call).with(['foo'], [], [])
129
- subject.start
130
- subject.queue(:file, :modified, dir, 'foo')
131
- sleep 0.25
132
- end
133
- end
134
-
135
- describe '#stop' do
136
- before do
137
- allow(Celluloid::SupervisionGroup).to receive(:run!) { supervisor }
138
- subject.start
139
- end
140
-
141
- it 'terminates supervisor' do
142
- expect(supervisor).to receive(:terminate)
143
- subject.stop
144
- end
145
- end
146
-
147
- describe '#pause' do
148
- before { subject.start }
149
- it 'sets paused to true' do
150
- subject.pause
151
- expect(subject).to be_paused
152
- end
153
- end
154
-
155
- describe '#unpause' do
156
- before do
157
- subject.start
158
- subject.pause
159
- end
160
-
161
- it 'sets paused to false' do
162
- subject.unpause
163
- expect(subject).to_not be_paused
164
- end
165
- end
166
-
167
- describe '#paused?' do
168
- before { subject.start }
169
- it 'returns true when paused' do
170
- subject.paused = true
171
- expect(subject).to be_paused
172
- end
173
- it 'returns false when not paused (nil)' do
174
- subject.paused = nil
175
- expect(subject).not_to be_paused
176
- end
177
- it 'returns false when not paused (false)' do
178
- subject.paused = false
179
- expect(subject).not_to be_paused
180
- end
181
- end
182
-
183
- describe '#listen?' do
184
- context 'when processing' do
185
- before { subject.start }
186
- it { should be_processing }
187
- end
188
-
189
- context 'when stopped' do
190
- it { should_not be_processing }
191
- end
192
-
193
- context 'when paused' do
194
- before do
195
- subject.start
196
- subject.pause
197
- end
198
- it { should_not be_processing }
199
- end
200
- end
201
-
202
- describe '#ignore' do
203
- context 'with existing ignore options' do
204
- let(:options) { { ignore: /bar/ } }
205
-
206
- it 'adds up to existing ignore options' do
207
- expect(silencer).to receive(:configure).with(options)
208
- subject.ignore(/foo/)
209
- expect(subject.options).to include(ignore: [/bar/, /foo/])
210
- end
211
- end
212
-
213
- context 'with existing ignore options (array)' do
214
- let(:options) { { ignore: [/bar/] } }
215
-
216
- it 'adds up to existing ignore options' do
217
- expect(silencer).to receive(:configure).with(options)
218
- subject.ignore(/foo/)
219
- expect(subject.options).to include(ignore: [[/bar/], /foo/])
220
- end
221
- end
222
- end
223
-
224
- describe '#ignore!' do
225
- context 'with no existing options' do
226
- let(:options) { {} }
227
-
228
- it 'sets options' do
229
- expect(silencer).to receive(:configure).with(options)
230
- subject
231
- end
232
- end
233
-
234
- context 'with existing ignore! options' do
235
- let(:options) { { ignore!: /bar/ } }
236
-
237
- it 'overwrites existing ignore options' do
238
- expect(silencer).to receive(:configure).with(options)
239
- subject.ignore!([/foo/])
240
- expect(subject.options).to include(ignore!: [/foo/])
241
- end
242
- end
243
-
244
- context 'with existing ignore options' do
245
- let(:options) { { ignore: /bar/ } }
246
-
247
- it 'deletes ignore options' do
248
- expect(silencer).to receive(:configure).with(options)
249
- subject.ignore!([/foo/])
250
- expect(subject.options).to_not include(ignore: /bar/)
251
- end
252
- end
253
- end
254
-
255
- describe '#only' do
256
- context 'with existing only options' do
257
- let(:options) { { only: /bar/ } }
258
-
259
- it 'overwrites existing ignore options' do
260
- expect(silencer).to receive(:configure).with(options)
261
- subject.only([/foo/])
262
- expect(subject.options).to include(only: [/foo/])
263
- end
264
- end
265
- end
266
-
267
- describe '_wait_for_changes' do
268
- it 'gets two changes and calls the block once' do
269
- allow(silencer).to receive(:silenced?) { false }
270
-
271
- subject.block = proc do |modified, added, _|
272
- expect(modified).to eql(['foo/bar.txt'])
273
- expect(added).to eql(['foo/baz.txt'])
274
- end
275
-
276
- bar = instance_double(
277
- Pathname,
278
- to_s: 'foo/bar.txt',
279
- exist?: true,
280
- directory?: false)
281
-
282
- baz = instance_double(
283
- Pathname,
284
- to_s: 'foo/baz.txt',
285
- exist?: true,
286
- directory?: false)
287
-
288
- dir = instance_double(Pathname)
289
- expect(dir).to receive(:+).with('bar.txt') { bar }
290
- expect(dir).to receive(:+).with('baz.txt') { baz }
291
-
292
- subject.start
293
- subject.queue(:file, :modified, dir, 'bar.txt', {})
294
- subject.queue(:file, :added, dir, 'baz.txt', {})
295
- sleep 0.25
296
- end
297
- end
298
-
299
- describe '_smoosh_changes' do
300
- it 'recognizes rename from temp file' do
301
- bar = instance_double(
302
- Pathname,
303
- to_s: 'bar',
304
- exist?: true,
305
- directory?: false)
306
-
307
- foo = instance_double(Pathname, to_s: 'foo')
308
- allow(foo).to receive(:+).with('bar') { bar }
309
-
310
- changes = [
311
- [:file, :modified, foo, 'bar'],
312
- [:file, :removed, foo, 'bar'],
313
- [:file, :added, foo, 'bar'],
314
- [:file, :modified, foo, 'bar']
315
- ]
316
- allow(silencer).to receive(:silenced?) { false }
317
- smooshed = subject.send :_smoosh_changes, changes
318
- expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
319
- end
320
-
321
- it 'ignores deleted temp file' do
322
- bar = instance_double(
323
- Pathname,
324
- to_s: 'bar',
325
- exist?: false)
326
-
327
- foo = instance_double(Pathname, to_s: 'foo')
328
- allow(foo).to receive(:+).with('bar') { bar }
329
-
330
- changes = [
331
- [:file, :added, foo, 'bar'],
332
- [:file, :modified, foo, 'bar'],
333
- [:file, :removed, foo, 'bar'],
334
- [:file, :modified, foo, 'bar']
335
- ]
336
- allow(silencer).to receive(:silenced?) { false }
337
- smooshed = subject.send :_smoosh_changes, changes
338
- expect(smooshed).to eq(modified: [], added: [], removed: [])
339
- end
340
-
341
- it 'recognizes double move as modification' do
342
- # e.g. "mv foo x && mv x foo" is like "touch foo"
343
- bar = instance_double(
344
- Pathname,
345
- to_s: 'bar',
346
- exist?: true)
347
-
348
- dir = instance_double(Pathname, to_s: 'foo')
349
- allow(dir).to receive(:+).with('bar') { bar }
350
-
351
- changes = [
352
- [:file, :removed, dir, 'bar'],
353
- [:file, :added, dir, 'bar']
354
- ]
355
- allow(silencer).to receive(:silenced?) { false }
356
- smooshed = subject.send :_smoosh_changes, changes
357
- expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
358
- end
359
-
360
- context 'with cookie' do
361
-
362
- it 'recognizes single moved_to as add' do
363
- foo = instance_double(
364
- Pathname,
365
- to_s: 'foo',
366
- exist?: true)
367
-
368
- dir = instance_double(Pathname, to_s: 'foo')
369
- allow(dir).to receive(:+).with('foo') { foo }
370
-
371
- changes = [[:file, :moved_to, dir, 'foo', cookie: 4321]]
372
- expect(silencer).to receive(:silenced?).
373
- with(Pathname('foo'), :file) { false }
374
-
375
- smooshed = subject.send :_smoosh_changes, changes
376
- expect(smooshed).to eq(modified: [], added: ['foo'], removed: [])
377
- end
378
-
379
- it 'recognizes related moved_to as add' do
380
- foo = instance_double(
381
- Pathname,
382
- to_s: 'foo',
383
- exist?: true,
384
- directory?: false)
385
-
386
- bar = instance_double(
387
- Pathname,
388
- to_s: 'bar',
389
- exist?: true,
390
- directory?: false)
391
-
392
- dir = instance_double(Pathname)
393
- allow(dir).to receive(:+).with('foo') { foo }
394
- allow(dir).to receive(:+).with('bar') { bar }
395
-
396
- changes = [
397
- [:file, :moved_from, dir, 'foo', cookie: 4321],
398
- [:file, :moved_to, dir, 'bar', cookie: 4321]
399
- ]
400
-
401
- expect(silencer).to receive(:silenced?).
402
- twice.with(Pathname('foo'), :file) { false }
403
-
404
- expect(silencer).to receive(:silenced?).
405
- with(Pathname('bar'), :file) { false }
406
-
407
- smooshed = subject.send :_smoosh_changes, changes
408
- expect(smooshed).to eq(modified: [], added: ['bar'], removed: [])
409
- end
410
-
411
- # Scenario with workaround for editors using rename()
412
- it 'recognizes related moved_to with ignored moved_from as modify' do
413
-
414
- ignored = instance_double(
415
- Pathname,
416
- to_s: 'ignored',
417
- exist?: true,
418
- directory?: false)
419
-
420
- foo = instance_double(
421
- Pathname,
422
- to_s: 'foo',
423
- exist?: true,
424
- directory?: false)
425
-
426
- dir = instance_double(Pathname)
427
- allow(dir).to receive(:+).with('foo') { foo }
428
- allow(dir).to receive(:+).with('ignored') { ignored }
429
-
430
- changes = [
431
- [:file, :moved_from, dir, 'ignored', cookie: 4321],
432
- [:file, :moved_to, dir, 'foo', cookie: 4321]
433
- ]
434
-
435
- expect(silencer).to receive(:silenced?).
436
- with(Pathname('ignored'), :file) { true }
437
-
438
- expect(silencer).to receive(:silenced?).
439
- with(Pathname('foo'), :file) { false }
440
-
441
- smooshed = subject.send :_smoosh_changes, changes
442
- expect(smooshed).to eq(modified: ['foo'], added: [], removed: [])
443
- end
444
- end
445
-
446
- context 'with no cookie' do
447
- context 'with ignored file' do
448
- let(:dir) { instance_double(Pathname) }
449
- let(:ignored) { instance_double(Pathname, to_s: 'foo', exist?: true) }
450
-
451
- before do
452
- expect(silencer).to receive(:silenced?).
453
- with(Pathname('ignored'), :file) { true }
454
-
455
- allow(dir).to receive(:+).with('ignored') { ignored }
456
- end
457
-
458
- it 'recognizes properly ignores files' do
459
- changes = [[:file, :modified, dir, 'ignored']]
460
- smooshed = subject.send :_smoosh_changes, changes
461
- expect(smooshed).to eq(modified: [], added: [], removed: [])
462
- end
463
- end
464
- end
465
- end
466
-
467
- context 'when listener is stopped' do
468
-
469
- before do
470
- allow(registry).to receive(:[]).with(:change_pool) { nil }
471
- subject.stop
472
- end
473
-
474
- let(:dir) { instance_double(Pathname) }
475
-
476
- it 'queuing does not crash when no worker is available' do
477
- expect do
478
- subject.send(:_queue_raw_change, :dir, dir, 'path', recursive: true)
479
- end.to_not raise_error
480
- end
481
- end
482
- end