Package com.google.common.util.concurrent

Source Code of com.google.common.util.concurrent.GeneratedMonitorTest$FlagGuard

/*
* Copyright (C) 2014 The Guava Authors
*
* 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 com.google.common.util.concurrent;

import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly;

import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

/**
* Generated tests for {@link Monitor}.
*
* <p>This test class generates all of its own test cases in the {@link #suite()} method. Every
* {@code enterXxx}, {@code tryEnterXxx}, and {@code waitForXxx} method of the {@code Monitor} class
* is analyzed reflectively to determine appropriate test cases based on its signature. Additional
* ad hoc test cases can be found in {@link SupplementalMonitorTest}.
*
* @author Justin T. Sampson
*/

public class GeneratedMonitorTest extends TestCase {

  public static TestSuite suite() {
    TestSuite suite = new TestSuite();

    Method[] methods = Monitor.class.getMethods();
    sortMethods(methods);
    for (Method method : methods) {
      if (isAnyEnter(method) || isWaitFor(method)) {
        validateMethod(method);
        addTests(suite, method);
      }
    }

    assertEquals(548, suite.testCount());

    return suite;
  }

  /**
   * A typical timeout value we'll use in the tests.
   */
  private static final long SMALL_TIMEOUT_MILLIS = 10;

  /**
   * How long to wait when determining that a thread is blocked if we expect it to be blocked.
   */
  private static final long EXPECTED_HANG_DELAY_MILLIS = 75;

  /**
   * How long to wait when determining that a thread is blocked if we DON'T expect it to be blocked.
   */
  private static final long UNEXPECTED_HANG_DELAY_MILLIS = 10000;

  /**
   * Various scenarios to be generated for each method under test. The actual scenario generation
   * (determining which scenarios are applicable to which methods and what the outcome should be)
   * takes place in {@link #addTests(TestSuite, Method)}.
   */
  private enum Scenario {

    SATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING,
    UNSATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING,
    SATISFIED_AND_OCCUPIED_BEFORE_ENTERING,
    SATISFIED_UNOCCUPIED_AND_INTERRUPTED_BEFORE_ENTERING,

    SATISFIED_BEFORE_WAITING,
    SATISFIED_WHILE_WAITING,
    SATISFIED_AND_INTERRUPTED_BEFORE_WAITING,
    UNSATISFIED_BEFORE_AND_WHILE_WAITING,
    UNSATISFIED_AND_INTERRUPTED_BEFORE_WAITING;

    @Override
    public String toString() {
      return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
    }

  }

  /**
   * Timeout values to combine with each {@link Scenario}.
   */
  private enum Timeout {

    MIN(Long.MIN_VALUE, "-oo"),
    MINUS_SMALL(-SMALL_TIMEOUT_MILLIS, "-" + SMALL_TIMEOUT_MILLIS + "ms"),
    ZERO(0L, "0ms"),
    SMALL(SMALL_TIMEOUT_MILLIS, SMALL_TIMEOUT_MILLIS + "ms"),
    LARGE(UNEXPECTED_HANG_DELAY_MILLIS * 2, (2 * UNEXPECTED_HANG_DELAY_MILLIS) + "ms"),
    MAX(Long.MAX_VALUE, "+oo");

    final long millis;
    final String label;

    private Timeout(long millis, String label) {
      this.millis = millis;
      this.label = label;
    }

    @Override
    public String toString() {
      return label;
    }

  }

  /**
   * Convenient subsets of the {@link Timeout} enumeration for specifying scenario outcomes.
   */
  private enum TimeoutsToUse {

    ANY(Timeout.values()),
    PAST(Timeout.MIN, Timeout.MINUS_SMALL, Timeout.ZERO),
    FUTURE(Timeout.SMALL, Timeout.MAX),
    SMALL(Timeout.SMALL),
    FINITE(Timeout.MIN, Timeout.MINUS_SMALL, Timeout.ZERO, Timeout.SMALL),
    INFINITE(Timeout.LARGE, Timeout.MAX);

    final ImmutableList<Timeout> timeouts;

    private TimeoutsToUse(Timeout... timeouts) {
      this.timeouts = ImmutableList.copyOf(timeouts);
    }

  }

  /**
   * Possible outcomes of calling any of the methods under test.
   */
  private enum Outcome {

    /**
     * The method returned normally and is either void or returned true.
     */
    SUCCESS,

