cucumber-compatibility-kit 13.0.0 → 13.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.
@@ -1,57 +1 @@
1
- # frozen_string_literal: true
2
-
3
- require 'shared_examples'
4
-
5
- module Cucumber::CompatibilityKit
6
- class << self
7
- def all_examples
8
- gherkin_examples + markdown_examples
9
- end
10
-
11
- def gherkin_examples
12
- Dir
13
- .entries(examples_path)
14
- .select do |file|
15
- folder = File.join(examples_path, file)
16
-
17
- file != '.' && file != '..' &&
18
- File.directory?(folder) &&
19
- is_gherkin_example?(folder)
20
- end
21
- end
22
-
23
- def markdown_examples
24
- Dir
25
- .entries(examples_path)
26
- .select do |file|
27
- folder = File.join(examples_path, file)
28
-
29
- file != '.' && file != '..' &&
30
- File.directory?(folder) &&
31
- is_markdown_example?(folder)
32
- end
33
- end
34
-
35
- def examples_path
36
- File.expand_path("#{File.dirname(__FILE__)}/../features/")
37
- end
38
-
39
- def example_path(example_name)
40
- path = File.join(examples_path, example_name)
41
-
42
- return path if File.directory?(path)
43
-
44
- raise ArgumentError.new
45
- end
46
-
47
- private
48
-
49
- def is_gherkin_example?(example_folder)
50
- Dir.entries(example_folder).select { |file| File.extname(file) == '.feature' }.count > 0
51
- end
52
-
53
- def is_markdown_example?(example_folder)
54
- Dir.entries(example_folder).select { |file| File.extname(file) == '.md' }.count > 0
55
- end
56
- end
57
- end
1
+ require_relative 'cucumber/cucumber-compatibility-kit'
data/lib/keys_checker.rb CHANGED
@@ -1,64 +1 @@
1
- # frozen_string_literal: true
2
-
3
- module CCK
4
- class KeysChecker
5
- def self.compare(detected, expected)
6
- new(detected, expected).compare
7
- end
8
-
9
- attr_reader :detected, :expected
10
-
11
- def initialize(detected, expected)
12
- @detected = detected
13
- @expected = expected
14
- end
15
-
16
- def compare
17
- return [] if identical_keys?
18
-
19
- errors << "Detected extra keys in message #{message_name}: #{extra_keys}" if extra_keys.any?
20
- errors << "Missing keys in message #{message_name}: #{missing_keys}" if missing_keys.any?
21
- errors
22
- rescue StandardError => e
23
- ["Unexpected error: #{e.message}"]
24
- end
25
-
26
- private
27
-
28
- def detected_keys
29
- @detected_keys ||= ordered_uniq_hash_keys(detected)
30
- end
31
-
32
- def expected_keys
33
- @expected_keys ||= ordered_uniq_hash_keys(expected)
34
- end
35
-
36
- def identical_keys?
37
- detected_keys == expected_keys
38
- end
39
-
40
- def missing_keys
41
- (expected_keys - detected_keys).reject { |key| meta_message? && key == :ci }
42
- end
43
-
44
- def extra_keys
45
- (detected_keys - expected_keys).reject { |key| meta_message? && key == :ci }
46
- end
47
-
48
- def meta_message?
49
- detected.instance_of?(Cucumber::Messages::Meta)
50
- end
51
-
52
- def message_name
53
- detected.class.name
54
- end
55
-
56
- def ordered_uniq_hash_keys(object)
57
- object.to_h(reject_nil_values: true).keys.sort
58
- end
59
-
60
- def errors
61
- @errors ||= []
62
- end
63
- end
64
- end
1
+ require_relative 'cck/keys_checker'
@@ -1,88 +1 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'keys_checker'
4
-
5
- module CCK
6
- class MessagesComparator
7
- def initialize(validator, found, expected)
8
- @all_errors = []
9
- @compared = []
10
- @validator = validator
11
-
12
- compare(found, expected)
13
- end
14
-
15
- def errors
16
- @all_errors.flatten
17
- end
18
-
19
- def debug
20
- # puts 'Compared the following type of message:'
21
- # puts @compared.uniq.map { |m| " - #{m}" }.join("\n")
22
- # puts ''
23
- puts errors.uniq.join("\n")
24
- end
25
-
26
- private
27
-
28
- def compare(found, expected)
29
- found_by_type = messages_by_type(found)
30
- expected_by_type = messages_by_type(expected)
31
-
32
- found_by_type.keys.each do |type|
33
- compare_list(found_by_type[type], expected_by_type[type])
34
- rescue StandardError => e
35
- @all_errors << "Error whild comparing #{type}: #{e.message}"
36
- end
37
- end
38
-
39
- def messages_by_type(messages)
40
- by_type = Hash.new { |h, k| h[k] = [] }
41
- messages.each do |msg|
42
- by_type[message_type(msg)] << remove_envelope(msg)
43
- end
44
- by_type
45
- end
46
-
47
- def message_type(message)
48
- message.to_h.each do |key, value|
49
- return key unless value.nil?
50
- end
51
- end
52
-
53
- def remove_envelope(message)
54
- message.send(message_type(message))
55
- end
56
-
57
- def compare_list(found, expected)
58
- found.each_with_index do |message, index|
59
- compare_message(message, expected[index])
60
- end
61
- end
62
-
63
- def compare_message(found, expected)
64
- return unless found.is_a?(Cucumber::Messages::Message)
65
- return if found.is_a?(Cucumber::Messages::GherkinDocument)
66
- return if found.is_a?(Cucumber::Messages::Pickle)
67
- return if found.is_a?(Cucumber::Messages::Timestamp) && expected.is_a?(Cucumber::Messages::Timestamp)
68
- return if found.is_a?(Cucumber::Messages::Duration) && expected.is_a?(Cucumber::Messages::Duration)
69
- return if ENV['CI'] && found.is_a?(Cucumber::Messages::Ci) && expected.nil?
70
-
71
- @compared << found.class.name
72
- @all_errors << @validator.compare(found, expected)
73
- compare_sub_messages(found, expected)
74
- end
75
-
76
- def compare_sub_messages(found, expected)
77
- return unless expected.respond_to? :to_h
78
- expected.to_h.keys.each do |key|
79
- value = expected.send(key)
80
- if value.is_a?(Array)
81
- compare_list(found.send(key), value)
82
- else
83
- compare_message(found.send(key), value)
84
- end
85
- end
86
- end
87
- end
88
- end
1
+ require_relative 'cck/messages_comparator'
@@ -8,6 +8,8 @@ require 'messages_comparator'
8
8
  require 'keys_checker'
