This commit is contained in:
@@ -19,15 +19,16 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidFormat = errors.New("invalid format, expected LLL-NNN-LC")
|
||||
ErrInvalidLetters = errors.New("invalid letters")
|
||||
ErrForbiddenLetterTriplet = errors.New("forbidden letter combination")
|
||||
ErrInvalidNumber = errors.New("invalid number")
|
||||
ErrNumberOutOfRange = errors.New("number out of range")
|
||||
ErrInvalidChecksum = errors.New("invalid checksum")
|
||||
ErrIndexOutOfRange = errors.New("index out of range")
|
||||
ErrRandomSourceFailed = errors.New("random source failed")
|
||||
ErrNoAvailableIndex = errors.New("no available index found")
|
||||
ErrInvalidFormat = errors.New("invalid format, expected LLL-NNN-LC")
|
||||
ErrInvalidFormatNoChecksum = errors.New("invalid format, expected LLL-NNN-L")
|
||||
ErrInvalidLetters = errors.New("invalid letters")
|
||||
ErrForbiddenLetterTriplet = errors.New("forbidden letter combination")
|
||||
ErrInvalidNumber = errors.New("invalid number")
|
||||
ErrNumberOutOfRange = errors.New("number out of range")
|
||||
ErrInvalidChecksum = errors.New("invalid checksum")
|
||||
ErrIndexOutOfRange = errors.New("index out of range")
|
||||
ErrRandomSourceFailed = errors.New("random source failed")
|
||||
ErrNoAvailableIndex = errors.New("no available index found")
|
||||
)
|
||||
|
||||
type RandomCodeOptions struct {
|
||||
@@ -112,6 +113,40 @@ func Decode(idx uint32) (string, error) {
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func CompleteCode(codeWithoutChecksum string) (string, uint32, error) {
|
||||
if len(codeWithoutChecksum) != 9 || codeWithoutChecksum[3] != '-' || codeWithoutChecksum[7] != '-' {
|
||||
return "", 0, ErrInvalidFormatNoChecksum
|
||||
}
|
||||
|
||||
l1, l2, l3, l4 := codeWithoutChecksum[0], codeWithoutChecksum[1], codeWithoutChecksum[2], codeWithoutChecksum[8]
|
||||
n1, n2, n3 := codeWithoutChecksum[4], codeWithoutChecksum[5], codeWithoutChecksum[6]
|
||||
|
||||
if !isUpperAlphaASCII(l1) || !isUpperAlphaASCII(l2) || !isUpperAlphaASCII(l3) || !isUpperAlphaASCII(l4) {
|
||||
return "", 0, ErrInvalidLetters
|
||||
}
|
||||
if IsForbiddenTriplet(l1, l2, l3) {
|
||||
return "", 0, ErrForbiddenLetterTriplet
|
||||
}
|
||||
if !isNumber(n1) || !isNumber(n2) || !isNumber(n3) {
|
||||
return "", 0, ErrInvalidNumber
|
||||
}
|
||||
|
||||
L1 := uint32(l1 - 'A')
|
||||
L2 := uint32(l2 - 'A')
|
||||
L3 := uint32(l3 - 'A')
|
||||
L4 := uint32(l4 - 'A')
|
||||
num := uint32(n1-'0')*100 + uint32(n2-'0')*10 + uint32(n3-'0')
|
||||
if num < 100 || num > 999 {
|
||||
return "", 0, ErrNumberOutOfRange
|
||||
}
|
||||
N := num - 100
|
||||
|
||||
idx := uint32((((((L1*letters+L2)*letters+L3)*letters + L4) * numbers) + N))
|
||||
checksum := checksumLetter(idx)
|
||||
|
||||
return codeWithoutChecksum + string(checksum), idx, nil
|
||||
}
|
||||
|
||||
func RandomCode(isInUse ...func(uint32) bool) (string, uint32, error) {
|
||||
options := RandomCodeOptions{}
|
||||
if len(isInUse) > 0 {
|
||||
|
||||
@@ -192,6 +192,38 @@ func TestEncodeRejectsNonDigitInNumber(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompleteCodeRoundtrip(t *testing.T) {
|
||||
original, err := serial.Decode(123456)
|
||||
if err != nil {
|
||||
t.Fatalf("Decode failed: %v", err)
|
||||
}
|
||||
|
||||
withoutChecksum := original[:len(original)-1]
|
||||
full, idx, err := serial.CompleteCode(withoutChecksum)
|
||||
if err != nil {
|
||||
t.Fatalf("CompleteCode failed: %v", err)
|
||||
}
|
||||
|
||||
if full != original {
|
||||
t.Fatalf("completed code mismatch: got %q, want %q", full, original)
|
||||
}
|
||||
|
||||
idx2, err := serial.Encode(full)
|
||||
if err != nil {
|
||||
t.Fatalf("Encode failed for completed code %q: %v", full, err)
|
||||
}
|
||||
if idx2 != idx {
|
||||
t.Fatalf("idx mismatch: got %d, want %d", idx, idx2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompleteCodeRejectsInvalidFormat(t *testing.T) {
|
||||
_, _, err := serial.CompleteCode("AAA-10-A")
|
||||
if !errors.Is(err, serial.ErrInvalidFormatNoChecksum) {
|
||||
t.Fatalf("expected invalid no-checksum format error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomCodeRoundtrip(t *testing.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
code, idx, err := serial.RandomCode()
|
||||
|
||||
Reference in New Issue
Block a user