From d6473d617f8c4b71d06e4adbc1c6a6201ce2f5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Wed, 4 Sep 2024 10:32:21 +0000 Subject: [PATCH] fix golint (#8) Co-authored-by: daniel.w Reviewed-on: https://code.30cm.net/digimon/library-go/pulls/8 --- utils/invited_code/const.go | 11 +++ utils/invited_code/convert.go | 80 +++++++++++++++++++ utils/invited_code/convert_test.go | 123 +++++++++++++++++++++++++++++ utils/invited_code/go.mod | 11 +++ utils/invited_code/usecase.go | 6 ++ 5 files changed, 231 insertions(+) create mode 100644 utils/invited_code/const.go create mode 100644 utils/invited_code/convert.go create mode 100644 utils/invited_code/convert_test.go create mode 100644 utils/invited_code/go.mod create mode 100644 utils/invited_code/usecase.go diff --git a/utils/invited_code/const.go b/utils/invited_code/const.go new file mode 100644 index 0000000..a27e3b7 --- /dev/null +++ b/utils/invited_code/const.go @@ -0,0 +1,11 @@ +package invited_code + +const DefaultCodeLen = 8 + +var ConvertTable = []string{ + "O", "D", "W", "X", "Y", + "G", "B", "C", "H", "E", + "F", "A", "Q", "I", "J", + "L", "M", "N", "Z", "K", + "P", "V", "R", "S", "T", +} diff --git a/utils/invited_code/convert.go b/utils/invited_code/convert.go new file mode 100644 index 0000000..004dd1f --- /dev/null +++ b/utils/invited_code/convert.go @@ -0,0 +1,80 @@ +package invited_code + +import ( + "fmt" + "math" + "strings" +) + +type Converter struct { + Base int + Length int + ConvertTable []string +} + +func (c *Converter) EncodeFromNum(id int64) (string, error) { + code, err := generateCode(id, c.Base, c.Length, c.ConvertTable) + if err != nil { + return "", err + } + + return code, nil +} + +func (c *Converter) DecodeFromCode(code string) (int64, error) { + var result int64 = 0 + length := len(code) + + for i := 0; i < length; i++ { + char := string(code[i]) + index := -1 + for j, v := range c.ConvertTable { + if v == char { + index = j + break + } + } + + if index >= 0 { + result = result*int64(c.Base) + int64(index) + } else { + return 0, fmt.Errorf("character not found in convert table") + } + } + return result, nil +} + +// generateCode 從 UID 生成 referralCode +func generateCode(id int64, base int, length int, convertTable []string) (string, error) { + maxReferralUIDBoundary := int64(math.Pow(float64(len(ConvertTable)), float64(DefaultCodeLen))) + if id > maxReferralUIDBoundary { + return "", fmt.Errorf("encode out of range") + } + + encoded := encodeToBase(id, base, length, convertTable) + + return encoded, nil +} + +func encodeToBase(num int64, base int, length int, convertTable []string) string { + result := "" + for num > 0 { + index := num % int64(base) + result = convertTable[index] + result + num /= int64(base) + } + + if len(result) < length { + result = strings.Repeat(convertTable[0], length-len(result)) + result + } + + return result +} + +func MustConverter(base int, length int, convertTable []string) ConvertUseCase { + return &Converter{ + Base: base, + Length: length, + ConvertTable: convertTable, + } +} diff --git a/utils/invited_code/convert_test.go b/utils/invited_code/convert_test.go new file mode 100644 index 0000000..2ab1a76 --- /dev/null +++ b/utils/invited_code/convert_test.go @@ -0,0 +1,123 @@ +package invited_code + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +// 測試 ConvertUseCase 的功能 +func TestConverter(t *testing.T) { + tests := []struct { + name string + id int64 + base int + length int + wantCode string + wantError bool + }{ + { + name: "Test Case 1: Valid ID 1000000", + id: 10000000, + base: 10, + length: 7, + wantCode: "DOOOOOOO", + wantError: false, + }, + { + name: "Test Case 2: Valid ID 12345678", + id: 12345678, + base: 10, + length: 8, + wantCode: "DWXYGBCH", + wantError: false, + }, + { + name: "Test Case 3: Valid ID 98765432", + id: 98765432, + base: 10, + length: 8, + wantCode: "EHCBGYXW", + wantError: false, + }, + { + name: "Test Case 4: ID too large", + id: 10000000000000001, // ID 超過界限 + base: 10, + length: 8, + wantCode: "", + wantError: true, + }, + } + + converter := MustConverter(10, 8, ConvertTable) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + code, err := converter.EncodeFromNum(tt.id) + + if tt.wantError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.wantCode, code) + } + + if !tt.wantError { + // 測試解碼 + decodedID, err := converter.DecodeFromCode(code) + assert.NoError(t, err) + assert.Equal(t, tt.id, decodedID) + } + }) + } +} + +func TestDecodeFromCode(t *testing.T) { + converter := MustConverter(10, 8, ConvertTable) + + tests := []struct { + name string + code string + wantID int64 + wantError bool + }{ + { + name: "Decode valid code 1", + code: "DOOOOOOO", // 對應於 id 10000000 + wantID: 10000000, + wantError: false, + }, + { + name: "Decode valid code 2", + code: "DWXYGBCH", // 對應於 id 12345678 + wantID: 12345678, + wantError: false, + }, + { + name: "Decode valid code 3", + code: "EHCBGYXW", // 對應於 id 98765432 + wantID: 98765432, + wantError: false, + }, + { + name: "Decode invalid code with character not in table", + code: "UWOXZZZ", // 包含 ZZZ,不在轉換表中 + wantID: 0, + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := converter.DecodeFromCode(tt.code) + + if tt.wantError { + assert.Error(t, err) + assert.Equal(t, int64(0), result) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.wantID, result) + } + }) + } +} diff --git a/utils/invited_code/go.mod b/utils/invited_code/go.mod new file mode 100644 index 0000000..40d838c --- /dev/null +++ b/utils/invited_code/go.mod @@ -0,0 +1,11 @@ +module code.30cm.net/digimon/library-go/utils/invited_code + +go 1.22.3 + +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/utils/invited_code/usecase.go b/utils/invited_code/usecase.go new file mode 100644 index 0000000..f91ecdb --- /dev/null +++ b/utils/invited_code/usecase.go @@ -0,0 +1,6 @@ +package invited_code + +type ConvertUseCase interface { + EncodeFromNum(id int64) (string, error) + DecodeFromCode(code string) (int64, error) +}