go-vise

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

runner_test.go (19918B)


      1 package vm
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"fmt"
      7 	"log"
      8 	"strings"
      9 	"testing"
     10 
     11 	"git.defalsify.org/vise.git/cache"
     12 	"git.defalsify.org/vise.git/internal/resourcetest"
     13 	"git.defalsify.org/vise.git/render"
     14 	"git.defalsify.org/vise.git/resource"
     15 	"git.defalsify.org/vise.git/state"
     16 )
     17 
     18 var (
     19 	ctx    = context.Background()
     20 	dynVal = "three"
     21 )
     22 
     23 type testResource struct {
     24 	*resourcetest.TestResource
     25 	state        *state.State
     26 	RootCode     []byte
     27 	CatchContent string
     28 }
     29 
     30 func newTestResource(st *state.State) testResource {
     31 	rs := resourcetest.NewTestResource()
     32 	tr := testResource{
     33 		TestResource: rs,
     34 		state:        st,
     35 	}
     36 	rs.AddTemplate(ctx, "foo", "inky pinky blinky clyde")
     37 	rs.AddTemplate(ctx, "bar", "inky pinky {{.one}} blinky {{.two}} clyde")
     38 	rs.AddTemplate(ctx, "baz", "inky pinky {{.baz}} blinky clyde")
     39 	rs.AddTemplate(ctx, "three", "{{.one}} inky pinky {{.three}} blinky clyde {{.two}}")
     40 	rs.AddTemplate(ctx, "root", "root")
     41 	rs.AddTemplate(ctx, "_catch", tr.CatchContent)
     42 	rs.AddTemplate(ctx, "ouf", "ouch")
     43 	rs.AddTemplate(ctx, "flagCatch", "flagiee")
     44 	rs.AddMenu(ctx, "one", "one")
     45 	rs.AddMenu(ctx, "two", "two")
     46 	rs.AddLocalFunc("two", getTwo)
     47 	rs.AddLocalFunc("dyn", getDyn)
     48 	rs.AddLocalFunc("arg", tr.getInput)
     49 	rs.AddLocalFunc("echo", getEcho)
     50 	rs.AddLocalFunc("setFlagOne", setFlag)
     51 	rs.AddLocalFunc("set_lang", set_lang)
     52 	rs.AddLocalFunc("aiee", uhOh)
     53 
     54 	var b []byte
     55 	b = NewLine(nil, HALT, nil, nil, nil)
     56 	rs.AddBytecode(ctx, "one", b)
     57 
     58 	b = NewLine(nil, MOUT, []string{"repent", "0"}, nil, nil)
     59 	b = NewLine(b, HALT, nil, nil, nil)
     60 	rs.AddBytecode(ctx, "_catch", b)
     61 
     62 	b = NewLine(nil, MOUT, []string{"repent", "0"}, nil, nil)
     63 	b = NewLine(b, HALT, nil, nil, nil)
     64 	b = NewLine(b, MOVE, []string{"_"}, nil, nil)
     65 	rs.AddBytecode(ctx, "flagCatch", b)
     66 
     67 	b = NewLine(nil, MOUT, []string{"oo", "1"}, nil, nil)
     68 	b = NewLine(b, HALT, nil, nil, nil)
     69 	rs.AddBytecode(ctx, "ouf", b)
     70 
     71 	rs.AddBytecode(ctx, "root", tr.RootCode)
     72 
     73 	return tr
     74 }
     75 
     76 func getOne(ctx context.Context, sym string, input []byte) (resource.Result, error) {
     77 	return resource.Result{
     78 		Content: "one",
     79 	}, nil
     80 }
     81 
     82 func getTwo(ctx context.Context, sym string, input []byte) (resource.Result, error) {
     83 	return resource.Result{
     84 		Content: "two",
     85 	}, nil
     86 }
     87 
     88 func getDyn(ctx context.Context, sym string, input []byte) (resource.Result, error) {
     89 	return resource.Result{
     90 		Content: dynVal,
     91 	}, nil
     92 }
     93 
     94 func getEcho(ctx context.Context, sym string, input []byte) (resource.Result, error) {
     95 	r := fmt.Sprintf("echo: %s", input)
     96 	return resource.Result{
     97 		Content: r,
     98 	}, nil
     99 }
    100 
    101 func uhOh(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    102 	return resource.Result{}, fmt.Errorf("uh-oh spaghetti'ohs")
    103 }
    104 
    105 func setFlag(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    106 	s := fmt.Sprintf("ping")
    107 	r := resource.Result{
    108 		Content: s,
    109 	}
    110 	if len(input) > 0 {
    111 		r.FlagSet = append(r.FlagSet, uint32(input[0]))
    112 	}
    113 	if len(input) > 1 {
    114 		r.FlagReset = append(r.FlagReset, uint32(input[1]))
    115 	}
    116 	log.Printf("setflag %v", r)
    117 	return r, nil
    118 
    119 }
    120 
    121 func set_lang(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    122 	return resource.Result{
    123 		Content: string(input),
    124 		FlagSet: []uint32{state.FLAG_LANG},
    125 	}, nil
    126 }
    127 
    128 //
    129 //type TestStatefulResolver struct {
    130 //	state *state.State
    131 //}
    132 
    133 func (r testResource) FuncFor(ctx context.Context, sym string) (resource.EntryFunc, error) {
    134 	switch sym {
    135 	case "one":
    136 		return getOne, nil
    137 	case "two":
    138 		return getTwo, nil
    139 	case "dyn":
    140 		return getDyn, nil
    141 	case "arg":
    142 		return r.getInput, nil
    143 	case "echo":
    144 		return getEcho, nil
    145 	case "setFlagOne":
    146 		return setFlag, nil
    147 	case "set_lang":
    148 		return set_lang, nil
    149 	case "aiee":
    150 		return uhOh, nil
    151 	}
    152 	return nil, fmt.Errorf("invalid function: '%s'", sym)
    153 }
    154 
    155 func (r testResource) getInput(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    156 	v, err := r.state.GetInput()
    157 	return resource.Result{
    158 		Content: string(v),
    159 	}, err
    160 }
    161 
    162 func (r testResource) getCode(sym string) ([]byte, error) {
    163 	var b []byte
    164 	switch sym {
    165 	case "_catch":
    166 		b = NewLine(b, MOUT, []string{"repent", "0"}, nil, nil)
    167 		b = NewLine(b, HALT, nil, nil, nil)
    168 	case "flagCatch":
    169 		b = NewLine(b, MOUT, []string{"repent", "0"}, nil, nil)
    170 		b = NewLine(b, HALT, nil, nil, nil)
    171 		b = NewLine(b, MOVE, []string{"_"}, nil, nil)
    172 	case "root":
    173 		b = r.RootCode
    174 	case "ouf":
    175 		b = NewLine(b, MOUT, []string{"oo", "1"}, nil, nil)
    176 		b = NewLine(b, HALT, nil, nil, nil)
    177 	}
    178 
    179 	return b, nil
    180 }
    181 
    182 func TestRun(t *testing.T) {
    183 	st := state.NewState(5)
    184 	rs := newTestResource(st)
    185 	rs.Lock()
    186 	ca := cache.NewCache()
    187 	vm := NewVm(st, &rs, ca, nil)
    188 
    189 	b := NewLine(nil, MOVE, []string{"foo"}, nil, nil)
    190 	b = NewLine(b, HALT, nil, nil, nil)
    191 	ctx := context.Background()
    192 	_, err := vm.Run(ctx, b)
    193 	if err == nil {
    194 		t.Fatalf("expected error")
    195 	}
    196 
    197 	b = []byte{0x01, 0x02}
    198 	_, err = vm.Run(ctx, b)
    199 	if err == nil {
    200 		t.Fatalf("no error on invalid opcode")
    201 	}
    202 }
    203 
    204 func TestRunLoadRender(t *testing.T) {
    205 	st := state.NewState(5)
    206 	rs := newTestResource(st)
    207 	rs.Lock()
    208 	ca := cache.NewCache()
    209 	vm := NewVm(st, &rs, ca, nil)
    210 
    211 	st.Down("bar")
    212 
    213 	var err error
    214 	ctx := context.Background()
    215 	b := NewLine(nil, LOAD, []string{"one"}, []byte{0x0a}, nil)
    216 	b = NewLine(b, MAP, []string{"one"}, nil, nil)
    217 	b = NewLine(b, LOAD, []string{"two"}, []byte{0x0a}, nil)
    218 	b = NewLine(b, MAP, []string{"two"}, nil, nil)
    219 	b = NewLine(b, HALT, nil, nil, nil)
    220 	b, err = vm.Run(ctx, b)
    221 	if err != nil {
    222 		t.Fatal(err)
    223 	}
    224 	r, err := vm.Render(ctx)
    225 	if err != nil {
    226 		t.Fatal(err)
    227 	}
    228 	expect := "inky pinky one blinky two clyde"
    229 	if r != expect {
    230 		t.Fatalf("Expected\n\t%s\ngot\n\t%s\n", expect, r)
    231 	}
    232 
    233 	b = NewLine(nil, LOAD, []string{"two"}, []byte{0x0a}, nil)
    234 	b = NewLine(b, MAP, []string{"two"}, nil, nil)
    235 	b = NewLine(b, HALT, nil, nil, nil)
    236 	b, err = vm.Run(ctx, b)
    237 	if err != nil {
    238 		t.Fatal(err)
    239 	}
    240 	b = NewLine(nil, MAP, []string{"one"}, nil, nil)
    241 	b = NewLine(b, MAP, []string{"two"}, nil, nil)
    242 	b = NewLine(b, HALT, nil, nil, nil)
    243 	_, err = vm.Run(ctx, b)
    244 	if err != nil {
    245 		t.Fatal(err)
    246 	}
    247 	r, err = vm.Render(ctx)
    248 	if err != nil {
    249 		t.Fatal(err)
    250 	}
    251 	expect = "inky pinky one blinky two clyde"
    252 	if r != expect {
    253 		t.Fatalf("Expected %v, got %v", expect, r)
    254 	}
    255 }
    256 
    257 func TestRunMultiple(t *testing.T) {
    258 	st := state.NewState(5)
    259 	rs := newTestResource(st)
    260 	rs.Lock()
    261 	ca := cache.NewCache()
    262 	vm := NewVm(st, &rs, ca, nil)
    263 
    264 	ctx := context.Background()
    265 	b := NewLine(nil, MOVE, []string{"test"}, nil, nil)
    266 	b = NewLine(b, LOAD, []string{"one"}, []byte{0x00}, nil)
    267 	b = NewLine(b, LOAD, []string{"two"}, []byte{42}, nil)
    268 	b = NewLine(b, HALT, nil, nil, nil)
    269 	var err error
    270 	b, err = vm.Run(ctx, b)
    271 	if err == nil {
    272 		t.Fatal(err)
    273 	}
    274 }
    275 
    276 func TestRunReload(t *testing.T) {
    277 	st := state.NewState(5)
    278 	rs := newTestResource(st)
    279 	rs.Lock()
    280 	ca := cache.NewCache()
    281 	szr := render.NewSizer(128)
    282 	vm := NewVm(st, &rs, ca, szr)
    283 
    284 	ctx := context.Background()
    285 	b := NewLine(nil, MOVE, []string{"root"}, nil, nil)
    286 	b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
    287 	b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
    288 	b = NewLine(b, HALT, nil, nil, nil)
    289 	_, err := vm.Run(ctx, b)
    290 	if err != nil {
    291 		t.Fatal(err)
    292 	}
    293 	r, err := vm.Render(ctx)
    294 	if err != nil {
    295 		t.Fatal(err)
    296 	}
    297 	if r != "root" {
    298 		t.Fatalf("expected result 'root', got %v", r)
    299 	}
    300 	dynVal = "baz"
    301 	b = NewLine(nil, RELOAD, []string{"dyn"}, nil, nil)
    302 	b = NewLine(b, HALT, nil, nil, nil)
    303 	_, err = vm.Run(ctx, b)
    304 	if err != nil {
    305 		t.Fatal(err)
    306 	}
    307 }
    308 
    309 func TestHalt(t *testing.T) {
    310 	st := state.NewState(5)
    311 	rs := newTestResource(st)
    312 	rs.Lock()
    313 	ca := cache.NewCache()
    314 	vm := NewVm(st, &rs, ca, nil)
    315 
    316 	b := NewLine(nil, MOVE, []string{"root"}, nil, nil)
    317 	b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
    318 	b = NewLine(b, HALT, nil, nil, nil)
    319 	b = NewLine(b, MOVE, []string{"foo"}, nil, nil)
    320 	var err error
    321 	ctx := context.Background()
    322 	b, err = vm.Run(ctx, b)
    323 	if err != nil {
    324 		t.Error(err)
    325 	}
    326 	r, _ := st.Where()
    327 	if r == "foo" {
    328 		t.Fatalf("Expected where-symbol not to be 'foo'")
    329 	}
    330 	if !bytes.Equal(b[:2], []byte{0x00, MOVE}) {
    331 		t.Fatalf("Expected MOVE instruction, found '%v'", b)
    332 	}
    333 }
    334 
    335 func TestRunArg(t *testing.T) {
    336 	st := state.NewState(5)
    337 	rs := newTestResource(st)
    338 	rs.Lock()
    339 	ca := cache.NewCache()
    340 	vm := NewVm(st, &rs, ca, nil)
    341 
    342 	input := []byte("bar")
    343 	_ = st.SetInput(input)
    344 
    345 	bi := NewLine(nil, INCMP, []string{"baz", "bar"}, nil, nil)
    346 	ctx := context.Background()
    347 
    348 	var err error
    349 	b, err := vm.Run(ctx, bi)
    350 	if err == nil {
    351 		t.Fatalf("expected error")
    352 	}
    353 	l := len(b)
    354 	if l != 0 {
    355 		t.Fatalf("expected empty remainder, got length %v: %v", l, b)
    356 	}
    357 	r, _ := st.Where()
    358 	if r != "baz" {
    359 		t.Fatalf("expected where-state baz, got %v", r)
    360 	}
    361 }
    362 
    363 func TestRunInputHandler(t *testing.T) {
    364 	st := state.NewState(5)
    365 	rs := newTestResource(st)
    366 	rs.Lock()
    367 	ca := cache.NewCache()
    368 	vm := NewVm(st, &rs, ca, nil)
    369 
    370 	_ = st.SetInput([]byte("baz"))
    371 
    372 	bi := NewLine([]byte{}, INCMP, []string{"aiee", "bar"}, nil, nil)
    373 	bi = NewLine(bi, INCMP, []string{"foo", "baz"}, nil, nil)
    374 	bi = NewLine(bi, LOAD, []string{"one"}, []byte{0x00}, nil)
    375 	bi = NewLine(bi, LOAD, []string{"two"}, []byte{0x03}, nil)
    376 	bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
    377 	bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
    378 	bi = NewLine(bi, HALT, nil, nil, nil)
    379 
    380 	var err error
    381 	ctx := context.Background()
    382 	_, err = vm.Run(ctx, bi)
    383 	if err == nil {
    384 		t.Fatalf("expected error")
    385 	}
    386 	r, _ := st.Where()
    387 	if r != "foo" {
    388 		t.Fatalf("expected where-sym 'foo', got '%v'", r)
    389 	}
    390 }
    391 
    392 func TestRunArgInvalid(t *testing.T) {
    393 	st := state.NewState(5)
    394 	rs := newTestResource(st)
    395 	rs.Lock()
    396 	ca := cache.NewCache()
    397 	vm := NewVm(st, &rs, ca, nil)
    398 
    399 	_ = st.SetInput([]byte("foo"))
    400 
    401 	var err error
    402 
    403 	st.Down("root")
    404 	b := NewLine(nil, INCMP, []string{"baz", "bar"}, nil, nil)
    405 
    406 	ctx := context.Background()
    407 	b, err = vm.Run(ctx, b)
    408 	if err != nil {
    409 		t.Fatal(err)
    410 	}
    411 	location, _ := st.Where()
    412 	if location != "_catch" {
    413 		t.Fatalf("expected where-state _catch, got %v", location)
    414 	}
    415 
    416 	r, err := vm.Render(ctx)
    417 	if err != nil {
    418 		t.Fatal(err)
    419 	}
    420 	expect := `invalid input: 'foo'
    421 0:repent`
    422 	if r != expect {
    423 		t.Fatalf("expected:\n\t%s\ngot:\n\t%s", expect, r)
    424 	}
    425 }
    426 
    427 func TestRunMenu(t *testing.T) {
    428 	st := state.NewState(5)
    429 	rs := newTestResource(st)
    430 	ca := cache.NewCache()
    431 	vm := NewVm(st, &rs, ca, nil)
    432 
    433 	var err error
    434 
    435 	ctx := context.Background()
    436 
    437 	rs.AddBytecode(ctx, "foo", []byte{})
    438 	rs.Lock()
    439 	b := NewLine(nil, MOVE, []string{"foo"}, nil, nil)
    440 	b = NewLine(b, MOUT, []string{"one", "0"}, nil, nil)
    441 	b = NewLine(b, MOUT, []string{"two", "1"}, nil, nil)
    442 	b = NewLine(b, HALT, nil, nil, nil)
    443 
    444 	b, err = vm.Run(ctx, b)
    445 	if err != nil {
    446 		t.Error(err)
    447 	}
    448 	l := len(b)
    449 	if l != 0 {
    450 		t.Errorf("expected empty remainder, got length %v: %v", l, b)
    451 	}
    452 
    453 	r, err := vm.Render(ctx)
    454 	if err != nil {
    455 		t.Fatal(err)
    456 	}
    457 	expect := "inky pinky blinky clyde\n0:one\n1:two"
    458 	if r != expect {
    459 		t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, r)
    460 	}
    461 }
    462 
    463 func TestRunMenuBrowse(t *testing.T) {
    464 	log.Printf("This test is incomplete, it must check the output of a menu browser once one is implemented. For now it only checks whether it can execute the runner endpoints for the instrucitons.")
    465 	st := state.NewState(5)
    466 	rs := newTestResource(st)
    467 	ca := cache.NewCache()
    468 	vm := NewVm(st, &rs, ca, nil)
    469 
    470 	var err error
    471 
    472 	ctx := context.Background()
    473 
    474 	rs.AddBytecode(ctx, "foo", []byte{})
    475 	rs.Lock()
    476 	b := NewLine(nil, MOVE, []string{"foo"}, nil, nil)
    477 	b = NewLine(b, MOUT, []string{"one", "0"}, nil, nil)
    478 	b = NewLine(b, MOUT, []string{"two", "1"}, nil, nil)
    479 	b = NewLine(b, HALT, nil, nil, nil)
    480 
    481 	b, err = vm.Run(ctx, b)
    482 	if err != nil {
    483 		t.Error(err)
    484 	}
    485 	l := len(b)
    486 	if l != 0 {
    487 		t.Errorf("expected empty remainder, got length %v: %v", l, b)
    488 	}
    489 
    490 	r, err := vm.Render(ctx)
    491 	if err != nil {
    492 		t.Fatal(err)
    493 	}
    494 	expect := "inky pinky blinky clyde\n0:one\n1:two"
    495 	if r != expect {
    496 		t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect, r)
    497 	}
    498 }
    499 
    500 func TestRunReturn(t *testing.T) {
    501 	st := state.NewState(5)
    502 	rs := newTestResource(st)
    503 	rs.Lock()
    504 	ca := cache.NewCache()
    505 	vm := NewVm(st, &rs, ca, nil)
    506 
    507 	var err error
    508 
    509 	st.Down("root")
    510 	b := NewLine(nil, INCMP, []string{"bar", "0"}, nil, nil)
    511 	b = NewLine(b, INCMP, []string{"_", "1"}, nil, nil)
    512 
    513 	ctx := context.Background()
    514 
    515 	st.SetInput([]byte("0"))
    516 	b, err = vm.Run(ctx, b)
    517 	if err == nil {
    518 		t.Fatalf("expected error")
    519 	}
    520 	location, _ := st.Where()
    521 	if location != "bar" {
    522 		t.Fatalf("expected location 'bar', got '%s'", location)
    523 	}
    524 
    525 	st.SetInput([]byte("1"))
    526 	b, err = vm.Run(ctx, b)
    527 	if err != nil {
    528 		t.Fatal(err)
    529 	}
    530 	location, _ = st.Where()
    531 	if location != "root" {
    532 		t.Fatalf("expected location 'root', got '%s'", location)
    533 	}
    534 }
    535 
    536 func TestRunLoadInput(t *testing.T) {
    537 	st := state.NewState(5)
    538 	rs := newTestResource(st)
    539 	rs.Lock()
    540 	ca := cache.NewCache()
    541 	vm := NewVm(st, &rs, ca, nil)
    542 
    543 	var err error
    544 
    545 	st.Down("root")
    546 	st.SetInput([]byte("foobar"))
    547 
    548 	b := NewLine(nil, LOAD, []string{"echo"}, []byte{0x00}, nil)
    549 	b = NewLine(b, HALT, nil, nil, nil)
    550 
    551 	ctx := context.Background()
    552 
    553 	b, err = vm.Run(ctx, b)
    554 	if err != nil {
    555 		t.Fatal(err)
    556 	}
    557 
    558 	r, err := ca.Get("echo")
    559 	if err != nil {
    560 		t.Fatal(err)
    561 	}
    562 	if r != "echo: foobar" {
    563 		t.Fatalf("expected 'echo: foobar', got %s", r)
    564 	}
    565 }
    566 
    567 func TestInputBranch(t *testing.T) {
    568 	st := state.NewState(5)
    569 	rs := newTestResource(st)
    570 	ca := cache.NewCache()
    571 	vm := NewVm(st, &rs, ca, nil)
    572 
    573 	var err error
    574 
    575 	st.Down("root")
    576 
    577 	b := NewLine(nil, LOAD, []string{"setFlagOne"}, []byte{0x00}, nil)
    578 	b = NewLine(b, RELOAD, []string{"setFlagOne"}, nil, nil)
    579 	b = NewLine(b, CATCH, []string{"flagCatch"}, []byte{8}, []uint8{1})
    580 	b = NewLine(b, CATCH, []string{"one"}, []byte{9}, []uint8{1})
    581 	rs.RootCode = b
    582 	rs.AddBytecode(ctx, "root", rs.RootCode)
    583 	rs.Lock()
    584 
    585 	ctx := context.Background()
    586 
    587 	st.SetInput([]byte{0x08})
    588 	b, err = vm.Run(ctx, b)
    589 	if err != nil {
    590 		t.Fatal(err)
    591 	}
    592 	location, _ := st.Where()
    593 	if location != "flagCatch" {
    594 		t.Fatalf("expected 'flagCatch', got %s", location)
    595 	}
    596 
    597 	st.SetInput([]byte{0x09, 0x08})
    598 	b, err = vm.Run(ctx, b)
    599 	if err != nil {
    600 		t.Fatal(err)
    601 	}
    602 	location, _ = st.Where()
    603 	if location != "one" {
    604 		t.Fatalf("expected 'one', got %s", location)
    605 	}
    606 }
    607 
    608 func TestInputIgnore(t *testing.T) {
    609 	st := state.NewState(5)
    610 	rs := newTestResource(st)
    611 	rs.Lock()
    612 	ca := cache.NewCache()
    613 	vm := NewVm(st, &rs, ca, nil)
    614 
    615 	var err error
    616 
    617 	st.Down("root")
    618 
    619 	b := NewLine(nil, INCMP, []string{"one", "foo"}, nil, nil)
    620 	b = NewLine(b, INCMP, []string{"two", "bar"}, nil, nil)
    621 	b = NewLine(b, HALT, nil, nil, nil)
    622 
    623 	ctx := context.Background()
    624 
    625 	st.SetInput([]byte("foo"))
    626 	b, err = vm.Run(ctx, b)
    627 	if err != nil {
    628 		t.Fatal(err)
    629 	}
    630 
    631 	location, _ := st.Where()
    632 	if location != "one" {
    633 		t.Fatalf("expected 'one', got %s", location)
    634 	}
    635 }
    636 
    637 func TestInputIgnoreWildcard(t *testing.T) {
    638 	st := state.NewState(5)
    639 	rs := newTestResource(st)
    640 	rs.Lock()
    641 	ca := cache.NewCache()
    642 	vm := NewVm(st, &rs, ca, nil)
    643 
    644 	var err error
    645 
    646 	st.Down("root")
    647 
    648 	b := NewLine(nil, INCMP, []string{"one", "foo"}, nil, nil)
    649 	b = NewLine(b, INCMP, []string{"two", "*"}, nil, nil)
    650 
    651 	ctx := context.Background()
    652 
    653 	st.SetInput([]byte("foo"))
    654 	b, err = vm.Run(ctx, b)
    655 	if err != nil {
    656 		t.Fatal(err)
    657 	}
    658 
    659 	location, _ := st.Where()
    660 	if location != "one" {
    661 		t.Fatalf("expected 'one', got %s", location)
    662 	}
    663 }
    664 
    665 func TestCatchCleanMenu(t *testing.T) {
    666 	st := state.NewState(5)
    667 	rs := newTestResource(st)
    668 	rs.Lock()
    669 	ca := cache.NewCache()
    670 	vm := NewVm(st, &rs, ca, nil)
    671 
    672 	var err error
    673 
    674 	st.Down("root")
    675 
    676 	b := NewLine(nil, MOUT, []string{"1", "one"}, nil, nil)
    677 	b = NewLine(b, MOUT, []string{"2", "two"}, nil, nil)
    678 	b = NewLine(b, HALT, nil, nil, nil)
    679 	b = NewLine(b, INCMP, []string{"foo", "1"}, nil, nil)
    680 	b = NewLine(b, CATCH, []string{"ouf"}, []byte{0x08}, []uint8{0x00})
    681 
    682 	ctx := context.Background()
    683 
    684 	st.SetInput([]byte("foo"))
    685 	b, err = vm.Run(ctx, b)
    686 	if err != nil {
    687 		t.Fatal(err)
    688 	}
    689 
    690 	st.SetInput([]byte("foo"))
    691 	b, err = vm.Run(ctx, b)
    692 	if err != nil {
    693 		t.Fatal(err)
    694 	}
    695 
    696 	_, err = vm.Render(ctx)
    697 	if err != nil {
    698 		t.Fatal(err)
    699 	}
    700 }
    701 
    702 func TestSetLang(t *testing.T) {
    703 	st := state.NewState(0)
    704 	rs := newTestResource(st)
    705 	rs.Lock()
    706 	ca := cache.NewCache()
    707 	vm := NewVm(st, &rs, ca, nil)
    708 
    709 	var err error
    710 
    711 	st.Down("root")
    712 
    713 	st.SetInput([]byte("no"))
    714 	b := NewLine(nil, LOAD, []string{"set_lang"}, []byte{0x01, 0x00}, nil)
    715 	b = NewLine(b, HALT, nil, nil, nil)
    716 
    717 	ctx := context.Background()
    718 	b, err = vm.Run(ctx, b)
    719 	if err != nil {
    720 		t.Fatal(err)
    721 	}
    722 	lang := *st.Language
    723 	if lang.Code != "nor" {
    724 		t.Fatalf("expected language 'nor',, got %s", lang.Code)
    725 	}
    726 }
    727 
    728 func TestLoadError(t *testing.T) {
    729 	st := state.NewState(0)
    730 	st.UseDebug()
    731 	rs := newTestResource(st)
    732 	rs.Lock()
    733 	ca := cache.NewCache()
    734 	vm := NewVm(st, &rs, ca, nil)
    735 
    736 	st.Down("root")
    737 	st.SetInput([]byte{})
    738 	b := NewLine(nil, LOAD, []string{"aiee"}, []byte{0x01, 0x10}, nil)
    739 	b = NewLine(b, HALT, nil, nil, nil)
    740 
    741 	var err error
    742 	ctx := context.Background()
    743 	b, err = vm.Run(ctx, b)
    744 	if err != nil {
    745 		t.Fatal(err)
    746 	}
    747 
    748 	r, err := vm.Render(ctx)
    749 	if err != nil {
    750 		t.Fatal(err)
    751 	}
    752 	expect := `error aiee:0
    753 0:repent`
    754 	if r != expect {
    755 		t.Fatalf("expected: \n\t%s\ngot:\n\t%s", expect, r)
    756 	}
    757 }
    758 
    759 func TestMatchFlag(t *testing.T) {
    760 	var err error
    761 	ctx := context.Background()
    762 
    763 	st := state.NewState(1)
    764 	st.UseDebug()
    765 	rs := newTestResource(st)
    766 	rs.Lock()
    767 	ca := cache.NewCache()
    768 	vm := NewVm(st, &rs, ca, nil)
    769 
    770 	st.Down("root")
    771 	st.SetFlag(state.FLAG_USERSTART)
    772 	st.SetInput([]byte{})
    773 	b := NewLine(nil, CATCH, []string{"aiee"}, []byte{state.FLAG_USERSTART}, []uint8{1})
    774 	b = NewLine(b, HALT, nil, nil, nil)
    775 	b, err = vm.Run(ctx, b)
    776 	if err == nil {
    777 		t.Fatal(err)
    778 	}
    779 
    780 	st.SetFlag(state.FLAG_USERSTART)
    781 	st.SetInput([]byte{})
    782 	b = NewLine(nil, CATCH, []string{"aiee"}, []byte{state.FLAG_USERSTART}, []uint8{0})
    783 	b = NewLine(b, HALT, nil, nil, nil)
    784 	b, err = vm.Run(ctx, b)
    785 	if err != nil {
    786 		t.Fatal(err)
    787 	}
    788 
    789 	st.Restart()
    790 	st.SetFlag(state.FLAG_USERSTART)
    791 	st.SetInput([]byte{})
    792 	b = NewLine(nil, CROAK, nil, []byte{state.FLAG_USERSTART}, []uint8{1})
    793 	b = NewLine(b, HALT, nil, nil, nil)
    794 	b, err = vm.Run(ctx, b)
    795 	if err != nil {
    796 		t.Fatal(err)
    797 	}
    798 	if st.MatchFlag(state.FLAG_TERMINATE, false) {
    799 		t.Fatalf("expected terminate set")
    800 	}
    801 
    802 	st.Restart()
    803 	st.SetFlag(state.FLAG_USERSTART)
    804 	st.SetInput([]byte{})
    805 	b = NewLine(nil, CROAK, nil, []byte{state.FLAG_USERSTART}, []uint8{0})
    806 	b = NewLine(b, HALT, nil, nil, nil)
    807 	b, err = vm.Run(ctx, b)
    808 	if err != nil {
    809 		t.Fatal(err)
    810 	}
    811 	if st.MatchFlag(state.FLAG_TERMINATE, true) {
    812 		t.Fatalf("expected no terminate")
    813 	}
    814 }
    815 
    816 func TestBatchRun(t *testing.T) {
    817 	var err error
    818 	ctx := context.Background()
    819 	st := state.NewState(0)
    820 	st.Down("root")
    821 	st.Down("one")
    822 	st.Down("two")
    823 	ca := cache.NewCache()
    824 	rs := newTestResource(st)
    825 	rs.Lock()
    826 	b := NewLine(nil, MNEXT, []string{"fwd", "0"}, nil, nil)
    827 	b = NewLine(b, MPREV, []string{"back", "11"}, nil, nil)
    828 	b = NewLine(b, MSINK, nil, nil, nil)
    829 	b = NewLine(b, HALT, nil, nil, nil)
    830 	vm := NewVm(st, rs, ca, nil)
    831 
    832 	b, err = vm.Run(ctx, b)
    833 	if err != nil {
    834 		t.Fatal(err)
    835 	}
    836 }
    837 
    838 func TestErrorOut(t *testing.T) {
    839 	var err error
    840 	ctx := context.Background()
    841 	st := state.NewState(0)
    842 	ca := cache.NewCache()
    843 	rs := newTestResource(st)
    844 	rs.AddLocalFunc("foo", getTwo)
    845 	rs.AddLocalFunc("aiee", uhOh)
    846 	rs.Lock()
    847 	b := NewLine(nil, LOAD, []string{"two"}, []byte{0x01, 0x10}, nil)
    848 	vm := NewVm(st, rs, ca, nil)
    849 	b, err = vm.Run(ctx, b)
    850 	if err != nil {
    851 		t.Fatal(err)
    852 	}
    853 	if !strings.Contains(vm.String(), " ok") {
    854 		t.Fatalf("expected ok, got %s", vm.String())
    855 	}
    856 
    857 	st = state.NewState(0)
    858 	b = NewLine(nil, LOAD, []string{"aiee"}, []byte{0x01, 0x10}, nil)
    859 	b = NewLine(b, HALT, nil, nil, nil)
    860 	vm = NewVm(st, rs, ca, nil)
    861 	b, err = vm.Run(ctx, b)
    862 	if err != nil {
    863 		t.Fatal(err)
    864 	}
    865 	if !strings.Contains(vm.String(), ") error load: aiee") {
    866 		t.Fatalf("expected load fail aiee in vm string, got %s", vm.String())
    867 	}
    868 	_, err = ca.Get("two")
    869 	if err != nil {
    870 		t.Fatal(err)
    871 	}
    872 	_, err = ca.Get("aiee")
    873 	if err == nil {
    874 		t.Fatalf("expected error")
    875 	}
    876 }