content: /**
   * Copyright (c) 2016-present, RxJava Contributors.
   *
   * 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 io.reactivex.common.internal.schedulers;
  
  import static org.junit.Assert.*;
  
  import java.lang.Thread.UncaughtExceptionHandler;
  import java.util.List;
  import java.util.concurrent.FutureTask;
  
  import org.junit.Test;
  
  import io.reactivex.common.*;
  import io.reactivex.common.disposables.CompositeDisposable;
  import io.reactivex.common.exceptions.TestException;
  import io.reactivex.common.internal.functions.Functions;
  
  public class ScheduledRunnableTest {
  
      @Test
      public void dispose() {
          CompositeDisposable set = new CompositeDisposable();
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
          set.add(run);
  
          assertFalse(run.isDisposed());
  
          set.dispose();
  
          assertTrue(run.isDisposed());
      }
  
      @Test
      public void disposeRun() {
          CompositeDisposable set = new CompositeDisposable();
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
          set.add(run);
  
          assertFalse(run.isDisposed());
  
          run.dispose();
          run.dispose();
  
          assertTrue(run.isDisposed());
      }
  
      @Test
      public void setFutureCancelRace() {
          for (int i = 0; i < 500; i++) {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
              set.add(run);
  
              final FutureTask<Object> ft = new FutureTask<Object>(Functions.EMPTY_RUNNABLE, 0);
  
              Runnable r1 = new Runnable() {
                  @Override
                  public void run() {
                      run.setFuture(ft);
                  }
              };
  
              Runnable r2 = new Runnable() {
                  @Override
                  public void run() {
                      run.dispose();
                  }
              };
  
              TestCommonHelper.race(r1, r2);
  
              assertEquals(0, set.size());
          }
      }
  
      @Test
      public void setFutureRunRace() {
          for (int i = 0; i < 500; i++) {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
              set.add(run);
  
              final FutureTask<Object> ft = new FutureTask<Object>(Functions.EMPTY_RUNNABLE, 0);
  
              Runnable r1 = new Runnable() {
                  @Override
                  public void run() {
                      run.setFuture(ft);
                  }
              };
  
              Runnable r2 = new Runnable() {
                  @Override
                  public void run() {
                      run.run();
                  }
              };
  
              TestCommonHelper.race(r1, r2);
  
              assertEquals(0, set.size());
          }
      }
  
      @Test
      public void disposeRace() {
          for (int i = 0; i < 500; i++) {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
              set.add(run);
  
              Runnable r1 = new Runnable() {
                  @Override
                  public void run() {
                      run.dispose();
                  }
              };
  
              TestCommonHelper.race(r1, r1);
  
              assertEquals(0, set.size());
          }
      }
  
      @Test
      public void runDispose() {
          for (int i = 0; i < 500; i++) {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
              set.add(run);
  
              Runnable r1 = new Runnable() {
                  @Override
                  public void run() {
                      run.call();
                  }
              };
  
              Runnable r2 = new Runnable() {
                  @Override
                  public void run() {
                      run.dispose();
                  }
              };
  
              TestCommonHelper.race(r1, r2);
  
              assertEquals(0, set.size());
          }
      }
  
      @Test
      public void pluginCrash() {
          Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
              @Override
              public void uncaughtException(Thread t, Throwable e) {
                  throw new TestException("Second");
              }
          });
  
          CompositeDisposable set = new CompositeDisposable();
          final ScheduledRunnable run = new ScheduledRunnable(new Runnable() {
              @Override
              public void run() {
                  throw new TestException("First");
              }
          }, set);
          set.add(run);
  
          try {
              run.run();
  
              fail("Should have thrown!");
          } catch (TestException ex) {
              assertEquals("Second", ex.getMessage());
          } finally {
              Thread.currentThread().setUncaughtExceptionHandler(null);
          }
          assertTrue(run.isDisposed());
  
          assertEquals(0, set.size());
      }
  
      @Test
      public void crashReported() {
          List<Throwable> errors = TestCommonHelper.trackPluginErrors();
          try {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(new Runnable() {
                  @Override
                  public void run() {
                      throw new TestException("First");
                  }
              }, set);
              set.add(run);
  
              run.run();
  
              assertTrue(run.isDisposed());
  
              assertEquals(0, set.size());
  
              TestCommonHelper.assertUndeliverable(errors, 0, TestException.class, "First");
          } finally {
              RxJavaCommonPlugins.reset();
          }
      }
  
      @Test
      public void withoutParentDisposed() {
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, null);
          run.dispose();
          run.call();
      }
  
      @Test
      public void withParentDisposed() {
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, new CompositeDisposable());
          run.dispose();
          run.call();
      }
  
      @Test
      public void withFutureDisposed() {
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, null);
          run.setFuture(new FutureTask<Void>(Functions.EMPTY_RUNNABLE, null));
          run.dispose();
          run.call();
      }
  
      @Test
      public void withFutureDisposed2() {
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, null);
          run.dispose();
          run.setFuture(new FutureTask<Void>(Functions.EMPTY_RUNNABLE, null));
          run.call();
      }
  
      @Test
      public void withFutureDisposed3() {
          ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, null);
          run.dispose();
          run.set(2, Thread.currentThread());
          run.setFuture(new FutureTask<Void>(Functions.EMPTY_RUNNABLE, null));
          run.call();
      }
  
      @Test
      public void runFuture() {
          for (int i = 0; i < 500; i++) {
              CompositeDisposable set = new CompositeDisposable();
              final ScheduledRunnable run = new ScheduledRunnable(Functions.EMPTY_RUNNABLE, set);
              set.add(run);
  
              final FutureTask<Void> ft = new FutureTask<Void>(Functions.EMPTY_RUNNABLE, null);
  
              Runnable r1 = new Runnable() {
                  @Override
                  public void run() {
                      run.call();
                  }
              };
  
              Runnable r2 = new Runnable() {
                  @Override
                  public void run() {
                      run.setFuture(ft);
                  }
              };
  
              TestCommonHelper.race(r1, r2);
          }
      }
  }
  