    /**
     * The method returned false.
     */
    FAILURE,

    /**
     * The method threw an InterruptedException.
     */
    INTERRUPT,

    /**
     * The method did not return or throw anything.
     */
    HANG;

    @Override
    public String toString() {
      return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
    }

  }

  /**
   * Identifies all enterXxx and tryEnterXxx methods.
   */
  private static boolean isAnyEnter(Method method) {
    return method.getName().startsWith("enter") || method.getName().startsWith("tryEnter");
  }

  /**
   * Identifies just tryEnterXxx methods (a subset of {@link #isAnyEnter}), which never block.
   */
  private static boolean isTryEnter(Method method) {
    return method.getName().startsWith("tryEnter");
  }

  /**
   * Identifies just enterIfXxx methods (a subset of {@link #isAnyEnter}), which are mostly like the
   * enterXxx methods but behave like tryEnterXxx in some scenarios.
   */
  private static boolean isEnterIf(Method method) {
    return method.getName().startsWith("enterIf");
  }

  /**
   * Identifies all waitForXxx methods, which must be called while occupying the monitor.
   */
  private static boolean isWaitFor(Method method) {
    return method.getName().startsWith("waitFor");
  }

  /**
   * Determines whether the given method takes a Guard as its first parameter.
   */
  private static boolean isGuarded(Method method) {
    Class<?>[] parameterTypes = method.getParameterTypes();
    return parameterTypes.length >= 1 && parameterTypes[0] == Monitor.Guard.class;
  }

  /**
   * Determines whether the given method takes a time and unit as its last two parameters.
   */
  private static boolean isTimed(Method method) {
    Class<?>[] parameterTypes = method.getParameterTypes();
    return parameterTypes.length >= 2
        && parameterTypes[parameterTypes.length - 2] == long.class
        && parameterTypes[parameterTypes.length - 1] == TimeUnit.class;
  }

  /**
   * Determines whether the given method returns a boolean value.
   */
  private static boolean isBoolean(Method method) {
    return method.getReturnType() == boolean.class;
  }

  /**
   * Determines whether the given method can throw InterruptedException.
   */
  private static boolean isInterruptible(Method method) {
    return Arrays.asList(method.getExceptionTypes()).contains(InterruptedException.class);
  }

  /**
   * Sorts the given methods primarily by name and secondarily by number of parameters.
   */
  private static void sortMethods(Method[] methods) {
    Arrays.sort(methods, new Comparator<Method>() {
      @Override public int compare(Method m1, Method m2) {
        int nameComparison = m1.getName().compareTo(m2.getName());
        if (nameComparison != 0) {
          return nameComparison;
        } else {
          return Ints.compare(m1.getParameterTypes().length, m2.getParameterTypes().length);
        }
      }
    });
  }

  /**
   * Validates that the given method's signature meets all of our assumptions.
   */
  private static void validateMethod(Method method) {
    String desc = method.toString();

    assertTrue(desc, isAnyEnter(method) || isWaitFor(method));

    switch (method.getParameterTypes().length) {
      case 0:
        assertFalse(desc, isGuarded(method));
        assertFalse(desc, isTimed(method));
        break;
      case 1:
        assertTrue(desc, isGuarded(method));
        assertFalse(desc, isTimed(method));
        break;
      case 2:
        assertFalse(desc, isGuarded(method));
        assertTrue(desc, isTimed(method));
        break;
      case 3:
        assertTrue(desc, isGuarded(method));
        assertTrue(desc, isTimed(method));
        break;
      default:
        fail(desc);
    }

    if (method.getReturnType() == void.class) {
      assertFalse(desc, isBoolean(method));
    } else {
      assertTrue(desc, isBoolean(method));
    }

    switch (method.getExceptionTypes().length) {
      case 0:
        assertFalse(desc, isInterruptible(method));
        break;
      case 1:
        assertTrue(desc, isInterruptible(method));
        break;
      default:
        fail(desc);
    }

    if (isEnterIf(method)) {
      assertTrue(desc, isGuarded(method));
      assertTrue(desc, isBoolean(method));
    } else if (isTryEnter(method)) {
      assertFalse(desc, isTimed(method));
      assertTrue(desc, isBoolean(method));
      assertFalse(desc, isInterruptible(method));
    } else if (isWaitFor(method)) {
      assertTrue(desc, isGuarded(method));
      assertEquals(desc, isTimed(method), isBoolean(method));
    } else { // any other enterXxx method
      assertEquals(desc, isTimed(method), isBoolean(method));
    }
  }

