rspec-twirp 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rspec/twirp/error_matcher.rb +44 -9
- data/lib/rspec/twirp/message_matcher.rb +2 -0
- data/lib/rspec/twirp/response_matcher.rb +24 -22
- data/lib/rspec/twirp/version.rb +1 -1
- data/lib/rspec/twirp.rb +7 -30
- data/spec/error_spec.rb +78 -5
- data/spec/message_spec.rb +69 -0
- data/spec/response_spec.rb +65 -32
- metadata +31 -20
- data/lib/rspec/twirp/client_response_matcher.rb +0 -48
- data/lib/rspec/twirp/request_matcher.rb +0 -37
- data/spec/client_response_spec.rb +0 -112
- data/spec/request_spec.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a9027f86450d9e045705304d1d8e590b51a733269938e83ca5ae098a90018d4
|
4
|
+
data.tar.gz: dca42845c93b814878cf24842320583ddf6dbce3b0d266cd897a58500cf31a31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
16
|
-
|
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
|
21
|
-
|
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
|
-
@
|
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
|
-
|
65
|
+
matched &= values_match?(meta_matcher, actual.meta)
|
37
66
|
end
|
38
67
|
|
39
|
-
|
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
|
@@ -1,34 +1,36 @@
|
|
1
|
-
RSpec::Matchers.define :be_a_twirp_response do
|
2
|
-
|
3
|
-
#
|
4
|
-
|
5
|
-
|
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
|
-
|
12
|
-
@fail_msg = "Expected a Twirp
|
13
|
-
return false
|
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
|
-
|
11
|
+
if @with_error
|
12
|
+
unless attrs.empty?
|
13
|
+
raise ArgumentError, "match data attributes or error, but not both"
|
14
|
+
end
|
16
15
|
|
17
|
-
|
16
|
+
@fail_msg = "Expected #{actual} to have an error, but found none"
|
17
|
+
return false unless actual.error
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
27
|
+
rescue RSpec::Expectations::ExpectationNotMetError => err
|
28
|
+
@fail_msg = err.message
|
29
|
+
false
|
28
30
|
end
|
29
31
|
|
30
32
|
description do
|
31
|
-
|
33
|
+
"a Twirp response"
|
32
34
|
end
|
33
35
|
|
34
36
|
failure_message { @fail_msg }
|
data/lib/rspec/twirp/version.rb
CHANGED
data/lib/rspec/twirp.rb
CHANGED
@@ -1,32 +1,9 @@
|
|
1
|
-
require "
|
2
|
-
require "rspec
|
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/
|
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
|
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
|
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
|
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
|
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
|
data/spec/response_spec.rb
CHANGED
@@ -1,56 +1,89 @@
|
|
1
1
|
describe "be_a_twirp_response" do
|
2
|
-
|
2
|
+
context "with a response" do
|
3
|
+
subject { Twirp::ClientResp.new(response, nil) }
|
3
4
|
|
4
|
-
|
5
|
+
let(:response) { GoodbyeResponse.new }
|
5
6
|
|
6
|
-
|
7
|
+
it { is_expected.to be_a_twirp_response }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
13
|
+
context "with attributes" do
|
14
|
+
let(:response) { GoodbyeResponse.new(**attrs) }
|
15
|
+
let(:attrs) { { message: "bye", name: "Bob" } }
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
21
|
+
it "supports regex matches" do
|
22
|
+
is_expected.to be_a_twirp_response(name: /^B/)
|
23
|
+
end
|
27
24
|
|
28
|
-
|
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
|
-
|
31
|
-
|
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(
|
37
|
-
}.to fail_with /to have
|
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
|
41
|
-
}.to fail_with /to have
|
69
|
+
is_expected.to be_a_twirp_response
|
70
|
+
}.to fail_with /to have data/
|
42
71
|
end
|
43
72
|
|
44
|
-
it "
|
73
|
+
it "fails the error match" do
|
45
74
|
expect {
|
46
|
-
is_expected.to be_a_twirp_response
|
47
|
-
}.to
|
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 "
|
83
|
+
it "does not permit both attr and error matching" do
|
51
84
|
expect {
|
52
|
-
is_expected.to be_a_twirp_response(
|
53
|
-
}.to raise_error(ArgumentError, /
|
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.
|
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-
|
11
|
+
date: 2022-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: google-protobuf
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
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: '
|
26
|
+
version: '3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: rspec
|
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:
|
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: :
|
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:
|
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:
|
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/
|
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/
|
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.
|
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/
|
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
|