luhn_test.gno
2.39 Kb · 95 lines
1package luhn
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/uassert/v0"
8)
9
10func TestValid(t *testing.T) {
11 cases := []struct {
12 name string
13 in string
14 want bool
15 }{
16 {"known-good test card", "4539148803436467", true},
17 {"spaces ignored", "4539 1488 0343 6467", true},
18 {"hyphens ignored", "4539-1488-0343-6467", true},
19 {"single digit flipped", "4539148803436468", false},
20 {"adjacent transposition", "4539148803436647", false},
21 {"classic 79927398713", "79927398713", true},
22 {"classic off by one", "79927398710", false},
23 {"all zeros is valid", "00", true},
24 {"letters rejected", "4539abc8803436467", false},
25 {"empty rejected", "", false},
26 {"one digit rejected", "7", false},
27 {"separators only rejected", " - ", false},
28 {"over MaxLen rejected", strings.Repeat("0", MaxLen+1), false},
29 }
30 for _, c := range cases {
31 t.Run(c.name, func(t *testing.T) {
32 uassert.Equal(t, c.want, Valid(c.in))
33 })
34 }
35}
36
37func TestCheckDigit(t *testing.T) {
38 cases := []struct {
39 payload string
40 want int
41 }{
42 {"7992739871", 3},
43 {"453914880343646", 7},
44 {"0", 0},
45 }
46 for _, c := range cases {
47 got, ok := CheckDigit(c.payload)
48 uassert.True(t, ok)
49 uassert.Equal(t, c.want, got)
50 }
51}
52
53func TestCheckDigitRejectsBadInput(t *testing.T) {
54 for _, in := range []string{"", "abc", " - "} {
55 _, ok := CheckDigit(in)
56 uassert.False(t, ok)
57 }
58}
59
60// Append must produce something Valid accepts — the round-trip property.
61func TestAppendRoundTrip(t *testing.T) {
62 payloads := []string{"7992739871", "453914880343646", "1", "123456789012345"}
63 for _, p := range payloads {
64 got, ok := Append(p)
65 uassert.True(t, ok)
66 uassert.True(t, Valid(got))
67 uassert.Equal(t, len(p)+1, len(got))
68 }
69}
70
71// Append strips separators, so a spaced payload yields the same digits.
72func TestAppendStripsSeparators(t *testing.T) {
73 a, ok := Append("4539 1488 0343 646")
74 uassert.True(t, ok)
75 b, ok2 := Append("453914880343646")
76 uassert.True(t, ok2)
77 uassert.Equal(t, b, a)
78 uassert.Equal(t, "4539148803436467", a)
79}
80
81// Every single-digit change to a valid number must be caught: that is the
82// guarantee Luhn actually makes.
83func TestDetectsEverySingleDigitError(t *testing.T) {
84 const base = "4539148803436467"
85 uassert.True(t, Valid(base))
86 for i := 0; i < len(base); i++ {
87 for d := byte('0'); d <= '9'; d++ {
88 if d == base[i] {
89 continue
90 }
91 mutated := base[:i] + string(d) + base[i+1:]
92 uassert.False(t, Valid(mutated))
93 }
94 }
95}