<commit_before>/**
 * Copyright 2014 Netflix, Inc.
 *
 * 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 rx.schedulers;

import io.reactivex.Scheduler;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InOrder;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

/**
 * Executes work on the JavaFx UI thread.
 * This scheduler should only be used with actions that execute quickly.
 */
public final class JavaFxSchedulerTest {

    @Rule
    public ExpectedException exception = ExpectedException.none();

    private static void waitForEmptyEventQueue() throws Exception {
        FXUtilities.runAndWait(() -> {
            // nothing to do, we're just waiting here for the event queue to be emptied
        });
    }

    public static class AsNonApp extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            // noop
        }
    }

    @BeforeClass
    public static void initJFX() {
        //use panel to initialize JavaFX thread
        JFXPanel panel = new JFXPanel();
    }

    @Test
    public void testPeriodicScheduling() throws Exception {
        final JavaFxScheduler scheduler = new JavaFxScheduler();
        final Scheduler.Worker inner = scheduler.createWorker();

        final CountDownLatch latch = new CountDownLatch(4);

        final Runnable innerAction = mock(Runnable.class);
        final Runnable action = () -> {
            try {
                innerAction.run();
                assertTrue(Platform.isFxApplicationThread());
            } finally {
                latch.countDown();
            }
        };

        inner.schedulePeriodically(action, 100, 400, TimeUnit.MILLISECONDS);

        if (!latch.await(5, TimeUnit.SECONDS)) {
            fail("timed out waiting for tasks to execute");
        }

        inner.dispose();
        waitForEmptyEventQueue();
        verify(innerAction, times(4)).run();
    }


	@Test
	public void testNestedActions() throws Exception {
		final JavaFxScheduler scheduler = new JavaFxScheduler();
		final Scheduler.Worker inner = scheduler.createWorker();

		final Runnable actionAStepStart = mock(Runnable.class);
		final Runnable actionAStepEnd = mock(Runnable.class);

		final Runnable actionBStepStart = mock(Runnable.class);
		final Runnable actionBStepEnd = mock(Runnable.class);

		final Runnable actionCStepStart = mock(Runnable.class);
		final Runnable actionCStepEnd = mock(Runnable.class);

		final Runnable actionDStepStart = mock(Runnable.class);
		final Runnable actionDStepEnd = mock(Runnable.class);

		final Runnable actionEStepStart = mock(Runnable.class);
		final Runnable actionEStepEnd = mock(Runnable.class);

		final Runnable actionCAction = () -> {
			assertTrue(Platform.isFxApplicationThread());
			actionCStepStart.run();
			actionCStepEnd.run();
		};
		final Runnable actionDAction = () -> {
			assertTrue(Platform.isFxApplicationThread());
			actionDStepStart.run();
			actionDStepEnd.run();
		};
		final Runnable actionBAction = () -> {
			assertTrue(Platform.isFxApplicationThread());
			actionBStepStart.run();
			inner.schedule(actionCAction);
			inner.schedule(actionDAction);
			actionBStepEnd.run();
		};
		final Runnable actionAAction = () -> {
			assertTrue(Platform.isFxApplicationThread());
			actionAStepStart.run();
			inner.schedule(actionBAction);
			actionAStepEnd.run();
		};

		final Runnable actionEAction = () -> {
			assertTrue(Platform.isFxApplicationThread());
			actionEStepStart.run();
			actionEStepEnd.run();
		};

		InOrder inOrder = inOrder(actionAStepStart, actionAStepEnd, actionBStepStart, actionBStepEnd, actionCStepStart, actionCStepEnd, actionDStepStart, actionDStepEnd, actionEStepStart, actionEStepEnd);

		inner.schedule(actionAAction);
		inner.schedule(actionEAction);
		waitForEmptyEventQueue();

		inOrder.verify(actionAStepStart, times(1)).run();
		inOrder.verify(actionAStepEnd, times(1)).run();
		inOrder.verify(actionEStepStart, times(1)).run();
		inOrder.verify(actionEStepEnd, times(1)).run();
		inOrder.verify(actionBStepStart, times(1)).run();
		inOrder.verify(actionBStepEnd, times(1)).run();
		inOrder.verify(actionCStepStart, times(1)).run();
		inOrder.verify(actionCStepEnd, times(1)).run();
		inOrder.verify(actionDStepStart, times(1)).run();
		inOrder.verify(actionDStepEnd, times(1)).run();
	}

    /*
     * based on http://www.guigarage.com/2013/01/invokeandwait-for-javafx/
     * by hendrikebbers
     */
    static public class FXUtilities {

        /**<commit_msg>extended test case for JavaFxScheduler to test for immediate invocation of nested actions even in the presence of asynchronous schedule requests test rework for readability<commit_after>/**
 * Copyright 2014 Netflix, Inc.
 *
 * 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 rx.schedulers;

import io.reactivex.Scheduler;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InOrder;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

/**
 * Executes work on the JavaFx UI thread.
 * This scheduler should only be used with actions that execute quickly.
 */
public final class JavaFxSchedulerTest {

    @Rule
    public ExpectedException exception = ExpectedException.none();

    private static void waitForEmptyEventQueue() throws Exception {
        FXUtilities.runAndWait(() -> {
            // nothing to do, we're just waiting here for the event queue to be emptied
        });
    }

    public static class AsNonApp extends Application {
        @Override
        public void start(Stage primaryStage) throws Exception {
            // noop
        }
    }

    @BeforeClass
    public static void initJFX() {
        //use panel to initialize JavaFX thread
        JFXPanel panel = new JFXPanel();
    }

    @Test
    public void testPeriodicScheduling() throws Exception {
        final JavaFxScheduler scheduler = new JavaFxScheduler();
        final Scheduler.Worker inner = scheduler.createWorker();

        final CountDownLatch latch = new CountDownLatch(4);

        final Runnable innerAction = mock(Runnable.class);
        final Runnable action = () -> {
            try {
                innerAction.run();
                assertTrue(Platform.isFxApplicationThread());
            } finally {
                latch.countDown();
            }
        };

        inner.schedulePeriodically(action, 100, 400, TimeUnit.MILLISECONDS);

        if (!latch.await(5, TimeUnit.SECONDS)) {
            fail("timed out waiting for tasks to execute");
        }

        inner.dispose();
        waitForEmptyEventQueue();
        verify(innerAction, times(4)).run();
    }

	@Test
	public void testNestedActions() throws Exception {
		final JavaFxScheduler scheduler = new JavaFxScheduler();
		final Scheduler.Worker inner = scheduler.createWorker();

		final CountDownLatch startAsync = new CountDownLatch(1);
		final CountDownLatch asyncStarted = new CountDownLatch(1);
		final AtomicBoolean directInvocation = new AtomicBoolean(false);

		TestAction a1n1 = TestAction.of("A1N1", () -> assertTrue(directInvocation.get()));
		TestAction a1n2 = TestAction.of("A1N2", () -> assertTrue(directInvocation.get()));
		TestAction a1n = TestAction.of("A1N", () -> {
			assertTrue(directInvocation.get());
			inner.schedule(a1n1);
			inner.schedule(a1n2);
		});
		TestAction a2n1 = TestAction.of("A2N1", () -> assertTrue(directInvocation.get()));
		TestAction a2n2 = TestAction.of("A2N2", () -> assertTrue(directInvocation.get()));
		TestAction a2n = TestAction.of("A2N", () -> {
			assertTrue(directInvocation.get());
			inner.schedule(a2n1);
			inner.schedule(a2n2);
		});
		TestAction a = TestAction.of("A", () -> {
			directInvocation.set(true);
			Platform.runLater(() -> directInvocation.set(false));

			inner.schedule(a1n);
			startAsync.countDown();
			try {
				asyncStarted.await(1, TimeUnit.SECONDS);
			} catch (Exception e) {
				fail();
			}
			inner.schedule(a2n);
		});
		TestAction b = TestAction.of("B", () -> {});
		TestAction async = TestAction.of("ASYNC", () -> {});

		inner.schedule(a);
		inner.schedule(b);

		startAsync.await();
		inner.schedule(async);
		asyncStarted.countDown();

		waitForEmptyEventQueue();

		TestAction.verifyOrder(a, b, a1n, async, a2n, a1n1, a1n2, a2n1, a2n2);
	}

	static class TestAction implements Runnable {
		private final Runnable userRunnable;
		private final Runnable start;
		private final Runnable end;

		public static TestAction of(String name, Runnable runnable) {
			return new TestAction(name, runnable);
		}

		private TestAction(String name, Runnable userRunnable) {
			this.userRunnable = userRunnable;
			this.start = mock(Runnable.class, name + "-Start");
			this.end = mock(Runnable.class, name + "-End");
		}

		@Override
		public void run() {
			assertTrue(Platform.isFxApplicationThread());
			start.run();
			userRunnable.run();
			end.run();
		}

		public static void verifyOrder(TestAction... actions) {
			Runnable[] runnables = new Runnable[actions.length * 2];
			for (int i = 0; i < actions.length; i++) {
				TestAction action = actions[i];
				runnables[2 * i] = action.start;
				runnables[2 * i + 1] = action.end;
			}
			InOrder inOrder = inOrder((Object[]) runnables);
			for (Runnable runnable : runnables) {
				inOrder.verify(runnable).run();
			}
		}
	}

    /*
     * based on http://www.guigarage.com/2013/01/invokeandwait-for-javafx/
     * by hendrikebbers
     */
    static public class FXUtilities {

        /**
{'fraction_non_alphanumeric': 0.11132370847103844, 'fraction_numerical': 0.009045051313271874, 'mean_word_length': 3.5612852042840144, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2008726', 'n_tokens_mistral': 3696, 'n_tokens_neox': 3390, 'n_words': 849}