9
9
 
10
10
  RSpec.shared_examples 'cucumber compatibility kit' do
11
+ include CCK::Helpers
12
+
11
13
  # Note: to use those examples, you need to define:
12
14
  # let(:example) { } # the name of the example to test
13
15
  # let(:messages) { } # the messages to validate
@@ -24,45 +26,20 @@ RSpec.shared_examples 'cucumber compatibility kit' do
24
26
  let(:generated_messages_types) { parsed_generated.map { |msg| message_type(msg) } }
25
27
 
26
28
  it 'generates valid message types' do
27
- debug_lists(original_messages_types, generated_messages_types)
28
29
  expect(generated_messages_types).to contain_exactly(*original_messages_types)
29
30
  end
30
31
 
31
32
  it 'generates valid message structure' do
32
33
  comparator = CCK::MessagesComparator.new(CCK::KeysChecker, parsed_generated, parsed_original)
33
- comparator.debug if ENV['VERBOSE']
34
34
 
35
- if comparator.errors.any?
36
- fail "There were comparison errors: #{comparator.errors}"
37
- end
35
+ expect(comparator.errors).to be_empty, "There were comparison errors: #{comparator.errors}"
38
36
  end
39
- end
40
37
 
41
- def parse_ndjson_file(path)
42
- parse_ndjson(File.read(path))
43
- end
44
-
45
- def parse_ndjson(ndjson)
46
- Cucumber::Messages::NdjsonToMessageEnumerator.new(ndjson)
47
- end
48
-
49
- def message_type(message)
50
- # TODO: This is duplicate code - from messages_comparator:45 - It should live in a common helper methods module
51
- message.to_h.each do |key, value|
52
- return key unless value.nil?
38
+ def parse_ndjson_file(path)
39
+ parse_ndjson(File.read(path))
53
40
  end
