Skip to content

Commit

Permalink
Fixes #60 - Adds native module for managing JavaScript timers.
Browse files Browse the repository at this point in the history
  • Loading branch information
rozele committed May 25, 2016
1 parent 6ed3986 commit 58c65bc
Show file tree
Hide file tree
Showing 10 changed files with 820 additions and 5 deletions.
2 changes: 1 addition & 1 deletion ReactNative.Tests/Internal/MockCatalystInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public T GetNativeModule<T>() where T : INativeModule
throw new NotImplementedException();
}

public T GetJavaScriptModule<T>() where T : IJavaScriptModule
public virtual T GetJavaScriptModule<T>() where T : IJavaScriptModule
{
throw new NotImplementedException();
}
Expand Down
28 changes: 28 additions & 0 deletions ReactNative.Tests/Modules/Core/JSTimersExecutionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using ReactNative.Modules.Core;

namespace ReactNative.Tests.Modules.Core
{
[TestClass]
public class JSTimersExecutionTests
{
public void JSTimersExecution_Invoke()
{
var module = new JSTimersExecution();

var name = default(string);
var args = default(object[]);
module.InvocationHandler = new MockInvocationHandler((n, a) =>
{
name = n;
args = a;
});

var ids = new[] { 42 };
module.callTimers(ids);
Assert.AreEqual(nameof(JSTimersExecution.callTimers), name);
Assert.AreEqual(1, args.Length);
Assert.AreSame(ids, args[0]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public void RCTDeviceEventEmitter_Invoke()
Assert.AreEqual(2, args.Length);
Assert.AreSame(eventName, args[0]);
Assert.AreSame(data, args[1]);

}
}
}
217 changes: 217 additions & 0 deletions ReactNative.Tests/Modules/Core/TimingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using ReactNative.Bridge;
using ReactNative.Modules.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ReactNative.Tests.Modules.Core
{
[TestClass]
public class TimingTests
{
[TestMethod]
public void Timing_Create()
{
var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

timing.createTimer(42, 100, DateTimeOffset.Now.ToUnixTimeMilliseconds(), false);

Assert.IsTrue(waitHandle.WaitOne(1000));
Assert.IsTrue(new[] { 42 }.SequenceEqual(ids));

timing.OnDestroy();
}

[TestMethod]
public void Timing_ManyTimers()
{
var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var count = 1000;
for (var i = 0; i < count; ++i)
{
timing.createTimer(i, i, now, false);
}

while (true)
{
Assert.IsTrue(waitHandle.WaitOne(2000));
if (ids.Count == count)
{
break;
}
}

timing.OnDestroy();
}

[TestMethod]
public void Timing_Create_Delete()
{
var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

var id = 42;
var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
timing.createTimer(id, 500, now, false);
timing.deleteTimer(id);
Assert.IsFalse(waitHandle.WaitOne(1000));

timing.OnDestroy();
}

[TestMethod]
public void Timing_Suspend_Resume()
{
var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

var id = 42;
var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
timing.createTimer(id, 500, now, false);
timing.OnSuspend();
Assert.IsFalse(waitHandle.WaitOne(1000));
timing.OnResume();
Assert.IsTrue(waitHandle.WaitOne(1000));
timing.OnDestroy();
}

[TestMethod]
public void Timing_Repeat()
{
var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

var id = 42;
var repeat = 3;
var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
timing.createTimer(id, 500, now, true);
for (var i = 0; i < repeat; ++i)
{
Assert.IsTrue(waitHandle.WaitOne(1000));
}

timing.deleteTimer(id);
Assert.IsFalse(waitHandle.WaitOne(1000));

timing.OnDestroy();
}

[TestMethod]
public async Task Timing_ManOrBoy()
{
var r = new Random();
var batchCount = 10;
var maxDuration = 1000;
var maxBatch = 5000;
var id = 0;

var ids = new List<int>();
var waitHandle = new AutoResetEvent(false);
var timing = CreateModule(new MockInvocationHandler((name, args) =>
{
Assert.AreEqual(name, nameof(JSTimersExecution.callTimers));
ids.AddRange((IList<int>)args[0]);
waitHandle.Set();
}));

for (var i = 0; i < batchCount; ++i)
{
var batchSize = r.Next(maxBatch);
for (var j = 0; j < batchSize; ++j)
{
var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var duration = r.Next(maxDuration);
timing.createTimer(id++, duration, now, false);
}

await Task.Delay(maxDuration / 4);
}

while (true)
{
Assert.IsTrue(waitHandle.WaitOne(maxDuration * 2));
ids.Sort();
if (ids.Count == id)
{
break;
}
}

timing.OnDestroy();
}

private static Timing CreateModule(IInvocationHandler handler)
{
var context = new ReactContext();
var jsTimers = new JSTimersExecution();

var waitHandle = new AutoResetEvent(false);
var ids = new List<int>();
jsTimers.InvocationHandler = handler;

var catalystInstance = new TestCatalystInstance(jsTimers);
context.InitializeWithInstance(catalystInstance);
var timing = new Timing(context);
timing.Initialize();
return timing;
}

class TestCatalystInstance : MockCatalystInstance
{
private readonly object _jsTimers;

public TestCatalystInstance(JSTimersExecution jsTimers)
: base()
{
_jsTimers = jsTimers;
}

public override T GetJavaScriptModule<T>()
{
if (typeof(JSTimersExecution) == typeof(T))
{
return (T)_jsTimers;
}

return base.GetJavaScriptModule<T>();
}
}
}
}
2 changes: 2 additions & 0 deletions ReactNative.Tests/ReactNative.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@
<Compile Include="Internal\MockJavaScriptExecutor.cs" />
<Compile Include="Internal\MockEvent.cs" />
<Compile Include="Modules\AppState\AppStateModuleTests.cs" />
<Compile Include="Modules\Core\JSTimersExecutionTests.cs" />
<Compile Include="Modules\Core\RCTDeviceEventEmitterTests.cs" />
<Compile Include="Modules\Core\RCTNativeAppEventEmitterTests.cs" />
<Compile Include="Modules\Core\TimingTests.cs" />
<Compile Include="Modules\Toast\ToastNotificationTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReactInstanceManagerTests.cs" />
Expand Down
Loading

0 comments on commit 58c65bc

Please sign in to comment.