miss_cleo 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73711bb2ed13dcc0c37f04ae6aa67f6b2af3e793
4
- data.tar.gz: 97ccdbbfd31a95325dc70fa45fb12c268a9ba3e1
3
+ metadata.gz: d918fe13d7cee5691d8fe6cc48589ebd9dd0fcbe
4
+ data.tar.gz: be479f4e751445144aec9b5d6f106795863cbff5
5
5
  SHA512:
6
- metadata.gz: c81e1f9ba4dbbf4d3b3e68d2b6000158c2ff6851182b1b21dab42058746124abac9b09e10c35a32634425d9c07334f88e9084f35aa0a15e0c55a010092251f53
7
- data.tar.gz: 996648338d022450dd25e11bd4266d0d51cd139beecd295b6a90ae4d98db9d308691cea5abad4d357c3d193ad813b7e3c53fb10d88a43ebee1a5bc6172e947ff
6
+ metadata.gz: 39a4f91fafa9685d0f8f2f8ec970b46d64310ba21e49a506a136de9464a616526ba0ab33d5ecd32eaa51be8dd4fd71c6bdc2daffb024bdb8978d575f73beab5f
7
+ data.tar.gz: 5c8f121ab1431fb0d823988443708c0423f4a9ec71117fb7505e47a2635663f25ce0e42847f2549d1f968b7d54f3222235f05877cf79c747c8981dfebc862ddb
data/bin/miss_cleo CHANGED
@@ -12,7 +12,7 @@ when "predict"
12
12
  puts "e.g. 'miss_cleo predict map.json.gz"
13
13
  else
14
14
  map = File.open(ARGV[1]).read.gunzip
15
- predict
15
+ predict(map)
16
16
  end
17
17
  else
18
18
  puts "Please run miss_cleo with 'build_deck' or 'predict'."
@@ -0,0 +1,90 @@
1
+ module MissCleo
2
+ class CoverageMap
3
+
4
+ attr_reader :map
5
+
6
+ def initialize(map = nil)
7
+ @map = map || Hash.new { |h, file| h[file] = Hash.new { |i, line| i[line] = [] } }
8
+ end
9
+
10
+ def add_to_coverage_map(test_diffs)
11
+ test_diffs.each do |test_to_code_map|
12
+ test_file_and_line = test_to_code_map.first
13
+ before = test_to_code_map.last["before"]
14
+ after = test_to_code_map.last["after"]
15
+ templates = test_to_code_map.last["templates"]
16
+
17
+ # calculate the per test coverage
18
+ delta = diff before, after
19
+ add_delta_to_map(delta, test_file_and_line)
20
+ add_templates_to_map(templates, test_file_and_line)
21
+ end
22
+
23
+ nil
24
+ end
25
+
26
+ def tests_for_lines(file, line)
27
+ begin
28
+ # NOTE: This is currently how templates and non-templates are being
29
+ # split. Since I will likely have to cover a bunch of blind spots
30
+ # manually like this, this probably needs to be rearchitected.
31
+ if file.include?("app/views")
32
+ map[file]["0"].uniq || []
33
+ else
34
+ map[file][line].uniq || []
35
+ end
36
+ rescue
37
+ []
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def diff before, after
44
+ after.each_with_object({}) do |(file_name,line_cov), res|
45
+ before_line_cov = before[file_name] || []
46
+
47
+ # skip arrays that are exactly the same
48
+ next if before_line_cov == line_cov
49
+
50
+ # subtract the old coverage from the new coverage
51
+ cov = line_cov.zip(before_line_cov).map do |line_after, line_before|
52
+ if line_before
53
+ line_after - line_before
54
+ else
55
+ line_after
56
+ end
57
+ end
58
+
59
+ # add the "diffed" coverage to the hash
60
+ res[file_name] = cov
61
+ end
62
+ end
63
+
64
+ def add_delta_to_map(delta, test_file_and_line)
65
+ delta.each_pair do |file, lines|
66
+ file_map = map[file]
67
+
68
+ lines.each_with_index do |val, i|
69
+ # skip lines that weren't executed
70
+ next unless val && val > 0
71
+
72
+ # add the test name to the map. Multiple tests can execute the same
73
+ # line, so we need to use an array.
74
+ file_map[i + 1] << test_file_and_line
75
+ end
76
+ end
77
+ end
78
+
79
+ def add_templates_to_map(templates, test_file_and_line)
80
+ templates.each do |template|
81
+ # NOTE: Currently templates do not know how many lines of code they
82
+ # are. I have temporarily decided to shove them into the 0 line
83
+ # to make them a special case. This will probably require
84
+ # re-architecting
85
+ map[template][0] << test_file_and_line
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -1,61 +1,38 @@
1
1
  module MissCleo
