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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.md +9 -0
  9. data/Rakefile +24 -0
  10. data/cucumber-core.gemspec +32 -0
  11. data/lib/cucumber/core.rb +37 -0
  12. data/lib/cucumber/core/ast.rb +13 -0
  13. data/lib/cucumber/core/ast/background.rb +33 -0
  14. data/lib/cucumber/core/ast/comment.rb +17 -0
  15. data/lib/cucumber/core/ast/data_table.rb +326 -0
  16. data/lib/cucumber/core/ast/describes_itself.rb +16 -0
  17. data/lib/cucumber/core/ast/doc_string.rb +83 -0
  18. data/lib/cucumber/core/ast/empty_background.rb +12 -0
  19. data/lib/cucumber/core/ast/examples_table.rb +95 -0
  20. data/lib/cucumber/core/ast/feature.rb +62 -0
  21. data/lib/cucumber/core/ast/location.rb +140 -0
  22. data/lib/cucumber/core/ast/multiline_argument.rb +33 -0
  23. data/lib/cucumber/core/ast/names.rb +19 -0
  24. data/lib/cucumber/core/ast/outline_step.rb +51 -0
  25. data/lib/cucumber/core/ast/scenario.rb +43 -0
  26. data/lib/cucumber/core/ast/scenario_outline.rb +44 -0
  27. data/lib/cucumber/core/ast/step.rb +38 -0
  28. data/lib/cucumber/core/ast/tag.rb +14 -0
  29. data/lib/cucumber/core/compiler.rb +136 -0
  30. data/lib/cucumber/core/gherkin/ast_builder.rb +315 -0
  31. data/lib/cucumber/core/gherkin/document.rb +20 -0
  32. data/lib/cucumber/core/gherkin/parser.rb +45 -0
  33. data/lib/cucumber/core/gherkin/writer.rb +220 -0
  34. data/lib/cucumber/core/gherkin/writer/helpers.rb +178 -0
  35. data/lib/cucumber/core/platform.rb +30 -0
  36. data/lib/cucumber/core/test/case.rb +143 -0
  37. data/lib/cucumber/core/test/filters.rb +48 -0
  38. data/lib/cucumber/core/test/filters/tag_filter.rb +110 -0
  39. data/lib/cucumber/core/test/hook_compiler.rb +109 -0
  40. data/lib/cucumber/core/test/mapper.rb +56 -0
  41. data/lib/cucumber/core/test/mapping.rb +67 -0
  42. data/lib/cucumber/core/test/result.rb +191 -0
  43. data/lib/cucumber/core/test/runner.rb +149 -0
  44. data/lib/cucumber/core/test/step.rb +69 -0
  45. data/lib/cucumber/core/test/timer.rb +31 -0
  46. data/lib/cucumber/core/version.rb +9 -0
  47. data/lib/cucumber/initializer.rb +18 -0
  48. data/spec/capture_warnings.rb +68 -0
  49. data/spec/coverage.rb +10 -0
  50. data/spec/cucumber/core/ast/data_table_spec.rb +139 -0
  51. data/spec/cucumber/core/ast/doc_string_spec.rb +77 -0
  52. data/spec/cucumber/core/ast/examples_table_spec.rb +87 -0
  53. data/spec/cucumber/core/ast/location_spec.rb +105 -0
  54. data/spec/cucumber/core/ast/outline_step_spec.rb +77 -0
  55. data/spec/cucumber/core/ast/step_spec.rb +44 -0
  56. data/spec/cucumber/core/compiler_spec.rb +249 -0
  57. data/spec/cucumber/core/gherkin/parser_spec.rb +182 -0
  58. data/spec/cucumber/core/gherkin/writer_spec.rb +332 -0
  59. data/spec/cucumber/core/test/case_spec.rb +416 -0
  60. data/spec/cucumber/core/test/hook_compiler_spec.rb +78 -0
  61. data/spec/cucumber/core/test/mapper_spec.rb +68 -0
  62. data/spec/cucumber/core/test/mapping_spec.rb +103 -0
  63. data/spec/cucumber/core/test/result_spec.rb +178 -0
  64. data/spec/cucumber/core/test/runner_spec.rb +265 -0
  65. data/spec/cucumber/core/test/step_spec.rb +58 -0
  66. data/spec/cucumber/core/test/timer_spec.rb +13 -0
  67. data/spec/cucumber/core_spec.rb +419 -0
  68. data/spec/cucumber/initializer_spec.rb +49 -0
  69. 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,12 @@
1
+ module Cucumber
2
+ module Core
3
+ module Ast
4
+ class EmptyBackground
5
+ def describe_to(*)
6
+ self
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -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