From 764351fafbea9307fe0e63f177ff553531136a82 Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 7 Mar 2025 13:17:45 -0600 Subject: [PATCH] Support udecimal library in code generation --- .github/workflows/ci.yaml | 46 +++++++++- Makefile | 12 ++- cmd/generate-fix/internal/generate.go | 1 + cmd/generate-fix/internal/template_helpers.go | 23 ++++- cmd/generate-fix/internal/templates.go | 25 +++++- fix_decimal_test.go | 23 +++++ fix_udecimal.go | 35 ++++++++ fix_udecimal_test.go | 85 +++++++++++++++++++ go.mod | 7 +- go.sum | 16 ++-- 10 files changed, 249 insertions(+), 24 deletions(-) create mode 100644 fix_udecimal.go create mode 100644 fix_udecimal_test.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2c13221db..0bd1b3749 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v4 with: - version: v1.57.2 + version: v1.64.6 build: name: Build Source @@ -101,6 +101,13 @@ jobs: STORE_TYPE: memory ACCEPTANCE_SET: server run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: memory + ACCEPTANCE_SET: server + run: make generate-ci-udecimal && make build && make $FIX_TEST serverfile: name: Server FileStore Suite @@ -135,6 +142,13 @@ jobs: STORE_TYPE: file ACCEPTANCE_SET: server run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: file + ACCEPTANCE_SET: server + run: make generate-ci-udecimal && make build && make $FIX_TEST servermongo: name: Server MongoStore Suite @@ -174,6 +188,13 @@ jobs: STORE_TYPE: mongo ACCEPTANCE_SET: server run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: mongo + ACCEPTANCE_SET: server + run: make generate-ci-udecimal && make build && make $FIX_TEST resendreqchunksize: name: ResendRequestChunkSize Suite @@ -208,6 +229,13 @@ jobs: STORE_TYPE: memory ACCEPTANCE_SET: resendreqchunksize run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: memory + ACCEPTANCE_SET: resendreqchunksize + run: make generate-ci-udecimal && make build && make $FIX_TEST lastseqnumprocessed: name: LastSeqNumProcessed Suite @@ -240,6 +268,13 @@ jobs: STORE_TYPE: memory ACCEPTANCE_SET: lastseqnumprocessed run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: memory + ACCEPTANCE_SET: lastseqnumprocessed + run: make generate-ci-udecimal && make build && make $FIX_TEST nextexpectedseqnum: name: NextExpectedSeqNum Suite @@ -269,4 +304,11 @@ jobs: FIX_TEST: ${{ matrix.fix-version }} STORE_TYPE: memory ACCEPTANCE_SET: nextexpectedseqnum - run: make generate-ci && make build && make $FIX_TEST \ No newline at end of file + run: make generate-ci && make build && make $FIX_TEST + - name: Acceptance test with udecimal + env: + GO111MODULE: on + FIX_TEST: ${{ matrix.fix-version }} + STORE_TYPE: memory + ACCEPTANCE_SET: nextexpectedseqnum + run: make generate-ci-udecimal && make build && make $FIX_TEST diff --git a/Makefile b/Makefile index 8d3c2c6cc..960ccacd6 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ clean: generate: clean mkdir -p gen; cd gen; go run ../cmd/generate-fix/generate-fix.go -pkg-root=github.com/quickfixgo/quickfix/gen ../spec/*.xml +generate-udecimal: clean + mkdir -p gen; cd gen; go run ../cmd/generate-fix/generate-fix.go -use-udecimal=true -pkg-root=github.com/quickfixgo/quickfix/gen ../spec/*.xml + fmt: gofmt -l -w -s $(shell find . -type f -name '*.go') @@ -19,14 +22,14 @@ test: linters-install: @golangci-lint --version >/dev/null 2>&1 || { \ echo "installing linting tools..."; \ - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.57.2; \ + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.64.6; \ } lint: linters-install golangci-lint run # An easy way to run the linter without going through the install process - -# docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.57.2 golangci-lint run -v +# docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.64.6 golangci-lint run -v # See https://golangci-lint.run/welcome/install/ for more details. # --------------------------------------------------------------- @@ -81,6 +84,9 @@ test-ci: go test -v -cover `go list ./... | grep -v quickfix/gen` generate-ci: clean - mkdir -p gen; cd gen; go run ../cmd/generate-fix/generate-fix.go -pkg-root=github.com/quickfixgo/quickfix/gen ../spec/$(shell echo $(FIX_TEST) | tr '[:lower:]' '[:upper:]').xml; + mkdir -p gen; cd gen; go run ../cmd/generate-fix/generate-fix.go -pkg-root=github.com/quickfixgo/quickfix/gen ../spec/$(shell echo $(FIX_TEST) | tr '[:lower:]' '[:upper:]').xml; + +generate-ci-udecimal: clean + mkdir -p gen; cd gen; go run ../cmd/generate-fix/generate-fix.go -use-udecimal=true -pkg-root=github.com/quickfixgo/quickfix/gen ../spec/$(shell echo $(FIX_TEST) | tr '[:lower:]' '[:upper:]').xml; # --------------------------------------------------------------- diff --git a/cmd/generate-fix/internal/generate.go b/cmd/generate-fix/internal/generate.go index 353b0e3d4..760e83826 100644 --- a/cmd/generate-fix/internal/generate.go +++ b/cmd/generate-fix/internal/generate.go @@ -13,6 +13,7 @@ import ( var ( useFloat = flag.Bool("use-float", false, "By default, FIX float fields are represented as arbitrary-precision fixed-point decimal numbers. Set to 'true' to instead generate FIX float fields as float64 values.") + useUDecimal = flag.Bool("use-udecimal", false, "By default, FIX uses the shopspring/decimal library for fixed-point decimal numbers. Set to 'true' to instead use the quagmt/udecimal library.") pkgRoot = flag.String("pkg-root", "github.com/quickfixgo", "Set a string here to provide a custom import path for generated packages.") tabWidth = 8 printerMode = printer.UseSpaces | printer.TabIndent diff --git a/cmd/generate-fix/internal/template_helpers.go b/cmd/generate-fix/internal/template_helpers.go index f2c201b82..af10963a0 100644 --- a/cmd/generate-fix/internal/template_helpers.go +++ b/cmd/generate-fix/internal/template_helpers.go @@ -6,6 +6,15 @@ import ( "github.com/quickfixgo/quickfix/datadictionary" ) +func isDecimalType(quickfixType string) bool { + switch quickfixType { + case "FIXDecimal", "FIXUDecimal": + return true + default: + return false + } +} + func checkIfDecimalImportRequiredForFields(fTypes []*datadictionary.FieldType) (ok bool, err error) { var t string for _, fType := range fTypes { @@ -14,7 +23,7 @@ func checkIfDecimalImportRequiredForFields(fTypes []*datadictionary.FieldType) ( return } - if t == "FIXDecimal" { + if isDecimalType(t) { return true, nil } } @@ -54,7 +63,7 @@ func checkFieldDecimalRequired(f *datadictionary.FieldDef) (required bool, err e return } - if t == "FIXDecimal" { + if isDecimalType(t) { required = true return } @@ -121,6 +130,10 @@ func collectStandardImports(m *datadictionary.MessageDef) (imports []string, err func collectExtraImports(m *datadictionary.MessageDef) (imports []string, err error) { var decimalRequired bool + importPath := "github.com/shopspring/decimal" + if *useUDecimal { + importPath = "github.com/quagmt/udecimal" + } for _, f := range m.Fields { if !decimalRequired { if decimalRequired, err = checkFieldDecimalRequired(f); err != nil { @@ -134,7 +147,7 @@ func collectExtraImports(m *datadictionary.MessageDef) (imports []string, err er } if decimalRequired { - imports = append(imports, "github.com/shopspring/decimal") + imports = append(imports, importPath) } return @@ -191,6 +204,8 @@ func quickfixValueType(quickfixType string) (goType string, err error) { goType = "float64" case "FIXDecimal": goType = "decimal.Decimal" + case "FIXUDecimal": + goType = "udecimal.Decimal" default: err = fmt.Errorf("Unknown QuickFIX Type: %v", quickfixType) } @@ -275,6 +290,8 @@ func quickfixType(field *datadictionary.FieldType) (quickfixType string, err err case "FLOAT": if *useFloat { quickfixType = "FIXFloat" + } else if *useUDecimal { + quickfixType = "FIXUDecimal" } else { quickfixType = "FIXDecimal" } diff --git a/cmd/generate-fix/internal/templates.go b/cmd/generate-fix/internal/templates.go index 93d01f8a2..994d087e9 100644 --- a/cmd/generate-fix/internal/templates.go +++ b/cmd/generate-fix/internal/templates.go @@ -27,8 +27,14 @@ func init() { "collectStandardImports": collectStandardImports, "collectExtraImports": collectExtraImports, "checkIfDecimalImportRequiredForFields": checkIfDecimalImportRequiredForFields, - "checkIfTimeImportRequiredForFields": checkIfTimeImportRequiredForFields, - "checkIfEnumImportRequired": checkIfEnumImportRequired, + "decimalImport": func() string { + if *useUDecimal { + return "github.com/quagmt/udecimal" + } + return "github.com/shopspring/decimal" + }, + "checkIfTimeImportRequiredForFields": checkIfTimeImportRequiredForFields, + "checkIfEnumImportRequired": checkIfEnumImportRequired, } baseTemplate := template.Must(template.New("Base").Funcs(tmplFuncs).Parse(` @@ -45,6 +51,10 @@ Set{{ .Name }}(v enum.{{ .Name }}) { Set{{ .Name }}(value decimal.Decimal, scale int32) { {{ template "receiver" }}.Set(field.New{{ .Name }}(value, scale)) } +{{- else if eq $qfix_type "FIXUDecimal" -}} +Set{{ .Name }}(value udecimal.Decimal, scale uint8) { + {{ template "receiver" }}.Set(field.New{{ .Name }}(value, scale)) +} {{- else -}} Set{{ .Name }}(v {{ quickfixValueType $qfix_type }}) { {{ template "receiver" }}.Set(field.New{{ .Name }}(v)) @@ -77,6 +87,8 @@ Get{{ .Name }}() (f field.{{ .Name }}Field, err quickfix.MessageRejectError) { Get{{ .Name }}() (v enum.{{ .Name }}, err quickfix.MessageRejectError) { {{- else if eq $bt "FIXDecimal" -}} Get{{ .Name }}() (v decimal.Decimal, err quickfix.MessageRejectError) { +{{- else if eq $bt "FIXUDecimal" -}} +Get{{ .Name }}() (v udecimal.Decimal, err quickfix.MessageRejectError) { {{- else -}} Get{{ .Name }}() (v {{ quickfixValueType $bt }}, err quickfix.MessageRejectError) { {{- end }} @@ -345,7 +357,7 @@ package field import ( {{ if checkIfTimeImportRequiredForFields . }}"time"{{ end }} - {{ if checkIfDecimalImportRequiredForFields . }}"github.com/shopspring/decimal"{{ end }} + {{ if checkIfDecimalImportRequiredForFields . }}"{{ decimalImport }}"{{ end }} "github.com/quickfixgo/quickfix" "{{ importRootPath }}/enum" @@ -391,6 +403,11 @@ func New{{ .Name }}(val enum.{{ .Name }}) {{ .Name }}Field { func New{{ .Name }}(val decimal.Decimal, scale int32) {{ .Name }}Field { return {{ .Name }}Field{ quickfix.FIXDecimal{ Decimal: val, Scale: scale} } } +{{ else if eq $base_type "FIXUDecimal" }} +// New{{ .Name }} returns a new {{ .Name }}Field initialized with val and scale. +func New{{ .Name }}(val udecimal.Decimal, scale uint8) {{ .Name }}Field { + return {{ .Name }}Field{ quickfix.FIXUDecimal{ Decimal: val, Scale: scale} } +} {{ else }} // New{{ .Name }} returns a new {{ .Name }}Field initialized with val. func New{{ .Name }}(val {{ quickfixValueType $base_type }}) {{ .Name }}Field { @@ -402,6 +419,8 @@ func New{{ .Name }}(val {{ quickfixValueType $base_type }}) {{ .Name }}Field { func (f {{ .Name }}Field) Value() enum.{{ .Name }} { return enum.{{ .Name }}(f.String()) } {{ else if eq $base_type "FIXDecimal" }} func (f {{ .Name }}Field) Value() (val decimal.Decimal) { return f.Decimal } +{{ else if eq $base_type "FIXUDecimal" }} +func (f {{ .Name }}Field) Value() (val udecimal.Decimal) { return f.Decimal } {{ else }} func (f {{ .Name }}Field) Value() ({{ quickfixValueType $base_type }}) { {{- if eq $base_type "FIXString" -}} diff --git a/fix_decimal_test.go b/fix_decimal_test.go index 7c8d3a265..f893cdc7b 100644 --- a/fix_decimal_test.go +++ b/fix_decimal_test.go @@ -23,6 +23,29 @@ import ( "github.com/stretchr/testify/require" ) +func BenchmarkFIXDecimalRead(b *testing.B) { + var dec FIXDecimal + byt := []byte("-124.3456") + for i := 0; i < b.N; i++ { + if err := dec.Read(byt); err != nil { + b.FailNow() + } + } +} + +func BenchmarkFIXDecimalWrite(b *testing.B) { + decValue, err := decimal.NewFromString("-124.3456") + if err != nil { + b.FailNow() + } + dec := FIXDecimal{Decimal: decValue, Scale: 5} + for i := 0; i < b.N; i++ { + if byt := dec.Write(); len(byt) == 0 { + b.FailNow() + } + } +} + func TestFIXDecimalWrite(t *testing.T) { var tests = []struct { decimal FIXDecimal diff --git a/fix_udecimal.go b/fix_udecimal.go new file mode 100644 index 000000000..ba760343a --- /dev/null +++ b/fix_udecimal.go @@ -0,0 +1,35 @@ +// Copyright (c) quickfixengine.org All rights reserved. +// +// This file may be distributed under the terms of the quickfixengine.org +// license as defined by quickfixengine.org and appearing in the file +// LICENSE included in the packaging of this file. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE. +// +// See http://www.quickfixengine.org/LICENSE for licensing information. +// +// Contact ask@quickfixengine.org if any conditions of this licensing +// are not clear to you. + +package quickfix + +import "github.com/quagmt/udecimal" + +// FIXUDecimal is a FIX Float Value that implements an arbitrary precision fixed-point udecimal. Implements FieldValue. +type FIXUDecimal struct { + udecimal.Decimal + + // Scale is the number of digits after the decimal point when Writing the field value as a FIX value. + Scale uint8 +} + +func (d FIXUDecimal) Write() []byte { + return []byte(d.Decimal.Trunc(d.Scale).StringFixed(d.Scale)) +} + +func (d *FIXUDecimal) Read(bytes []byte) (err error) { + d.Decimal, err = udecimal.Parse(string(bytes)) + return +} diff --git a/fix_udecimal_test.go b/fix_udecimal_test.go new file mode 100644 index 000000000..d662f1656 --- /dev/null +++ b/fix_udecimal_test.go @@ -0,0 +1,85 @@ +// Copyright (c) quickfixengine.org All rights reserved. +// +// This file may be distributed under the terms of the quickfixengine.org +// license as defined by quickfixengine.org and appearing in the file +// LICENSE included in the packaging of this file. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING +// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE. +// +// See http://www.quickfixengine.org/LICENSE for licensing information. +// +// Contact ask@quickfixengine.org if any conditions of this licensing +// are not clear to you. + +package quickfix + +import ( + "testing" + + decimal "github.com/quagmt/udecimal" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func BenchmarkFIXUDecimalRead(b *testing.B) { + var dec FIXUDecimal + byt := []byte("-124.3456") + for i := 0; i < b.N; i++ { + if err := dec.Read(byt); err != nil { + b.FailNow() + } + } +} + +func BenchmarkFIXUDecimalWrite(b *testing.B) { + dec := FIXUDecimal{Decimal: decimal.MustParse("-124.3456"), Scale: 5} + for i := 0; i < b.N; i++ { + if byt := dec.Write(); len(byt) == 0 { + b.FailNow() + } + } +} + +func TestFIXUDecimalWrite(t *testing.T) { + var tests = []struct { + decimal FIXUDecimal + expected string + }{ + {decimal: FIXUDecimal{Decimal: decimal.MustParse("-124.3456"), Scale: 4}, expected: "-124.3456"}, + {decimal: FIXUDecimal{Decimal: decimal.MustParse("-124.3456"), Scale: 5}, expected: "-124.34560"}, + {decimal: FIXUDecimal{Decimal: decimal.MustParse("-124.3456"), Scale: 0}, expected: "-124"}, + } + + for _, test := range tests { + b := test.decimal.Write() + assert.Equal(t, test.expected, string(b)) + } +} + +func TestFIXUDecimalRead(t *testing.T) { + var tests = []struct { + bytes string + expected decimal.Decimal + expectError bool + }{ + {bytes: "15", expected: decimal.MustParse("15")}, + {bytes: "15.000", expected: decimal.MustParse("15")}, + {bytes: "15.001", expected: decimal.MustParse("15.001")}, + {bytes: "-15.001", expected: decimal.MustParse("-15.001")}, + {bytes: "blah", expectError: true}, + {bytes: "+200.00", expected: decimal.MustParse("200")}, + } + + for _, test := range tests { + var field FIXUDecimal + + err := field.Read([]byte(test.bytes)) + require.Equal(t, test.expectError, err != nil) + + if !test.expectError { + assert.True(t, test.expected.Equal(field.Decimal), "Expected %s got %s", test.expected, field.Decimal) + } + } +} diff --git a/go.mod b/go.mod index 8b36cf024..e4b091c04 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,14 @@ module github.com/quickfixgo/quickfix -go 1.21 +go 1.23 require ( github.com/mattn/go-sqlite3 v1.14.22 github.com/pires/go-proxyproto v0.7.0 github.com/pkg/errors v0.9.1 + github.com/quagmt/udecimal v1.8.0 github.com/shopspring/decimal v1.4.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.0 golang.org/x/net v0.24.0 ) @@ -19,7 +20,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/montanaflynn/stats v0.6.6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect diff --git a/go.sum b/go.sum index a7e47992c..478e37d12 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -24,16 +23,14 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quagmt/udecimal v1.8.0 h1:d4MJNGb/dg8r03AprkeSiDlVKtkZnL10L3de/YGOiiI= +github.com/quagmt/udecimal v1.8.0/go.mod h1:ScmJ/xTGZcEoYiyMMzgDLn79PEJHcMBiJ4NNRT3FirA= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -84,6 +81,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=