Skip to content

Added a ability to select the default JavaScript engine #413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/React.Core/Exceptions/ReactEngineNotFoundException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public class ReactEngineNotFoundException : ReactException
/// </summary>
public ReactEngineNotFoundException() : base(GetMessage()) { }

/// <summary>
/// Initializes a new instance of the <see cref="ReactEngineNotFoundException"/> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ReactEngineNotFoundException(string message) : base(message) { }

#if NET40
/// <summary>
/// Used by deserialization
Expand All @@ -40,8 +46,8 @@ private static string GetMessage()
{
return
"No usable JavaScript engine was found. Please install a JavaScript engine such " +
"as React.JavaScriptEngine.ClearScriptV8 (on Windows) or " +
"React.JavaScriptEngine.VroomJs (on Linux and Mac OS X). Refer to the ReactJS.NET " +
"as JavaScriptEngineSwitcher.V8.V8JsEngine (on Windows) or " +
"React.VroomJsEngine (on Linux and Mac OS X). Refer to the ReactJS.NET " +
"documentation for more details.";
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/React.Core/JavaScriptEngineFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,23 @@ public virtual void ReturnEngineToPool(IJsEngine engine)
private static Func<IJsEngine> GetFactory(JsEngineSwitcher jsEngineSwitcher, bool allowMsie)
{
EnsureJsEnginesRegistered(jsEngineSwitcher, allowMsie);

string defaultEngineName = jsEngineSwitcher.DefaultEngineName;
if (!string.IsNullOrWhiteSpace(defaultEngineName))
{
var engineFactory = jsEngineSwitcher.EngineFactories.Get(defaultEngineName);
if (engineFactory != null)
{
return engineFactory.CreateEngine;
}
else
{
throw new ReactEngineNotFoundException(
"Could not find a factory, that creates an instance of the JavaScript " +
"engine with name `" + defaultEngineName + "`.");
}
}

foreach (var engineFactory in jsEngineSwitcher.EngineFactories)
{
IJsEngine engine = null;
Expand Down
130 changes: 125 additions & 5 deletions tests/React.Tests/Core/JavaScriptEngineFactoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace React.Tests.Core
{
public class JavaScriptEngineFactoryTest
{
private static object _engineSwitcherSynchronizer = new object();


private JavaScriptEngineFactory CreateBasicFactory()
{
var config = new Mock<IReactSiteConfiguration>();
Expand All @@ -44,11 +47,17 @@ Func<IJsEngine> innerEngineFactory
engineFactory.Setup(x => x.CreateEngine()).Returns(innerEngineFactory);

// JsEngineSwitcher is a singleton :(
var engineFactories = JsEngineSwitcher.Instance.EngineFactories;
engineFactories.Clear();
engineFactories.Add(engineFactory.Object);

return new JavaScriptEngineFactory(JsEngineSwitcher.Instance, config.Object, fileSystem.Object);
lock (_engineSwitcherSynchronizer)
{
var engineSwitcher = JsEngineSwitcher.Instance;
engineSwitcher.DefaultEngineName = string.Empty;

var engineFactories = engineSwitcher.EngineFactories;
engineFactories.Clear();
engineFactories.Add(engineFactory.Object);

return new JavaScriptEngineFactory(engineSwitcher, config.Object, fileSystem.Object);
}
}

[Fact]
Expand Down Expand Up @@ -176,5 +185,116 @@ public void ShouldCatchErrorsWhileLoadingScripts()
var ex = Assert.Throws<ReactScriptLoadException>(() => factory.GetEngineForCurrentThread());
Assert.Equal("Error while loading \"foo.js\": Fail\r\nLine: 42\r\nColumn: 911", ex.Message);
}

[Fact]
public void ShouldReturnDefaultEngine()
{
const string someEngineName = "SomeEngine";
const string defaultEngineName = "DefaultEngine";
const string someOtherEngineName = "SomeOtherEngine";

var someEngineFactory = new Mock<IJsEngineFactory>();
someEngineFactory.Setup(x => x.EngineName).Returns(someEngineName);
someEngineFactory.Setup(x => x.CreateEngine()).Returns(() =>
{
var someEngine = new Mock<IJsEngine>();
someEngine.Setup(x => x.Name).Returns(someEngineName);
return someEngine.Object;
});

var defaultEngineFactory = new Mock<IJsEngineFactory>();
defaultEngineFactory.Setup(x => x.EngineName).Returns(defaultEngineName);
defaultEngineFactory.Setup(x => x.CreateEngine()).Returns(() =>
{
var defaultEngine = new Mock<IJsEngine>();
defaultEngine.Setup(x => x.Name).Returns(defaultEngineName);
return defaultEngine.Object;
});

var someOtherEngineFactory = new Mock<IJsEngineFactory>();
someOtherEngineFactory.Setup(x => x.EngineName).Returns(someOtherEngineName);
someOtherEngineFactory.Setup(x => x.CreateEngine()).Returns(() =>
{
var someOtherEngine = new Mock<IJsEngine>();
someOtherEngine.Setup(x => x.Name).Returns(someOtherEngineName);
return someOtherEngine.Object;
});

var config = new Mock<IReactSiteConfiguration>();
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string>());
config.Setup(x => x.LoadReact).Returns(true);

var fileSystem = new Mock<IFileSystem>();

JavaScriptEngineFactory factory;

// JsEngineSwitcher is a singleton :(
lock (_engineSwitcherSynchronizer)
{
var engineSwitcher = JsEngineSwitcher.Instance;
engineSwitcher.DefaultEngineName = defaultEngineName;

var engineFactories = engineSwitcher.EngineFactories;
engineFactories.Clear();
engineFactories.Add(someEngineFactory.Object);
engineFactories.Add(defaultEngineFactory.Object);
engineFactories.Add(someOtherEngineFactory.Object);

factory = new JavaScriptEngineFactory(engineSwitcher, config.Object, fileSystem.Object);
}

var engine = factory.GetEngineForCurrentThread();

Assert.Equal(defaultEngineName, engine.Name);
}

[Fact]
public void ShouldThrowIfDefaultEngineFactoryNotFound()
{
const string someEngineName = "SomeEngine";
const string defaultEngineName = "DefaultEngine";
const string someOtherEngineName = "SomeOtherEngine";

var someEngineFactory = new Mock<IJsEngineFactory>();
someEngineFactory.Setup(x => x.EngineName).Returns(someEngineName);
someEngineFactory.Setup(x => x.CreateEngine()).Returns(() =>
{
var someEngine = new Mock<IJsEngine>();
someEngine.Setup(x => x.Name).Returns(someEngineName);
return someEngine.Object;
});

var someOtherEngineFactory = new Mock<IJsEngineFactory>();
someOtherEngineFactory.Setup(x => x.EngineName).Returns(someOtherEngineName);
someOtherEngineFactory.Setup(x => x.CreateEngine()).Returns(() =>
{
var someOtherEngine = new Mock<IJsEngine>();
someOtherEngine.Setup(x => x.Name).Returns(someOtherEngineName);
return someOtherEngine.Object;
});

var config = new Mock<IReactSiteConfiguration>();
config.Setup(x => x.ScriptsWithoutTransform).Returns(new List<string>());
config.Setup(x => x.LoadReact).Returns(true);

var fileSystem = new Mock<IFileSystem>();

// JsEngineSwitcher is a singleton :(
lock (_engineSwitcherSynchronizer)
{
var engineSwitcher = JsEngineSwitcher.Instance;
engineSwitcher.DefaultEngineName = defaultEngineName;

var engineFactories = engineSwitcher.EngineFactories;
engineFactories.Clear();
engineFactories.Add(someEngineFactory.Object);
engineFactories.Add(someOtherEngineFactory.Object);

Assert.Throws<ReactEngineNotFoundException>(() =>
{
var factory = new JavaScriptEngineFactory(engineSwitcher, config.Object, fileSystem.Object);
});
}
}
}
}