Skip to content

Commit

Permalink
Fix case when the longest prefix does not satisfy the length requirement
Browse files Browse the repository at this point in the history
  • Loading branch information
khasanovbi committed Aug 18, 2019
1 parent 4d07519 commit 4b93e7f
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 37 deletions.
37 changes: 24 additions & 13 deletions paymentsystem/payment_system.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package paymentsystem

import (
"errors"
"strconv"

"github.com/armon/go-radix"
Expand Down Expand Up @@ -42,13 +43,15 @@ func getPaymentSystemFromValue(v interface{}, creditCardLength int, ignoreLength
return nil
}

type paymentSystemDB struct {
var errNonUniquePrefix = errors.New("non unique prefix")

type radixDB struct {
tree *radix.Tree
}

func (p *paymentSystemDB) findPaymentSystem(creditCard string, ignoreLengthCheck bool) (paymentSystem *PaymentSystem) {
func (r *radixDB) findPaymentSystem(creditCard string, ignoreLengthCheck bool) (paymentSystem *PaymentSystem) {
creditCardLength := len(creditCard)
prefix, value, ok := p.tree.LongestPrefix(creditCard)
prefix, value, ok := r.tree.LongestPrefix(creditCard)
if !ok {
return nil
}
Expand All @@ -57,22 +60,25 @@ func (p *paymentSystemDB) findPaymentSystem(creditCard string, ignoreLengthCheck
if paymentSystem != nil {
return paymentSystem
}
p.tree.WalkPath(prefix, func(s string, v interface{}) bool {
paymentSystem = getPaymentSystemFromValue(v, creditCardLength, ignoreLengthCheck)
r.tree.WalkPath(prefix, func(s string, v interface{}) bool {
currentPaymentSystem := getPaymentSystemFromValue(v, creditCardLength, ignoreLengthCheck)
if currentPaymentSystem != nil {
paymentSystem = currentPaymentSystem
}
return false
})
return
}

func (p *paymentSystemDB) FindPaymentSystem(creditCard string) (paymentSystem *PaymentSystem) {
return p.findPaymentSystem(creditCard, false)
func (r *radixDB) FindPaymentSystem(creditCard string) (paymentSystem *PaymentSystem) {
return r.findPaymentSystem(creditCard, false)
}

func (p *paymentSystemDB) FindPaymentSystemByPrefix(creditCardPrefix string) (paymentSystem *PaymentSystem) {
return p.findPaymentSystem(creditCardPrefix, true)
func (r *radixDB) FindPaymentSystemByPrefix(creditCardPrefix string) (paymentSystem *PaymentSystem) {
return r.findPaymentSystem(creditCardPrefix, true)
}

func (p *paymentSystemDB) InitFromMap(rawPaymentSystems map[PaymentSystem][]paymentSystemInfo) error {
func (r *radixDB) InitFromMap(rawPaymentSystems map[PaymentSystem][]paymentSystemInfo) error {
for paymentSystem, paymentSystemParams := range rawPaymentSystems {
for i := range paymentSystemParams {
paymentSystemParam := paymentSystemParams[i]
Expand All @@ -87,14 +93,15 @@ func (p *paymentSystemDB) InitFromMap(rawPaymentSystems map[PaymentSystem][]paym
}
for _, prefix := range prefixes {
newValue := &radixValue{paymentSystem: paymentSystem, lengthChecker: paymentSystemParam.lengthChecker}
oldValue, isUpdated := p.tree.Insert(strconv.Itoa(prefix), newValue)
oldValue, isUpdated := r.tree.Insert(strconv.Itoa(prefix), newValue)
if isUpdated {
oldPaymentSystem := oldValue.(*radixValue).paymentSystem
return xerrors.Errorf(
"unexpected update: prefix=%d, old=%s, new=%s",
"prefix=%d, old=%s, new=%s: %w",
prefix,
oldPaymentSystem,
newValue.paymentSystem,
errNonUniquePrefix,
)
}
}
Expand All @@ -103,9 +110,13 @@ func (p *paymentSystemDB) InitFromMap(rawPaymentSystems map[PaymentSystem][]paym
return nil
}

func newRadixDB() *radixDB {
return &radixDB{tree: radix.New()}
}

// NewDB creates instance of payment system DB.
func NewDB() DB {
db := &paymentSystemDB{tree: radix.New()}
db := newRadixDB()
err := db.InitFromMap(rawPaymentSystems)
if err != nil {
panic(err)
Expand Down
94 changes: 70 additions & 24 deletions paymentsystem/payment_system_test.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,92 @@
package paymentsystem_test
package paymentsystem

import (
"testing"

"github.com/khasanovbi/banksdb/v2/paymentsystem"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"golang.org/x/xerrors"
)

func TestFindPaymentSystem(t *testing.T) {
tests := map[paymentsystem.PaymentSystem]string{
paymentsystem.AmericanExpress: "341414688673814",
paymentsystem.Dankort: "5019613744152545",
paymentsystem.DinersClubInternational: "3872481490310852",
paymentsystem.Discover: "6011988461284820",
paymentsystem.InterPayment: "6365364106904019758",
paymentsystem.InstaPayment: "6397686307314238",
paymentsystem.JCB: "3582616798872373",
paymentsystem.LankaPay: "3571113212345544",
paymentsystem.Maestro: "5080741549588144561",
paymentsystem.MasterCard: "2550053850150029",
paymentsystem.Mir: "2204941877211882",
paymentsystem.NPSPridnestrovie: "6054740386428539",
paymentsystem.RuPay: "6522133919284495",
paymentsystem.Troy: "9792376700578340",
paymentsystem.TUnion: "3152259470993676486",
paymentsystem.UATP: "132435418436821",
paymentsystem.UnionPay: "6221269639999729",
paymentsystem.Verve: "5061725767660126",
paymentsystem.Visa: "4607322866767830",
tests := map[PaymentSystem]string{
AmericanExpress: "341414688673814",
Dankort: "5019613744152545",
DinersClubInternational: "3872481490310852",
Discover: "6011988461284820",
InterPayment: "6365364106904019758",
InstaPayment: "6397686307314238",
JCB: "3582616798872373",
LankaPay: "3571113212345544",
Maestro: "5080741549588144561",
MasterCard: "2550053850150029",
Mir: "2204941877211882",
NPSPridnestrovie: "6054740386428539",
RuPay: "6522133919284495",
Troy: "9792376700578340",
TUnion: "3152259470993676486",
UATP: "132435418436821",
UnionPay: "6221269639999729",
Verve: "5061725767660126",
Visa: "4607322866767830",
}
for ps, creditCard := range tests {
ps := ps
creditCard := creditCard
t.Run(string(ps), func(t *testing.T) {
actualPaymentSystem := paymentsystem.FindPaymentSystem(creditCard)
actualPaymentSystem := FindPaymentSystem(creditCard)
require.NotNil(t, actualPaymentSystem)
require.EqualValues(t, ps, *actualPaymentSystem)
})
}
}

func TestEmptyCreditCardFindPaymentSystem(t *testing.T) {
actualPaymentSystem := paymentsystem.FindPaymentSystem("")
actualPaymentSystem := FindPaymentSystem("")
require.Nil(t, actualPaymentSystem)
}

type RadixDBTestSuite struct {
suite.Suite
}

func (suite *RadixDBTestSuite) TestNotLongestPrefix() {
db := newRadixDB()
EqualByPrefixPs := PaymentSystem("EqualByPrefixPs")
EqualByLengthAndPrefixPs := PaymentSystem("EqualByLengthAndPrefixPs")
creditCard := "12"
err := db.InitFromMap(map[PaymentSystem][]paymentSystemInfo{
EqualByLengthAndPrefixPs: {
{prefixes: []int{1}, lengthChecker: &exactLengthChecker{Exact: 2}},
},
EqualByPrefixPs: {
{prefixes: []int{12}, lengthChecker: &exactLengthChecker{Exact: 5}},
},
})
suite.Require().NoError(err)
actualPs := db.FindPaymentSystem(creditCard)
suite.Require().NotNil(actualPs)
suite.Require().Equal(EqualByLengthAndPrefixPs, *actualPs)
actualPs = db.FindPaymentSystemByPrefix(creditCard)
suite.Require().NotNil(actualPs)
suite.Require().Equal(EqualByPrefixPs, *actualPs)
}

func (suite *RadixDBTestSuite) TestInitErrorAtSamePrefix() {
db := newRadixDB()
ps1 := PaymentSystem("ps1")
ps2 := PaymentSystem("ps2")
err := db.InitFromMap(map[PaymentSystem][]paymentSystemInfo{
ps1: {
{prefixes: []int{1}, lengthChecker: &exactLengthChecker{Exact: 2}},
},
ps2: {
{prefixes: []int{1}, lengthChecker: &exactLengthChecker{Exact: 5}},
},
})
suite.Require().True(xerrors.Is(err, errNonUniquePrefix))
}

func TestRadixDBTestSuite(t *testing.T) {
suite.Run(t, new(RadixDBTestSuite))
}

0 comments on commit 4b93e7f

Please sign in to comment.