diff options
Diffstat (limited to 'pkg/lang/vm/mem/mem_test.go')
| -rw-r--r-- | pkg/lang/vm/mem/mem_test.go | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/pkg/lang/vm/mem/mem_test.go b/pkg/lang/vm/mem/mem_test.go new file mode 100644 index 0000000..a75753c --- /dev/null +++ b/pkg/lang/vm/mem/mem_test.go @@ -0,0 +1,238 @@ +package mem_test + +import ( + "jinx/pkg/lang/vm/mem" + "jinx/pkg/lang/vm/value" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAllocation(t *testing.T) { + m := mem.New() + + one, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + + two, err := m.Allocate(mem.CellKindArray) + assert.NoError(t, err) + + assert.Equal(t, one, mem.Ptr(1)) + assert.Equal(t, two, mem.Ptr(2)) +} + +func TestGetSet(t *testing.T) { + m := mem.New() + + one, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(one, value.StringCell("one"))) + + two, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(two, value.StringCell("two"))) + + oneCell, err := m.Get(one) + assert.NoError(t, err) + assert.Equal(t, oneCell.(value.StringCell).Get(), "one") + + twoCell, err := m.Get(two) + assert.NoError(t, err) + assert.Equal(t, twoCell.(value.StringCell).Get(), "two") + + assert.NoError(t, m.Set(one, value.StringCell("one, but changed"))) + + oneCell, err = m.Get(one) + assert.NoError(t, err) + assert.Equal(t, oneCell.(value.StringCell).Get(), "one, but changed") +} + +func TestNullIsForbidden(t *testing.T) { + m := mem.New() + + _, err := m.Get(mem.NullPtr) + assert.Error(t, err) + + assert.Error(t, m.Set(mem.NullPtr, value.StringCell("one"))) + + assert.Error(t, m.Retain(mem.NullPtr)) + assert.Error(t, m.Release(mem.NullPtr)) + assert.Equal(t, 0, m.RefCount(mem.NullPtr)) +} + +func TestCantGetNorSetUnallocatedCell(t *testing.T) { + m := mem.New() + + _, err := m.Get(mem.Ptr(123)) + assert.Error(t, err) + + err = m.Set(mem.Ptr(123), value.StringCell("one")) + assert.Error(t, err) +} + +func TestCantAllocateMarkerCells(t *testing.T) { + m := mem.New() + + _, err := m.Allocate(mem.CellKindEmpty) + assert.Error(t, err) + + _, err = m.Allocate(mem.CellKindForbidden) + assert.Error(t, err) +} + +func TestCantAssignWrongCellKind(t *testing.T) { + m := mem.New() + + one, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.Error(t, m.Set(one, value.EnvCell(value.NewEnv()))) +} + +func TestIsAndKind(t *testing.T) { + m := mem.New() + + one, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + + assert.True(t, m.Is(one, mem.CellKindString)) + assert.False(t, m.Is(one, mem.CellKindArray)) + + assert.Equal(t, mem.CellKindString, m.Kind(one)) +} + +func TestIsAndKindAlwaysAgree(t *testing.T) { + m := mem.New() + + _, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + _, err = m.Allocate(mem.CellKindArray) + assert.NoError(t, err) + _, err = m.Allocate(mem.CellKindOutlet) + assert.NoError(t, err) + _, err = m.Allocate(mem.CellKindEnv) + assert.NoError(t, err) + + for i := 0; i < 100; i++ { + ptr := mem.Ptr(i) + assert.True(t, m.Is(ptr, m.Kind(ptr))) + } +} + +func TestRetainRelease(t *testing.T) { + m := mem.New() + + ptr, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(ptr, value.StringCell("an allocated string"))) + + assert.True(t, m.Is(ptr, mem.CellKindString)) + assert.Equal(t, 1, m.RefCount(ptr)) + + assert.NoError(t, m.Retain(ptr)) + assert.NoError(t, m.Retain(ptr)) + assert.NoError(t, m.Retain(ptr)) + + assert.True(t, m.Is(ptr, mem.CellKindString)) + assert.Equal(t, 4, m.RefCount(ptr)) + + assert.NoError(t, m.Release(ptr)) + assert.NoError(t, m.Release(ptr)) + assert.NoError(t, m.Release(ptr)) + + assert.True(t, m.Is(ptr, mem.CellKindString)) + cell, err := m.Get(ptr) + assert.NoError(t, err) + assert.Equal(t, "an allocated string", cell.(value.StringCell).Get()) + assert.Equal(t, 1, m.RefCount(ptr)) + + assert.NoError(t, m.Release(ptr)) + + assert.Equal(t, 0, m.RefCount(ptr)) + assert.True(t, m.Is(ptr, mem.CellKindEmpty)) + _, err = m.Get(ptr) + assert.Error(t, err) +} + +func TestCantReleaseTooMuch(t *testing.T) { + m := mem.New() + + ptr, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(ptr, value.StringCell("an allocated string"))) + + assert.NoError(t, m.Retain(ptr)) + assert.Equal(t, 2, m.RefCount(ptr)) + + assert.NoError(t, m.Release(ptr)) + assert.NoError(t, m.Release(ptr)) + assert.Error(t, m.Release(ptr)) +} + +func TestCantRetainNorReleaseUnallocated(t *testing.T) { + m := mem.New() + + assert.Error(t, m.Retain(mem.Ptr(123))) + assert.Error(t, m.Release(mem.Ptr(123))) +} + +func TestChainDrop(t *testing.T) { + m := mem.New() + + arr := []value.Value{ + unwrap(t, func() (value.Value, error) { return value.NewString(m, "one") }), + unwrap(t, func() (value.Value, error) { return value.NewString(m, "two") }), + + unwrap(t, func() (value.Value, error) { + return value.NewArray(m, []value.Value{ + unwrap(t, func() (value.Value, error) { return value.NewString(m, "three") }), + }) + }), + } + + val, err := value.NewArray(m, arr) + assert.NoError(t, err) + + assert.Equal(t, mem.CellKindString, m.Kind(mem.Ptr(1))) + assert.Equal(t, mem.CellKindString, m.Kind(mem.Ptr(2))) + assert.Equal(t, mem.CellKindString, m.Kind(mem.Ptr(3))) + assert.Equal(t, mem.CellKindArray, m.Kind(mem.Ptr(4))) + assert.Equal(t, mem.CellKindArray, m.Kind(mem.Ptr(5))) + assert.Equal(t, mem.CellKindEmpty, m.Kind(mem.Ptr(6))) + + val.Drop(m) + + for _, ptr := range []mem.Ptr{1, 2, 3, 4, 5, 6} { + assert.Equal(t, mem.CellKindEmpty, m.Kind(ptr)) + } +} + +func TestFreeCellsGetReused(t *testing.T) { + m := mem.New() + + one, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(one, value.StringCell("old one"))) + + two, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(two, value.StringCell("old two"))) + + assert.NoError(t, m.Release(one)) + + newOne, err := m.Allocate(mem.CellKindString) + assert.NoError(t, err) + assert.NoError(t, m.Set(newOne, value.StringCell("new one"))) + + assert.Equal(t, mem.CellKindString, m.Kind(newOne)) + newCell, err := m.Get(newOne) + assert.NoError(t, err) + assert.Equal(t, "new one", newCell.(value.StringCell).Get()) + assert.Equal(t, 1, m.RefCount(newOne)) + assert.Equal(t, one, newOne) +} + +func unwrap[X any](t *testing.T, f func() (X, error)) X { + x, err := f() + assert.NoError(t, err) + return x +} |
