LuaJIT-to-Go/tests/table_test.go

247 lines
6.0 KiB
Go
Raw Normal View History

2025-02-26 07:00:01 -06:00
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)
}