package optimizer import ( "testing" "c65gm/internal/preproc" ) func TestNewConfigWithAll(t *testing.T) { ps := preproc.NewPragmaSet(map[string]string{ "_P_OPT_ALL": "1", "_P_OPT_DEBUG": "1", }) cfg := NewConfig(ps) if !cfg.Any() { t.Error("expected Any()=true") } if !cfg.EnableLoad { t.Error("expected EnableLoad=true from _P_OPT_ALL") } if !cfg.EnableImm { t.Error("expected EnableImm=true from _P_OPT_ALL") } if !cfg.Debug { t.Error("expected Debug=true") } } func TestParseExcludeRange(t *testing.T) { tests := []struct { name string input string wantOk bool wantS uint16 wantE uint16 }{ {"hex", "0xD000:0xDFFF", true, 0xD000, 0xDFFF}, {"hex lowercase", "0xd000:0xdfff", true, 0xD000, 0xDFFF}, {"hex mixed case", "0XD000:0XdFfF", true, 0xD000, 0xDFFF}, {"decimal", "53248:57343", true, 53248, 57343}, {"single address", "0xD020:0xD020", true, 0xD020, 0xD020}, {"invalid range", "0xFFFF:0x0000", false, 0, 0}, {"bad format", "garbage", false, 0, 0}, {"bad hex", "0xGGGG:0x0000", false, 0, 0}, {"too many colons", "0xD000:0xDFFF:extra", false, 0, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r, err := ParseExcludeRange(tt.input) if tt.wantOk { if err != nil { t.Errorf("unexpected error: %v", err) } if r.Start != tt.wantS || r.End != tt.wantE { t.Errorf("got %04X:%04X, want %04X:%04X", r.Start, r.End, tt.wantS, tt.wantE) } } else { if err == nil { t.Errorf("expected error, got %04X:%04X", r.Start, r.End) } } }) } } func TestAddIORegions(t *testing.T) { cfg := &Config{} cfg.AddIORegions([]IORegion{ {Start: 0xD000, End: 0xDFFF}, }) if !cfg.IOMap[0xD000] { t.Error("expected 0xD000 to be marked I/O") } if !cfg.IOMap[0xDFFF] { t.Error("expected 0xDFFF to be marked I/O") } if cfg.IOMap[0xCFFF] { t.Error("expected 0xCFFF to NOT be marked I/O") } if cfg.IOMap[0xE000] { t.Error("expected 0xE000 to NOT be marked I/O") } } func TestAddIORegionsMultiple(t *testing.T) { cfg := &Config{} cfg.AddIORegions([]IORegion{ {Start: 0xD000, End: 0xDFFF}, {Start: 0xDC00, End: 0xDC0F}, // overlaps — still correct }) if !cfg.IOMap[0xD000] { t.Error("expected 0xD000 I/O") } if !cfg.IOMap[0xDC00] { t.Error("expected 0xDC00 I/O") } if !cfg.IOMap[0xDC0F] { t.Error("expected 0xDC0F I/O") } } func TestBuildIOMap(t *testing.T) { p := preproc.NewPragma() p.AddPragma("_P_OPT_IO", "$D000 $DFFF") // Last pragma set should have _P_OPT_IO ps := p.GetPragmaSetByIndex(p.GetCurrentPragmaSetIndex()) cfg := NewConfig(ps) cfg.BuildIOMap(p) if !cfg.IOMap[0xD000] { t.Error("expected $D000 I/O from pragma") } if !cfg.IOMap[0xDFFF] { t.Error("expected $DFFF I/O from pragma") } } func TestBuildIOMapMultiple(t *testing.T) { // Simulate two _P_OPT_IO pragmas p := preproc.NewPragma() p.AddPragma("_P_OPT_IO", "$D000 $DFFF") p.AddPragma("_P_OPT_IO", "$DC00 $DC0F") p.AddPragma("_P_SOMETHING_ELSE", "1") // BuildIOMap scans ALL sets, finding _P_OPT_IO at index 1 and 2 ps := p.GetPragmaSetByIndex(p.GetCurrentPragmaSetIndex()) cfg := NewConfig(ps) cfg.BuildIOMap(p) if !cfg.IOMap[0xD000] { t.Error("expected $D000 I/O") } if !cfg.IOMap[0xDC00] { t.Error("expected $DC00 I/O") } } func TestBuildIOMapEmpty(t *testing.T) { p := preproc.NewPragma() ps := p.GetPragmaSetByIndex(p.GetCurrentPragmaSetIndex()) cfg := NewConfig(ps) cfg.BuildIOMap(p) for _, addr := range []uint16{0, 0xD000, 0xFFFF} { if cfg.IOMap[addr] { t.Errorf("address %04X should not be I/O", addr) } } } func TestNewConfigPragmasAccumulate(t *testing.T) { // Pragma sets COPY previous values — so last set has ALL pragmas p := preproc.NewPragma() p.AddPragma("_P_OPT_ALL", "1") p.AddPragma("_P_OPT_DEBUG", "1") p.AddPragma("_P_SOMETHING_ELSE", "1") // Last set should have all three ps := p.GetPragmaSetByIndex(p.GetCurrentPragmaSetIndex()) if v := ps.GetPragma("_P_OPT_ALL"); v != "1" { t.Errorf("expected _P_OPT_ALL=1, got %q", v) } if v := ps.GetPragma("_P_OPT_DEBUG"); v != "1" { t.Errorf("expected _P_OPT_DEBUG=1, got %q", v) } if v := ps.GetPragma("_P_SOMETHING_ELSE"); v != "1" { t.Errorf("expected _P_SOMETHING_ELSE=1, got %q", v) } cfg := NewConfig(ps) if !cfg.Any() { t.Error("expected Any()=true") } if !cfg.Debug { t.Error("expected Debug=true") } }