rspeed 0.0.1 → 0.5.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/LICENSE +1 -1
  4. data/README.md +88 -5
  5. data/lib/generators/rspeed/install_generator.rb +13 -0
  6. data/lib/generators/rspeed/templates/lib/tasks/rspeed.rb +9 -0
  7. data/lib/rspeed.rb +9 -0
  8. data/lib/rspeed/env.rb +43 -0
  9. data/lib/rspeed/extension.rb +12 -0
  10. data/lib/rspeed/observer.rb +43 -0
  11. data/lib/rspeed/redis.rb +55 -0
  12. data/lib/rspeed/runner.rb +13 -0
  13. data/lib/rspeed/splitter.rb +130 -0
  14. data/lib/rspeed/variable.rb +31 -0
  15. data/lib/rspeed/version.rb +1 -1
  16. data/spec/common_helper.rb +10 -0
  17. data/spec/fixtures/1_spec.rb +9 -0
  18. data/spec/fixtures/2_spec.rb +5 -0
  19. data/spec/fixtures/empty.rb +4 -0
  20. data/spec/fixtures/new_spec.rb.csv +1 -0
  21. data/spec/models/rspeed/env/db_spec.rb +17 -0
  22. data/spec/models/rspeed/env/host_spec.rb +17 -0
  23. data/spec/models/rspeed/env/name_spec.rb +17 -0
  24. data/spec/models/rspeed/env/pipe_spec.rb +19 -0
  25. data/spec/models/rspeed/env/pipes_spec.rb +41 -0
  26. data/spec/models/rspeed/env/port_spec.rb +17 -0
  27. data/spec/models/rspeed/env/result_key_spec.rb +19 -0
  28. data/spec/models/rspeed/env/rspeed_spec.rb +43 -0
  29. data/spec/models/rspeed/env/tmp_spec.rb +19 -0
  30. data/spec/models/rspeed/observer/after_spec.rb +16 -0
  31. data/spec/models/rspeed/observer/after_suite_spec.rb +46 -0
  32. data/spec/models/rspeed/observer/before_spec.rb +15 -0
  33. data/spec/models/rspeed/observer/before_suite_spec.rb +37 -0
  34. data/spec/models/rspeed/redis/clean_pipes_flag_spec.rb +14 -0
  35. data/spec/models/rspeed/redis/client_spec.rb +7 -0
  36. data/spec/models/rspeed/redis/destroy_spec.rb +29 -0
  37. data/spec/models/rspeed/redis/get_spec.rb +9 -0
  38. data/spec/models/rspeed/redis/keys_spec.rb +29 -0
  39. data/spec/models/rspeed/redis/result_spec.rb +13 -0
  40. data/spec/models/rspeed/redis/set_spec.rb +9 -0
  41. data/spec/models/rspeed/redis/specs_finished_spec.rb +19 -0
  42. data/spec/models/rspeed/redis/specs_initiated_spec.rb +13 -0
  43. data/spec/models/rspeed/runner/run_spec.rb +30 -0
  44. data/spec/models/rspeed/splitter/actual_examples_spec.rb +26 -0
  45. data/spec/models/rspeed/splitter/append_spec.rb +35 -0
  46. data/spec/models/rspeed/splitter/diff_spec.rb +30 -0
  47. data/spec/models/rspeed/splitter/first_pipe_spec.rb +17 -0
  48. data/spec/models/rspeed/splitter/get_spec.rb +74 -0
  49. data/spec/models/rspeed/splitter/pipe_files_spec.rb +26 -0
  50. data/spec/models/rspeed/splitter/redundant_run_spec.rb +45 -0
  51. data/spec/models/rspeed/splitter/rename_spec.rb +16 -0
  52. data/spec/models/rspeed/splitter/split_spec.rb +89 -0
  53. data/spec/models/rspeed/variable/append_name_spec.rb +19 -0
  54. data/spec/models/rspeed/variable/csv_spec.rb +5 -0
  55. data/spec/models/rspeed/variable/default_partner_spec.rb +5 -0
  56. data/spec/models/rspeed/variable/key_spec.rb +15 -0
  57. data/spec/models/rspeed/variable/pipe_name_spec.rb +15 -0
  58. data/spec/models/rspeed/variable/pipes_pattern_spec.rb +5 -0
  59. data/spec/models/rspeed/variable/result_spec.rb +19 -0
  60. data/spec/models/rspeed/variable/tmp_spec.rb +15 -0
  61. data/spec/spec_helper.rb +27 -0
  62. data/spec/support/common.rb +5 -3
  63. data/spec/support/coverage.rb +14 -0
  64. data/spec/support/env_mock.rb +3 -0
  65. data/spec/support/fakeredis.rb +3 -0
  66. metadata +180 -23
  67. data/spec/rails_helper.rb +0 -9
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '#destroy' do
4
+ let!(:redis) { described_class }
5
+
6
+ before do
7
+ redis.set('rspeed', '{}')
8
+ redis.set('rspeed_1', '{}')
9
+ redis.set('rspeed_2', '{}')
10
+ end
11
+
12
+ it 'destroys via wildcard' do
13
+ redis.destroy('rspeed_*')
14
+
15
+ expect(redis.keys('*')).to eq %w[rspeed]
16
+ end
17
+
18
+ it 'destroys via single name' do
19
+ redis.destroy('rspeed')
20
+
21
+ expect(redis.keys('*')).to eq %w[rspeed_1 rspeed_2]
22
+ end
23
+
24
+ it 'destroys default partner when no pattern is given' do
25
+ redis.destroy
26
+
27
+ expect(redis.keys('*')).to eq %w[rspeed]
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '.set' do
4
+ it 'sets a key on redis' do
5
+ described_class.client.set('key', 'value')
6
+
7
+ expect(described_class.get('key')).to eq('value')
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '.keys' do
4
+ subject(:redis) { described_class }
5
+
6
+ context 'with default config' do
7
+ before do
8
+ described_class.set('rspeed_1', 'value_1')
9
+ described_class.set('rspeed_2', 'value_2')
10
+ described_class.set('rspeed_3', 'value_3')
11
+ end
12
+
13
+ it 'shows keys' do
14
+ expect(redis.keys).to eq %w[rspeed_1 rspeed_2 rspeed_3]
15
+ end
16
+ end
17
+
18
+ context 'with custom key' do
19
+ before do
20
+ described_class.set('custom_key_1', 'value_1')
21
+ described_class.set('custom_key_2', 'value_2')
22
+ described_class.set('custom_key_3', 'value_3')
23
+ end
24
+
25
+ it 'shows keys' do
26
+ expect(redis.keys('custom_key_*')).to eq %w[custom_key_1 custom_key_2 custom_key_3]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '#result?' do
4
+ context 'when has no key rspeed on redis' do
5
+ it { expect(described_class.result?).to be(false) }
6
+ end
7
+
8
+ context 'when has key rspeed on redis' do
9
+ before { described_class.set('rspeed', { files: [[1, '1_spec.rb']], number: 0, total: 1 }.to_json) }
10
+
11
+ it { expect(described_class.result?).to be(true) }
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '.set' do
4
+ it 'sets a key on redis' do
5
+ described_class.set('key', 'value')
6
+
7
+ expect(described_class.client.get('key')).to eq('value')
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '.specs_finished?' do
4
+ before do
5
+ described_class.set('rspeed_pipe_1', '1.0')
6
+
7
+ allow(RSpeed::Env).to receive(:pipes).and_return(2)
8
+ end
9
+
10
+ context 'when the quantity of pipe result is not the same as the quantity of pipes' do
11
+ it { expect(described_class.specs_finished?).to be(false) }
12
+ end
13
+
14
+ context 'when the quantity of pipe result is the same as the quantity of pipes' do
15
+ before { described_class.set('rspeed_pipe_2', '2.0') }
16
+
17
+ it { expect(described_class.specs_finished?).to be(true) }
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Redis, '.specs_initiated?' do
4
+ context 'when has no pipe flag key' do
5
+ it { expect(described_class.specs_finished?).to be(false) }
6
+ end
7
+
8
+ context 'when has at least one pipe flag key' do
9
+ before { described_class.set('rspeed_pipe_1', '1.0') }
10
+
11
+ it { expect(described_class.specs_finished?).to be(true) }
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Runner, '#run' do
4
+ let!(:shell) { double('shell') }
5
+ let!(:splitter) { instance_double('RSpeed::Splitter') }
6
+
7
+ before { allow(RSpeed::Splitter).to receive(:new).and_return(splitter) }
8
+
9
+ context 'when is a redundant run' do
10
+ before { allow(splitter).to receive(:redundant_run?).and_return(true) }
11
+
12
+ it 'aborts the run' do
13
+ expect(described_class.run(shell)).to be(nil)
14
+ end
15
+ end
16
+
17
+ context 'when is not a redundant run' do
18
+ before do
19
+ allow(splitter).to receive(:redundant_run?).and_return(false)
20
+ allow(shell).to receive(:call)
21
+ allow(splitter).to receive(:pipe_files).and_return('spec_1.rb spec_2.rb')
22
+ end
23
+
24
+ it 'run the pipe specs' do
25
+ described_class.run(shell)
26
+
27
+ expect(shell).to have_received(:call).with('bundle exec rspec spec_1.rb spec_2.rb')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#actual_examples' do
4
+ it 'returns all examples' do
5
+ splitter = described_class.new(specs_path: 'spec/fixtures/**/*_spec.rb')
6
+
7
+ expect(splitter.actual_examples).to eq [
8
+ 'spec/fixtures/1_spec.rb:4',
9
+ 'spec/fixtures/1_spec.rb:6',
10
+ 'spec/fixtures/1_spec.rb:8',
11
+ 'spec/fixtures/2_spec.rb:4',
12
+ ]
13
+ end
14
+
15
+ it 'does not raise when no file match' do
16
+ splitter = described_class.new(specs_path: 'spec/fixtures/**/*_missing.rb')
17
+
18
+ expect(splitter.actual_examples).to eq []
19
+ end
20
+
21
+ it 'does not raise when file is empty' do
22
+ splitter = described_class.new(specs_path: 'spec/fixtures/**/empty.rb')
23
+
24
+ expect(splitter.actual_examples).to eq []
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#append' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ it 'appends file and time on rspeed key' do
7
+ splitter.append [[1, '1_spec.rb'], [2, '2_spec.rb']]
8
+
9
+ expect(splitter.get('rspeed_tmp')).to eq [
10
+ '{"file":"2_spec.rb","time":2.0}',
11
+ '{"file":"1_spec.rb","time":1.0}',
12
+ ]
13
+ end
14
+
15
+ context 'when files is not given' do
16
+ before do
17
+ truncate_file
18
+ populate_csv_file
19
+ end
20
+
21
+ it 'read csv and append file and time on rspeed key' do
22
+ splitter.append
23
+
24
+ expect(splitter.get('rspeed_tmp')).to eq [
25
+ '{"file":"./spec/0_2_spec.rb","time":0.2}',
26
+ '{"file":"./spec/0_3_spec.rb","time":0.3}',
27
+ '{"file":"./spec/0_4_spec.rb","time":0.4}',
28
+ '{"file":"./spec/0_7_spec.rb","time":0.7}',
29
+ '{"file":"./spec/1_1_spec.rb","time":1.1}',
30
+ '{"file":"./spec/1_5_spec.rb","time":1.5}',
31
+ '{"file":"./spec/2_0_spec.rb","time":2.0}',
32
+ ]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#diff' do
4
+ subject(:splitter) { described_class.new(specs_path: './spec/fixtures/*_spec.rb') }
5
+
6
+ let!(:redis) { redis_object }
7
+
8
+ before do
9
+ redis.lpush 'rspeed', { file: './spec/fixtures/1_spec.rb:4', time: '1.4' }.to_json
10
+ redis.lpush 'rspeed', { file: './spec/fixtures/1_spec.rb:6', time: '1.6' }.to_json
11
+ redis.lpush 'rspeed', { file: './spec/fixtures/1_spec.rb:8', time: '1.8' }.to_json
12
+ redis.lpush 'rspeed', { file: './spec/fixtures/2_spec.rb:4', time: '2.4' }.to_json
13
+ redis.lpush 'rspeed', { file: './spec/fixtures/2_spec.rb:666', time: '6' }.to_json
14
+ redis.lpush 'rspeed', { file: './spec/fixtures/x_spec.rb:1', time: 3 }.to_json
15
+
16
+ File.open('spec/fixtures/new_spec.rb', 'a') { |file| file.write('it') }
17
+ end
18
+
19
+ after { delete_file('spec/fixtures/new_spec.rb') }
20
+
21
+ it 'removes removed specs and adds new spec and keeps keeped specs based on rspeed key values' do
22
+ expect(splitter.diff).to eq [
23
+ { file: './spec/fixtures/2_spec.rb:4', time: '2.4' },
24
+ { file: './spec/fixtures/1_spec.rb:8', time: '1.8' },
25
+ { file: './spec/fixtures/1_spec.rb:6', time: '1.6' },
26
+ { file: './spec/fixtures/1_spec.rb:4', time: '1.4' },
27
+ { file: './spec/fixtures/new_spec.rb:1', time: 0 },
28
+ ]
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '.first_pipe?' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ context 'when pipe env is 1' do
7
+ before { allow(RSpeed::Env).to receive(:pipe).and_return 1 }
8
+
9
+ it { expect(splitter.first_pipe?).to eq true }
10
+ end
11
+
12
+ context 'when pipe env is not 1' do
13
+ before { allow(RSpeed::Env).to receive(:pipe).and_return 2 }
14
+
15
+ it { expect(splitter.first_pipe?).to eq false }
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#get' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ let!(:redis) { redis_object }
7
+
8
+ context 'when wildcard pattern is given' do
9
+ before do
10
+ redis.set 'rspeed_1', { files: [[1, '1_spec.rb'], [2, '2_spec.rb']], number: 0, total: 3 }.to_json
11
+ redis.set 'rspeed_2', { files: [[3, '3_spec.rb']], number: 1, total: 3 }.to_json
12
+ end
13
+
14
+ it 'returns all values' do
15
+ expect(splitter.get('rspeed_*')).to eq [
16
+ {
17
+ 'files' => [[1, '1_spec.rb'], [2, '2_spec.rb']],
18
+ 'number' => 0,
19
+ 'total' => 3,
20
+ },
21
+
22
+ {
23
+ 'files' => [[3, '3_spec.rb']],
24
+ 'number' => 1,
25
+ 'total' => 3,
26
+ },
27
+ ]
28
+ end
29
+ end
30
+
31
+ context 'when normal pattern is given' do
32
+ before do
33
+ redis.set 'pattern', { files: [[1, '1_spec.rb'], [2, '2_spec.rb']], number: 0, total: 3 }.to_json
34
+ end
35
+
36
+ it 'returns all values from that key' do
37
+ expect(splitter.get('pattern')).to eq [
38
+ {
39
+ 'files' => [[1, '1_spec.rb'], [2, '2_spec.rb']],
40
+ 'number' => 0,
41
+ 'total' => 3,
42
+ },
43
+ ]
44
+ end
45
+ end
46
+
47
+ context 'when pattern is rspeed' do
48
+ before do
49
+ redis.lpush 'rspeed', { file: '1_spec.rb', time: 1 }.to_json
50
+ redis.lpush 'rspeed', { file: '2_spec.rb', time: 2 }.to_json
51
+ end
52
+
53
+ it 'executes the right fetch method' do
54
+ expect(splitter.get('rspeed')).to eq [
55
+ '{"file":"2_spec.rb","time":2}',
56
+ '{"file":"1_spec.rb","time":1}',
57
+ ]
58
+ end
59
+ end
60
+
61
+ context 'when pattern is rspeed_tmp' do
62
+ before do
63
+ redis.lpush 'rspeed_tmp', { file: '1_spec.rb', time: 1 }.to_json
64
+ redis.lpush 'rspeed_tmp', { file: '2_spec.rb', time: 2 }.to_json
65
+ end
66
+
67
+ it 'executes the right fetch method' do
68
+ expect(splitter.get('rspeed_tmp')).to eq [
69
+ '{"file":"2_spec.rb","time":2}',
70
+ '{"file":"1_spec.rb","time":1}',
71
+ ]
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#pipe_files' do
4
+ let!(:shell) { double('shell') }
5
+ let!(:splitter) { described_class.new }
6
+
7
+ before { allow(RSpeed::Env).to receive(:pipe).and_return(1) }
8
+
9
+ context 'when has no result' do
10
+ before { allow(RSpeed::Redis).to receive(:result?).and_return(false) }
11
+
12
+ it { expect(splitter.pipe_files).to be(nil) }
13
+ end
14
+
15
+ context 'when has result' do
16
+ before do
17
+ allow(RSpeed::Redis).to receive(:result?).and_return(true)
18
+
19
+ allow(splitter).to receive(:split).and_return(rspeed_1: { files: [{ file: 'spec_1.rb' }, { file: 'spec_2.rb' }] })
20
+ end
21
+
22
+ it 'returns the splitted pipe files' do
23
+ expect(splitter.pipe_files).to eq 'spec_1.rb spec_2.rb'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '.redundant_run?' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ context 'when is not pipe 1' do
7
+ before { allow(RSpeed::Env).to receive(:pipe).and_return(2) }
8
+
9
+ context 'when result key exists' do
10
+ let!(:redis) { redis_object }
11
+
12
+ before do
13
+ redis.set('rspeed', '{}')
14
+
15
+ allow(RSpeed::Env).to receive(:pipe).and_return(2)
16
+ end
17
+
18
+ it { expect(splitter.redundant_run?).to be(false) }
19
+ end
20
+
21
+ context 'when result key does not exist' do
22
+ it { expect(splitter.redundant_run?).to be(true) }
23
+ end
24
+ end
25
+
26
+ context 'when is the first pipe' do
27
+ before { allow(RSpeed::Env).to receive(:pipe).and_return(1) }
28
+
29
+ context 'when result key exists' do
30
+ let!(:redis) { redis_object }
31
+
32
+ before do
33
+ redis.set('rspeed', '{}')
34
+
35
+ allow(RSpeed::Env).to receive(:pipe).and_return(2)
36
+ end
37
+
38
+ it { expect(splitter.redundant_run?).to be(false) }
39
+ end
40
+
41
+ context 'when result key does not exist' do
42
+ it { expect(splitter.redundant_run?).to be(false) }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '#rename' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ let!(:redis) { redis_object }
7
+
8
+ before { redis.lpush('rspeed_tmp', { file: '1_spec.rb', time: 1.0 }.to_json) }
9
+
10
+ it 'renames the key' do
11
+ splitter.rename
12
+
13
+ expect(redis.lrange('rspeed_tmp', 0, -1)).to eq([])
14
+ expect(redis.lrange('rspeed', 0, -1)).to eq(['{"file":"1_spec.rb","time":1.0}'])
15
+ end
16
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpeed::Splitter, '.split' do
4
+ subject(:splitter) { described_class.new }
5
+
6
+ let!(:unsorted_data) do
7
+ [
8
+ { file: './spec/1_5_spec.rb', time: '1.5' },
9
+ { file: './spec/1_1_spec.rb', time: '1.1' },
10
+ { file: './spec/0_7_spec.rb', time: '0.7' },
11
+ { file: './spec/0_4_spec.rb', time: '0.4' },
12
+ { file: './spec/0_3_spec.rb', time: '0.3' },
13
+ { file: './spec/0_2_spec.rb', time: '0.2' },
14
+ { file: './spec/2_0_spec.rb', time: '2.0' },
15
+ ]
16
+ end
17
+
18
+ before { allow(RSpeed::Env).to receive(:pipes).and_return 3 }
19
+
20
+ context 'when diff is given' do
21
+ it 'splits the times between the pipes' do
22
+ expect(splitter.split(unsorted_data)).to eq(
23
+ rspeed_1: {
24
+ files: [{ file: './spec/2_0_spec.rb', time: 2.0 }],
25
+ number: 1,
26
+ total: 2.0,
27
+ },
28
+
29
+ rspeed_2: {
30
+ files: [
31
+ { file: './spec/1_5_spec.rb', time: 1.5 },
32
+ { file: './spec/0_4_spec.rb', time: 0.4 },
33
+ { file: './spec/0_2_spec.rb', time: 0.2 },
34
+ ],
35
+
36
+ number: 2,
37
+ total: 1.5 + 0.4 + 0.2, # 1.5 -> 1.9 -> 2.1
38
+ },
39
+
40
+ rspeed_3: {
41
+ files: [
42
+ { file: './spec/1_1_spec.rb', time: 1.1 },
43
+ { file: './spec/0_7_spec.rb', time: 0.7 },
44
+ { file: './spec/0_3_spec.rb', time: 0.3 },
45
+ ],
46
+
47
+ number: 3,
48
+ total: 1.1 + 0.7 + 0.3, # 1.1 -> 1.8 -> 2.1
49
+ }
50
+ )
51
+ end
52
+ end
53
+
54
+ context 'when diff is not given' do
55
+ before { allow(splitter).to receive(:diff).and_return(unsorted_data) }
56
+
57
+ it 'splits the diff result into times between the pipes' do
58
+ expect(splitter.split).to eq(
59
+ rspeed_1: {
60
+ files: [{ file: './spec/2_0_spec.rb', time: 2.0 }],
61
+ number: 1,
62
+ total: 2.0,
63
+ },
64
+
65
+ rspeed_2: {
66
+ files: [
67
+ { file: './spec/1_5_spec.rb', time: 1.5 },
68
+ { file: './spec/0_4_spec.rb', time: 0.4 },
69
+ { file: './spec/0_2_spec.rb', time: 0.2 },
70
+ ],
71
+
72
+ number: 2,
73
+ total: 1.5 + 0.4 + 0.2, # 1.5 -> 1.9 -> 2.1
74
+ },
75
+
76
+ rspeed_3: {
77
+ files: [
78
+ { file: './spec/1_1_spec.rb', time: 1.1 },
79
+ { file: './spec/0_7_spec.rb', time: 0.7 },
80
+ { file: './spec/0_3_spec.rb', time: 0.3 },
81
+ ],
82
+
83
+ number: 3,
84
+ total: 1.1 + 0.7 + 0.3, # 1.1 -> 1.8 -> 2.1
85
+ }
86
+ )
87
+ end
88
+ end
89
+ end