From 82679048e0561a44ed27e1e52e54e26e0a97c4b2 Mon Sep 17 00:00:00 2001 From: micha Date: Fri, 20 Feb 2026 22:59:44 +0100 Subject: [PATCH] Ready for testing. --- go.mod | 3 + serial/serial.go | 101 +++++++++++++++--------- serial/serial_test.go | 175 +++++++++++++++++++++--------------------- 3 files changed, 153 insertions(+), 126 deletions(-) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1b6befb --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.hoiting.org/micha/triplex + +go 1.25.0 diff --git a/serial/serial.go b/serial/serial.go index cf4e7ea..291f013 100644 --- a/serial/serial.go +++ b/serial/serial.go @@ -1,61 +1,86 @@ +package serial + +import ( + "errors" + "fmt" + "log" +) + const ( - letters = 26 - numbers = 900 // 100–999 - block = letters * letters * letters * numbers // 26^3 * 900 + MaxIndex = block + + letters = 26 + numbers = 900 // 100–999 + block = letters * letters * letters * numbers // 26^3 * 900 ) func Encode(code string) (uint32, error) { - // Verwacht formaat: L1L2-NNN-L3-C => lengte 10, posities: 0,1,3,4,5,7,9 - if len(code) != 10 || code[2] != '-' || code[6] != '-' || code[8] != '-' { - return 0, errors.New("invalid format, expected LL-NNN-L-C") - } + log.Printf("code: %v", code) + // Verwacht formaat: L1L2-NNN-L3-C => lengte 10, posities: 0,1,3,4,5,7,9 + if len(code) != 10 || code[2] != '-' || code[6] != '-' || code[8] != '-' { + return 0, errors.New("invalid format, expected LL-NNN-L-C") + } - l1, l2, l3 := code[0], code[1], code[7] + l1, l2, l3 := code[0], code[1], code[7] + n1, n2, n3 := code[3], code[4], code[5] - // letters checken - // forbidden alleen op l1,l2 - // nummer parsen uit code[3:6] + // letters checken + // forbidden alleen op l1,l2 + // nummer parsen uit code[3:6] - L1 := int(l1 - 'A') - L2 := int(l2 - 'A') - L3 := int(l3 - 'A') - N := num - 100 + L1 := uint32(l1 - 'A') + L2 := uint32(l2 - 'A') + L3 := uint32(l3 - 'A') + num := uint32(n1*100 + n2*10 + n3) + N := num - 100 - idx := uint32((((L1*letters + L2)*letters + L3) * numbers) + N) + idx := uint32((((L1*letters+L2)*letters + L3) * numbers) + N) - if code[9] != checksumLetter(idx) { - return 0, errors.New("invalid checksum") - } + if code[9] != checksumLetter(idx) { + return 0, errors.New("invalid checksum") + } - return idx, nil + log.Printf("idx: %v", idx) + return idx, nil } func Decode(idx uint32) (string, error) { - if idx >= block { - return "", errors.New("index out of range") - } + log.Printf("idx: %v", idx) + if idx >= block { + return "", errors.New("index out of range") + } - x := int(idx) + x := int(idx) - L1 := x / (letters * letters * numbers) - r1 := x % (letters * letters * numbers) + L1 := x / (letters * letters * numbers) + r1 := x % (letters * letters * numbers) - L2 := r1 / (letters * numbers) - r2 := r1 % (letters * numbers) + L2 := r1 / (letters * numbers) + r2 := r1 % (letters * numbers) - L3 := r2 / numbers - N := r2 % numbers + L3 := r2 / numbers + N := r2 % numbers - l1 := byte('A' + L1) - l2 := byte('A' + L2) - l3 := byte('A' + L3) + l1 := byte('A' + L1) + l2 := byte('A' + L2) + l3 := byte('A' + L3) - if isForbiddenPair(l1, l2) { - return "", errors.New("forbidden letter combination") - } + if IsForbiddenPair(l1, l2) { + return "", errors.New("forbidden letter combination") + } - c := checksumLetter(idx) + c := checksumLetter(idx) - return fmt.Sprintf("%c%c-%03d-%c-%c", l1, l2, N+100, l3, c), nil + code := fmt.Sprintf("%c%c-%03d-%c-%c", l1, l2, N+100, l3, c) + + log.Printf("code: %v", code) + return code, nil } +func checksumLetter(idx uint32) byte { + return byte('A' + idx%26) +} + +func IsForbiddenPair(l1, l2 byte) bool { + return false +} diff --git a/serial/serial_test.go b/serial/serial_test.go index 905198c..3c7473e 100644 --- a/serial/serial_test.go +++ b/serial/serial_test.go @@ -1,128 +1,127 @@ package serial_test import ( - "testing" - "testing/quick" + "testing" + "testing/quick" - "yourmodule/serial" + "git.hoiting.org/micha/triplex/serial" ) // Property: Decode(Encode(code)) == code (voor geldige codes) func TestEncodeDecodeRoundtrip(t *testing.T) { - f := func(idx uint32) bool { - if idx >= serial.MaxIndex { - return true - } + f := func(idx uint32) bool { + if idx >= serial.MaxIndex { + return true + } - code, err := serial.Decode(idx) - if err != nil { - return false - } + code, err := serial.Decode(idx) + if err != nil { + return false + } - idx2, err := serial.Encode(code) - if err != nil { - return false - } + idx2, err := serial.Encode(code) + if err != nil { + return false + } - return idx == idx2 - } + return idx == idx2 + } - if err := quick.Check(f, nil); err != nil { - t.Fatalf("Encode/Decode roundtrip failed: %v", err) - } + if err := quick.Check(f, nil); err != nil { + t.Fatalf("Encode/Decode roundtrip failed: %v", err) + } } // Property: Decode(Encode(Decode(i))) == Decode(i) (idempotent op geldige indices) func TestDecodeEncodeDecodeIdempotent(t *testing.T) { - f := func(idx uint32) bool { - if idx >= serial.MaxIndex { - return true - } + f := func(idx uint32) bool { + if idx >= serial.MaxIndex { + return true + } - code1, err := serial.Decode(idx) - if err != nil { - return true // decode mag indices weigeren (bv. forbidden pair) - } + code1, err := serial.Decode(idx) + if err != nil { + return true // decode mag indices weigeren (bv. forbidden pair) + } - idx2, err := serial.Encode(code1) - if err != nil { - return false - } + idx2, err := serial.Encode(code1) + if err != nil { + return false + } - code2, err := serial.Decode(idx2) - if err != nil { - return false - } + code2, err := serial.Decode(idx2) + if err != nil { + return false + } - return code1 == code2 - } + return code1 == code2 + } - if err := quick.Check(f, nil); err != nil { - t.Fatalf("Decode/Encode/Decode idempotence failed: %v", err) - } + if err := quick.Check(f, nil); err != nil { + t.Fatalf("Decode/Encode/Decode idempotence failed: %v", err) + } } // Property: forbidden eerste twee letters komen nooit uit Decode func TestForbiddenPairsNeverDecoded(t *testing.T) { - f := func(idx uint32) bool { - if idx >= serial.MaxIndex { - return true - } + f := func(idx uint32) bool { + if idx >= serial.MaxIndex { + return true + } - code, err := serial.Decode(idx) - if err != nil { - return true // decode mag indices weigeren - } + code, err := serial.Decode(idx) + if err != nil { + return true // decode mag indices weigeren + } - l1 := code[0] - l2 := code[1] + l1 := code[0] + l2 := code[1] - return !serial.IsForbiddenPair(l1, l2) - } + return !serial.IsForbiddenPair(l1, l2) + } - if err := quick.Check(f, nil); err != nil { - t.Fatalf("Forbidden pairs appeared in Decode: %v", err) - } + if err := quick.Check(f, nil); err != nil { + t.Fatalf("Forbidden pairs appeared in Decode: %v", err) + } } // Optional: basis-check op formaat LL-NNN-L-C func TestDecodedFormatLooksCorrect(t *testing.T) { - f := func(idx uint32) bool { - if idx >= serial.MaxIndex { - return true - } + f := func(idx uint32) bool { + if idx >= serial.MaxIndex { + return true + } - code, err := serial.Decode(idx) - if err != nil { - return true - } + code, err := serial.Decode(idx) + if err != nil { + return true + } - if len(code) != 10 { - return false - } - if code[2] != '-' || code[6] != '-' || code[8] != '-' { - return false - } + if len(code) != 10 { + return false + } + if code[2] != '-' || code[6] != '-' || code[8] != '-' { + return false + } - // letters op posities 0,1,7,9 - for _, p := range []int{0, 1, 7, 9} { - if code[p] < 'A' || code[p] > 'Z' { - return false - } - } + // letters op posities 0,1,7,9 + for _, p := range []int{0, 1, 7, 9} { + if code[p] < 'A' || code[p] > 'Z' { + return false + } + } - // cijfers op posities 3,4,5 - for _, p := range []int{3, 4, 5} { - if code[p] < '0' || code[p] > '9' { - return false - } - } + // cijfers op posities 3,4,5 + for _, p := range []int{3, 4, 5} { + if code[p] < '0' || code[p] > '9' { + return false + } + } - return true - } + return true + } - if err := quick.Check(f, nil); err != nil { - t.Fatalf("Decoded format property failed: %v", err) - } + if err := quick.Check(f, nil); err != nil { + t.Fatalf("Decoded format property failed: %v", err) + } } -