  /**
   * Generates all test cases appropriate for the given method.
   */
  private static void addTests(TestSuite suite, Method method) {
    if (isGuarded(method)) {
      for (boolean fair1 : new boolean[] { true, false }) {
        for (boolean fair2 : new boolean[] { true, false }) {
          suite.addTest(generateGuardWithWrongMonitorTestCase(method, fair1, fair2));
        }
      }
    }
    if (isAnyEnter(method)) {
      addTests(suite, method,
          Scenario.SATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING,
          TimeoutsToUse.ANY,
          Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.UNSATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING,
          TimeoutsToUse.FINITE,
          isGuarded(method)
              ? (isBoolean(method) ? Outcome.FAILURE : Outcome.HANG)
              : Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.UNSATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING,
          TimeoutsToUse.INFINITE,
          isGuarded(method)
              ? (isTryEnter(method) || isEnterIf(method) ? Outcome.FAILURE : Outcome.HANG)
              : Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.SATISFIED_AND_OCCUPIED_BEFORE_ENTERING,
          TimeoutsToUse.FINITE,
          isBoolean(method) ? Outcome.FAILURE : Outcome.HANG);
      addTests(suite, method,
          Scenario.SATISFIED_AND_OCCUPIED_BEFORE_ENTERING,
          TimeoutsToUse.INFINITE,
          isGuarded(method)
              ? Outcome.HANG
              : (isTryEnter(method) ? Outcome.FAILURE : Outcome.HANG));
      addTests(suite, method,
          Scenario.SATISFIED_UNOCCUPIED_AND_INTERRUPTED_BEFORE_ENTERING,
          TimeoutsToUse.ANY,
          isInterruptible(method) ? Outcome.INTERRUPT : Outcome.SUCCESS);
    } else { // any waitForXxx method
      suite.addTest(generateWaitForWhenNotOccupyingTestCase(method, true));
      suite.addTest(generateWaitForWhenNotOccupyingTestCase(method, false));
      addTests(suite, method,
          Scenario.SATISFIED_BEFORE_WAITING,
          TimeoutsToUse.ANY,
          Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.SATISFIED_WHILE_WAITING,
          TimeoutsToUse.INFINITE,
          Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.SATISFIED_WHILE_WAITING,
          TimeoutsToUse.PAST,
          Outcome.FAILURE);
      addTests(suite, method,
          Scenario.SATISFIED_AND_INTERRUPTED_BEFORE_WAITING,
          TimeoutsToUse.ANY,
          Outcome.SUCCESS);
      addTests(suite, method,
          Scenario.UNSATISFIED_BEFORE_AND_WHILE_WAITING,
          TimeoutsToUse.FINITE,
          Outcome.FAILURE);
      addTests(suite, method,
          Scenario.UNSATISFIED_BEFORE_AND_WHILE_WAITING,
          TimeoutsToUse.INFINITE,
          Outcome.HANG);
      addTests(suite, method,
          Scenario.UNSATISFIED_AND_INTERRUPTED_BEFORE_WAITING,
          TimeoutsToUse.PAST,
          // prefer responding to interrupt over timing out
          isInterruptible(method) ? Outcome.INTERRUPT : Outcome.FAILURE);
      addTests(suite, method,
          Scenario.UNSATISFIED_AND_INTERRUPTED_BEFORE_WAITING,
          TimeoutsToUse.SMALL,
          isInterruptible(method) ? Outcome.INTERRUPT : Outcome.FAILURE);
      addTests(suite, method,
          Scenario.UNSATISFIED_AND_INTERRUPTED_BEFORE_WAITING,
          TimeoutsToUse.INFINITE,
          isInterruptible(method) ? Outcome.INTERRUPT : Outcome.HANG);
    }
  }

