rspec-twirp 0.1.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
  SHA256:
3
- metadata.gz: c2f0ca51df29824ba1c1f2d1944ca94119501b3ec6366d09144f077bd99c92f2
4
- data.tar.gz: 513bdae144ce76ecec652954cff14d3f8467037f6ec706ab67181be0ac036d61
3
+ metadata.gz: 7a9027f86450d9e045705304d1d8e590b51a733269938e83ca5ae098a90018d4
4
+ data.tar.gz: dca42845c93b814878cf24842320583ddf6dbce3b0d266cd897a58500cf31a31
5
5
  SHA512:
6
- metadata.gz: 4a4ebdce6d3d96826eca31484d1d4c22dc5b9e07fb109bea659315c5cfc7265f497f8d0a0bb498115e654ee139b232d6c6eb74bfd6da03a325a44411e636486c
7
- data.tar.gz: 4342593db5f6e34db3fb0c3829a04ff1b8bc5806960e6b0efb144f650c38b80b08559b7f1f1a616a1c36712e2fb4a1c9cb963e457accd9451ac1ad3a6314096f
6
+ metadata.gz: 98d362457d71269cf64bffa1fe0b1fe00e173fe68df88e12cf0af20aa1030d518e031415d005050209b070095c36a6eac454e1bdba740661a090ce3be90cfa15
7
+ data.tar.gz: a0923b782b8568198fb267cd1e3bc6192bb032b0a7e746be478a4e8d66317ccc81652487f6f3b442847c6c2946b2e398f25b60682c0cc6b1c794c556837d0978
@@ -1,30 +1,59 @@
1
1
  RSpec::Matchers.define :be_a_twirp_error do |*matchers, **meta_matcher|
2
2
  match do |actual|
3
- @fail_msg = "Expected #{actual} to be a Twirp::Error, found #{actual.class}"
3
+ @fail_msg = "Expected `#{actual}` to be a Twirp::Error, found: #{actual.class}"
4
4
  return false unless actual.is_a?(Twirp::Error)
5
5
 
6
- matchers.each do |matcher|
6
+ @expected = {}
7
+ @actual = {}
8
+
9
+ matched = matchers.all? do |matcher|
7
10
  case matcher
8
11
  when Symbol
9
12
  # match code
13
+ @expected[:code] = matcher
14
+ @actual[:code] = actual.code
10
15
 
11
16
  unless Twirp::Error.valid_code?(matcher)
12
17
  raise ArgumentError, "invalid error code: #{matcher.inspect}"
13
18
  end
14
19
 
15
- @fail_msg = "Expected #{actual} to have code: #{matcher.inspect}, found #{actual.code}"
16
- return false unless actual.code == matcher
20
+ @fail_msg = "Expected #{actual} to have code `#{matcher.inspect}`, found: #{actual.code.inspect}"
21
+ actual.code == matcher
22
+ when Integer
23
+ # match http status code
24
+
25
+ if code = Twirp::ERROR_CODES_TO_HTTP_STATUS.key(matcher)
26
+ @expected[:code] = code
27
+ @actual[:code] = actual.code
28
+
29
+ actual_status = Twirp::ERROR_CODES_TO_HTTP_STATUS[actual.code]
30
+
31
+ @fail_msg = "Expected #{actual} to have status #{matcher} / #{code.inspect}, found: #{actual_status} / #{actual.code.inspect}"
32
+ actual.code == code
33
+ else
34
+ raise ArgumentError, "invalid error status code: #{matcher}"
35
+ end
36
+ when Twirp::Error
37
+ # match instance
38
+ @expected = matcher.to_h
39
+ @actual = actual.to_h
40
+
41
+ @fail_msg = "Expected #{actual} to equal #{matcher}"
42
+ values_match?(matcher.to_h, actual.to_h)
17
43
  else
18
44
  # match msg
45
+ @expected[:msg] = matcher
46
+ @actual[:msg] = actual.msg
19
47
 
20
- @fail_msg = "Expected #{actual} to have msg: #{matcher.inspect}, found #{actual.msg}"
21
- return false unless values_match?(matcher, actual.msg)
48
+ @fail_msg = "Expected #{actual} to have msg #{matcher.inspect}, found: #{actual.msg.inspect}"
49
+ values_match?(matcher, actual.msg)
22
50
  end
23
51
  end
