vise/go/vm/vm_test.go

301 lines
6.4 KiB
Go
Raw Normal View History

2023-03-31 11:52:04 +02:00
package vm
import (
"bytes"
2023-03-31 11:52:04 +02:00
"context"
"fmt"
"log"
2023-03-31 11:52:04 +02:00
"testing"
2023-03-31 11:59:55 +02:00
"text/template"
2023-03-31 11:52:04 +02:00
2023-03-31 11:59:55 +02:00
"git.defalsify.org/festive/resource"
// "git.defalsify.org/festive/router"
2023-03-31 11:52:04 +02:00
"git.defalsify.org/festive/state"
)
var dynVal = "three"
2023-03-31 11:52:04 +02:00
type TestResource struct {
2023-03-31 19:17:43 +02:00
state *state.State
2023-03-31 11:52:04 +02:00
}
func getOne(ctx context.Context) (string, error) {
2023-03-31 11:59:55 +02:00
return "one", nil
}
func getTwo(ctx context.Context) (string, error) {
2023-03-31 11:59:55 +02:00
return "two", nil
}
func getDyn(ctx context.Context) (string, error) {
return dynVal, nil
}
2023-03-31 19:17:43 +02:00
type TestStatefulResolver struct {
state *state.State
}
2023-04-01 11:58:02 +02:00
func (r *TestResource) GetTemplate(sym string) (string, error) {
2023-03-31 11:52:04 +02:00
switch sym {
case "foo":
return "inky pinky blinky clyde", nil
case "bar":
2023-03-31 11:59:55 +02:00
return "inky pinky {{.one}} blinky {{.two}} clyde", nil
case "baz":
return "inky pinky {{.baz}} blinky clyde", nil
case "three":
return "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}", nil
2023-04-01 22:25:20 +02:00
case "_catch":
return "aiee", nil
2023-03-31 11:52:04 +02:00
}
2023-04-01 10:03:03 +02:00
panic(fmt.Sprintf("unknown symbol %s", sym))
2023-03-31 11:52:04 +02:00
return "", fmt.Errorf("unknown symbol %s", sym)
}
2023-04-01 11:58:02 +02:00
func (r *TestResource) RenderTemplate(sym string, values map[string]string) (string, error) {
v, err := r.GetTemplate(sym)
2023-03-31 11:59:55 +02:00
if err != nil {
return "", err
}
2023-03-31 14:24:14 +02:00
tp, err := template.New("tester").Option("missingkey=error").Parse(v)
2023-03-31 11:59:55 +02:00
if err != nil {
return "", err
}
b := bytes.NewBuffer([]byte{})
2023-03-31 14:24:14 +02:00
err = tp.Execute(b, values)
2023-03-31 11:59:55 +02:00
if err != nil {
return "", err
}
return b.String(), err
}
func (r *TestResource) FuncFor(sym string) (resource.EntryFunc, error) {
switch sym {
case "one":
return getOne, nil
case "two":
return getTwo, nil
case "dyn":
return getDyn, nil
2023-03-31 19:17:43 +02:00
case "arg":
return r.getInput, nil
2023-03-31 11:59:55 +02:00
}
return nil, fmt.Errorf("invalid function: '%s'", sym)
2023-03-31 11:52:04 +02:00
}
func(r *TestResource) getInput(ctx context.Context) (string, error) {
v, err := r.state.GetInput()
return string(v), err
}
func(r *TestResource) GetCode(sym string) ([]byte, error) {
2023-04-01 11:58:02 +02:00
return []byte{}, nil
}
2023-03-31 11:52:04 +02:00
func TestRun(t *testing.T) {
2023-03-31 14:06:59 +02:00
st := state.NewState(5)
2023-03-31 11:52:04 +02:00
rs := TestResource{}
2023-04-01 10:03:03 +02:00
b := []byte{0x00, MOVE, 0x03}
2023-03-31 16:03:54 +02:00
b = append(b, []byte("foo")...)
2023-04-01 15:47:03 +02:00
_, err := Run(b, &st, &rs, context.TODO())
2023-03-31 11:52:04 +02:00
if err != nil {
t.Errorf("error on valid opcode: %v", err)
}
b = []byte{0x01, 0x02}
2023-04-01 15:47:03 +02:00
_, err = Run(b, &st, &rs, context.TODO())
2023-03-31 11:52:04 +02:00
if err == nil {
t.Errorf("no error on invalid opcode")
}
}
2023-03-31 11:59:55 +02:00
2023-03-31 19:17:43 +02:00
func TestRunLoadRender(t *testing.T) {
2023-03-31 14:06:59 +02:00
st := state.NewState(5)
2023-03-31 16:03:54 +02:00
st.Down("barbarbar")
2023-03-31 11:59:55 +02:00
rs := TestResource{}
sym := "one"
ins := append([]byte{uint8(len(sym))}, []byte(sym)...)
2023-03-31 16:03:54 +02:00
ins = append(ins, 0x0a)
2023-03-31 11:59:55 +02:00
var err error
2023-04-01 15:47:03 +02:00
_, err = RunLoad(ins, &st, &rs, context.TODO())
2023-03-31 11:59:55 +02:00
if err != nil {
t.Error(err)
}
m, err := st.Get()
if err != nil {
t.Error(err)
}
2023-04-01 11:58:02 +02:00
r, err := rs.RenderTemplate("foo", m)
2023-03-31 11:59:55 +02:00
if err != nil {
t.Error(err)
}
expect := "inky pinky blinky clyde"
if r != expect {
t.Errorf("Expected %v, got %v", []byte(expect), []byte(r))
}
2023-04-01 11:58:02 +02:00
r, err = rs.RenderTemplate("bar", m)
2023-03-31 11:59:55 +02:00
if err == nil {
t.Errorf("expected error for render of bar: %v" ,err)
}
sym = "two"
ins = append([]byte{uint8(len(sym))}, []byte(sym)...)
2023-03-31 16:03:54 +02:00
ins = append(ins, 0)
2023-04-01 15:47:03 +02:00
_, err = RunLoad(ins, &st, &rs, context.TODO())
2023-03-31 11:59:55 +02:00
if err != nil {
t.Error(err)
}
m, err = st.Get()
if err != nil {
t.Error(err)
}
2023-04-01 11:58:02 +02:00
r, err = rs.RenderTemplate("bar", m)
2023-03-31 11:59:55 +02:00
if err != nil {
t.Error(err)
}
expect = "inky pinky one blinky two clyde"
if r != expect {
t.Errorf("Expected %v, got %v", expect, r)
}
}
2023-03-31 16:24:29 +02:00
func TestRunMultiple(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
b := []byte{}
2023-03-31 20:24:30 +02:00
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
b = NewLine(b, LOAD, []string{"two"}, nil, []uint8{42})
2023-04-01 15:47:03 +02:00
_, err := Run(b, &st, &rs, context.TODO())
2023-03-31 16:24:29 +02:00
if err != nil {
t.Error(err)
}
}
func TestRunReload(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
b := []byte{}
2023-03-31 20:24:30 +02:00
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
2023-04-01 15:47:03 +02:00
_, err := Run(b, &st, &rs, context.TODO())
if err != nil {
t.Error(err)
}
r, err := st.Val("dyn")
if err != nil {
t.Error(err)
}
if r != "three" {
t.Errorf("expected result 'three', got %v", r)
}
dynVal = "baz"
b = []byte{}
2023-03-31 20:24:30 +02:00
b = NewLine(b, RELOAD, []string{"dyn"}, nil, nil)
2023-04-01 15:47:03 +02:00
_, err = Run(b, &st, &rs, context.TODO())
if err != nil {
t.Error(err)
}
r, err = st.Val("dyn")
if err != nil {
t.Error(err)
}
log.Printf("dun now %s", r)
if r != "baz" {
t.Errorf("expected result 'baz', got %v", r)
}
}
func TestHalt(t *testing.T) {
2023-03-31 20:24:30 +02:00
st := state.NewState(5)
2023-04-01 15:47:03 +02:00
rs := TestResource{}
b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
b = NewLine(b, HALT, nil, nil, nil)
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
2023-03-31 20:24:30 +02:00
var err error
b, err = Run(b, &st, &rs, context.TODO())
2023-03-31 20:24:30 +02:00
if err != nil {
t.Error(err)
}
2023-03-31 20:24:30 +02:00
r := st.Where()
if r == "foo" {
t.Fatalf("Expected where-symbol not to be 'foo'")
}
if !bytes.Equal(b[:2], []byte{0x00, MOVE}) {
t.Fatalf("Expected MOVE instruction, found '%v'", b)
}
}
2023-03-31 20:24:30 +02:00
func TestRunArg(t *testing.T) {
2023-03-31 20:24:30 +02:00
st := state.NewState(5)
rs := TestResource{}
2023-04-02 00:56:02 +02:00
input := []byte("bar")
_ = st.SetInput(input)
2023-04-02 00:56:02 +02:00
bi := NewLine([]byte{}, INCMP, []string{"bar", "baz"}, nil, nil)
b, err := Run(bi, &st, &rs, context.TODO())
2023-03-31 20:24:30 +02:00
if err != nil {
t.Error(err)
}
l := len(b)
if l != 0 {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
r := st.Where()
if r != "baz" {
t.Errorf("expected where-state baz, got %v", r)
2023-03-31 20:24:30 +02:00
}
}
func TestRunInputHandler(t *testing.T) {
2023-04-01 22:25:20 +02:00
st := state.NewState(5)
rs := TestResource{}
2023-04-02 00:56:02 +02:00
_ = st.SetInput([]byte("baz"))
2023-04-01 22:25:20 +02:00
2023-04-02 00:56:02 +02:00
bi := NewLine([]byte{}, INCMP, []string{"bar", "aiee"}, nil, nil)
bi = NewLine(bi, INCMP, []string{"baz", "foo"}, nil, nil)
bi = NewLine(bi, LOAD, []string{"one"}, nil, []uint8{0})
2023-04-01 22:25:20 +02:00
bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
2023-04-01 22:25:20 +02:00
var err error
_, err = Run(bi, &st, &rs, context.TODO())
if err != nil {
t.Fatal(err)
}
r := st.Where()
if r != "foo" {
t.Fatalf("expected where-sym 'foo', got '%v'", r)
2023-04-01 22:25:20 +02:00
}
}
func TestRunArgInvalid(t *testing.T) {
2023-04-01 22:25:20 +02:00
st := state.NewState(5)
rs := TestResource{}
_ = st.SetInput([]byte("foo"))
2023-04-01 22:25:20 +02:00
var err error
2023-04-02 00:56:02 +02:00
b := NewLine([]byte{}, INCMP, []string{"bar", "baz"}, nil, nil)
b = NewLine(b, CATCH, []string{"_catch"}, []byte{state.FLAG_INMATCH}, []uint8{1})
2023-04-01 22:25:20 +02:00
b, err = Run(b, &st, &rs, context.TODO())
2023-04-01 22:25:20 +02:00
if err != nil {
t.Error(err)
2023-04-01 22:25:20 +02:00
}
l := len(b)
2023-04-01 22:25:20 +02:00
if l != 0 {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
r := st.Where()
if r != "_catch" {
t.Errorf("expected where-state _catch, got %v", r)
2023-04-01 22:25:20 +02:00
}
}