cucover 0.1.2
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.
- data/.gitignore +6 -0
- data/Licence.txt +22 -0
- data/README.markdown +69 -0
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/bin/cucover +3 -0
- data/cucover.gemspec +182 -0
- data/cucumber.yml +3 -0
- data/examples/self_test/rails/.gitignore +4 -0
- data/examples/self_test/rails/Rakefile +10 -0
- data/examples/self_test/rails/app/controllers/application_controller.rb +2 -0
- data/examples/self_test/rails/app/controllers/widgets_controller.rb +2 -0
- data/examples/self_test/rails/app/helpers/application_helper.rb +3 -0
- data/examples/self_test/rails/app/views/widgets/index.html.erb +1 -0
- data/examples/self_test/rails/config/boot.rb +110 -0
- data/examples/self_test/rails/config/cucumber.yml +7 -0
- data/examples/self_test/rails/config/database.yml +25 -0
- data/examples/self_test/rails/config/environment.rb +41 -0
- data/examples/self_test/rails/config/environments/cucumber.rb +27 -0
- data/examples/self_test/rails/config/environments/development.rb +17 -0
- data/examples/self_test/rails/config/environments/production.rb +28 -0
- data/examples/self_test/rails/config/environments/test.rb +28 -0
- data/examples/self_test/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/self_test/rails/config/initializers/inflections.rb +10 -0
- data/examples/self_test/rails/config/initializers/mime_types.rb +5 -0
- data/examples/self_test/rails/config/initializers/new_rails_defaults.rb +21 -0
- data/examples/self_test/rails/config/initializers/session_store.rb +15 -0
- data/examples/self_test/rails/config/locales/en.yml +5 -0
- data/examples/self_test/rails/config/routes.rb +43 -0
- data/examples/self_test/rails/db/seeds.rb +7 -0
- data/examples/self_test/rails/features/see_widgets.feature +7 -0
- data/examples/self_test/rails/features/step_definitions/web_steps.rb +273 -0
- data/examples/self_test/rails/features/support/env.rb +57 -0
- data/examples/self_test/rails/features/support/paths.rb +29 -0
- data/examples/self_test/rails/lib/tasks/cucumber.rake +47 -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/favicon.ico +0 -0
- data/examples/self_test/rails/public/images/rails.png +0 -0
- data/examples/self_test/rails/public/index.html +275 -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 +973 -0
- data/examples/self_test/rails/public/javascripts/effects.js +1128 -0
- data/examples/self_test/rails/public/javascripts/prototype.js +4320 -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 +10 -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/plugin +3 -0
- data/examples/self_test/rails/script/runner +3 -0
- data/examples/self_test/rails/script/server +3 -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 +81 -0
- data/features/fail.feature +60 -0
- data/features/help.feature +15 -0
- data/features/lazy_run.feature +76 -0
- data/features/lazy_run_per_scenario.feature +108 -0
- data/features/lazy_run_per_scenario_outline_example.feature +29 -0
- data/features/lazy_run_triggered_by_rails_view_change.feature +43 -0
- data/features/run.feature +25 -0
- data/features/show_recordings.feature +28 -0
- data/features/step_definitions/main_steps.rb +41 -0
- data/features/support/env.rb +52 -0
- data/lib/at_exit_hook.rb +3 -0
- data/lib/cucover.rb +65 -0
- data/lib/cucover/cli.rb +50 -0
- data/lib/cucover/cli_commands/coverage_of.rb +44 -0
- data/lib/cucover/cli_commands/cucumber.rb +46 -0
- data/lib/cucover/cli_commands/show_recordings.rb +29 -0
- data/lib/cucover/cli_commands/version.rb +13 -0
- data/lib/cucover/controller.rb +28 -0
- data/lib/cucover/cucumber_hooks.rb +45 -0
- data/lib/cucover/line_numbers.rb +10 -0
- data/lib/cucover/logging_config.rb +16 -0
- data/lib/cucover/monkey.rb +14 -0
- data/lib/cucover/rails.rb +23 -0
- data/lib/cucover/recorder.rb +37 -0
- data/lib/cucover/recording.rb +66 -0
- data/lib/cucover/recording/covered_file.rb +53 -0
- data/lib/cucover/store.rb +70 -0
- 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 +236 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Cucover
|
|
2
|
+
class Controller
|
|
3
|
+
def initialize(file_colon_line, store)
|
|
4
|
+
@file_colon_line = file_colon_line
|
|
5
|
+
@store = store
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def should_execute?
|
|
9
|
+
dirty? or failed_on_last_run?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def failed_on_last_run?
|
|
15
|
+
return false unless recording
|
|
16
|
+
recording.failed?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def dirty?
|
|
20
|
+
Cucover.logger.debug("Assuming dirty as no recording found") and return true unless recording
|
|
21
|
+
recording.covered_files.any?{ |f| f.dirty? }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def recording
|
|
25
|
+
@recording ||= @store.latest_recording(@file_colon_line)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Cucover
|
|
2
|
+
module FeatureElementExtensions
|
|
3
|
+
def reset_skipped_steps!
|
|
4
|
+
return unless @steps
|
|
5
|
+
@steps.each do |step|
|
|
6
|
+
step.instance_variable_set("@skip_invoke", nil)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Cucover
|
|
13
|
+
module ExampleRowExtensions
|
|
14
|
+
include FeatureElementExtensions
|
|
15
|
+
|
|
16
|
+
def file_colon_line
|
|
17
|
+
"#{file}:#{line}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def file
|
|
21
|
+
@scenario_outline.file_colon_line.split(':').first
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Cucover::Monkey.extend_every Cucumber::Ast::Scenario => Cucover::FeatureElementExtensions
|
|
27
|
+
Cucover::Monkey.extend_every Cucumber::Ast::OutlineTable::ExampleRow => Cucover::ExampleRowExtensions
|
|
28
|
+
|
|
29
|
+
Before do |scenario_or_table_row|
|
|
30
|
+
scenario_or_table_row.reset_skipped_steps!
|
|
31
|
+
|
|
32
|
+
Cucover.logger.info("Starting #{scenario_or_table_row.class} #{scenario_or_table_row.file_colon_line}")
|
|
33
|
+
Cucover::Rails.patch_if_necessary
|
|
34
|
+
|
|
35
|
+
if Cucover.should_execute?(scenario_or_table_row)
|
|
36
|
+
Cucover.start_recording!(scenario_or_table_row)
|
|
37
|
+
else
|
|
38
|
+
announce "[ Cucover - Skipping clean scenario ]"
|
|
39
|
+
scenario_or_table_row.skip_invoke!
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
After do
|
|
44
|
+
Cucover.stop_recording!
|
|
45
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Logging.configure do
|
|
2
|
+
logger('Cucover') do
|
|
3
|
+
level :debug
|
|
4
|
+
appenders 'logfile'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
appender('logfile') do
|
|
8
|
+
type 'File'
|
|
9
|
+
level :debug
|
|
10
|
+
filename File.dirname(__FILE__) + '/../../tmp/cucover.log'
|
|
11
|
+
layout do
|
|
12
|
+
type 'Pattern'
|
|
13
|
+
pattern '[%d] %l %c : %m\n'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Cucover
|
|
2
|
+
module Monkey
|
|
3
|
+
def self.extend_every(args)
|
|
4
|
+
class_to_extend = args.keys.first
|
|
5
|
+
module_to_extend_with = args.values.first
|
|
6
|
+
|
|
7
|
+
class_to_extend.instance_eval <<-PATCH
|
|
8
|
+
def new(*args)
|
|
9
|
+
super(*args).extend(#{module_to_extend_with})
|
|
10
|
+
end
|
|
11
|
+
PATCH
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Cucover
|
|
2
|
+
module Rails
|
|
3
|
+
class << self
|
|
4
|
+
def patch_if_necessary
|
|
5
|
+
return if @patched
|
|
6
|
+
return unless defined?(ActionView)
|
|
7
|
+
|
|
8
|
+
Monkey.extend_every ActionView::Base => Cucover::Rails::RecordsRenders
|
|
9
|
+
# Monkey.extend_every ActionView::Template => Cucover::Rails::RecordsRenders # TODO: patch nicer template
|
|
10
|
+
|
|
11
|
+
@patched = true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module RecordsRenders
|
|
16
|
+
def render(*args)
|
|
17
|
+
filename = args[0][:file].filename
|
|
18
|
+
Cucover.record_file(filename)
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Cucover
|
|
2
|
+
class Recorder
|
|
3
|
+
def initialize(scenario_or_table_row)
|
|
4
|
+
@scenario_or_table_row = scenario_or_table_row
|
|
5
|
+
@analyzer = Rcov::CodeCoverageAnalyzer.new
|
|
6
|
+
@additional_covered_files = []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def record_file!(source_file)
|
|
10
|
+
unless @additional_covered_files.include?(source_file)
|
|
11
|
+
@additional_covered_files << source_file
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def start!
|
|
16
|
+
@start_time = Time.now
|
|
17
|
+
@analyzer.install_hook
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop!
|
|
21
|
+
@end_time = Time.now
|
|
22
|
+
@analyzer.remove_hook
|
|
23
|
+
Cucover.logger.info("Finished recording #{@scenario_or_table_row.file_colon_line}.")
|
|
24
|
+
Cucover.logger.debug("Covered files: #{@analyzer.analyzed_files.join(',')}")
|
|
25
|
+
Cucover.logger.debug("Additional Covered files: #{@additional_covered_files.join(',')}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def recording
|
|
29
|
+
Recording.new(
|
|
30
|
+
@scenario_or_table_row.file_colon_line,
|
|
31
|
+
@scenario_or_table_row.exception,
|
|
32
|
+
@additional_covered_files,
|
|
33
|
+
@analyzer,
|
|
34
|
+
@start_time, @end_time)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
IGNORE_PATTERNS = [
|
|
10
|
+
/gem/,
|
|
11
|
+
/vendor/,
|
|
12
|
+
/lib\/ruby/,
|
|
13
|
+
/cucover\/lib/
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
def feature_filename
|
|
17
|
+
file_colon_line.split(':').first
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def covers_file?(source_file)
|
|
21
|
+
covered_files.include?(source_file)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def covers_line?(source_file, line_number)
|
|
25
|
+
covered_files.detect{ |f| f.file == source_file }.covers_line?(line_number)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def covered_files
|
|
29
|
+
@covered_files ||= analyzed_covered_files + additional_covered_files
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def failed?
|
|
33
|
+
!!exception
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def additional_covered_files
|
|
39
|
+
super.map do |filename|
|
|
40
|
+
CoveredFile.new(filename, nil, self)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def analyzed_covered_files
|
|
45
|
+
filtered_analyzed_files.map do |filename|
|
|
46
|
+
lines, marked_info, count_info = analyzer.data(filename)
|
|
47
|
+
CoveredFile.new(filename, marked_info, self)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def boring?(file)
|
|
52
|
+
IGNORE_PATTERNS.any? do |expression|
|
|
53
|
+
file.match expression
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def filtered_analyzed_files
|
|
58
|
+
analyzer.analyzed_files.reject{ |f| boring?(f) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def normalized_files
|
|
62
|
+
cleaned_analyzed_files + additional_covered_files
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
require 'cucover/recording/covered_file'
|
|
@@ -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 + Cucover::LineNumbers.offset
|
|
47
|
+
@covered_lines << line_number if covered
|
|
48
|
+
end
|
|
49
|
+
@covered_lines
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -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/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
|