  /**
   * Generates test cases for the given combination of scenario and timeouts. For methods that take
   * an explicit timeout value, all of the given timeoutsToUse result in individual test cases. For
   * methods that do not take an explicit timeout value, a single test case is generated only if the
   * implicit timeout of that method matches the given timeoutsToUse. For example, enter() is
   * treated like enter(MAX, MILLIS) and tryEnter() is treated like enter(0, MILLIS).
   */
  private static void addTests(TestSuite suite, Method method, Scenario scenario,
      TimeoutsToUse timeoutsToUse, Outcome expectedOutcome) {
    for (boolean fair : new boolean[] { true, false }) {
      if (isTimed(method)) {
        for (Timeout timeout : timeoutsToUse.timeouts) {
          suite.addTest(new GeneratedMonitorTest(method, scenario, fair, timeout, expectedOutcome));
        }
      } else {
        Timeout implicitTimeout = (isTryEnter(method) ? Timeout.ZERO : Timeout.MAX);
        if (timeoutsToUse.timeouts.contains(implicitTimeout)) {
          suite.addTest(new GeneratedMonitorTest(method, scenario, fair, null, expectedOutcome));
        }
      }
    }
  }

  /**
   * A guard that encapsulates a simple, mutable boolean flag.
   */
  static class FlagGuard extends Monitor.Guard {

    private boolean satisfied;

    protected FlagGuard(Monitor monitor) {
      super(monitor);
    }

    @Override
    public boolean isSatisfied() {
      return satisfied;
    }

    public void setSatisfied(boolean satisfied) {
      this.satisfied = satisfied;
    }

  }

  private final Method method;
  private final Scenario scenario;
  private final Timeout timeout;
  private final Outcome expectedOutcome;
  private final Monitor monitor;
  private final FlagGuard guard;
  private final CountDownLatch tearDownLatch;
  private final CountDownLatch doingCallLatch;
  private final CountDownLatch callCompletedLatch;

  private GeneratedMonitorTest(
      Method method, Scenario scenario, boolean fair, Timeout timeout, Outcome expectedOutcome) {
    super(nameFor(method, scenario, fair, timeout, expectedOutcome));
    this.method = method;
    this.scenario = scenario;
    this.timeout = timeout;
    this.expectedOutcome = expectedOutcome;
    this.monitor = new Monitor(fair);
    this.guard = new FlagGuard(monitor);
    this.tearDownLatch = new CountDownLatch(1);
    this.doingCallLatch = new CountDownLatch(1);
    this.callCompletedLatch = new CountDownLatch(1);
  }

  private static String nameFor(
      Method method, Scenario scenario, boolean fair, Timeout timeout, Outcome expectedOutcome) {
    return String.format("%s%s(%s)/%s->%s",
                         method.getName(),
                         fair ? "(fair)" : "(nonfair)",
                         (timeout == null) ? "untimed" : timeout,
                         scenario,
                         expectedOutcome);
  }

  @Override
  protected void runTest() throws Throwable {
    final Runnable runChosenTest = new Runnable() {
      @Override public void run() { runChosenTest(); }
    };
    final FutureTask<Void> task = new FutureTask<Void>(runChosenTest, null);
    startThread(new Runnable() {
        @Override public void run() { task.run(); }
      });
    awaitUninterruptibly(doingCallLatch);
    long hangDelayMillis = (expectedOutcome == Outcome.HANG)
        ? EXPECTED_HANG_DELAY_MILLIS
        : UNEXPECTED_HANG_DELAY_MILLIS;
    boolean hung = !awaitUninterruptibly(
        callCompletedLatch, hangDelayMillis, TimeUnit.MILLISECONDS);
    if (hung) {
      assertEquals(expectedOutcome, Outcome.HANG);
    } else {
      assertNull(task.get(UNEXPECTED_HANG_DELAY_MILLIS, TimeUnit.MILLISECONDS));
    }
  }

  @Override
  protected void tearDown() throws Exception {
    // We don't want to leave stray threads running after each test. At this point, every thread
    // launched by this test is either:
    //
    // (a) Blocked attempting to enter the monitor.
    // (b) Waiting for the single guard to become satisfied.
    // (c) Occupying the monitor and awaiting the tearDownLatch.
    //
    // Except for (c), every thread should occupy the monitor very briefly, and every thread leaves
    // the monitor with the guard satisfied. Therefore as soon as tearDownLatch is triggered, we
    // should be able to enter the monitor, and then we set the guard to satisfied for the benefit
    // of any remaining waiting threads.

    tearDownLatch.countDown();
    assertTrue("Monitor still occupied in tearDown()",
        monitor.enter(UNEXPECTED_HANG_DELAY_MILLIS, TimeUnit.MILLISECONDS));
    try {
      guard.setSatisfied(true);
    } finally {
      monitor.leave();
    }
  }

  private void runChosenTest() {
    if (isAnyEnter(method)) {
      runEnterTest();
    } else {
      runWaitTest();
    }
  }

