/* * Copyright 2012 Jason Miller * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jj.script; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; import jj.execution.DelayedExecutor.CancelKey; import jj.execution.MockTaskRunner; import jj.resource.Location; import jj.resource.ResourceIdentifier; import jj.script.module.RootScriptEnvironment; import jj.util.Closer; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.mozilla.javascript.Callable; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import java.io.IOException; /** * @author jason * */ @RunWith(MockitoJUnitRunner.class) public class TimersTest { public static class RootEnvironment extends AbstractScriptEnvironment<Void> implements RootScriptEnvironment<Void> { public RootEnvironment(Dependencies dependencies) { super(dependencies); } @Override public boolean needsReplacing() throws IOException { return false; } @Override public Scriptable scope() { return null; } @Override public Script script() { return null; } @Override public String scriptName() { return null; } @Override public String sha1() { return null; } @Override public ScriptableObject global() { return null; } @Override public Location moduleLocation() { return null; } } public static class ChildEnvironment extends AbstractScriptEnvironment<Void> implements ChildScriptEnvironment<Void> { public ChildEnvironment(Dependencies dependencies) { super(dependencies); } @Override public boolean needsReplacing() throws IOException { return false; } @Override public ScriptEnvironment<?> parent() { return null; } @Override public Scriptable scope() { return null; } @Override public Script script() { return null; } @Override public String scriptName() { return null; } @Override public String sha1() { return null; } } MockTaskRunner taskRunner; MockRhinoContextProvider contextProvider; Timers timers; @Mock Callable callable; @Mock ScriptableObject scope; @Mock ChildEnvironment child; @Mock ResourceIdentifier<ChildEnvironment, Void> childIdentifier; @Mock RootEnvironment root; @Mock ResourceIdentifier<RootEnvironment, Void> rootIdentifier; CurrentScriptEnvironment env; @Mock CancelKey cancelKey; @Mock PendingKey pendingKey; @SuppressWarnings("unchecked") private void prepIdentifiers() { given((ResourceIdentifier<RootEnvironment, Void>)root.identifier()).willReturn(rootIdentifier); given((ResourceIdentifier<ChildEnvironment, Void>) child.identifier()).willReturn(childIdentifier); } @Before public void before() { taskRunner = new MockTaskRunner(); taskRunner.cancelKey = cancelKey; willReturn(root).given(((ChildScriptEnvironment<?>) child)).parent(); env = new CurrentScriptEnvironment(contextProvider); given(child.execute(any(Callable.class), anyVararg())).willReturn(pendingKey); prepIdentifiers(); timers = new Timers(taskRunner, env); } @Test public void testEnvironmentDied() { try (Closer closer = env.enterScope(root)) { timers.setInterval.call(null, scope, null, new Object[]{ callable, "2" }); } ScriptEnvironmentDied event = new ScriptEnvironmentDied(root); timers.on(event); verify(cancelKey).cancel(); } String cancelId; @Test public void testSetIntervalFromRoot() throws Throwable { testRun(interval1, 2L, true, 3L); testRun(interval2, 0L, true); } @Test public void testSetTimeoutFromRoot() throws Throwable { testRun(timeout1, 600L, false, "hi", "there"); testRun(timeout2, 0L, false); } @Test public void testCancelSetInterval() throws Throwable { try (Closer closer = env.enterScope(child)) { interval1.run(); } try (Closer closer = env.enterScope(root)) { timers.clearInterval.call(null, scope, null, new Object[] { cancelId }); } verify(cancelKey).cancel(); } @Test public void testCancelSetTimeout() throws Throwable { try (Closer closer = env.enterScope(child)) { timeout1.run(); } try (Closer closer = env.enterScope(root)) { timers.clearTimeout.call(null, scope, null, new Object[] { cancelId }); } verify(cancelKey).cancel(); } private Runnable interval1 = new Runnable() { @Override public void run() { cancelId = (String)timers.setInterval.call(null, scope, null, new Object[]{ callable, "2", 3L }); } }; private Runnable interval2 = new Runnable() { @Override public void run() { cancelId = (String)timers.setInterval.call(null, scope, null, new Object[]{ callable }); } }; private Runnable timeout1 = new Runnable() { @Override public void run() { cancelId = (String)timers.setTimeout.call(null, scope, null, new Object[]{ callable, 600, "hi", "there" }); } }; private Runnable timeout2 = new Runnable() { @Override public void run() { cancelId = (String)timers.setTimeout.call(null, scope, null, new Object[]{ callable }); } }; private void testRun(Runnable r, long delay, boolean repeat, Object...args) throws Throwable { try (Closer closer = env.enterScope(child)) { r.run(); } assertThat(taskRunner.firstTaskDelay(), is(delay)); ScriptTask<?> task = (ScriptTask<?>)taskRunner.runFirstTask(); // verify we're doing this! cause i forgot lol assertThat(task.pendingKey, is(pendingKey)); task.complete(); assertThat(taskRunner.taskWillRepeat(task), is(repeat)); verify(child).execute(callable, args); } }