diff options
author | gjoranv <gv@verizonmedia.com> | 2022-07-13 11:38:09 +0200 |
---|---|---|
committer | gjoranv <gv@verizonmedia.com> | 2022-07-13 11:39:09 +0200 |
commit | 3ad0117c5ec96bb3d32495a222409df074cfd7d9 (patch) | |
tree | 3f2d0024cbf719b8cd38365016e1dd49754b5a48 /vespajlib/src/test | |
parent | 0781a0b3ce6b7433f442d3a1bc3097272971f0ba (diff) |
Move yolean code into vespajlib.
Diffstat (limited to 'vespajlib/src/test')
7 files changed, 704 insertions, 0 deletions
diff --git a/vespajlib/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java b/vespajlib/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java new file mode 100644 index 00000000000..53cf3efe363 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java @@ -0,0 +1,81 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean; + +import org.junit.Test; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.NoSuchFileException; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +/** + * @author bratseth + */ +public class ExceptionsTestCase { + + @Test + public void testFindCause() { + IllegalArgumentException e1 = new IllegalArgumentException(); + IllegalStateException e2 = new IllegalStateException(e1); + RuntimeException e3 = new RuntimeException(e2); + + assertEquals(Optional.of(e3), Exceptions.findCause(e3, RuntimeException.class)); + assertEquals(Optional.of(e1), Exceptions.findCause(e3, IllegalArgumentException.class)); + assertEquals(Optional.empty(), Exceptions.findCause(e3, NumberFormatException.class)); + + assertEquals(Optional.of(e2), Exceptions.findCause(e2, RuntimeException.class)); + } + + @Test + public void testToMessageStrings() { + assertEquals("Blah",Exceptions.toMessageString(new Exception("Blah"))); + assertEquals("Blah", Exceptions.toMessageString(new Exception(new Exception("Blah")))); + assertEquals("Exception",Exceptions.toMessageString(new Exception())); + assertEquals("Foo: Blah",Exceptions.toMessageString(new Exception("Foo",new Exception(new IllegalArgumentException("Blah"))))); + assertEquals("Foo",Exceptions.toMessageString(new Exception("Foo",new Exception("Foo")))); + assertEquals("Foo: Exception",Exceptions.toMessageString(new Exception("Foo",new Exception()))); + assertEquals("Foo",Exceptions.toMessageString(new Exception(new Exception("Foo")))); + } + + @Test + public void testUnchecks() { + try { + Exceptions.uncheck(this::throwNoSuchFileException); + } catch (UncheckedIOException e) { + assertEquals("filename", e.getCause().getMessage()); + } + + try { + Exceptions.uncheck(this::throwNoSuchFileException, "additional %s", "info"); + } catch (UncheckedIOException e) { + assertEquals("additional info", e.getMessage()); + } + + try { + int i = Exceptions.uncheck(this::throwNoSuchFileExceptionSupplier); + } catch (UncheckedIOException e) { + assertEquals("filename", e.getCause().getMessage()); + } + + try { + int i = Exceptions.uncheck(this::throwNoSuchFileExceptionSupplier, "additional %s", "info"); + } catch (UncheckedIOException e) { + assertEquals("additional info", e.getMessage()); + } + + Exceptions.uncheckAndIgnore(this::throwNoSuchFileException, NoSuchFileException.class); + assertNull(Exceptions.uncheckAndIgnore(this::throwNoSuchFileExceptionSupplier, NoSuchFileException.class)); + } + + private void throwNoSuchFileException() throws IOException { + throw new NoSuchFileException("filename"); + } + + private int throwNoSuchFileExceptionSupplier() throws IOException { + throw new NoSuchFileException("filename"); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java new file mode 100644 index 00000000000..3f2526172a9 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java @@ -0,0 +1,106 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.concurrent; + +import org.junit.Test; + +import java.util.Iterator; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * @author baldersheim + * @since 5.2 + */ +public class CopyOnWriteHashMapTest { + + @Test + public void requireThatAccessorsWork() { + Map<String, String> map = new CopyOnWriteHashMap<>(); + assertEquals(0, map.size()); + assertEquals(true, map.isEmpty()); + assertEquals(false, map.containsKey("fooKey")); + assertEquals(false, map.containsValue("fooVal")); + assertNull(map.get("fooKey")); + assertNull(map.remove("fooKey")); + assertEquals(0, map.keySet().size()); + assertEquals(0, map.entrySet().size()); + assertEquals(0, map.values().size()); + + map.put("fooKey", "fooVal"); + assertEquals(1, map.size()); + assertEquals(false, map.isEmpty()); + assertEquals(true, map.containsKey("fooKey")); + assertEquals(true, map.containsValue("fooVal")); + assertEquals("fooVal", map.get("fooKey")); + assertEquals(1, map.keySet().size()); + assertEquals(1, map.entrySet().size()); + assertEquals(1, map.values().size()); + + map.put("barKey", "barVal"); + assertEquals(2, map.size()); + assertEquals(false, map.isEmpty()); + assertEquals(true, map.containsKey("fooKey")); + assertEquals(true, map.containsKey("barKey")); + assertEquals(true, map.containsValue("fooVal")); + assertEquals(true, map.containsValue("barVal")); + assertEquals("fooVal", map.get("fooKey")); + assertEquals("barVal", map.get("barKey")); + assertEquals(2, map.keySet().size()); + assertEquals(2, map.entrySet().size()); + assertEquals(2, map.values().size()); + + assertEquals("fooVal", map.remove("fooKey")); + assertEquals(1, map.size()); + assertEquals(false, map.isEmpty()); + assertEquals(false, map.containsKey("fooKey")); + assertEquals(true, map.containsKey("barKey")); + assertEquals(false, map.containsValue("fooVal")); + assertEquals(true, map.containsValue("barVal")); + assertNull(map.get("fooKey")); + assertEquals("barVal", map.get("barKey")); + assertEquals(1, map.keySet().size()); + assertEquals(1, map.entrySet().size()); + assertEquals(1, map.values().size()); + } + + @Test + public void requireThatEntrySetDoesNotReflectConcurrentModifications() { + Map<String, String> map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); + assertEquals("fooVal", map.remove("fooKey")); + + assertTrue(it.hasNext()); + Map.Entry<String, String> entry = it.next(); + assertEquals("fooKey", entry.getKey()); + assertEquals("fooVal", entry.getValue()); + } + + @Test + public void requireThatKeySetDoesNotReflectConcurrentModifications() { + Map<String, String> map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator<String> it = map.keySet().iterator(); + assertEquals("fooVal", map.remove("fooKey")); + + assertTrue(it.hasNext()); + assertEquals("fooKey", it.next()); + } + + @Test + public void requireThatValuesDoNotReflectConcurrentModifications() { + Map<String, String> map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator<String> it = map.values().iterator(); + assertEquals("fooVal", map.remove("fooKey")); + + assertTrue(it.hasNext()); + assertEquals("fooVal", it.next()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/concurrent/MemoizedTest.java b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/MemoizedTest.java new file mode 100644 index 00000000000..7f2f49c75f2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/MemoizedTest.java @@ -0,0 +1,101 @@ +package com.yahoo.yolean.concurrent; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +/** + * @author jonmv + */ +public class MemoizedTest { + + final Phaser phaser = new Phaser(); + final int threads = 128; + + @Test + public void test() throws ExecutionException, InterruptedException { + var lazy = new Memoized<>(new OnceSupplier(), OnceCloseable::close); + phaser.register(); // test thread + phaser.register(); // whoever calls the factory + + Phaser latch = new Phaser(threads + 1); + ExecutorService executor = Executors.newFixedThreadPool(threads); + List<Future<?>> futures = new ArrayList<>(); + for (int i = 0; i < 128; i++) { + futures.add(executor.submit(() -> { + latch.arriveAndAwaitAdvance(); + lazy.get().rendezvous(); + while (true) lazy.get(); + })); + } + + // All threads waiting for latch, will race to factory + latch.arriveAndAwaitAdvance(); + + // One thread waiting in factory, the others are blocked, will go to rendezvous + phaser.arriveAndAwaitAdvance(); + + // All threads waiting in rendezvous, will repeatedly get until failure + phaser.arriveAndAwaitAdvance(); + + // Unsynchronized close should be detected by all threads + lazy.close(); + + // Close should carry through only once + lazy.close(); + + assertEquals("already closed", + assertThrows(IllegalStateException.class, lazy::get).getMessage()); + + for (Future<?> future : futures) + assertEquals("java.lang.IllegalStateException: already closed", + assertThrows(ExecutionException.class, future::get).getMessage()); + + executor.shutdown(); + } + + @Test + public void closeBeforeFirstGet() throws Exception { + OnceSupplier supplier = new OnceSupplier(); + Memoized<OnceCloseable, ?> lazy = Memoized.of(supplier); + lazy.close(); + assertEquals("already closed", + assertThrows(IllegalStateException.class, lazy::get).getMessage()); + lazy.close(); + assertFalse(supplier.initialized.get()); + } + + class OnceSupplier implements Supplier<OnceCloseable> { + final AtomicBoolean initialized = new AtomicBoolean(); + @Override public OnceCloseable get() { + phaser.arriveAndAwaitAdvance(); + if ( ! initialized.compareAndSet(false, true)) fail("initialized more than once"); + phaser.bulkRegister(threads - 1); // register all the threads who didn't get the factory + return new OnceCloseable(); + } + } + + class OnceCloseable implements AutoCloseable { + final AtomicBoolean closed = new AtomicBoolean(); + @Override public void close() { + if ( ! closed.compareAndSet(false, true)) fail("closed more than once"); + } + void rendezvous() { + phaser.arriveAndAwaitAdvance(); + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java new file mode 100644 index 00000000000..c2edaf1fb00 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java @@ -0,0 +1,146 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.concurrent; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> + */ +public class ThreadRobustListTestCase { + + private final static int NUM_THREADS = 64; + private final static int NUM_ITEMS_TO_WRITE = 1000000; + private final static int NUM_TIMES_TO_READ = 10; + + @Test + public void requireThatListIsThreadRobust() throws Exception { + final CountDownLatch latch = new CountDownLatch(NUM_THREADS); + final ThreadRobustList<Integer> sharedList = new ThreadRobustList<>(); + + List<Callable<Boolean>> tasks = new ArrayList<>(NUM_THREADS); + tasks.add(new WriterTask(latch, sharedList)); + for (int i = 1; i < NUM_THREADS; ++i) { + tasks.add(new ReaderTask(latch, sharedList)); + } + for (Future<Boolean> result : Executors.newFixedThreadPool(NUM_THREADS).invokeAll(tasks)) { + assertTrue(result.get(60, TimeUnit.SECONDS)); + } + } + + @Test + public void requireThatAccessorsWork() { + ThreadRobustList<Object> lst = new ThreadRobustList<>(); + assertTrue(lst.isEmpty()); + assertFalse(lst.iterator().hasNext()); + + Object foo = new Object(); + lst.add(foo); + assertFalse(lst.isEmpty()); + Iterator<Object> it = lst.iterator(); + assertNotNull(it); + assertTrue(it.hasNext()); + assertSame(foo, it.next()); + assertFalse(it.hasNext()); + + Object bar = new Object(); + lst.add(bar); + assertFalse(lst.isEmpty()); + assertNotNull(it = lst.iterator()); + assertTrue(it.hasNext()); + assertSame(foo, it.next()); + assertTrue(it.hasNext()); + assertSame(bar, it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void requireThatIteratorNextThrowsNoSuchElementExceptionWhenDone() { + ThreadRobustList<Object> lst = new ThreadRobustList<>(); + Iterator<Object> it = lst.iterator(); + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + + } + } + + @Test + public void requireThatIteratorRemoveIsNotSupported() { + ThreadRobustList<Object> lst = new ThreadRobustList<>(); + Object obj = new Object(); + lst.add(obj); + Iterator<Object> it = lst.iterator(); + assertTrue(it.hasNext()); + assertSame(obj, it.next()); + try { + it.remove(); + fail(); + } catch (UnsupportedOperationException e) { + + } + } + + private static class WriterTask implements Callable<Boolean> { + + final CountDownLatch latch; + final ThreadRobustList<Integer> sharedList; + + WriterTask(CountDownLatch latch, ThreadRobustList<Integer> sharedList) { + this.latch = latch; + this.sharedList = sharedList; + } + + @Override + public Boolean call() throws Exception { + latch.countDown(); + assertTrue(latch.await(60, TimeUnit.SECONDS)); + for (int i = 0; i < NUM_ITEMS_TO_WRITE; ++i) { + sharedList.add(i); + } + return true; + } + } + + private static class ReaderTask implements Callable<Boolean> { + + final CountDownLatch latch; + final ThreadRobustList<Integer> sharedList; + + ReaderTask(CountDownLatch latch, ThreadRobustList<Integer> sharedList) { + this.latch = latch; + this.sharedList = sharedList; + } + + @Override + public Boolean call() throws Exception { + latch.countDown(); + assertTrue(latch.await(60, TimeUnit.SECONDS)); + for (int i = 0; i < NUM_TIMES_TO_READ; ++i) { + Iterator<Integer> it = sharedList.iterator(); + for (int j = 0; it.hasNext(); ++j) { + assertEquals(j, it.next().intValue()); + } + } + return true; + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/system/CatchSignalsTestCase.java b/vespajlib/src/test/java/com/yahoo/yolean/system/CatchSignalsTestCase.java new file mode 100644 index 00000000000..66a27235088 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/system/CatchSignalsTestCase.java @@ -0,0 +1,18 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.system; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author arnej27959 + */ +public class CatchSignalsTestCase { + + @Test + public void testThatSetupCompiles() { + CatchSignals.setup(new AtomicBoolean(false)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java b/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java new file mode 100644 index 00000000000..3019b646867 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java @@ -0,0 +1,231 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.trace; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @author bratseth + */ +public class TraceNodeTestCase { + + @Test + public void requireThatAccessorsWork() { + TraceNode node = new TraceNode(null, 6); + assertNull(node.payload()); + assertEquals(6, node.timestamp()); + assertFalse(node.children().iterator().hasNext()); + assertFalse(node.descendants(Object.class).iterator().hasNext()); + assertTrue(node.isRoot()); + assertNull(node.parent()); + assertSame(node, node.root()); + } + + @Test + public void requireThatToStringIsReadable() { + TraceNode trace = new TraceNode(null, 0) + .add(new TraceNode("a", 1)) + .add(new TraceNode("b", 2) + .add(new TraceNode("c", 3))); + assertEquals("[ [ a b [ c ] ] ]", trace.toString()); + } + + @Test + public void requireThatPayloadMayBeNull() { + TraceNode node = new TraceNode(null, 6); + assertNull(node.payload()); + } + + @Test + public void requireThatRootNodesCanBeAdded() { + TraceNode parent = new TraceNode(null, 1); + + TraceNode foo = new TraceNode(null, 2); + parent.add(foo); + assertSame(parent, foo.parent()); + + TraceNode bar = new TraceNode(null, 3); + parent.add(bar); + assertSame(parent, bar.parent()); + + Iterator<TraceNode> children = parent.children().iterator(); + assertTrue(children.hasNext()); + assertSame(foo, children.next()); + assertTrue(children.hasNext()); + assertSame(bar, children.next()); + assertFalse(children.hasNext()); + + Iterator<Object> payloads = parent.descendants(Object.class).iterator(); + assertFalse(payloads.hasNext()); + } + + @Test + public void requireThatNonRootNodeCanNotBeAdded() { + TraceNode foo = new TraceNode(null, 0); + TraceNode bar = new TraceNode(null, 0); + TraceNode baz = new TraceNode(null, 0); + bar.add(baz); + try { + foo.add(baz); + fail(); + } catch (IllegalArgumentException e) { + + } + assertSame(bar, baz.parent()); + assertTrue(bar.children().iterator().hasNext()); + assertFalse(foo.children().iterator().hasNext()); + } + + @Test + public void requireThatChildrenIsNeverNull() { + assertNotNull(new TraceNode(null, 69).children()); + } + + @Test + public void requireThatDescendantsIsNeverNull() { + assertNotNull(new TraceNode(null, 69).descendants(Object.class)); + } + + @Test + public void requireThatDescendantsOrderIsDepthFirstPrefix() { + TraceNode trace = new TraceNode(null, 0) + .add(new TraceNode("a", 0) + .add(new TraceNode("b", 0)) + .add(new TraceNode("c", 0) + .add(new TraceNode("d", 0)) + .add(new TraceNode("e", 0)))) + .add(new TraceNode("f", 0) + .add(new TraceNode("g", 0))); + + Iterator<String> it = trace.descendants(String.class).iterator(); + assertTrue(it.hasNext()); + assertEquals("a", it.next()); + assertTrue(it.hasNext()); + assertEquals("b", it.next()); + assertTrue(it.hasNext()); + assertEquals("c", it.next()); + assertTrue(it.hasNext()); + assertEquals("d", it.next()); + assertTrue(it.hasNext()); + assertEquals("e", it.next()); + assertTrue(it.hasNext()); + assertEquals("f", it.next()); + assertTrue(it.hasNext()); + assertEquals("g", it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void requireThatDescendantsFilterPayloads() { + TraceNode trace = new TraceNode(null, 0) + .add(new TraceNode("a", 0) + .add(new TraceNode(69, 0)) + .add(new TraceNode("b", 0) + .add(new TraceNode("c", 0)) + .add(new TraceNode(new Object(), 0)))) + .add(new TraceNode("d", 0) + .add(new TraceNode("e", 0))); + + Iterator<String> it = trace.descendants(String.class).iterator(); + assertTrue(it.hasNext()); + assertEquals("a", it.next()); + assertTrue(it.hasNext()); + assertEquals("b", it.next()); + assertTrue(it.hasNext()); + assertEquals("c", it.next()); + assertTrue(it.hasNext()); + assertEquals("d", it.next()); + assertTrue(it.hasNext()); + assertEquals("e", it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void requireThatVisitorOrderIsDepthFirstPrefix() { + TraceNode trace = new TraceNode(null, 0) + .add(new TraceNode("a", 0) + .add(new TraceNode("b", 0)) + .add(new TraceNode("c", 0) + .add(new TraceNode("d", 0)) + .add(new TraceNode(3, 0)))) + .add(new TraceNode("f", 0) + .add(new TraceNode("g", 0))); + + final List<Object> payloads = new ArrayList<>(); + trace.accept(new TraceVisitor() { + + @Override + public void visit(TraceNode node) { + payloads.add(node.payload()); + } + }); + assertEquals(Arrays.<Object>asList(null, "a", "b", "c", "d", 3, "f", "g"), + payloads); + } + + @Test + public void requireThatVisitorDoesNotEnterOrLeaveNodesThatHaveNoChildren() { + TraceNode trace = new TraceNode(null, 0); + trace.accept(new TraceVisitor() { + + @Override + public void visit(TraceNode node) { + + } + + @Override + public void entering(TraceNode node) { + fail(); + } + + @Override + public void leaving(TraceNode node) { + fail(); + } + }); + } + + @Test + public void requireThatVisitorEntersAndLeavesNodesThatHaveChildren() { + TraceNode trace = new TraceNode("", 0) + .add(new TraceNode("a", 0) + .add(new TraceNode("b", 0)) + .add(new TraceNode("c", 0) + .add(new TraceNode("d", 0)) + .add(new TraceNode("e", 0)))) + .add(new TraceNode("f", 0) + .add(new TraceNode("g", 0))); + + final StringBuilder out = new StringBuilder(); + trace.accept(new TraceVisitor() { + + @Override + public void visit(TraceNode node) { + out.append(node.payload()); + } + + @Override + public void entering(TraceNode node) { + out.append("["); + } + + @Override + public void leaving(TraceNode node) { + out.append("]"); + } + }); + assertEquals("[a[bc[de]]f[g]]", out.toString()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java b/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java new file mode 100644 index 00000000000..4eaa5b0241e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java @@ -0,0 +1,21 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.trace; + +import org.junit.Test; + +/** + * @author Simon Thoresen Hult + */ +public class TraceVisitorTestCase { + + @Test + public void requireThatTraceVisitorCompilesWithOnlyVisitImplemented() { + new TraceNode(null, 0).accept(new TraceVisitor() { + + @Override + public void visit(TraceNode node) { + + } + }); + } +} |