24
52
 
25
53
  # match meta
26
54
  unless meta_matcher.empty?
27
- @cur_match = { meta: meta_matcher }
55
+ @expected[:meta] = meta_matcher
56
+ @actual[:meta] = actual.meta
28
57
 
29
58
  # sanity check...values must be Strings or Regexp
30
59
  discrete_attrs = meta_matcher.transform_values do |attr|
@@ -33,10 +62,10 @@ RSpec::Matchers.define :be_a_twirp_error do |*matchers, **meta_matcher|
33
62
  actual.send(:validate_meta, discrete_attrs)
34
63
 
35
64
  @fail_msg = "Expected #{actual} to have meta: #{meta_matcher.inspect}, found #{actual.meta}"
36
- return false unless values_match?(meta_matcher, actual.meta)
65
+ matched &= values_match?(meta_matcher, actual.meta)
37
66
  end
38
67
 
39
- true
68
+ matched
40
69
  end
41
70
 
42
71
  description do
@@ -44,6 +73,12 @@ RSpec::Matchers.define :be_a_twirp_error do |*matchers, **meta_matcher|
44
73
  end
45
74
 
46
75
  failure_message { @fail_msg }
76
+
77
+ diffable
78
+
79
+ def expected
80
+ @expected
81
+ end
47
82
  end
48
83
 
49
84
  RSpec::Matchers.alias_matcher :a_twirp_error, :be_a_twirp_error
@@ -0,0 +1,2 @@
1
+ RSpec::Matchers.alias_matcher :be_a_twirp_message, :be_a_protobuf
2
+ RSpec::Matchers.alias_matcher :a_twirp_message, :a_protobuf
@@ -1,34 +1,36 @@
1
- RSpec::Matchers.define :be_a_twirp_response do |type = nil, **attrs|
2
- match do |actual|
3
- # ensure type is a valid twirp response type
4
- if type && !(type < Google::Protobuf::MessageExts)
5
- raise ArgumentError, "Expected `type` to be a Twirp response, found: #{type}"
6
- end
7
-
8
- @fail_msg = "Expected a Twirp response, found #{actual}"
9
- return false unless actual.is_a?(Google::Protobuf::MessageExts)
1
+ RSpec::Matchers.define :be_a_twirp_response do |**attrs|
2
+ chain :with_error do |*matchers, **meta_matchers|
3
+ # code, msg, meta
4
+ @with_error = [ matchers, meta_matchers ]
5
+ end
10
6
 
11
- # match expected response type
12
- @fail_msg = "Expected a Twirp response of type #{type}, found #{actual.class}"
13
- return false if type && actual.class != type
7
+ match do |actual|
8
+ @fail_msg = "Expected a Twirp::ClientResp, found #{actual}"
9
+ return false unless actual.is_a?(Twirp::ClientResp)
14
10
 
15
- return true if attrs.empty?
11
+ if @with_error
12
+ unless attrs.empty?
13
+ raise ArgumentError, "match data attributes or error, but not both"
14
+ end
16
15
 
17
- RSpec::Twirp.validate_types(attrs, actual.class)
16
+ @fail_msg = "Expected #{actual} to have an error, but found none"
17
+ return false unless actual.error
18
18
 
19
- # match attributes which are present
20
- attrs.each do |attr_name, expected_attr|
21
- actual_attr = actual.send(attr_name)
19
+ matchers, meta_matchers = @with_error
20
+ expect(actual.error).to be_a_twirp_error(*matchers, **meta_matchers)
21
+ else
22
+ @fail_msg = "Expected #{actual} to have data, but found none"
23
+ return false unless actual.data
22
24
 
23
- @fail_msg = "Expected #{actual} to have #{attr_name}: #{expected_attr.inspect}, found #{actual_attr}"
24
- return false unless values_match?(expected_attr, actual_attr)
25
+ expect(actual.data).to be_a_twirp_message(**attrs)
25
26
  end
26
-
27
- true
27
+ rescue RSpec::Expectations::ExpectationNotMetError => err
28
+ @fail_msg = err.message
29
+ false
28
30
  end
29
31
 
30
32
  description do
31
- type ? "a #{type} Twirp response" : "a Twirp response"
33
+ "a Twirp response"
32
34
  end
33
35
 
34
36
  failure_message { @fail_msg }
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module Twirp
3
- VERSION = "0.1.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
data/lib/rspec/twirp.rb CHANGED
@@ -1,32 +1,9 @@
1
- require "rspec/expectations"
2
- require "rspec/twirp/client_response_matcher"
1
+ require "google/protobuf"
2
+ require "rspec"
3
+ require "rspec/protobuf"
4
+ require "twirp"
5
+
3
6
  require "rspec/twirp/error_matcher"
4
- require "rspec/twirp/request_matcher"
7
+ require "rspec/twirp/message_matcher"
5
8
  require "rspec/twirp/response_matcher"
6
-
7
- module RSpec
8
- module Twirp
9
- extend self
10
-
11
- def validate_types(attrs, klass)
12
- # sanity check type and names of attrs by constructing an actual
13
- # proto object
14
- discrete_attrs = attrs.transform_values do |attr|
15
- case attr
16
- when Regexp
17
- attr.inspect
18
- when Range
19
- attr.first
20
- when RSpec::Matchers::BuiltIn::BaseMatcher
21
- nil
22
- else
23
- attr
24
- end
25
- end.compact
26
-
27
- klass.new(**discrete_attrs)
28
- rescue Google::Protobuf::TypeError => e
29
- raise TypeError, e.message
30
- end
31
- end
32
- end
9
+ require "rspec/twirp/version"
data/spec/error_spec.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  describe "be_a_twirp_error" do
2
- subject { Twirp::Error.new(code, msg, meta) }
2
+ subject(:error) { Twirp::Error.new(code, msg, meta) }
3
3
 
4
4
  let(:code) { :not_found }
5
5
  let(:msg) { "Not Found" }
@@ -7,16 +7,54 @@ describe "be_a_twirp_error" do
7
7
 
8
8
  it { is_expected.to be_a_twirp_error }
9
9
 
10
+ it "is composable" do
11
+ expect(e: error).to include(e: a_twirp_error)
12
+ end
13
+
10
14
  it "catches type mismatches" do
11
15
  expect {
12
16
  expect(Object).to be_a_twirp_error
13
17
  }.to fail_with /to be a Twirp::Error/
14
18
  end
15
19
 
20
+ describe "status matches" do
21
+ it { is_expected.to be_a_twirp_error(404) }
22
+
23
+ it "catches mismatches" do
24
+ expect {
25
+ is_expected.to be_a_twirp_error(400)
26
+ }.to fail_including(
27
+ "to have status 400",
28
+ "found: 404",
29
+
30
+ # diff
31
+ "-:code => :invalid_argument,",
32
+ "+:code => :not_found,",
33
+ )
34
+ end
35
+
36
+ it "catches erroneous codes" do
37
+ expect {
38
+ is_expected.to be_a_twirp_error(123)
39
+ }.to raise_error(ArgumentError, /invalid error/)
40
+ end
41
+ end
42
+
16
43
  describe "code matches" do
17
44
  it { is_expected.to be_a_twirp_error(:not_found) }
18
45
 
19
- it { expect { is_expected.to be_a_twirp_error(:unknown) }.to fail }
46
+ it "catches mismatches" do
47
+ expect {
48
+ is_expected.to be_a_twirp_error(:unknown)
49
+ }.to fail_including(
50
+ "to have code `:unknown`",
51
+ "found: :not_found",
52
+
53
+ # diff
54
+ "-:code => :unknown,",
55
+ "+:code => :not_found,",
56
+ )
57
+ end
20
58
 
21
59
  it "catches erroneous codes" do
22
60
  expect {
@@ -35,11 +73,22 @@ describe "be_a_twirp_error" do
35
73
  it "catches mismatches" do
36
74
  expect {
37
75
  is_expected.to be_a_twirp_error("Not")
38
- }.to fail_with /to have msg: "Not"/
76
+ }.to fail_including(
77
+ 'to have msg "Not"',
78
+ 'found: "Not Found"',
79
+
80
+ # diff
81
+ '-:msg => "Not",',
82
+ '+:msg => "Not Found",',
83
+ )
39
84
 
40
85
  expect {
41
86
  is_expected.to be_a_twirp_error(/Nope/)
42
- }.to fail_with /to have msg: \/Nope\//
87
+ }.to fail_including(
88
+ # diff
89
+ '-:msg => /Nope/,',
90
+ '+:msg => "Not Found",',
91
+ )
43
92
  end
44
93
  end
45
94
 
@@ -50,7 +99,13 @@ describe "be_a_twirp_error" do
50
99
  it "catches mismatches" do
51
100
  expect {
52
101
  is_expected.to be_a_twirp_error(is_meta: "false")
53
- }.to fail_with /to have meta.*is_meta/
102
+ }.to fail_including(
103
+ "to have meta",
104
+
105
+ # diff
106
+ '-:meta => {:is_meta=>"false"},',
107
+ '+:meta => {:is_meta=>"true"},',
108
+ )
54
109
 
55
110
  expect {
56
111
  is_expected.to be_a_twirp_error(not_meta: "")
@@ -64,6 +119,24 @@ describe "be_a_twirp_error" do
64
119
  end
65
120
  end
66
121
 
122
+ describe "instance matches" do
123
+ it "matches similar looking instances" do
124
+ error = Twirp::Error.new(code, msg, meta)
125
+ is_expected.to be_a_twirp_error(error)
126
+ end
127
+
128
+ it "catches mismatches" do
129
+ # no meta
130
+ expect {
131
+ is_expected.to be_a_twirp_error(Twirp::Error.not_found("Not Found"))
132
+ }.to fail
133
+
134
+ expect {
135
+ is_expected.to be_a_twirp_error(Twirp::Error.internal("boom"))
136
+ }.to fail
137
+ end
138
+ end
139
+
67
140
  describe "multi matches" do
68
141
  it { is_expected.to be_a_twirp_error(:not_found, "Not Found") }
69
142
  it { is_expected.to be_a_twirp_error(:not_found, /Not/) }
@@ -0,0 +1,69 @@
1
+ describe "be_a_twirp_message" do
2
+ subject(:request) { HelloRequest.new(**attrs) }
3
+
4
+ let(:attrs) { {} }
5
+
6
+ it { is_expected.to be_a_twirp_message }
7
+
8
+ it "works with responses also" do
9
+ expect(HelloResponse.new).to be_a_twirp_message
10
+ end
11
+
12
+ it "supports compound matchers" do
13
+ expect([ request ]).to include(a_twirp_message)
14
+ end
15
+
16
+ it "does not match non-twirp subjects" do
17
+ expect(Object).not_to be_a_twirp_message
18
+ end
19
+
20
+ it "matches a specific message type" do
21
+ is_expected.to be_a_twirp_message(HelloRequest)
22
+ end
23
+
24
+ it "catches type mismatches" do
25
+ is_expected.not_to be_a_twirp_message(GoodbyeRequest)
26
+ end
27
+
28
+ it "catches erroneous message types" do
29
+ expect {
30
+ is_expected.to be_a_twirp_message(Object)
31
+ }.to raise_error(TypeError, /Object/)
32
+ end
33
+
34
+ context "with attributes" do
35
+ let(:attrs) { { name: "Bob", count: 3 } }
36
+
37
+ it "can match attributes" do
38
+ is_expected.to be_a_twirp_message(HelloRequest, **attrs)
39
+ end
40
+
41
+ it "supports regex matches" do
42
+ is_expected.to be_a_twirp_message(name: /^B/)
43
+ end
44
+
45
+ it "supports range matches" do
46
+ is_expected.to be_a_twirp_message(count: 1..5)
47
+ end
48
+
49
+ it "catches mismatches" do
50
+ expect {
51
+ is_expected.to be_a_twirp_message(GoodbyeRequest, name: "Bob")
52
+ }.to fail_with /message of type/
53
+
54
+ is_expected.not_to be_a_twirp_message(name: "nope")
55
+
56
+ is_expected.not_to be_a_twirp_message(name: /no/)
57
+
58
+ is_expected.not_to be_a_twirp_message(count: 1)
59
+ end
60
+
61
+ it "catches erroneous attribute matches" do
62
+ is_expected.not_to be_a_twirp_message(namezzz: "Bob")
63
+ end
64
+
65
+ it "handles type mismatches" do
66
+ is_expected.not_to be_a_twirp_message(name: 123)
67
+ end
68
+ end
69
+ end
@@ -1,56 +1,89 @@
1
1
  describe "be_a_twirp_response" do
2
- subject { HelloResponse.new(**attrs) }
2
+ context "with a response" do
3
+ subject { Twirp::ClientResp.new(response, nil) }
3
4
 
4
- let(:attrs) { {} }
5
+ let(:response) { GoodbyeResponse.new }
5
6
 
6
- it { is_expected.to be_a_twirp_response }
7
+ it { is_expected.to be_a_twirp_response }
7
8
 
8
- it "catches non-twirp response" do
9
- expect {
10
- expect(Object).to be_a_twirp_response
11
- }.to fail_with /Expected a Twirp response, found Object/
12
- end
9
+ it "handles non-twirp response" do
10
+ expect(Object).not_to be_a_twirp_response
11
+ end
13
12
 
14
- it "matches a specific response type" do
15
- is_expected.to be_a_twirp_request(HelloResponse)
16
- end
13
+ context "with attributes" do
14
+ let(:response) { GoodbyeResponse.new(**attrs) }
15
+ let(:attrs) { { message: "bye", name: "Bob" } }
17
16
 
18
- it "catches type mismatches" do
19
- expect {
20
- is_expected.to be_a_twirp_request(GoodbyeResponse)
21
- }.to fail_with /request of type GoodbyeResponse/
22
- end
17
+ it "can match attributes" do
18
+ is_expected.to be_a_twirp_response(**attrs)
19
+ end
23
20
 
24
- context "with attributes" do
25
- let(:attrs) { { message: msg } }
26
- let(:msg) { [ "Hello World" ] }
21
+ it "supports regex matches" do
22
+ is_expected.to be_a_twirp_response(name: /^B/)
23
+ end
27
24
 
28
- it { is_expected.to be_a_twirp_response(**attrs) }
25
+ it "catches mismatches" do
26
+ expect {
27
+ is_expected.to be_a_twirp_response(name: "nope")
28
+ }.to fail_including(
29
+ '-:name => "nope",',
30
+ '+:name => "Bob",',
31
+ )
29
32
 
30
- it "supports regex matches" do
31
- is_expected.to be_a_twirp_response(message: include(/Hello/))
33
+ expect {
34
+ is_expected.to be_a_twirp_response(name: /no/)
35
+ }.to fail_including(
36
+ '-:name => /no/,',
37
+ '+:name => "Bob",',
38
+ )
39
+ end
32
40
  end
41
+ end
42
+
43
+ context "with error" do
44
+ subject { Twirp::ClientResp.new(nil, error) }
45
+
46
+ let(:error) { Twirp::Error.new(code, msg, meta) }
47
+ let(:code) { :not_found }
48
+ let(:msg) { "Not Found" }
49
+ let(:meta) { { is_meta: "true" } }
50
+
51
+ it { is_expected.to be_a_twirp_response.with_error }
52
+ it { is_expected.to be_a_twirp_response.with_error(code) }
53
+ it { is_expected.to be_a_twirp_response.with_error(msg) }
54
+ it { is_expected.to be_a_twirp_response.with_error(**meta) }
55
+ it { is_expected.to be_a_twirp_response.with_error(/Not/) }
33
56
 
34
57
  it "catches mismatches" do
35
58
  expect {
36
- is_expected.to be_a_twirp_response(message: [ "" ])
37
- }.to fail_with /to have message/
59
+ is_expected.to be_a_twirp_response.with_error(:internal)
60
+ }.to fail_with /to have code `:internal`/
61
+ end
62
+ end
38
63
 
64
+ context "with neither response nor error" do
65
+ subject { Twirp::ClientResp.new(nil, nil) }
66
+
67
+ it "fails the response match" do
39
68
  expect {
40
- is_expected.to be_a_twirp_response(message: [ "Hello" ])
41
- }.to fail_with /to have message/
69
+ is_expected.to be_a_twirp_response
70
+ }.to fail_with /to have data/
42
71
  end
43
72
 
44
- it "catches the erroneous attributes" do
73
+ it "fails the error match" do
45
74
  expect {
46
- is_expected.to be_a_twirp_response(msg: [])
47
- }.to raise_error(ArgumentError, /msg/)
75
+ is_expected.to be_a_twirp_response.with_error
76
+ }.to fail_with /to have an error/
48
77
  end
78
+ end
79
+
80
+ context "with both response and error" do
81
+ subject { Twirp::ClientResp.new(GoodbyeResponse.new, Twirp::Error.not_found("Not Found")) }
49
82
 
50
- it "catches type mismatches" do
83
+ it "does not permit both attr and error matching" do
51
84
  expect {
52
- is_expected.to be_a_twirp_response(message: "Hello World")
53
- }.to raise_error(ArgumentError, /Expected array/)
85
+ is_expected.to be_a_twirp_response(name: "Bob").with_error
86
+ }.to raise_error(ArgumentError, /but not both/)
54
87
  end
55
88
  end
56
89
  end
metadata CHANGED
@@ -1,31 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-twirp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Pepper
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-25 00:00:00.000000000 Z
11
+ date: 2022-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: twirp
14
+ name: google-protobuf
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '3'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rspec-expectations
28
+ name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,21 +39,35 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3'
41
41
  - !ruby/object:Gem::Dependency
42
- name: byebug
42
+ name: rspec-protobuf
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
47
+ version: '0.2'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '0.2'
55
55
  - !ruby/object:Gem::Dependency
56
- name: codecov
56
+ name: twirp
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: byebug
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
@@ -67,7 +81,7 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: rspec
84
+ name: codecov
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - ">="
@@ -94,7 +108,7 @@ dependencies:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
97
- description: "..."
111
+ description: Twirp RSpec matchers
98
112
  email:
99
113
  executables: []
100
114
  extensions: []
@@ -102,14 +116,12 @@ extra_rdoc_files: []
102
116
  files:
103
117
  - lib/rspec-twirp.rb
104
118
  - lib/rspec/twirp.rb
105
- - lib/rspec/twirp/client_response_matcher.rb
106
119
  - lib/rspec/twirp/error_matcher.rb
107
- - lib/rspec/twirp/request_matcher.rb
120
+ - lib/rspec/twirp/message_matcher.rb
108
121
  - lib/rspec/twirp/response_matcher.rb
109
122
  - lib/rspec/twirp/version.rb
110
- - spec/client_response_spec.rb
111
123
  - spec/error_spec.rb
112
- - spec/request_spec.rb
124
+ - spec/message_spec.rb
113
125
  - spec/response_spec.rb
114
126
  homepage: https://github.com/dpep/rspec-twirp_rb
115
127
  licenses:
@@ -130,12 +142,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
142
  - !ruby/object:Gem::Version
131
143
  version: '0'
132
144
  requirements: []
133
- rubygems_version: 3.1.6
145
+ rubygems_version: 3.3.7
134
146
  signing_key:
135
147
  specification_version: 4
136
148
  summary: Gem::Specification::RSpec::Twirp
137
149
  test_files:
138
150
  - spec/error_spec.rb
139
- - spec/request_spec.rb
151
+ - spec/message_spec.rb
140
152
  - spec/response_spec.rb
