braintree 1.0.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.
Files changed (65) hide show
  1. data/LICENSE +22 -0
  2. data/README.rdoc +62 -0
  3. data/lib/braintree.rb +66 -0
  4. data/lib/braintree/address.rb +122 -0
  5. data/lib/braintree/base_module.rb +29 -0
  6. data/lib/braintree/configuration.rb +99 -0
  7. data/lib/braintree/credit_card.rb +231 -0
  8. data/lib/braintree/credit_card_verification.rb +31 -0
  9. data/lib/braintree/customer.rb +231 -0
  10. data/lib/braintree/digest.rb +20 -0
  11. data/lib/braintree/error_codes.rb +95 -0
  12. data/lib/braintree/error_result.rb +39 -0
  13. data/lib/braintree/errors.rb +29 -0
  14. data/lib/braintree/http.rb +105 -0
  15. data/lib/braintree/paged_collection.rb +55 -0
  16. data/lib/braintree/ssl_expiration_check.rb +28 -0
  17. data/lib/braintree/successful_result.rb +38 -0
  18. data/lib/braintree/test/credit_card_numbers.rb +50 -0
  19. data/lib/braintree/test/transaction_amounts.rb +10 -0
  20. data/lib/braintree/transaction.rb +360 -0
  21. data/lib/braintree/transaction/address_details.rb +15 -0
  22. data/lib/braintree/transaction/credit_card_details.rb +22 -0
  23. data/lib/braintree/transaction/customer_details.rb +13 -0
  24. data/lib/braintree/transparent_redirect.rb +110 -0
  25. data/lib/braintree/util.rb +94 -0
  26. data/lib/braintree/validation_error.rb +15 -0
  27. data/lib/braintree/validation_error_collection.rb +80 -0
  28. data/lib/braintree/version.rb +9 -0
  29. data/lib/braintree/xml.rb +12 -0
  30. data/lib/braintree/xml/generator.rb +80 -0
  31. data/lib/braintree/xml/libxml.rb +69 -0
  32. data/lib/braintree/xml/parser.rb +93 -0
  33. data/lib/ssl/securetrust_ca.crt +44 -0
  34. data/lib/ssl/valicert_ca.crt +18 -0
  35. data/spec/integration/braintree/address_spec.rb +352 -0
  36. data/spec/integration/braintree/credit_card_spec.rb +676 -0
  37. data/spec/integration/braintree/customer_spec.rb +664 -0
  38. data/spec/integration/braintree/http_spec.rb +201 -0
  39. data/spec/integration/braintree/test/transaction_amounts_spec.rb +29 -0
  40. data/spec/integration/braintree/transaction_spec.rb +900 -0
  41. data/spec/integration/spec_helper.rb +38 -0
  42. data/spec/script/httpsd.rb +27 -0
  43. data/spec/spec_helper.rb +41 -0
  44. data/spec/unit/braintree/address_spec.rb +86 -0
  45. data/spec/unit/braintree/configuration_spec.rb +190 -0
  46. data/spec/unit/braintree/credit_card_spec.rb +137 -0
  47. data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
  48. data/spec/unit/braintree/customer_spec.rb +103 -0
  49. data/spec/unit/braintree/digest_spec.rb +28 -0
  50. data/spec/unit/braintree/error_result_spec.rb +42 -0
  51. data/spec/unit/braintree/errors_spec.rb +81 -0
  52. data/spec/unit/braintree/http_spec.rb +42 -0
  53. data/spec/unit/braintree/paged_collection_spec.rb +128 -0
  54. data/spec/unit/braintree/ssl_expiration_check_spec.rb +92 -0
  55. data/spec/unit/braintree/successful_result_spec.rb +27 -0
  56. data/spec/unit/braintree/transaction/credit_card_details_spec.rb +22 -0
  57. data/spec/unit/braintree/transaction_spec.rb +136 -0
  58. data/spec/unit/braintree/transparent_redirect_spec.rb +154 -0
  59. data/spec/unit/braintree/util_spec.rb +142 -0
  60. data/spec/unit/braintree/validation_error_collection_spec.rb +128 -0
  61. data/spec/unit/braintree/validation_error_spec.rb +19 -0
  62. data/spec/unit/braintree/xml/libxml_spec.rb +51 -0
  63. data/spec/unit/braintree/xml_spec.rb +122 -0
  64. data/spec/unit/spec_helper.rb +1 -0
  65. metadata +118 -0
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::CreditCardVerification do
4
+ describe "inspect" do
5
+ it "is better than the default inspect" do
6
+ verification = Braintree::CreditCardVerification._new(
7
+ :status => "verified",
8
+ :avs_error_response_code => "I",
9
+ :avs_postal_code_response_code => "I",
10
+ :avs_street_address_response_code => "I",
11
+ :cvv_response_code => "I"
12
+ )
13
+ verification.inspect.should == %(#<Braintree::CreditCardVerification status: "verified", cvv_response_code: "I", avs_error_response_code: "I", avs_postal_code_response_code: "I", avs_street_address_response_code: "I">)
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Customer do
4
+ describe "inspect" do
5
+ it "includes the id first" do
6
+ output = Braintree::Customer._new({:first_name => 'Dan', :id => '1234'}).inspect
7
+ output.should include("#<Braintree::Customer id: \"1234\",")
8
+ end
9
+
10
+ it "includes all customer attributes" do
11
+ customer = Braintree::Customer._new(
12
+ :company => "Company",
13
+ :email => "e@mail.com",
14
+ :fax => "483-438-5821",
15
+ :first_name => "Patrick",
16
+ :last_name => "Smith",
17
+ :phone => "802-483-5932",
18
+ :website => "patrick.smith.com",
19
+ :created_at => Time.now,
20
+ :updated_at => Time.now
21
+ )
22
+ output = customer.inspect
23
+ output.should include(%q(company: "Company"))
24
+ output.should include(%q(email: "e@mail.com"))
25
+ output.should include(%q(fax: "483-438-5821"))
26
+ output.should include(%q(first_name: "Patrick"))
27
+ output.should include(%q(last_name: "Smith"))
28
+ output.should include(%q(phone: "802-483-5932"))
29
+ output.should include(%q(website: "patrick.smith.com"))
30
+ output.should include(%Q(created_at: #{customer.created_at.inspect}))
31
+ output.should include(%Q(updated_at: #{customer.updated_at.inspect}))
32
+ end
33
+ end
34
+
35
+ describe "self.create" do
36
+ it "raises an exception if hash includes an invalid key" do
37
+ expect do
38
+ Braintree::Customer.create(:first_name => "Joe", :invalid_key => "foo")
39
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
40
+ end
41
+ end
42
+
43
+ describe "self.update" do
44
+ it "raises an exception if hash includes an invalid key" do
45
+ expect do
46
+ Braintree::Customer.update("customer_id", :first_name => "Joe", :invalid_key => "foo")
47
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
48
+ end
49
+ end
50
+
51
+ describe "self.create_from_transparent_redirect" do
52
+ it "raises an exception if the query string is forged" do
53
+ expect do
54
+ Braintree::Customer.create_from_transparent_redirect("forged=query_string")
55
+ end.to raise_error(Braintree::ForgedQueryString)
56
+ end
57
+ end
58
+
59
+ describe "==" do
60
+ it "returns true when given a customer with the same id" do
61
+ first = Braintree::Customer._new(:id => 123)
62
+ second = Braintree::Customer._new(:id => 123)
63
+
64
+ first.should == second
65
+ second.should == first
66
+ end
67
+
68
+ it "returns false when given a customer with a different id" do
69
+ first = Braintree::Customer._new(:id => 123)
70
+ second = Braintree::Customer._new(:id => 124)
71
+
72
+ first.should_not == second
73
+ second.should_not == first
74
+ end
75
+
76
+ it "returns false when not given a customer" do
77
+ customer = Braintree::Customer._new(:id => 123)
78
+ customer.should_not == "not a customer"
79
+ end
80
+ end
81
+
82
+ describe "initialize" do
83
+ it "converts payment method hashes into payment method objects" do
84
+ customer = Braintree::Customer._new(
85
+ :credit_cards => [
86
+ {:token => "pm1"},
87
+ {:token => "pm2"}
88
+ ]
89
+ )
90
+ customer.credit_cards.size.should == 2
91
+ customer.credit_cards[0].token.should == "pm1"
92
+ customer.credit_cards[1].token.should == "pm2"
93
+ end
94
+ end
95
+
96
+ describe "new" do
97
+ it "is protected" do
98
+ expect do
99
+ Braintree::Customer.new
100
+ end.to raise_error(NoMethodError, /protected method .new/)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Digest do
4
+ describe "self.hexdigest" do
5
+ it "returns the sha1 hmac of the input string (test case 6 from RFC 2202)" do
6
+ begin
7
+ original_key = Braintree::Configuration.private_key
8
+ Braintree::Configuration.private_key = "\xaa" * 80
9
+ data = "Test Using Larger Than Block-Size Key - Hash Key First"
10
+ Braintree::Digest.hexdigest(data).should == "aa4ae5e15272d00e95705637ce8a3b55ed402112"
11
+ ensure
12
+ Braintree::Configuration.private_key = original_key
13
+ end
14
+ end
15
+
16
+ it "returns the sha1 hmac of the input string (test case 7 from RFC 2202)" do
17
+ begin
18
+ original_key = Braintree::Configuration.private_key
19
+ Braintree::Configuration.private_key = "\xaa" * 80
20
+ data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
21
+ Braintree::Digest.hexdigest(data).should == "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"
22
+ ensure
23
+ Braintree::Configuration.private_key = original_key
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::ErrorResult do
4
+ describe "initialize" do
5
+ it "initializes params and errors" do
6
+ errors = {
7
+ :scope => {
8
+ :errors => [{:code => "123", :message => "something is invalid", :attribute => "something"}]
9
+ }
10
+ }
11
+ result = Braintree::ErrorResult.new(:params => "params", :errors => errors)
12
+ result.success?.should == false
13
+ result.params.should == "params"
14
+ result.errors.size.should == 1
15
+ result.errors.for(:scope)[0].message.should == "something is invalid"
16
+ result.errors.for(:scope)[0].attribute.should == "something"
17
+ result.errors.for(:scope)[0].code.should == "123"
18
+ end
19
+
20
+ it "ignores data other than params and errors" do
21
+ # so that we can add more data into the response in the future without breaking the client lib
22
+ expect do
23
+ result = Braintree::ErrorResult.new(:params => "params", :errors => {:errors => []}, :extra => "is ignored")
24
+ end.to_not raise_error
25
+ end
26
+ end
27
+
28
+ describe "inspect" do
29
+ it "shows errors 2 levels deep" do
30
+ errors = {
31
+ :level1 => {
32
+ :errors => [{:code => "code1", :attribute => "attr", :message => "message"}],
33
+ :level2 => {
34
+ :errors => [{:code => "code2", :attribute => "attr2", :message => "message2"}],
35
+ }
36
+ }
37
+ }
38
+ result = Braintree::ErrorResult.new(:params => "params", :errors => errors)
39
+ result.inspect.should == "#<Braintree::ErrorResult params:{...} errors:<level1:[(code1) message], level1/level2:[(code2) message2]>>"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Errors do
4
+ describe "for" do
5
+ it "accesses errors for the given scope" do
6
+ errors = Braintree::Errors.new(
7
+ :level1 => {:errors => [{:code => "code1", :attribute => "attr", :message => "message"}]}
8
+ )
9
+ errors.for(:level1).size.should == 1
10
+ errors.for(:level1)[0].code.should == "code1"
11
+ end
12
+
13
+ it "returns nil if there are no errors at the given scope" do
14
+ errors = Braintree::Errors.new(
15
+ :level1 => {:errors => [{:code => "code1", :attribute => "attr", :message => "message"}]}
16
+ )
17
+ errors.for(:no_errors_here).should == nil
18
+ end
19
+ end
20
+
21
+ describe "inspect" do
22
+ it "is better than the default inspect" do
23
+ errors = Braintree::Errors.new(
24
+ :level1 => {:errors => [{:code => "code1", :attribute => "attr", :message => "message"}]}
25
+ )
26
+ errors.inspect.should == "#<Braintree::Errors level1:[(code1) message]>"
27
+ end
28
+
29
+ it "shows errors 2 levels deep" do
30
+ errors = Braintree::Errors.new(
31
+ :level1 => {
32
+ :errors => [{:code => "code1", :attribute => "attr", :message => "message"}],
33
+ :level2 => {
34
+ :errors => [{:code => "code2", :attribute => "attr2", :message => "message2"}],
35
+ }
36
+ }
37
+ )
38
+ errors.inspect.should == "#<Braintree::Errors level1:[(code1) message], level1/level2:[(code2) message2]>"
39
+ end
40
+
41
+ it "shows errors 3 levels deep" do
42
+ errors = Braintree::Errors.new(
43
+ :level1 => {
44
+ :errors => [{:code => "code1", :attribute => "attr", :message => "message"}],
45
+ :level2 => {
46
+ :errors => [{:code => "code2", :attribute => "attr2", :message => "message2"}],
47
+ :level3 => {
48
+ :errors => [{:code => "code3", :attribute => "attr3", :message => "message3"}],
49
+ }
50
+ }
51
+ }
52
+ )
53
+ errors.inspect.should == "#<Braintree::Errors level1:[(code1) message], level1/level2:[(code2) message2], level1/level2/level3:[(code3) message3]>"
54
+ end
55
+ end
56
+
57
+ describe "size" do
58
+ it "returns the number of validation errors at the first level if only has one level" do
59
+ errors = Braintree::Errors.new(
60
+ :level1 => {:errors => [{:code => "1", :attribute => "attr", :message => "message"}]}
61
+ )
62
+ errors.size.should == 1
63
+ end
64
+
65
+ it "returns the total number of validation errors in the hierarchy" do
66
+ errors = Braintree::Errors.new(
67
+ :level1 => {
68
+ :errors => [{:code => "1", :attribute => "attr", :message => "message"}],
69
+ :level2 => {
70
+ :errors => [
71
+ {:code => "2", :attribute => "attr2", :message => "message2"},
72
+ {:code => "3", :attribute => "attr3", :message => "message3"}
73
+ ],
74
+ }
75
+ }
76
+ )
77
+ errors.size.should == 3
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Http do
4
+ describe "self._format_and_sanitize_body_for_log" do
5
+ it "adds [Braintree] before each line" do
6
+ input_xml = <<-END
7
+ <customer>
8
+ <first-name>Joe</first-name>
9
+ <last-name>Doe</last-name>
10
+ </customer>
11
+ END
12
+ expected_xml = <<-END
13
+ [Braintree] <customer>
14
+ [Braintree] <first-name>Joe</first-name>
15
+ [Braintree] <last-name>Doe</last-name>
16
+ [Braintree] </customer>
17
+ END
18
+ Braintree::Http._format_and_sanitize_body_for_log(input_xml).should == expected_xml
19
+ end
20
+
21
+ it "sanitizes credit card number and cvv" do
22
+ input_xml = <<-END
23
+ <customer>
24
+ <first-name>Joe</first-name>
25
+ <last-name>Doe</last-name>
26
+ <number>1234560000001234</number>
27
+ <cvv>123</cvv>
28
+ </customer>
29
+ END
30
+
31
+ expected_xml = <<-END
32
+ [Braintree] <customer>
33
+ [Braintree] <first-name>Joe</first-name>
34
+ [Braintree] <last-name>Doe</last-name>
35
+ [Braintree] <number>123456******1234</number>
36
+ [Braintree] <cvv>***</cvv>
37
+ [Braintree] </customer>
38
+ END
39
+ Braintree::Http._format_and_sanitize_body_for_log(input_xml).should == expected_xml
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,128 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe "Braintree::PagedCollection" do
4
+ it "includes enumerable" do
5
+ collection = Braintree::PagedCollection.new(:items => ["a"])
6
+ collection.detect { |item| item == "a" }.should == "a"
7
+ end
8
+
9
+ describe "[]" do
10
+ it "returns the element at the given index" do
11
+ collection = Braintree::PagedCollection.new(:items => ["one", "two", "three"])
12
+ collection[0].should == "one"
13
+ collection[2].should == "three"
14
+ collection[3].should == nil
15
+ end
16
+ end
17
+
18
+ describe "each" do
19
+ it "iterates over the contents" do
20
+ expected = ["apples", "bananas", "cherries"]
21
+ collection = Braintree::PagedCollection.new(
22
+ :items => expected
23
+ )
24
+ actual = []
25
+ collection.each do |item|
26
+ actual << item
27
+ end
28
+ actual.should == expected
29
+ end
30
+ end
31
+
32
+ describe "first" do
33
+ it "returns the first element" do
34
+ collection = Braintree::PagedCollection.new(
35
+ :items => ["apples", "bananas", "cherries"]
36
+ )
37
+ collection.first.should == "apples"
38
+ end
39
+ end
40
+
41
+ describe "initialize" do
42
+ it "initializes attributes as expected" do
43
+ collection = Braintree::PagedCollection.new(
44
+ :current_page_number => 1,
45
+ :page_size => 2,
46
+ :total_items => 4,
47
+ :items => ["apples", "bananas", "cherries"]
48
+ )
49
+ collection.current_page_number.should == 1
50
+ collection.page_size.should == 2
51
+ collection.total_items.should == 4
52
+ collection.items.should == ["apples", "bananas", "cherries"]
53
+ end
54
+ end
55
+
56
+ describe "last_page?" do
57
+ it "returns true if the page is the last page" do
58
+ collection = Braintree::PagedCollection.new(:current_page_number => 3, :page_size => 50, :total_items => 150)
59
+ collection.last_page?.should == true
60
+ end
61
+
62
+ it "returns false if the page is not the last page" do
63
+ collection = Braintree::PagedCollection.new(:current_page_number => 3, :page_size => 50, :total_items => 151)
64
+ collection.last_page?.should == false
65
+ end
66
+ end
67
+
68
+ describe "next_page" do
69
+ it "returns the next page of results" do
70
+ collection = Braintree::PagedCollection.new(
71
+ :current_page_number => 1,
72
+ :page_size => 1,
73
+ :total_items => 2
74
+ ) do |page_num|
75
+ "contents of page #{page_num}"
76
+ end
77
+ collection.next_page.should == "contents of page 2"
78
+ end
79
+
80
+ it "returns nil if on last page" do
81
+ collection = Braintree::PagedCollection.new(
82
+ :current_page_number => 2,
83
+ :page_size => 2,
84
+ :total_items => 4
85
+ )
86
+ collection.next_page.should == nil
87
+ end
88
+ end
89
+
90
+ describe "next_page_number" do
91
+ it "returns the next page number when not on the last page" do
92
+ collection = Braintree::PagedCollection.new(
93
+ :current_page_number => 2,
94
+ :page_size => 1,
95
+ :total_items => 50
96
+ )
97
+ collection.next_page_number.should == 3
98
+ end
99
+
100
+ it "returns nil when on the last page" do
101
+ collection = Braintree::PagedCollection.new(
102
+ :current_page_number => 1,
103
+ :page_size => 1,
104
+ :total_items => 1
105
+ )
106
+ collection.next_page_number.should == nil
107
+ end
108
+ end
109
+
110
+ describe "total_pages" do
111
+ it "calculates the total number of pages when total items is not evenly divisible by page size" do
112
+ collection = Braintree::PagedCollection.new(
113
+ :page_size => 5,
114
+ :total_items => 13
115
+ )
116
+ collection.total_pages.should == 3
117
+ end
118
+
119
+ it "calculates the total number of pages when total items is not evenly divisible by page size" do
120
+ collection = Braintree::PagedCollection.new(
121
+ :page_size => 5,
122
+ :total_items => 20
123
+ )
124
+ collection.total_pages.should == 4
125
+ end
126
+ end
127
+
128
+ end