|
Java example source code file (GeneratedMonitorTest.java)
The GeneratedMonitorTest.java Java example source code/* * 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 com.google.errorprone.annotations.CanIgnoreReturnValue; 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.Locale; 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(Locale.ROOT, "%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 Other Java examples (source code examples)Here is a short list of links related to this Java GeneratedMonitorTest.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.