Files
2026-09-26 16:32:40 +03:00

164 lines
4.4 KiB
Go

package bootstrap
import (
"os"
"path/filepath"
"testing"
"time"
"aego/project"
)
func writeFile(t *testing.T, path, content string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
}
type fixture struct {
engine string
game *project.Project
}
func newFixture(t *testing.T) fixture {
t.Helper()
root := t.TempDir()
engine := filepath.Join(root, "engine")
writeFile(t, filepath.Join(engine, "go.mod"), "module aego\n\ngo 1.27\n")
writeFile(t, filepath.Join(engine, "app", "run", "run.go"), "package run\n")
writeFile(t, filepath.Join(engine, "engine", "res", "shaders", "sprite.vert"), "void main() {}\n")
gameDir := filepath.Join(engine, "examples", "game")
p, err := project.Create(gameDir, "Game", true)
if err != nil {
t.Fatal(err)
}
writeFile(t, filepath.Join(gameDir, "go.mod"),
"module game\n\ngo 1.27\n\nrequire aego v0.0.0\n\nreplace aego => ../..\n")
writeFile(t, filepath.Join(p.NativeDir(), "module.go"), "package native\n")
return fixture{engine: engine, game: p}
}
func key(t *testing.T, p *project.Project) Key {
t.Helper()
k, err := CacheKey(p, HostTarget(), "test")
if err != nil {
t.Fatal(err)
}
return k
}
func TestKeyTracksReplacedEngineSources(t *testing.T) {
f := newFixture(t)
base := key(t, f.game)
if key(t, f.game) != base {
t.Fatal("key is not deterministic")
}
writeFile(t, filepath.Join(f.engine, "app", "run", "run.go"), "package run\n\nconst X = 1\n")
if key(t, f.game) == base {
t.Fatal("editing the replaced engine did not change the key")
}
}
func TestKeyTracksEmbeddedEngineAssets(t *testing.T) {
f := newFixture(t)
base := key(t, f.game)
writeFile(t, filepath.Join(f.engine, "engine", "res", "shaders", "sprite.vert"), "void main() { }\n")
if key(t, f.game) == base {
t.Fatal("editing an embedded engine resource did not change the key")
}
}
func TestKeyIgnoresIrrelevantFiles(t *testing.T) {
f := newFixture(t)
base := key(t, f.game)
writeFile(t, filepath.Join(f.engine, "app", "run", "run_test.go"), "package run\n")
writeFile(t, filepath.Join(f.engine, ".cache", "native", "libSDL3.a"), "binary")
writeFile(t, filepath.Join(f.engine, ".git", "HEAD"), "ref")
writeFile(t, filepath.Join(f.engine, "tools", "genfont", "go.mod"), "module genfont\n")
writeFile(t, filepath.Join(f.engine, "tools", "genfont", "main.go"), "package main\n")
writeFile(t, filepath.Join(f.game.BuildDir(), "abc", "game"), "binary")
if key(t, f.game) != base {
t.Fatal("tests, caches, nested modules or build outputs changed the key")
}
}
func TestKeyTracksNativeSources(t *testing.T) {
f := newFixture(t)
base := key(t, f.game)
writeFile(t, filepath.Join(f.game.NativeDir(), "module.go"), "package native\n\nconst Speed = 2\n")
if key(t, f.game) == base {
t.Fatal("editing native code did not change the key")
}
}
func TestLocalReplaces(t *testing.T) {
root := t.TempDir()
writeFile(t, filepath.Join(root, "go.mod"), `module game
go 1.27
replace aego => ../engine // local engine
replace (
example.com/a v1.2.3 => ./vendor/a
example.com/b => example.com/b v1.0.0
example.com/c => /abs/c
)
`)
got, err := LocalReplaces(root)
if err != nil {
t.Fatal(err)
}
want := map[string]bool{
filepath.Clean(filepath.Join(root, "../engine")): true,
filepath.Clean(filepath.Join(root, "vendor", "a")): true,
filepath.Clean("/abs/c"): true,
}
if len(got) != len(want) {
t.Fatalf("replaces = %v", got)
}
for _, g := range got {
if !want[g] {
t.Fatalf("unexpected replace %q in %v", g, got)
}
}
}
func TestLocalReplacesWithoutGoMod(t *testing.T) {
got, err := LocalReplaces(t.TempDir())
if err != nil || len(got) != 0 {
t.Fatalf("got %v, %v", got, err)
}
}
func TestPruneKeepsRecentBuilds(t *testing.T) {
dir := t.TempDir()
names := []string{"a", "b", "c", "d", "e"}
for i, n := range names {
p := filepath.Join(dir, n)
os.MkdirAll(p, 0o755)
ts := int64(1_700_000_000 + i)
os.Chtimes(p, unixTime(ts), unixTime(ts))
}
pruneBuilds(dir, "e", 3)
for _, n := range []string{"e", "d", "c"} {
if _, err := os.Stat(filepath.Join(dir, n)); err != nil {
t.Fatalf("%s was pruned", n)
}
}
for _, n := range []string{"a", "b"} {
if _, err := os.Stat(filepath.Join(dir, n)); err == nil {
t.Fatalf("%s survived pruning", n)
}
}
}
func unixTime(s int64) time.Time {
return time.Unix(s, 0)
}