rspec-hive 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0ecaa7596db283e59f0ea63fbb677942e714d09
4
- data.tar.gz: ae43c8734de7c85b0551454534fc1e339a74d2f5
3
+ metadata.gz: 0b75898c0b7364fe12b80f91a36da04a54c5bab6
4
+ data.tar.gz: 86e7fcbbb5a50fc536a0954ddc27fd4cb90ef915
5
5
  SHA512:
6
- metadata.gz: 906bd8f828ba76a4646c535cee8679d60f3acf23714e8686c62789ee770d754f95f216930758d504bf57964a40c127e189b58dc17e03c674f12a283f181e83cf
7
- data.tar.gz: 6cf54197ee350b05235eb08869226dd2b26c3e63f83764ad17356c5ef842379f8d5b5b2d4a8aafe63d212d91b02c91b78d64bcd0bb729c5bb37daf8a8da05084
6
+ metadata.gz: da919d5129641e77e15c5bfeed2bef2396e3d02dd3eaa93ef61dae7af099323d6a9106a8b9b8ac02644035ab39588a88c6cbabbe40f7f53832e961d499a7244f
7
+ data.tar.gz: 2ea4738a1f9bb1d84426ed4873a33bfb2b8f2480a1b557fbb73e2b5fe8821fbb266defffe8fab57c3114558d6c10c3e0a8f9ee3d11fc0fd0c5138de884c4748c
@@ -2,28 +2,104 @@ require 'rspec/matchers'
2
2
 
3
3
  RSpec::Matchers.define :match_result_set do |expected|
4
4
  match do |actual|
5
- return false if expected.size != actual.size
5
+ @diffable_actual = []
6
6
 
7
- expected.each.with_index.all? do |expected_row, i|
7
+ @actual = actual.clone
8
+
9
+ expected.map.with_index do |expected_row, i|
8
10
  if expected_row.respond_to?(:each_pair)
9
11
  if @partial_match
10
- selected_actual_values = actual[i].values_at(*expected_row.keys)
11
- values_match?(expected_row.values, selected_actual_values)
12
+ result_set_match?(
13
+ actual[i], expected_row,
14
+ expected_transformer: ->(e) { e.values },
15
+ actual_transformer: ->(candidate) { candidate.values_at(*expected_row.keys) },
16
+ diffable_transformer: ->(candidate) { candidate.select { |k, _v| expected_row.keys.include?(k) } }
17
+ )
12
18
  else
13
- values_match?(expected_row, actual[i])
19
+ result_set_match?(actual[i], expected_row)
14
20
  end
15
21
  elsif expected_row.respond_to?(:each)
16
22
  raise ArgumentError, "Can't use partially matcher with Arrays" if @partial_match
17
- values_match?(expected_row, actual[i].values)
23
+ result_set_match?(
24
+ actual[i], expected_row,
25
+ actual_transformer: ->(candidate) { candidate.values }
26
+ )
18
27
  else
19
28
  raise ArgumentError, 'Unknown type'
20
29
  end
21
- end
30
+ end.all? && expected.size == actual.size
22
31
  end
23
32
 
24
33
  chain :partially do
25
34
  @partial_match = true
26
35
  end
27
36
 
