listen 2.8.4 → 2.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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