diff --git a/.gitignore b/.gitignore index d256830..ff9adbc 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .env coverage Gemfile.lock +pkg spec/examples.txt spec/vcr_cassettes diff --git a/.rubocop.yml b/.rubocop.yml index 8b2cb66..0d91bb7 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,6 +4,8 @@ require: AllCops: TargetRubyVersion: 2.6.4 + Exclude: + - bin/**/* Layout/AlignParameters: EnforcedStyle: with_fixed_indentation diff --git a/Rakefile b/Rakefile index b7e9ed5..b6ae734 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "bundler/gem_tasks" require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) -task :default => :spec +task default: :spec diff --git a/eml.gemspec b/eml.gemspec index c9cd53a..209a4a7 100644 --- a/eml.gemspec +++ b/eml.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/MorningCoffeeDev/eml_ruby" spec.license = "MIT" - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do + spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0"). reject { |f| f.match(%r{^(test|spec|features)/}) } end diff --git a/lib/eml.rb b/lib/eml.rb index 22c3358..6d2dbc7 100644 --- a/lib/eml.rb +++ b/lib/eml.rb @@ -30,6 +30,7 @@ module EML require "eml/lib/basic_auth/verify" require "eml/lib/constant_time_compare" require "eml/lib/endpoint_class" +require "eml/lib/model_hash" require "eml/model" require "eml/parameters" diff --git a/lib/eml/error/rest.rb b/lib/eml/error/rest.rb index 47ee025..1988415 100644 --- a/lib/eml/error/rest.rb +++ b/lib/eml/error/rest.rb @@ -16,27 +16,27 @@ class RESTError < Error def initialize(message = nil, response = nil) super(message) - @response = T.let(response, EML::Response) + @response = T.let(response, T.nilable(EML::Response)) end - sig { returns(String) } + sig { returns(T.nilable(String)) } def http_body - @response.error || @response.body.to_s + @response&.error || @response&.body&.to_s end - sig { returns(T::Hash[Symbol, String]) } + sig { returns(T.nilable(T::Hash[Symbol, String])) } def http_headers - @response.headers + @response&.headers end - sig { returns(Integer) } + sig { returns(T.nilable(Integer)) } def http_status - @response.status + @response&.http_status end - sig { returns(String) } + sig { returns(T.nilable(String)) } def url - @response.url.to_s + @response&.url&.to_s end end end diff --git a/lib/eml/lib/basic_auth/generate.rb b/lib/eml/lib/basic_auth/generate.rb index 4bdb2b9..552c9fd 100644 --- a/lib/eml/lib/basic_auth/generate.rb +++ b/lib/eml/lib/basic_auth/generate.rb @@ -16,7 +16,7 @@ class Generate ).returns(String) end def self.call(username, password, prefix: "") - new(username, password, prefix).call + new(username, password, prefix: prefix).call end sig do @@ -26,10 +26,10 @@ def self.call(username, password, prefix: "") prefix: String ).void end - def initialize(username, password, prefix) - @username = username - @password = password - @prefix = prefix + def initialize(username, password, prefix: "") + @username = T.let(username, String) + @password = T.let(password, String) + @prefix = T.let(prefix, String) end sig { returns(String) } diff --git a/lib/eml/lib/basic_auth/verify.rb b/lib/eml/lib/basic_auth/verify.rb index cd10366..c0454ed 100644 --- a/lib/eml/lib/basic_auth/verify.rb +++ b/lib/eml/lib/basic_auth/verify.rb @@ -8,7 +8,7 @@ class Verify sig do params( - auth_token: String, + auth_token: T.nilable(String), username: String, password: String ).returns(T::Boolean) @@ -19,15 +19,15 @@ def self.call(auth_token, username, password) sig do params( - auth_token: String, + auth_token: T.nilable(String), username: String, password: String ).void end def initialize(auth_token, username, password) - @auth_token = auth_token - @username = username - @password = password + @auth_token = T.let(auth_token || "", String) + @username = T.let(username, String) + @password = T.let(password, String) end sig { returns(T::Boolean) } @@ -40,6 +40,7 @@ def call private + sig { returns(String) } def parse_auth_token @auth_token.sub(/^[^\s]+\s/, "") end diff --git a/lib/eml/lib/constant_time_compare.rb b/lib/eml/lib/constant_time_compare.rb index f69fbe8..b09778f 100644 --- a/lib/eml/lib/constant_time_compare.rb +++ b/lib/eml/lib/constant_time_compare.rb @@ -12,8 +12,8 @@ def self.call(comparison, expected) sig { params(comparison: String, expected: String).void } def initialize(comparison, expected) - @comparison = comparison - @expected = expected + @comparison = T.let(comparison, String) + @expected = T.let(expected, String) end sig { returns(T::Boolean) } @@ -22,8 +22,8 @@ def call result = 0 - Hash[[@comparison.bytes, @expected.bytes].transpose]. - each { |x, y| result |= x ^ y } + transposed = [@comparison.bytes, @expected.bytes].transpose + Hash[transposed].each { |x, y| result |= x ^ y } result.zero? end diff --git a/lib/eml/lib/endpoint_class.rb b/lib/eml/lib/endpoint_class.rb index d5237bc..d609762 100644 --- a/lib/eml/lib/endpoint_class.rb +++ b/lib/eml/lib/endpoint_class.rb @@ -5,6 +5,10 @@ module EML class EndpointClass extend T::Sig + sig do + params(class_type: String, resource_class: T.untyped, endpoint: String). + returns(T.untyped) + end def self.call(class_type:, resource_class:, endpoint:) new( class_type: class_type, @@ -13,18 +17,25 @@ def self.call(class_type:, resource_class:, endpoint:) ).call end + sig do + params(class_type: String, resource_class: T.untyped, endpoint: String). + void + end def initialize(class_type:, resource_class:, endpoint:) - @class_type = class_type - @resource_class = resource_class - @endpoint = endpoint + @class_type = T.let(class_type, String) + @resource_class = T.let(resource_class, T.untyped) + @endpoint = T.let(endpoint, String) + @class_name = T.let(nil, T.nilable(String)) end + sig { returns(T.untyped) } def call Object.const_get(class_name) if Object.const_defined?(class_name) end private + sig { returns(String) } def class_name @class_name ||= begin name_parts = @resource_class.name.split("::") @@ -35,6 +46,7 @@ def class_name end end + sig { returns(String) } def action_class_name @endpoint.capitalize.sub(/s$/, "") end diff --git a/lib/eml/lib/model_hash.rb b/lib/eml/lib/model_hash.rb new file mode 100644 index 0000000..1a7d675 --- /dev/null +++ b/lib/eml/lib/model_hash.rb @@ -0,0 +1,54 @@ +# typed: strict +# frozen_string_literal: true + +module EML + class ModelHash + extend T::Sig + + sig { params(model: EML::Model).returns(T::Hash[Symbol, T.untyped]) } + def self.call(model) + new(model).call + end + + sig { params(model: EML::Model).void } + def initialize(model) + @model = T.let(model, EML::Model) + @hash = T.let({}, T::Hash[Symbol, T.untyped]) + end + + sig { returns(T::Hash[Symbol, T.untyped]) } + def call + @model.class.enumerate_fields do |_, local_name| + value = @model.public_send(local_name) + add_value(local_name, value) + end + + @hash + end + + private + + sig { params(name: Symbol, value: T.untyped).void } + def add_value(name, value) + @hash[name] = stored_value(value) + end + + sig { params(value: T.untyped).returns(T.untyped) } + def stored_value(value) + if value.is_a?(Array) + array_value(value) + elsif value.respond_to?(:to_h) + value.to_h + else + value + end + end + + sig { params(value: T::Array[T.untyped]).returns(T::Array[T.untyped]) } + def array_value(value) + value.each_with_object([]) do |item, array| + array << stored_value(item) + end + end + end +end diff --git a/lib/eml/model.rb b/lib/eml/model.rb index 4eb26fb..06abbf2 100644 --- a/lib/eml/model.rb +++ b/lib/eml/model.rb @@ -1,27 +1,52 @@ # typed: true # frozen_string_literal: true +require "json" + module EML class Model extend T::Sig + extend T::Helpers + abstract! + sig do + params( + fields: T.any(T::Hash[String, T.untyped], T::Array[String]) + ).void + end def self.fields(fields) const_set(:FIELDS, fields.freeze) - fields.each do |response_name, local_name| - local_name ||= response_name + enumerate_fields do |_, local_name| __send__(:attr_reader, :"#{local_name}") end end + sig { void } + def self.enumerate_fields + const_get(:FIELDS).each do |response_name, local_name| + local_name ||= response_name.to_sym + yield(response_name, local_name) + end + end + sig { params(raw_values: T::Hash[String, T.untyped]).void } def initialize(raw_values) - self.class::FIELDS.each do |response_name, local_name| - local_name ||= response_name + self.class.enumerate_fields do |response_name, local_name| value = field_value(response_name, raw_values[response_name]) instance_variable_set(:"@#{local_name}", value) end end + sig { returns(T::Hash[Symbol, T.untyped]) } + def to_h + ModelHash.(self) + end + + sig { params(_args: T.nilable(Array)).returns(String) } + def to_json(*_args) + to_h.to_json + end + protected sig { params(name: String, raw_value: T.untyped).returns(T.untyped) } diff --git a/lib/eml/parameters.rb b/lib/eml/parameters.rb index 4eab247..196b36c 100644 --- a/lib/eml/parameters.rb +++ b/lib/eml/parameters.rb @@ -24,7 +24,7 @@ class << self params: T::Hash[Symbol, T.untyped] ).returns(T.untyped) end - def self.convert(resource_class, endpoint, params) + def convert(resource_class, endpoint, params) endpoint_class = EML::EndpointClass.( class_type: ENDPOINT_CLASS_TYPE, resource_class: resource_class, endpoint: endpoint @@ -112,6 +112,7 @@ def validate_max_length(param_name, param_value, length) private + sig { params(array: T::Array[String]).returns(String) } def array_as_string(array) array.dup.tap { |vals| vals[-1] = "or #{vals.last}" }.join(", ") end diff --git a/lib/eml/response.rb b/lib/eml/response.rb index f26c27f..5d55e84 100644 --- a/lib/eml/response.rb +++ b/lib/eml/response.rb @@ -84,7 +84,7 @@ def raise_error(id: nil) sig { returns(T.nilable(EML::RESTError)) } def check_for_incorrectly_categorised_errors - if error.match?(/is not in (the proper|a valid) status/) + if error&.match?(/is not in (the proper|a valid) status/) raise T.unsafe(EML::REST::UnprocessableEntityError).new(error, self) end end diff --git a/lib/eml/uk.rb b/lib/eml/uk.rb index a8ffce8..95f07c4 100644 --- a/lib/eml/uk.rb +++ b/lib/eml/uk.rb @@ -12,8 +12,9 @@ module UK require "eml/uk/lib/endpoint_class" require "eml/uk/lib/parse_date" -require "eml/uk/models/tns_card" -require "eml/uk/models/tns_transaction" +require "eml/uk/models/tns/card" +require "eml/uk/models/tns/message" +require "eml/uk/models/tns/transaction" require "eml/uk/models/transaction" require "eml/uk/parameters" diff --git a/lib/eml/uk/api_resource.rb b/lib/eml/uk/api_resource.rb index a7e5e67..57063cb 100644 --- a/lib/eml/uk/api_resource.rb +++ b/lib/eml/uk/api_resource.rb @@ -15,6 +15,7 @@ class APIResource def initialize(id: nil) @id = T.let(id, T.nilable(String)) @headers = T.let(nil, T.nilable(T::Hash[String, String])) + @credentials = T.let(nil, T.nilable(T::Hash[Symbol, String])) end sig do @@ -50,13 +51,13 @@ def resource_url(endpoint) private - sig { returns(T::Hash[Symbol, T.nilable(String)]) } + sig { returns(T::Hash[Symbol, String]) } def credentials @credentials ||= begin config = EML::UK.config { - username: config.rest_username, - password: config.rest_password, + username: config.rest_username || "", + password: config.rest_password || "", } end end @@ -74,8 +75,8 @@ def domain def headers @headers ||= { "Authorization" => ::EML::BasicAuth::Generate.( - credentials[:username], - credentials[:password], + T.must(credentials[:username]), + T.must(credentials[:password]), prefix: "Basic " ), } diff --git a/lib/eml/uk/models/tns/card.rb b/lib/eml/uk/models/tns/card.rb new file mode 100644 index 0000000..5eb894a --- /dev/null +++ b/lib/eml/uk/models/tns/card.rb @@ -0,0 +1,22 @@ +# typed: true +# frozen_string_literal: true + +module EML + module UK + module Models + module TNS + class Card < ::EML::Model + fields( + "AvailableBalance" => :availableBalance, + "CarrierNumber" => :carrierNumber, + "ClientTrackingId" => :clientTrackingId, + "Currency" => :currency, + "ExternalId" => :externalId, + "Program" => :program, + "MerchantGroup" => :merchantGroup + ) + end + end + end + end +end diff --git a/lib/eml/uk/models/tns/message.rb b/lib/eml/uk/models/tns/message.rb new file mode 100644 index 0000000..7cc8ca2 --- /dev/null +++ b/lib/eml/uk/models/tns/message.rb @@ -0,0 +1,25 @@ +# typed: true +# frozen_string_literal: true + +module EML + module UK + module Models + module TNS + class Message < ::EML::Model + extend T::Sig + + fields("Transactions" => :transactions) + + sig { params(raw_values: T::Hash[Symbol, T.untyped]).void } + def initialize(raw_values) + @transactions = raw_values[:Transactions]. + each_with_object([]) do |raw_transaction, transactions| + transactions << EML::UK::Models::TNS::Transaction. + new(raw_transaction) + end + end + end + end + end + end +end diff --git a/lib/eml/uk/models/tns/transaction.rb b/lib/eml/uk/models/tns/transaction.rb new file mode 100644 index 0000000..211ea94 --- /dev/null +++ b/lib/eml/uk/models/tns/transaction.rb @@ -0,0 +1,51 @@ +# typed: true +# frozen_string_literal: true + +module EML + module UK + module Models + module TNS + class Transaction < ::EML::Model + extend T::Sig + + fields( + "AuthorizationRequestId" => :authorizationRequestId, + "Card" => :card, + "Cards" => :cards, + "EmlId" => :emlId, + "MerchantCategoryCode" => :merchantCategoryCode, + "MerchantCountry" => :merchantCountry, + "Note" => :note, + "OriginalTransactionDate" => :originalDate, + "PosTransactionTime" => :posTime, + "Reason" => :reason, + "Result" => :result, + "RetrievalReferenceNumber" => :retrievalReferenceNumber, + "TransactionAmount" => :amount, + "TransactionCurrency" => :currency, + "TransactionDescription" => :description, + "TransactionId" => :transactionId, + "TransactionLocation" => :location, + "TransactionTime" => :time + ) + + sig { params(raw_values: T::Hash[String, T.untyped]).void } + def initialize(raw_values) + super + initialize_cards + end + + private + + sig { void } + def initialize_cards + @card = Card.new(@card) unless @card.nil? + @cards = (@cards || []).each_with_object([]) do |card, cards| + cards << Card.new(card) + end + end + end + end + end + end +end diff --git a/lib/eml/uk/models/tns_card.rb b/lib/eml/uk/models/tns_card.rb deleted file mode 100644 index fb3e8f3..0000000 --- a/lib/eml/uk/models/tns_card.rb +++ /dev/null @@ -1,20 +0,0 @@ -# typed: true -# frozen_string_literal: true - -module EML - module UK - module Models - class TNSCard < ::EML::Model - fields( - "AvailableBalance" => :availableBalance, - "CarrierNumber" => :carrierNumber, - "ClientTrackingId" => :clientTrackingId, - "Currency" => :currency, - "ExternalId" => :externalId, - "Program" => :program, - "MerchantGroup" => :merchantGroup, - ) - end - end - end -end diff --git a/lib/eml/uk/models/tns_transaction.rb b/lib/eml/uk/models/tns_transaction.rb deleted file mode 100644 index 690958a..0000000 --- a/lib/eml/uk/models/tns_transaction.rb +++ /dev/null @@ -1,49 +0,0 @@ -# typed: true -# frozen_string_literal: true - -module EML - module UK - module Models - class TNSTransaction < ::EML::Model - extend T::Sig - - fields( - "AuthorizationRequestId" => :authorizationRequestId, - "Card" => :card, - "Cards" => :cards, - "EmlId" => :emlId, - "MerchantCategoryCode" => :merchantCategoryCode, - "MerchantCountry" => :merchantCountry, - "Note" => :note, - "OriginalTransactionDate" => :originalDate, - "PosTransactionTime" => :posTime, - "Reason" => :reason, - "Result" => :result, - "RetrievalReferenceNumber" => :retrievalReferenceNumber, - "TransactionAmount" => :amount, - "TransactionCurrency" => :currency, - "TransactionDescription" => :description, - "TransactionId" => :transactionId, - "TransactionLocation" => :location, - "TransactionTime" => :time - ) - - sig { params(raw_values: T::Hash[String, T.untyped]).void } - def initialize(raw_values) - super - initialize_cards - end - - private - - sig { void } - def initialize_cards - @card = TNSCard.new(@card) unless @card.nil? - @cards = (@cards || []).each_with_object([]) do |card, cards| - cards << TNSCard.new(card) - end - end - end - end - end -end diff --git a/lib/eml/uk/models/transaction.rb b/lib/eml/uk/models/transaction.rb index b2a4c58..99a675d 100644 --- a/lib/eml/uk/models/transaction.rb +++ b/lib/eml/uk/models/transaction.rb @@ -38,7 +38,7 @@ class Transaction < ::EML::Model sig { params(field: String, raw_value: T.untyped).returns(T.untyped) } def field_value(field, raw_value) if field.match?(/date|time/) - EML::UK::ParseDate.(raw_value) + ::EML::UK::ParseDate.(raw_value) else raw_value end diff --git a/lib/eml/uk/parameters.rb b/lib/eml/uk/parameters.rb index ee460cf..6184602 100644 --- a/lib/eml/uk/parameters.rb +++ b/lib/eml/uk/parameters.rb @@ -27,7 +27,7 @@ class << self end def convert(resource_class, endpoint, params) endpoint_class = EML::UK::EndpointClass.( - class_type: self::ENDPOINT_CLASS_TYPE, + class_type: const_get(:ENDPOINT_CLASS_TYPE), resource_class: resource_class, endpoint: endpoint ) @@ -40,10 +40,13 @@ def convert(resource_class, endpoint, params) protected - SEARCH_PARAMETER_OPTIONS = %w[ - ActualCardNumber CarrierNumber ClientTrackingId ExternalId - PaymentTrackingID PrintText - ].freeze + SEARCH_PARAMETER_OPTIONS = T.let( + %w[ + ActualCardNumber CarrierNumber ClientTrackingId ExternalId + PaymentTrackingID PrintText + ].freeze, + T::Array[String] + ) sig { params(value: String).void } def validate_search_parameter(value) diff --git a/lib/eml/uk/payload.rb b/lib/eml/uk/payload.rb index 16d1905..459cac3 100644 --- a/lib/eml/uk/payload.rb +++ b/lib/eml/uk/payload.rb @@ -26,7 +26,7 @@ class << self end def convert(resource_class, endpoint, payload) endpoint_class = EML::UK::EndpointClass.( - class_type: self::ENDPOINT_CLASS_TYPE, + class_type: const_get(:ENDPOINT_CLASS_TYPE), resource_class: resource_class, endpoint: endpoint ) diff --git a/lib/eml/uk/responses/card/transaction.rb b/lib/eml/uk/responses/card/transaction.rb index 071a48e..83626c8 100644 --- a/lib/eml/uk/responses/card/transaction.rb +++ b/lib/eml/uk/responses/card/transaction.rb @@ -10,6 +10,16 @@ class Transaction < ::EML::UK::Response field :count + sig { params(response: HTTP::Response, id: T.nilable(String)).void } + def initialize(response, id: nil) + super + + @transactions = T.let( + nil, + T.nilable(T::Array[::EML::UK::Models::Transaction]) + ) + end + sig { returns(T::Array[::EML::UK::Models::Transaction]) } def transactions @transactions ||= body["transactions"]. diff --git a/lib/eml/uk/tns/process_request.rb b/lib/eml/uk/tns/process_request.rb index 6994107..a485d0d 100644 --- a/lib/eml/uk/tns/process_request.rb +++ b/lib/eml/uk/tns/process_request.rb @@ -11,7 +11,7 @@ class ProcessRequest params( auth_token: String, parameters: T::Hash[Symbol, T.untyped] - ).returns(EML::UK::TNS::Response) + ).returns(EML::UK::Models::TNS::Message) end def self.call(auth_token, parameters) new(auth_token, parameters).call @@ -24,14 +24,15 @@ def self.call(auth_token, parameters) ).void end def initialize(auth_token, parameters) - @auth_token = auth_token - @parameters = parameters + @auth_token = T.let(auth_token, String) + @parameters = T.let(parameters, T::Hash[Symbol, T.untyped]) + @credentials = T.let(nil, T.nilable(T::Hash[Symbol, T.untyped])) end - sig { returns(EML::UK::TNS::Response) } + sig { returns(EML::UK::Models::TNS::Message) } def call verify_auth_token - EML::UK::TNS::Response.new(@parameters) + EML::UK::Models::TNS::Message.new(@parameters) end private diff --git a/lib/eml/uk/tns/response.rb b/lib/eml/uk/tns/response.rb index a8d062e..a738069 100644 --- a/lib/eml/uk/tns/response.rb +++ b/lib/eml/uk/tns/response.rb @@ -7,13 +7,27 @@ module TNS class Response extend T::Sig + sig { returns(T::Array[EML::UK::Models::TNS::Transaction]) } attr_reader :transactions sig { params(response: T::Hash[Symbol, T.untyped]).void } def initialize(response) - @transactions = response[:Transactions]. + @transactions = T.let( + model_transactions(response), + T::Array[EML::UK::Models::TNS::Transaction] + ) + end + + private + + sig do + params(response: T::Hash[Symbol, T.untyped]). + returns(T::Array[EML::UK::Models::TNS::Transaction]) + end + def model_transactions(response) + response[:Transactions]. each_with_object([]) do |raw_transaction, transactions| - transactions << EML::UK::Models::TNSTransaction. + transactions << EML::UK::Models::TNS::Transaction. new(raw_transaction) end end diff --git a/lib/eml/version.rb b/lib/eml/version.rb index 352f607..3c69a81 100644 --- a/lib/eml/version.rb +++ b/lib/eml/version.rb @@ -2,5 +2,5 @@ # frozen_string_literal: true module EML - VERSION = "2.0.0" + VERSION = "2.1.0" end diff --git a/spec/helpers/tns_uk_helper.rb b/spec/helpers/tns_uk_helper.rb index 575ddb1..ce1f120 100644 --- a/spec/helpers/tns_uk_helper.rb +++ b/spec/helpers/tns_uk_helper.rb @@ -6,37 +6,41 @@ module Helpers module TNSUK extend T::Sig - TRANSACTION = { - "TransactionId" => 123_456_789, - "EmlId" => nil, - "TransactionTime" => "2020-01-01T00:00:00.1234567-06:00", - "TransactionAmount" => 1.0, - "TransactionDescription" => "Unload", - "TransactionCurrency" => "GBP", - "TransactionLocation" => "", - "Reason" => "Active", - "Result" => "Unlocked", - "Note" => "Testing", - "MerchantCategoryCode" => "", - "MerchantCountry" => "", - "PosTransactionTime" => nil, - "OriginalTransactionDate" => nil, - "AuthorizationRequestId" => "", - "RetrievalReferenceNumber" => "", - "Card" => { - "AvailableBalance" => 1.23, - "ExternalId" => "ABCDEFGHIJKLMNOP", - "ClientTrackingId" => "ABCDEFGHIJ", - "Program" => "Program123", - "MerchantGroup" => "Merchant12", - "Currency" => "GBP", - "CarrierNumber" => nil, - }, - }.freeze + TRANSACTION = T.let( + { + "TransactionId" => 123_456_789, + "EmlId" => nil, + "TransactionTime" => "2020-01-01T00:00:00.1234567-06:00", + "TransactionAmount" => 1.0, + "TransactionDescription" => "Unload", + "TransactionCurrency" => "GBP", + "TransactionLocation" => "", + "Reason" => "Active", + "Result" => "Unlocked", + "Note" => "Testing", + "MerchantCategoryCode" => "", + "MerchantCountry" => "", + "PosTransactionTime" => nil, + "OriginalTransactionDate" => nil, + "AuthorizationRequestId" => "", + "RetrievalReferenceNumber" => "", + "Card" => { + "AvailableBalance" => 1.23, + "ExternalId" => "ABCDEFGHIJKLMNOP", + "ClientTrackingId" => "ABCDEFGHIJ", + "Program" => "Program123", + "MerchantGroup" => "Merchant12", + "Currency" => "GBP", + "CarrierNumber" => nil, + }, + }.freeze, + T::Hash[String, T.untyped] + ) - RESPONSE = { - Transactions: [TRANSACTION], - }.freeze + RESPONSE = T.let( + { Transactions: [TRANSACTION] }.freeze, + T::Hash[Symbol, T::Array[T::Hash[String, T.untyped]]] + ) end end end diff --git a/spec/lib/basic_auth/verify_spec.rb b/spec/lib/basic_auth/verify_spec.rb index bfab15b..ea70cef 100644 --- a/spec/lib/basic_auth/verify_spec.rb +++ b/spec/lib/basic_auth/verify_spec.rb @@ -2,12 +2,12 @@ # frozen_string_literal: true RSpec.describe EML::BasicAuth::Verify do + subject { described_class.(token, username, password) } + let(:expected_token) { "dXNlcm5hbWU6cGFzc3dvcmQ=" } let(:username) { "username" } let(:password) { "password" } - subject { described_class.(token, username, password) } - context "when the token is valid for the username and password" do let(:token) { expected_token } diff --git a/spec/lib/constant_time_compare_spec.rb b/spec/lib/constant_time_compare_spec.rb index 8f5d9ff..c9973cf 100644 --- a/spec/lib/constant_time_compare_spec.rb +++ b/spec/lib/constant_time_compare_spec.rb @@ -2,7 +2,7 @@ # frozen_string_literal: true RSpec.describe EML::ConstantTimeCompare do - subject { described_class.(expected, comparison) } + subject(:compare) { described_class.(expected, comparison) } let(:expected) { "expected" } @@ -29,13 +29,13 @@ let(:expected) { 1 } let(:comparison) { "expected" } - specify { expect { subject }.to raise_error TypeError } + specify { expect { compare }.to raise_error TypeError } end context "when the comparison value is an integer" do let(:comparison) { 1 } - specify { expect { subject }.to raise_error TypeError } + specify { expect { compare }.to raise_error TypeError } end end end diff --git a/spec/model_spec.rb b/spec/model_spec.rb new file mode 100644 index 0000000..784cc77 --- /dev/null +++ b/spec/model_spec.rb @@ -0,0 +1,59 @@ +# typed: ignore +# frozen_string_literal: true + +RSpec.describe EML::Model do + before do + test_model = Class.new(::EML::Model) do + fields( + "First" => :first, + "Second" => :second, + "Third" => :third, + "Fourth" => :fourth, + "Fifth" => :fifth + ) + end + stub_const("TestModel", test_model) + end + + let(:params) do + { + "First" => "A", + "Second" => 1, + "Third" => Time.now, + "Fourth" => { a: "a" }, + "Fifth" => %w[a b], + } + end + + describe "#to_h" do + let(:expected_hash) do + { + first: params["First"], + second: params["Second"], + third: params["Third"], + fourth: params["Fourth"], + fifth: params["Fifth"], + } + end + + it "converts the model to a hash" do + expect(TestModel.new(params).to_h).to eq(expected_hash) + end + end + + describe "#to_json" do + let(:expected_string) do + { + first: params["First"], + second: params["Second"], + third: params["Third"], + fourth: params["Fourth"], + fifth: params["Fifth"], + }.to_json + end + + it "converts the model to a JSON string" do + expect(TestModel.new(params).to_json).to eq(expected_string) + end + end +end