go-vise

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

runner_test.go (18940B)


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