Skip to content

Commit 3390321

Browse files
braintreepsklaguerrePaywysmith-publicgit
committed
4.33.1
Co-authored-by: Kevin Laguerre <klaguerre@paypal.com> Co-authored-by: Wyatt Smith <wysmith@paypal.com>
1 parent 007819b commit 3390321

6 files changed

Lines changed: 105 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 4.33.1
4+
- Bug fix for Nokogiri XML parsing
5+
36
## 4.33.0
47
- Switch from libxml-ruby to Nokogiri to allow use with JRuby.
58

lib/braintree/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Braintree
22
module Version
33
Major = 4
44
Minor = 33
5-
Tiny = 0
5+
Tiny = 1
66

77
String = "#{Major}.#{Minor}.#{Tiny}"
88
end

lib/braintree/xml/nokogiri.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ def self.parse(xml_string)
1212
end
1313

1414
def self._node_to_hash(node, hash = {})
15+
sub_hash = node.text? ? hash : _build_sub_hash(hash, node.name)
16+
1517
if node.text? || (node.children.size == 1 && node.children.first.text?)
1618
content = node.text? ? node.content : node.children.first.content
1719
raise "Content too large" if content.length >= NOKOGIRI_XML_LIMIT
18-
hash[CONTENT_ROOT] = content
20+
sub_hash[CONTENT_ROOT] = content
21+
_attributes_to_hash(node, sub_hash) unless node.text?
1922
else
20-
sub_hash = _build_sub_hash(hash, node.name)
2123
_attributes_to_hash(node, sub_hash)
2224
if _array?(node)
2325
_children_array_to_hash(node, sub_hash)
@@ -66,4 +68,4 @@ def self._array?(node)
6668
end
6769
end
6870
end
69-
end
71+
end

spec/unit/braintree/client_token_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,16 @@ module Braintree
3333
end
3434
end
3535
end
36+
37+
describe "error response handling" do
38+
it "correctly parses error response with nested structure" do
39+
error_xml = "<api-error-response><message>Invalid request</message><errors><errors type=\"array\"></errors></errors></api-error-response>"
40+
result = Braintree::Xml::Parser.hash_from_xml(error_xml)
41+
42+
expect(result[:api_error_response]).to be_a(Hash)
43+
expect(result[:api_error_response][:message]).to eq("Invalid request")
44+
expect(result[:api_error_response][:errors]).to be_a(Hash)
45+
end
46+
end
3647
end
3748
end

spec/unit/braintree/error_result_spec.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,34 @@
1414
)
1515
end.to_not raise_error
1616
end
17+
18+
it "handles parsed XML error response structure correctly" do
19+
data = {
20+
:message => "Validation failed",
21+
:errors => {
22+
:errors => [{:code => "81234", :message => "Field is required"}]
23+
}
24+
}
25+
26+
expect do
27+
result = Braintree::ErrorResult.new(:gateway, data)
28+
expect(result.message).to eq("Validation failed")
29+
expect(result.errors.inspect).to eq("#<Braintree::Errors :[(81234) Field is required]>")
30+
end.to_not raise_error
31+
end
32+
33+
it "handles empty error array in parsed XML response" do
34+
data = {
35+
:message => "Invalid request",
36+
:errors => {:errors => []}
37+
}
38+
39+
expect do
40+
result = Braintree::ErrorResult.new(:gateway, data)
41+
expect(result.message).to eq("Invalid request")
42+
expect(result.errors).to be_a(Braintree::Errors)
43+
end.to_not raise_error
44+
end
1745
end
1846

1947
describe "inspect" do

spec/unit/braintree/xml/parser_spec.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,62 @@
8181
END
8282
expect(xml).to parse_to(:root => {:paypal_details => {:deets => [{:secret_code => "1234"}], :payer_email => "abc@test.com", :payment_id => "1234567890"}})
8383
end
84+
85+
it "does not collapse nested structures with single-child elements" do
86+
xml = "<api-error-response><message>Test</message><errors><errors type=\"array\"></errors></errors></api-error-response>"
87+
expect(xml).to parse_to({:api_error_response=>{:message=>"Test", :errors=>{:errors=>[]}}})
88+
end
89+
90+
it "preserves hash structure when one key has array value" do
91+
xml = <<-END
92+
<root>
93+
<message>Error message</message>
94+
<items type="array">
95+
<item>Value1</item>
96+
</items>
97+
</root>
98+
END
99+
expect(xml).to parse_to({:root => {:message => "Error message", :items => ["Value1"]}})
100+
end
101+
102+
it "handles error response with nested errors correctly" do
103+
xml = <<-END
104+
<api-error-response>
105+
<message>Validation failed</message>
106+
<errors>
107+
<errors type="array">
108+
<error>
109+
<code>81234</code>
110+
<message>Field is required</message>
111+
</error>
112+
</errors>
113+
</errors>
114+
</api-error-response>
115+
END
116+
expect(xml).to parse_to({
117+
:api_error_response => {
118+
:message => "Validation failed",
119+
:errors => {
120+
:errors => [{:code => "81234", :message => "Field is required"}]
121+
}
122+
}
123+
})
124+
end
125+
126+
it "handles client token error response structure" do
127+
xml = <<-END
128+
<api-error-response>
129+
<message>Invalid request</message>
130+
<errors>
131+
<errors type="array"></errors>
132+
</errors>
133+
</api-error-response>
134+
END
135+
result = Braintree::Xml::Parser.hash_from_xml(xml)
136+
expect(result[:api_error_response]).to be_a(Hash)
137+
expect(result[:api_error_response][:message]).to eq("Invalid request")
138+
expect(result[:api_error_response][:errors]).to be_a(Hash)
139+
expect(result[:api_error_response][:errors][:errors]).to eq([])
140+
end
84141
end
85142
end

0 commit comments

Comments
 (0)