54
- end
55
-
56
- def debug_lists(expected, obtained)
57
- return unless ENV['VERBOSE']
58
- return if expected.sort == obtained.sort
59
-
60
- to_read = expected.count > obtained.count ? expected : obtained
61
- columnize = "\t\t\t\t | \t\t\t\t"
62
41
 
63
- puts " | Expected #{columnize} GOT"
64
- to_read.each_with_index do |_, index|
65
- ok = expected[index] == obtained[index] ? 'v' : 'x'
66
- puts "[#{ok}] | #{expected[index]} #{columnize} #{obtained[index]}"
42
+ def parse_ndjson(ndjson)
43
+ Cucumber::Messages::NdjsonToMessageEnumerator.new(ndjson)
67
44
  end
68
45
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require 'cucumber/messages'
5
+ require_relative '../../lib/keys_checker'
6
+
7
+ describe CCK::KeysChecker do
8
+ describe '#compare' do
9
+ let(:expected_values) { Cucumber::Messages::Attachment.new(url: 'https://foo.com', file_name: 'file.extension') }
10
+ let(:erroneous_values) { Cucumber::Messages::Attachment.new(source: '1', test_step_id: '123') }
11
+ let(:wrong_values) { Cucumber::Messages::Attachment.new(url: 'https://otherfoo.com', file_name: 'file.other') }
12
+
13
+ it 'finds missing keys' do
14
+ expect(described_class.compare(erroneous_values, expected_values)).to include(
15
+ 'Missing keys in message Cucumber::Messages::Attachment: [:file_name, :url]'
16
+ )
17
+ end
18
+
19
+ it 'finds extra keys' do
20
+ expect(described_class.compare(erroneous_values, expected_values)).to include(
21
+ 'Detected extra keys in message Cucumber::Messages::Attachment: [:source, :test_step_id]'
22
+ )
23
+ end
24
+
25
+ it 'finds extra and missing keys' do
26
+ expect(described_class.compare(erroneous_values, expected_values)).to contain_exactly(
27
+ 'Missing keys in message Cucumber::Messages::Attachment: [:file_name, :url]',
28
+ 'Detected extra keys in message Cucumber::Messages::Attachment: [:source, :test_step_id]'
29
+ )
30
+ end
31
+
32
+ it 'does not care about the values' do
33
+ expect(described_class.compare(expected_values, wrong_values)).to be_empty
34
+ end
35
+
36
+ context 'when default values are omitted' do
37
+ let(:default_set) { Cucumber::Messages::Duration.new(seconds: 0, nanos: 12) }
38
+ let(:default_not_set) { Cucumber::Messages::Duration.new(nanos: 12) }
39
+
40
+ it 'does not raise an exception' do
41
+ expect(described_class.compare(default_set, default_not_set)).to be_empty
42
+ end
43
+ end
44
+
45
+ context 'when executed as part of a CI' do
46
+ before { allow(ENV).to receive(:[]).with('CI').and_return(true) }
47
+
48
+ it 'ignores actual CI related messages' do
49
+ detected = Cucumber::Messages::Meta.new(ci: Cucumber::Messages::Ci.new(name: 'Some CI'))
50
+ expected = Cucumber::Messages::Meta.new
51
+
52
+ expect(described_class.compare(detected, expected)).to be_empty
53
+ end
54
+ end
55
+
56
+ context 'when an unexpected error occurs' do
57
+ it 'does not raise error' do
58
+ expect { described_class.compare(nil, nil) }.not_to raise_error
59
+ end
60
+
61
+ it 'returns the error' do
62
+ expect(described_class.compare(nil, nil))
63
+ .to eq(['Unexpected error: wrong number of arguments (given 1, expected 0)'])
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require 'cucumber/messages'
5
+ require_relative '../../lib/messages_comparator'
6
+
7
+ describe CCK::MessagesComparator do
8
+ context 'when executed as part of a CI' do
9
+ before { allow(ENV).to receive(:[]).with('CI').and_return(true) }
10
+
11
+ let(:ci_message) { Cucumber::Messages::Ci.new(name: 'Some CI') }
12
+ let(:blank_meta_message) { Cucumber::Messages::Meta.new }
13
+ let(:filled_meta_message) { Cucumber::Messages::Meta.new(ci: ci_message) }
14
+ let(:ci_message_envelope) { Cucumber::Messages::Envelope.new(meta: filled_meta_message) }
15
+ let(:meta_message_envelope) { Cucumber::Messages::Envelope.new(meta: blank_meta_message) }
16
+
17
+ it 'ignores any detected CI messages' do
18
+ comparator = described_class.new(CCK::KeysChecker, [ci_message_envelope], [meta_message_envelope])
19
+
20
+ expect(comparator.errors).to be_empty
21
+ end
22
+
23
+ it 'ignores any expected CI messages' do
24
+ comparator = described_class.new(CCK::KeysChecker, [meta_message_envelope], [ci_message_envelope])
25
+
26
+ expect(comparator.errors).to be_empty
27
+ end
28
+ end
29
+ end
@@ -3,8 +3,8 @@
3
3
  require 'cucumber-compatibility-kit'
