cucumber-gherkin 9.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.
@@ -0,0 +1,40 @@
1
+ require 'stringio'
2
+ require 'gherkin/token'
3
+ require 'gherkin/gherkin_line'
4
+
5
+ module Gherkin
6
+ # The scanner reads a gherkin doc (typically read from a .feature file) and
7
+ # creates a token for line. The tokens are passed to the parser, which outputs
8
+ # an AST (Abstract Syntax Tree).
9
+ #
10
+ # If the scanner sees a # language header, it will reconfigure itself dynamically
11
+ # to look for Gherkin keywords for the associated language. The keywords are defined
12
+ # in gherkin-languages.json.
13
+ class TokenScanner
14
+ def initialize(source_or_io)
15
+ @line_number = 0
16
+
17
+ case(source_or_io)
18
+ when String
19
+ @io = StringIO.new(source_or_io)
20
+ when StringIO, IO
21
+ @io = source_or_io
22
+ else
23
+ fail ArgumentError, "Please a pass String, StringIO or IO. I got a #{source_or_io.class}"
24
+ end
25
+ end
26
+
27
+ def read
28
+ location = {line: @line_number += 1, column: 0}
29
+ if @io.nil? || line = @io.gets
30
+ gherkin_line = line ? GherkinLine.new(line, location[:line]) : nil
31
+ Token.new(gherkin_line, location)
32
+ else
33
+ @io.close unless @io.closed? # ARGF closes the last file after final gets
34
+ @io = nil
35
+ Token.new(nil, location)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ # With thanks to @myronmarston
3
+ # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
4
+
5
+ module CaptureWarnings
6
+ def report_warnings(&block)
7
+ current_dir = Dir.pwd
8
+ warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
9
+ project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
10
+
11
+ if errors.any?
12
+ puts errors.join("\n")
13
+ end
14
+
15
+ if other_warnings.any?
16
+ puts "#{ other_warnings.count } warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
17
+ print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
18
+ end
19
+
20
+ # Until they fix https://bugs.ruby-lang.org/issues/10661
21
+ if RUBY_VERSION == "2.2.0"
22
+ project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
23
+ end
24
+
25
+ if project_warnings.any?
26
+ puts "#{ project_warnings.count } warnings detected"
27
+ print_warnings('cucumber-expressions', project_warnings)
28
+ fail "Please remove all cucumber-expressions warnings."
29
+ end
30
+
31
+ ensure_system_exit_if_required
32
+ end
33
+
34
+ def capture_error(&block)
35
+ old_stderr = STDERR.clone
36
+ pipe_r, pipe_w = IO.pipe
37
+ pipe_r.sync = true
38
+ error = String.new
39
+ reader = Thread.new do
40
+ begin
41
+ loop do
42
+ error << pipe_r.readpartial(1024)
43
+ end
44
+ rescue EOFError
45
+ end
46
+ end
47
+ STDERR.reopen(pipe_w)
48
+ block.call
49
+ ensure
50
+ capture_system_exit
51
+ STDERR.reopen(old_stderr)
52
+ pipe_w.close
53
+ reader.join
54
+ return error.split("\n")
55
+ end
56
+
57
+ def print_warnings(type, warnings)
58
+ puts
59
+ puts "-" * 30 + " #{type} warnings: " + "-" * 30
60
+ puts
61
+ puts warnings.join("\n")
62
+ puts
63
+ puts "-" * 75
64
+ puts
65
+ end
66
+
67
+ def ensure_system_exit_if_required
68
+ raise @system_exit if @system_exit
69
+ end
70
+
71
+ def capture_system_exit
72
+ @system_exit = $!
73
+ end
74
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require 'simplecov'
3
+ formatters = [ SimpleCov::Formatter::HTMLFormatter ]
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(*formatters)
6
+ SimpleCov.add_filter 'spec/'
7
+ SimpleCov.start
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+ require 'rspec'
3
+ require 'gherkin/dialect'
4
+
5
+ module Gherkin
6
+ describe Dialect do
7
+ it 'provides an interface to the keywords of a dialect' do
8
+ dialect_en = Dialect.for('en')
9
+
10
+ expect(dialect_en.feature_keywords).to eq(['Feature', 'Business Need', 'Ability'])
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ require 'rspec'
2
+ require 'gherkin'
3
+
4
+ describe Gherkin do
5
+ it "can process feature file paths" do
6
+ messages = Gherkin.from_paths(
7
+ ["testdata/good/minimal.feature"],
8
+ {include_source: true,
9
+ include_gherkin_document: true,
10
+ include_pickles: true}
11
+ ).to_a
12
+
13
+ expect(messages.length).to eq(3)
14
+ end
15
+
16
+ it "can process feature file content" do
17
+ data = File.open("testdata/good/minimal.feature", 'r:UTF-8', &:read)
18
+
19
+ messages = Gherkin.from_source(
20
+ "uri",
21
+ data,
22
+ {include_source: true,
23
+ include_gherkin_document: true,
24
+ include_pickles: true}
25
+ ).to_a
26
+
27
+ expect(messages.length).to eq(3)
28
+ end
29
+
30
+ it "can set the default dialect for the feature file content" do
31
+ data = File.open("testdata/good/i18n_no.feature", 'r:UTF-8', &:read)
32
+ data_without_language_header = data.split("\n")[1..-1].join("\n")
33
+
34
+ messages = Gherkin.from_source(
35
+ "uri",
36
+ data,
37
+ {include_source: true,
38
+ include_gherkin_document: true,
39
+ include_pickles: true,
40
+ default_dialect: "no"}
41
+ ).to_a
42
+
43
+ expect(messages.length).to eq(3)
44
+ end
45
+ end
@@ -0,0 +1,142 @@
1
+ require 'rspec'
2
+ require 'gherkin'
3
+ require 'gherkin/query'
4
+
5
+ describe Gherkin::Query do
6
+ let(:subject) { Gherkin::Query.new() }
7
+
8
+ def filter_messages_by_attribute(messages, attribute)
9
+ messages.map do |message|
10
+ return unless message.respond_to?(attribute)
11
+ message.send(attribute)
12
+ end.compact
13
+ end
14
+
15
+ def find_message_by_attribute(messages, attribute)
16
+ filter_messages_by_attribute(messages, attribute).first
17
+ end
18
+
19
+ let(:gherkin_document) { find_message_by_attribute(messages, :gherkin_document) }
20
+
21
+ let(:messages) {
22
+ Gherkin.from_source(
23
+ "some/path",
24
+ feature_content,
25
+ {
26
+ include_gherkin_document: true
27
+ }
28
+ ).to_a
29
+ }
30
+
31
+ let(:feature_content) {
32
+ """
33
+ @feature-tag
34
+ Feature: my feature
35
+
36
+ Background:
37
+ Given a passed background step
38
+
39
+ @scenario-tag
40
+ Scenario: my scenario
41
+ Given a passed step
42
+
43
+ Scenario Outline: with examples
44
+ Given a <Status> step
45
+
46
+ @example-tag
47
+ Examples:
48
+ | Status |
49
+ | passed |
50
+
51
+
52
+ Rule: this is a rule
53
+ Background:
54
+ Given the passed step in the rule background
55
+
56
+ @ruled-scenario-tag
57
+ Scenario: a ruled scenario
58
+ Given a step in the ruled scenario
59
+ """
60
+ }
61
+
62
+ before do
63
+ messages.each { |message|
64
+ subject.update(message)
65
+ }
66
+ end
67
+
68
+ context '#location' do
69
+ let(:background) { find_message_by_attribute(gherkin_document.feature.children, :background) }
70
+ let(:scenarios) { filter_messages_by_attribute(gherkin_document.feature.children, :scenario) }
71
+ let(:scenario) { scenarios.first }
72
+
73
+ it 'raises an exception when the AST node ID is unknown' do
74
+ expect { subject.location("this-id-may-not-exist-for-real") }.to raise_exception(Gherkin::AstNodeNotLocatedException)
75
+ end
76
+
77
+ it 'provides the location of a scenario' do
78
+ expect(subject.location(scenario.id)).to eq(scenario.location)
79
+ end
80
+
81
+ it 'provides the location of an examples table row' do
82
+ node = scenarios.last.examples.first.table_body.first
83
+ expect(subject.location(node.id)).to eq(node.location)
84
+ end
85
+
86
+ context 'when querying steps' do
87
+ let(:background_step) { background.steps.first }
88
+ let(:scenario_step) { scenario.steps.first }
89
+
90
+ it 'provides the location of a background step' do
91
+ expect(subject.location(background_step.id)).to eq(background_step.location)
92
+ end
93
+
94
+ it 'provides the location of a scenario step' do
95
+ expect(subject.location(scenario_step.id)).to eq(scenario_step.location)
96
+ end
97
+ end
98
+
99
+ context 'when querying tags' do
100
+ let(:feature_tag) { gherkin_document.feature.tags.first }
101
+ let(:scenario_tag) { scenario.tags.first }
102
+ let(:example_tag) { scenarios.last.examples.first.tags.first }
103
+
104
+ it 'provides the location of a feature tags' do
105
+ expect(subject.location(feature_tag.id)).to eq(feature_tag.location)
106
+ end
107
+
108
+ it 'provides the location of a scenario tags' do
109
+ expect(subject.location(scenario_tag.id)).to eq(scenario_tag.location)
110
+ end
111
+
112
+ it 'provides the location of a scenario example tags' do
113
+ expect(subject.location(example_tag.id)).to eq(example_tag.location)
114
+ end
115
+ end
116
+
117
+ context 'when children are scoped in a Rule' do
118
+ let(:rule) { find_message_by_attribute(gherkin_document.feature.children, :rule) }
119
+ let(:rule_background) { find_message_by_attribute(rule.children, :background) }
120
+ let(:rule_background_step) { rule_background.steps.first }
121
+ let(:rule_scenario) { find_message_by_attribute(rule.children, :scenario) }
122
+ let(:rule_scenario_step) { rule_scenario.steps.first }
123
+ let(:rule_scenario_tag) { rule_scenario.tags.first }
124
+
125
+ it 'provides the location of a background step' do
126
+ expect(subject.location(rule_background_step.id)).to eq(rule_background_step.location)
127
+ end
128
+
129
+ it 'provides the location of a scenario' do
130
+ expect(subject.location(rule_scenario.id)).to eq(rule_scenario.location)
131
+ end
132
+
133
+ it 'provides the location of a scenario tag' do
134
+ expect(subject.location(rule_scenario_tag.id)).to eq(rule_scenario_tag.location)
135
+ end
136
+
137
+ it 'provides the location of a scenario step' do
138
+ expect(subject.location(rule_scenario_step.id)).to eq(rule_scenario_step.location)
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,67 @@
1
+ require 'rspec'
2
+ require 'gherkin/stream/parser_message_stream'
3
+
4
+ module Gherkin
5
+ module Stream
6
+ describe ParserMessageStream do
7
+ let(:feature_content) {
8
+ "Feature: my feature\n" \
9
+ " Scenario: a scenario\n" \
10
+ " Given some context"
11
+ }
12
+
13
+ let(:source_feature) {
14
+ Cucumber::Messages::Source.new({
15
+ uri: '//whatever/uri',
16
+ data: feature_content,
17
+ media_type: 'text/x.cucumber.gherkin+plain'
18
+ })
19
+ }
20
+
21
+ let(:options) {
22
+ {
23
+ include_gherkin_document: true,
24
+ }
25
+ }
26
+
27
+ let(:gherkin_document) {
28
+ ParserMessageStream.new([], [source_feature], options).messages.first.gherkin_document
29
+ }
30
+
31
+ let(:scenario_id) { gherkin_document.feature.children.first.scenario.id }
32
+
33
+ context '#messages' do
34
+ it "raises an exception on second iteration" do
35
+ messages = ParserMessageStream.new([], [source_feature], options).messages
36
+
37
+ expect { messages.map(&:to_s) }.not_to raise_exception
38
+ expect { messages.map(&:to_s) }.to raise_exception(Gherkin::DoubleIterationException)
39
+ end
40
+ end
41
+
42
+ context 'options.id_generator' do
43
+ context 'when not set' do
44
+ it 'generates random UUIDs' do
45
+ expect(scenario_id).to match(/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/)
46
+ end
47
+ end
48
+
49
+
50
+ context 'when set' do
51
+ let(:id_generator) { double }
52
+ let(:options) {
53
+ {
54
+ include_gherkin_document: true,
55
+ id_generator: id_generator
56
+ }
57
+ }
58
+
59
+ it 'uses the generator instance to produce the IDs' do
60
+ allow(id_generator).to receive(:new_id).and_return('some-random-id')
61
+ expect(scenario_id).to eq('some-random-id')
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,18 @@
1
+ require 'rspec'
2
+ require 'gherkin/stream/subprocess_message_stream'
3
+
4
+ module Gherkin
5
+ module Stream
6
+ describe SubprocessMessageStream do
7
+ it "works" do
8
+ cucumber_messages = SubprocessMessageStream.new(
9
+ "./bin/gherkin",
10
+ ["testdata/good/minimal.feature"],
11
+ true, true, true
12
+ )
13
+ messages = cucumber_messages.messages.to_a
14
+ expect(messages.length).to eq(3)
15
+ end
16
+ end
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cucumber-gherkin
3
+ version: !ruby/object:Gem::Version
4
+ version: 9.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gáspár Nagy
8
+ - Aslak Hellesøy
9
+ - Steve Tooke
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2020-01-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: cucumber-messages
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 9.0.3
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - "~>"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 9.0.3
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '13.0'
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 13.0.1
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - "~>"
50
+ - !ruby/object:Gem::Version
51
+ version: '13.0'
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 13.0.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.9.0
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '3.9'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 3.9.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: coveralls
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.8'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 0.8.23
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '0.8'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 0.8.23
95
+ description: Gherkin parser
96
+ email: cukes@googlegroups.com
97
+ executables:
98
+ - gherkin-ruby
99
+ - gherkin
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - LICENSE
104
+ - README.md
105
+ - bin/gherkin
106
+ - bin/gherkin-ruby
107
+ - lib/gherkin.rb
108
+ - lib/gherkin/ast_builder.rb
109
+ - lib/gherkin/ast_node.rb
110
+ - lib/gherkin/dialect.rb
111
+ - lib/gherkin/errors.rb
112
+ - lib/gherkin/gherkin-languages.json
113
+ - lib/gherkin/gherkin_line.rb
114
+ - lib/gherkin/parser.rb
115
+ - lib/gherkin/pickles/compiler.rb
116
+ - lib/gherkin/query.rb
117
+ - lib/gherkin/stream/parser_message_stream.rb
118
+ - lib/gherkin/stream/subprocess_message_stream.rb
119
+ - lib/gherkin/token.rb
120
+ - lib/gherkin/token_formatter_builder.rb
121
+ - lib/gherkin/token_matcher.rb
122
+ - lib/gherkin/token_scanner.rb
123
+ - spec/capture_warnings.rb
124
+ - spec/coverage.rb
125
+ - spec/gherkin/dialect_spec.rb
126
+ - spec/gherkin/gherkin_spec.rb
127
+ - spec/gherkin/query_spec.rb
128
+ - spec/gherkin/stream/parser_message_stream_spec.rb
129
+ - spec/gherkin/stream/subprocess_message_stream_spec.rb
130
+ homepage: https://github.com/cucumber/gherkin-ruby
131
+ licenses:
132
+ - MIT
133
+ metadata:
134
+ bug_tracker_uri: https://github.com/cucumber/cucumber/issues
135
+ changelog_uri: https://github.com/cucumber/cucumber/blob/master/gherkin/CHANGELOG.md
136
+ documentation_uri: https://cucumber.io/docs/gherkin/
137
+ mailing_list_uri: https://groups.google.com/forum/#!forum/cukes
138
+ source_code_uri: https://github.com/cucumber/cucumber/blob/master/gherkin/ruby
139
+ post_install_message:
140
+ rdoc_options:
141
+ - "--charset=UTF-8"
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '2.3'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.7.6.2
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: cucumber-gherkin-9.1.0
160
+ test_files:
161
+ - spec/gherkin/dialect_spec.rb
162
+ - spec/gherkin/stream/parser_message_stream_spec.rb
163
+ - spec/gherkin/stream/subprocess_message_stream_spec.rb
164
+ - spec/gherkin/gherkin_spec.rb
165
+ - spec/gherkin/query_spec.rb
166
+ - spec/capture_warnings.rb
167
+ - spec/coverage.rb