c65gm/internal/commands/point_test.go

131 lines
3.3 KiB
Go

package commands
import (
"strings"
"testing"
"c65gm/internal/compiler"
"c65gm/internal/preproc"
)
func TestPointerCommand_Generate(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantAsm []string
}{
{
name: "pointer to label — uses A only",
line: "POINTER ptr -> TARGET",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("ptr", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
},
wantAsm: []string{
"\tlda #<TARGET",
"\tsta ptr",
"\tlda #>TARGET",
"\tsta ptr+1",
},
},
{
name: "pointer to variable — uses A only",
line: "POINTER ptr TO targetVar",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("ptr", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
st.AddVar("targetVar", "", compiler.KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
},
wantAsm: []string{
"\tlda #<targetVar",
"\tsta ptr",
"\tlda #>targetVar",
"\tsta ptr+1",
},
},
{
name: "pointer to numeric address — uses A only",
line: "POINTER ptr -> 53280",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("ptr", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PointerCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
if err := cmd.Interpret(line, ctx); err != nil {
t.Fatalf("Interpret() error = %v", err)
}
asm, err := cmd.Generate(ctx)
if err != nil {
t.Fatalf("Generate() error = %v", err)
}
if tt.name == "pointer to numeric address — uses A only" {
foundLo := false
foundHi := false
foundSta := false
for _, a := range asm {
if strings.Contains(a, "lda #<") {
foundLo = true
}
if strings.Contains(a, "lda #>") {
foundHi = true
}
if strings.Contains(a, "sta ptr+1") {
foundSta = true
}
}
if !foundLo || !foundHi || !foundSta {
t.Errorf("expected A-only pattern (lda #< / sta ptr / lda #> / sta ptr+1), got:\n%s", strings.Join(asm, "\n"))
}
return
}
if !equalAsm(asm, tt.wantAsm) {
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
strings.Join(asm, "\n"),
strings.Join(tt.wantAsm, "\n"))
}
})
}
}
func TestPointerCommand_NoXRegister(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
ctx.SymbolTable.AddVar("ptr", "", compiler.KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
cmd := &PointerCommand{}
line := preproc.Line{
Text: "POINTER ptr -> $0400",
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
if err := cmd.Interpret(line, ctx); err != nil {
t.Fatalf("Interpret() error = %v", err)
}
asm, err := cmd.Generate(ctx)
if err != nil {
t.Fatalf("Generate() error = %v", err)
}
joined := strings.Join(asm, "\n")
if strings.Contains(joined, "ldx") || strings.Contains(joined, "stx") {
t.Errorf("POINTER should not use X register, got:\n%s", joined)
}
}