  private void runEnterTest() {
    assertFalse(Thread.currentThread().isInterrupted());
    assertFalse(monitor.isOccupiedByCurrentThread());

    doEnterScenarioSetUp();

    boolean interruptedBeforeCall = Thread.currentThread().isInterrupted();
    Outcome actualOutcome = doCall();
    boolean occupiedAfterCall = monitor.isOccupiedByCurrentThread();
    boolean interruptedAfterCall = Thread.currentThread().isInterrupted();

    if (occupiedAfterCall) {
      guard.setSatisfied(true);
      monitor.leave();
      assertFalse(monitor.isOccupiedByCurrentThread());
    }

    assertEquals(expectedOutcome, actualOutcome);
    assertEquals(expectedOutcome == Outcome.SUCCESS, occupiedAfterCall);
    assertEquals(interruptedBeforeCall && expectedOutcome != Outcome.INTERRUPT,
        interruptedAfterCall);
  }

  private void doEnterScenarioSetUp() {
    switch (scenario) {
      case SATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING:
        enterSatisfyGuardAndLeaveInCurrentThread();
        break;
      case UNSATISFIED_AND_UNOCCUPIED_BEFORE_ENTERING:
        break;
      case SATISFIED_AND_OCCUPIED_BEFORE_ENTERING:
        enterSatisfyGuardAndLeaveInCurrentThread();
        enterAndRemainOccupyingInAnotherThread();
        break;
      case SATISFIED_UNOCCUPIED_AND_INTERRUPTED_BEFORE_ENTERING:
        enterSatisfyGuardAndLeaveInCurrentThread();
        Thread.currentThread().interrupt();
        break;
      default:
        throw new AssertionError("unsupported scenario: " + scenario);
    }
  }

  private void runWaitTest() {
    assertFalse(Thread.currentThread().isInterrupted());
    assertFalse(monitor.isOccupiedByCurrentThread());
    monitor.enter();
    try {
      assertTrue(monitor.isOccupiedByCurrentThread());

      doWaitScenarioSetUp();

      boolean interruptedBeforeCall = Thread.currentThread().isInterrupted();
      Outcome actualOutcome = doCall();
      boolean occupiedAfterCall = monitor.isOccupiedByCurrentThread();
      boolean interruptedAfterCall = Thread.currentThread().isInterrupted();

      assertEquals(expectedOutcome, actualOutcome);
      assertTrue(occupiedAfterCall);
      assertEquals(interruptedBeforeCall && expectedOutcome != Outcome.INTERRUPT,
          interruptedAfterCall);
    } finally {
      guard.setSatisfied(true);
      monitor.leave();
      assertFalse(monitor.isOccupiedByCurrentThread());
    }
  }

  private void doWaitScenarioSetUp() {
    switch (scenario) {
      case SATISFIED_BEFORE_WAITING:
        guard.setSatisfied(true);
        break;
      case SATISFIED_WHILE_WAITING:
        guard.setSatisfied(false);
        enterSatisfyGuardAndLeaveInAnotherThread(); // enter blocks until we call waitFor
        break;
      case UNSATISFIED_BEFORE_AND_WHILE_WAITING:
        guard.setSatisfied(false);
        break;
      case SATISFIED_AND_INTERRUPTED_BEFORE_WAITING:
        guard.setSatisfied(true);
        Thread.currentThread().interrupt();
        break;
      case UNSATISFIED_AND_INTERRUPTED_BEFORE_WAITING:
        guard.setSatisfied(false);
        Thread.currentThread().interrupt();
        break;
      default:
        throw new AssertionError("unsupported scenario: " + scenario);
    }
  }

  private Outcome doCall() {
    boolean guarded = isGuarded(method);
    boolean timed = isTimed(method);
    Object[] arguments = new Object[(guarded ? 1 : 0) + (timed ? 2 : 0)];
    if (guarded) {
      arguments[0] = guard;
    }
    if (timed) {
      arguments[arguments.length - 2] = timeout.millis;
      arguments[arguments.length - 1] = TimeUnit.MILLISECONDS;
    }
    try {
      Object result;
      doingCallLatch.countDown();
      try {
        result = method.invoke(monitor, arguments);
      } finally {
        callCompletedLatch.countDown();
      }
      if (result == null) {
        return Outcome.SUCCESS;
      } else if ((Boolean) result) {
        return Outcome.SUCCESS;
      } else {
        return Outcome.FAILURE;
      }
    } catch (InvocationTargetException targetException) {
      Throwable actualException = targetException.getTargetException();
      if (actualException instanceof InterruptedException) {
        return Outcome.INTERRUPT;
      } else {
        throw new AssertionError("unexpected exception", targetException);
      }
    } catch (IllegalAccessException e) {
      throw new AssertionError("unexpected exception", e);
    }
  }

