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:
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")
+ }
+}