lseq/conformance-tests/runners/golang/main_test.go

124 lines
2.8 KiB
Go

package main
import (
"encoding/json"
"os"
"path/filepath"
"sort"
"strings"
"testing"
"peoplesgrocers.com/code/oss/lseq/golang"
)
type Operation struct {
Before *int `json:"before,omitempty"`
After *int `json:"after,omitempty"`
Expected string `json:"expected"`
}
type Scenario struct {
Name string `json:"name"`
Description string `json:"description"`
Seed int `json:"seed"`
Init []string `json:"init"`
RNG []float64 `json:"rng"`
Operations []Operation `json:"operations"`
}
func createMockRandom(values []float64) func() float64 {
index := 0
return func() float64 {
if index >= len(values) {
panic("ran out of random values")
}
v := values[index]
index++
return v
}
}
func TestConformance(t *testing.T) {
testDataDir := "../../genfiles"
entries, err := os.ReadDir(testDataDir)
if err != nil {
t.Fatalf("Failed to read test data directory: %v", err)
}
var files []string
for _, entry := range entries {
if strings.HasSuffix(entry.Name(), ".scenario.json") {
files = append(files, entry.Name())
}
}
sort.Strings(files)
for _, file := range files {
filePath := filepath.Join(testDataDir, file)
data, err := os.ReadFile(filePath)
if err != nil {
t.Fatalf("Failed to read %s: %v", file, err)
}
var scenario Scenario
if err := json.Unmarshal(data, &scenario); err != nil {
t.Fatalf("Failed to parse %s: %v", file, err)
}
t.Run(scenario.Name, func(t *testing.T) {
mockRandom := createMockRandom(scenario.RNG)
l := lseq.NewLSEQ(mockRandom)
state := make([]string, len(scenario.Init))
copy(state, scenario.Init)
for i, op := range scenario.Operations {
var beforeKey, afterKey *string
var insertIdx int
if op.Before != nil {
// Insert before index X
idx := *op.Before
if idx < 0 {
idx = len(state) + idx
}
if idx > 0 {
beforeKey = &state[idx-1]
}
if idx < len(state) {
afterKey = &state[idx]
}
insertIdx = idx
} else if op.After != nil {
// Insert after index X
idx := *op.After
if idx < 0 {
idx = len(state) + idx
}
if idx >= 0 && idx < len(state) {
beforeKey = &state[idx]
}
if idx+1 < len(state) {
afterKey = &state[idx+1]
}
insertIdx = idx + 1
} else {
// Neither specified - insert at end
if len(state) > 0 {
beforeKey = &state[len(state)-1]
}
insertIdx = len(state)
}
result := l.Alloc(beforeKey, afterKey)
if result != op.Expected {
t.Errorf("op %d: alloc(%v, %v) = %q, want %q",
i, beforeKey, afterKey, result, op.Expected)
}
// Insert result into state
state = append(state[:insertIdx], append([]string{result}, state[insertIdx:]...)...)
}
})
}
}