Skip to content

Commit

Permalink
Added a ability to select the default JavaScript engine (#413)
Browse files Browse the repository at this point in the history
* Added a ability to select the default JavaScript engine

* Added a unit tests
  • Loading branch information
Taritsyn authored and Daniel15 committed Jul 2, 2017
1 parent 5168caa commit e1809a0
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 7 deletions.
10 changes: 8 additions & 2 deletions src/React.Core/Exceptions/ReactEngineNotFoundException.cs
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
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
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);
});
}
}
}
}

0 comments on commit e1809a0

Please sign in to comment.