package luajit_test import ( "reflect" "testing" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) func TestGetTableLength(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Create a table with numeric indices if err := state.DoString("t = {10, 20, 30, 40, 50}"); err != nil { t.Fatalf("Failed to create test table: %v", err) } // Get the table state.GetGlobal("t") length := state.GetTableLength(-1) if length != 5 { t.Fatalf("Expected length 5, got %d", length) } state.Pop(1) // Create a table with string keys if err := state.DoString("t2 = {a=1, b=2, c=3}"); err != nil { t.Fatalf("Failed to create test table: %v", err) } // Get the table state.GetGlobal("t2") length = state.GetTableLength(-1) if length != 0 { t.Fatalf("Expected length 0 for string-keyed table, got %d", length) } state.Pop(1) } func TestPushTable(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Create a test table testTable := map[string]any{ "int": 42, "float": 3.14, "string": "hello", "boolean": true, "nil": nil, } // Push the table onto the stack if err := state.PushTable(testTable); err != nil { t.Fatalf("Failed to push table: %v", err) } // Execute Lua code to test the table contents if err := state.DoString(` function validate_table(t) return t.int == 42 and math.abs(t.float - 3.14) < 0.0001 and t.string == "hello" and t.boolean == true and t["nil"] == nil end `); err != nil { t.Fatalf("Failed to create validation function: %v", err) } // Call the validation function state.GetGlobal("validate_table") state.PushCopy(-2) // Copy the table to the top if err := state.Call(1, 1); err != nil { t.Fatalf("Failed to call validation function: %v", err) } if !state.ToBoolean(-1) { t.Fatalf("Table validation failed") } state.Pop(2) // Pop the result and the table } func TestToTable(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Test regular table conversion if err := state.DoString(`t = {a=1, b=2.5, c="test", d=true, e=nil}`); err != nil { t.Fatalf("Failed to create test table: %v", err) } state.GetGlobal("t") table, err := state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert table: %v", err) } state.Pop(1) expected := map[string]any{ "a": float64(1), "b": 2.5, "c": "test", "d": true, } for k, v := range expected { if table[k] != v { t.Fatalf("Expected table[%s] = %v, got %v", k, v, table[k]) } } // Test array-like table conversion if err := state.DoString(`arr = {10, 20, 30, 40, 50}`); err != nil { t.Fatalf("Failed to create test array: %v", err) } state.GetGlobal("arr") table, err = state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert array table: %v", err) } state.Pop(1) // For array tables, we should get a special format with an empty key // and the array as the value expectedArray := []float64{10, 20, 30, 40, 50} if arr, ok := table[""].([]float64); !ok { t.Fatalf("Expected array table to be converted with empty key, got: %v", table) } else if !reflect.DeepEqual(arr, expectedArray) { t.Fatalf("Expected %v, got %v", expectedArray, arr) } // Test invalid table index _, err = state.ToTable(100) if err == nil { t.Fatalf("Expected error for invalid table index, got nil") } // Test non-table value state.PushNumber(123) _, err = state.ToTable(-1) if err == nil { t.Fatalf("Expected error for non-table value, got nil") } state.Pop(1) // Test mixed array with non-numeric values if err := state.DoString(`mixed = {10, 20, key="value", 30}`); err != nil { t.Fatalf("Failed to create mixed table: %v", err) } state.GetGlobal("mixed") table, err = state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert mixed table: %v", err) } // Let's print the table for debugging t.Logf("Table contents: %v", table) state.Pop(1) // Check if the array part is detected and stored with empty key if arr, ok := table[""]; !ok { t.Fatalf("Expected array-like part to be detected, got: %v", table) } else { // Verify the array contains the expected values expectedArr := []float64{10, 20, 30} actualArr := arr.([]float64) if len(actualArr) != len(expectedArr) { t.Fatalf("Expected array length %d, got %d", len(expectedArr), len(actualArr)) } for i, v := range expectedArr { if actualArr[i] != v { t.Fatalf("Expected array[%d] = %v, got %v", i, v, actualArr[i]) } } } // Based on the implementation, we need to create a separate test for string keys if err := state.DoString(`dict = {foo="bar", baz="qux"}`); err != nil { t.Fatalf("Failed to create dict table: %v", err) } state.GetGlobal("dict") dictTable, err := state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert dict table: %v", err) } state.Pop(1) // Check the string keys if val, ok := dictTable["foo"]; !ok || val != "bar" { t.Fatalf("Expected dictTable[\"foo\"] = \"bar\", got: %v", val) } if val, ok := dictTable["baz"]; !ok || val != "qux" { t.Fatalf("Expected dictTable[\"baz\"] = \"qux\", got: %v", val) } } func TestTablePooling(t *testing.T) { state := luajit.New() if state == nil { t.Fatal("Failed to create Lua state") } defer state.Close() // Create a Lua table and push it onto the stack if err := state.DoString(`t = {a=1, b=2}`); err != nil { t.Fatalf("Failed to create test table: %v", err) } state.GetGlobal("t") // First conversion - should get a table from the pool table1, err := state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert table (1): %v", err) } // Second conversion - should get another table from the pool table2, err := state.ToTable(-1) if err != nil { t.Fatalf("Failed to convert table (2): %v", err) } // Both tables should have the same content if !reflect.DeepEqual(table1, table2) { t.Fatalf("Tables should have the same content: %v vs %v", table1, table2) } // Clean up state.Pop(1) }