cucumber_fm-core 0.1
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/LICENCE +20 -0
- data/lib/cucumber_f_m/aggregator.rb +65 -0
- data/lib/cucumber_f_m/comment_module/comment.rb +7 -0
- data/lib/cucumber_f_m/config.rb +37 -0
- data/lib/cucumber_f_m/cvs/git.rb +7 -0
- data/lib/cucumber_f_m/feature.rb +141 -0
- data/lib/cucumber_f_m/feature_element/background.rb +10 -0
- data/lib/cucumber_f_m/feature_element/comment.rb +13 -0
- data/lib/cucumber_f_m/feature_element/component/comments.rb +21 -0
- data/lib/cucumber_f_m/feature_element/component/information/component.rb +16 -0
- data/lib/cucumber_f_m/feature_element/component/tags.rb +108 -0
- data/lib/cucumber_f_m/feature_element/component/title.rb +26 -0
- data/lib/cucumber_f_m/feature_element/component/total_estimation.rb +42 -0
- data/lib/cucumber_f_m/feature_element/example.rb +7 -0
- data/lib/cucumber_f_m/feature_element/info.rb +13 -0
- data/lib/cucumber_f_m/feature_element/narrative.rb +7 -0
- data/lib/cucumber_f_m/feature_element/scenario.rb +15 -0
- data/lib/cucumber_f_m/feature_element/scenario_outline.rb +23 -0
- data/lib/cucumber_f_m/feature_element/step.rb +7 -0
- data/lib/cucumber_f_m/statistic.rb +31 -0
- data/lib/cucumber_f_m/tag_filter.rb +85 -0
- data/lib/cucumber_feature_manager.rb +164 -0
- data/lib/grit/lib/grit.rb +75 -0
- data/lib/grit/lib/grit/actor.rb +36 -0
- data/lib/grit/lib/grit/blame.rb +61 -0
- data/lib/grit/lib/grit/blob.rb +126 -0
- data/lib/grit/lib/grit/commit.rb +247 -0
- data/lib/grit/lib/grit/commit_stats.rb +128 -0
- data/lib/grit/lib/grit/config.rb +44 -0
- data/lib/grit/lib/grit/diff.rb +70 -0
- data/lib/grit/lib/grit/errors.rb +7 -0
- data/lib/grit/lib/grit/git-ruby.rb +267 -0
- data/lib/grit/lib/grit/git-ruby/commit_db.rb +52 -0
- data/lib/grit/lib/grit/git-ruby/file_index.rb +193 -0
- data/lib/grit/lib/grit/git-ruby/git_object.rb +350 -0
- data/lib/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
- data/lib/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
- data/lib/grit/lib/grit/git-ruby/internal/pack.rb +384 -0
- data/lib/grit/lib/grit/git-ruby/internal/raw_object.rb +37 -0
- data/lib/grit/lib/grit/git-ruby/object.rb +325 -0
- data/lib/grit/lib/grit/git-ruby/repository.rb +767 -0
- data/lib/grit/lib/grit/git.rb +323 -0
- data/lib/grit/lib/grit/index.rb +122 -0
- data/lib/grit/lib/grit/lazy.rb +33 -0
- data/lib/grit/lib/grit/merge.rb +45 -0
- data/lib/grit/lib/grit/ref.rb +74 -0
- data/lib/grit/lib/grit/repo.rb +482 -0
- data/lib/grit/lib/grit/ruby1.9.rb +7 -0
- data/lib/grit/lib/grit/status.rb +151 -0
- data/lib/grit/lib/grit/submodule.rb +88 -0
- data/lib/grit/lib/grit/tag.rb +16 -0
- data/lib/grit/lib/grit/tree.rb +123 -0
- data/lib/grit/lib/open3_detach.rb +46 -0
- data/spec/cucumber_f_m/aggregator_spec.rb +210 -0
- data/spec/cucumber_f_m/comment_module/comment_spec.rb +4 -0
- data/spec/cucumber_f_m/config_spec.rb +27 -0
- data/spec/cucumber_f_m/cvs/git_spec.rb +40 -0
- data/spec/cucumber_f_m/feature_all_tags_to_scenario_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_file_manipulation_spec.rb +29 -0
- data/spec/cucumber_f_m/feature_module/background_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/comment_spec.rb +23 -0
- data/spec/cucumber_f_m/feature_module/example_spec.rb +5 -0
- data/spec/cucumber_f_m/feature_module/info_spec.rb +30 -0
- data/spec/cucumber_f_m/feature_module/narrative_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/scenario_outline_spec.rb +39 -0
- data/spec/cucumber_f_m/feature_module/scenario_spec.rb +33 -0
- data/spec/cucumber_f_m/feature_module/step_spec.rb +7 -0
- data/spec/cucumber_f_m/feature_module/tag_spec.rb +96 -0
- data/spec/cucumber_f_m/feature_spec.rb +229 -0
- data/spec/cucumber_f_m/tag_filter_spec.rb +191 -0
- data/spec/cucumber_feature_manager_spec.rb +59 -0
- data/spec/data/feature_manager/some_ruby_file.rb +0 -0
- data/spec/spec_helper.rb +1 -0
- metadata +141 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Status
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
@base = nil
|
7
|
+
@files = nil
|
8
|
+
|
9
|
+
def initialize(base)
|
10
|
+
@base = base
|
11
|
+
construct_status
|
12
|
+
end
|
13
|
+
|
14
|
+
def changed
|
15
|
+
@files.select { |k, f| f.type == 'M' }
|
16
|
+
end
|
17
|
+
|
18
|
+
def added
|
19
|
+
@files.select { |k, f| f.type == 'A' }
|
20
|
+
end
|
21
|
+
|
22
|
+
def deleted
|
23
|
+
@files.select { |k, f| f.type == 'D' }
|
24
|
+
end
|
25
|
+
|
26
|
+
def untracked
|
27
|
+
@files.select { |k, f| f.untracked }
|
28
|
+
end
|
29
|
+
|
30
|
+
def pretty
|
31
|
+
out = ''
|
32
|
+
self.each do |file|
|
33
|
+
out << file.path
|
34
|
+
out << "\n\tsha(r) " + file.sha_repo.to_s + ' ' + file.mode_repo.to_s
|
35
|
+
out << "\n\tsha(i) " + file.sha_index.to_s + ' ' + file.mode_index.to_s
|
36
|
+
out << "\n\ttype " + file.type.to_s
|
37
|
+
out << "\n\tstage " + file.stage.to_s
|
38
|
+
out << "\n\tuntrac " + file.untracked.to_s
|
39
|
+
out << "\n"
|
40
|
+
end
|
41
|
+
out << "\n"
|
42
|
+
out
|
43
|
+
end
|
44
|
+
|
45
|
+
# enumerable method
|
46
|
+
|
47
|
+
def [](file)
|
48
|
+
@files[file]
|
49
|
+
end
|
50
|
+
|
51
|
+
def each
|
52
|
+
@files.each do |k, file|
|
53
|
+
yield file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class StatusFile
|
58
|
+
attr_accessor :path, :type, :stage, :untracked
|
59
|
+
attr_accessor :mode_index, :mode_repo
|
60
|
+
attr_accessor :sha_index, :sha_repo
|
61
|
+
|
62
|
+
@base = nil
|
63
|
+
|
64
|
+
def initialize(base, hash)
|
65
|
+
@base = base
|
66
|
+
@path = hash[:path]
|
67
|
+
@type = hash[:type]
|
68
|
+
@stage = hash[:stage]
|
69
|
+
@mode_index = hash[:mode_index]
|
70
|
+
@mode_repo = hash[:mode_repo]
|
71
|
+
@sha_index = hash[:sha_index]
|
72
|
+
@sha_repo = hash[:sha_repo]
|
73
|
+
@untracked = hash[:untracked]
|
74
|
+
end
|
75
|
+
|
76
|
+
def blob(type = :index)
|
77
|
+
if type == :repo
|
78
|
+
@base.object(@sha_repo)
|
79
|
+
else
|
80
|
+
@base.object(@sha_index) rescue @base.object(@sha_repo)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def construct_status
|
89
|
+
@files = ls_files
|
90
|
+
|
91
|
+
Dir.chdir(@base.working_dir) do
|
92
|
+
# find untracked in working dir
|
93
|
+
Dir.glob('**/*') do |file|
|
94
|
+
if !@files[file]
|
95
|
+
@files[file] = {:path => file, :untracked => true} if !File.directory?(file)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# find modified in tree
|
100
|
+
diff_files.each do |path, data|
|
101
|
+
@files[path] ? @files[path].merge!(data) : @files[path] = data
|
102
|
+
end
|
103
|
+
|
104
|
+
# find added but not committed - new files
|
105
|
+
diff_index('HEAD').each do |path, data|
|
106
|
+
@files[path] ? @files[path].merge!(data) : @files[path] = data
|
107
|
+
end
|
108
|
+
|
109
|
+
@files.each do |k, file_hash|
|
110
|
+
@files[k] = StatusFile.new(@base, file_hash)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# compares the index and the working directory
|
116
|
+
def diff_files
|
117
|
+
hsh = {}
|
118
|
+
@base.git.diff_files.split("\n").each do |line|
|
119
|
+
(info, file) = line.split("\t")
|
120
|
+
(mode_src, mode_dest, sha_src, sha_dest, type) = info.split
|
121
|
+
hsh[file] = {:path => file, :mode_file => mode_src.to_s[1, 7], :mode_index => mode_dest,
|
122
|
+
:sha_file => sha_src, :sha_index => sha_dest, :type => type}
|
123
|
+
end
|
124
|
+
hsh
|
125
|
+
end
|
126
|
+
|
127
|
+
# compares the index and the repository
|
128
|
+
def diff_index(treeish)
|
129
|
+
hsh = {}
|
130
|
+
@base.git.diff_index({}, treeish).split("\n").each do |line|
|
131
|
+
(info, file) = line.split("\t")
|
132
|
+
(mode_src, mode_dest, sha_src, sha_dest, type) = info.split
|
133
|
+
hsh[file] = {:path => file, :mode_repo => mode_src.to_s[1, 7], :mode_index => mode_dest,
|
134
|
+
:sha_repo => sha_src, :sha_index => sha_dest, :type => type}
|
135
|
+
end
|
136
|
+
hsh
|
137
|
+
end
|
138
|
+
|
139
|
+
def ls_files
|
140
|
+
hsh = {}
|
141
|
+
lines = @base.git.ls_files({:stage => true})
|
142
|
+
lines.split("\n").each do |line|
|
143
|
+
(info, file) = line.split("\t")
|
144
|
+
(mode, sha, stage) = info.split
|
145
|
+
hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
|
146
|
+
end
|
147
|
+
hsh
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Submodule
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :mode
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
# Create a Submodule containing just the specified attributes
|
9
|
+
# +repo+ is the Repo
|
10
|
+
# +atts+ is a Hash of instance variable data
|
11
|
+
#
|
12
|
+
# Returns Grit::Submodule (unbaked)
|
13
|
+
def self.create(repo, atts)
|
14
|
+
self.allocate.create_initialize(repo, atts)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Initializer for Submodule.create
|
18
|
+
# +repo+ is the Repo
|
19
|
+
# +atts+ is a Hash of instance variable data
|
20
|
+
#
|
21
|
+
# Returns Grit::Submodule
|
22
|
+
def create_initialize(repo, atts)
|
23
|
+
@repo = repo
|
24
|
+
atts.each do |k, v|
|
25
|
+
instance_variable_set("@#{k}".to_sym, v)
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# The url of this submodule
|
31
|
+
# +ref+ is the committish that should be used to look up the url
|
32
|
+
#
|
33
|
+
# Returns String
|
34
|
+
def url(ref)
|
35
|
+
config = self.class.config(@repo, ref)
|
36
|
+
|
37
|
+
lookup = config.keys.inject({}) do |acc, key|
|
38
|
+
id = config[key]['id']
|
39
|
+
acc[id] = config[key]['url']
|
40
|
+
acc
|
41
|
+
end
|
42
|
+
|
43
|
+
lookup[@id]
|
44
|
+
end
|
45
|
+
|
46
|
+
# The configuration information for the given +repo+
|
47
|
+
# +repo+ is the Repo
|
48
|
+
# +ref+ is the committish (defaults to 'master')
|
49
|
+
#
|
50
|
+
# Returns a Hash of { <path:String> => { 'url' => <url:String>, 'id' => <id:String> } }
|
51
|
+
# Returns {} if no .gitmodules file was found
|
52
|
+
def self.config(repo, ref = "master")
|
53
|
+
commit = repo.commit(ref)
|
54
|
+
blob = commit.tree/'.gitmodules'
|
55
|
+
return {} unless blob
|
56
|
+
|
57
|
+
lines = blob.data.gsub(/\r\n?/, "\n" ).split("\n")
|
58
|
+
|
59
|
+
config = {}
|
60
|
+
current = nil
|
61
|
+
|
62
|
+
lines.each do |line|
|
63
|
+
if line =~ /^\[submodule "(.+)"\]$/
|
64
|
+
current = $1
|
65
|
+
config[current] = {}
|
66
|
+
config[current]['id'] = (commit.tree/current).id
|
67
|
+
elsif line =~ /^\t(\w+) = (.+)$/
|
68
|
+
config[current][$1] = $2
|
69
|
+
config[current]['id'] = (commit.tree/$2).id if $1 == 'path'
|
70
|
+
else
|
71
|
+
# ignore
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
config
|
76
|
+
end
|
77
|
+
|
78
|
+
def basename
|
79
|
+
File.basename(name)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Pretty object inspection
|
83
|
+
def inspect
|
84
|
+
%Q{#<Grit::Submodule "#{@id}">}
|
85
|
+
end
|
86
|
+
end # Submodule
|
87
|
+
|
88
|
+
end # Grit
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Tag < Ref
|
4
|
+
def self.find_all(repo, options = {})
|
5
|
+
refs = repo.git.refs(options, prefix)
|
6
|
+
refs.split("\n").map do |ref|
|
7
|
+
name, id = *ref.split(' ')
|
8
|
+
cid = repo.git.commit_from_sha(id)
|
9
|
+
raise "Unknown object type." if cid == ''
|
10
|
+
commit = Commit.create(repo, :id => cid)
|
11
|
+
self.new(name, commit)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Grit
|
2
|
+
|
3
|
+
class Tree
|
4
|
+
lazy_reader :contents
|
5
|
+
attr_reader :id
|
6
|
+
attr_reader :mode
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# Construct the contents of the tree
|
10
|
+
# +repo+ is the Repo
|
11
|
+
# +treeish+ is the reference
|
12
|
+
# +paths+ is an optional Array of directory paths to restrict the tree
|
13
|
+
#
|
14
|
+
# Returns Grit::Tree (baked)
|
15
|
+
def self.construct(repo, treeish, paths = [])
|
16
|
+
output = repo.git.ls_tree({}, treeish, *paths)
|
17
|
+
self.allocate.construct_initialize(repo, treeish, output)
|
18
|
+
end
|
19
|
+
|
20
|
+
def construct_initialize(repo, id, text)
|
21
|
+
@repo = repo
|
22
|
+
@id = id
|
23
|
+
@contents = []
|
24
|
+
|
25
|
+
text.split("\n").each do |line|
|
26
|
+
@contents << content_from_string(repo, line)
|
27
|
+
end
|
28
|
+
@contents.compact!
|
29
|
+
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def lazy_source
|
34
|
+
Tree.construct(@repo, @id, [])
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create an unbaked Tree containing just the specified attributes
|
38
|
+
# +repo+ is the Repo
|
39
|
+
# +atts+ is a Hash of instance variable data
|
40
|
+
#
|
41
|
+
# Returns Grit::Tree (unbaked)
|
42
|
+
def self.create(repo, atts)
|
43
|
+
self.allocate.create_initialize(repo, atts)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Initializer for Tree.create
|
47
|
+
# +repo+ is the Repo
|
48
|
+
# +atts+ is a Hash of instance variable data
|
49
|
+
#
|
50
|
+
# Returns Grit::Tree (unbaked)
|
51
|
+
def create_initialize(repo, atts)
|
52
|
+
@repo = repo
|
53
|
+
|
54
|
+
atts.each do |k, v|
|
55
|
+
instance_variable_set("@#{k}", v)
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# Parse a content item and create the appropriate object
|
61
|
+
# +repo+ is the Repo
|
62
|
+
# +text+ is the single line containing the items data in `git ls-tree` format
|
63
|
+
#
|
64
|
+
# Returns Grit::Blob or Grit::Tree
|
65
|
+
def content_from_string(repo, text)
|
66
|
+
mode, type, id, name = text.split(" ", 4)
|
67
|
+
case type
|
68
|
+
when "tree"
|
69
|
+
Tree.create(repo, :id => id, :mode => mode, :name => name)
|
70
|
+
when "blob"
|
71
|
+
Blob.create(repo, :id => id, :mode => mode, :name => name)
|
72
|
+
when "link"
|
73
|
+
Blob.create(repo, :id => id, :mode => mode, :name => name)
|
74
|
+
when "commit"
|
75
|
+
Submodule.create(repo, :id => id, :mode => mode, :name => name)
|
76
|
+
else
|
77
|
+
raise "Invalid type: #{type}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Find the named object in this tree's contents
|
82
|
+
#
|
83
|
+
# Examples
|
84
|
+
# Repo.new('/path/to/grit').tree/'lib'
|
85
|
+
# # => #<Grit::Tree "6cc23ee138be09ff8c28b07162720018b244e95e">
|
86
|
+
# Repo.new('/path/to/grit').tree/'README.txt'
|
87
|
+
# # => #<Grit::Blob "8b1e02c0fb554eed2ce2ef737a68bb369d7527df">
|
88
|
+
#
|
89
|
+
# Returns Grit::Blob or Grit::Tree or nil if not found
|
90
|
+
def /(file)
|
91
|
+
if file =~ /\//
|
92
|
+
file.split("/").inject(self) { |acc, x| acc/x } rescue nil
|
93
|
+
else
|
94
|
+
self.contents.find { |c| c.name == file }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def basename
|
99
|
+
File.basename(name)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Pretty object inspection
|
103
|
+
def inspect
|
104
|
+
%Q{#<Grit::Tree "#{@id}">}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Find only Tree objects from contents
|
108
|
+
def trees
|
109
|
+
contents.select {|v| v.kind_of? Tree}
|
110
|
+
end
|
111
|
+
|
112
|
+
# Find only Blob objects from contents
|
113
|
+
def blobs
|
114
|
+
contents.select {|v| v.kind_of? Blob}
|
115
|
+
end
|
116
|
+
|
117
|
+
# Compares trees by name
|
118
|
+
def <=>(other)
|
119
|
+
name <=> other.name
|
120
|
+
end
|
121
|
+
end # Tree
|
122
|
+
|
123
|
+
end # Grit
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Open3
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def popen3(*cmd)
|
5
|
+
pw = IO::pipe # pipe[0] for read, pipe[1] for write
|
6
|
+
pr = IO::pipe
|
7
|
+
pe = IO::pipe
|
8
|
+
|
9
|
+
pid = fork{
|
10
|
+
# child
|
11
|
+
fork{
|
12
|
+
# grandchild
|
13
|
+
pw[1].close
|
14
|
+
STDIN.reopen(pw[0])
|
15
|
+
pw[0].close
|
16
|
+
|
17
|
+
pr[0].close
|
18
|
+
STDOUT.reopen(pr[1])
|
19
|
+
pr[1].close
|
20
|
+
|
21
|
+
pe[0].close
|
22
|
+
STDERR.reopen(pe[1])
|
23
|
+
pe[1].close
|
24
|
+
|
25
|
+
exec(*cmd)
|
26
|
+
}
|
27
|
+
exit!(0)
|
28
|
+
}
|
29
|
+
|
30
|
+
pw[0].close
|
31
|
+
pr[1].close
|
32
|
+
pe[1].close
|
33
|
+
Process.waitpid(pid)
|
34
|
+
pi = [pw[1], pr[0], pe[0]]
|
35
|
+
pw[1].sync = true
|
36
|
+
if defined? yield
|
37
|
+
begin
|
38
|
+
return yield(*pi)
|
39
|
+
ensure
|
40
|
+
Process.detach(pid) if pid
|
41
|
+
pi.each { |p| p.close unless p.closed? }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
pi
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# TODO understand why subject { Klass.new(a,b) } doesn't work in rspec as it should
|
4
|
+
|
5
|
+
describe CucumberFM::Aggregator do
|
6
|
+
before(:each) do
|
7
|
+
@f1 = mock('feature1')
|
8
|
+
@f2 = mock('feature2')
|
9
|
+
@s11 = mock('scenario1', :feature => @f1, :tags => ['@m1', '@mc', '@i1'],
|
10
|
+
:tags_without_technical => ['@m1', '@mc', '@i1'], :estimation => 1.5)
|
11
|
+
@s12 = mock('scenario2', :feature => @f1, :tags => ['@m2', '@ak', '@i1'],
|
12
|
+
:tags_without_technical => ['@m2', '@ak', '@i1'], :estimation => 1.75)
|
13
|
+
@s13 = mock('scenario5', :feature => @f1, :tags => ['@m2', '@ak', '@i1'],
|
14
|
+
:tags_without_technical => ['@m2', '@ak', '@i1'], :estimation => 1)
|
15
|
+
@s21 = mock('scenario3', :feature => @f2, :tags => ['@m3', '@mc', '@i1'],
|
16
|
+
:tags_without_technical => ['@m3', '@mc', '@i1'], :estimation => 2)
|
17
|
+
@s22 = mock('scenario4', :feature => @f2, :tags => ['@m2', '@tb', '@i2'],
|
18
|
+
:tags_without_technical => ['@m2', '@tb', '@i2'], :estimation => 1)
|
19
|
+
@cfm = mock('cfm', :scenarios => [@s11, @s12, @s13, @s21, @s22])
|
20
|
+
@aggregator1 = CucumberFM::FeatureElement::Component::Tags::PATTERN[:milestone]
|
21
|
+
@aggregator2 = CucumberFM::FeatureElement::Component::Tags::PATTERN[:iteration]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return estimation value for scenarios array" do
|
25
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator1])
|
26
|
+
@aggregator.collection['@m2'][@f1].estimation.should == 2.75
|
27
|
+
end
|
28
|
+
|
29
|
+
context "totals values should be correct" do
|
30
|
+
before(:each) do
|
31
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator1])
|
32
|
+
@collection = @aggregator.collection
|
33
|
+
end
|
34
|
+
it "for features" do
|
35
|
+
@collection.should have(2).features
|
36
|
+
end
|
37
|
+
it "for scenarios" do
|
38
|
+
@collection.should have(5).scenarios
|
39
|
+
end
|
40
|
+
it "for estimation" do
|
41
|
+
@collection.estimation.should == 7.25
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "single dimension" do
|
46
|
+
before(:each) do
|
47
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator1])
|
48
|
+
@collection = @aggregator.collection
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should aggregate correctly" do
|
52
|
+
@collection.should ==
|
53
|
+
{
|
54
|
+
'@m1' => {
|
55
|
+
@f1 => [@s11]
|
56
|
+
},
|
57
|
+
'@m2' => {
|
58
|
+
@f1 => [@s12, @s13],
|
59
|
+
@f2 => [@s22]
|
60
|
+
},
|
61
|
+
'@m3' => {
|
62
|
+
@f2 => [@s21]
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
{'@m1' =>[1, 1, 1.5], '@m2' => [2, 3, 3.75], '@m3' => [1, 1, 2]}.each_pair do |key, value|
|
68
|
+
context "should correct count" do
|
69
|
+
context key do
|
70
|
+
it "features" do
|
71
|
+
@collection[key].should have(value[0]).features
|
72
|
+
end
|
73
|
+
it "scenarios" do
|
74
|
+
@collection[key].should have(value[1]).scenarios
|
75
|
+
end
|
76
|
+
it "estimation" do
|
77
|
+
@collection[key].estimation.should == value[2]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "double dimension" do
|
85
|
+
before(:each) do
|
86
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator1, @aggregator2])
|
87
|
+
@collection = @aggregator.collection
|
88
|
+
end
|
89
|
+
it "should aggregate correctly" do
|
90
|
+
@collection.should ==
|
91
|
+
{
|
92
|
+
'@m1' => {
|
93
|
+
'@i1' => { @f1 => [@s11] }
|
94
|
+
},
|
95
|
+
'@m2' => {
|
96
|
+
'@i1' => { @f1 => [@s12, @s13]},
|
97
|
+
'@i2' => { @f2 => [@s22]}
|
98
|
+
},
|
99
|
+
'@m3' => {
|
100
|
+
'@i1' => { @f2 => [@s21]}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
{'@m1' =>[1, 1, 1.5], '@m2' => [2, 3, 3.75], '@m3' => [1, 1, 2]}.each_pair do |key, value|
|
106
|
+
context "should count correctly at first level" do
|
107
|
+
context key do
|
108
|
+
it "features " do
|
109
|
+
@collection[key].should have(value[0]).features
|
110
|
+
end
|
111
|
+
it "scenarios" do
|
112
|
+
@collection[key].should have(value[1]).scenarios
|
113
|
+
end
|
114
|
+
it "estimation" do
|
115
|
+
@collection[key].estimation.should == value[2]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
{['@m2', '@i1'] =>[1, 2, 2.75], ['@m2', '@i2'] =>[1, 1, 1], ['@m3', '@i1'] => [1, 1, 2]}.each_pair do |key, value|
|
122
|
+
context "should count correctly at second level" do
|
123
|
+
context key do
|
124
|
+
it "features " do
|
125
|
+
@collection[key.first][key.last].should have(value[0]).features
|
126
|
+
end
|
127
|
+
it "scenarios" do
|
128
|
+
@collection[key.first][key.last].should have(value[1]).scenarios
|
129
|
+
end
|
130
|
+
it "estimation" do
|
131
|
+
@collection[key.first][key.last].estimation.should == value[2]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
context "when tag for pattern not found is should be labelled as 'undefined' " do
|
140
|
+
before(:each) do
|
141
|
+
@s22 = mock('scenario4', :feature => @f2, :tags => ['@tb'], :tags_without_technical => ['@tb'],
|
142
|
+
:estimation => 1)
|
143
|
+
@cfm = mock('cfm', :scenarios => [@s11, @s12, @s13, @s21, @s22])
|
144
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator1])
|
145
|
+
@collection = @aggregator.collection
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should aggregate correctly" do
|
149
|
+
@collection.should ==
|
150
|
+
{
|
151
|
+
'@m1' => {
|
152
|
+
@f1 => [@s11]
|
153
|
+
},
|
154
|
+
'@m2' => {
|
155
|
+
@f1 => [@s12, @s13]
|
156
|
+
},
|
157
|
+
'_undefined_' => {
|
158
|
+
@f2 => [@s22]
|
159
|
+
},
|
160
|
+
'@m3' => {
|
161
|
+
@f2 => [@s21]
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "multiple tags (one scenario can be aggregated many times" do
|
168
|
+
before(:each) do
|
169
|
+
@s22 = mock('scenario4', :feature => @f2, :tags => ['@mc', '@tb'],
|
170
|
+
:tags_without_technical => ['@mc', '@tb'], :estimation => 1)
|
171
|
+
@cfm = mock('cfm', :scenarios => [@s11, @s12, @s13, @s21, @s22])
|
172
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, nil, ['@mc', '@tb', '@ak'])
|
173
|
+
@collection = @aggregator.collection
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should aggregate correctly" do
|
177
|
+
@collection.should ==
|
178
|
+
{
|
179
|
+
'@mc' => [@s11, @s21, @s22],
|
180
|
+
'@tb' => [@s22],
|
181
|
+
'@ak' => [@s12, @s13]
|
182
|
+
}
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
context "results should not be aggregated by technical tags on second level" do
|
188
|
+
before(:each) do
|
189
|
+
@aggregator_component = CucumberFM::FeatureElement::Component::Tags::PATTERN[:component]
|
190
|
+
@aggregator_developer = CucumberFM::FeatureElement::Component::Tags::PATTERN[:developer]
|
191
|
+
@s22 = mock('scenario4', :feature => @f2, :tags => ['@selenium', '@aggregator', '@ao'],
|
192
|
+
:tags_without_technical => ['@aggregator','@ao'], :estimation => 1)
|
193
|
+
@cfm = mock('cfm', :scenarios => [@s22])
|
194
|
+
@aggregator = CucumberFM::Aggregator.new(@cfm, [@aggregator_developer, @aggregator_component])
|
195
|
+
@collection = @aggregator.collection
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should aggregate correctly" do
|
199
|
+
@collection.should ==
|
200
|
+
{
|
201
|
+
'@ao' => {
|
202
|
+
'@aggregator' => {
|
203
|
+
@f2 => [@s22]
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|