package luajit_test import ( "testing" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) func TestPushGoFunction(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Define a simple function that adds two numbers add := func(s *luajit.State) int { a := s.ToNumber(1) b := s.ToNumber(2) s.PushNumber(a + b) return 1 // Return one result } // Push the function onto the stack if err := state.PushGoFunction(add); err != nil { t.Fatalf("PushGoFunction failed: %v", err) } // Verify that a function is on the stack if !state.IsFunction(-1) { t.Fatalf("Expected function at top of stack") } // Push arguments state.PushNumber(3) state.PushNumber(4) // Call the function if err := state.Call(2, 1); err != nil { t.Fatalf("Failed to call function: %v", err) } // Check the result if state.ToNumber(-1) != 7 { t.Fatalf("Function returned %f, expected 7", state.ToNumber(-1)) } state.Pop(1) } func TestRegisterGoFunction(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Define a function that squares a number square := func(s *luajit.State) int { x := s.ToNumber(1) s.PushNumber(x * x) return 1 } // Register the function if err := state.RegisterGoFunction("square", square); err != nil { t.Fatalf("RegisterGoFunction failed: %v", err) } // Call the function from Lua if err := state.DoString("result = square(5)"); err != nil { t.Fatalf("Failed to call registered function: %v", err) } // Check the result state.GetGlobal("result") if state.ToNumber(-1) != 25 { t.Fatalf("Function returned %f, expected 25", state.ToNumber(-1)) } state.Pop(1) // Test UnregisterGoFunction state.UnregisterGoFunction("square") // Function should no longer exist err := state.DoString("result = square(5)") if err == nil { t.Fatalf("Expected error after unregistering function, got nil") } } func TestGoFunctionWithErrorHandling(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Function that returns an error in Lua errFunc := func(s *luajit.State) int { s.PushString("error from Go function") return -1 // Signal error } // Register the function if err := state.RegisterGoFunction("errorFunc", errFunc); err != nil { t.Fatalf("RegisterGoFunction failed: %v", err) } // Call the function expecting an error err := state.DoString("result = errorFunc()") if err == nil { t.Fatalf("Expected error from function, got nil") } // Error message should contain our message luaErr, ok := err.(*luajit.LuaError) if !ok { t.Fatalf("Expected LuaError, got %T: %v", err, err) } if luaErr.Message == "" { t.Fatalf("Expected non-empty error message from Go function") } } func TestCleanup(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } // Register several functions for i := 0; i < 5; i++ { dummy := func(s *luajit.State) int { return 0 } if err := state.RegisterGoFunction("dummy", dummy); err != nil { t.Fatalf("RegisterGoFunction failed: %v", err) } } // Call Cleanup explicitly state.Cleanup() // Make sure we can still close the state state.Close() // Also test that Close can be called after Cleanup state = luajit.New() if state == nil { t.Fatal("Failed to create second Lua state") } state.Close() // Should call Cleanup internally } func TestGoFunctionErrorPointer(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Create a Lua function that calls a non-existent Go function pointer // This isn't a direct test of internal implementation, but tries to cover // error cases in the goFunctionWrapper code := ` function test() -- This is a stub that doesn't actually call the wrapper, -- but we're testing error handling in our State.DoString return "test" end ` if err := state.DoString(code); err != nil { t.Fatalf("Failed to define test function: %v", err) } // The real test is that Cleanup doesn't crash state.Cleanup() }