4
4
 
5
5
  describe Cucumber::CompatibilityKit do
6
- let(:features_path) { File.expand_path("#{File.dirname(__FILE__)}/../features") }
7
- let(:gherkin_examples) {
6
+ let(:features_path) { File.expand_path("#{File.dirname(__FILE__)}/../../features") }
7
+ let(:gherkin_examples) do
8
8
  [
9
9
  'attachments',
10
10
  'cdata',
@@ -21,47 +21,38 @@ describe Cucumber::CompatibilityKit do
21
21
  'undefined',
22
22
  'unknown-parameter-type'
23
23
  ]
24
- }
25
- let(:markdown_examples) {
26
- [
27
- 'markdown'
28
- ]
29
- }
24
+ end
25
+ let(:markdown_examples) { ['markdown'] }
30
26
 
31
27
  describe '#examples_path' do
32
28
  it 'returns the path of the features folder' do
33
- expect(described_class.examples_path)
34
- .to eq(features_path)
29
+ expect(described_class.examples_path).to eq(features_path)
35
30
  end
36
31
  end
37
32
 
38
33
  describe '#example_path' do
39
34
  context 'with an existing example' do
40
35
  it 'returns the path of the folder of the example' do
41
- expect(described_class.example_path('hooks'))
42
- .to eq("#{features_path}/hooks")
36
+ expect(described_class.example_path('hooks')).to eq("#{features_path}/hooks")
43
37
  end
44
38
  end
45
39
 
46
- context 'with an unexisting example' do
40
+ context 'with an non-existent example' do
47
41
  it 'raises ArgumentError' do
48
- expect { described_class.example_path('should-not-exists') }
49
- .to raise_error(ArgumentError)
42
+ expect { described_class.example_path('should-not-exists') }.to raise_error(ArgumentError)
50
43
  end
51
44
  end
52
45
  end
53
46
 
54
47
  describe '#gherkin_examples' do
55
48
  it 'returns the list of gherkin examples' do
56
- expect(described_class.gherkin_examples)
57
- .to match_array(gherkin_examples)
49
+ expect(described_class.gherkin_examples).to match_array(gherkin_examples)
58
50
  end
59
51
  end
60
52
 
61
53
  describe '#markdown_examples' do
62
54
  it 'returns the list of markdown examples' do
63
- expect(described_class.markdown_examples)
64
- .to match_array(markdown_examples)
55
+ expect(described_class.markdown_examples).to match_array(markdown_examples)
65
56
  end
