go-vise

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

runner_test.go (18929B)


      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/render"
     12 	"git.defalsify.org/vise.git/resource"
     13 	"git.defalsify.org/vise.git/internal/resourcetest"
     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 
    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 //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 
    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 }