2
2
  module CoverageMapHelper
3
3
 
4
- def build_deck(filenames)
5
- cov_map = Hash.new { |h, file| h[file] = Hash.new { |i, line| i[line] = [] } }
6
- filenames.each do |filename|
7
- File.open(filename, "r") do |f|
4
+ def build_deck(file_names)
5
+ cov_map = ::MissCleo::CoverageMap.new
6
+ file_names.each do |file_name|
7
+ File.open(file_name, "r") do |f|
8
8
  f.read
9
9
  end.tap do |contents|
10
10
  begin
11
- build_coverage_map(cov_map, JSON.parse(contents))
11
+ cov_map.add_to_coverage_map(JSON.parse(contents))
12
12
  rescue
13
- puts "#{filename} is malformed, this may affect test predictons"
13
+ puts "#{file_name} is malformed, this may affect test predictons"
14
14
  end
15
15
  end
16
16
  end
17
17
 
18
18
  File.open("total_coverage_map.json.gz", "w") do |f|
19
- f.write(JSON.dump(cov_map).gzip)
19
+ f.write(JSON.dump(cov_map.map).gzip)
20
20
  end
21
21
  end
22
22
 
23
23
  def predict(unzipped_file)
24
- repo = Rugged::Repository.new '.'
25
- lines_changed = Set.new
26
-
27
- repo.index.diff.each_patch do |patch|
28
- file = patch.delta.old_file[:path]
29
-
30
- patch.each_hunk do |hunk|
31
- hunk.each_line do |line|
32
- case line.line_origin
33
- when :addition
34
- lines_changed << [file, line.new_lineno] unless exclude_from_map?(file)
35
- when :deletion
36
- lines_changed << [file, line.old_lineno] unless exclude_from_map?(file)
37
- when :context
38
- # do nothing
39
- end
40
- end
41
- end
42
- end
43
-
44
- coverage_map = JSON.parse(unzipped_file)
24
+ coverage_map = ::MissCleo::CoverageMap.new(JSON.parse(unzipped_file))
45
25
  tests_to_run = []
46
26
  lines_changed.each do |file, line|
47
- coverage_map && coverage_map[file] && coverage_map[file].fetch(line.to_s, []).uniq.each do |desc|
48
- tests_to_run << desc
49
- end
27
+ tests_to_run |= coverage_map.tests_for_lines(file, line)
50
28
  end
51
- tests_to_run = tests_to_run.uniq.sort.reverse
52
29
  if lines_changed.empty?
53
30
  puts "No line changes detected."
54
31
  elsif tests_to_run.empty?
55
32
  puts "No tests found. May be due to blind spot, new tests you've just written, or the changes may be untested."
56
33
  else
57
34
  puts "Run these tests:"
58
- puts tests_to_run.uniq.sort
35
+ puts tests_to_run.sort.reverse
59
36
  end
60
37
 
61
38
  tests_to_run
@@ -69,51 +46,27 @@ module MissCleo
69
46
  file_name == "db/structure.sql"
70
47
  end
71
48
 
72
- def build_coverage_map(cov_map, cov_diffs)
73
- cov_diffs.each do |test_to_code_map|
74
- if test_to_code_map.length == 4 # for Minitest
75
- test_file_and_line = test_to_code_map.first(2).join('#')
76
- else # for RSpec
77
- test_file_and_line = test_to_code_map.first
78
- end
79
- before, after = test_to_code_map.last(2)
80
-
81
- # calculate the per test coverage
82
- delta = diff before, after
83
-
84
- delta.each_pair do |file, lines|
85
- file_map = cov_map[file]
86
-
87
- lines.each_with_index do |val, i|
88
- # skip lines that weren't executed
89
- next unless val && val > 0
90
-
91
- # add the test name to the map. Multiple tests can execute the same
92
- # line, so we need to use an array.
93
- file_map[i + 1] << test_file_and_line
94
- end
95
- end
96
- end
97
- end
98
-
99
- def diff before, after
100
- after.each_with_object({}) do |(file_name,line_cov), res|
101
- before_line_cov = before[file_name] || []
102
49
 