28
- diffable
37
+ chain :unordered do
38
+ @unordered = true
39
+ end
40
+
41
+ def result_set_match?(
42
+ actual, expected_row,
43
+ expected_transformer: ->(expected) { expected },
44
+ actual_transformer: ->(candidate) { candidate },
45
+ diffable_transformer: actual_transformer
46
+ )
47
+ if @unordered
48
+ unordered_result_set_match?(expected_row, expected_transformer, actual_transformer, diffable_transformer)
49
+ else
50
+ ordered_result_set_match?(actual, expected_row, expected_transformer, actual_transformer, diffable_transformer)
51
+ end
52
+ end
53
+
54
+ def unordered_result_set_match?(expected_row, expected_transformer, actual_transformer, diffable_transformer)
55
+ found_index = @actual.find_index do |candidate|
56
+ values_match?(expected_transformer.call(expected_row), actual_transformer.call(candidate))
57
+ end
58
+ return false unless found_index
59
+ found = @actual[found_index]
60
+ @actual.delete_at(found_index)
61
+ @diffable_actual << diffable_transformer.call(found)
62
+ true
63
+ end
64
+
65
+ def ordered_result_set_match?(actual, expected_row, expected_transformer, actual_transformer, diffable_transformer)
66
+ @diffable_actual << diffable_transformer.call(actual)
67
+ values_match?(expected_transformer.call(expected_row), actual_transformer.call(actual))
68
+ end
69
+
70
+ failure_message do |actual|
71
+ "expected #{actual} to match result set #{expected}\n#{diff_message(expected)}"
72
+ end
73
+
74
+ failure_message_when_negated do |actual|
75
+ "expected #{actual} not to match result set #{expected}, but did\n#{diff_message(expected)}"
76
+ end
77
+
78
+ def diff_message(expected)
79
+ "Diff: #{differ.diff_as_object(@diffable_actual, expected)}"
80
+ end
81
+
82
+ def differ
83
+ RSpec::Support::Differ.new(
84
+ object_preparer: ->(object) { surface_descriptions_in(object) },
85
+ color: RSpec::Matchers.configuration.color?
86
+ )
87
+ end
88
+
89
+ # Copied and adapted from RSpec::Matchers::Composable
90
+ # rubocop:disable Style/CaseEquality
91
+ def surface_descriptions_in(item)
92
+ if RSpec::Matchers.is_a_describable_matcher?(item)
93
+ RSpec::Matchers::Composable::DescribableItem.new(item)
94
+ elsif Hash === item
95
+ Hash[surface_descriptions_in(item.to_a.sort)]
96
+ elsif Struct === item || unreadable_io?(item)
97
+ RSpec::Support::ObjectFormatter.format(item)
98
+ elsif should_enumerate?(item)
99
+ item.map { |subitem| surface_descriptions_in(subitem) }
100
+ else
101
+ item
102
+ end
103
+ end
104
+ # rubocop:enable Style/CaseEquality
29
105
  end
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module Hive
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
@@ -8,9 +8,24 @@ RSpec.describe 'match_result_set' do
8
8
  let(:paul) { {first_name: 'Paul', last_name: 'McCartney', age: 73} }
9
9
 
10
10
  let(:full_match) { expect(actual_rows).to match_result_set(expected_rows) }
11
+ let(:unordered_match) { expect(actual_rows).to match_result_set(expected_rows).unordered }
11
12
  let(:partial_match) { expect(actual_rows).to match_result_set(expected_rows).partially }
13
+ let(:partial_unordered_match) { expect(actual_rows).to match_result_set(expected_rows).partially.unordered }
14
+
12
15
  let(:full_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows) }
16
+ let(:unordered_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows).unordered }
13
17
  let(:partial_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows).partially }
18
+ let(:partial_unordered_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows).partially.unordered }
19
+
20
+ let(:partial_match_raises_error) do
21
+ error_message = "Can't use partially matcher with Arrays"
22
+ aggregate_failures do
23
+ expect { partial_match }.to raise_error(ArgumentError, error_message)
24
+ expect { partial_match_fails }.to raise_error(ArgumentError, error_message)
25
+ expect { partial_unordered_match }.to raise_error(ArgumentError, error_message)
26
+ expect { partial_unordered_match_fails }.to raise_error(ArgumentError, error_message)
27
+ end
28
+ end
14
29
 
15
30
  context 'when the expected set has only one row' do
16
31
  context 'but the actual set has more rows' do
@@ -20,14 +35,17 @@ RSpec.describe 'match_result_set' do
20
35
  let(:expected_rows) { [john.values] }
21
36
 
22
37
  specify { full_match_fails }
23
- specify { partial_match_fails }
38
+ specify { unordered_match_fails }
39
+ specify { partial_match_raises_error }
24
40
  end
25
41
 
26
42
  context 'when the row is given as a hash' do
27
43
  let(:expected_rows) { [john] }
28
44
 
29
45
  specify { full_match_fails }
46
+ specify { unordered_match_fails }
30
47
  specify { partial_match_fails }
48
+ specify { partial_unordered_match_fails }
31
49
  end
32
50
  end
33
51
 
@@ -39,24 +57,32 @@ RSpec.describe 'match_result_set' do
39
57
  let(:expected_rows) { [john.values << 'yoko'] }
40
58
 
41
59
  specify { full_match_fails }
60
+ specify { unordered_match_fails }
61
+ specify { partial_match_raises_error }
42
62
  end
43
63
 
44
64
  context 'when the actual and expected have are different' do
45
65
  let(:expected_rows) { [paul.values] }
46
66
 
47
67
  specify { full_match_fails }
68
+ specify { unordered_match_fails }
69
+ specify { partial_match_raises_error }
48
70
  end
49
71
 
50
72
  context 'when the actual and expected rows are equal' do
