Skip to content

Commit

Permalink
Fix test script resolution to work with NET 8 artifacts output (#1690)
Browse files Browse the repository at this point in the history
* expose failed file path in module loading exception
  • Loading branch information
lahma committed Nov 22, 2023
1 parent 4b4d64f commit 473ca00
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 57 deletions.
24 changes: 20 additions & 4 deletions Jint.Tests.PublicInterface/ShadowRealmTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void MultipleShadowRealmsDoNotInterfere()
engine.SetValue("message", "world");
engine.Evaluate("function hello() {return message}");

Assert.Equal("world",engine.Evaluate("hello();"));
Assert.Equal("world", engine.Evaluate("hello();"));

var shadowRealm = engine.Realm.Intrinsics.ShadowRealm.Construct();
shadowRealm.SetValue("message", "realm 1");
Expand Down Expand Up @@ -97,16 +97,32 @@ private static string GetBasePath()
var assemblyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);

var current = assemblyDirectory;
while (current is not null && current.GetDirectories().All(x => x.Name != "Jint.Tests"))
var binDirectory = $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}";
while (current is not null)
{
current = current.Parent;
if (current.FullName.Contains(binDirectory) || current.Name == "bin")
{
current = current.Parent;
continue;
}

var testDirectory = current.GetDirectories("Jint.Tests").FirstOrDefault();
if (testDirectory == null)
{
current = current.Parent;
continue;
}

// found it
current = testDirectory;
break;
}

if (current is null)
{
throw new NullReferenceException($"Could not find tests base path, assemblyPath: {assemblyDirectory}");
}

