miss_cleo 0.3.7 → 0.4.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.
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: