delta_test 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +4 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +165 -0
  8. data/Rakefile +17 -0
  9. data/bin/delta_test +12 -0
  10. data/circle.yml +12 -0
  11. data/delta_test.gemspec +30 -0
  12. data/lib/delta_test/analyzer.rb +47 -0
  13. data/lib/delta_test/cli.rb +224 -0
  14. data/lib/delta_test/configuration.rb +173 -0
  15. data/lib/delta_test/dependencies_table.rb +83 -0
  16. data/lib/delta_test/errors.rb +55 -0
  17. data/lib/delta_test/generator.rb +101 -0
  18. data/lib/delta_test/git.rb +88 -0
  19. data/lib/delta_test/related_spec_list.rb +64 -0
  20. data/lib/delta_test/spec_helpers.rb +42 -0
  21. data/lib/delta_test/utils.rb +93 -0
  22. data/lib/delta_test/version.rb +9 -0
  23. data/lib/delta_test.rb +47 -0
  24. data/spec/fixtures/sample/alpha.rb +19 -0
  25. data/spec/fixtures/sample/beta.rb +15 -0
  26. data/spec/fixtures/sample/gamma.rb +9 -0
  27. data/spec/lib/delta_test/analyzer_spec.rb +126 -0
  28. data/spec/lib/delta_test/cli_spec.rb +422 -0
  29. data/spec/lib/delta_test/configuration_spec.rb +353 -0
  30. data/spec/lib/delta_test/dependencies_table_spec.rb +129 -0
  31. data/spec/lib/delta_test/generator_spec.rb +201 -0
  32. data/spec/lib/delta_test/git_spec.rb +178 -0
  33. data/spec/lib/delta_test/related_spec_list_spec.rb +182 -0
  34. data/spec/lib/delta_test/spec_helpers_spec.rb +72 -0
  35. data/spec/lib/delta_test/utils_spec.rb +244 -0
  36. data/spec/lib/delta_test_spec.rb +119 -0
  37. data/spec/rails/.gitignore +19 -0
  38. data/spec/rails/.rspec +3 -0
  39. data/spec/rails/Gemfile +15 -0
  40. data/spec/rails/Gemfile.lock +163 -0
  41. data/spec/rails/README.rdoc +28 -0
  42. data/spec/rails/Rakefile +6 -0
  43. data/spec/rails/app/controllers/application_controller.rb +5 -0
  44. data/spec/rails/app/controllers/concerns/.keep +0 -0
  45. data/spec/rails/app/helpers/application_helper.rb +2 -0
  46. data/spec/rails/app/mailers/.keep +0 -0
  47. data/spec/rails/app/models/.keep +0 -0
  48. data/spec/rails/app/models/concerns/.keep +0 -0
  49. data/spec/rails/app/views/layouts/application.html.haml +7 -0
  50. data/spec/rails/bin/bundle +3 -0
  51. data/spec/rails/bin/rails +4 -0
  52. data/spec/rails/bin/rake +4 -0
  53. data/spec/rails/bin/setup +29 -0
  54. data/spec/rails/config/application.rb +35 -0
  55. data/spec/rails/config/boot.rb +3 -0
  56. data/spec/rails/config/database.yml +25 -0
  57. data/spec/rails/config/environment.rb +5 -0
  58. data/spec/rails/config/environments/development.rb +41 -0
  59. data/spec/rails/config/environments/production.rb +79 -0
  60. data/spec/rails/config/environments/test.rb +42 -0
  61. data/spec/rails/config/initializers/assets.rb +11 -0
  62. data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
  63. data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
  64. data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
  65. data/spec/rails/config/initializers/inflections.rb +16 -0
  66. data/spec/rails/config/initializers/mime_types.rb +4 -0
  67. data/spec/rails/config/initializers/session_store.rb +3 -0
  68. data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
  69. data/spec/rails/config/locales/en.yml +23 -0
  70. data/spec/rails/config/routes.rb +56 -0
  71. data/spec/rails/config/secrets.yml +22 -0
  72. data/spec/rails/config.ru +4 -0
  73. data/spec/rails/db/seeds.rb +7 -0
  74. data/spec/rails/delta_test.yml +5 -0
  75. data/spec/rails/lib/assets/.keep +0 -0
  76. data/spec/rails/lib/tasks/.keep +0 -0
  77. data/spec/rails/log/.keep +0 -0
  78. data/spec/rails/public/404.html +67 -0
  79. data/spec/rails/public/422.html +67 -0
  80. data/spec/rails/public/500.html +66 -0
  81. data/spec/rails/public/favicon.ico +0 -0
  82. data/spec/rails/public/robots.txt +5 -0
  83. data/spec/rails/spec/features/sample_spec.rb +7 -0
  84. data/spec/rails/spec/spec_helper.rb +16 -0
  85. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  86. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  87. data/spec/spec_helper.rb +39 -0
  88. data/spec/supports/create_table_file.rb +21 -0
  89. metadata +283 -0
