package assets import ( "bytes" "os" "path/filepath" "testing" ) func TestCompileDrivesEngineAndReplacesInPlace(t *testing.T) { home := t.TempDir() userData := filepath.Join(home, ".local", "share", "Neverwinter Nights") dev := filepath.Join(userData, "development") mc := filepath.Join(userData, "modelcompiler") for _, d := range []string{dev, mc} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } // Fake nwmain binary for discovery via --nwn. binDir := t.TempDir() nwmain := filepath.Join(binDir, "nwmain-linux") if err := os.WriteFile(nwmain, []byte("#!/bin/sh\n"), 0o755); err != nil { t.Fatal(err) } getenv := func(k string) string { switch k { case "HOME": return home case "DISPLAY": return ":0" // pretend a display exists so no xvfb wrap is needed } return "" } // Stub the engine: writes a binary compiled model into modelcompiler/. orig := runner defer func() { runner = orig }() runner = func(dir string, env []string, name string, args ...string) ([]byte, error) { // args: compilemodel stem := args[len(args)-1] compiled := filepath.Join(mc, stem+".mdl") return nil, os.WriteFile(compiled, []byte("\x00\x00compiled"), 0o644) } // Source tree with one ASCII model whose names already match its stem. srcDir := t.TempDir() src := filepath.Join(srcDir, "foo.mdl") body := "newmodel foo\nbeginmodelgeom foo\n node dummy foo\n parent null\n endnode\nendmodelgeom foo\ndonemodel foo\n" if err := os.WriteFile(src, []byte(body), 0o644); err != nil { t.Fatal(err) } var stdout, stderr bytes.Buffer code := runCompile([]string{"--nwn", nwmain, srcDir}, &stdout, &stderr, getenv) if code != exitOK { t.Fatalf("compile exit = %d\n%s", code, stderr.String()) } // The source is now binary (the compiled artifact moved back over it). data, err := os.ReadFile(src) if err != nil { t.Fatalf("compiled model missing: %v", err) } if string(data) != "\x00\x00compiled" { t.Fatalf("source not replaced by compiled binary: %q", data) } } func TestCompileAbortsOnNameMismatch(t *testing.T) { home := t.TempDir() if err := os.MkdirAll(filepath.Join(home, ".local", "share", "Neverwinter Nights", "development"), 0o755); err != nil { t.Fatal(err) } binDir := t.TempDir() nwmain := filepath.Join(binDir, "nwmain-linux") if err := os.WriteFile(nwmain, []byte("#!/bin/sh\n"), 0o755); err != nil { t.Fatal(err) } getenv := func(k string) string { if k == "HOME" { return home } if k == "DISPLAY" { return ":0" } return "" } orig := runner defer func() { runner = orig }() engineCalled := false runner = func(string, []string, string, ...string) ([]byte, error) { engineCalled = true return nil, nil } srcDir := t.TempDir() // Internal name "wrong" != stem "foo": must abort before touching the engine. if err := os.WriteFile(filepath.Join(srcDir, "foo.mdl"), []byte("newmodel wrong\ndonemodel wrong\n"), 0o644); err != nil { t.Fatal(err) } var stdout, stderr bytes.Buffer if code := runCompile([]string{"--nwn", nwmain, srcDir}, &stdout, &stderr, getenv); code != exitFail { t.Fatalf("mismatch exit = %d, want %d", code, exitFail) } if engineCalled { t.Fatal("engine should not run for a name-mismatched model") } }