66
57
  end
67
58
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber-compatibility-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 13.0.0
4
+ version: 13.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aurélien Reeves
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-10-09 00:00:00.000000000 Z
14
+ date: 2023-10-11 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: cucumber-messages
@@ -178,14 +178,17 @@ files:
178
178
  - features/unknown-parameter-type/unknown-parameter-type.feature
179
179
  - features/unknown-parameter-type/unknown-parameter-type.feature.ndjson
180
180
  - features/unknown-parameter-type/unknown-parameter-type.feature.rb
181
+ - lib/cck/helpers.rb
182
+ - lib/cck/keys_checker.rb
183
+ - lib/cck/messages_comparator.rb
181
184
  - lib/cucumber-compatibility-kit.rb
185
+ - lib/cucumber/cucumber-compatibility-kit.rb
182
186
  - lib/keys_checker.rb
183
187
  - lib/messages_comparator.rb
184
188
  - lib/shared_examples.rb
185
- - spec/capture_warnings.rb
186
- - spec/cucumber-compatibility-kit_spec.rb
187
- - spec/keys_checker_spec.rb
188
- - spec/messages_comparator_spec.rb
189
+ - spec/cck/keys_checker_spec.rb
190
+ - spec/cck/messages_comparator_spec.rb
191
+ - spec/cucumber/cucumber-compatibility-kit_spec.rb
189
192
  homepage: https://github.com/cucumber/compatibility-kit
190
193
  licenses:
191
194
  - MIT
@@ -214,9 +217,8 @@ requirements: []
214
217
  rubygems_version: 3.4.10
215
218
  signing_key:
216
219
  specification_version: 4
217
- summary: cucumber-compatibility-kit-13.0.0
220
+ summary: cucumber-compatibility-kit-13.0.1
218
221
  test_files:
219
- - spec/capture_warnings.rb
220
- - spec/cucumber-compatibility-kit_spec.rb
221
- - spec/keys_checker_spec.rb
222
- - spec/messages_comparator_spec.rb
222
+ - spec/cck/keys_checker_spec.rb
223
+ - spec/cck/messages_comparator_spec.rb
224
+ - spec/cucumber/cucumber-compatibility-kit_spec.rb
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # With thanks to @myronmarston
4
- # https://github.com/vcr/vcr/blob/master/spec/capture_warnings.rb
5
-
6
- module CaptureWarnings
7
- def report_warnings(&block)
8
- current_dir = Dir.pwd
9
- warnings, errors = capture_error(&block).partition { |line| line.include?('warning') }
10
- project_warnings, other_warnings = warnings.uniq.partition { |line| line.include?(current_dir) }
11
-
12
- if errors.any?
13
- puts errors.join("\n")
14
- end
15
-
16
- if other_warnings.any?
17
- puts "#{ other_warnings.count } warnings detected, set VIEW_OTHER_WARNINGS=true to see them."
18
- print_warnings('other', other_warnings) if ENV['VIEW_OTHER_WARNINGS']
19
- end
20
-
21
- # Until they fix https://bugs.ruby-lang.org/issues/10661
22
- if RUBY_VERSION == '2.2.0'
23
- project_warnings = project_warnings.reject { |w| w =~ /warning: possible reference to past scope/ }
24
- end
25
-
26
- if project_warnings.any?
27
- puts "#{ project_warnings.count } warnings detected"
28
- print_warnings('cucumber-expressions', project_warnings)
29
- fail 'Please remove all cucumber-expressions warnings.'
30
- end
31
-
32
- ensure_system_exit_if_required
33
- end
34
-
35
- def capture_error(&block)
36
- old_stderr = STDERR.clone
37
- pipe_r, pipe_w = IO.pipe
38
- pipe_r.sync = true
39
- error = String.new
40
- reader = Thread.new do
41
- begin
42
- loop do
43
- error << pipe_r.readpartial(1024)
44
- end
45
- rescue EOFError
46
- end
47
- end
48
- STDERR.reopen(pipe_w)
49
- block.call
50
- ensure
51
- capture_system_exit
52
- STDERR.reopen(old_stderr)
53
- pipe_w.close
54
- reader.join
55
- return error.split("\n")
56
- end
57
-
58
- def print_warnings(type, warnings)
59
- puts
60
- puts '-' * 30 + " #{type} warnings: " + '-' * 30
61
- puts
62
- puts warnings.join("\n")
63
- puts
64
- puts '-' * 75
65
- puts
66
- end
67
-
68
- def ensure_system_exit_if_required
69
- raise @system_exit if @system_exit
70
- end
71
-
72
- def capture_system_exit
73
- @system_exit = $ERROR_INFO
74
- end
75
- end
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rspec'
4
- require 'cucumber/messages'
5
- require_relative '../lib/keys_checker'
6
-
7
- describe CCK::KeysChecker do
8
- let(:subject) { described_class }
9
-
10
- describe '#compare' do
11
- let(:complete) do
12
- Cucumber::Messages::PickleStepArgument.new(
13
- doc_string: '1',
14
- data_table: '12'
15
- )
16
- end
17
-
18
- let(:missing_data_table) do
19
- Cucumber::Messages::PickleStepArgument.new(doc_string: '1')
20
- end
21
-
22
- let(:missing_doc_string) do
23
- Cucumber::Messages::PickleStepArgument.new(data_table: '12')
24
- end
25
-
26
- let(:wrong_values) do
27
- Cucumber::Messages::PickleStepArgument.new(
28
- doc_string: '123',
29
- data_table: '456'
30
- )
31
- end
32
-
33
- it 'finds missing key' do
34
- expect(subject.compare(missing_data_table, complete)).to eq(
35
- ['Missing keys in message Cucumber::Messages::PickleStepArgument: [:data_table]']
36
- )
37
- end
38
-
39
- it 'finds extra keys' do
40
- expect(subject.compare(complete, missing_doc_string)).to eq(
41
- ['Detected extra keys in message Cucumber::Messages::PickleStepArgument: [:doc_string]']
42
- )
43
- end
44
-
45
- it 'finds extra and missing' do
46
- expect(subject.compare(missing_doc_string, missing_data_table)).to contain_exactly(
47
- 'Missing keys in message Cucumber::Messages::PickleStepArgument: [:doc_string]',
48
- 'Detected extra keys in message Cucumber::Messages::PickleStepArgument: [:data_table]'
49
- )
50
- end
51
-
52
- it 'does not care about the values' do
53
- expect(subject.compare(complete, wrong_values)).to be_empty
54
- end
55
-
56
- context 'when default values are omitted' do
57
- let(:default_set) do
58
- Cucumber::Messages::Duration.new(
59
- seconds: 0,
60
- nanos: 12
61
- )
62
- end
63
-
64
- let(:default_not_set) do
65
- Cucumber::Messages::Duration.new(nanos: 12)
66
- end
67
-
68
- it 'does not raise an exception' do
69
- expect(subject.compare(default_set, default_not_set)).to be_empty
70
- end
71
- end
72
-
73
- context 'when executed as part of a CI' do
74
- before { allow(ENV).to receive(:[]).with('CI').and_return(true) }
75
-
76
- it 'ignores actual CI related messages' do
77
- detected = Cucumber::Messages::Meta.new(ci: Cucumber::Messages::Ci.new(name: 'Some CI'))
78
- expected = Cucumber::Messages::Meta.new
79
-
80
- expect(subject.compare(detected, expected)).to be_empty
81
- end
82
- end
83
-
84
- context 'when an unexpected error occurs' do
85
- it 'does not raise error' do
86
- expect { subject.compare(nil, nil) }.not_to raise_error
87
- end
88
-
89
- it 'returns the error' do
90
- expect(subject.compare(nil, nil))
91
- .to eq(['Unexpected error: wrong number of arguments (given 1, expected 0)'])
92
- end
93
- end
94
- end
95
- end