  private void enterSatisfyGuardAndLeaveInCurrentThread() {
    monitor.enter();
    try {
      guard.setSatisfied(true);
    } finally {
      monitor.leave();
    }
  }

  private void enterSatisfyGuardAndLeaveInAnotherThread() {
    final CountDownLatch startedLatch = new CountDownLatch(1);
    startThread(new Runnable() {
      @Override public void run() {
        startedLatch.countDown();
        enterSatisfyGuardAndLeaveInCurrentThread();
      }
    });
    awaitUninterruptibly(startedLatch);
  }

  private void enterAndRemainOccupyingInAnotherThread() {
    final CountDownLatch enteredLatch = new CountDownLatch(1);
    startThread(new Runnable() {
      @Override public void run() {
        monitor.enter();
        try {
          enteredLatch.countDown();
          awaitUninterruptibly(tearDownLatch);
          guard.setSatisfied(true);
        } finally {
          monitor.leave();
        }
      }
    });
    awaitUninterruptibly(enteredLatch);
  }

  static Thread startThread(Runnable runnable) {
    Thread thread = new Thread(runnable);
    thread.setDaemon(true);
    thread.start();
    return thread;
  }

  /**
   * Generates a test case verifying that calling any enterXxx, tryEnterXxx, or waitForXxx method
   * with a guard that doesn't match the monitor produces an IllegalMonitorStateException.
   */
  private static TestCase generateGuardWithWrongMonitorTestCase(final Method method,
                                                                final boolean fair1,
                                                                final boolean fair2) {
    final boolean timed = isTimed(method); // Not going to bother with all timeouts, just 0ms.
    return new TestCase(method.getName() + (timed ? "(0ms)" : "()") + "/WrongMonitor->IMSE") {
      @Override protected void runTest() throws Throwable {
        Monitor monitor1 = new Monitor(fair1);
        Monitor monitor2 = new Monitor(fair2);
        FlagGuard guard = new FlagGuard(monitor2);
        Object[] arguments =
            (timed ? new Object[] {guard, 0L, TimeUnit.MILLISECONDS} : new Object[] {guard});
        boolean occupyMonitor = isWaitFor(method);
        if (occupyMonitor) {
          // If we don't already occupy the monitor, we'll get an IMSE regardless of the guard (see
          // generateWaitForWhenNotOccupyingTestCase).
          monitor1.enter();
        }
        try {
          method.invoke(monitor1, arguments);
          fail("expected IllegalMonitorStateException");
        } catch (InvocationTargetException e) {
          assertEquals(IllegalMonitorStateException.class, e.getTargetException().getClass());
        } finally {
          if (occupyMonitor) {
            monitor1.leave();
          }
        }
      }
    };
  }

  /**
   * Generates a test case verifying that calling any waitForXxx method when not occupying the
   * monitor produces an IllegalMonitorStateException.
   */
  private static TestCase generateWaitForWhenNotOccupyingTestCase(final Method method,
                                                                  final boolean fair) {
    final boolean timed = isTimed(method); // Not going to bother with all timeouts, just 0ms.
    String testName = method.getName()
        + (fair ? "(fair)" : "(nonfair)")
        + (timed ? "(0ms)" : "()")
        + "/NotOccupying->IMSE";
    return new TestCase(testName) {
      @Override protected void runTest() throws Throwable {
        Monitor monitor = new Monitor(fair);
        FlagGuard guard = new FlagGuard(monitor);
        Object[] arguments =
            (timed ? new Object[] {guard, 0L, TimeUnit.MILLISECONDS} : new Object[] {guard});
        try {
          method.invoke(monitor, arguments);
          fail("expected IllegalMonitorStateException");
        } catch (InvocationTargetException e) {
          assertEquals(IllegalMonitorStateException.class, e.getTargetException().getClass());
        }
      }
    };
  }

}
TOP

Related Classes of com.google.common.util.concurrent.GeneratedMonitorTest$FlagGuard

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.