github.com/kosmosJS/engine-node@v0.0.0-20220426040216-d53e2a72192e/require/module_test.go (about) 1 package require 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path" 11 "testing" 12 13 js "github.com/kosmosJS/engine" 14 ) 15 16 func mapFileSystemSourceLoader(files map[string]string, t *testing.T) SourceLoader { 17 return func(path string) ([]byte, error) { 18 s, ok := files[path] 19 if !ok { 20 return nil, ModuleFileDoesNotExistError 21 } 22 return []byte(s), nil 23 } 24 } 25 26 func TestRequireNativeModule(t *testing.T) { 27 const SCRIPT = ` 28 var m = require("test/m"); 29 m.test(); 30 ` 31 32 vm := js.New() 33 34 registry := new(Registry) 35 registry.Enable(vm) 36 37 RegisterNativeModule("test/m", func(runtime *js.Runtime, module *js.Object) { 38 o := module.Get("exports").(*js.Object) 39 o.Set("test", func(call js.FunctionCall) js.Value { 40 return runtime.ToValue("passed") 41 }) 42 }) 43 44 v, err := vm.RunString(SCRIPT) 45 if err != nil { 46 t.Fatal(err) 47 } 48 49 if !v.StrictEquals(vm.ToValue("passed")) { 50 t.Fatalf("Unexpected result: %v", v) 51 } 52 } 53 54 func TestRequireRegistryNativeModule(t *testing.T) { 55 const SCRIPT = ` 56 var log = require("test/log"); 57 log.print('passed'); 58 ` 59 60 logWithOutput := func(w io.Writer, prefix string) ModuleLoader { 61 return func(vm *js.Runtime, module *js.Object) { 62 o := module.Get("exports").(*js.Object) 63 o.Set("print", func(call js.FunctionCall) js.Value { 64 fmt.Fprint(w, prefix, call.Argument(0).String()) 65 return js.Undefined() 66 }) 67 } 68 } 69 70 vm1 := js.New() 71 buf1 := &bytes.Buffer{} 72 73 registry1 := new(Registry) 74 registry1.Enable(vm1) 75 76 registry1.RegisterNativeModule("test/log", logWithOutput(buf1, "vm1 ")) 77 78 vm2 := js.New() 79 buf2 := &bytes.Buffer{} 80 81 registry2 := new(Registry) 82 registry2.Enable(vm2) 83 84 registry2.RegisterNativeModule("test/log", logWithOutput(buf2, "vm2 ")) 85 86 _, err := vm1.RunString(SCRIPT) 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 s := buf1.String() 92 if s != "vm1 passed" { 93 t.Fatalf("vm1: Unexpected result: %q", s) 94 } 95 96 _, err = vm2.RunString(SCRIPT) 97 if err != nil { 98 t.Fatal(err) 99 } 100 101 s = buf2.String() 102 if s != "vm2 passed" { 103 t.Fatalf("vm2: Unexpected result: %q", s) 104 } 105 } 106 107 func TestRequire(t *testing.T) { 108 const SCRIPT = ` 109 var m = require("./testdata/m.js"); 110 m.test(); 111 ` 112 113 vm := js.New() 114 115 registry := new(Registry) 116 registry.Enable(vm) 117 118 v, err := vm.RunString(SCRIPT) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 if !v.StrictEquals(vm.ToValue("passed")) { 124 t.Fatalf("Unexpected result: %v", v) 125 } 126 } 127 128 func TestSourceLoader(t *testing.T) { 129 const SCRIPT = ` 130 var m = require("m.js"); 131 m.test(); 132 ` 133 134 const MODULE = ` 135 function test() { 136 return "passed1"; 137 } 138 139 exports.test = test; 140 ` 141 142 vm := js.New() 143 144 registry := NewRegistry(WithGlobalFolders("."), WithLoader(func(name string) ([]byte, error) { 145 if name == "m.js" { 146 return []byte(MODULE), nil 147 } 148 return nil, errors.New("Module does not exist") 149 })) 150 registry.Enable(vm) 151 152 v, err := vm.RunString(SCRIPT) 153 if err != nil { 154 t.Fatal(err) 155 } 156 157 if !v.StrictEquals(vm.ToValue("passed1")) { 158 t.Fatalf("Unexpected result: %v", v) 159 } 160 } 161 162 func TestStrictModule(t *testing.T) { 163 const SCRIPT = ` 164 var m = require("m.js"); 165 m.test(); 166 ` 167 168 const MODULE = ` 169 "use strict"; 170 171 function test() { 172 var a = "passed1"; 173 eval("var a = 'not passed'"); 174 return a; 175 } 176 177 exports.test = test; 178 ` 179 180 vm := js.New() 181 182 registry := NewRegistry(WithGlobalFolders("."), WithLoader(func(name string) ([]byte, error) { 183 if name == "m.js" { 184 return []byte(MODULE), nil 185 } 186 return nil, errors.New("Module does not exist") 187 })) 188 registry.Enable(vm) 189 190 v, err := vm.RunString(SCRIPT) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 if !v.StrictEquals(vm.ToValue("passed1")) { 196 t.Fatalf("Unexpected result: %v", v) 197 } 198 } 199 200 func TestResolve(t *testing.T) { 201 testRequire := func(src, fpath string, globalFolders []string, fs map[string]string) (*js.Runtime, js.Value, error) { 202 vm := js.New() 203 r := NewRegistry(WithGlobalFolders(globalFolders...), WithLoader(mapFileSystemSourceLoader(fs, t))) 204 r.Enable(vm) 205 t.Logf("Require(%s)", fpath) 206 ret, err := vm.RunScript(path.Join(src, "test.js"), fmt.Sprintf("require('%s')", fpath)) 207 if err != nil { 208 return nil, nil, err 209 } 210 return vm, ret, nil 211 } 212 213 globalFolders := []string{ 214 "/usr/lib/node_modules", 215 "/home/src/.node_modules", 216 } 217 218 fs := map[string]string{ 219 "/home/src/app/app.js": `exports.name = "app"`, 220 "/home/src/app2/app2.json": `{"name": "app2"}`, 221 "/home/src/app3/index.js": `exports.name = "app3"`, 222 "/home/src/app4/index.json": `{"name": "app4"}`, 223 "/home/src/app5/package.json": `{"main": "app5.js"}`, 224 "/home/src/app5/app5.js": `exports.name = "app5"`, 225 "/home/src/app6/package.json": `{"main": "."}`, 226 "/home/src/app6/index.js": `exports.name = "app6"`, 227 "/home/src/app7/package.json": `{"main": "./a/b/c/file.js"}`, 228 "/home/src/app7/a/b/c/file.js": `exports.name = "app7"`, 229 "/usr/lib/node_modules/app8": `exports.name = "app8"`, 230 "/home/src/app9/app9.js": `exports.name = require('./a/file.js').name`, 231 "/home/src/app9/a/file.js": `exports.name = require('./b/file.js').name`, 232 "/home/src/app9/a/b/file.js": `exports.name = require('./c/file.js').name`, 233 "/home/src/app9/a/b/c/file.js": `exports.name = "app9"`, 234 "/home/src/.node_modules/app10": `exports.name = "app10"`, 235 "/home/src/app11/app11.js": `exports.name = require('d/file.js').name`, 236 "/home/src/app11/a/b/c/app11.js": `exports.name = require('d/file.js').name`, 237 "/home/src/app11/node_modules/d/file.js": `exports.name = "app11"`, 238 "/app12.js": `exports.name = require('a/file.js').name`, 239 "/node_modules/a/file.js": `exports.name = "app12"`, 240 "/app13/app13.js": `exports.name = require('b/file.js').name`, 241 "/node_modules/b/file.js": `exports.name = "app13"`, 242 "node_modules/app14/index.js": `exports.name = "app14"`, 243 "../node_modules/app15/index.js": `exports.name = "app15"`, 244 } 245 246 for i, tc := range []struct { 247 src string 248 path string 249 ok bool 250 field string 251 value string 252 }{ 253 {"/home/src", "./app/app", true, "name", "app"}, 254 {"/home/src", "./app/app.js", true, "name", "app"}, 255 {"/home/src", "./app/bad.js", false, "", ""}, 256 {"/home/src", "./app2/app2", true, "name", "app2"}, 257 {"/home/src", "./app2/app2.json", true, "name", "app2"}, 258 {"/home/src", "./app/bad.json", false, "", ""}, 259 {"/home/src", "./app3", true, "name", "app3"}, 260 {"/home/src", "./appbad", false, "", ""}, 261 {"/home/src", "./app4", true, "name", "app4"}, 262 {"/home/src", "./appbad", false, "", ""}, 263 {"/home/src", "./app5", true, "name", "app5"}, 264 {"/home/src", "./app6", true, "name", "app6"}, 265 {"/home/src", "./app7", true, "name", "app7"}, 266 {"/home/src", "app8", true, "name", "app8"}, 267 {"/home/src", "./app9/app9", true, "name", "app9"}, 268 {"/home/src", "app10", true, "name", "app10"}, 269 {"/home/src", "./app11/app11.js", true, "name", "app11"}, 270 {"/home/src", "./app11/a/b/c/app11.js", true, "name", "app11"}, 271 {"/", "./app12", true, "name", "app12"}, 272 {"/", "./app13/app13", true, "name", "app13"}, 273 {".", "app14", true, "name", "app14"}, 274 {"..", "nonexistent", false, "", ""}, 275 } { 276 vm, mod, err := testRequire(tc.src, tc.path, globalFolders, fs) 277 if err != nil { 278 if tc.ok { 279 t.Errorf("%d: require() failed: %v", i, err) 280 } 281 continue 282 } else { 283 if !tc.ok { 284 t.Errorf("%d: expected to fail, but did not", i) 285 continue 286 } 287 } 288 f := mod.ToObject(vm).Get(tc.field) 289 if f == nil { 290 t.Errorf("%v: field %q not found", i, tc.field) 291 continue 292 } 293 value := f.String() 294 if value != tc.value { 295 t.Errorf("%v: got %q expected %q", i, value, tc.value) 296 } 297 } 298 } 299 300 func TestRequireCycle(t *testing.T) { 301 vm := js.New() 302 r := NewRegistry(WithLoader(mapFileSystemSourceLoader(map[string]string{ 303 "a.js": `var b = require('./b.js'); exports.done = true;`, 304 "b.js": `var a = require('./a.js'); exports.done = true;`, 305 }, t))) 306 r.Enable(vm) 307 res, err := vm.RunString(` 308 var a = require('./a.js'); 309 var b = require('./b.js'); 310 a.done && b.done; 311 `) 312 if err != nil { 313 t.Fatal(err) 314 } 315 if v := res.Export(); v != true { 316 t.Fatalf("Unexpected result: %v", v) 317 } 318 } 319 320 func TestErrorPropagation(t *testing.T) { 321 vm := js.New() 322 r := NewRegistry(WithLoader(mapFileSystemSourceLoader(map[string]string{ 323 "m.js": `throw 'test passed';`, 324 }, t))) 325 rr := r.Enable(vm) 326 _, err := rr.Require("./m") 327 if err == nil { 328 t.Fatal("Expected an error") 329 } 330 if ex, ok := err.(*js.Exception); ok { 331 if !ex.Value().StrictEquals(vm.ToValue("test passed")) { 332 t.Fatalf("Unexpected Exception: %v", ex) 333 } 334 } else { 335 t.Fatal(err) 336 } 337 } 338 339 func TestSourceMapLoader(t *testing.T) { 340 vm := js.New() 341 r := NewRegistry(WithLoader(func(p string) ([]byte, error) { 342 switch p { 343 case "dir/m.js": 344 return []byte(`throw 'test passed'; 345 //# sourceMappingURL=m.js.map`), nil 346 case "dir/m.js.map": 347 return []byte(`{"version":3,"file":"m.js","sourceRoot":"","sources":["m.ts"],"names":[],"mappings":";AAAA"} 348 `), nil 349 } 350 return nil, ModuleFileDoesNotExistError 351 })) 352 353 rr := r.Enable(vm) 354 _, err := rr.Require("./dir/m") 355 if err == nil { 356 t.Fatal("Expected an error") 357 } 358 if ex, ok := err.(*js.Exception); ok { 359 if !ex.Value().StrictEquals(vm.ToValue("test passed")) { 360 t.Fatalf("Unexpected Exception: %v", ex) 361 } 362 } else { 363 t.Fatal(err) 364 } 365 } 366 367 func testsetup() (string, func(), error) { 368 name, err := ioutil.TempDir("", "engine-nodejs-require-test") 369 if err != nil { 370 return "", nil, err 371 } 372 return name, func() { 373 os.RemoveAll(name) 374 }, nil 375 } 376 377 func TestDefaultModuleLoader(t *testing.T) { 378 workdir, teardown, err := testsetup() 379 if err != nil { 380 t.Fatal(err) 381 } 382 defer teardown() 383 384 err = os.Chdir(workdir) 385 if err != nil { 386 t.Fatal(err) 387 } 388 err = os.Mkdir("module", 0755) 389 if err != nil { 390 t.Fatal(err) 391 } 392 err = ioutil.WriteFile("module/index.js", []byte(`throw 'test passed';`), 0644) 393 if err != nil { 394 t.Fatal(err) 395 } 396 vm := js.New() 397 r := NewRegistry() 398 rr := r.Enable(vm) 399 _, err = rr.Require("./module") 400 if err == nil { 401 t.Fatal("Expected an error") 402 } 403 if ex, ok := err.(*js.Exception); ok { 404 if !ex.Value().StrictEquals(vm.ToValue("test passed")) { 405 t.Fatalf("Unexpected Exception: %v", ex) 406 } 407 } else { 408 t.Fatal(err) 409 } 410 }