1 /*
2  * Copyright (C) 2014 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static com.google.common.util.concurrent.GeneratedMonitorTest.startThread;
20 import static com.google.common.util.concurrent.Uninterruptibles.joinUninterruptibly;
21 
22 import com.google.common.util.concurrent.GeneratedMonitorTest.FlagGuard;
23 import java.util.concurrent.atomic.AtomicBoolean;
24 import java.util.concurrent.atomic.AtomicInteger;
25 import java.util.concurrent.atomic.AtomicReference;
26 import junit.framework.TestCase;
27 
28 /**
29  * Supplemental tests for {@link Monitor}.
30  *
31  * <p>This test class contains various test cases that don't fit into the test case generation in
32  * {@link GeneratedMonitorTest}.
33  *
34  * @author Justin T. Sampson
35  */
36 
37 public class SupplementalMonitorTest extends TestCase {
38 
testLeaveWithoutEnterThrowsIMSE()39   public void testLeaveWithoutEnterThrowsIMSE() {
40     Monitor monitor = new Monitor();
41     try {
42       monitor.leave();
43       fail("expected IllegalMonitorStateException");
44     } catch (IllegalMonitorStateException expected) {
45     }
46   }
47 
testGetWaitQueueLengthWithWrongMonitorThrowsIMSE()48   public void testGetWaitQueueLengthWithWrongMonitorThrowsIMSE() {
49     Monitor monitor1 = new Monitor();
50     Monitor monitor2 = new Monitor();
51     FlagGuard guard = new FlagGuard(monitor2);
52     try {
53       monitor1.getWaitQueueLength(guard);
54       fail("expected IllegalMonitorStateException");
55     } catch (IllegalMonitorStateException expected) {
56     }
57   }
58 
testHasWaitersWithWrongMonitorThrowsIMSE()59   public void testHasWaitersWithWrongMonitorThrowsIMSE() {
60     Monitor monitor1 = new Monitor();
61     Monitor monitor2 = new Monitor();
62     FlagGuard guard = new FlagGuard(monitor2);
63     try {
64       monitor1.hasWaiters(guard);
65       fail("expected IllegalMonitorStateException");
66     } catch (IllegalMonitorStateException expected) {
67     }
68   }
69 
testNullMonitorInGuardConstructorThrowsNPE()70   public void testNullMonitorInGuardConstructorThrowsNPE() {
71     try {
72       new FlagGuard(null);
73       fail("expected NullPointerException");
74     } catch (NullPointerException expected) {
75     }
76   }
77 
testIsFair()78   public void testIsFair() {
79     assertTrue(new Monitor(true).isFair());
80     assertFalse(new Monitor(false).isFair());
81   }
82 
testOccupiedMethods()83   public void testOccupiedMethods() {
84     Monitor monitor = new Monitor();
85     verifyOccupiedMethodsInCurrentThread(monitor, false, false, 0);
86     verifyOccupiedMethodsInAnotherThread(monitor, false, false, 0);
87     monitor.enter();
88     try {
89       verifyOccupiedMethodsInCurrentThread(monitor, true, true, 1);
90       verifyOccupiedMethodsInAnotherThread(monitor, true, false, 0);
91       monitor.enter();
92       try {
93         verifyOccupiedMethodsInCurrentThread(monitor, true, true, 2);
94         verifyOccupiedMethodsInAnotherThread(monitor, true, false, 0);
95       } finally {
96         monitor.leave();
97       }
98       verifyOccupiedMethodsInCurrentThread(monitor, true, true, 1);
99       verifyOccupiedMethodsInAnotherThread(monitor, true, false, 0);
100     } finally {
101       monitor.leave();
102     }
103     verifyOccupiedMethodsInCurrentThread(monitor, false, false, 0);
104     verifyOccupiedMethodsInAnotherThread(monitor, false, false, 0);
105   }
106 
verifyOccupiedMethodsInCurrentThread( Monitor monitor, boolean expectedIsOccupied, boolean expectedIsOccupiedByCurrentThread, int expectedOccupiedDepth)107   private static void verifyOccupiedMethodsInCurrentThread(
108       Monitor monitor,
109       boolean expectedIsOccupied,
110       boolean expectedIsOccupiedByCurrentThread,
111       int expectedOccupiedDepth) {
112     assertEquals(expectedIsOccupied, monitor.isOccupied());
113     assertEquals(expectedIsOccupiedByCurrentThread, monitor.isOccupiedByCurrentThread());
114     assertEquals(expectedOccupiedDepth, monitor.getOccupiedDepth());
115   }
116 
verifyOccupiedMethodsInAnotherThread( final Monitor monitor, boolean expectedIsOccupied, boolean expectedIsOccupiedByCurrentThread, int expectedOccupiedDepth)117   private static void verifyOccupiedMethodsInAnotherThread(
118       final Monitor monitor,
119       boolean expectedIsOccupied,
120       boolean expectedIsOccupiedByCurrentThread,
121       int expectedOccupiedDepth) {
122     final AtomicBoolean actualIsOccupied = new AtomicBoolean();
123     final AtomicBoolean actualIsOccupiedByCurrentThread = new AtomicBoolean();
124     final AtomicInteger actualOccupiedDepth = new AtomicInteger();
125     final AtomicReference<Throwable> thrown = new AtomicReference<>();
126     joinUninterruptibly(
127         startThread(
128             new Runnable() {
129               @Override
130               public void run() {
131                 try {
132                   actualIsOccupied.set(monitor.isOccupied());
133                   actualIsOccupiedByCurrentThread.set(monitor.isOccupiedByCurrentThread());
134                   actualOccupiedDepth.set(monitor.getOccupiedDepth());
135                 } catch (Throwable t) {
136                   thrown.set(t);
137                 }
138               }
139             }));
140     assertNull(thrown.get());
141     assertEquals(expectedIsOccupied, actualIsOccupied.get());
142     assertEquals(expectedIsOccupiedByCurrentThread, actualIsOccupiedByCurrentThread.get());
143     assertEquals(expectedOccupiedDepth, actualOccupiedDepth.get());
144   }
145 }
146