go-vise

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

commit af7906e867c1ee244da960911213054299b24d07
parent 194522fd95bd8323209c8ebc056567b87f59fe5e
Author: lash <dev@holbrook.no>
Date:   Mon, 17 Apr 2023 16:30:54 +0100

Add tests for state debug outputs

Diffstat:
Astate/debug.go | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Astate/debug_test.go | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstate/flag.go | 8+++++++-
Mstate/state.go | 28++++++++++++++++++++--------
4 files changed, 135 insertions(+), 9 deletions(-)

diff --git a/state/debug.go b/state/debug.go @@ -0,0 +1,51 @@ +package state + +import ( + "fmt" + "strings" +) + +type flagDebugger struct { + flagStrings map[uint32]string +} + +func newFlagDebugger() flagDebugger { + fd := flagDebugger{ + flagStrings: make(map[uint32]string), + } + fd.register(FLAG_READIN, "INTERNAL_READIN") + fd.register(FLAG_INMATCH, "INTERNAL_INMATCH") + fd.register(FLAG_TERMINATE, "INTERNAL_TERMINATE") + fd.register(FLAG_DIRTY, "INTERNAL_DIRTY") + fd.register(FLAG_WAIT, "INTERNAL_WAIT") + fd.register(FLAG_LOADFAIL, "INTERNAL_LOADFAIL") + return fd +} + +func(fd *flagDebugger) register(flag uint32, name string) { + fd.flagStrings[flag] = name +} + +func(fd *flagDebugger) Register(flag uint32, name string) error { + if (flag < 8) { + return fmt.Errorf("flag %v is not definable by user", flag) + } + fd.register(flag, name) + return nil +} + +func(fd *flagDebugger) AsString(flags []byte, length uint32) string { + var r []string + var i uint32 + for i = 0; i < length + 8; i++ { + if getFlag(i, flags) { + s := fmt.Sprintf("%s(%v)", fd.flagStrings[i], i) + r = append(r, s) + } + } + return strings.Join(r, ",") +} + +var ( + FlagDebugger = newFlagDebugger() +) diff --git a/state/debug_test.go b/state/debug_test.go @@ -0,0 +1,57 @@ +package state + +import ( + "fmt" + "testing" +) + +func TestDebugFlagDenied(t *testing.T) { + err := FlagDebugger.Register(7, "foo") + if err == nil { + t.Fatalf("expected error") + } +} + +func TestDebugFlagString(t *testing.T) { + err := FlagDebugger.Register(8, "FOO") + if err != nil { + t.Fatal(err) + } + err = FlagDebugger.Register(9, "BAR") + if err != nil { + t.Fatal(err) + } + err = FlagDebugger.Register(11, "BAZ") + if err != nil { + t.Fatal(err) + } + flags := []byte{0x06, 0x09} + r := FlagDebugger.AsString(flags, 4) + expect := "INTERNAL_INMATCH(1),INTERNAL_TERMINATE(2),FOO(8),BAZ(11)" + if r != expect { + t.Fatalf("expected '%s', got '%s'", expect, r) + } +} + +func TestDebugState(t *testing.T) { + err := FlagDebugger.Register(8, "FOO") + if err != nil { + t.Fatal(err) + } + st := NewState(1).WithDebug() + _, err = st.SetFlag(FLAG_DIRTY) + if err != nil { + t.Fatal(err) + } + _, err = st.SetFlag(8) + if err != nil { + t.Fatal(err) + } + st.Down("root") + + r := fmt.Sprintf("%s", st) + expect := "moves: 1 idx: 0 flags: INTERNAL_DIRTY(3),FOO(8) path: root" + if r != expect { + t.Fatalf("expected '%s', got '%s'", expect, r) + } +} diff --git a/state/flag.go b/state/flag.go @@ -20,5 +20,11 @@ func IsWriteableFlag(flag uint32) bool { return false } -type FlagDebugger struct { +// Retrieve the state of a state flag +func getFlag(bitIndex uint32, bitField []byte) bool { + byteIndex := bitIndex / 8 + localBitIndex := bitIndex % 8 + b := bitField[byteIndex] + return (b & (1 << localBitIndex)) > 0 } + diff --git a/state/state.go b/state/state.go @@ -36,6 +36,7 @@ type State struct { Flags []byte // Error state Moves uint32 // Number of times navigation has been performed input []byte // Last input + debug bool // Make string representation more human friendly } // number of bytes necessary to represent a bitfield of the given size. @@ -50,13 +51,13 @@ func toByteSize(BitSize uint32) uint8 { return uint8(BitSize / 8) } -// Retrieve the state of a state flag -func getFlag(bitIndex uint32, bitField []byte) bool { - byteIndex := bitIndex / 8 - localBitIndex := bitIndex % 8 - b := bitField[byteIndex] - return (b & (1 << localBitIndex)) > 0 -} +//// Retrieve the state of a state flag +//func getFlag(bitIndex uint32, bitField []byte) bool { +// byteIndex := bitIndex / 8 +// localBitIndex := bitIndex % 8 +// b := bitField[byteIndex] +// return (b & (1 << localBitIndex)) > 0 +//} // NewState creates a new State object with BitSize number of error condition states in ADDITION to the 8 builtin flags. func NewState(BitSize uint32) State { @@ -72,6 +73,11 @@ func NewState(BitSize uint32) State { return st } +func(st State) WithDebug() State { + st.debug = true + return st +} + // SetFlag sets the flag at the given bit field index // // Returns true if bit state was changed. @@ -342,7 +348,13 @@ func(st *State) Restart() error { // String implements String interface func(st State) String() string { - return fmt.Sprintf("moves %v idx %v flags: 0x%x path: %s", st.Moves, st.SizeIdx, st.Flags, strings.Join(st.ExecPath, "/")) + var flags string + if st.debug { + flags = FlagDebugger.AsString(st.Flags, st.BitSize - 8) + } else { + flags = fmt.Sprintf("0x%x", st.Flags) + } + return fmt.Sprintf("moves: %v idx: %v flags: %s path: %s", st.Moves, st.SizeIdx, flags, strings.Join(st.ExecPath, "/")) } // initializes all flags not in control of client.