engine_test.go (11246B)
1 package engine 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 8 // "io/ioutil" 9 "log" 10 // "path" 11 "testing" 12 13 "git.defalsify.org/vise.git/cache" 14 "git.defalsify.org/vise.git/db" 15 fsdb "git.defalsify.org/vise.git/db/fs" 16 "git.defalsify.org/vise.git/lang" 17 "git.defalsify.org/vise.git/resource" 18 "git.defalsify.org/vise.git/state" 19 "git.defalsify.org/vise.git/testdata" 20 "git.defalsify.org/vise.git/vm" 21 ) 22 23 var ( 24 dataGenerated bool = false 25 dataDir string = testdata.DataDir 26 ) 27 28 type testWrapper struct { 29 resource.Resource 30 st *state.State 31 db db.Db 32 } 33 34 func newTestWrapper(path string, st *state.State) testWrapper { 35 ctx := context.Background() 36 store := fsdb.NewFsDb() 37 store.Connect(ctx, path) 38 rs := resource.NewDbResource(store) 39 rs.With(db.DATATYPE_STATICLOAD) 40 wr := testWrapper{ 41 rs, 42 st, 43 store, 44 } 45 rs.AddLocalFunc("one", wr.one) 46 rs.AddLocalFunc("inky", wr.inky) 47 rs.AddLocalFunc("pinky", wr.pinky) 48 rs.AddLocalFunc("set_lang", wr.set_lang) 49 rs.AddLocalFunc("translate", wr.translate) 50 rs.AddLocalFunc("quit", quitFunc) 51 return wr 52 } 53 54 func (fs testWrapper) getStore() db.Db { 55 return fs.db 56 } 57 58 func (fs testWrapper) one(ctx context.Context, sym string, input []byte) (resource.Result, error) { 59 return resource.Result{ 60 Content: "one", 61 }, nil 62 } 63 64 func (fs testWrapper) inky(ctx context.Context, sym string, input []byte) (resource.Result, error) { 65 return resource.Result{ 66 Content: "tinkywinky", 67 }, nil 68 } 69 70 func (fs testWrapper) pinky(ctx context.Context, sym string, input []byte) (resource.Result, error) { 71 r := fmt.Sprintf("xyzzy: %x", input) 72 return resource.Result{ 73 Content: r, 74 }, nil 75 } 76 77 func (fs testWrapper) translate(ctx context.Context, sym string, input []byte) (resource.Result, error) { 78 r := "cool" 79 v := ctx.Value("Language") 80 code := "" 81 lang, ok := v.(lang.Language) 82 if ok { 83 code = lang.Code 84 } 85 if code == "nor" { 86 r = "fett" 87 } 88 return resource.Result{ 89 Content: r, 90 }, nil 91 } 92 93 func (fs testWrapper) set_lang(ctx context.Context, sym string, input []byte) (resource.Result, error) { 94 return resource.Result{ 95 Content: string(input), 96 FlagSet: []uint32{state.FLAG_LANG}, 97 }, nil 98 } 99 100 //func(fs testWrapper) GetCode(ctx context.Context, sym string) ([]byte, error) { 101 // sym += ".bin" 102 // fp := path.Join(fs.Path, sym) 103 // r, err := ioutil.ReadFile(fp) 104 // return r, err 105 //} 106 107 func generateTestData(t *testing.T) { 108 if dataGenerated { 109 return 110 } 111 var err error 112 dataDir, err = testdata.Generate() 113 if err != nil { 114 t.Fatal(err) 115 } 116 } 117 118 func quitFunc(ctx context.Context, sym string, input []byte) (resource.Result, error) { 119 return resource.Result{ 120 Content: "these aren't the droids you are looking for", 121 }, nil 122 } 123 124 func TestEngineInit(t *testing.T) { 125 var err error 126 generateTestData(t) 127 ctx := context.Background() 128 st := state.NewState(17) 129 rs := newTestWrapper(dataDir, st) 130 ca := cache.NewCache().WithCacheSize(1024) 131 132 cfg := Config{ 133 Root: "root", 134 } 135 en := NewEngine(cfg, &rs) 136 en = en.WithState(st) 137 en = en.WithMemory(ca) 138 139 //_, err = en.Init(ctx) 140 _, err = en.Exec(ctx, []byte{}) 141 if err != nil { 142 t.Fatal(err) 143 } 144 w := bytes.NewBuffer(nil) 145 _, err = en.Flush(ctx, w) 146 if err != nil { 147 t.Fatal(err) 148 } 149 b := w.Bytes() 150 expect_str := `hello world 151 1:do the foo 152 2:go to the bar 153 3:language template` 154 155 if !bytes.Equal(b, []byte(expect_str)) { 156 t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expect_str, b) 157 } 158 159 input := []byte("1") 160 _, err = en.Exec(ctx, input) 161 if err != nil { 162 t.Fatal(err) 163 } 164 r, _ := st.Where() 165 if r != "foo" { 166 t.Fatalf("expected where-string 'foo', got %s", r) 167 } 168 w = bytes.NewBuffer(nil) 169 _, err = en.Flush(ctx, w) 170 if err != nil { 171 t.Fatal(err) 172 } 173 b = w.Bytes() 174 expect := `this is in foo 175 176 it has more lines 177 0:to foo 178 1:go bar 179 2:see long` 180 181 if !bytes.Equal(b, []byte(expect)) { 182 t.Fatalf("expected\n\t%s\ngot:\n\t%s\n", expect, b) 183 } 184 } 185 186 func TestEngineExecInvalidInput(t *testing.T) { 187 generateTestData(t) 188 ctx := context.Background() 189 st := state.NewState(17) 190 rs := newTestWrapper(dataDir, st) 191 ca := cache.NewCache().WithCacheSize(1024) 192 193 cfg := Config{ 194 Root: "root", 195 } 196 en := NewEngine(cfg, &rs) 197 en = en.WithState(st) 198 en = en.WithMemory(ca) 199 var err error 200 //_, err = en.Init(ctx) 201 _, err = en.Exec(ctx, []byte{}) 202 if err != nil { 203 t.Fatal(err) 204 } 205 _, err = en.Exec(ctx, []byte("_foo")) 206 if err == nil { 207 t.Fatalf("expected fail on invalid input") 208 } 209 } 210 211 func TestEngineResumeTerminated(t *testing.T) { 212 generateTestData(t) 213 ctx := context.Background() 214 st := state.NewState(17) 215 rs := newTestWrapper(dataDir, st) 216 ca := cache.NewCache().WithCacheSize(1024) 217 218 cfg := Config{ 219 Root: "root", 220 } 221 en := NewEngine(cfg, &rs) 222 en = en.WithState(st) 223 en = en.WithMemory(ca) 224 var err error 225 //_, err = en.Init(ctx) 226 _, err = en.Exec(ctx, []byte{}) 227 if err != nil { 228 t.Fatal(err) 229 } 230 231 _, err = en.Exec(ctx, []byte("1")) 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 _, err = en.Exec(ctx, []byte("1")) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 location, idx := st.Where() 242 if location != "baz" { 243 t.Fatalf("expected 'baz', got %s", location) 244 } 245 if idx != 0 { 246 t.Fatalf("expected idx '0', got %v", idx) 247 } 248 } 249 250 func TestLanguageSet(t *testing.T) { 251 generateTestData(t) 252 ctx := context.Background() 253 st := state.NewState(0) 254 rs := newTestWrapper(dataDir, st) 255 ca := cache.NewCache().WithCacheSize(1024) 256 257 cfg := Config{ 258 Root: "root", 259 } 260 en := NewEngine(cfg, &rs) 261 en = en.WithState(st) 262 en = en.WithMemory(ca) 263 264 var err error 265 //_, err = en.Init(ctx) 266 _, err = en.Exec(ctx, []byte{}) 267 if err != nil { 268 t.Fatal(err) 269 } 270 271 b := vm.NewLine(nil, vm.LOAD, []string{"translate"}, []byte{0x01, 0xff}, nil) 272 b = vm.NewLine(b, vm.LOAD, []string{"set_lang"}, []byte{0x01, 0x00}, nil) 273 b = vm.NewLine(b, vm.MOVE, []string{"."}, nil, nil) 274 st.SetCode(b) 275 276 _, err = en.Exec(ctx, []byte("no")) 277 if err != nil { 278 t.Fatal(err) 279 } 280 r, err := ca.Get("translate") 281 if err != nil { 282 t.Fatal(err) 283 } 284 if r != "cool" { 285 t.Fatalf("expected 'cool', got '%s'", r) 286 } 287 288 b = vm.NewLine(nil, vm.RELOAD, []string{"translate"}, nil, nil) 289 b = vm.NewLine(b, vm.MOVE, []string{"."}, nil, nil) 290 st.SetCode(b) 291 292 _, err = en.Exec(ctx, []byte("no")) 293 if err != nil { 294 t.Fatal(err) 295 } 296 r, err = ca.Get("translate") 297 if err != nil { 298 t.Fatal(err) 299 } 300 if r != "fett" { 301 t.Fatalf("expected 'fett', got '%s'", r) 302 } 303 } 304 305 func TestLanguageRender(t *testing.T) { 306 generateTestData(t) 307 ctx := context.Background() 308 st := state.NewState(0) 309 rs := newTestWrapper(dataDir, st) 310 ca := cache.NewCache() 311 312 cfg := Config{ 313 Root: "root", 314 } 315 en := NewEngine(cfg, &rs) 316 en = en.WithState(st) 317 en = en.WithMemory(ca) 318 319 var err error 320 //_, err = en.Init(ctx) 321 _, err = en.Exec(ctx, []byte{}) 322 if err != nil { 323 t.Fatal(err) 324 } 325 326 b := vm.NewLine(nil, vm.LOAD, []string{"set_lang"}, []byte{0x01, 0x00}, nil) 327 b = vm.NewLine(b, vm.MOVE, []string{"lang"}, nil, nil) 328 st.SetCode(b) 329 330 _, err = en.Exec(ctx, []byte("nor")) 331 if err != nil { 332 t.Fatal(err) 333 } 334 335 br := bytes.NewBuffer(nil) 336 _, err = en.Flush(ctx, br) 337 if err != nil { 338 t.Fatal(err) 339 } 340 expect := "dette endrer" 341 r := br.String() 342 if r[:len(expect)] != expect { 343 t.Fatalf("expected %s, got %s", expect, r[:len(expect)]) 344 } 345 346 } 347 348 func TestConfigLanguageRender(t *testing.T) { 349 generateTestData(t) 350 ctx := context.Background() 351 st := state.NewState(0) 352 rs := newTestWrapper(dataDir, st) 353 ca := cache.NewCache() 354 355 cfg := Config{ 356 Root: "root", 357 Language: "nor", 358 } 359 en := NewEngine(cfg, &rs) 360 en = en.WithState(st) 361 en = en.WithMemory(ca) 362 363 var err error 364 //_, err = en.Init(ctx) 365 _, err = en.Exec(ctx, []byte{}) 366 if err != nil { 367 t.Fatal(err) 368 } 369 370 b := vm.NewLine(nil, vm.LOAD, []string{"set_lang"}, []byte{0x01, 0x00}, nil) 371 b = vm.NewLine(b, vm.MOVE, []string{"lang"}, nil, nil) 372 st.SetCode(b) 373 374 _, err = en.Exec(ctx, []byte("foo")) 375 if err != nil { 376 t.Fatal(err) 377 } 378 br := bytes.NewBuffer(nil) 379 _, err = en.Flush(ctx, br) 380 if err != nil { 381 t.Fatal(err) 382 } 383 384 expect := `dette endrer med språket tinkywinky 385 0:tilbake` 386 r := br.String() 387 if r != expect { 388 t.Fatalf("expected:\n\t%s\ngot:\n\t%s", expect, r) 389 } 390 } 391 392 func preBlock(ctx context.Context, sym string, input []byte) (resource.Result, error) { 393 log.Printf("executing preBlock") 394 return resource.Result{ 395 Content: "None shall pass", 396 FlagSet: []uint32{state.FLAG_TERMINATE}, 397 }, nil 398 } 399 400 func preAllow(ctx context.Context, sym string, input []byte) (resource.Result, error) { 401 log.Printf("executing preAllow") 402 return resource.Result{}, nil 403 } 404 405 func TestPreVm(t *testing.T) { 406 var b []byte 407 var out *bytes.Buffer 408 generateTestData(t) 409 ctx := context.Background() 410 st := state.NewState(0) 411 st.UseDebug() 412 rs := newTestWrapper(dataDir, st) 413 ca := cache.NewCache() 414 415 cfg := Config{ 416 Root: "root", 417 } 418 en := NewEngine(cfg, &rs) 419 en = en.WithState(st) 420 en = en.WithMemory(ca) 421 en = en.WithFirst(preBlock) 422 //r, err := en.Init(ctx) 423 r, err := en.Exec(ctx, []byte{}) 424 if err != nil { 425 t.Fatal(err) 426 } 427 if r { 428 t.Fatalf("expected init to return 'not continue'") 429 } 430 out = bytes.NewBuffer(b) 431 _, err = en.Flush(ctx, out) 432 if err != nil { 433 t.Fatal(err) 434 } 435 if !bytes.Equal(out.Bytes(), []byte("None shall pass")) { 436 t.Fatalf("expected writeresult 'None shall pass', got %s", out) 437 } 438 439 st = state.NewState(0) 440 ca = cache.NewCache() 441 en = NewEngine(cfg, &rs) 442 en = en.WithState(st) 443 en = en.WithMemory(ca) 444 en = en.WithFirst(preAllow) 445 //r, err = en.Init(ctx) 446 r, err = en.Exec(ctx, []byte{}) 447 if err != nil { 448 t.Fatal(err) 449 } 450 if !r { 451 t.Fatalf("expected init to return 'continue'") 452 } 453 } 454 455 func TestManyQuits(t *testing.T) { 456 b := bytes.NewBuffer(nil) 457 ctx := context.Background() 458 st := state.NewState(0) 459 st.UseDebug() 460 generateTestData(t) 461 rs := newTestWrapper(dataDir, st) 462 ca := cache.NewCache() 463 464 cfg := Config{ 465 Root: "nothing", 466 } 467 468 en := NewEngine(cfg, rs) 469 en = en.WithState(st) 470 en = en.WithMemory(ca) 471 r, err := en.Exec(ctx, []byte{}) 472 if err != nil { 473 t.Fatal(err) 474 } 475 if r { 476 t.Fatalf("expected init to return 'not continue'") 477 } 478 _, err = en.Flush(ctx, b) 479 if err != nil { 480 t.Fatal(err) 481 } 482 483 en = NewEngine(cfg, rs) 484 en = en.WithState(st) 485 en = en.WithMemory(ca) 486 r, err = en.Exec(ctx, []byte{}) 487 if err != nil { 488 t.Fatal(err) 489 } 490 if r { 491 t.Fatalf("expected init to return 'not continue'") 492 } 493 _, err = en.Flush(ctx, b) 494 if err != nil { 495 t.Fatal(err) 496 } 497 498 en = NewEngine(cfg, rs) 499 en = en.WithState(st) 500 en = en.WithMemory(ca) 501 r, err = en.Exec(ctx, []byte{}) 502 if err != nil { 503 t.Fatal(err) 504 } 505 if r { 506 t.Fatalf("expected init to return 'not continue'") 507 } 508 509 b = bytes.NewBuffer(nil) 510 _, err = en.Flush(ctx, b) 511 if err != nil { 512 t.Fatal(err) 513 } 514 x := "these aren't the droids you are looking for" 515 if !bytes.Equal(b.Bytes(), []byte(x)) { 516 t.Fatalf("expected '%s', got '%s'", x, b.Bytes()) 517 } 518 } 519 520 func TestOutEmpty(t *testing.T) { 521 ctx := context.Background() 522 st := state.NewState(0) 523 st.UseDebug() 524 generateTestData(t) 525 rs := newTestWrapper(dataDir, st) 526 ca := cache.NewCache() 527 528 cfg := Config{ 529 Root: "something", 530 } 531 532 en := NewEngine(cfg, rs) 533 en = en.WithState(st) 534 en = en.WithMemory(ca) 535 r, err := en.Exec(ctx, []byte{}) 536 if err != nil { 537 t.Fatal(err) 538 } 539 if r { 540 t.Fatalf("expected init to return 'not continue'") 541 } 542 543 v := bytes.NewBuffer(nil) 544 en.Flush(ctx, v) 545 x := "mmmm, something..." 546 if !bytes.Equal(v.Bytes(), []byte(x)) { 547 t.Fatalf("expected '%s', got '%s'", x, v.Bytes()) 548 } 549 }