go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 7429f891d61d7224eb2d3cfa857a0bbb4c59ec5b
parent cab74c82992d31cad0c3fffd4b0087754e944101
Author: lash <dev@holbrook.no>
Date:   Wed, 11 Sep 2024 15:52:50 +0100

Reach >80% coverage on state/state.go

Diffstat:
MCHANGELOG | 3+++
MMakefile | 3++-
Mengine/engine_test.go | 4++--
Mstate/state.go | 15++++++++-------
Mstate/state_test.go | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 278 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -13,6 +13,9 @@ * State constructor returns pointer. * Prevent endless state move recursion. * Ensure SessionId and Language is available in context in all engine execution branches. + * Reduce cache usage size correctly on reset. + * Add flush state and cache option for persister on save. + * Remove dead code from asm package. - 0.0.15 * Add comprehensive documentation with texinfo. * Prevent cursor leak in sizer. diff --git a/Makefile b/Makefile @@ -31,5 +31,6 @@ doc: make -C doc cov: - go test -cover ./... -coverprofile=cover.out + #go test -cover ./... -coverprofile=cover.out + go test -cover ./state/... -coverprofile=cover.out go tool cover -html=cover.out diff --git a/engine/engine_test.go b/engine/engine_test.go @@ -228,8 +228,8 @@ func TestEngineResumeTerminated(t *testing.T) { } location, idx := st.Where() - if location != "" { - t.Fatalf("expected '', got %s", location) + if location != "root" { + t.Fatalf("expected 'root', got %s", location) } if idx != 0 { t.Fatalf("expected idx '0', got %v", idx) diff --git a/state/state.go b/state/state.go @@ -9,9 +9,6 @@ import ( var ( IndexError = fmt.Errorf("already at first index") -) - -const ( MaxLevel = 128 ) @@ -314,8 +311,8 @@ func(st *State) Up() (string, error) { } // Depth returns the current call stack depth. -func(st *State) Depth() uint8 { - return uint8(len(st.ExecPath)-1) +func(st *State) Depth() int { + return len(st.ExecPath)-1 } // Appendcode adds the given bytecode to the end of the existing code. @@ -358,11 +355,16 @@ func(st *State) SetInput(input []byte) error { // Reset re-initializes the state to run from top node with accumulated client state. func(st *State) Restart() error { + var err error + if len(st.ExecPath) == 0 { + return fmt.Errorf("Restart called but no root set") + } st.resetBaseFlags() st.Moves = 0 st.SizeIdx = 0 st.input = []byte{} - return nil + st.ExecPath = st.ExecPath[:1] + return err } // SetLanguage validates and sets language according to the given ISO639 language code. @@ -405,4 +407,3 @@ func(st State) String() string { func(st *State) resetBaseFlags() { st.Flags[0] = 0 } - diff --git a/state/state_test.go b/state/state_test.go @@ -19,6 +19,19 @@ func TestNewState(t *testing.T) { if len(st.Flags) != 4 { t.Fatalf("invalid state flag length: %v", len(st.Flags)) } + v := st.FlagBitSize() + x := uint32(17+8) + if v != x { + t.Fatalf("expected %d, get %d", x, v) + } + v = uint32(st.FlagByteSize()) + x = 4 + if v != x { + t.Fatalf("expected %d, get %d", x, v) + } + if !IsWriteableFlag(8) { + t.Fatal("expected true") + } } func TestStateflags(t *testing.T) { @@ -64,6 +77,42 @@ func TestStateflags(t *testing.T) { if !bytes.Equal(st.Flags[:3], []byte{0x04, 0x04, 0x01}) { t.Fatalf("Expected 0x040401, got %v", st.Flags[:3]) } + defer func() { + if r := recover(); r == nil { + t.Fatal("did not panic") + } + }() + v = st.SetFlag(42) +} + +func TestStateFlagReset(t *testing.T) { + st := NewState(9) + v := st.SetFlag(10) + v = st.SetFlag(11) + v = st.ResetFlag(10) + if !v { + t.Fatal("expected true") + } + v = st.ResetFlag(10) + if v { + t.Fatal("expected false") + } + defer func() { + if r := recover(); r == nil { + t.Fatal("did not panic") + } + }() + v = st.ResetFlag(42) +} + +func TestStateFlagGetOutOfRange(t *testing.T) { + st := NewState(1) + defer func() { + if r := recover(); r == nil { + t.Fatal("did not panic") + } + }() + st.GetFlag(9) } func TestStateFlagFromSlice(t *testing.T) { @@ -202,3 +251,217 @@ func TestStateFlagMatch(t *testing.T) { t.Fatalf("unexpected flag") } } + +func TestStateMovementNoRoot(t *testing.T) { + var err error + st := NewState(0) + _, err = st.Next() + if err == nil { + t.Fatal("expected error") + } + _, err = st.Previous() + if err == nil { + t.Fatal("expected error") + } + vl, vr := st.Sides() + if vl { + t.Fatal("expected false") + } + if vr { + t.Fatal("expected false") + } + _, err = st.Top() + if err == nil { + t.Fatal("expected error") + } + _, err = st.Up() + if err == nil { + t.Fatal("expected error") + } + v := st.Depth() + if v != -1 { + t.Fatalf("expected -1, got %d", v) + } +} + +func TestStateInput(t *testing.T) { + var err error + var wrongInput [257]byte + st := NewState(0) + _, err = st.GetInput() + if err == nil { + t.Fatal("expected error") + } + err = st.SetInput(wrongInput[:]) + if err == nil { + t.Fatal("expected error") + } + b := []byte("foo") + err = st.SetInput(b) + if err != nil { + t.Fatal(err) + } + v, err := st.GetInput() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(v, b) { + t.Fatalf("expected %x, got %x", b, v) + } +} + +func TestStateMovement(t *testing.T) { + var x uint16 + st := NewState(0) + err := st.Down("foo") + if err != nil { + t.Fatal(err) + } + r, err := st.Top() + if err != nil { + t.Fatal(err) + } + if !r { + t.Fatal("expected true") + } + err = st.Down("bar") + if err != nil { + t.Fatal(err) + } + err = st.Down("baz") + if err != nil { + t.Fatal(err) + } + v := st.Depth() + if v != 2 { + t.Fatalf("expected 1, got %d", v) + } + s, err := st.Up() + if err != nil { + t.Fatal(err) + } + if s != "bar" { + t.Fatalf("expected 'bar', got '%s'", s) + } + v = st.Depth() + if v != 1 { + t.Fatalf("expected 1, got %d", v) + } + vr, vl := st.Sides() + if !vr { + t.Fatal("expected true") + } + if vl { + t.Fatal("expected false") + } + _, err = st.Previous() + if err == nil { + t.Fatal("expected error") + } + x, err = st.Next() + if err != nil { + t.Fatal(err) + } + if x != 1 { + t.Fatalf("expected 1, got %d", x) + } + vr, vl = st.Sides() + if !vr { + t.Fatal("expected true") + } + if !vl { + t.Fatal("expected true") + } + x, err = st.Next() + if err != nil { + t.Fatal(err) + } + if x != 2 { + t.Fatalf("expected 2, got %d", x) + } + _, err = st.Next() + if err != nil { + t.Fatal(err) + } + s, x = st.Where() + if s != "bar" { + t.Fatalf("expected 'baz', got '%s'", s) + } + if x != 3 { + t.Fatalf("expected 3, got '%d'", x) + } + x, err = st.Previous() + if x != 2 { + t.Fatalf("expected 2, got '%d'", x) + } + vl, vr = st.Sides() + if !vr { + t.Fatal("expected true") + } + if !vl { + t.Fatal("expected true") + } +} + +func TestStateMaxMovement(t *testing.T) { + MaxLevel = 3 + st := NewState(0) + st.Down("inky") + st.Down("pinky") + st.Down("blinky") + st.Down("clyde") + defer func() { + if r := recover(); r == nil { + t.Fatal("did not panic") + } + }() + st.Down("sue") +} + +func TestStateReset(t *testing.T) { + st := NewState(3) + st.SetFlag(2) + st.SetFlag(9) + st.Down("foo") + st.Down("bar") + st.Down("baz") + st.Next() + st.Next() + st.SetInput([]byte("xyzzy")) + err := st.Restart() + if err != nil { + t.Fatal(err) + } + r, err := st.Top() + if err != nil { + t.Fatal(err) + } + if !r { + t.Fatal("expected true") + } + if st.GetFlag(2) { + t.Fatal("expected not set") + } + s, v := st.Where() + if s != "foo" { + t.Fatalf("expected 'foo', got '%s'", s) + } + if v > 0 { + t.Fatalf("expected 0, got %d", v) + } + +} + +func TestStateLanguage(t *testing.T) { + st := NewState(0) + if st.Language != nil { + t.Fatal("expected language not set") + } + err := st.SetLanguage("nor") + if err != nil { + t.Fatal(err) + } + if st.Language == nil { + t.Fatal("expected language set") + } +}