103
- # skip arrays that are exactly the same
104
- next if before_line_cov == line_cov
105
-
106
- # subtract the old coverage from the new coverage
107
- cov = line_cov.zip(before_line_cov).map do |line_after, line_before|
108
- if line_before
109
- line_after - line_before
110
- else
111
- line_after
50
+ def lines_changed
51
+ @_lines_changed ||= Set.new.tap do |changed_lines|
52
+ repo = Rugged::Repository.new '.'
53
+ repo.index.diff.each_patch do |patch|
54
+ file = patch.delta.old_file[:path]
55
+
56
+ patch.each_hunk do |hunk|
57
+ hunk.each_line do |line|
58
+ case line.line_origin
59
+ when :addition
60
+ changed_lines << [file, line.new_lineno] unless exclude_from_map?(file)
61
+ when :deletion
62
+ changed_lines << [file, line.old_lineno] unless exclude_from_map?(file)
63
+ when :context
64
+ # do nothing
65
+ end
66
+ end
112
67
  end
113
68
  end
114
69
 
115
- # add the "diffed" coverage to the hash
116
- res[file_name] = cov
117
70
  end
118
71
  end
119
72
  end
@@ -0,0 +1,22 @@
1
+ module MissCleo
2
+ module TemplateHelper
3
+ module_function
4
+
5
+ def template_coverage
6
+ @template_coverage ||= []
7
+ end
8
+
9
+ def add_to_template_coverage(template)
10
+ template_coverage << trim_path(template)
11
+ end
12
+
13
+ def reset_coverage
14
+ template_coverage = []
15
+ end
16
+
17
+ def trim_path(path)
18
+ path.gsub(/#{Regexp.quote(`pwd`.chomp)}\//, "")
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module MissCleo
2
+ module TestConfigurations
3
+ module ActionViewHook
4
+ module_function
5
+
6
+ def record_template(template)
7
+ MissCleo::TemplateHelper.add_to_template_coverage(template)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -8,11 +8,13 @@ module MissCleo
8
8
  if ENV["COVERAGE"]
9
9
  Coverage.start
10
10
  context.Around do |scenario, execute|
11
+ MissCleo::TemplateHelper.reset_coverage
11
12
  before = Coverage.peek_result
12
13
  execute.call
13
14
  after = Coverage.peek_result
15
+ templates = MissCleo::TemplateHelper.template_coverage
14
16
  if file_and_line = scenario.try(:file_colon_line)
15
- LOGS << [ file_and_line, CoverageFilter.filter_and_trim(before), CoverageFilter.filter_and_trim(after) ]
17
+ LOGS << [ file_and_line, { before: CoverageFilter.filter_and_trim(before), after: CoverageFilter.filter_and_trim(after), templates: templates } ]
16
18
  end
17
19
  end
18
20
 
@@ -0,0 +1,10 @@
1
+ module MissCleo
2
+ module TestConfigurations
3
+ module ActionViewConfig
4
+ def render(*args)
5
+ MissCleo::TestConfigurations::ActionViewHook.record_template(identifier)
6
+ super(*args)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -12,11 +12,16 @@ module MissCleo
12
12
  end
13
13
 
14
14
  RSpec.configuration.around(:example) do |example|
15
+ MissCleo::TemplateHelper.reset_coverage
15
16
  before = Coverage.peek_result
16
17
  example.call
17
18
  after = Coverage.peek_result
18
- LOGS << [ example.location, CoverageFilter.filter_and_trim(before),
19
- CoverageFilter.filter_and_trim(after) ]
19
+ templates = MissCleo::TemplateHelper.template_coverage
20
+ LOGS << [ example.location, {
21
+ before: CoverageFilter.filter_and_trim(before),
22
+ after: CoverageFilter.filter_and_trim(after),
23
+ templates: templates
24
+ } ]
20
25
  end
21
26
  end
22
27
  end
@@ -1,3 +1,3 @@
1
1
  module MissCleo
2
- VERSION = "0.3.7"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/miss_cleo.rb CHANGED
@@ -8,9 +8,13 @@ require 'gzip'
8
8
 
9
9
  require "miss_cleo/version"
10
10
  require 'miss_cleo/coverage_filter'
11
+ require 'miss_cleo/coverage_map'
11
12
  require 'miss_cleo/test_configurations/cucumber_config'
12
13
  require 'miss_cleo/test_configurations/rspec_config'
13
14
  require 'miss_cleo/coverage_map_helper.rb'
15
+ require 'miss_cleo/test_configurations/action_view_hook'
16
+ require 'miss_cleo/test_configurations/rails_action_view_config'
17
+ require 'miss_cleo/template_helper'
14
18
 
15
19
  module MissCleo
16
20
  end
data/miss_cleo.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Dean Hu", "Lee Ourand", "John Bernier"]
10
10
  spec.email = ["devs@gust.com"]
11
11
 
12
- spec.summary = %q{Predict your test failures}
12
+ spec.summary = %q{Regression Test Selection}
13
13
  spec.description = %q{Miss Cleo frees you from having to run your full test suite to be confident in your recent code changes. Call me now!}
14
14
  spec.homepage = "http://github.com/gust/miss_cleo"
15
15
  spec.license = "MIT"
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = ["miss_cleo"]
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.8"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_runtime_dependency "rugged"
24
- spec.add_runtime_dependency "gzip"
21
+ spec.add_development_dependency "bundler", "~> 1.7.6"
22
+ spec.add_development_dependency "rake", "~> 10.5.0"
23
+ spec.add_development_dependency "pry", "~> 0.9.12"
24
+ spec.add_runtime_dependency "rugged", "~> 0.23.3"
25
+ spec.add_runtime_dependency "gzip", "~> 1.0"
25
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miss_cleo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Hu
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-12-25 00:00:00.000000000 Z
13
+ date: 2016-02-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -18,56 +18,70 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '1.8'
21
+ version: 1.7.6
22
22
  type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '1.8'
28
+ version: 1.7.6
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rake
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - "~>"
34
34
  - !ruby/object:Gem::Version
35
- version: '10.0'
35
+ version: 10.5.0
36
36
  type: :development
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: '10.0'
42
+ version: 10.5.0
43
+ - !ruby/object:Gem::Dependency
44
+ name: pry
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 0.9.12
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.9.12
43
57
  - !ruby/object:Gem::Dependency
44
58
  name: rugged
45
59
  requirement: !ruby/object:Gem::Requirement
46
60
  requirements:
47
- - - ">="
61
+ - - "~>"
48
62
  - !ruby/object:Gem::Version
49
- version: '0'
63
+ version: 0.23.3
50
64
  type: :runtime
51
65
  prerelease: false
52
66
  version_requirements: !ruby/object:Gem::Requirement
53
67
  requirements:
54
- - - ">="
68
+ - - "~>"
55
69
  - !ruby/object:Gem::Version
56
- version: '0'
70
+ version: 0.23.3
57
71
  - !ruby/object:Gem::Dependency
58
72
  name: gzip
59
73
  requirement: !ruby/object:Gem::Requirement
60
74
  requirements:
61
- - - ">="
75
+ - - "~>"
62
76
  - !ruby/object:Gem::Version
63
- version: '0'
77
+ version: '1.0'
64
78
  type: :runtime
65
79
  prerelease: false
66
80
  version_requirements: !ruby/object:Gem::Requirement
67
81
  requirements:
68
- - - ">="
82
+ - - "~>"
69
83
  - !ruby/object:Gem::Version
70
- version: '0'
84
+ version: '1.0'
71
85
  description: Miss Cleo frees you from having to run your full test suite to be confident
72
86
  in your recent code changes. Call me now!
73
87
  email:
@@ -90,8 +104,12 @@ files:
90
104
  - bin/setup
91
105
  - lib/miss_cleo.rb
92
106
  - lib/miss_cleo/coverage_filter.rb
107
+ - lib/miss_cleo/coverage_map.rb
93
108
  - lib/miss_cleo/coverage_map_helper.rb
109
+ - lib/miss_cleo/template_helper.rb
110
+ - lib/miss_cleo/test_configurations/action_view_hook.rb
94
111
  - lib/miss_cleo/test_configurations/cucumber_config.rb
112
+ - lib/miss_cleo/test_configurations/rails_action_view_config.rb
95
113
  - lib/miss_cleo/test_configurations/rspec_config.rb
96
114
  - lib/miss_cleo/version.rb
97
115
  - miss_cleo.gemspec
@@ -115,9 +133,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
133
  version: '0'
116
134
  requirements: []
117
135
  rubyforge_project:
118
- rubygems_version: 2.4.3
136
+ rubygems_version: 2.5.1
119
137
  signing_key:
120
138
  specification_version: 4
121
- summary: Predict your test failures
139
+ summary: Regression Test Selection
122
140
  test_files: []
123
141
  has_rdoc: