mattwynne-cucover 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Licence.txt +22 -0
- data/README.markdown +23 -7
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/bin/cucover +1 -1
- data/cucover.gemspec +305 -0
- data/examples/self_test/rails/.gitignore +2 -0
- data/examples/self_test/rails/README +256 -0
- data/examples/self_test/rails/Rakefile +10 -0
- data/examples/self_test/rails/app/controllers/application.rb +2 -0
- data/examples/self_test/rails/app/controllers/widgets_controller.rb +2 -0
- data/examples/self_test/rails/app/views/widgets/index.html.erb +1 -0
- data/examples/self_test/rails/config/boot.rb +109 -0
- data/examples/self_test/rails/config/database.yml +19 -0
- data/examples/self_test/rails/config/environment.rb +68 -0
- data/examples/self_test/rails/config/environments/development.rb +17 -0
- data/examples/self_test/rails/config/environments/production.rb +22 -0
- data/examples/self_test/rails/config/environments/test.rb +22 -0
- data/examples/self_test/rails/config/routes.rb +43 -0
- data/examples/self_test/rails/db/test.sqlite3 +0 -0
- data/examples/self_test/rails/features/see_widgets.feature +7 -0
- data/examples/self_test/rails/features/step_definitions/env.rb +0 -0
- data/examples/self_test/rails/features/step_definitions/webrat_steps.rb +7 -0
- data/examples/self_test/rails/features/support/env.rb +17 -0
- data/examples/self_test/rails/lib/tasks/cucumber.rake +15 -0
- data/examples/self_test/rails/public/404.html +30 -0
- data/examples/self_test/rails/public/422.html +30 -0
- data/examples/self_test/rails/public/500.html +30 -0
- data/examples/self_test/rails/public/dispatch.cgi +10 -0
- data/examples/self_test/rails/public/dispatch.fcgi +24 -0
- data/examples/self_test/rails/public/dispatch.rb +10 -0
- data/examples/self_test/rails/public/favicon.ico +0 -0
- data/examples/self_test/rails/public/images/rails.png +0 -0
- data/examples/self_test/rails/public/index.html +274 -0
- data/examples/self_test/rails/public/javascripts/application.js +2 -0
- data/examples/self_test/rails/public/javascripts/controls.js +963 -0
- data/examples/self_test/rails/public/javascripts/dragdrop.js +972 -0
- data/examples/self_test/rails/public/javascripts/effects.js +1120 -0
- data/examples/self_test/rails/public/javascripts/prototype.js +4225 -0
- data/examples/self_test/rails/public/robots.txt +5 -0
- data/examples/self_test/rails/script/about +4 -0
- data/examples/self_test/rails/script/console +3 -0
- data/examples/self_test/rails/script/cucumber +8 -0
- data/examples/self_test/rails/script/dbconsole +3 -0
- data/examples/self_test/rails/script/destroy +3 -0
- data/examples/self_test/rails/script/generate +3 -0
- data/examples/self_test/rails/script/performance/benchmarker +3 -0
- data/examples/self_test/rails/script/performance/profiler +3 -0
- data/examples/self_test/rails/script/performance/request +3 -0
- data/examples/self_test/rails/script/plugin +3 -0
- data/examples/self_test/rails/script/process/inspector +3 -0
- data/examples/self_test/rails/script/process/reaper +3 -0
- data/examples/self_test/rails/script/process/spawner +3 -0
- data/examples/self_test/rails/script/runner +3 -0
- data/examples/self_test/rails/script/server +3 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/.specification +148 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/History.txt +324 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/MIT-LICENSE.txt +19 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/README.rdoc +85 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/Rakefile +151 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/install.rb +1 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/configuration.rb +98 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/area.rb +31 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/element.rb +33 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/field.rb +403 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/form.rb +103 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/label.rb +31 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/link.rb +92 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/elements/select_option.rb +35 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/area_locator.rb +38 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/button_locator.rb +54 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/field_by_id_locator.rb +37 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/field_labeled_locator.rb +56 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/field_locator.rb +25 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/field_named_locator.rb +41 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/form_locator.rb +19 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/label_locator.rb +34 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/link_locator.rb +66 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/locator.rb +20 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators/select_option_locator.rb +59 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/locators.rb +20 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/logging.rb +21 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/matchers/have_content.rb +73 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/matchers/have_selector.rb +74 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/matchers/have_tag.rb +21 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/matchers/have_xpath.rb +147 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/matchers.rb +4 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/methods.rb +61 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/mime.rb +29 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/save_and_open_page.rb +50 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/scope.rb +350 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/session.rb +281 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/xml/hpricot.rb +19 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/xml/nokogiri.rb +76 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/xml/rexml.rb +24 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core/xml.rb +115 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core.rb +14 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/blank.rb +58 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/deprecate.rb +8 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/detect_mapped.rb +12 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/meta_class.rb +6 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/nil_to_param.rb +5 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/core_extensions/tcp_socket.rb +27 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/mechanize.rb +74 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/merb.rb +9 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/merb_session.rb +65 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/rack.rb +24 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/rails.rb +105 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/rspec-rails.rb +13 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/application_server.rb +71 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/button.js +12 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/label.js +16 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/webrat.js +5 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/webratlink.js +9 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/webratlinkwithin.js +15 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/location_strategy_javascript/webratselectwithoption.js +5 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/matchers/have_content.rb +66 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/matchers/have_selector.rb +49 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/matchers/have_tag.rb +72 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/matchers/have_xpath.rb +45 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/matchers.rb +4 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/merb_application_server.rb +48 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/rails_application_server.rb +42 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/selenium_extensions.js +6 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/selenium_rc_server.rb +80 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/selenium_session.rb +241 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium/sinatra_application_server.rb +35 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/selenium.rb +80 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat/sinatra.rb +44 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/lib/webrat.rb +34 -0
- data/examples/self_test/rails/vendor/gems/webrat-0.4.4/vendor/selenium-server.jar +0 -0
- data/examples/self_test/simple/features/call_foo.feature +4 -0
- data/examples/self_test/simple/features/call_foo_and_bar_together.feature +5 -0
- data/examples/self_test/simple/features/call_foo_from_background_then_bar.feature +7 -0
- data/examples/self_test/simple/features/call_foo_from_background_then_bar_then_baz.feature +10 -0
- data/examples/self_test/simple/features/call_foo_then_bar.feature +7 -0
- data/examples/self_test/simple/features/call_foo_then_bar_from_scenario_outline_examples.feature +9 -0
- data/examples/self_test/simple/features/fail.feature +10 -0
- data/examples/self_test/simple/features/step_definitions/main_steps.rb +15 -0
- data/examples/self_test/simple/lib/bar.rb +5 -0
- data/examples/self_test/simple/lib/baz.rb +5 -0
- data/examples/self_test/simple/lib/foo.rb +9 -0
- data/features/call_foo.feature +0 -0
- data/features/coverage_of.feature +44 -0
- data/features/fail.feature +54 -0
- data/features/lazy_run.feature +79 -0
- data/features/lazy_run_per_scenario.feature +113 -0
- data/features/lazy_run_per_scenario_outline_example.feature +31 -0
- data/features/lazy_run_triggered_by_rails_view_change.feature +42 -0
- data/features/run.feature +25 -0
- data/features/show_recordings.feature +28 -0
- data/features/step_definitions/main_steps.rb +36 -0
- data/features/support/env.rb +48 -0
- data/lib/cucover/cli.rb +26 -0
- data/lib/cucover/cli_commands/coverage_of.rb +36 -0
- data/lib/cucover/cli_commands/cucumber.rb +25 -0
- data/lib/cucover/cli_commands/show_recordings.rb +29 -0
- data/lib/cucover/controller.rb +28 -0
- data/lib/cucover/cucumber_hooks.rb +29 -0
- data/lib/cucover/logging_config.rb +16 -0
- data/lib/cucover/monkey.rb +14 -0
- data/lib/cucover/rails.rb +20 -0
- data/lib/cucover/recorder.rb +37 -0
- data/lib/cucover/recording/covered_file.rb +53 -0
- data/lib/cucover/recording.rb +64 -0
- data/lib/cucover/store.rb +70 -0
- data/lib/cucover.rb +35 -212
- data/lib/dependencies.rb +10 -0
- data/spec/cucover/cli_spec.rb +31 -0
- data/spec/cucover/controller_spec.rb +16 -0
- data/spec/cucover/recording/covered_file_spec.rb +20 -0
- data/spec/cucover/store_spec.rb +28 -0
- data/spec/spec_helper.rb +7 -0
- data/tmp/.gitignore +0 -0
- metadata +304 -21
@@ -0,0 +1,53 @@
|
|
1
|
+
module Cucover
|
2
|
+
class Recording::CoveredFile
|
3
|
+
attr_reader :file
|
4
|
+
|
5
|
+
def initialize(full_filename, rcov_marked_info, recording)
|
6
|
+
@full_filename = full_filename
|
7
|
+
@rcov_marked_info = rcov_marked_info
|
8
|
+
@recording = recording
|
9
|
+
@file = File.expand_path(full_filename).gsub(/^#{Dir.pwd}\//, '')
|
10
|
+
|
11
|
+
extend HasLineNumberDetail if @rcov_marked_info
|
12
|
+
end
|
13
|
+
|
14
|
+
def dirty?
|
15
|
+
Cucover.logger.debug("#{file} last modified at #{File.mtime(@full_filename)}")
|
16
|
+
Cucover.logger.debug("#{file} recording started at #{@recording.start_time}")
|
17
|
+
result = File.mtime(@full_filename).to_i >= @recording.start_time.to_i
|
18
|
+
Cucover.logger.debug("verdict: #{(result ? "dirty" : "not dirty")}")
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def covers_line?(line_number)
|
23
|
+
covered_lines.include?(line_number)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(other)
|
27
|
+
other == file
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{file}:#{covered_lines.join(':')}"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def covered_lines
|
37
|
+
['<unknown lines>']
|
38
|
+
end
|
39
|
+
|
40
|
+
module HasLineNumberDetail
|
41
|
+
def covered_lines
|
42
|
+
return @covered_lines if @covered_lines
|
43
|
+
|
44
|
+
@covered_lines = []
|
45
|
+
@rcov_marked_info.each_with_index do |covered, index|
|
46
|
+
line_number = index + 1
|
47
|
+
@covered_lines << line_number if covered
|
48
|
+
end
|
49
|
+
@covered_lines
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Cucover
|
2
|
+
class Recording < Struct.new(
|
3
|
+
:file_colon_line,
|
4
|
+
:exception,
|
5
|
+
:additional_covered_files,
|
6
|
+
:analyzer,
|
7
|
+
:start_time, :end_time)
|
8
|
+
|
9
|
+
def feature_filename
|
10
|
+
file_colon_line.split(':').first
|
11
|
+
end
|
12
|
+
|
13
|
+
def covers_file?(source_file)
|
14
|
+
covered_files.include?(source_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def covers_line?(source_file, line_number)
|
18
|
+
covered_files.detect{ |f| f.file == source_file }.covers_line?(line_number)
|
19
|
+
end
|
20
|
+
|
21
|
+
def covered_files
|
22
|
+
@covered_files ||= analyzed_covered_files + additional_covered_files
|
23
|
+
end
|
24
|
+
|
25
|
+
def failed?
|
26
|
+
!!exception
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def additional_covered_files
|
32
|
+
super.map do |filename|
|
33
|
+
CoveredFile.new(filename, nil, self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def analyzed_covered_files
|
38
|
+
filtered_analyzed_files.map do |filename|
|
39
|
+
lines, marked_info, count_info = analyzer.data(filename)
|
40
|
+
CoveredFile.new(filename, marked_info, self)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def boring?(file)
|
45
|
+
[
|
46
|
+
/gem/,
|
47
|
+
/vendor/,
|
48
|
+
/lib\/ruby/,
|
49
|
+
/cucover/
|
50
|
+
].any? do |expression|
|
51
|
+
file.match expression
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def filtered_analyzed_files
|
56
|
+
analyzer.analyzed_files.reject{ |f| boring?(f) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalized_files
|
60
|
+
cleaned_analyzed_files + additional_covered_files
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
require 'cucover/recording/covered_file'
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Cucover
|
2
|
+
class Store
|
3
|
+
def initialize(cache = DiskCache.new)
|
4
|
+
@cache = cache
|
5
|
+
end
|
6
|
+
|
7
|
+
def latest_recordings
|
8
|
+
recordings.keys.map{ |file_colon_line| latest_recording(file_colon_line) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def latest_recording(file_colon_line)
|
12
|
+
recordings[file_colon_line].sort{ |x, y| x.end_time <=> y.end_time }.last
|
13
|
+
end
|
14
|
+
|
15
|
+
def keep!(recording_data)
|
16
|
+
Cucover.logger.debug("Storing recording of #{recording_data.file_colon_line}")
|
17
|
+
recordings[recording_data.file_colon_line] << recording_data
|
18
|
+
@cache.save(@recordings)
|
19
|
+
end
|
20
|
+
|
21
|
+
def recordings_covering(source_file)
|
22
|
+
latest_recordings.select { |r| r.covers_file?(source_file) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def recordings
|
26
|
+
ensure_recordings_loaded!
|
27
|
+
@recordings
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def ensure_recordings_loaded!
|
33
|
+
return if @recordings
|
34
|
+
|
35
|
+
if @recordings = @cache.load
|
36
|
+
Cucover.logger.debug("Loaded #{@recordings.length} recording(s)")
|
37
|
+
else
|
38
|
+
Cucover.logger.debug("Starting with no existing coverage data.")
|
39
|
+
@recordings = Recordings.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Recordings < Hash
|
44
|
+
def [](key)
|
45
|
+
self[key] = [] if super.nil?
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class DiskCache
|
51
|
+
def save(recordings)
|
52
|
+
Cucover.logger.debug("Saving #{recordings.length} recording(s) to #{data_file}")
|
53
|
+
File.open(data_file, 'w') { |f| f.puts Marshal.dump(recordings) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def load
|
57
|
+
return unless File.exists?(data_file)
|
58
|
+
|
59
|
+
Cucover.logger.debug("Reading existing coverage data from #{data_file}")
|
60
|
+
File.open(data_file) { |f| Marshal.load(f) }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def data_file
|
66
|
+
Dir.pwd + '/cucover.data'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/cucover.rb
CHANGED
@@ -1,237 +1,60 @@
|
|
1
|
-
|
2
|
-
require 'rubygems'
|
3
|
-
|
4
|
-
gem 'cucumber', '>=0.3'
|
5
|
-
require 'cucumber'
|
6
|
-
|
7
|
-
gem 'spicycode-rcov', '>=0.8.1.5.0'
|
8
|
-
require 'rcov'
|
9
|
-
require 'spec'
|
10
|
-
|
11
1
|
$:.unshift(File.dirname(__FILE__))
|
2
|
+
require 'dependencies'
|
3
|
+
require 'cucover/logging_config'
|
4
|
+
require 'cucover/cli_commands/coverage_of'
|
5
|
+
require 'cucover/cli_commands/cucumber'
|
6
|
+
require 'cucover/cli_commands/show_recordings'
|
7
|
+
require 'cucover/controller'
|
8
|
+
require 'cucover/cli'
|
12
9
|
require 'cucover/monkey'
|
13
10
|
require 'cucover/rails'
|
11
|
+
require 'cucover/recording'
|
12
|
+
require 'cucover/recorder'
|
13
|
+
require 'cucover/store'
|
14
14
|
|
15
15
|
module Cucover
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@feature_file, @visitor = feature_file, visitor
|
20
|
-
end
|
21
|
-
|
22
|
-
def record(source_file)
|
23
|
-
additional_covered_files << source_file
|
24
|
-
end
|
25
|
-
|
26
|
-
def fail!
|
27
|
-
@failed = true
|
28
|
-
end
|
29
|
-
|
30
|
-
def watch
|
31
|
-
announce_skip unless may_execute?
|
32
|
-
|
33
|
-
analyzer.run_hooked do
|
34
|
-
yield
|
35
|
-
end
|
36
|
-
|
37
|
-
record(@feature_file)
|
38
|
-
source_files_cache.save analyzed_files
|
39
|
-
status_cache.record(status)
|
40
|
-
end
|
41
|
-
|
42
|
-
def may_execute?
|
43
|
-
dirty? || failed_on_last_run?
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def status
|
49
|
-
@failed ? :failed : :passed
|
50
|
-
end
|
51
|
-
|
52
|
-
def additional_covered_files
|
53
|
-
@additional_covered_files ||= []
|
54
|
-
end
|
55
|
-
|
56
|
-
def announce_skip
|
57
|
-
messages = []
|
58
|
-
messages << "Cucover - Skipping clean feature"
|
59
|
-
messages << "Last run status: #{status_cache.last_run_status}"
|
60
|
-
@visitor.announce messages.flatten.map{ |m| "[ #{m.rstrip} ]"}.join("\n")
|
61
|
-
end
|
62
|
-
|
63
|
-
def failed_on_last_run?
|
64
|
-
return false unless status_cache.exists?
|
65
|
-
status_cache.last_run_status == "failed"
|
66
|
-
end
|
67
|
-
|
68
|
-
def dirty?
|
69
|
-
return true unless source_files_cache.exists?
|
70
|
-
source_files_cache.any_dirty_files?
|
16
|
+
class << self
|
17
|
+
def logger
|
18
|
+
Logging::Logger['Cucover']
|
71
19
|
end
|
72
20
|
|
73
|
-
def
|
74
|
-
|
21
|
+
def should_execute?(scenario_or_table_row)
|
22
|
+
controller(scenario_or_table_row).should_execute?
|
75
23
|
end
|
76
24
|
|
77
|
-
def
|
78
|
-
|
79
|
-
end
|
25
|
+
def start_recording!(scenario_or_table_row)
|
26
|
+
raise("Already recording. Please call stop first.") if recording?
|
80
27
|
|
81
|
-
|
82
|
-
|
28
|
+
@current_recorder = Recorder.new(scenario_or_table_row)
|
29
|
+
@current_recorder.start!
|
30
|
+
record_file(scenario_or_table_row.file_colon_line.split(':').first) # TODO: clean this by extending the feature element
|
83
31
|
end
|
84
|
-
|
85
|
-
def analyzed_files
|
86
|
-
normalized_files.reject{ |f| boring?(f) }.sort
|
87
|
-
end
|
88
|
-
|
89
|
-
def normalized_files
|
90
|
-
(analyzer.analyzed_files + additional_covered_files.uniq).map{ |f| File.expand_path(f).gsub(/^#{Dir.pwd}\//, '') }
|
91
|
-
end
|
92
|
-
|
93
|
-
def boring?(file)
|
94
|
-
return false
|
95
|
-
(file.match /gem/) || (file.match /vendor/) || (file.match /lib\/ruby/)
|
96
|
-
end
|
97
|
-
|
98
|
-
def analyzer
|
99
|
-
@analyzer ||= Rcov::CodeCoverageAnalyzer.new
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
class << self
|
105
|
-
def start_test(test, visitor)
|
106
|
-
@current_test = TestRun.new(test.file, visitor)
|
107
32
|
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def fail_current_test!
|
114
|
-
current_test.fail!
|
115
|
-
end
|
116
|
-
|
117
|
-
def record(source_file)
|
118
|
-
current_test.record(source_file)
|
119
|
-
end
|
120
|
-
|
121
|
-
def should_skip?
|
122
|
-
not current_test.may_execute?
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def current_test
|
128
|
-
@current_test or raise("You need to start the a test first!")
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
class Cache
|
133
|
-
def initialize(feature_file)
|
134
|
-
@feature_file = feature_file
|
135
|
-
end
|
136
|
-
|
137
|
-
def exists?
|
138
|
-
File.exist?(cache_filename)
|
139
|
-
end
|
140
|
-
|
141
|
-
def cache_filename
|
142
|
-
@feature_file.gsub /([^\/]*\.feature)/, '.coverage/\1'
|
143
|
-
end
|
144
|
-
|
145
|
-
def time
|
146
|
-
File.mtime(cache_filename)
|
147
|
-
end
|
33
|
+
def stop_recording!
|
34
|
+
return unless recording?
|
148
35
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
yield file
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
class StatusCache < Cache
|
158
|
-
def last_run_status
|
159
|
-
File.open(cache_filename, "r") do |file|
|
160
|
-
file.each_line do |line|
|
161
|
-
return line.strip
|
162
|
-
end
|
163
|
-
end
|
36
|
+
@current_recorder.stop!
|
37
|
+
store.keep!(@current_recorder.recording)
|
38
|
+
@current_recorder = nil
|
164
39
|
end
|
165
40
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
private
|
173
|
-
|
174
|
-
def cache_filename
|
175
|
-
super + '.status'
|
41
|
+
def record_file(source_file)
|
42
|
+
Cucover.logger.debug("Recording extra source file #{source_file}")
|
43
|
+
@current_recorder.record_file!(source_file)
|
176
44
|
end
|
177
|
-
end
|
178
45
|
|
179
|
-
class SourceFileCache < Cache
|
180
|
-
def save(analyzed_files)
|
181
|
-
write_to_cache do |file|
|
182
|
-
file.puts analyzed_files
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def any_dirty_files?
|
187
|
-
not dirty_files.empty?
|
188
|
-
end
|
189
|
-
|
190
|
-
def source_files
|
191
|
-
result = []
|
192
|
-
File.open(cache_filename, "r") do |file|
|
193
|
-
file.each_line do |line|
|
194
|
-
result.push line
|
195
|
-
end
|
196
|
-
end
|
197
|
-
result
|
198
|
-
end
|
199
|
-
|
200
46
|
private
|
201
|
-
|
202
|
-
def dirty_files
|
203
|
-
source_files.select do |source_file|
|
204
|
-
File.mtime(source_file.strip) >= time
|
205
|
-
end
|
206
|
-
end
|
207
47
|
|
208
|
-
|
209
|
-
|
210
|
-
module LazyStepInvocation
|
211
|
-
def accept(visitor)
|
212
|
-
skip_invoke! if Cucover.should_skip?
|
213
|
-
super
|
48
|
+
def controller(scenario_or_table_row)
|
49
|
+
Controller.new(scenario_or_table_row.file_colon_line, store)
|
214
50
|
end
|
215
51
|
|
216
|
-
def
|
217
|
-
|
218
|
-
super
|
52
|
+
def recording?
|
53
|
+
!!@current_recorder
|
219
54
|
end
|
220
|
-
end
|
221
55
|
|
222
|
-
|
223
|
-
|
224
|
-
Cucover.start_test(self, visitor) do
|
225
|
-
super
|
226
|
-
end
|
56
|
+
def store
|
57
|
+
@store ||= Store.new
|
227
58
|
end
|
228
|
-
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
Cucover::Monkey.extend_every Cucumber::Ast::Feature => Cucover::LazyFeature
|
233
|
-
Cucover::Monkey.extend_every Cucumber::Ast::StepInvocation => Cucover::LazyStepInvocation
|
234
|
-
|
235
|
-
Before do
|
236
|
-
Cucover::Rails.patch_if_necessary
|
59
|
+
end
|
237
60
|
end
|
data/lib/dependencies.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Cucover::Cli do
|
4
|
+
describe "given a --coverage-of command" do
|
5
|
+
before(:each) do
|
6
|
+
@args = ['--coverage-of', 'lib/foo.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a CoverageOf command object and execute it" do
|
10
|
+
Cucover::CliCommands::CoverageOf.should_receive(:new).with(['--coverage-of', 'lib/foo.rb']).and_return(command = mock('command'))
|
11
|
+
command.should_receive(:execute)
|
12
|
+
cli = Cucover::Cli.new(@args)
|
13
|
+
cli.start
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "given arguments for Cucumber" do
|
18
|
+
before(:each) do
|
19
|
+
@args = ['--', 'c', 'd']
|
20
|
+
end
|
21
|
+
it "should pass the arguments after the -- to cucumber" do
|
22
|
+
cli = Cucover::Cli.new(@args)
|
23
|
+
|
24
|
+
Kernel.stub!(:load).with(Cucumber::BINARY) do
|
25
|
+
ARGV.should == ['c', 'd']
|
26
|
+
end
|
27
|
+
|
28
|
+
cli.start
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module Cucover
|
4
|
+
describe Controller do
|
5
|
+
describe "#should_execute?" do
|
6
|
+
before(:each) do
|
7
|
+
@store = mock(Store)
|
8
|
+
@example_id = 'foo.feature:123'
|
9
|
+
end
|
10
|
+
it "when no previous recording exists, it should always return true" do
|
11
|
+
@store.should_receive(:latest_recording).with(@example_id).and_return(nil)
|
12
|
+
Controller.new(@example_id, @store).should_execute?.should be_true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
class Cucover::Recording
|
4
|
+
describe CoveredFile do
|
5
|
+
describe "with a marked info" do
|
6
|
+
before(:each) do
|
7
|
+
@recording = mock('Recording')
|
8
|
+
@covered_file = CoveredFile.new("foo.rb", [true, true, false], @recording)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should set the covered_lines correctly from the marked info" do
|
12
|
+
[1,2].each do |line_number|
|
13
|
+
@covered_file.covers_line?(line_number).should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
@covered_file.covers_line?(3).should be_false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module Cucover
|
4
|
+
describe Store do
|
5
|
+
before(:each) do
|
6
|
+
@cache = mock('cache', :load => nil)
|
7
|
+
@store = Store.new(@cache)
|
8
|
+
end
|
9
|
+
describe "#latest_recording" do
|
10
|
+
it "should return nil if no recordings match the given identifier" do
|
11
|
+
@store.latest_recording('blah:234').should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "when multiple recordings match the given indentifier" do
|
15
|
+
before(:each) do
|
16
|
+
old_recording = mock('old data', :end_time => Time.now - 200)
|
17
|
+
@new_recording = mock('new data', :end_time => Time.now)
|
18
|
+
@cache.stub!(:load).and_return({
|
19
|
+
'foo.feature:33' => [ old_recording, @new_recording ]
|
20
|
+
})
|
21
|
+
end
|
22
|
+
it "should return the one with the latest end_time" do
|
23
|
+
@store.latest_recording('foo.feature:33').should == @new_recording
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tmp/.gitignore
ADDED
File without changes
|