cucumber-core 0.1.0
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +9 -0
- data/Rakefile +24 -0
- data/cucumber-core.gemspec +32 -0
- data/lib/cucumber/core.rb +37 -0
- data/lib/cucumber/core/ast.rb +13 -0
- data/lib/cucumber/core/ast/background.rb +33 -0
- data/lib/cucumber/core/ast/comment.rb +17 -0
- data/lib/cucumber/core/ast/data_table.rb +326 -0
- data/lib/cucumber/core/ast/describes_itself.rb +16 -0
- data/lib/cucumber/core/ast/doc_string.rb +83 -0
- data/lib/cucumber/core/ast/empty_background.rb +12 -0
- data/lib/cucumber/core/ast/examples_table.rb +95 -0
- data/lib/cucumber/core/ast/feature.rb +62 -0
- data/lib/cucumber/core/ast/location.rb +140 -0
- data/lib/cucumber/core/ast/multiline_argument.rb +33 -0
- data/lib/cucumber/core/ast/names.rb +19 -0
- data/lib/cucumber/core/ast/outline_step.rb +51 -0
- data/lib/cucumber/core/ast/scenario.rb +43 -0
- data/lib/cucumber/core/ast/scenario_outline.rb +44 -0
- data/lib/cucumber/core/ast/step.rb +38 -0
- data/lib/cucumber/core/ast/tag.rb +14 -0
- data/lib/cucumber/core/compiler.rb +136 -0
- data/lib/cucumber/core/gherkin/ast_builder.rb +315 -0
- data/lib/cucumber/core/gherkin/document.rb +20 -0
- data/lib/cucumber/core/gherkin/parser.rb +45 -0
- data/lib/cucumber/core/gherkin/writer.rb +220 -0
- data/lib/cucumber/core/gherkin/writer/helpers.rb +178 -0
- data/lib/cucumber/core/platform.rb +30 -0
- data/lib/cucumber/core/test/case.rb +143 -0
- data/lib/cucumber/core/test/filters.rb +48 -0
- data/lib/cucumber/core/test/filters/tag_filter.rb +110 -0
- data/lib/cucumber/core/test/hook_compiler.rb +109 -0
- data/lib/cucumber/core/test/mapper.rb +56 -0
- data/lib/cucumber/core/test/mapping.rb +67 -0
- data/lib/cucumber/core/test/result.rb +191 -0
- data/lib/cucumber/core/test/runner.rb +149 -0
- data/lib/cucumber/core/test/step.rb +69 -0
- data/lib/cucumber/core/test/timer.rb +31 -0
- data/lib/cucumber/core/version.rb +9 -0
- data/lib/cucumber/initializer.rb +18 -0
- data/spec/capture_warnings.rb +68 -0
- data/spec/coverage.rb +10 -0
- data/spec/cucumber/core/ast/data_table_spec.rb +139 -0
- data/spec/cucumber/core/ast/doc_string_spec.rb +77 -0
- data/spec/cucumber/core/ast/examples_table_spec.rb +87 -0
- data/spec/cucumber/core/ast/location_spec.rb +105 -0
- data/spec/cucumber/core/ast/outline_step_spec.rb +77 -0
- data/spec/cucumber/core/ast/step_spec.rb +44 -0
- data/spec/cucumber/core/compiler_spec.rb +249 -0
- data/spec/cucumber/core/gherkin/parser_spec.rb +182 -0
- data/spec/cucumber/core/gherkin/writer_spec.rb +332 -0
- data/spec/cucumber/core/test/case_spec.rb +416 -0
- data/spec/cucumber/core/test/hook_compiler_spec.rb +78 -0
- data/spec/cucumber/core/test/mapper_spec.rb +68 -0
- data/spec/cucumber/core/test/mapping_spec.rb +103 -0
- data/spec/cucumber/core/test/result_spec.rb +178 -0
- data/spec/cucumber/core/test/runner_spec.rb +265 -0
- data/spec/cucumber/core/test/step_spec.rb +58 -0
- data/spec/cucumber/core/test/timer_spec.rb +13 -0
- data/spec/cucumber/core_spec.rb +419 -0
- data/spec/cucumber/initializer_spec.rb +49 -0
- metadata +221 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Core
|
3
|
+
module Ast
|
4
|
+
module DescribesItself
|
5
|
+
def describe_to(visitor, *args)
|
6
|
+
visitor.send(description_for_visitors, self, *args) do |child_visitor=visitor|
|
7
|
+
children.each do |child|
|
8
|
+
child.describe_to(child_visitor, *args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'cucumber/core/ast/describes_itself'
|
2
|
+
module Cucumber
|
3
|
+
module Core
|
4
|
+
module Ast
|
5
|
+
# Represents an inline argument in a step. Example:
|
6
|
+
#
|
7
|
+
# Given the message
|
8
|
+
# """
|
9
|
+
# I like
|
10
|
+
# Cucumber sandwich
|
11
|
+
# """
|
12
|
+
#
|
13
|
+
# The text between the pair of <tt>"""</tt> is stored inside a DocString,
|
14
|
+
# which is yielded to the StepDefinition block as the last argument.
|
15
|
+
#
|
16
|
+
# The StepDefinition can then access the String via the #to_s method. In the
|
17
|
+
# example above, that would return: <tt>"I like\nCucumber sandwich"</tt>
|
18
|
+
#
|
19
|
+
# Note how the indentation from the source is stripped away.
|
20
|
+
#
|
21
|
+
class DocString
|
22
|
+
include HasLocation
|
23
|
+
include DescribesItself
|
24
|
+
attr_accessor :file
|
25
|
+
|
26
|
+
def self.default_arg_name
|
27
|
+
"string"
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :content_type, :content
|
31
|
+
|
32
|
+
def initialize(string, content_type, location)
|
33
|
+
@content = string
|
34
|
+
@content_type = content_type
|
35
|
+
@location = location
|
36
|
+
end
|
37
|
+
|
38
|
+
def encoding
|
39
|
+
@content.encoding
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_str
|
43
|
+
@content
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
to_str
|
48
|
+
end
|
49
|
+
|
50
|
+
def gsub(*args)
|
51
|
+
@content.gsub(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def map
|
55
|
+
raise ArgumentError, "No block given" unless block_given?
|
56
|
+
new_content = yield content
|
57
|
+
self.class.new(new_content, content_type, location)
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_step_definition_arg
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def ==(other)
|
65
|
+
if other.respond_to?(:content_type)
|
66
|
+
return false unless content_type == other.content_type
|
67
|
+
end
|
68
|
+
if other.respond_to?(:to_str)
|
69
|
+
return content == other.to_str
|
70
|
+
end
|
71
|
+
raise ArgumentError, "Can't compare a #{self.class.name} with a #{other.class.name}"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def description_for_visitors
|
77
|
+
:doc_string
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'cucumber/initializer'
|
2
|
+
require 'cucumber/core/ast/describes_itself'
|
3
|
+
require 'cucumber/core/ast/location'
|
4
|
+
|
5
|
+
module Cucumber
|
6
|
+
module Core
|
7
|
+
module Ast
|
8
|
+
|
9
|
+
class ExamplesTable
|
10
|
+
include HasLocation
|
11
|
+
include DescribesItself
|
12
|
+
|
13
|
+
attr_reader :header, :keyword, :name, :tags, :comments
|
14
|
+
|
15
|
+
include Cucumber.initializer(
|
16
|
+
:location, :comments, :tags, :keyword, :name, :description, :header, :example_rows
|
17
|
+
)
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def description_for_visitors
|
22
|
+
:examples_table
|
23
|
+
end
|
24
|
+
|
25
|
+
def children
|
26
|
+
@example_rows
|
27
|
+
end
|
28
|
+
|
29
|
+
class Header
|
30
|
+
include HasLocation
|
31
|
+
|
32
|
+
def initialize(cells, location)
|
33
|
+
@cells = cells
|
34
|
+
@location = location
|
35
|
+
end
|
36
|
+
|
37
|
+
def values
|
38
|
+
@cells
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_row(row_cells, number, location)
|
42
|
+
Row.new(Hash[@cells.zip(row_cells)], number, location)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Row
|
47
|
+
include DescribesItself
|
48
|
+
include HasLocation
|
49
|
+
|
50
|
+
attr_reader :number
|
51
|
+
|
52
|
+
def initialize(data, number, location)
|
53
|
+
raise ArgumentError, data.to_s unless data.is_a?(Hash)
|
54
|
+
@data = data
|
55
|
+
@number = number
|
56
|
+
@location = location
|
57
|
+
end
|
58
|
+
|
59
|
+
def ==(other)
|
60
|
+
return false unless other.class == self.class
|
61
|
+
other.number == number &&
|
62
|
+
other.location == location &&
|
63
|
+
other.data == data
|
64
|
+
end
|
65
|
+
|
66
|
+
def values
|
67
|
+
@data.values
|
68
|
+
end
|
69
|
+
|
70
|
+
def expand(string)
|
71
|
+
result = string.dup
|
72
|
+
@data.each do |key, value|
|
73
|
+
result.gsub!("<#{key}>", value.to_s)
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def inspect
|
79
|
+
"#{self.class}: #{@data.inspect}"
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
attr_reader :data
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def description_for_visitors
|
89
|
+
:examples_table_row
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'cucumber/initializer'
|
2
|
+
require 'cucumber/core/ast/describes_itself'
|
3
|
+
require 'cucumber/core/ast/names'
|
4
|
+
require 'cucumber/core/ast/location'
|
5
|
+
|
6
|
+
module Cucumber
|
7
|
+
module Core
|
8
|
+
module Ast
|
9
|
+
# Represents the root node of a parsed feature.
|
10
|
+
class Feature #:nodoc:
|
11
|
+
include Names
|
12
|
+
include HasLocation
|
13
|
+
include DescribesItself
|
14
|
+
|
15
|
+
attr_accessor :language
|
16
|
+
attr_reader :feature_elements
|
17
|
+
attr_reader :comments, :background, :tags, :keyword, :location, :title
|
18
|
+
|
19
|
+
include Cucumber.initializer(:location, :background, :comments, :tags, :keyword, :title, :description, :feature_elements)
|
20
|
+
def initialize(*)
|
21
|
+
super
|
22
|
+
feature_elements.each { |e| e.feature = self }
|
23
|
+
end
|
24
|
+
|
25
|
+
def gherkin_statement(statement=nil)
|
26
|
+
@gherkin_statement ||= statement
|
27
|
+
end
|
28
|
+
|
29
|
+
def children
|
30
|
+
[background] + @feature_elements
|
31
|
+
end
|
32
|
+
|
33
|
+
def short_name
|
34
|
+
first_line = name.split(/\n/)[0]
|
35
|
+
if first_line =~ /#{language.keywords('feature')}:(.*)/
|
36
|
+
$1.strip
|
37
|
+
else
|
38
|
+
first_line
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_sexp
|
43
|
+
sexp = [:feature, file, name]
|
44
|
+
comment = @comment.to_sexp
|
45
|
+
sexp += [comment] if comment
|
46
|
+
tags = @tags.to_sexp
|
47
|
+
sexp += tags if tags.any?
|
48
|
+
sexp += [@background.to_sexp] if @background
|
49
|
+
sexp += @feature_elements.map{|fe| fe.to_sexp}
|
50
|
+
sexp
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def description_for_visitors
|
56
|
+
:feature
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Cucumber
|
3
|
+
module Core
|
4
|
+
module Ast
|
5
|
+
class Location < Struct.new(:filepath, :lines)
|
6
|
+
WILDCARD = :*
|
7
|
+
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def_delegator :lines, :include?
|
11
|
+
def_delegator :lines, :line
|
12
|
+
def_delegator :filepath, :same_as?
|
13
|
+
def_delegator :filepath, :filename, :file
|
14
|
+
|
15
|
+
def initialize(filepath, lines=WILDCARD)
|
16
|
+
filepath || raise(ArgumentError, "file is mandatory")
|
17
|
+
lines || raise(ArgumentError, "line is mandatory")
|
18
|
+
super(FilePath.new(filepath), Lines.new(lines))
|
19
|
+
end
|
20
|
+
|
21
|
+
def match?(other)
|
22
|
+
other.same_as?(filepath) && other.include?(lines)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
[filepath.to_s, lines.to_s].reject { |v| v == WILDCARD.to_s }.join(":")
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_str
|
30
|
+
to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_line(new_line)
|
34
|
+
Location.new(filepath.filename, new_line)
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
"<#{self.class}: #{to_s}>"
|
39
|
+
end
|
40
|
+
|
41
|
+
class FilePath < Struct.new(:filename)
|
42
|
+
def same_as?(other)
|
43
|
+
filename == other.filename
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
filename
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'set'
|
52
|
+
class Lines
|
53
|
+
attr_reader :line
|
54
|
+
def initialize(line)
|
55
|
+
if Cucumber::JRUBY && line.is_a?(::Java::GherkinFormatterModel::Range)
|
56
|
+
line = Range.new(line.first, line.last)
|
57
|
+
end
|
58
|
+
@line = line
|
59
|
+
@data = Array(line).to_set
|
60
|
+
end
|
61
|
+
|
62
|
+
def include?(other)
|
63
|
+
return true if (data|other.data).include?(WILDCARD)
|
64
|
+
other.data.subset?(data) || data.subset?(other.data)
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
boundary.join('..')
|
69
|
+
end
|
70
|
+
|
71
|
+
def ==(other)
|
72
|
+
other.data == data
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
attr_reader :data
|
78
|
+
|
79
|
+
def boundary
|
80
|
+
first_and_last(value).uniq
|
81
|
+
end
|
82
|
+
|
83
|
+
def at_index(idx)
|
84
|
+
data.to_a[idx]
|
85
|
+
end
|
86
|
+
|
87
|
+
def value
|
88
|
+
method :at_index
|
89
|
+
end
|
90
|
+
|
91
|
+
def first_and_last(something)
|
92
|
+
[0, -1].map(&something)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module HasLocation
|
98
|
+
def file_colon_line
|
99
|
+
location.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
def file
|
103
|
+
location.file
|
104
|
+
end
|
105
|
+
|
106
|
+
def line
|
107
|
+
location.line
|
108
|
+
end
|
109
|
+
|
110
|
+
def location
|
111
|
+
raise('Please set @location in the constructor') unless defined?(@location)
|
112
|
+
@location
|
113
|
+
end
|
114
|
+
|
115
|
+
def match_locations?(queried_locations)
|
116
|
+
return true if attributes.any? { |node| node.match_locations? queried_locations }
|
117
|
+
queried_locations.any? { |queried_location| queried_location.match? location }
|
118
|
+
end
|
119
|
+
|
120
|
+
def attributes
|
121
|
+
# TODO: Remove compact when we have a null multiline arg object
|
122
|
+
[tags, comments, multiline_arg].flatten.compact
|
123
|
+
end
|
124
|
+
|
125
|
+
def tags
|
126
|
+
# will be overriden by nodes that actually have tags
|
127
|
+
[]
|
128
|
+
end
|
129
|
+
|
130
|
+
def comments
|
131
|
+
[]
|
132
|
+
end
|
133
|
+
|
134
|
+
def multiline_arg
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'gherkin/rubify'
|
2
|
+
|
3
|
+
module Cucumber
|
4
|
+
module Core
|
5
|
+
module Ast
|
6
|
+
module MultilineArgument
|
7
|
+
|
8
|
+
class << self
|
9
|
+
include Gherkin::Rubify
|
10
|
+
|
11
|
+
def from(argument, parent_location)
|
12
|
+
return unless argument
|
13
|
+
return argument if argument.respond_to?(:to_step_definition_arg)
|
14
|
+
|
15
|
+
argument = rubify(argument)
|
16
|
+
case argument
|
17
|
+
when String
|
18
|
+
Ast::DocString.new(argument, 'text/plain', parent_location)
|
19
|
+
when ::Gherkin::Formatter::Model::DocString
|
20
|
+
Ast::DocString.new(argument.value, argument.content_type, parent_location.on_line(argument.line_range))
|
21
|
+
when Array
|
22
|
+
location = parent_location.on_line(argument.first.line..argument.last.line)
|
23
|
+
Ast::DataTable.new(argument.map{|row| row.cells}, location)
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Don't know how to convert #{argument.inspect} into a MultilineArgument"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|