2023-03-31 11:52:04 +02:00
|
|
|
package vm
|
|
|
|
|
|
|
|
import (
|
2023-03-31 17:12:14 +02:00
|
|
|
"bytes"
|
2023-03-31 11:52:04 +02:00
|
|
|
"context"
|
|
|
|
"fmt"
|
2023-03-31 17:12:14 +02:00
|
|
|
"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"
|
2023-03-31 20:24:30 +02:00
|
|
|
"git.defalsify.org/festive/router"
|
2023-03-31 11:52:04 +02:00
|
|
|
"git.defalsify.org/festive/state"
|
|
|
|
)
|
|
|
|
|
2023-03-31 17:12:14 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-03-31 23:35:13 +02:00
|
|
|
func getOne(ctx context.Context) (string, error) {
|
2023-03-31 11:59:55 +02:00
|
|
|
return "one", nil
|
|
|
|
}
|
|
|
|
|
2023-03-31 23:35:13 +02:00
|
|
|
func getTwo(ctx context.Context) (string, error) {
|
2023-03-31 11:59:55 +02:00
|
|
|
return "two", nil
|
|
|
|
}
|
|
|
|
|
2023-03-31 23:35:13 +02:00
|
|
|
func getDyn(ctx context.Context) (string, error) {
|
2023-03-31 17:12:14 +02:00
|
|
|
return dynVal, nil
|
|
|
|
}
|
|
|
|
|
2023-03-31 19:17:43 +02:00
|
|
|
type TestStatefulResolver struct {
|
|
|
|
state *state.State
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-31 23:35:13 +02:00
|
|
|
func (r *TestResource) getEachArg(ctx context.Context) (string, error) {
|
2023-03-31 19:17:43 +02:00
|
|
|
return r.state.PopArg()
|
|
|
|
}
|
|
|
|
|
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
|
2023-03-31 17:12:14 +02:00
|
|
|
case "baz":
|
|
|
|
return "inky pinky {{.baz}} blinky clyde", nil
|
|
|
|
case "three":
|
|
|
|
return "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}", 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
|
2023-03-31 17:12:14 +02:00
|
|
|
case "dyn":
|
|
|
|
return getDyn, nil
|
2023-03-31 19:17:43 +02:00
|
|
|
case "arg":
|
|
|
|
return r.getEachArg, 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
|
|
|
}
|
|
|
|
|
2023-04-01 11:58:02 +02:00
|
|
|
func (r *TestResource) GetCode(sym string) ([]byte, error) {
|
|
|
|
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{}
|
2023-03-31 17:12:14 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2023-03-31 17:12:14 +02:00
|
|
|
|
|
|
|
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())
|
2023-03-31 17:12:14 +02:00
|
|
|
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())
|
2023-03-31 17:12:14 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-03-31 20:24:30 +02:00
|
|
|
func TestRunArg(t *testing.T) {
|
|
|
|
st := state.NewState(5)
|
2023-04-01 15:47:03 +02:00
|
|
|
rs := TestResource{}
|
2023-03-31 20:24:30 +02:00
|
|
|
rt := router.NewRouter()
|
|
|
|
rt.Add("foo", "bar")
|
|
|
|
rt.Add("baz", "xyzzy")
|
|
|
|
b := []byte{0x03}
|
|
|
|
b = append(b, []byte("baz")...)
|
2023-04-01 15:47:03 +02:00
|
|
|
//b = append(b, rt.ToBytes()...)
|
2023-03-31 20:24:30 +02:00
|
|
|
var err error
|
2023-04-01 15:47:03 +02:00
|
|
|
b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
2023-03-31 20:24:30 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
2023-03-31 17:12:14 +02:00
|
|
|
}
|
2023-03-31 20:24:30 +02:00
|
|
|
l := len(b)
|
|
|
|
if l != 0 {
|
|
|
|
t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
2023-03-31 17:12:14 +02:00
|
|
|
}
|
2023-03-31 20:24:30 +02:00
|
|
|
r := st.Where()
|
|
|
|
if r != "xyzzy" {
|
|
|
|
t.Errorf("expected where-state baz, got %v", r)
|
2023-03-31 17:12:14 +02:00
|
|
|
}
|
|
|
|
}
|
2023-03-31 20:24:30 +02:00
|
|
|
|
|
|
|
func TestRunArgInvalid(t *testing.T) {
|
|
|
|
st := state.NewState(5)
|
|
|
|
rt := router.NewRouter()
|
|
|
|
rt.Add("foo", "bar")
|
|
|
|
rt.Add("baz", "xyzzy")
|
|
|
|
b := []byte{0x03}
|
|
|
|
b = append(b, []byte("bar")...)
|
2023-04-01 15:47:03 +02:00
|
|
|
//b = append(b, rt.ToBytes()...)
|
2023-03-31 20:24:30 +02:00
|
|
|
var err error
|
2023-04-01 15:47:03 +02:00
|
|
|
b, err = Apply(b, rt.ToBytes(), &st, nil, 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 != "_catch" {
|
|
|
|
t.Errorf("expected where-state _catch, got %v", r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-01 15:47:03 +02:00
|
|
|
//func TestRunArgInstructions(t *testing.T) {
|
|
|
|
// st := state.NewState(5)
|
|
|
|
// rs := TestResource{}
|
|
|
|
//
|
|
|
|
// rt := router.NewRouter()
|
|
|
|
// rt.Add("foo", "bar")
|
|
|
|
// b := []byte{0x03}
|
|
|
|
// b = append(b, []byte("foo")...)
|
|
|
|
// b = append(b, rt.ToBytes()...)
|
|
|
|
//
|
|
|
|
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
|
|
|
// 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)
|
|
|
|
// var err error
|
|
|
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
|
|
|
// if err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
// l := len(b)
|
|
|
|
// if l != 0 {
|
|
|
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
|
|
// }
|
|
|
|
// loc := st.Where()
|
|
|
|
// if loc != "bar" {
|
|
|
|
// t.Errorf("expected where-state bar, got %v", loc)
|
|
|
|
// }
|
|
|
|
// m, err := st.Get()
|
|
|
|
// if err != nil {
|
|
|
|
// t.Fatal(err)
|
|
|
|
// }
|
|
|
|
// _, err = rs.RenderTemplate(loc, m)
|
|
|
|
// if err == nil {
|
|
|
|
// t.Fatalf("expected error to generate template")
|
|
|
|
// }
|
|
|
|
// _, err = Run(bi, &st, &rs, context.TODO())
|
|
|
|
// if err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
// m, err = st.Get()
|
|
|
|
// if err != nil {
|
|
|
|
// t.Fatal(err)
|
|
|
|
// }
|
|
|
|
// _, err = rs.RenderTemplate(loc, m)
|
|
|
|
// if err != nil {
|
|
|
|
// t.Fatal(err)
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//func TestRunMoveAndBack(t *testing.T) {
|
|
|
|
// st := state.NewState(5)
|
|
|
|
// rs := TestResource{}
|
|
|
|
// rt := router.NewRouter()
|
|
|
|
// rt.Add("foo", "bar")
|
|
|
|
// b := []byte{0x03}
|
|
|
|
// b = append(b, []byte("foo")...)
|
|
|
|
// //b = append(b, rt.ToBytes()...)
|
|
|
|
// bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
|
|
|
//
|
|
|
|
// var err error
|
|
|
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
|
|
|
// if err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
// l := len(b)
|
|
|
|
// if l != 0 {
|
|
|
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// rt = router.NewRouter()
|
|
|
|
// rt.Add("foo", "baz")
|
|
|
|
// b = []byte{0x03}
|
|
|
|
// b = append(b, []byte("foo")...)
|
|
|
|
// b = append(b, rt.ToBytes()...)
|
|
|
|
// bi = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
|
|
|
// b, err = Apply(b, bi, &st, &rs, context.TODO())
|
|
|
|
// if err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
// l = len(b)
|
|
|
|
// if l != 0 {
|
|
|
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// rt = router.NewRouter()
|
|
|
|
// rt.Add("foo", "_")
|
|
|
|
// b = []byte{0x03}
|
|
|
|
// b = append(b, []byte("foo")...)
|
|
|
|
// //b = append(b, rt.ToBytes()...)
|
|
|
|
// b, err = Apply(b, rt.ToBytes(), &st, &rs, context.TODO())
|
|
|
|
// if err != nil {
|
|
|
|
// t.Error(err)
|
|
|
|
// }
|
|
|
|
// l = len(b)
|
|
|
|
// if l != 0 {
|
|
|
|
// t.Errorf("expected empty remainder, got length %v: %v", l, b)
|
|
|
|
// }
|
|
|
|
// loc := st.Where()
|
|
|
|
// if loc != "bar" {
|
|
|
|
// t.Errorf("expected where-string 'bar', got %v", loc)
|
|
|
|
// }
|
|
|
|
//}
|
2023-04-01 10:03:03 +02:00
|
|
|
|
|
|
|
func TestCatchAndBack(t *testing.T) {
|
|
|
|
st := state.NewState(5)
|
|
|
|
rs := TestResource{}
|
|
|
|
rt := router.NewRouter()
|
|
|
|
rt.Add("foo", "bar")
|
|
|
|
b := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
|
|
|
|
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
|
|
|
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
2023-04-01 15:47:03 +02:00
|
|
|
_, err := Run(b, &st, &rs, context.TODO())
|
2023-04-01 10:03:03 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
r := st.Where()
|
|
|
|
if r != "foo" {
|
|
|
|
t.Errorf("expected where-symbol 'foo', got %v", r)
|
|
|
|
}
|
|
|
|
|
|
|
|
st.SetFlag(2)
|
|
|
|
b = NewLine([]byte{}, LOAD, []string{"two"}, nil, []uint8{0})
|
|
|
|
b = NewLine(b, CATCH, []string{"bar"}, []byte{0x04}, nil)
|
|
|
|
b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
|
2023-04-01 15:47:03 +02:00
|
|
|
_, err = Run(b, &st, &rs, context.TODO())
|
2023-04-01 10:03:03 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
r = st.Where()
|
|
|
|
if r != "bar" {
|
|
|
|
t.Errorf("expected where-symbol 'bar', got %v", r)
|
|
|
|
}
|
2023-04-01 10:06:08 +02:00
|
|
|
|
|
|
|
st.Up()
|
|
|
|
r = st.Where()
|
|
|
|
if r != "foo" {
|
|
|
|
t.Errorf("expected where-symbol 'foo', got %v", r)
|
|
|
|
}
|
|
|
|
err = st.Map("one")
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
2023-04-01 10:03:03 +02:00
|
|
|
}
|