data/lib/delta_test.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'pathname'
2
+
3
+ require_relative 'delta_test/version'
4
+ require_relative 'delta_test/errors'
5
+ require_relative 'delta_test/configuration'
6
+
7
+ module DeltaTest
8
+
9
+ ACTIVE_FLAG = 'DELTA_TEST_ACTIVE'
10
+ VERBOSE_FLAG = 'DELTA_TEST_VERBOSE'
11
+
12
+ class << self
13
+
14
+ attr_reader :config
15
+
16
+ attr_writer *%i[
17
+ active
18
+ verbose
19
+ ]
20
+
21
+ def setup
22
+ @config = Configuration.new
23
+ @config.auto_configure! if active?
24
+ end
25
+
26
+ def configure(&block)
27
+ @config.update(&block)
28
+ end
29
+
30
+ def active?
31
+ return !!@active unless @active.nil?
32
+ @active = (!ENV[ACTIVE_FLAG].nil? && ENV[ACTIVE_FLAG] !~ /0|false/i)
33
+ end
34
+
35
+ def verbose?
36
+ return !!@verbose unless @verbose.nil?
37
+ @verbose = (!ENV[VERBOSE_FLAG].nil? && ENV[VERBOSE_FLAG] !~ /0|false/i)
38
+ end
39
+
40
+ def log(*args)
41
+ puts *args if verbose?
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ DeltaTest.setup
@@ -0,0 +1,19 @@
1
+ require_relative "beta"
2
+
3
+ module Sample
4
+ class Alpha
5
+
6
+ def alpha
7
+ self
8
+ end
9
+
10
+ def beta
11
+ Beta.new.beta
12
+ end
13
+
14
+ def beta_gamma
15
+ beta.gamma
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "gamma"
2
+
3
+ module Sample
4
+ class Beta
5
+
6
+ def beta
7
+ self
8
+ end
9
+
10
+ def gamma
11
+ Gamma.new.gamma
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Sample
2
+ class Gamma
3
+
4
+ def gamma
5
+ self
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,126 @@
1
+ require 'delta_test/analyzer'
2
+
3
+ describe DeltaTest::Analyzer do
4
+
5
+ let(:analyzer) { DeltaTest::Analyzer.new }
6
+
7
+ after do
8
+ RubyProf.stop if RubyProf.running?
9
+ end
10
+
11
+ describe '#new' do
12
+
13
+ it 'should initialize new instance' do
14
+ expect { analyzer }.not_to raise_error
15
+ end
16
+
17
+ end
18
+
19
+ describe '#start' do
20
+
21
+ it 'should start ruby-prof' do
22
+ expect(RubyProf.running?).to be(false)
23
+
24
+ expect {
25
+ analyzer.start
26
+ }.not_to raise_error
27
+
28
+ expect(RubyProf.running?).to be(true)
29
+ end
30
+
31
+ end
32
+
33
+ describe '#stop' do
34
+
35
+ it 'should not raise error if `start` is not yet called' do
36
+ expect {
37
+ analyzer.stop
38
+ }.not_to raise_error
39
+ end
40
+
41
+ it 'should set result' do
42
+ analyzer.start
43
+
44
+ expect(analyzer.result).to be_nil
45
+
46
+ expect {
47
+ analyzer.stop
48
+ }.not_to raise_error
49
+
50
+ expect(analyzer.result).not_to be_nil
51
+ end
52
+
53
+ end
54
+
55
+ describe '#related_source_files' do
56
+
57
+ it 'should retrun nil if not yet started' do
58
+ expect(analyzer.related_source_files).to be_nil
59
+ end
60
+
61
+ it 'should return an empty set unless stop' do
62
+ analyzer.start
63
+ expect(analyzer.related_source_files).to be_empty
64
+ end
65
+
66
+ it 'should return a set of source files after stopped' do
67
+ analyzer.start
68
+ analyzer.stop
69
+ expect(analyzer.related_source_files).not_to be_empty
70
+ end
71
+
72
+ describe 'Source files' do
73
+
74
+ context 'Instantiated class in a file' do
75
+
76
+ it 'should not include the file' do
77
+ analyzer.start
78
+ Sample::Alpha.new
79
+ analyzer.stop
80
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/alpha.rb'))
81
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/beta.rb'))
82
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/gamma.rb'))
83
+ end
84
+
85
+ end
86
+
87
+ context 'Called some instance methods of a class in the file' do
88
+
89
+ it 'should include the file' do
90
+ analyzer.start
91
+ Sample::Alpha.new.alpha
92
+ analyzer.stop
93
+ expect(analyzer.related_source_files).to include(fixture_path('sample/alpha.rb'))
94
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/beta.rb'))
95
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/gamma.rb'))
96
+ end
97
+
98
+ end
99
+
100
+ context 'Called methods that uses extarnal classes' do
101
+
102
+ it 'should include a extarnal file' do
103
+ analyzer.start
104
+ Sample::Alpha.new.beta
105
+ analyzer.stop
106
+ expect(analyzer.related_source_files).to include(fixture_path('sample/alpha.rb'))
107
+ expect(analyzer.related_source_files).to include(fixture_path('sample/beta.rb'))
108
+ expect(analyzer.related_source_files).not_to include(fixture_path('sample/gamma.rb'))
109
+ end
110
+
111
+ it 'should include extarnal files even if nested' do
112
+ analyzer.start
113
+ Sample::Alpha.new.beta_gamma
114
+ analyzer.stop
115
+ expect(analyzer.related_source_files).to include(fixture_path('sample/alpha.rb'))
116
+ expect(analyzer.related_source_files).to include(fixture_path('sample/beta.rb'))
117
+ expect(analyzer.related_source_files).to include(fixture_path('sample/gamma.rb'))
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+
126
+ end
@@ -0,0 +1,422 @@
1
+ require 'delta_test/cli'
2
+ require 'delta_test/git'
3
+
4
+ describe DeltaTest::CLI do
5
+
6
+ let(:cli) { DeltaTest::CLI.new }
7
+
8
+ before do
9
+ DeltaTest::CLI.class_eval do
10
+ attr_writer :args
11
+ attr_writer :options
12
+ attr_writer :command
13
+ attr_reader :list
14
+ end
15
+
16
+ # ignore outputs
17
+ allow($stdout).to receive(:puts).with(any_args).and_return(nil)
18
+ allow($stderr).to receive(:puts).with(any_args).and_return(nil)
19
+ end
20
+
21
+ describe '#run' do
22
+
23
+ before do
24
+ allow(cli).to receive(:invoke).with(no_args).and_return(nil)
25
+ end
26
+
27
+ it 'should set the first argument as command' do
28
+ args = ['command', 'foo', 'bar']
29
+ cli.run(args)
30
+ expect(cli.command).to eq(args[0])
31
+ end
32
+
33
+ it 'should call `parse_options!` and `invoke`' do
34
+ expect(cli).to receive(:parse_options!).with(no_args).and_return({}).once.ordered
35
+ expect(cli).to receive(:invoke).with(no_args).once.ordered
36
+
37
+ args = ['command', 'foo', 'bar']
38
+ cli.run(args)
39
+ end
40
+
41
+ end
42
+
43
+ describe '#parse_options!' do
44
+
45
+ it 'should parse short options' do
46
+ cli.args = ['-a', '-b']
47
+
48
+ options = cli.parse_options!
49
+
50
+ expect(cli.args).to be_empty
51
+ expect(options).to be_a(Hash)
52
+ expect(options['a']).to be(true)
53
+ expect(options['b']).to be(true)
54
+ end
55
+
56
+ it 'should parse long options' do
57
+ cli.args = ['--long-a', '--long-b']
58
+
59
+ options = cli.parse_options!
60
+
61
+ expect(cli.args).to be_empty
62
+ expect(options).to be_a(Hash)
63
+ expect(options['long-a']).to be(true)
64
+ expect(options['long-b']).to be(true)
65
+ end
66
+
67
+ it 'should parse long options with value' do
68
+ cli.args = ['--long-a=value-of-a', '--long-b=value-of-b']
69
+
70
+ options = cli.parse_options!
71
+
72
+ expect(cli.args).to be_empty
73
+ expect(options).to be_a(Hash)
74
+ expect(options['long-a']).to eq('value-of-a')
75
+ expect(options['long-b']).to eq('value-of-b')
76
+ end
77
+
78
+ it 'should not parse options after once non-option args appears' do
79
+ cli.args = ['-a', '--long-a', 'non-option', '--long-b=value-of-b']
80
+
81
+ options = cli.parse_options!
82
+
83
+ expect(cli.args).to eq(['non-option', '--long-b=value-of-b'])
84
+ expect(options).to be_a(Hash)
85
+ expect(options['a']).to be(true)
86
+ expect(options['long-a']).to be(true)
87
+ expect(options['long-b']).to be_nil
88
+ end
89
+
90
+ describe 'Defaults' do
91
+
92
+ it 'should set default options' do
93
+ cli.args = []
94
+
95
+ options = cli.parse_options!
96
+
97
+ expect(options).to be_a(Hash)
98
+
99
+ expect(options['base']).to eq('master')
100
+ expect(options['head']).to eq('HEAD')
101
+ end
102
+
103
+ it 'should be able to overwrite default options' do
104
+ cli.args = ['--base=develop', '--head=feature/foo']
105
+
106
+ options = cli.parse_options!
107
+
108
+ expect(options).to be_a(Hash)
109
+
110
+ expect(options['base']).to eq('develop')
111
+ expect(options['head']).to eq('feature/foo')
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ describe '#exit_with_message' do
119
+
120
+ let(:message) { 'a message' }
121
+ let(:message_regexp) { /a message/ }
122
+
123
+ context 'With status code of zero' do
124
+
125
+ let(:status) { 0 }
126
+
127
+ it 'should print a message to stdout and exit' do
128
+ expect {
129
+ begin
130
+ cli.exit_with_message(status, message)
131
+ rescue SystemExit => e
132
+ expect(e.status).to eq(status)
133
+ end
134
+ }.to output(message_regexp).to_stdout
135
+ end
136
+
137
+ end
138
+
139
+ context 'With status code of non-zero' do
140
+
141
+ let(:status) { 1 }
142
+
143
+ it 'should print a message to stderr and exit' do
144
+ expect {
145
+ begin
146
+ cli.exit_with_message(status, message)
147
+ rescue SystemExit => e
148
+ expect(e.status).to eq(status)
149
+ end
150
+ }.to output(message_regexp).to_stderr
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+
157
+ describe '#run_full_tests?' do
158
+
159
+ let(:map) do
160
+ {
161
+ 'master' => '0000000000000000000000000000000000000000',
162
+ 'feature/foo' => '1111111111111111111111111111111111111111',
163
+ }
164
+ end
165
+
166
+ before do
167
+ map.each do |name, commit_id|
168
+ allow(DeltaTest::Git).to receive(:rev_parse).with(name).and_return(commit_id)
169
+ end
170
+ end
171
+
172
+ context 'When base and head is the same commit' do
173
+
174
+ before do
175
+ cli.options = {
176
+ 'base' => 'master',
177
+ 'head' => 'master',
178
+ }
179
+ end
180
+
181
+ it 'should return true' do
182
+ expect(cli.run_full_tests?).to be(true)
183
+ end
184
+
185
+ end
186
+
187
+ context 'When base and head is a different commit' do
188
+
189
+ before do
190
+ cli.options = {
191
+ 'base' => 'master',
192
+ 'head' => 'feature/foo',
193
+ }
194
+ end
195
+
196
+ it 'should return false' do
197
+ expect(cli.run_full_tests?).to be(false)
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+
204
+ context 'Commands' do
205
+
206
+ describe '#do_table' do
207
+
208
+ let(:table) do
209
+ {
210
+ 'spec/foo_spec.rb' => ['lib/foo.rb']
211
+ }
212
+ end
213
+
214
+ before do
215
+ allow(cli).to receive(:invoke).with(no_args).and_return(nil)
216
+
217
+ cli.run([])
218
+
219
+ allow(cli.list).to receive(:load_table!).with(no_args).and_return(nil)
220
+ allow(cli.list).to receive(:table).with(no_args).and_return(table)
221
+ end
222
+
223
+ it 'should load a table file' do
224
+ expect(cli.list).to receive(:load_table!).with(no_args).once.ordered
225
+ expect(cli.list).to receive(:table).with(no_args).once.ordered
226
+
227
+ expect {
228
+ cli.do_table
229
+ }.not_to raise_error
230
+ end
231
+
232
+ it 'should show the table contents' do
233
+ expect(cli.list).to receive(:load_table!).with(no_args).once.ordered
234
+ expect(cli.list).to receive(:table).with(no_args).once.ordered
235
+
236
+ expect {
237
+ cli.do_table
238
+ }.to output(/foo_spec\.rb/).to_stdout
239
+ end
240
+
241
+ end
242
+
243
+ describe '#do_list' do
244
+
245
+ let(:related_spec_files) do
246
+ [
247
+ 'spec/foo_spec.rb',
248
+ ]
249
+ end
250
+
251
+ before do
252
+ allow(cli).to receive(:invoke).with(no_args).and_return(nil)
253
+
254
+ cli.run([])
255
+
256
+ allow(cli.list).to receive(:load_table!).with(no_args).and_return(nil)
257
+ allow(cli.list).to receive(:retrive_changed_files!).with(any_args).and_return(nil)
258
+ allow(cli.list).to receive(:related_spec_files).with(no_args).and_return(related_spec_files)
259
+ end
260
+
261
+ it 'should load a table file and retrive changed files' do
262
+ expect(cli.list).to receive(:load_table!).with(no_args).once.ordered
263
+ expect(cli.list).to receive(:retrive_changed_files!).with(any_args).once.ordered
264
+
265
+ expect {
266
+ cli.do_list
267
+ }.not_to raise_error
268
+ end
269
+
270
+ it 'should show a list of related spec files' do
271
+ expect(cli.list).to receive(:load_table!).with(no_args).once.ordered
272
+ expect(cli.list).to receive(:retrive_changed_files!).with(any_args).once.ordered
273
+ expect(cli.list).to receive(:related_spec_files).with(no_args).once.ordered
274
+
275
+ expect {
276
+ cli.do_list
277
+ }.to output(/foo_spec\.rb/).to_stdout
278
+ end
279
+
280
+ end
281
+
282
+ describe '#do_exec' do
283
+
284
+ let(:args) do
285
+ ['exec', 'bundle', 'exec', 'rspec']
286
+ end
287
+
288
+ let(:related_spec_files) do
289
+ [
290
+ 'spec/foo_spec.rb',
291
+ ]
292
+ end
293
+
294
+ before do
295
+ allow(cli).to receive(:invoke).with(no_args).and_return(nil)
296
+
297
+ cli.run(args)
298
+
299
+ allow(cli.list).to receive(:load_table!).with(no_args).and_return(nil)
300
+ allow(cli.list).to receive(:retrive_changed_files!).with(any_args).and_return(nil)
301
+ allow(cli.list).to receive(:related_spec_files).with(no_args).and_return(related_spec_files)
302
+
303
+ allow(Open3).to receive(:popen3).with(any_args).and_return(nil)
304
+ end
305
+
306
+ context 'Full tests' do
307
+
308
+ before do
309
+ expect(cli).to receive(:run_full_tests?).with(no_args).and_return(true)
310
+ end
311
+
312
+ it 'should run script with a flag' do
313
+ expect(cli.list).not_to receive(:related_spec_files).with(no_args)
314
+
315
+ _args = ['%s=%s' % [DeltaTest::ACTIVE_FLAG, true], *args[1..-1]].join(' ')
316
+ expect(Open3).to receive(:popen3).with(_args)
317
+
318
+ expect {
319
+ cli.do_exec
320
+ }.not_to raise_error
321
+ end
322
+
323
+ end
324
+
325
+ context 'Partial tests' do
326
+
327
+ before do
328
+ expect(cli).to receive(:run_full_tests?).with(no_args).and_return(false)
329
+ end
330
+
331
+ context 'Any related files' do
332
+
333
+ it 'should run script with related spec files' do
334
+ expect(cli.list).to receive(:related_spec_files).with(no_args)
335
+
336
+ _args = ['cat', '|', 'xargs', *args[1..-1]].join(' ')
337
+ expect(Open3).to receive(:popen3).with(_args)
338
+
339
+ expect {
340
+ cli.do_exec
341
+ }.not_to raise_error
342
+ end
343
+
344
+ end
345
+
346
+ context 'No related files' do
347
+
348
+ let(:related_spec_files) { [] }
349
+
350
+ it 'should not run script and exit with a message' do
351
+ expect(cli.list).to receive(:related_spec_files).with(no_args)
352
+
353
+ expect {
354
+ begin
355
+ cli.do_exec
356
+ rescue SystemExit => e
357
+ expect(e.status).to eq(0)
358
+ end
359
+ }.to output(/Nothing/).to_stdout
360
+ end
361
+
362
+ end
363
+
364
+ end
365
+
366
+ end
367
+
368
+ describe '#do_help' do
369
+
370
+ it 'should print help' do
371
+ expect {
372
+ cli.do_help
373
+ }.to output(/usage/).to_stdout
374
+ end
375
+
376
+ end
377
+
378
+ describe '#do_version' do
379
+
380
+ it 'should print gem version' do
381
+ expect {
382
+ cli.do_version
383
+ }.to output(/v\d+\.\d+.\d+/).to_stdout
384
+ end
385
+
386
+ end
387
+
388
+ end
389
+
390
+ describe '#invoke' do
391
+
392
+ let(:commands) do
393
+ {
394
+ 'list' => 'do_list',
395
+ 'table' => 'do_table',
396
+ 'exec' => 'do_exec',
397
+ 'help' => 'do_help',
398
+ '-v' => 'do_version',
399
+ }
400
+ end
401
+
402
+ before do
403
+ commands.each do |_, action|
404
+ allow(cli).to receive(action).with(no_args).and_return(nil)
405
+ end
406
+ end
407
+
408
+ it 'should invoke method for a command' do
409
+ commands.each do |command, action|
410
+ expect(cli).to receive(action).with(no_args)
411
+
412
+ cli.command = command
413
+
414
+ expect {
415
+ cli.invoke
416
+ }.not_to raise_error
417
+ end
418
+ end
419
+
420
+ end
421
+
422
+ end