51
73
  let(:expected_rows) { [john.values] }
52
74
 
53
75
  specify { full_match }
76
+ specify { unordered_match }
77
+ specify { partial_match_raises_error }
54
78
  end
55
79
 
56
80
  context 'when the actual and expected rows are equal with rspec matchers' do
57
81
  let(:expected_rows) { [[a_string_matching('John'), a_string_matching(/lennon/i), 40]] }
58
82
 
59
83
  specify { full_match }
84
+ specify { unordered_match }
85
+ specify { partial_match_raises_error }
60
86
  end
61
87
  end
62
88
 
@@ -65,28 +91,106 @@ RSpec.describe 'match_result_set' do
65
91
  let(:expected_rows) { [john.dup.tap { |j| j[:ono] = 'yoko' }] }
66
92
 
67
93
  specify { full_match_fails }
94
+ specify { unordered_match_fails }
68
95
  specify { partial_match_fails }
96
+ specify { partial_unordered_match_fails }
69
97
  end
70
98
 
71
99
  context 'when the actual and expected have are different' do
72
100
  let(:expected_rows) { [john.dup.tap { |j| j[:first_name] = 'yoko' }] }
73
101
 
74
102
  specify { full_match_fails }
103
+ specify { unordered_match_fails }
75
104
  specify { partial_match_fails }
105
+ specify { partial_unordered_match_fails }
76
106
  end
77
107
 
78
108
  context 'when the actual and expected rows are equal' do
79
109
  let(:expected_rows) { [john] }
80
110
 
81
111
  specify { full_match }
112
+ specify { unordered_match }
82
113
  specify { partial_match }
114
+ specify { partial_unordered_match }
83
115
  end
84
116
 
85
117
  context 'when matching a subset of columns' do
86
118
  let(:expected_rows) { [{first_name: john[:first_name]}] }
87
119
 
88
120
  specify { full_match_fails }
121
+ specify { unordered_match_fails }
89
122
  specify { partial_match }
123
+ specify { partial_unordered_match }
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'when the expected set has multiple rows' do
130
+ let(:ringo) { {first_name: 'Richard', last_name: 'Starkey', age: -75} }
131
+
132
+ context 'and the actual set has the same number of rows' do
133
+ let(:actual_rows) { [ringo, paul, john] }
134
+
135
+ context 'when the row is given as an array' do
136
+ context 'when rows are returned in order' do
137
+ let(:expected_rows) { [ringo.values, paul.values, john.values] }
138
+
139
+ specify { full_match }
140
+ specify { unordered_match }
141
+ specify { partial_match_raises_error }
142
+ end
143
+
144
+ context 'when rows are returned in different order' do
145
+ let(:expected_rows) { [paul.values, john.values, ringo.values] }
146
+
147
+ specify { full_match_fails }
148
+ specify { unordered_match }
149
+ specify { partial_match_raises_error }
150
+ end
151
+ end
152
+
153
+ context 'when the row is given as a hash' do
154
+ context 'when matching all columns' do
155
+ context 'when rows are returned in order' do
156
+ let(:expected_rows) { [ringo, paul, john] }
157
+
158
+ specify { full_match }
159
+ specify { unordered_match }
160
+ specify { partial_match }
161
+ specify { partial_unordered_match }
162
+ end
163
+
164
+ context 'when rows are returned in different order' do
165
+ let(:expected_rows) { [paul, john, ringo] }
166
+
167
+ specify { full_match_fails }
168
+ specify { unordered_match }
169
+ specify { partial_match_fails }
170
+ specify { partial_unordered_match }
171
+ end
172
+ end
173
+
174
+ context 'when matching a subset of columns' do
175
+ let(:expected_rows) { members.map { |member| {age: member[:age]} } }
176
+
177
+ context 'when rows are returned in order' do
178
+ let(:members) { [ringo, paul, john] }
179
+
180
+ specify { full_match_fails }
181
+ specify { unordered_match_fails }
182
+ specify { partial_match }
183
+ specify { partial_unordered_match }
184
+ end
185
+
186
+ context 'when rows are returned in different order' do
187
+ let(:members) { [john, paul, ringo] }
188
+
189
+ specify { full_match_fails }
190
+ specify { unordered_match_fails }
191
+ specify { partial_match_fails }
192
+ specify { partial_unordered_match }
193
+ end
90
194
  end
91
195
  end
92
196
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-hive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wojtek Mielczarek
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-05-09 00:00:00.000000000 Z
12
+ date: 2016-05-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake