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 +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
|