Updated tests so they work with new FuncHandler signature

This commit is contained in:
Mattias Hansson 2026-04-13 20:29:45 +02:00
parent 652e147298
commit bd4dc5d885
3 changed files with 74 additions and 33 deletions

View file

@ -116,12 +116,33 @@ All file operations must be restricted to the project's source code and document
3. Update documentation in appropriate .md files 3. Update documentation in appropriate .md files
4. Consider adding examples in `examples/` directory 4. Consider adding examples in `examples/` directory
### Testing ### Testing and Rebuilding
**IMPORTANT**: The agent cannot run tests. Provide these instructions to the user: **IMPORTANT**: The agent cannot run tests or compile code. Provide these instructions to the user:
#### Testing:
- Run all tests: `go test ./...` - Run all tests: `go test ./...`
- Run specific package tests: `go test ./internal/compiler` - Run specific package tests: `go test ./internal/compiler`
- Test with verbose output: `go test -v ./...` - Test with verbose output: `go test -v ./...`
#### Rebuilding c65gm:
When making changes to the compiler, ask the user to rebuild c65gm:
```bash
go build -o c65gm
```
This creates a fresh binary with your changes. The agent should:
1. Make code changes
2. Ask the user to rebuild c65gm: `go build -o c65gm`
3. **Check file datetime**: Verify the c65gm binary was recently updated (use `ls -la c65gm` or similar)
4. Ask the user to run tests: `go test ./...`
5. Test the changes with example .c65 files
**IMPORTANT**: Always check the file datetime of the c65gm binary after asking for a rebuild. If the timestamp hasn't changed, the user may have forgotten to rebuild, or the build may have failed. Testing with an old version is wasteful and can lead to incorrect conclusions.
#### Compiling .c65 files:
```bash
C65LIBPATH=/app/lib ./c65gm -in input.c65 -out output.asm
```
## Common Pitfalls ## Common Pitfalls
1. **Expression evaluation**: Remember no operator precedence 1. **Expression evaluation**: Remember no operator precedence
@ -165,3 +186,24 @@ acme -f cbm -o output.prg output.asm
### Testing ### Testing
- `*_test.go` files throughout the codebase - `*_test.go` files throughout the codebase
- `examples/`: Functional test programs - `examples/`: Functional test programs
## Tool Notes
### Shell Environment
- **Shell**: Only `/bin/sh` (BusyBox) is available, not bash
- **The `bash` tool** in the interface runs commands through `/bin/sh` (BusyBox)
- **BusyBox limitations**: Many GNU extensions are not available
### grep Limitations
The environment uses BusyBox grep which doesn't support GNU grep extensions:
- **NOT supported**: `--include="*.go"`, `--exclude="*.md"`, etc.
- **Use instead**: `find /app -name "*.go" -type f -exec grep -l "pattern" {} \;`
- **Example**: Instead of `grep -r "CheckUnusedFunctions" /app --include="*.go"`, use:
```bash
find /app -name "*.go" -type f -exec grep -l "CheckUnusedFunctions" {} \;
```
### File Operations
- Use `find` with `-exec` for pattern-based file searches
- Use `grep` without GNU extensions for simple pattern matching
- Prefer the `bash` tool with proper BusyBox-compatible commands

View file

