cuporter 0.3.10 → 0.3.12
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/README.textile +86 -70
- data/Rakefile +6 -5
- data/bin/cuporter +2 -0
- data/config/batch_mode.example.yml +47 -0
- data/config/cli/options.rb +19 -3
- data/config/configuration.rb +23 -126
- data/config/cuporter.example.yml +8 -0
- data/config/option_set.rb +79 -0
- data/config/yaml_file/option_set_collection.rb +42 -0
- data/lib/cuporter.rb +1 -3
- data/lib/cuporter/feature_parser.rb +6 -70
- data/lib/cuporter/feature_parser/language.rb +41 -0
- data/lib/cuporter/feature_parser/node_parser.rb +64 -0
- data/lib/cuporter/feature_parser/old_gherkin_yaml/i18n.rb +9 -0
- data/lib/cuporter/feature_parser/parser_base.rb +84 -0
- data/lib/cuporter/feature_parser/tag_nodes_parser.rb +96 -0
- data/lib/cuporter/logging.rb +32 -0
- data/lib/cuporter/node.rb +6 -6
- data/lib/cuporter/report/tag_report.rb +1 -1
- metadata +31 -9
- data/lib/cuporter/node_parser.rb +0 -62
- data/lib/cuporter/tag_nodes_parser.rb +0 -94
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
module Cuporter
|
3
|
+
module Config
|
4
|
+
|
5
|
+
class OptionSet
|
6
|
+
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def initialize(file_config = {})
|
10
|
+
# CLI options replace any found in the file
|
11
|
+
cli_options_over_file_options = file_config.merge(Cuporter::Config::CLI::Options.options)
|
12
|
+
|
13
|
+
# defaults will be used for anything not so far specified in the file
|
14
|
+
# or CLI
|
15
|
+
@options = post_process(Cuporter::Config::DEFAULTS.merge(cli_options_over_file_options))
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](key)
|
19
|
+
@options[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def output_file(format)
|
23
|
+
if (file = @options[:output_file].find {|f| f =~ ext_for(format) })
|
24
|
+
File.open(file, "w")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def dump
|
29
|
+
col_1_max = @options.keys.max_by {|i| i.to_s.length }.to_s.size
|
30
|
+
@options.each do |key, value|
|
31
|
+
puts ":#{key.to_s.ljust(col_1_max, ' ')} => #{value.inspect}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def dry_run?
|
36
|
+
@options[:dry_run]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def post_process(options)
|
42
|
+
options[:input_file_pattern] = options.delete(:input_file) || "#{options.delete(:input_dir)}/**/*.feature"
|
43
|
+
options[:root_dir] = options[:input_file_pattern].split(File::SEPARATOR).first
|
44
|
+
options[:filter_args] = Cuporter::Config::CLI::FilterArgsBuilder.new(options.delete(:tags)).args
|
45
|
+
options[:output_file].each_with_index do |file_path, i|
|
46
|
+
options[:output_file][i] = full_path(options[:output_home], file_path.dup )
|
47
|
+
end
|
48
|
+
|
49
|
+
unless options[:output_file].find {|f| f =~ /\.html$/ }
|
50
|
+
options[:copy_public_assets] = options[:use_copied_public_assets] = false
|
51
|
+
end
|
52
|
+
|
53
|
+
unless options[:output_file].empty?
|
54
|
+
options[:log_dir] = File.dirname(options[:output_file].first)
|
55
|
+
end
|
56
|
+
options
|
57
|
+
end
|
58
|
+
|
59
|
+
def full_path(root_dir, file_path)
|
60
|
+
path = root_dir.empty? ? file_path : File.join(root_dir, file_path)
|
61
|
+
expanded_path = File.expand_path(path)
|
62
|
+
path_nodes = expanded_path.split(File::SEPARATOR)
|
63
|
+
file = path_nodes.pop
|
64
|
+
FileUtils.makedirs(path_nodes.join(File::SEPARATOR))
|
65
|
+
expanded_path
|
66
|
+
end
|
67
|
+
|
68
|
+
def ext_for(format)
|
69
|
+
case format
|
70
|
+
when 'text', 'pretty'
|
71
|
+
/\.txt$/
|
72
|
+
else
|
73
|
+
/\.#{format}$/
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
module Cuporter
|
3
|
+
module Config
|
4
|
+
module YamlFile
|
5
|
+
class OptionSetCollection
|
6
|
+
|
7
|
+
def self.path
|
8
|
+
Cuporter::Config::CLI::Options[:config_file] || "config/cuporter.yml"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.config_file
|
12
|
+
return [] unless File.exists?(path)
|
13
|
+
|
14
|
+
require 'yaml'
|
15
|
+
yaml = YAML.load_file(path)
|
16
|
+
if yaml["option_sets"]
|
17
|
+
yaml["option_sets"].map do |option_set|
|
18
|
+
cast(option_set["options"])
|
19
|
+
end
|
20
|
+
else
|
21
|
+
yaml["defaults"].empty? ? [] : [cast(yaml["defaults"])]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.cast(option_set)
|
26
|
+
pairs = {}
|
27
|
+
option_set.each do |key, value|
|
28
|
+
pairs[key.to_sym] = case key
|
29
|
+
when /^(tags|output_file|format)$/i
|
30
|
+
value.is_a?(Array) ? value : [value]
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
return pairs
|
37
|
+
end
|
38
|
+
|
39
|
+
end # class
|
40
|
+
end # File
|
41
|
+
end # Config
|
42
|
+
end
|
data/lib/cuporter.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
# Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
|
2
2
|
$LOAD_PATH.unshift( File.expand_path("#{File.dirname(__FILE__)}"))
|
3
|
-
$LOAD_PATH.unshift( File.expand_path("#{File.dirname(__FILE__)}/.."))
|
4
3
|
require 'cuporter/extensions/string'
|
4
|
+
require 'cuporter/logging'
|
5
5
|
require 'cuporter/node'
|
6
6
|
require 'cuporter/formatters/text'
|
7
7
|
require 'cuporter/formatters/csv'
|
8
8
|
require 'cuporter/filter'
|
9
9
|
require 'cuporter/feature_parser'
|
10
|
-
require 'cuporter/tag_nodes_parser'
|
11
|
-
require 'cuporter/node_parser'
|
12
10
|
require 'cuporter/document'
|
13
11
|
require 'cuporter/document/assets'
|
14
12
|
require 'cuporter/document/html_document'
|
@@ -1,16 +1,11 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
require 'cuporter/feature_parser/language'
|
3
|
+
require 'cuporter/feature_parser/parser_base'
|
4
|
+
require 'cuporter/feature_parser/tag_nodes_parser'
|
5
|
+
require 'cuporter/feature_parser/node_parser'
|
2
6
|
|
3
7
|
module Cuporter
|
4
|
-
|
5
|
-
FEATURE_LINE = /^\s*(Feature:[^#]*)/u
|
6
|
-
TAG_LINE = /^\s*(@\w.+)/u
|
7
|
-
SCENARIO_LINE = /^\s*(Scenario:[^#]*)$/u
|
8
|
-
SCENARIO_OUTLINE_LINE = /^\s*(Scenario Outline:[^#]*)$/u
|
9
|
-
SCENARIO_SET_LINE = /^\s*(Scenarios:[^#]*)$/u
|
10
|
-
EXAMPLE_SET_LINE = /^\s*(Examples:[^#]*)$/u
|
11
|
-
EXAMPLE_LINE = /^\s*(\|.*\|)\s*$/u
|
12
|
-
PY_STRING_LINE = /^\s*"""\s*$/u
|
13
|
-
|
8
|
+
module FeatureParser
|
14
9
|
# adds a node to the doc for each cucumber '@' tag, populated with features and
|
15
10
|
# scenarios
|
16
11
|
def self.tag_nodes(file, report, filter, root_dir)
|
@@ -25,64 +20,5 @@ module Cuporter
|
|
25
20
|
parser.root = root_dir
|
26
21
|
parser.parse_feature
|
27
22
|
end
|
28
|
-
attr_writer :root
|
29
|
-
|
30
|
-
def initialize(file)
|
31
|
-
@file = file
|
32
|
-
@current_tags = []
|
33
|
-
@lines = File.read(@file).split(/\n/)
|
34
|
-
end
|
35
|
-
|
36
|
-
def file_relative_path
|
37
|
-
@file_relative_path ||= @file.sub(/^.*#{@root}\//,"#{@root}/")
|
38
|
-
end
|
39
|
-
|
40
|
-
def parse_feature
|
41
|
-
@open_comment_block = false
|
42
|
-
|
43
|
-
@lines.each do |line|
|
44
|
-
next if @open_comment_block && line !~ PY_STRING_LINE
|
45
|
-
|
46
|
-
case line
|
47
|
-
when PY_STRING_LINE
|
48
|
-
# toggle, to declare the multiline comment 'heredoc' open or closed
|
49
|
-
@open_comment_block = !@open_comment_block
|
50
|
-
when TAG_LINE
|
51
|
-
# may be more than one tag line
|
52
|
-
@current_tags |= clean_cuke_line($1).split(/\s+/)
|
53
|
-
when FEATURE_LINE
|
54
|
-
@feature = new_feature_node(clean_cuke_line($1), file_relative_path)
|
55
|
-
@current_tags = []
|
56
|
-
when SCENARIO_LINE
|
57
|
-
# How do we know when we have read all the lines from a "Scenario Outline:"?
|
58
|
-
# One way is when we encounter a "Scenario:"
|
59
|
-
close_scenario_outline
|
60
|
-
|
61
|
-
handle_scenario_line(clean_cuke_line($1))
|
62
|
-
@current_tags = []
|
63
|
-
when SCENARIO_OUTLINE_LINE
|
64
|
-
# ... another is when we hit a subsequent "Scenario Outline:"
|
65
|
-
close_scenario_outline
|
66
|
-
|
67
|
-
@scenario_outline = new_scenario_outline_node(clean_cuke_line($1))
|
68
|
-
@current_tags = []
|
69
|
-
when EXAMPLE_SET_LINE, SCENARIO_SET_LINE
|
70
|
-
handle_example_set_line if @example_set
|
71
|
-
|
72
|
-
@example_set = new_example_set_node(clean_cuke_line($1))
|
73
|
-
@current_tags = []
|
74
|
-
when @example_set && EXAMPLE_LINE
|
75
|
-
new_example_line(clean_cuke_line($1))
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# EOF is the final way that we know we are finished with a "Scenario Outline"
|
80
|
-
close_scenario_outline
|
81
|
-
return @feature
|
82
|
-
end
|
83
|
-
|
84
|
-
def clean_cuke_line(sub_expression)
|
85
|
-
sub_expression.strip.escape_apostrophe
|
86
|
-
end
|
87
23
|
end
|
88
24
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
begin
|
3
|
+
require 'gherkin/i18n'
|
4
|
+
rescue LoadError => ex
|
5
|
+
$gherkin_warning = %Q{Warning: Rubygems could not find Gherkin. Cuporter will use an old gherkin (2.3.3) language file.
|
6
|
+
Make sure the 'gherkin' gem is installed by checking your rvm config, your bundler config, or gem list.
|
7
|
+
|
8
|
+
"#{ex.class}: #{ex.message}"
|
9
|
+
"#{ex.backtrace.join("\n\t\t")}"
|
10
|
+
}
|
11
|
+
require 'cuporter/feature_parser/old_gherkin_yaml/i18n'
|
12
|
+
end
|
13
|
+
|
14
|
+
module Cuporter
|
15
|
+
module FeatureParser
|
16
|
+
class Language
|
17
|
+
|
18
|
+
attr_reader :feature_line, :scenario_line, :scenario_outline_line, :examples_line
|
19
|
+
|
20
|
+
def initialize(line_1)
|
21
|
+
@iso_code = 'en'
|
22
|
+
if (line_1.to_s =~ LANGUAGE_LINE)
|
23
|
+
@iso_code = $1
|
24
|
+
warn($gherkin_warning) if $gherkin_warning
|
25
|
+
end
|
26
|
+
@feature_line = pattern_for('feature')
|
27
|
+
@scenario_line = pattern_for('scenario')
|
28
|
+
@scenario_outline_line = pattern_for('scenario_outline')
|
29
|
+
@examples_line = pattern_for('examples')
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def pattern_for(keyword)
|
35
|
+
/^\s*((#{Gherkin::I18n::LANGUAGES[@iso_code][keyword]}):[^#]*)/u
|
36
|
+
end
|
37
|
+
|
38
|
+
LANGUAGE_LINE = /^\s*#\s*language:\s*([\w-]+)/u
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
|
3
|
+
module Cuporter
|
4
|
+
module FeatureParser
|
5
|
+
class NodeParser < ParserBase
|
6
|
+
|
7
|
+
# ++sub_expression++ is the paren group in the regex, dereferenced with $1 in the caller
|
8
|
+
def new_feature_node(sub_expression, file)
|
9
|
+
f = Node.new_node(:Feature, @doc, :cuke_name => sub_expression, :tags => @current_tags, :file_path => file)
|
10
|
+
f.filter = @filter
|
11
|
+
f
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_scenario_line(sub_expression)
|
15
|
+
if @filter.pass?(@current_tags | @feature.tags)
|
16
|
+
@feature.add_child(Node.new_node(:Scenario, @doc, :cuke_name => sub_expression, :tags => @current_tags))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_scenario_outline_node(sub_expression)
|
21
|
+
so = Node.new_node(:ScenarioOutline, @doc, :cuke_name => sub_expression, :tags => @current_tags)
|
22
|
+
so.filter = @filter
|
23
|
+
so
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_example_set_line
|
27
|
+
if @filter.pass?(@feature.tags | @scenario_outline.tags | @example_set.tags)
|
28
|
+
@scenario_outline.add_child @example_set
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_example_set_node(sub_expression)
|
33
|
+
es = Node.new_node(:Examples, @doc, :cuke_name => sub_expression, :tags => @current_tags)
|
34
|
+
es.filter = @filter
|
35
|
+
es
|
36
|
+
end
|
37
|
+
|
38
|
+
def new_example_line(sub_expression)
|
39
|
+
example_type = :ExampleHeader
|
40
|
+
# if the example set has a child already, then it must be the header
|
41
|
+
example_type = :Example if @example_set.has_children?
|
42
|
+
@example_set.add_child(Node.new_node(example_type, @doc, :cuke_name => sub_expression))
|
43
|
+
end
|
44
|
+
|
45
|
+
def close_scenario_outline
|
46
|
+
if @scenario_outline
|
47
|
+
if @example_set
|
48
|
+
handle_example_set_line
|
49
|
+
@example_set = nil
|
50
|
+
end
|
51
|
+
@feature.add_child(@scenario_outline) if @scenario_outline.has_children?
|
52
|
+
@scenario_outline = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(file, doc, filter)
|
57
|
+
super(file)
|
58
|
+
@filter = filter
|
59
|
+
@doc = doc
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
|
3
|
+
module Cuporter
|
4
|
+
module FeatureParser
|
5
|
+
class ParserBase
|
6
|
+
TAG_LINE = /^\s*(@\w.+)/u
|
7
|
+
EXAMPLE_LINE = /^\s*(\|.*\|)\s*$/u
|
8
|
+
PY_STRING_LINE = /^\s*"""\s*$/u
|
9
|
+
|
10
|
+
def initialize(file)
|
11
|
+
@file = file
|
12
|
+
@current_tags = []
|
13
|
+
@lines = File.read(@file).split(/\n/)
|
14
|
+
@lang = Language.new(@lines.first)
|
15
|
+
end
|
16
|
+
attr_reader :lang
|
17
|
+
attr_writer :root
|
18
|
+
|
19
|
+
def file_relative_path
|
20
|
+
@file_relative_path ||= @file.sub(/^.*#{@root}\//,"#{@root}/")
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_feature
|
24
|
+
begin
|
25
|
+
handle_lines
|
26
|
+
rescue Exception => ex
|
27
|
+
Cuporter.log_error(ex, "Error parsing file", "at line #{@line_no}:", @file,
|
28
|
+
%Q{\n\tIf this file can be run by Cucumber with no Gherkin lexing or parsing errors,
|
29
|
+
please submit a bug ticket @ github including: 1) this feature file or its contents, and 2) this stack trace.
|
30
|
+
})
|
31
|
+
end
|
32
|
+
return @feature
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_lines
|
36
|
+
@open_comment_block = false
|
37
|
+
|
38
|
+
@lines.each_with_index do |line, i|
|
39
|
+
@line_no = i + 1
|
40
|
+
next if @open_comment_block && line !~ PY_STRING_LINE
|
41
|
+
|
42
|
+
case line
|
43
|
+
when PY_STRING_LINE
|
44
|
+
# toggle, to declare the multiline comment 'heredoc' open or closed
|
45
|
+
@open_comment_block = !@open_comment_block
|
46
|
+
when TAG_LINE
|
47
|
+
# may be more than one tag line
|
48
|
+
@current_tags |= clean_cuke_line($1).split(/\s+/)
|
49
|
+
when @lang.feature_line
|
50
|
+
@feature = new_feature_node(clean_cuke_line($1), file_relative_path)
|
51
|
+
@current_tags = []
|
52
|
+
when @lang.scenario_line
|
53
|
+
# How do we know when we have read all the lines from a "Scenario Outline:"?
|
54
|
+
# One way is when we encounter a "Scenario:"
|
55
|
+
close_scenario_outline
|
56
|
+
|
57
|
+
handle_scenario_line(clean_cuke_line($1))
|
58
|
+
@current_tags = []
|
59
|
+
when @lang.scenario_outline_line
|
60
|
+
# ... another is when we hit a subsequent "Scenario Outline:"
|
61
|
+
close_scenario_outline
|
62
|
+
|
63
|
+
@scenario_outline = new_scenario_outline_node(clean_cuke_line($1))
|
64
|
+
@current_tags = []
|
65
|
+
when @lang.examples_line
|
66
|
+
handle_example_set_line if @example_set
|
67
|
+
|
68
|
+
@example_set = new_example_set_node(clean_cuke_line($1))
|
69
|
+
@current_tags = []
|
70
|
+
when @example_set && EXAMPLE_LINE
|
71
|
+
new_example_line(clean_cuke_line($1))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# EOF is the final way that we know we are finished with a "Scenario Outline"
|
76
|
+
close_scenario_outline
|
77
|
+
end
|
78
|
+
|
79
|
+
def clean_cuke_line(sub_expression)
|
80
|
+
sub_expression.strip.escape_apostrophe
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
|
2
|
+
|
3
|
+
module Cuporter
|
4
|
+
module FeatureParser
|
5
|
+
class TagNodesParser < ParserBase
|
6
|
+
|
7
|
+
# ++sub_expression++ is the paren group in the regex, dereferenced with $1 in the caller
|
8
|
+
def new_feature_node(sub_expression, file)
|
9
|
+
{:cuke_name => sub_expression, :tags => @current_tags, :file_path => file}
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_scenario_line(sub_expression)
|
13
|
+
if @filter.pass?(@feature[:tags] | @current_tags)
|
14
|
+
s = {:cuke_name => sub_expression, :tags => @current_tags}
|
15
|
+
|
16
|
+
(@feature[:tags] | s[:tags]).each do |tag|
|
17
|
+
next unless @filter.pass?([tag])
|
18
|
+
add_scenario(tag, @feature, s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def new_scenario_outline_node(sub_expression)
|
24
|
+
{:cuke_name => sub_expression, :tags => @current_tags}
|
25
|
+
end
|
26
|
+
|
27
|
+
def handle_example_set_line
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_example_set_node(sub_expression)
|
31
|
+
{:cuke_name => sub_expression.to_s.strip, :tags => @current_tags}
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_example_line(sub_expression)
|
35
|
+
context_tags = (@feature[:tags] | @scenario_outline[:tags] | @example_set[:tags])
|
36
|
+
if @filter.pass?(context_tags)
|
37
|
+
e = {:cuke_name => sub_expression}
|
38
|
+
|
39
|
+
context_tags.each do |tag|
|
40
|
+
next unless @filter.pass?([tag])
|
41
|
+
add_example(tag, @feature, @scenario_outline, @example_set, e)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close_scenario_outline
|
47
|
+
if @scenario_outline
|
48
|
+
if @example_set
|
49
|
+
@example_set = nil
|
50
|
+
end
|
51
|
+
@scenario_outline = nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def add_scenario(tag, feature, scenario)
|
55
|
+
unless ( t = @report.tag_node(tag))
|
56
|
+
t = @report.add_child(Node.new_node(:tag, @doc, 'cuke_name' => tag))
|
57
|
+
end
|
58
|
+
unless ( f = t.feature_node(feature) )
|
59
|
+
f = t.add_child(Node.new_node(:Feature, @doc, feature))
|
60
|
+
end
|
61
|
+
f.add_child(Node.new_node(:Scenario, @doc, scenario))
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_example(tag, feature, scenario_outline, example_set, example)
|
65
|
+
unless ( t = @report.tag_node(tag))
|
66
|
+
t = @report.add_child(Node.new_node(:Tag, @doc, 'cuke_name' => tag))
|
67
|
+
end
|
68
|
+
unless ( f = t.feature_node(feature) )
|
69
|
+
f = t.add_child(Node.new_node(:Feature, @doc, feature))
|
70
|
+
end
|
71
|
+
unless ( so = f.scenario_outline_node(scenario_outline) )
|
72
|
+
so = f.add_child(Node.new_node(:ScenarioOutline, @doc, scenario_outline))
|
73
|
+
end
|
74
|
+
|
75
|
+
# The first Example is an ExampleHeader, which does not get counted or
|
76
|
+
# numbered. If the ExampleSet is new, it has no children, and therefore
|
77
|
+
# this is the first and should be an ExampleHeader.
|
78
|
+
example_type = :Example
|
79
|
+
unless ( es = so.example_set_node(example_set) )
|
80
|
+
es = so.add_child(Node.new_node(:Examples, @doc, example_set))
|
81
|
+
example_type = :ExampleHeader
|
82
|
+
end
|
83
|
+
es.add_child(Node.new_node(example_type, @doc, example))
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def initialize(file, report, filter)
|
88
|
+
super(file)
|
89
|
+
@filter = filter
|
90
|
+
@report = report
|
91
|
+
@doc = report.document
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|