141
- - spec/client_response_spec.rb
@@ -1,48 +0,0 @@
1
- RSpec::Matchers.define :be_a_twirp_client_response do |type = nil, **attrs|
2
- chain :with_error do |*matchers, **meta_matchers|
3
- # code, msg, meta
4
- @with_error = [ matchers, meta_matchers ]
5
- end
6
-
7
- match do |actual|
8
- # ensure type is a valid twirp request type
9
- if type && !(type < Google::Protobuf::MessageExts)
10
- raise ArgumentError, "Expected `type` to be a Twirp response, found: #{type}"
11
- end
12
-
13
- @fail_msg = "Expected a Twirp::ClientResp, found #{actual}"
14
- return false unless actual.is_a?(Twirp::ClientResp)
15
-
16
- # match expected response type
17
- @fail_msg = "Expected a Twirp::ClientResp of type #{type}, found #{actual.data&.class}"
18
- return false if type && actual.data&.class != type
19
-
20
- if @with_error
21
- unless attrs.empty?
22
- raise ArgumentError, "match data attributes or error, but not both"
23
- end
24
-
25
- @fail_msg = "Expected #{actual} to have an error"
26
- return false unless actual.error
27
-
28
- matchers, meta_matchers = @with_error
29
- expect(actual.error).to be_a_twirp_error(*matchers, **meta_matchers)
30
- else
31
- @fail_msg = "Expected #{actual} to have data"
32
- return false unless actual.data
33
-
34
- expect(actual.data).to be_a_twirp_response(**attrs)
35
- end
36
- rescue RSpec::Expectations::ExpectationNotMetError => err
37
- @fail_msg = err.message
38
- false
39
- end
40
-
41
- description do
42
- type ? "a #{type} Twirp response" : "a Twirp response"
43
- end
44
-
45
- failure_message { @fail_msg }
46
- end
47
-
48
- RSpec::Matchers.alias_matcher :a_twirp_client_response, :be_a_twirp_client_response
@@ -1,37 +0,0 @@
1
- RSpec::Matchers.define :be_a_twirp_request do |type = nil, **attrs|
2
- match do |actual|
3
- # ensure type is a valid twirp request type
4
- if type && !(type < Google::Protobuf::MessageExts)
5
- raise ArgumentError, "Expected `type` to be a Twirp request, found: #{type}"
6
- end
7
-
8
- @fail_msg = "Expected a Twirp request, found #{actual}"
9
- return false unless actual.is_a?(Google::Protobuf::MessageExts)
10
-
11
- # match expected request type
12
- @fail_msg = "Expected a Twirp request of type #{type}, found #{actual.class}"
13
- return false if type && actual.class != type
14
-
15
- return true if attrs.empty?
16
-
17
- RSpec::Twirp.validate_types(attrs, actual.class)
18
-
19
- # match attributes which are present
20
- attrs.each do |attr_name, expected_attr|
21
- actual_attr = actual.send(attr_name)
22
-
23
- @fail_msg = "Expected #{actual} to have #{attr_name}: #{expected_attr.inspect}, found #{actual_attr}"
24
- return false unless values_match?(expected_attr, actual_attr)
25
- end
26
-
27
- true
28
- end
29
-
30
- description do
31
- type ? "a #{type} Twirp request" : "a Twirp request"
32
- end
33
-
34
- failure_message { @fail_msg }
35
- end
36
-
37
- RSpec::Matchers.alias_matcher :a_twirp_request, :be_a_twirp_request
@@ -1,112 +0,0 @@
1
- describe "be_a_twirp_client_response" do
2
- context "with a response" do
3
- subject { Twirp::ClientResp.new(GoodbyeResponse.new, nil) }
4
-
5
- it { is_expected.to be_a_twirp_client_response }
6
-
7
- it "catches non-twirp response" do
8
- expect {
9
- expect(Object).to be_a_twirp_client_response
10
- }.to fail_with /found Object/
11
- end
12
-
13
- it "matches a specific response type" do
14
- is_expected.to be_a_twirp_client_response(GoodbyeResponse)
15
- end
16
-
17
- it "catches type mismatches" do
18
- expect {
19
- is_expected.to be_a_twirp_client_response(HelloResponse)
20
- }.to fail_with /of type HelloResponse/
21
- end
22
-
23
- it "catches erroneous response types" do
24
- expect {
25
- is_expected.to be_a_twirp_client_response(Object)
26
- }.to raise_error(ArgumentError, /Object/)
27
- end
28
-
29
- context "with attributes" do
30
- subject { Twirp::ClientResp.new(GoodbyeResponse.new(**attrs), nil) }
31
-
32
- let(:attrs) { { message: "bye", name: "Bob" } }
33
-
34
- it "can match attributes" do
35
- is_expected.to be_a_twirp_client_response(GoodbyeResponse, **attrs)
36
- end
37
-
38
- it "supports regex matches" do
39
- is_expected.to be_a_twirp_client_response(name: /^B/)
40
- end
41
-
42
- it "catches mismatches" do
43
- expect {
44
- is_expected.to be_a_twirp_client_response(name: "nope")
45
- }.to fail_with /to have name: "nope"/
46
-
47
- expect {
48
- is_expected.to be_a_twirp_client_response(name: /no/)
49
- }.to fail_with /to have name: \/no\//
50
- end
51
-
52
- it "catches the erroneous attributes" do
53
- expect {
54
- is_expected.to be_a_twirp_client_response(namezzz: "Bob")
55
- }.to raise_error(ArgumentError, /namezzz/)
56
- end
57
-
58
- it "catches type mismatches" do
59
- expect {
60
- is_expected.to be_a_twirp_client_response(name: 123)
61
- }.to raise_error(TypeError, /string field.*given Integer/)
62
- end
63
- end
64
- end
65
-
66
- context "with error" do
67
- subject { Twirp::ClientResp.new(nil, error) }
68
-
69
- let(:error) { Twirp::Error.new(code, msg, meta) }
70
- let(:code) { :not_found }
71
- let(:msg) { "Not Found" }
72
- let(:meta) { { is_meta: "true" } }
73
-
74
- it { is_expected.to be_a_twirp_client_response.with_error }
75
- it { is_expected.to be_a_twirp_client_response.with_error(code) }
76
- it { is_expected.to be_a_twirp_client_response.with_error(msg) }
77
- it { is_expected.to be_a_twirp_client_response.with_error(**meta) }
78
- it { is_expected.to be_a_twirp_client_response.with_error(/Not/) }
79
-
80
- it "catches mismatches" do
81
- expect {
82
- is_expected.to be_a_twirp_client_response.with_error(:internal)
83
- }.to fail_with /code: :internal/
84
- end
85
- end
86
-
87
- context "with neither response nor error" do
88
- subject { Twirp::ClientResp.new(nil, nil) }
89
-
90
- it "fails the response match" do
91
- expect {
92
- is_expected.to be_a_twirp_client_response
93
- }.to fail_with /to have data/
94
- end
95
-
96
- it "fails the error match" do
97
- expect {
98
- is_expected.to be_a_twirp_client_response.with_error
99
- }.to fail_with /to have an error/
100
- end
101
- end
102
-
103
- context "with both response and error" do
104
- subject { Twirp::ClientResp.new(GoodbyeResponse.new, Twirp::Error.not_found("Not Found")) }
105
-
106
- it "fails" do
107
- expect {
108
- is_expected.to be_a_twirp_client_response(name: "Bob").with_error
109
- }.to raise_error(ArgumentError, /but not both/)
110
- end
111
- end
112
- end
data/spec/request_spec.rb DELETED
@@ -1,75 +0,0 @@
1
- describe "be_a_twirp_request" do
2
- subject { HelloRequest.new(**attrs) }
3
-
4
- let(:attrs) { {} }
5
-
6
- it { is_expected.to be_a_twirp_request }
7
-
8
- it "catches non-twirp requests" do
9
- expect {
10
- expect(Object).to be_a_twirp_request
11
- }.to fail_with /Expected a Twirp request, found Object/
12
- end
13
-
14
- it "matches a specific request type" do
15
- is_expected.to be_a_twirp_request(HelloRequest)
16
- end
17
-
18
- it "catches type mismatches" do
19
- expect {
20
- is_expected.to be_a_twirp_request(GoodbyeRequest)
21
- }.to fail_with /request of type GoodbyeRequest/
22
- end
23
-
24
- it "catches erroneous request types" do
25
- expect {
26
- is_expected.to be_a_twirp_request(Object)
27
- }.to raise_error(ArgumentError, /Object/)
28
- end
29
-
30
- context "with attributes" do
31
- let(:attrs) { { name: "Bob", count: 3 } }
32
-
33
- it "can match attributes" do
34
- is_expected.to be_a_twirp_request(HelloRequest, **attrs)
35
- end
36
-
37
- it "supports regex matches" do
38
- is_expected.to be_a_twirp_request(name: /^B/)
39
- end
40
-
41
- it "supports range matches" do
42
- is_expected.to be_a_twirp_request(count: 1..5)
43
- end
44
-
45
- it "catches mismatches" do
46
- expect {
47
- is_expected.to be_a_twirp_request(GoodbyeRequest, name: "Bob")
48
- }.to fail_with /request of type/
49
-
50
- expect {
51
- is_expected.to be_a_twirp_request(name: "nope")
52
- }.to fail_with /to have name: "nope"/
53
-
54
- expect {
55
- is_expected.to be_a_twirp_request(name: /no/)
56
- }.to fail_with /to have name: \/no\//
57
-
58
- expect {
59
- is_expected.to be_a_twirp_request(count: 1)
60
- }.to fail_with /to have count: 1/
61
- end
62
-
63
- it "catches the erroneous attribute matches" do
64
- expect {
65
- is_expected.to be_a_twirp_request(namezzz: "Bob")
66
- }.to raise_error(ArgumentError, /namezzz/)
67
- end
68
-
69
- it "catches type mismatches" do
70
- expect {
71
- is_expected.to be_a_twirp_request(name: 123)
72
- }.to raise_error(TypeError, /string field.*given Integer/)
73
- end
74
- end
75
- end