@ -1020,10 +1020,16 @@ func (fh *FunctionHandler) CheckUnusedFunctions() []string {
// Check if pragma indicates we should ignore unused warnings for this function // Check if pragma indicates we should ignore unused warnings for this function
if fh.pragma != nil { if fh.pragma != nil {
pragmaSet := fh.pragma.GetPragmaSetByIndex(funcDecl.Line.PragmaSetIndex) pragmaSet := fh.pragma.GetPragmaSetByIndex(funcDecl.Line.PragmaSetIndex)
// Skip warning if _P_IGNORE_UNUSED is enabled
value := pragmaSet.GetPragma("_P_IGNORE_UNUSED") value := pragmaSet.GetPragma("_P_IGNORE_UNUSED")
if value != "" && value != "0" { if value != "" && value != "0" {
continue // Skip warning for this function continue // Skip warning for this function
} }
// Also skip warning if _P_REMOVE_UNUSED is enabled (function will be removed)
removeValue := pragmaSet.GetPragma("_P_REMOVE_UNUSED")
if removeValue != "" && removeValue != "0" {
continue // Skip warning for this function (it will be removed)
}
} }
// Format warning message with file and line info // Format warning message with file and line info

View file

@ -215,13 +215,6 @@ func TestHandleFuncDecl_VoidFunction(t *testing.T) {
t.Fatalf("expected funcName = \"test_void\", got %q", funcName) t.Fatalf("expected funcName = \"test_void\", got %q", funcName)
} }
if len(asm) != 1 {
t.Fatalf("expected 1 asm line, got %d", len(asm))
}
if asm[0] != "test_void" {
t.Errorf("expected label 'test_void', got %q", asm[0])
}
if !fh.FuncExists("test_void") { if !fh.FuncExists("test_void") {
t.Error("function should exist") t.Error("function should exist")
} }
@ -238,13 +231,13 @@ func TestHandleFuncDecl_WithExistingParams(t *testing.T) {
st.AddVar("x", "test_func", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("x", "test_func", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
st.AddVar("y", "test_func", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("y", "test_func", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_func ( x y )")) funcName, err := fh.HandleFuncDecl(makeLine("FUNC test_func ( x y )"))
if err != nil { if err != nil {
t.Fatalf("HandleFuncDecl failed: %v", err) t.Fatalf("HandleFuncDecl failed: %v", err)
} }
if len(asm) != 1 { if funcName != "test_func" {
t.Fatalf("expected 1 asm line, got %d", len(asm)) t.Fatalf("expected funcName = \"test_func\", got %q", funcName)
} }
funcDecl := fh.findFunc("test_func") funcDecl := fh.findFunc("test_func")
@ -263,13 +256,13 @@ func TestHandleFuncDecl_ImplicitDeclarations(t *testing.T) {
pragma := preproc.NewPragma() pragma := preproc.NewPragma()
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_impl ( {BYTE a} {WORD b} )")) funcName, err := fh.HandleFuncDecl(makeLine("FUNC test_impl ( {BYTE a} {WORD b} )"))
if err != nil { if err != nil {
t.Fatalf("HandleFuncDecl failed: %v", err) t.Fatalf("HandleFuncDecl failed: %v", err)
} }
if len(asm) != 1 { if funcName != "test_impl" {
t.Fatalf("expected 1 asm line, got %d", len(asm)) t.Fatalf("expected funcName = \"test_impl\", got %q", funcName)
} }
// Check that variables were declared // Check that variables were declared
@ -297,7 +290,7 @@ func TestHandleFuncDecl_WithDirections(t *testing.T) {
pragma := preproc.NewPragma() pragma := preproc.NewPragma()
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
_, _, err := fh.HandleFuncDecl(makeLine("FUNC test_dir ( in:{BYTE a} out:{BYTE b} io:{WORD c} )")) _, err := fh.HandleFuncDecl(makeLine("FUNC test_dir ( in:{BYTE a} out:{BYTE b} io:{WORD c} )"))
if err != nil { if err != nil {
t.Fatalf("HandleFuncDecl failed: %v", err) t.Fatalf("HandleFuncDecl failed: %v", err)
} }
@ -369,7 +362,7 @@ func TestHandleFuncDecl_Errors(t *testing.T) {
// Special case for redeclaration test // Special case for redeclaration test
if tt.name == "redeclaration" { if tt.name == "redeclaration" {
fh.HandleFuncDecl(makeLine("FUNC duplicate ( {BYTE x} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC duplicate ( {BYTE x} )"))
} }
_, err := fh.HandleFuncDecl(makeLine(tt.line)) _, err := fh.HandleFuncDecl(makeLine(tt.line))
@ -393,7 +386,7 @@ func TestHandleFuncCall_VarArgs(t *testing.T) {
// Declare function with params // Declare function with params
st.AddVar("param_a", "test_func", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("param_a", "test_func", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
st.AddVar("param_b", "test_func", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("param_b", "test_func", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test_func ( param_a param_b )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test_func ( param_a param_b )"))
// Declare caller variables // Declare caller variables
st.AddVar("var_a", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("var_a", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
@ -435,7 +428,7 @@ func TestHandleFuncCall_OutParams(t *testing.T) {
// Declare function with out param // Declare function with out param
st.AddVar("result", "get_result", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("result", "get_result", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC get_result ( out:result )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC get_result ( out:result )"))
// Declare caller variable // Declare caller variable
st.AddVar("output", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("output", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
@ -475,7 +468,7 @@ func TestHandleFuncCall_ConstArgs(t *testing.T) {
// Declare function // Declare function
st.AddVar("x", "test_const", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("x", "test_const", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
st.AddVar("y", "test_const", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("y", "test_const", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test_const ( x y )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test_const ( x y )"))
asm, err := fh.HandleFuncCall(makeLine("CALL test_const ( 42 $1234 )")) asm, err := fh.HandleFuncCall(makeLine("CALL test_const ( 42 $1234 )"))
if err != nil { if err != nil {
@ -511,7 +504,7 @@ func TestHandleFuncCall_LabelArg(t *testing.T) {
// Declare function // Declare function
st.AddVar("ptr", "test_label", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("ptr", "test_label", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test_label ( ptr )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test_label ( ptr )"))
asm, err := fh.HandleFuncCall(makeLine("CALL test_label ( @my_label )")) asm, err := fh.HandleFuncCall(makeLine("CALL test_label ( @my_label )"))
if err != nil { if err != nil {
@ -544,7 +537,7 @@ func TestHandleFuncCall_StringArg(t *testing.T) {
// Declare function // Declare function
st.AddVar("str_ptr", "print", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("str_ptr", "print", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC print ( str_ptr )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC print ( str_ptr )"))
asm, err := fh.HandleFuncCall(makeLine(`CALL print ( "hello" )`)) asm, err := fh.HandleFuncCall(makeLine(`CALL print ( "hello" )`))
if err != nil { if err != nil {
@ -587,7 +580,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
name: "wrong arg count", name: "wrong arg count",
setup: func(fh *FunctionHandler, st *SymbolTable) { setup: func(fh *FunctionHandler, st *SymbolTable) {
st.AddVar("x", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("x", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test ( x )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
}, },
line: "CALL test ( 1 2 )", line: "CALL test ( 1 2 )",
wantErr: "expected 1 arguments, got 2", wantErr: "expected 1 arguments, got 2",
@ -598,7 +591,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
name: "type mismatch", name: "type mismatch",
setup: func(fh *FunctionHandler, st *SymbolTable) { setup: func(fh *FunctionHandler, st *SymbolTable) {
st.AddVar("param", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("param", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test ( param )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test ( param )"))
st.AddVar("wvar", "", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("wvar", "", KindWord, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
}, },
line: "CALL test ( wvar )", line: "CALL test ( wvar )",
@ -608,7 +601,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
name: "const to out param", name: "const to out param",
setup: func(fh *FunctionHandler, st *SymbolTable) { setup: func(fh *FunctionHandler, st *SymbolTable) {
st.AddVar("result", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("result", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test ( out:result )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test ( out:result )"))
}, },
line: "CALL test ( 42 )", line: "CALL test ( 42 )",
wantErr: "out/io parameter", wantErr: "out/io parameter",
@ -617,7 +610,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
name: "label to byte param", name: "label to byte param",
setup: func(fh *FunctionHandler, st *SymbolTable) { setup: func(fh *FunctionHandler, st *SymbolTable) {
st.AddVar("x", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("x", "test", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
fh.HandleFuncDecl(makeLine("FUNC test ( x )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
}, },
line: "CALL test ( @label )", line: "CALL test ( @label )",
wantErr: "byte parameter", wantErr: "byte parameter",
@ -653,7 +646,7 @@ func TestHandleFuncCall_EmptyParens(t *testing.T) {
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
// Declare void function // Declare void function
fh.HandleFuncDecl(makeLine("FUNC init")) _, _ = fh.HandleFuncDecl(makeLine("FUNC init"))
tests := []struct { tests := []struct {
name string name string
@ -696,7 +689,7 @@ func TestEndFunction(t *testing.T) {
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
// Declare function (pushes to stack) // Declare function (pushes to stack)
fh.HandleFuncDecl(makeLine("FUNC test ( {BYTE x} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test ( {BYTE x} )"))
if fh.CurrentFunction() != "test" { if fh.CurrentFunction() != "test" {
t.Errorf("current function = %q, want 'test'", fh.CurrentFunction()) t.Errorf("current function = %q, want 'test'", fh.CurrentFunction())
@ -721,12 +714,12 @@ func TestCurrentFunction(t *testing.T) {
t.Error("expected empty current function initially") t.Error("expected empty current function initially")
} }
fh.HandleFuncDecl(makeLine("FUNC func1 ( {BYTE x} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC func1 ( {BYTE x} )"))
if fh.CurrentFunction() != "func1" { if fh.CurrentFunction() != "func1" {
t.Errorf("expected 'func1', got %q", fh.CurrentFunction()) t.Errorf("expected 'func1', got %q", fh.CurrentFunction())
} }
fh.HandleFuncDecl(makeLine("FUNC func2 ( {BYTE y} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC func2 ( {BYTE y} )"))
if fh.CurrentFunction() != "func2" { if fh.CurrentFunction() != "func2" {
t.Errorf("expected 'func2', got %q", fh.CurrentFunction()) t.Errorf("expected 'func2', got %q", fh.CurrentFunction())
} }
@ -922,7 +915,7 @@ func TestHandleFuncCall_AbsoluteParams(t *testing.T) {
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
// Declare function with absolute params // Declare function with absolute params
fh.HandleFuncDecl(makeLine("FUNC test_abs ( {BYTE param_a @ $fa} {WORD param_b @ $fb} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC test_abs ( {BYTE param_a @ $fa} {WORD param_b @ $fb} )"))
// Declare caller variables // Declare caller variables
st.AddVar("var_a", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("var_a", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})
@ -963,7 +956,7 @@ func TestHandleFuncCall_AbsoluteOutParams(t *testing.T) {
fh := NewFunctionHandler(st, ls, csh, pragma) fh := NewFunctionHandler(st, ls, csh, pragma)
// Declare function with absolute out param // Declare function with absolute out param
fh.HandleFuncDecl(makeLine("FUNC get_result ( out:{BYTE result @ $fa} )")) _, _ = fh.HandleFuncDecl(makeLine("FUNC get_result ( out:{BYTE result @ $fa} )"))
// Declare caller variable // Declare caller variable
st.AddVar("output", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1}) st.AddVar("output", "", KindByte, 0, preproc.Line{Filename: "test.c65", LineNo: 1})