return Path.Combine(current.FullName, "Jint.Tests", "Runtime", "Scripts");
return Path.Combine(current.FullName, "Runtime", "Scripts");
}
}
103 changes: 67 additions & 36 deletions Jint.Tests/Runtime/ModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ModuleTests()
[Fact]
public void ShouldExportNamed()
{
_engine.AddModule("my-module", @"export const value = 'exported value';");
_engine.AddModule("my-module", "export const value = 'exported value';");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("value").AsString());
Expand All @@ -24,7 +24,7 @@ public void ShouldExportNamed()
[Fact]
public void ShouldExportNamedListRenamed()
{
_engine.AddModule("my-module", @"const value1 = 1; const value2 = 2; export { value1 as renamed1, value2 as renamed2 }");
_engine.AddModule("my-module", "const value1 = 1; const value2 = 2; export { value1 as renamed1, value2 as renamed2 }");
var ns = _engine.ImportModule("my-module");

Assert.Equal(1, ns.Get("renamed1").AsInteger());
Expand All @@ -34,7 +34,7 @@ public void ShouldExportNamedListRenamed()
[Fact]
public void ShouldExportDefault()
{
_engine.AddModule("my-module", @"export default 'exported value';");
_engine.AddModule("my-module", "export default 'exported value';");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("default").AsString());
Expand All @@ -43,8 +43,8 @@ public void ShouldExportDefault()
[Fact]
public void ShouldExportAll()
{
_engine.AddModule("module1", @"export const value = 'exported value';");
_engine.AddModule("module2", @"export * from 'module1';");
_engine.AddModule("module1", "export const value = 'exported value';");
_engine.AddModule("module2", "export * from 'module1';");
var ns = _engine.ImportModule("module2");

Assert.Equal("exported value", ns.Get("value").AsString());
Expand All @@ -53,8 +53,8 @@ public void ShouldExportAll()
[Fact]
public void ShouldImportNamed()
{
_engine.AddModule("imported-module", @"export const value = 'exported value';");
_engine.AddModule("my-module", @"import { value } from 'imported-module'; export const exported = value;");
_engine.AddModule("imported-module", "export const value = 'exported value';");
_engine.AddModule("my-module", "import { value } from 'imported-module'; export const exported = value;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("exported").AsString());
Expand All @@ -63,8 +63,8 @@ public void ShouldImportNamed()
[Fact]
public void ShouldImportRenamed()
{
_engine.AddModule("imported-module", @"export const value = 'exported value';");
_engine.AddModule("my-module", @"import { value as renamed } from 'imported-module'; export const exported = renamed;");
_engine.AddModule("imported-module", "export const value = 'exported value';");
_engine.AddModule("my-module", "import { value as renamed } from 'imported-module'; export const exported = renamed;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("exported").AsString());
Expand All @@ -73,8 +73,8 @@ public void ShouldImportRenamed()
[Fact]
public void ShouldImportDefault()
{
_engine.AddModule("imported-module", @"export default 'exported value';");
_engine.AddModule("my-module", @"import imported from 'imported-module'; export const exported = imported;");
_engine.AddModule("imported-module", "export default 'exported value';");
_engine.AddModule("my-module", "import imported from 'imported-module'; export const exported = imported;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("exported").AsString());
Expand All @@ -83,8 +83,8 @@ public void ShouldImportDefault()
[Fact]
public void ShouldImportAll()
{
_engine.AddModule("imported-module", @"export const value = 'exported value';");
_engine.AddModule("my-module", @"import * as imported from 'imported-module'; export const exported = imported.value;");
_engine.AddModule("imported-module", "export const value = 'exported value';");
_engine.AddModule("my-module", "import * as imported from 'imported-module'; export const exported = imported.value;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("exported value", ns.Get("exported").AsString());
Expand All @@ -95,7 +95,7 @@ public void ShouldImportDynamically()
{
var received = false;
_engine.AddModule("imported-module", builder => builder.ExportFunction("signal", () => received = true));
_engine.AddModule("my-module", @"import('imported-module').then(ns => { ns.signal(); });");
_engine.AddModule("my-module", "import('imported-module').then(ns => { ns.signal(); });");

_engine.ImportModule("my-module");

Expand All @@ -105,8 +105,8 @@ public void ShouldImportDynamically()
[Fact]
public void ShouldPropagateParseError()
{
_engine.AddModule("imported", @"export const invalid;");
_engine.AddModule("my-module", @"import { invalid } from 'imported';");
_engine.AddModule("imported", "export const invalid;");
_engine.AddModule("my-module", "import { invalid } from 'imported';");

var exc = Assert.Throws<JavaScriptException>(() => _engine.ImportModule("my-module"));
Assert.Equal("Error while loading module: error in module 'imported': Line 1: Missing initializer in const declaration", exc.Message);
Expand All @@ -116,8 +116,8 @@ public void ShouldPropagateParseError()
[Fact]
public void ShouldPropagateLinkError()
{
_engine.AddModule("imported", @"export invalid;");
_engine.AddModule("my-module", @"import { value } from 'imported';");
_engine.AddModule("imported", "export invalid;");
_engine.AddModule("my-module", "import { value } from 'imported';");

var exc = Assert.Throws<JavaScriptException>(() => _engine.ImportModule("my-module"));
Assert.Equal("Error while loading module: error in module 'imported': Line 1: Unexpected identifier", exc.Message);
Expand All @@ -127,7 +127,7 @@ public void ShouldPropagateLinkError()
[Fact]
public void ShouldPropagateExecuteError()
{
_engine.AddModule("my-module", @"throw new Error('imported successfully');");
_engine.AddModule("my-module", "throw new Error('imported successfully');");

var exc = Assert.Throws<JavaScriptException>(() => _engine.ImportModule("my-module"));
Assert.Equal("imported successfully", exc.Message);
Expand All @@ -137,8 +137,8 @@ public void ShouldPropagateExecuteError()
[Fact]
public void ShouldPropagateThrowStatementThroughJavaScriptImport()
{
_engine.AddModule("imported-module", @"throw new Error('imported successfully');");
_engine.AddModule("my-module", @"import 'imported-module';");
_engine.AddModule("imported-module", "throw new Error('imported successfully');");
_engine.AddModule("my-module", "import 'imported-module';");

var exc = Assert.Throws<JavaScriptException>(() => _engine.ImportModule("my-module"));
Assert.Equal("imported successfully", exc.Message);
Expand All @@ -156,8 +156,11 @@ public void ShouldAddModuleFromJsValue()
[Fact]
public void ShouldAddModuleFromClrInstance()
{
_engine.AddModule("imported-module", builder => builder.ExportObject("value", new ImportedClass { Value = "instance value" }));
_engine.AddModule("my-module", @"import { value } from 'imported-module'; export const exported = value.value;");
_engine.AddModule("imported-module", builder => builder.ExportObject("value", new ImportedClass
{
Value = "instance value"
}));
_engine.AddModule("my-module", "import { value } from 'imported-module'; export const exported = value.value;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("instance value", ns.Get("exported").AsString());
Expand All @@ -178,7 +181,7 @@ public void ShouldAllowInvokeUserDefinedClass()
public void ShouldAddModuleFromClrType()
{
_engine.AddModule("imported-module", builder => builder.ExportType<ImportedClass>());
_engine.AddModule("my-module", @"import { ImportedClass } from 'imported-module'; export const exported = new ImportedClass().value;");
_engine.AddModule("my-module", "import { ImportedClass } from 'imported-module'; export const exported = new ImportedClass().value;");
var ns = _engine.ImportModule("my-module");

Assert.Equal("hello world", ns.Get("exported").AsString());
Expand Down Expand Up @@ -207,8 +210,20 @@ public void ShouldAddModuleFromClrFunction()
export const result = [fns.act_noargs(), fns.act_args('ok'), fns.fn_noargs(), fns.fn_args('ok')];");
var ns = _engine.ImportModule("my-module");

Assert.Equal(new[] { "act_noargs", "act_args:ok", "fn_noargs", "fn_args:ok" }, received.ToArray());
Assert.Equal(new[] { "undefined", "undefined", "ret", "ret" }, ns.Get("result").AsArray().Select(x => x.ToString()).ToArray());
Assert.Equal(new[]
{
"act_noargs",
"act_args:ok",
"fn_noargs",
"fn_args:ok"
}, received.ToArray());
Assert.Equal(new[]
{
"undefined",
"undefined",
"ret",
"ret"
}, ns.Get("result").AsArray().Select(x => x.ToString()).ToArray());
}

private class ImportedClass
Expand All @@ -222,7 +237,7 @@ public void ShouldAllowExportMultipleImports()
_engine.AddModule("@mine/import1", builder => builder.ExportValue("value1", JsNumber.Create(1)));
_engine.AddModule("@mine/import2", builder => builder.ExportValue("value2", JsNumber.Create(2)));
_engine.AddModule("@mine", "export * from '@mine/import1'; export * from '@mine/import2'");
_engine.AddModule("app", @"import { value1, value2 } from '@mine'; export const result = `${value1} ${value2}`");
_engine.AddModule("app", "import { value1, value2 } from '@mine'; export const result = `${value1} ${value2}`");
var ns = _engine.ImportModule("app");

Assert.Equal("1 2", ns.Get("result").AsString());
Expand Down Expand Up @@ -258,7 +273,7 @@ public void ShouldImportOnlyOnce()
{
var called = 0;
_engine.AddModule("imported-module", builder => builder.ExportFunction("count", args => called++));
_engine.AddModule("my-module", @"import { count } from 'imported-module'; count();");
_engine.AddModule("my-module", "import { count } from 'imported-module'; count();");
_engine.ImportModule("my-module");
_engine.ImportModule("my-module");

Expand All @@ -268,14 +283,14 @@ public void ShouldImportOnlyOnce()
[Fact]
public void ShouldAllowSelfImport()
{
_engine.AddModule("my-globals", @"export const globals = { counter: 0 };");
_engine.AddModule("my-globals", "export const globals = { counter: 0 };");
_engine.AddModule("my-module", @"
import { globals } from 'my-globals';
import {} from 'my-module';
globals.counter++;
export const count = globals.counter;
");
var ns= _engine.ImportModule("my-module");
var ns = _engine.ImportModule("my-module");

Assert.Equal(1, ns.Get("count").AsInteger());
}
Expand All @@ -285,8 +300,8 @@ public void ShouldAllowCyclicImport()
{
// https://tc39.es/ecma262/#sec-example-cyclic-module-record-graphs

_engine.AddModule("B", @"import { a } from 'A'; export const b = 'b';");
_engine.AddModule("A", @"import { b } from 'B'; export const a = 'a';");
_engine.AddModule("B", "import { a } from 'A'; export const b = 'b';");
_engine.AddModule("A", "import { b } from 'B'; export const a = 'a';");

var nsA = _engine.ImportModule("A");
var nsB = _engine.ImportModule("B");
Expand All @@ -301,7 +316,7 @@ public void ShouldSupportConstraints()
var engine = new Engine(opts => opts.TimeoutInterval(TimeSpan.FromTicks(1)));

engine.AddModule("sleep", builder => builder.ExportFunction("sleep", () => Thread.Sleep(100)));
engine.AddModule("my-module", @"import { sleep } from 'sleep'; for(var i = 0; i < 100; i++) { sleep(); } export const result = 'ok';");
engine.AddModule("my-module", "import { sleep } from 'sleep'; for(var i = 0; i < 100; i++) { sleep(); } export const result = 'ok';");
Assert.Throws<TimeoutException>(() => engine.ImportModule("my-module"));
}

Expand Down Expand Up @@ -350,14 +365,30 @@ public void CanReuseModule()
}
}

internal static string GetBasePath()
private static string GetBasePath()
{
var assemblyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);

var current = assemblyDirectory;
while (current is not null && current.Name != "Jint.Tests")
var binDirectory = $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}";
while (current is not null)
{
current = current.Parent;
if (current.FullName.Contains(binDirectory) || current.Name == "bin")
{
current = current.Parent;
continue;
}

var testDirectory = current.GetDirectories("Jint.Tests").FirstOrDefault();
if (testDirectory == null)
{
current = current.Parent;
continue;
}

// found it
current = testDirectory;
break;
}

if (current is null)
Expand Down
4 changes: 2 additions & 2 deletions Jint/Runtime/ExceptionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ public static void ThrowExecutionCanceledException()
}

[DoesNotReturn]
public static void ThrowModuleResolutionException(string resolverAlgorithmError, string specifier, string? parent)
public static void ThrowModuleResolutionException(string message, string specifier, string? parent, string? filePath = null)
{
throw new ModuleResolutionException(resolverAlgorithmError, specifier, parent);
throw new ModuleResolutionException(message, specifier, parent, filePath);
}
}
}
12 changes: 4 additions & 8 deletions Jint/Runtime/Modules/DefaultModuleLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ public sealed class DefaultModuleLoader : IModuleLoader
private readonly Uri _basePath;
private readonly bool _restrictToBasePath;

public DefaultModuleLoader(string basePath) : this(basePath, true)
{

}

public DefaultModuleLoader(string basePath, bool restrictToBasePath)
public DefaultModuleLoader(string basePath, bool restrictToBasePath = true)
{
if (string.IsNullOrWhiteSpace(basePath))
{
Expand Down Expand Up @@ -74,7 +69,7 @@ public ResolvedSpecifier Resolve(string? referencingModuleLocation, string speci
return new ResolvedSpecifier(
specifier,
specifier,
null,
Uri: null,
SpecifierType.Bare
);
}
Expand Down Expand Up @@ -120,10 +115,11 @@ public Module LoadModule(Engine engine, ResolvedSpecifier resolved)
{
ExceptionHelper.ThrowInvalidOperationException($"Module '{resolved.Specifier}' of type '{resolved.Type}' has no resolved URI.");
}

var fileName = Uri.UnescapeDataString(resolved.Uri.AbsolutePath);
if (!File.Exists(fileName))
{
ExceptionHelper.ThrowArgumentException("Module Not Found: ", resolved.Specifier);
ExceptionHelper.ThrowModuleResolutionException("Module Not Found", resolved.Specifier, parent: null, fileName);
return default;
}

Expand Down
16 changes: 9 additions & 7 deletions Jint/Runtime/Modules/ModuleResolutionException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ namespace Jint.Runtime.Modules;

public sealed class ModuleResolutionException : JintException
{
public string ResolverAlgorithmError { get; }
public string Specifier { get; }

public ModuleResolutionException(string message, string specifier, string? parent)
: base($"{message} in module '{parent ?? "(null)"}': '{specifier}'")
public ModuleResolutionException(string resolverAlgorithmError, string specifier, string? parent, string? filePath)
: base($"{resolverAlgorithmError} in module '{parent ?? "(null)"}': '{specifier}'")
{
ResolverAlgorithmError = message;
ResolverAlgorithmError = resolverAlgorithmError;
Specifier = specifier;
FilePath = filePath;
}
}

public string ResolverAlgorithmError { get; }
public string Specifier { get; }
public string? FilePath { get; }
}

0 comments on commit 473ca00

Please sign in to comment.