mattwynne-cucover 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +19 -0
- data/bin/cucover +5 -0
- data/lib/cucover.rb +110 -0
- metadata +75 -0
data/README.markdown
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Cucover
|
2
|
+
|
3
|
+
Cucover is a thin wrapper for [Cucumber](http://github.com/aslakhellesoy/cucumber/tree/master) which makes it lazy.
|
4
|
+
|
5
|
+
What does it mean for Cucumber to be lazy? It will only run a feature if it needs to.
|
6
|
+
|
7
|
+
How does it decide whether it needs to run a feature? Every time you run a feature using Cucover, it watches the code in your application that is executed, and remembers. The next time you run Cucover, it skips a feature if the source files (or the feature itself) have not been changed since it was last run.
|
8
|
+
|
9
|
+
## Installation and Usage
|
10
|
+
|
11
|
+
There's no gem for now, so just clone the code from github.
|
12
|
+
|
13
|
+
To run your features lazily, just use the cucover binary instead of cucumber. Use the same command-line options as usual, they are all passed directly to cucumber. No magic to see here, just a little gentle duck-punching.
|
14
|
+
|
15
|
+
## Limitations
|
16
|
+
|
17
|
+
* Cucover uses RCov to watch the code executed by each feature. RCov does not report ERB view templates so Rails views, for example, that are touched will not cause any features to be re-run.
|
18
|
+
* Anything that runs out of process will not be covered, and therefore cannot trigger a re-run, so if you use Cucumber to drive Selenium, for example, you're out of luck.
|
19
|
+
* This is very new and experimental. There may be bugs. Feedback is welcome via github messages.
|
data/bin/cucover
ADDED
data/lib/cucover.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rcov'
|
6
|
+
|
7
|
+
module Cucover
|
8
|
+
|
9
|
+
class SourceFileCache
|
10
|
+
def initialize(feature_file)
|
11
|
+
@feature_file = feature_file
|
12
|
+
end
|
13
|
+
|
14
|
+
def save(analyzed_files)
|
15
|
+
FileUtils.mkdir_p File.dirname(cache_filename)
|
16
|
+
File.open(cache_filename, "w") do |file|
|
17
|
+
file.puts analyzed_files
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def exists?
|
22
|
+
File.exist?(cache_filename)
|
23
|
+
end
|
24
|
+
|
25
|
+
def dirty_files
|
26
|
+
source_files.select do |source_file|
|
27
|
+
File.mtime(Dir.pwd + '/' + source_file.strip) > time
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def time
|
32
|
+
File.mtime(cache_filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def source_files
|
38
|
+
result = []
|
39
|
+
File.open(cache_filename, "r") do |file|
|
40
|
+
file.each_line do |line|
|
41
|
+
result.push line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def cache_filename
|
48
|
+
@feature_file.gsub /([^\/]*\.feature)/, '.coverage/\1'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module LazyFeature
|
53
|
+
|
54
|
+
def accept(visitor)
|
55
|
+
return unless dirty?
|
56
|
+
analyzer.run_hooked do
|
57
|
+
super
|
58
|
+
end
|
59
|
+
source_files_cache.save analyzed_files
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def dirty?
|
65
|
+
return true unless source_files_cache.exists?
|
66
|
+
return true if File.mtime(@file) >= source_files_cache.time
|
67
|
+
not source_files_cache.dirty_files.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def source_files_cache
|
71
|
+
@source_files_cache ||= SourceFileCache.new(@file)
|
72
|
+
end
|
73
|
+
|
74
|
+
def source_files
|
75
|
+
analyzed_files
|
76
|
+
end
|
77
|
+
|
78
|
+
def analyzed_files
|
79
|
+
normalized_files = analyzer.analyzed_files.map{ |f| File.expand_path(f).gsub(/^#{Dir.pwd}\//, '') }
|
80
|
+
interesting_files = normalized_files.reject{ |f| boring?(f) }
|
81
|
+
interesting_files.sort
|
82
|
+
end
|
83
|
+
|
84
|
+
def boring?(file)
|
85
|
+
(file.match /gem/) || (file.match /vendor/) || (file.match /lib\/ruby/)
|
86
|
+
end
|
87
|
+
|
88
|
+
def analyzer
|
89
|
+
@analyzer ||= Rcov::CodeCoverageAnalyzer.new
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module LazyFeatures
|
94
|
+
def add_feature(feature)
|
95
|
+
super feature.extend(LazyFeature)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module Cucumber
|
101
|
+
module Ast
|
102
|
+
class Features
|
103
|
+
class << self
|
104
|
+
def new(*args)
|
105
|
+
super(*args).extend(Cucover::LazyFeatures)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mattwynne-cucover
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Wynne
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-18 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: cucumber
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0.2"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rcov
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.1.5
|
34
|
+
version:
|
35
|
+
description: Cucover is a thin wrapper for Cucumber which makes it lazy.
|
36
|
+
email: matt@mattwynne.net
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/cucover.rb
|
45
|
+
- bin/cucover
|
46
|
+
- README.markdown
|
47
|
+
has_rdoc: false
|
48
|
+
homepage: http://github.com/mattwynne/cucover
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
- bin
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project: cucover
|
70
|
+
rubygems_version: 1.2.0
|
71
|
+
signing_key:
|
72
|
+
specification_version: 2
|
73
|
+
summary: Cucover is a thin wrapper for Cucumber which makes it lazy.
|
74
|
+
test_files: []
|
75
|
+
|