braintree 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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