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 }