puppetlabs_spec_helper 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +481 -116
  3. data/README.md +5 -19
  4. data/lib/puppetlabs_spec_helper/module_spec_helper.rb +9 -10
  5. data/lib/puppetlabs_spec_helper/puppet_spec_helper.rb +2 -86
  6. data/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb +3 -1
  7. data/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb +3 -3
  8. data/lib/puppetlabs_spec_helper/puppetlabs_spec/matchers.rb +0 -17
  9. data/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb +35 -68
  10. data/lib/puppetlabs_spec_helper/rake_tasks.rb +44 -63
  11. data/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb +1 -3
  12. data/lib/puppetlabs_spec_helper/tasks/fixtures.rb +14 -12
  13. data/lib/puppetlabs_spec_helper/version.rb +1 -6
  14. data/spec/acceptance/fixtures/Rakefile +3 -0
  15. data/spec/acceptance/smoke_spec.rb +14 -0
  16. data/spec/spec_helper.rb +53 -0
  17. data/spec/unit/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals_spec.rb +71 -0
  18. data/spec/unit/puppetlabs_spec_helper/tasks/check_symlinks_spec.rb +162 -0
  19. data/spec/unit/puppetlabs_spec_helper/tasks/check_test_file_spec.rb +45 -0
  20. data/spec/unit/puppetlabs_spec_helper/tasks/fixtures_spec.rb +262 -0
  21. data/spec/watchr.rb +81 -0
  22. metadata +33 -148
  23. data/.github/dependabot.yml +0 -15
  24. data/.gitignore +0 -9
  25. data/.noexec.yaml +0 -4
  26. data/.rspec +0 -2
  27. data/.rubocop_todo.yml +0 -119
  28. data/.travis.yml +0 -23
  29. data/CHANGELOG.md +0 -715
  30. data/CODEOWNERS +0 -2
  31. data/CONTRIBUTING.md +0 -14
  32. data/Gemfile +0 -42
  33. data/HISTORY.md +0 -498
  34. data/Rakefile +0 -45
  35. data/puppet_spec_helper.rb +0 -7
  36. data/puppetlabs_spec_helper.gemspec +0 -38
  37. data/puppetlabs_spec_helper.rb +0 -7
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'rspec-puppet'
5
+
6
+ describe PuppetlabsSpec::PuppetInternals do
7
+ before(:all) do # this is only needed once # rubocop:disable RSpec/BeforeAfterAll
8
+ Puppet.initialize_settings
9
+ end
10
+
11
+ describe '.resource' do
12
+ subject(:resource) { described_class.resource }
13
+
14
+ it 'can have a defined type' do
15
+ expect(described_class.resource(type: :node).type).to eq(:node)
16
+ end
17
+
18
+ it 'defaults to a type of hostclass' do
19
+ expect(resource.type).to eq(:hostclass)
20
+ end
21
+
22
+ it 'can have a defined name' do
23
+ expect(described_class.resource(name: 'testingrsrc').name).to eq('testingrsrc')
24
+ end
25
+
26
+ it 'defaults to a name of testing' do
27
+ expect(resource.name).to eq('testing')
28
+ end
29
+ end
30
+
31
+ describe '.compiler' do
32
+ let(:node) { described_class.node }
33
+
34
+ it 'can have a defined node' do
35
+ expect(described_class.compiler(node: node).node).to be node
36
+ end
37
+ end
38
+
39
+ describe '.node' do
40
+ it 'can have a defined name' do
41
+ expect(described_class.node(name: 'mine').name).to eq('mine')
42
+ end
43
+
44
+ it 'can have a defined environment' do
45
+ expect(described_class.node(environment: 'mine').environment.name).to eq(:mine)
46
+ end
47
+
48
+ it 'defaults to a name of testinghost' do
49
+ expect(described_class.node.name).to eq('testinghost')
50
+ end
51
+
52
+ it 'accepts facts via options for rspec-puppet' do
53
+ fact_values = { 'fqdn' => 'jeff.puppetlabs.com' }
54
+ node = described_class.node(options: { parameters: fact_values })
55
+ expect(node.parameters).to eq(fact_values)
56
+ end
57
+ end
58
+
59
+ describe '.function_method', type: :puppet_function do
60
+ it 'accepts an injected scope' do
61
+ expect(Puppet::Parser::Functions).to receive(:function).with('my_func').and_return(true)
62
+ expect(scope).to receive(:method).with(:function_my_func).and_return(:fake_method)
63
+ expect(described_class.function_method('my_func', scope: scope)).to eq(:fake_method)
64
+ end
65
+
66
+ it "returns nil if the function doesn't exist" do
67
+ expect(Puppet::Parser::Functions).to receive(:function).with('my_func').and_return(false)
68
+ expect(described_class.function_method('my_func', scope: scope)).to be_nil
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'rake check:symlinks', type: :task do
6
+ before(:each) do
7
+ test_files.each do |f|
8
+ FileUtils.mkdir_p(File.dirname(f))
9
+ FileUtils.touch(f)
10
+ end
11
+
12
+ symlinks.each do |link, target|
13
+ FileUtils.mkdir_p(File.dirname(link))
14
+ FileUtils.ln_s(target, link)
15
+ end
16
+ end
17
+
18
+ let(:test_files) { [] }
19
+ let(:symlinks) { {} }
20
+ let(:expected_output) do
21
+ symlinks.map { |link, target| "Symlink found: #{link} => #{target}" }.join("\n")
22
+ end
23
+
24
+ context 'when there are no files' do
25
+ it 'runs without raising an error' do
26
+ expect { task.execute }.not_to raise_error
27
+ end
28
+ end
29
+
30
+ context 'when there are regular files' do
31
+ let(:test_files) do
32
+ [
33
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
34
+ File.join(Dir.pwd, 'files', 'another_file.pp'),
35
+ ]
36
+ end
37
+
38
+ it 'runs without raising an error' do
39
+ expect { task.execute }.not_to raise_error
40
+ end
41
+ end
42
+
43
+ context 'when there is a symlink present' do
44
+ let(:test_files) do
45
+ [
46
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
47
+ ]
48
+ end
49
+
50
+ let(:symlinks) do
51
+ {
52
+ File.join(Dir.pwd, 'files', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
53
+ }
54
+ end
55
+
56
+ it 'raises an error' do
57
+ expect { task.execute }
58
+ .to raise_error(%r{symlink\(s\) exist}i)
59
+ .and output(a_string_including(expected_output)).to_stdout
60
+ end
61
+ end
62
+
63
+ context 'when there are symlinks under .git/' do
64
+ let(:test_files) do
65
+ [
66
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
67
+ ]
68
+ end
69
+
70
+ let(:symlinks) do
71
+ {
72
+ File.join(Dir.pwd, '.git', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
73
+ }
74
+ end
75
+
76
+ it 'runs without raising an error' do
77
+ expect { task.execute }.not_to raise_error
78
+ end
79
+ end
80
+
81
+ context 'when there are symlinks under .bundle/' do
82
+ let(:test_files) do
83
+ [
84
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
85
+ ]
86
+ end
87
+
88
+ let(:symlinks) do
89
+ {
90
+ File.join(Dir.pwd, '.bundle', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
91
+ }
92
+ end
93
+
94
+ it 'runs without raising an error' do
95
+ expect { task.execute }.not_to raise_error
96
+ end
97
+ end
98
+
99
+ context 'when there are symlinks under vendor/' do
100
+ let(:test_files) do
101
+ [
102
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
103
+ ]
104
+ end
105
+
106
+ let(:symlinks) do
107
+ {
108
+ File.join(Dir.pwd, 'vendor', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
109
+ }
110
+ end
111
+
112
+ it 'runs without raising an error' do
113
+ expect { task.execute }.not_to raise_error
114
+ end
115
+ end
116
+
117
+ context 'when there are symlinks under a directory listed in .gitignore' do
118
+ before(:each) do
119
+ File.write(File.join(Dir.pwd, '.gitignore'), "a_directory/\n")
120
+ end
121
+
122
+ let(:test_files) do
123
+ [
124
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
125
+ ]
126
+ end
127
+
128
+ let(:symlinks) do
129
+ {
130
+ File.join(Dir.pwd, 'a_directory', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
131
+ }
132
+ end
133
+
134
+ it 'runs without raising an error' do
135
+ expect { task.execute }.not_to raise_error
136
+ end
137
+ end
138
+
139
+ context 'when there are symlinks under a directory listed in .pdkignore' do
140
+ before(:each) do
141
+ File.open(File.join(Dir.pwd, '.pdkignore'), 'w') do |f|
142
+ f.puts '/another_directory/'
143
+ end
144
+ end
145
+
146
+ let(:test_files) do
147
+ [
148
+ File.join(Dir.pwd, 'files', 'a_file.pp'),
149
+ ]
150
+ end
151
+
152
+ let(:symlinks) do
153
+ {
154
+ File.join(Dir.pwd, 'another_directory', 'a_symlink.pp') => File.join(Dir.pwd, 'files', 'a_file.pp'),
155
+ }
156
+ end
157
+
158
+ it 'runs without raising an error' do
159
+ expect { task.execute }.not_to raise_error
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'rake check:test_file', type: :task do
6
+ context 'when there are .pp files under tests/' do
7
+ before(:each) do
8
+ test_files.each do |f|
9
+ FileUtils.mkdir_p(File.dirname(f))
10
+ FileUtils.touch(f)
11
+ end
12
+ end
13
+
14
+ let(:test_files) do
15
+ [
16
+ File.join(Dir.pwd, 'tests', 'an_example.pp'),
17
+ File.join(Dir.pwd, 'tests', 'deep', 'directory', 'structure', 'another_example.pp'),
18
+ ]
19
+ end
20
+
21
+ it 'raises an error' do
22
+ expected_output = test_files.join("\n")
23
+
24
+ expect { task.execute }
25
+ .to raise_error(%r{pp files present in tests folder})
26
+ .and output(a_string_including(expected_output)).to_stdout
27
+ end
28
+ end
29
+
30
+ context 'when there are no .pp files under tests/' do
31
+ before(:each) do
32
+ FileUtils.mkdir('tests')
33
+ end
34
+
35
+ it 'runs without raising an error' do
36
+ expect { task.execute }.not_to raise_error
37
+ end
38
+ end
39
+
40
+ context 'when there is no tests/ directory' do
41
+ it 'runs without raising an error' do
42
+ expect { task.execute }.not_to raise_error
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'puppetlabs_spec_helper/tasks/fixtures'
5
+
6
+ describe PuppetlabsSpecHelper::Tasks::FixtureHelpers do
7
+ describe '.module_name' do
8
+ subject(:module_name) { described_class.module_name }
9
+
10
+ before(:each) do
11
+ allow(Dir).to receive(:pwd).and_return(File.join('path', 'to', 'my-awsome-module_from_pwd'))
12
+ end
13
+
14
+ shared_examples 'module name from working directory' do
15
+ it 'determines the module name from the working directory name' do
16
+ expect(module_name).to eq('module_from_pwd')
17
+ end
18
+ end
19
+
20
+ shared_examples 'module name from metadata' do
21
+ it 'determines the module name from the module metadata' do
22
+ expect(module_name).to eq('module_from_metadata')
23
+ end
24
+ end
25
+
26
+ context 'when metadata.json does not exist' do
27
+ before(:each) do
28
+ allow(File).to receive(:file?).with('metadata.json').and_return(false)
29
+ end
30
+
31
+ it_behaves_like 'module name from working directory'
32
+ end
33
+
34
+ context 'when metadata.json does exist' do
35
+ before(:each) do
36
+ allow(File).to receive(:file?).with('metadata.json').and_return(true)
37
+ end
38
+
39
+ context 'but it is not readable' do
40
+ before(:each) do
41
+ allow(File).to receive(:readable?).with('metadata.json').and_return(false)
42
+ end
43
+
44
+ it_behaves_like 'module name from working directory'
45
+ end
46
+
47
+ context 'and it is readable' do
48
+ before(:each) do
49
+ allow(File).to receive(:readable?).with('metadata.json').and_return(true)
50
+ allow(File).to receive(:read).with('metadata.json').and_return(metadata_content)
51
+ end
52
+
53
+ context 'but it contains invalid JSON' do
54
+ let(:metadata_content) { '{ "name": "my-awesome-module_from_metadata", }' }
55
+
56
+ it_behaves_like 'module name from working directory'
57
+ end
58
+
59
+ context 'and it contains a name value' do
60
+ let(:metadata_content) { '{ "name": "my-awesome-module_from_metadata" }' }
61
+
62
+ it_behaves_like 'module name from metadata'
63
+ end
64
+
65
+ context 'but it does not contain a name value' do
66
+ let(:metadata_content) { '{}' }
67
+
68
+ it_behaves_like 'module name from working directory'
69
+ end
70
+
71
+ context 'but the name has a null value' do
72
+ let(:metadata_content) { '{ "name": null }' }
73
+
74
+ it_behaves_like 'module name from working directory'
75
+ end
76
+
77
+ context 'but the name is blank' do
78
+ let(:metadata_content) { '{ "name": "" }' }
79
+
80
+ it_behaves_like 'module name from working directory'
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '.fixtures' do
87
+ subject(:helper) { described_class }
88
+
89
+ before :each do
90
+ # Unstub the fixtures "helpers"
91
+ PuppetlabsSpec::Fixtures.instance_methods.each do |m|
92
+ PuppetlabsSpec::Fixtures.send(:undef_method, m)
93
+ end
94
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return false
95
+ allow(File).to receive(:exist?).with('.fixtures.yaml').and_return false
96
+ allow(ENV).to receive(:[]).and_call_original
97
+ allow(ENV).to receive(:[]).with('FIXTURES_YML').and_return(nil)
98
+ allow(described_class).to receive(:auto_symlink).and_return('project' => source_dir.to_s)
99
+ end
100
+
101
+ context 'when file is missing' do
102
+ it 'returns basic directories per category' do
103
+ expect(helper.fixtures('forge_modules')).to eq({})
104
+ expect(helper.fixtures('repositories')).to eq({})
105
+ end
106
+ end
107
+
108
+ context 'when file is empty' do
109
+ it 'returns basic directories per category' do
110
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
111
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return false
112
+ expect(helper.fixtures('forge_modules')).to eq({})
113
+ expect(helper.fixtures('repositories')).to eq({})
114
+ end
115
+ end
116
+
117
+ context 'when file is malformed' do
118
+ it 'raises an error' do
119
+ expect(File).to receive(:exist?).with('.fixtures.yml').and_return true
120
+ expect(YAML).to receive(:load_file).with('.fixtures.yml').and_raise(Psych::SyntaxError.new('/file', '123', '0', '0', 'spec message', 'spec context'))
121
+ expect { helper.fixtures('forge_modules') }.to raise_error(RuntimeError, %r{malformed YAML})
122
+ end
123
+ end
124
+
125
+ context 'when file contains no fixtures' do
126
+ it 'raises an error' do
127
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
128
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return('some' => 'key')
129
+ expect { helper.fixtures('forge_modules') }.to raise_error(RuntimeError, %r{No 'fixtures'})
130
+ end
131
+ end
132
+
133
+ context 'when file specifies fixtures' do
134
+ it 'returns the hash' do
135
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
136
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return('fixtures' => { 'forge_modules' => { 'stdlib' => 'puppetlabs-stdlib' } })
137
+ expect(helper.fixtures('forge_modules')).to eq(
138
+ 'puppetlabs-stdlib' => {
139
+ 'target' => 'spec/fixtures/modules/stdlib',
140
+ 'ref' => nil,
141
+ 'branch' => nil,
142
+ 'scm' => nil,
143
+ 'flags' => nil,
144
+ 'subdir' => nil,
145
+ },
146
+ )
147
+ end
148
+ end
149
+
150
+ context 'when file specifies defaults' do
151
+ it 'returns the hash' do
152
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
153
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return('defaults' => { 'forge_modules' => { 'flags' => '--module_repository=https://myforge.example.com/' } },
154
+ 'fixtures' => { 'forge_modules' => { 'stdlib' => 'puppetlabs-stdlib' } })
155
+ expect(helper.fixtures('forge_modules')).to eq(
156
+ 'puppetlabs-stdlib' => {
157
+ 'target' => 'spec/fixtures/modules/stdlib',
158
+ 'ref' => nil,
159
+ 'branch' => nil,
160
+ 'scm' => nil,
161
+ 'flags' => '--module_repository=https://myforge.example.com/',
162
+ 'subdir' => nil,
163
+ },
164
+ )
165
+ end
166
+ end
167
+
168
+ context 'when file specifies repository fixtures' do
169
+ before(:each) do
170
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
171
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return(
172
+ 'fixtures' => {
173
+ 'repositories' => { 'stdlib' => 'https://github.com/puppetlabs/puppetlabs-stdlib.git' },
174
+ },
175
+ )
176
+ end
177
+
178
+ it 'returns the hash' do
179
+ expect(helper.repositories).to eq(
180
+ 'https://github.com/puppetlabs/puppetlabs-stdlib.git' => {
181
+ 'target' => 'spec/fixtures/modules/stdlib',
182
+ 'ref' => nil,
183
+ 'branch' => nil,
184
+ 'scm' => nil,
185
+ 'flags' => nil,
186
+ 'subdir' => nil,
187
+ },
188
+ )
189
+ end
190
+ end
191
+
192
+ context 'when file specifies repository fixtures with an invalid git ref' do
193
+ before(:each) do
194
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
195
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return(
196
+ 'fixtures' => {
197
+ 'repositories' => {
198
+ 'stdlib' => {
199
+ 'scm' => 'git',
200
+ 'repo' => 'https://github.com/puppetlabs/puppetlabs-stdlib.git',
201
+ 'ref' => 'this/is/a/branch',
202
+ },
203
+ },
204
+ },
205
+ )
206
+ end
207
+
208
+ it 'raises an ArgumentError' do
209
+ expect { helper.fixtures('repositories') }.to raise_error(ArgumentError)
210
+ end
211
+ end
212
+
213
+ context 'when file specifies puppet version' do
214
+ def stub_fixtures(data)
215
+ allow(File).to receive(:exist?).with('.fixtures.yml').and_return true
216
+ allow(YAML).to receive(:load_file).with('.fixtures.yml').and_return(data)
217
+ end
218
+
219
+ it 'includes the fixture if the puppet version matches', if: Gem::Version.new(Puppet::PUPPETVERSION) > Gem::Version.new('4') do
220
+ stub_fixtures(
221
+ 'fixtures' => {
222
+ 'forge_modules' => {
223
+ 'stdlib' => {
224
+ 'repo' => 'puppetlabs-stdlib',
225
+ 'puppet_version' => Puppet::PUPPETVERSION,
226
+ },
227
+ },
228
+ },
229
+ )
230
+ expect(helper.fixtures('forge_modules')).to include('puppetlabs-stdlib')
231
+ end
232
+
233
+ it 'excludes the fixture if the puppet version does not match', if: Gem::Version.new(Puppet::PUPPETVERSION) > Gem::Version.new('4') do
234
+ stub_fixtures(
235
+ 'fixtures' => {
236
+ 'forge_modules' => {
237
+ 'stdlib' => {
238
+ 'repo' => 'puppetlabs-stdlib',
239
+ 'puppet_version' => '>= 999.9.9',
240
+ },
241
+ },
242
+ },
243
+ )
244
+ expect(helper.fixtures('forge_modules')).to eq({})
245
+ end
246
+
247
+ it 'includes the fixture on obsolete puppet versions', if: Gem::Version.new(Puppet::PUPPETVERSION) <= Gem::Version.new('4') do
248
+ stub_fixtures(
249
+ 'fixtures' => {
250
+ 'forge_modules' => {
251
+ 'stdlib' => {
252
+ 'repo' => 'puppetlabs-stdlib',
253
+ 'puppet_version' => Puppet::PUPPETVERSION,
254
+ },
255
+ },
256
+ },
257
+ )
258
+ expect(helper.fixtures('forge_modules')).to include('puppetlabs-stdlib')
259
+ end
260
+ end
261
+ end
262
+ end
data/spec/watchr.rb ADDED
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV['FOG_MOCK'] ||= 'true'
4
+ ENV['AUTOTEST'] = 'true'
5
+ ENV['WATCHR'] = '1'
6
+
7
+ system 'clear'
8
+
9
+ def growl(message)
10
+ growlnotify = `which growlnotify`.chomp
11
+ title = 'Watchr Test Results'
12
+ image = case message
13
+ when %r{(\d+)\s+?(failure|error)}i
14
+ (Regexp.last_match(1).to_i == 0) ? '~/.watchr_images/passed.png' : '~/.watchr_images/failed.png'
15
+ else
16
+ '~/.watchr_images/unknown.png'
17
+ end
18
+ options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
19
+ system %(#{growlnotify} #{options} &)
20
+ end
21
+
22
+ def run(cmd)
23
+ puts(cmd)
24
+ `#{cmd}`
25
+ end
26
+
27
+ def run_spec_test(file)
28
+ if File.exist? file
29
+ result = run "rspec --format p #{file}"
30
+ growl result.split("\n").last
31
+ puts result
32
+ else
33
+ puts "FIXME: No test #{file} [#{Time.now}]"
34
+ end
35
+ end
36
+
37
+ def filter_rspec(data)
38
+ data.split("\n").select { |l|
39
+ l =~ %r{^(\d+)\s+exampl\w+.*?(\d+).*?failur\w+.*?(\d+).*?pending}
40
+ }.join("\n")
41
+ end
42
+
43
+ def run_all_tests
44
+ system('clear')
45
+ files = Dir.glob('spec/**/*_spec.rb').join(' ')
46
+ result = run "rspec #{files}"
47
+ growl_results = filter_rspec result
48
+ growl growl_results
49
+ puts result
50
+ puts "GROWL: #{growl_results}"
51
+ end
52
+
53
+ # Ctrl-\
54
+ Signal.trap 'QUIT' do
55
+ puts " --- Running all tests ---\n\n"
56
+ run_all_tests
57
+ end
58
+
59
+ @interrupted = false
60
+
61
+ # Ctrl-C
62
+ Signal.trap 'INT' do
63
+ if @interrupted
64
+ @wants_to_quit = true
65
+ abort("\n")
66
+ else
67
+ puts 'Interrupt a second time to quit'
68
+ @interrupted = true
69
+ Kernel.sleep 1.5
70
+ # raise Interrupt, nil # let the run loop catch it
71
+ run_suite
72
+ end
73
+ end
74
+
75
+ watch('spec/.*_spec\.rb') do |_md|
76
+ run_all_tests
77
+ end
78
+
79
+ watch('lib/.*\.rb') do |_md|
80
+ run_all_tests
81
+ end