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,38 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ require 'timeout'
4
+ require 'socket'
5
+
6
+
7
+ def start_ssl_server
8
+ web_server_pid_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "httpsd.pid"))
9
+
10
+ TCPSocket.class_eval do
11
+ def self.wait_for_service(options)
12
+ Timeout::timeout(options[:timeout] || 20) do
13
+ loop do
14
+ begin
15
+ socket = TCPSocket.new(options[:host], options[:port])
16
+ socket.close
17
+ return
18
+ rescue Errno::ECONNREFUSED
19
+ sleep 0.5
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ FileUtils.rm(web_server_pid_file) if File.exist?(web_server_pid_file)
27
+ command = File.expand_path(File.join(File.dirname(__FILE__), "..", "script", "httpsd.rb"))
28
+ #puts command
29
+ `#{command} #{web_server_pid_file}`
30
+ #puts "== waiting for web server - port: #{8433}"
31
+ TCPSocket.wait_for_service :host => "127.0.0.1", :port => 8443
32
+
33
+ yield
34
+
35
+ 10.times { unless File.exists?(web_server_pid_file); sleep 1; end }
36
+ #puts "\n== killing web server - pid: #{File.read(web_server_pid_file).to_i}"
37
+ Process.kill "INT", File.read(web_server_pid_file).to_i
38
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require 'webrick'
3
+ require 'webrick/https'
4
+ require 'openssl'
5
+
6
+ private_key_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "ssl", "privateKey.key"))
7
+ cert_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "ssl", "certificate.crt"))
8
+
9
+ pkey = OpenSSL::PKey::RSA.new(File.read(private_key_file))
10
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
11
+
12
+ pid_file = ARGV[0]
13
+
14
+ s = WEBrick::HTTPServer.new(
15
+ :Port => 8443,
16
+ :Logger => WEBrick::Log::new(nil, WEBrick::Log::ERROR),
17
+ :DocumentRoot => File.join(File.dirname(__FILE__)),
18
+ :ServerType => WEBrick::Daemon,
19
+ :SSLEnable => true,
20
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
21
+ :SSLCertificate => cert,
22
+ :SSLPrivateKey => pkey,
23
+ :SSLCertName => [ [ "CN",WEBrick::Utils::getservername ] ],
24
+ :StartCallback => proc { File.open(pid_file, "w") { |f| f.write $$.to_s }}
25
+ )
26
+ trap("INT"){ s.shutdown }
27
+ s.start
@@ -0,0 +1,41 @@
1
+ unless defined?(SPEC_HELPER_LOADED)
2
+ SPEC_HELPER_LOADED = true
3
+
4
+ project_root = File.expand_path(File.dirname(__FILE__) + "/..")
5
+ require "rubygems"
6
+ gem "libxml-ruby", ENV["LIBXML_VERSION"] || "1.1.3"
7
+ gem "builder", ENV["BUILDER_VERSION"] || "2.1.2"
8
+ braintree_lib = "#{project_root}/lib"
9
+ $LOAD_PATH << braintree_lib
10
+ require "braintree"
11
+
12
+ Braintree::Configuration.environment = :development
13
+ Braintree::Configuration.merchant_id = "integration_merchant_id"
14
+ Braintree::Configuration.public_key = "integration_public_key"
15
+ Braintree::Configuration.private_key = "integration_private_key"
16
+ Braintree::Configuration.logger = Logger.new("/dev/null")
17
+ Braintree::Configuration.logger.level = Logger::INFO
18
+
19
+ Spec::Runner.configure do |config|
20
+ end
21
+
22
+ module SpecHelper
23
+ def self.stub_time_dot_now(desired_time)
24
+ Time.class_eval do
25
+ class << self
26
+ alias original_now now
27
+ end
28
+ end
29
+ (class << Time; self; end).class_eval do
30
+ define_method(:now) { desired_time }
31
+ end
32
+ yield
33
+ ensure
34
+ Time.class_eval do
35
+ class << self
36
+ alias now original_now
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,86 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Address do
4
+ describe "==" do
5
+ it "returns true if given an address with the same id and customer_id" do
6
+ first = Braintree::Address._new(:customer_id => "c1", :id => 'a1')
7
+ second = Braintree::Address._new(:customer_id => "c1", :id => "a1")
8
+
9
+ first.should == second
10
+ second.should == first
11
+ end
12
+
13
+ it "returns false if given an address with a different id and the same customer_id" do
14
+ first = Braintree::Address._new(:customer_id => "c1", :id => "a1")
15
+ second = Braintree::Address._new(:customer_id => "c1", :id => "not a1")
16
+
17
+ first.should_not == second
18
+ second.should_not == first
19
+ end
20
+
21
+ it "returns false if given an address with a different customer_id and the same id" do
22
+ first = Braintree::Address._new(:customer_id => "c1", :id => "a1")
23
+ second = Braintree::Address._new(:customer_id => "not c1", :id => "a1")
24
+
25
+ first.should_not == second
26
+ second.should_not == first
27
+ end
28
+
29
+ it "returns false when not given an address" do
30
+ address = Braintree::Address._new(:id => "a1")
31
+ address.should_not == "not an address"
32
+ end
33
+ end
34
+
35
+ describe "self.create" do
36
+ it "raises an ArgumentError if not given a :customer_id" do
37
+ expect do
38
+ Braintree::Address.create({})
39
+ end.to raise_error(ArgumentError, "Expected hash to contain a :customer_id")
40
+ end
41
+
42
+ it "raises if customer id contains invalid chars" do
43
+ expect do
44
+ Braintree::Address.create(:customer_id => "invalid@chars")
45
+ end.to raise_error(ArgumentError, ":customer_id contains invalid characters")
46
+ end
47
+
48
+ it "raises an exception if hash includes an invalid key" do
49
+ expect do
50
+ Braintree::Address.create(:street_address => "123 E Main St", :invalid_key => "foo")
51
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
52
+ end
53
+ end
54
+
55
+ describe "self.update" do
56
+ it "raises an exception if hash includes an invalid key" do
57
+ expect do
58
+ Braintree::Address.update("customer_id", "address_id", :street_address => "456 E Main", :invalid_key => "foo")
59
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
60
+ end
61
+ end
62
+
63
+ describe "self.find" do
64
+ it "raises an error if customer_id contains invalid chars" do
65
+ expect do
66
+ Braintree::Address.find("spaces not allowed", "address_id")
67
+ end.to raise_error(ArgumentError, "customer_id contains invalid characters")
68
+ end
69
+ end
70
+
71
+ describe "self.new" do
72
+ it "is protected" do
73
+ expect do
74
+ Braintree::Address.new
75
+ end.to raise_error(NoMethodError, /protected method .new/)
76
+ end
77
+ end
78
+
79
+ describe "update" do
80
+ it "raises an exception if hash includes an invalid key" do
81
+ expect do
82
+ Braintree::Address._new({}).update(:street_address => "456 E Main", :invalid_key2 => "foo")
83
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key2")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,190 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::Configuration do
4
+
5
+ before do
6
+ @original_merchant_id = Braintree::Configuration.merchant_id
7
+ @original_public_key = Braintree::Configuration.public_key
8
+ @original_private_key = Braintree::Configuration.private_key
9
+ @original_environment = Braintree::Configuration.environment
10
+ end
11
+
12
+ after do
13
+ Braintree::Configuration.merchant_id = @original_merchant_id
14
+ Braintree::Configuration.public_key = @original_public_key
15
+ Braintree::Configuration.private_key = @original_private_key
16
+ Braintree::Configuration.environment = @original_environment
17
+ end
18
+
19
+ describe "self.base_merchant_path" do
20
+ it "returns /merchants/{merchant_id}" do
21
+ Braintree::Configuration.base_merchant_path.should == "/merchants/integration_merchant_id"
22
+ end
23
+ end
24
+
25
+ describe "self.base_merchant_url" do
26
+ it "returns the expected url for the development env" do
27
+ Braintree::Configuration.environment = :development
28
+ Braintree::Configuration.base_merchant_url.should == "http://localhost:3000/merchants/integration_merchant_id"
29
+ end
30
+
31
+ it "returns the expected url for the sandbox env" do
32
+ Braintree::Configuration.environment = :sandbox
33
+ Braintree::Configuration.base_merchant_url.should == "https://sandbox.braintreegateway.com:443/merchants/integration_merchant_id"
34
+ end
35
+
36
+ it "returns the expected url for the production env" do
37
+ Braintree::Configuration.environment = :production
38
+ Braintree::Configuration.base_merchant_url.should == "https://www.braintreegateway.com:443/merchants/integration_merchant_id"
39
+ end
40
+ end
41
+
42
+ describe "self.ca_file" do
43
+ it "qa" do
44
+ Braintree::Configuration.environment = :qa
45
+ ca_file = Braintree::Configuration.ca_file
46
+ ca_file.should match(/valicert_ca.crt$/)
47
+ File.exists?(ca_file).should == true
48
+ end
49
+
50
+ it "sandbox" do
51
+ Braintree::Configuration.environment = :sandbox
52
+ ca_file = Braintree::Configuration.ca_file
53
+ ca_file.should match(/valicert_ca.crt$/)
54
+ File.exists?(ca_file).should == true
55
+ end
56
+
57
+ it "production" do
58
+ Braintree::Configuration.environment = :production
59
+ ca_file = Braintree::Configuration.ca_file
60
+ ca_file.should match(/securetrust_ca.crt$/)
61
+ File.exists?(ca_file).should == true
62
+ end
63
+ end
64
+
65
+ describe "self.environment" do
66
+ it "raises an exception if it hasn't been set yet" do
67
+ Braintree::Configuration.instance_variable_set(:@environment, nil)
68
+ expect do
69
+ Braintree::Configuration.environment
70
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.environment needs to be set")
71
+ end
72
+ end
73
+
74
+ describe "self.environment=" do
75
+ it "raises an exception if the environment is invalid" do
76
+ expect do
77
+ Braintree::Configuration.environment = :invalid_environment
78
+ end.to raise_error(ArgumentError, ":invalid_environment is not a valid environment")
79
+ end
80
+ end
81
+
82
+ describe "self.logger" do
83
+ it "defaults to logging to stdout with log_level info" do
84
+ begin
85
+ old_logger = Braintree::Configuration.logger
86
+ Braintree::Configuration.logger = nil
87
+ Braintree::Configuration.logger.level.should == Logger::INFO
88
+ ensure
89
+ Braintree::Configuration.logger = old_logger
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "self.merchant_id" do
95
+ it "raises an exception if it hasn't been set yet" do
96
+ Braintree::Configuration.instance_variable_set(:@merchant_id, nil)
97
+ expect do
98
+ Braintree::Configuration.merchant_id
99
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.merchant_id needs to be set")
100
+ end
101
+ end
102
+
103
+ describe "self.public_key" do
104
+ it "raises an exception if it hasn't been set yet" do
105
+ Braintree::Configuration.instance_variable_set(:@public_key, nil)
106
+ expect do
107
+ Braintree::Configuration.public_key
108
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.public_key needs to be set")
109
+ end
110
+ end
111
+
112
+ describe "self.private_key" do
113
+ it "raises an exception if it hasn't been set yet" do
114
+ Braintree::Configuration.instance_variable_set(:@private_key, nil)
115
+ expect do
116
+ Braintree::Configuration.private_key
117
+ end.to raise_error(Braintree::ConfigurationError, "Braintree::Configuration.private_key needs to be set")
118
+ end
119
+ end
120
+
121
+ describe "self.port" do
122
+ it "is 443 for production" do
123
+ Braintree::Configuration.environment = :production
124
+ Braintree::Configuration.port.should == 443
125
+ end
126
+
127
+ it "is 443 for sandbox" do
128
+ Braintree::Configuration.environment = :sandbox
129
+ Braintree::Configuration.port.should == 443
130
+ end
131
+
132
+ it "is 3000 for development" do
133
+ Braintree::Configuration.environment = :development
134
+ Braintree::Configuration.port.should == 3000
135
+ end
136
+ end
137
+
138
+ describe "self.protocol" do
139
+ it "is http for development" do
140
+ Braintree::Configuration.environment = :development
141
+ Braintree::Configuration.protocol.should == "http"
142
+ end
143
+
144
+ it "is https for production" do
145
+ Braintree::Configuration.environment = :production
146
+ Braintree::Configuration.protocol.should == "https"
147
+ end
148
+
149
+ it "is https for sandbox" do
150
+ Braintree::Configuration.environment = :sandbox
151
+ Braintree::Configuration.protocol.should == "https"
152
+ end
153
+
154
+ end
155
+
156
+ describe "self.server" do
157
+ it "is localhost for development" do
158
+ Braintree::Configuration.environment = :development
159
+ Braintree::Configuration.server.should == "localhost"
160
+ end
161
+
162
+ it "is www.braintreegateway.com for production" do
163
+ Braintree::Configuration.environment = :production
164
+ Braintree::Configuration.server.should == "www.braintreegateway.com"
165
+ end
166
+
167
+ it "is sandbox.braintreegateway.com for sandbox" do
168
+ Braintree::Configuration.environment = :sandbox
169
+ Braintree::Configuration.server.should == "sandbox.braintreegateway.com"
170
+ end
171
+ end
172
+
173
+ describe "self.ssl?" do
174
+ it "returns false for development" do
175
+ Braintree::Configuration.environment = :development
176
+ Braintree::Configuration.ssl?.should == false
177
+ end
178
+
179
+ it "returns true for production" do
180
+ Braintree::Configuration.environment = :production
181
+ Braintree::Configuration.ssl?.should == true
182
+ end
183
+
184
+ it "returns true for sandbox" do
185
+ Braintree::Configuration.environment = :sandbox
186
+ Braintree::Configuration.ssl?.should == true
187
+ end
188
+ end
189
+
190
+ end
@@ -0,0 +1,137 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Braintree::CreditCard do
4
+ describe "self.create" do
5
+ it "raises an exception if attributes contain an invalid key" do
6
+ expect do
7
+ Braintree::CreditCard.create(:invalid_key => 'val')
8
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
9
+ end
10
+ end
11
+
12
+ describe "self.create_from_transparent_redirect" do
13
+ it "raises an exception if the query string is forged" do
14
+ expect do
15
+ Braintree::CreditCard.create_from_transparent_redirect("forged=query_string")
16
+ end.to raise_error(Braintree::ForgedQueryString)
17
+ end
18
+ end
19
+
20
+ describe "self.create_credit_card_url" do
21
+ it "returns the url" do
22
+ Braintree::CreditCard.create_credit_card_url.should == "http://localhost:3000/merchants/integration_merchant_id/payment_methods/all/create_via_transparent_redirect_request"
23
+ end
24
+ end
25
+
26
+ describe "==" do
27
+ it "returns true if given a credit card with the same token" do
28
+ first = Braintree::CreditCard._new(:token => 123)
29
+ second = Braintree::CreditCard._new(:token => 123)
30
+
31
+ first.should == second
32
+ second.should == first
33
+ end
34
+
35
+ it "returns false if given a credit card with a different token" do
36
+ first = Braintree::CreditCard._new(:token => 123)
37
+ second = Braintree::CreditCard._new(:token => 124)
38
+
39
+ first.should_not == second
40
+ second.should_not == first
41
+ end
42
+
43
+ it "returns false if not given a credit card" do
44
+ credit_card = Braintree::CreditCard._new(:token => 123)
45
+ credit_card.should_not == "not a credit card"
46
+ end
47
+ end
48
+
49
+ describe "default?" do
50
+ it "is true if the credit card is the default credit card for the customer" do
51
+ Braintree::CreditCard._new(:default => true).default?.should == true
52
+ end
53
+
54
+ it "is false if the credit card is not the default credit card for the customer" do
55
+ Braintree::CreditCard._new(:default => false).default?.should == false
56
+ end
57
+ end
58
+
59
+ describe "expired?" do
60
+ it "is true if the payment method is this year and the month has passed" do
61
+ SpecHelper.stub_time_dot_now(Time.mktime(2009, 10, 20)) do
62
+ expired_pm = Braintree::CreditCard._new(:expiration_month => "09", :expiration_year => "2009")
63
+ expired_pm.expired?.should == true
64
+ end
65
+ end
66
+
67
+ it "is true if the payment method is in a previous year" do
68
+ expired_pm = Braintree::CreditCard._new(:expiration_month => "12", :expiration_year => (Time.now.year - 1).to_s)
69
+ expired_pm.expired?.should == true
70
+ end
71
+
72
+ it "is false if the payment method is not expired" do
73
+ not_expired_pm = Braintree::CreditCard._new(:expiration_month => "01", :expiration_year => (Time.now.year + 1).to_s)
74
+ not_expired_pm.expired?.should == false
75
+ end
76
+ end
77
+
78
+ describe "inspect" do
79
+ it "includes the token first" do
80
+ output = Braintree::CreditCard._new(:token => "cc123").inspect
81
+ output.should include("#<Braintree::CreditCard token: \"cc123\",")
82
+ end
83
+
84
+ it "includes all customer attributes" do
85
+ credit_card = Braintree::CreditCard._new(
86
+ :bin => "411111",
87
+ :card_type => "Visa",
88
+ :cardholder_name => "John Miller",
89
+ :created_at => Time.now,
90
+ :customer_id => "cid1",
91
+ :expiration_month => "01",
92
+ :expiration_year => "2020",
93
+ :last_4 => "1111",
94
+ :token => "tok1",
95
+ :updated_at => Time.now
96
+ )
97
+ output = credit_card.inspect
98
+ output.should include(%q(bin: "411111"))
99
+ output.should include(%q(card_type: "Visa"))
100
+ output.should include(%q(cardholder_name: "John Miller"))
101
+
102
+ output.should include(%q(customer_id: "cid1"))
103
+ output.should include(%q(expiration_month: "01"))
104
+ output.should include(%q(expiration_year: "2020"))
105
+ output.should include(%q(last_4: "1111"))
106
+ output.should include(%q(token: "tok1"))
107
+ output.should include(%Q(updated_at: #{credit_card.updated_at.inspect}))
108
+ output.should include(%Q(created_at: #{credit_card.created_at.inspect}))
109
+ end
110
+ end
111
+
112
+ describe "masked_number" do
113
+ it "uses the bin and last_4 to build the masked number" do
114
+ credit_card = Braintree::CreditCard._new(
115
+ :bin => "510510",
116
+ :last_4 => "5100"
117
+ )
118
+ credit_card.masked_number.should == "510510******5100"
119
+ end
120
+ end
121
+
122
+ describe "self.update" do
123
+ it "raises an exception if attributes contain an invalid key" do
124
+ expect do
125
+ Braintree::CreditCard._new({}).update(:invalid_key => 'val')
126
+ end.to raise_error(ArgumentError, "invalid keys: invalid_key")
127
+ end
128
+ end
129
+
130
+ describe "self.new" do
131
+ it "is protected" do
132
+ expect do
133
+ Braintree::CreditCard.new
134
+ end.to raise_error(NoMethodError, /protected method .new/)
135
+ end
136
+ end
137
+ end