1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3.concurrent;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNull;
21
22 import java.util.concurrent.atomic.AtomicBoolean;
23 import java.util.concurrent.atomic.AtomicInteger;
24
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27
28 /**
29 * Test class for {@code AtomicSafeInitializer} which also serves as a simple example.
30 */
31 public class AtomicSafeInitializerTest extends AbstractConcurrentInitializerTest {
32
33 /**
34 * A concrete test implementation of {@code AtomicSafeInitializer} which also serves as a simple example.
35 * <p>
36 * This implementation also counts the number of invocations of the initialize() method.
37 * </p>
38 */
39 private static final class AtomicSafeInitializerTestImpl extends AtomicSafeInitializer<Object> {
40 /** A counter for initialize() invocations. */
41 final AtomicInteger initCounter = new AtomicInteger();
42
43 @Override
44 protected Object initialize() {
45 initCounter.incrementAndGet();
46 return new Object();
47 }
48 }
49
50 /** The instance to be tested. */
51 private AtomicSafeInitializerTestImpl initializer;
52
53 /**
54 * Returns the initializer to be tested.
55 *
56 * @return the {@code AtomicSafeInitializer} under test
57 */
58 @Override
59 protected ConcurrentInitializer<Object> createInitializer() {
60 return initializer;
61 }
62
63 @BeforeEach
64 public void setUp() {
65 initializer = new AtomicSafeInitializerTestImpl();
66 }
67
68 @Test
69 public void testGetThatReturnsNullFirstTime() throws ConcurrentException {
70 final AtomicSafeInitializer<Object> initializer = new AtomicSafeInitializer<Object>() {
71 final AtomicBoolean firstRun = new AtomicBoolean(true);
72
73 @Override
74 protected Object initialize() {
75 if (firstRun.getAndSet(false)) {
76 return null;
77 } else {
78 return new Object();
79 }
80 }
81 };
82
83 assertNull(initializer.get());
84 assertNull(initializer.get());
85 }
86
87 /**
88 * Tests that initialize() is called only once.
89 *
90 * @throws org.apache.commons.lang3.concurrent.ConcurrentException because {@link #testGetConcurrent()} may throw it
91 * @throws InterruptedException because {@link #testGetConcurrent()} may throw it
92 */
93 @Test
94 public void testNumberOfInitializeInvocations() throws ConcurrentException, InterruptedException {
95 testGetConcurrent();
96 assertEquals(1, initializer.initCounter.get(), "Wrong number of invocations");
97 }
98 }