cucumber-compatibility-kit 13.0.0 → 13.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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