add AllKinds to the public API. Use it as a single source of truth.

This commit is contained in:
2026-08-01 04:18:48 +01:00
parent c55ab96a4f
commit af06fab1f1
2 changed files with 115 additions and 19 deletions

View File

@@ -1,6 +1,10 @@
package lottery package lottery
import "fmt" import (
"fmt"
"slices"
"strings"
)
type Kind string type Kind string
@@ -12,22 +16,43 @@ const (
KindPowerball Kind = "powerball" KindPowerball Kind = "powerball"
) )
func ParseKind(kind string) (Kind, error) { var allKinds = []Kind{
switch kind { KindLotto,
case "lotto": KindEuroMillions,
return KindLotto, nil KindSetForLife,
case "euromillions": KindThunderball,
return KindEuroMillions, nil KindPowerball,
case "setforlife": }
return KindSetForLife, nil
case "thunderball": var allKindsText = []string{
return KindThunderball, nil string(KindLotto),
case "powerball": string(KindEuroMillions),
return KindPowerball, nil string(KindSetForLife),
default: string(KindThunderball),
return "", fmt.Errorf( string(KindPowerball),
"invalid lottery kind: %s, must be one of: lotto, euromillions, setforlife, thunderball, powerball", }
kind,
) var allKindsCSV = strings.Join(allKindsText, ", ")
}
// AllKinds returns the complete, ordered list of supported lottery kinds.
//
// The returned slice is a copy and can be modified safely by callers.
func AllKinds() []Kind {
kinds := make([]Kind, len(allKinds))
copy(kinds, allKinds)
return kinds
}
// ParseKind parses a string into a Kind, returning an error if the string is not a valid kind.
func ParseKind(kind string) (Kind, error) {
parsed := Kind(kind)
if slices.Contains(allKinds, parsed) {
return parsed, nil
}
return "", fmt.Errorf(
"invalid lottery kind: %s, must be one of: %s",
kind,
allKindsCSV,
)
} }

71
kinds_test.go Normal file
View File

@@ -0,0 +1,71 @@
package lottery
import (
"strings"
"testing"
)
func TestAllKindsReturnsExpectedOrder(t *testing.T) {
t.Parallel()
got := AllKinds()
want := []Kind{
KindLotto,
KindEuroMillions,
KindSetForLife,
KindThunderball,
KindPowerball,
}
if len(got) != len(want) {
t.Fatalf("expected %d kinds, got %d", len(want), len(got))
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("kind at index %d: expected %q, got %q", i, want[i], got[i])
}
}
}
func TestAllKindsReturnsCopy(t *testing.T) {
t.Parallel()
first := AllKinds()
first[0] = "mutated"
again := AllKinds()
if again[0] != KindLotto {
t.Fatalf("expected AllKinds to return a defensive copy")
}
}
func TestParseKindAcceptsAllKinds(t *testing.T) {
t.Parallel()
for _, kind := range AllKinds() {
parsed, err := ParseKind(string(kind))
if err != nil {
t.Fatalf("expected no error for %q, got %v", kind, err)
}
if parsed != kind {
t.Fatalf("expected %q, got %q", kind, parsed)
}
}
}
func TestParseKindIncludesAllKindsInError(t *testing.T) {
t.Parallel()
_, err := ParseKind("invalid")
if err == nil {
t.Fatalf("expected an error for invalid kind")
}
message := err.Error()
for _, kind := range AllKinds() {
if !strings.Contains(message, string(kind)) {
t.Fatalf("expected error message to contain kind %q: %s", kind, message)
}
}
}