From 72231250ed81e10d66bfe70701e64fa5fe50f712 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 15 Jun 2016 23:09:44 +0200 Subject: Publish --- .../binaryprefix/BinaryScaledAmountTestCase.java | 38 ++ .../test/java/com/yahoo/cache/CacheTestCase.java | 197 ++++++ .../test/java/com/yahoo/cache/CalcTestCase.java | 176 +++++ .../com/yahoo/collections/ArraySetTestCase.java | 303 +++++++++ .../com/yahoo/collections/BobHashTestCase.java | 45 ++ .../collections/ByteArrayComparatorTestCase.java | 38 ++ .../collections/CollectionComparatorTestCase.java | 40 ++ .../com/yahoo/collections/CollectionUtilTest.java | 50 ++ .../yahoo/collections/CollectionsBenchMark.java | 204 ++++++ .../collections/CopyOnWriteHashMapTestCase.java | 64 ++ .../collections/FreezableArrayListListener.java | 74 ++ .../com/yahoo/collections/HashletTestCase.java | 186 +++++ .../collections/IntArrayComparatorTestCase.java | 37 + .../java/com/yahoo/collections/LazyMapTest.java | 285 ++++++++ .../java/com/yahoo/collections/LazySetTest.java | 265 ++++++++ .../com/yahoo/collections/ListMapTestCase.java | 153 +++++ .../collections/ListenableArrayListTestCase.java | 50 ++ .../java/com/yahoo/collections/MD5TestCase.java | 33 + .../yahoo/collections/PredicateSplitTestCase.java | 30 + .../yahoo/collections/TinyIdentitySetTestCase.java | 302 ++++++++ .../java/com/yahoo/collections/TupleTestCase.java | 48 ++ .../com/yahoo/compress/IntegerCompressorTest.java | 105 +++ .../yahoo/concurrent/CopyOnWriteHashMapTest.java | 106 +++ .../com/yahoo/concurrent/EventBarrierTestCase.java | 168 +++++ .../com/yahoo/concurrent/ExecutorsTestCase.java | 139 ++++ .../com/yahoo/concurrent/ReceiverTestCase.java | 59 ++ .../yahoo/concurrent/ThreadFactoryFactoryTest.java | 44 ++ .../concurrent/ThreadLocalDirectoryTestCase.java | 125 ++++ .../yahoo/concurrent/ThreadRobustListTestCase.java | 103 +++ .../data/access/InspectorConformanceTestBase.java | 365 ++++++++++ .../access/simple/SimpleConformanceTestCase.java | 55 ++ .../access/slime/SlimeConformanceTestCase.java | 45 ++ .../java/com/yahoo/data/inspect/slime/.gitignore | 0 .../com/yahoo/geo/BoundingBoxParserTestCase.java | 162 +++++ .../java/com/yahoo/geo/DegreesParserTestCase.java | 282 ++++++++ .../test/java/com/yahoo/geo/ZCurveTestCase.java | 204 ++++++ .../src/test/java/com/yahoo/io/BlobTestCase.java | 95 +++ .../test/java/com/yahoo/io/ByteWriterTestCase.java | 444 ++++++++++++ .../com/yahoo/io/FatalErrorHandlerTestCase.java | 55 ++ .../test/java/com/yahoo/io/FileReadTestCase.java | 39 ++ .../io/GrowableBufferOutputStreamTestCase.java | 126 ++++ .../com/yahoo/io/GrowableByteBufferTestCase.java | 756 +++++++++++++++++++++ .../test/java/com/yahoo/io/HexDumpTestCase.java | 40 ++ .../test/java/com/yahoo/io/IOUtilsTestCase.java | 149 ++++ .../test/java/com/yahoo/io/ListenerTestCase.java | 108 +++ .../java/com/yahoo/io/SlowInflateTestCase.java | 61 ++ .../com/yahoo/io/reader/NamedReaderTestCase.java | 131 ++++ .../test/java/com/yahoo/java7compat/UtilTest.java | 29 + .../com/yahoo/javacc/FastCharStreamTestCase.java | 181 +++++ .../com/yahoo/javacc/UnicodeUtilitiesTestCase.java | 112 +++ .../test/java/com/yahoo/net/HostNameTestCase.java | 16 + .../com/yahoo/net/LinuxInetAddressTestCase.java | 41 ++ .../src/test/java/com/yahoo/net/URITestCase.java | 512 ++++++++++++++ .../test/java/com/yahoo/net/UriToolsTestCase.java | 25 + .../src/test/java/com/yahoo/net/UrlTestCase.java | 192 ++++++ .../test/java/com/yahoo/net/UrlTokenTestCase.java | 47 ++ .../java/com/yahoo/net/UrlTokenizerTestCase.java | 385 +++++++++++ .../src/test/java/com/yahoo/path/PathTest.java | 128 ++++ .../java/com/yahoo/protect/TestErrorMessage.java | 31 + .../java/com/yahoo/protect/ValidatorTestCase.java | 88 +++ .../java/com/yahoo/reflection/CastingTest.java | 36 + vespajlib/src/test/java/com/yahoo/rmi/.gitignore | 0 .../java/com/yahoo/slime/BinaryFormatTestCase.java | 567 ++++++++++++++++ .../test/java/com/yahoo/slime/JsonBenchmark.java | 114 ++++ .../java/com/yahoo/slime/JsonFormatTestCase.java | 273 ++++++++ .../test/java/com/yahoo/slime/SlimeTestCase.java | 330 +++++++++ .../test/java/com/yahoo/slime/VisitorTestCase.java | 101 +++ vespajlib/src/test/java/com/yahoo/system/Bar.java | 7 + .../com/yahoo/system/CatchSigTermTestCase.java | 19 + .../yahoo/system/CommandLineParserTestCase.java | 125 ++++ vespajlib/src/test/java/com/yahoo/system/Foo.java | 7 + .../java/com/yahoo/system/ForceLoadTestCase.java | 27 + .../com/yahoo/system/ProcessExecuterTestCase.java | 23 + .../com/yahoo/tensor/MapTensorBuilderTestCase.java | 48 ++ .../java/com/yahoo/tensor/MapTensorTestCase.java | 69 ++ .../java/com/yahoo/tensor/TensorTypeTestCase.java | 89 +++ .../serialization/CompactBinaryFormatTestCase.java | 78 +++ .../src/test/java/com/yahoo/text/AsciiTest.java | 187 +++++ .../src/test/java/com/yahoo/text/Benchmark.java | 106 +++ .../java/com/yahoo/text/BooleanParserTestCase.java | 35 + .../text/CaseInsensitiveIdentifierTestCase.java | 46 ++ .../com/yahoo/text/DataTypeIdentifierTestCase.java | 39 ++ .../com/yahoo/text/DoubleFormatterTestCase.java | 204 ++++++ .../java/com/yahoo/text/DoubleParserTestCase.java | 158 +++++ .../com/yahoo/text/DoubleToStringBenchmark.java | 123 ++++ .../java/com/yahoo/text/ForwardWriterTestCase.java | 435 ++++++++++++ .../java/com/yahoo/text/GenericWriterTestCase.java | 107 +++ .../src/test/java/com/yahoo/text/HTMLTestCase.java | 49 ++ .../java/com/yahoo/text/IdentifierTestCase.java | 42 ++ .../src/test/java/com/yahoo/text/JSONTest.java | 25 + .../java/com/yahoo/text/JSONWriterTestCase.java | 114 ++++ .../com/yahoo/text/JsonMicroBenchmarkTestCase.java | 563 +++++++++++++++ .../java/com/yahoo/text/LanguageHacksTestCase.java | 28 + .../yahoo/text/LowercaseIdentifierTestCase.java | 41 ++ .../java/com/yahoo/text/LowercaseTestCase.java | 96 +++ .../com/yahoo/text/MapParserMicroBenchmark.java | 62 ++ .../java/com/yahoo/text/MapParserTestCase.java | 71 ++ .../yahoo/text/StringAppendMicroBenchmarkTest.java | 77 +++ .../java/com/yahoo/text/StringUtilitiesTest.java | 85 +++ .../java/com/yahoo/text/Utf8ArrayTestCase.java | 167 +++++ .../src/test/java/com/yahoo/text/Utf8TestCase.java | 554 +++++++++++++++ .../src/test/java/com/yahoo/text/XMLTestCase.java | 115 ++++ .../java/com/yahoo/text/XMLWriterTestCase.java | 178 +++++ .../com/yahoo/time/WallClockSourceTestCase.java | 86 +++ .../transaction/NestedTransactionTestCase.java | 181 +++++ .../java/com/yahoo/vespa/objects/BigIdClass.java | 183 +++++ .../com/yahoo/vespa/objects/FieldBaseTestCase.java | 50 ++ .../com/yahoo/vespa/objects/FooBarIdClass.java | 35 + .../yahoo/vespa/objects/ObjectDumperTestCase.java | 161 +++++ .../com/yahoo/vespa/objects/SerializeTestCase.java | 143 ++++ .../java/com/yahoo/vespa/objects/SomeIdClass.java | 13 + 111 files changed, 14843 insertions(+) create mode 100644 vespajlib/src/test/java/com/yahoo/binaryprefix/BinaryScaledAmountTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/cache/CacheTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/cache/CalcTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/ArraySetTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/BobHashTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/ByteArrayComparatorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/CollectionComparatorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/CollectionUtilTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/CollectionsBenchMark.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/CopyOnWriteHashMapTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/FreezableArrayListListener.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/HashletTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/IntArrayComparatorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/LazyMapTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/LazySetTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/ListMapTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/ListenableArrayListTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/MD5TestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/PredicateSplitTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/TinyIdentitySetTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/collections/TupleTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/compress/IntegerCompressorTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/CopyOnWriteHashMapTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/EventBarrierTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/ExecutorsTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/ReceiverTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/ThreadFactoryFactoryTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/ThreadLocalDirectoryTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/concurrent/ThreadRobustListTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/data/access/InspectorConformanceTestBase.java create mode 100644 vespajlib/src/test/java/com/yahoo/data/access/simple/SimpleConformanceTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/data/access/slime/SlimeConformanceTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/data/inspect/slime/.gitignore create mode 100644 vespajlib/src/test/java/com/yahoo/geo/BoundingBoxParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/geo/DegreesParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/geo/ZCurveTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/BlobTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/ByteWriterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/java7compat/UtilTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/javacc/FastCharStreamTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/javacc/UnicodeUtilitiesTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/HostNameTestCase.java create mode 100755 vespajlib/src/test/java/com/yahoo/net/LinuxInetAddressTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/URITestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/UriToolsTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/UrlTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/UrlTokenTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/net/UrlTokenizerTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/path/PathTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/protect/TestErrorMessage.java create mode 100644 vespajlib/src/test/java/com/yahoo/protect/ValidatorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/reflection/CastingTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/rmi/.gitignore create mode 100644 vespajlib/src/test/java/com/yahoo/slime/BinaryFormatTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/slime/JsonBenchmark.java create mode 100644 vespajlib/src/test/java/com/yahoo/slime/JsonFormatTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/slime/SlimeTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/slime/VisitorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/Bar.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/CatchSigTermTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/CommandLineParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/Foo.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/ForceLoadTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/system/ProcessExecuterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/tensor/MapTensorBuilderTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/tensor/MapTensorTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/tensor/TensorTypeTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/tensor/serialization/CompactBinaryFormatTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/AsciiTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/Benchmark.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/BooleanParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/CaseInsensitiveIdentifierTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/DataTypeIdentifierTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/ForwardWriterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/GenericWriterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/HTMLTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/IdentifierTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/JSONTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/JSONWriterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/JsonMicroBenchmarkTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/LanguageHacksTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/LowercaseIdentifierTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/LowercaseTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/MapParserMicroBenchmark.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/MapParserTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/StringAppendMicroBenchmarkTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/StringUtilitiesTest.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/Utf8ArrayTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/Utf8TestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/XMLTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/text/XMLWriterTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/time/WallClockSourceTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/BigIdClass.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/FieldBaseTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/FooBarIdClass.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/ObjectDumperTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/SerializeTestCase.java create mode 100644 vespajlib/src/test/java/com/yahoo/vespa/objects/SomeIdClass.java (limited to 'vespajlib/src/test/java/com/yahoo') diff --git a/vespajlib/src/test/java/com/yahoo/binaryprefix/BinaryScaledAmountTestCase.java b/vespajlib/src/test/java/com/yahoo/binaryprefix/BinaryScaledAmountTestCase.java new file mode 100644 index 00000000000..bfb36ec80ce --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/binaryprefix/BinaryScaledAmountTestCase.java @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.binaryprefix; + +import junit.framework.TestCase; + +/** + * @author tonytv + */ +public class BinaryScaledAmountTestCase extends TestCase { + public void testConversion() { + BinaryScaledAmount oneMeg = new BinaryScaledAmount(1024, BinaryPrefix.kilo); + + assertEquals(1, oneMeg.as(BinaryPrefix.mega)); + assertEquals(1024, oneMeg.as(BinaryPrefix.kilo)); + assertEquals(1024*1024, oneMeg.as(BinaryPrefix.unit)); + assertEquals(1 << 20, oneMeg.hashCode()); + + Object v = this; + assertEquals(false, oneMeg.equals(v)); + v = new BinaryScaledAmount(1, BinaryPrefix.mega); + assertEquals(true, oneMeg.equals(v)); + } + + public void testSymbols() { + BinaryScaledAmount oneMeg = new BinaryScaledAmount(1024, BinaryPrefix.kilo); + + assertEquals(1, oneMeg.as(BinaryPrefix.fromSymbol('M'))); + assertEquals(1024, oneMeg.as(BinaryPrefix.fromSymbol('K'))); + + boolean ex = false; + try { + BinaryPrefix invalid = BinaryPrefix.fromSymbol('q'); + } catch (RuntimeException e) { + ex = true; + } + assertEquals(true, ex); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/cache/CacheTestCase.java b/vespajlib/src/test/java/com/yahoo/cache/CacheTestCase.java new file mode 100644 index 00000000000..992974eeb63 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/cache/CacheTestCase.java @@ -0,0 +1,197 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.cache; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Collection; + +public class CacheTestCase extends TestCase { + + public void testBasicGet() { + Cache cache = new Cache<>(100 * 1024 * 1024, 3600, 10000); + String q = "/std_xmls_a00?hits=5&offset=5&query=flowers+shop&tracelevel=4&objid=ffffffffffffffff"; + String q2 = "/std_xmls_a00?hits=5&offset=5&query=flowers+shop&tracelevel=4&objid=ffffffffffffffff"; + String r = "result"; + String r2 = "result2"; + assertNull(cache.get(q)); + cache.put(q, r); + assertNotNull(cache.get(q)); + assertEquals(cache.get(q), r); + cache.put(q2, r); + assertEquals(cache.get(q2), r); + cache.put(q, r2); + assertEquals(cache.get(q), r2); + } + + public void testPutTooLarge() { + byte[] tenMB = new byte[10*1024*1024]; + for (int i = 0 ; i <10*1024*1024 ; i++) { + tenMB[i]=127; + } + byte[] sevenMB = new byte[7*1024*1024]; + for (int i = 0 ; i <7*1024*1024 ; i++) { + sevenMB[i]=127; + } + Cache cache=new Cache<>(9*1024*1024,3600, 100*1024*1024); // 9 MB + assertFalse(cache.put("foo", tenMB)); + assertTrue(cache.put("foo", sevenMB)); + assertEquals(cache.get("foo"), sevenMB); + } + + public void testInvalidate() { + byte[] tenMB = new byte[10*1024*1024]; + for (int i = 0 ; i <10*1024*1024 ; i++) { + tenMB[i]=127; + } + byte[] sevenMB = new byte[7*1024*1024]; + for (int i = 0 ; i <7*1024*1024 ; i++) { + sevenMB[i]=127; + } + //log.info("10 MB: "+calc.sizeOf(tenMB)); + //log.info("7 MB: "+calc.sizeOf(sevenMB)); + Cache cache=new Cache<>(11*1024*1024,3600, 100*1024*1024); // 11 MB + assertTrue(cache.put("foo", sevenMB)); + assertTrue(cache.put("bar", tenMB)); + assertNull(cache.get("foo")); + assertEquals(cache.get("bar"), tenMB); + } + + public void testInvalidateLRU() { + Cache cache=new Cache<>(10*1024*1024,3600, 100*1024*1024); // 10 MB + byte[] fiveMB = new byte[5*1024*1024]; + for (int i = 0 ; i <5*1024*1024 ; i++) { + fiveMB[i]=127; + } + + byte[] twoMB = new byte[2*1024*1024]; + for (int i = 0 ; i <2*1024*1024 ; i++) { + twoMB[i]=127; + } + + byte[] fourMB = new byte[4*1024*1024]; + for (int i = 0 ; i <4*1024*1024 ; i++) { + fourMB[i]=127; + } + assertTrue(cache.put("five", fiveMB)); + assertTrue(cache.put("two", twoMB)); + Object dummy = cache.get("five"); // Makes two LRU + assertEquals(dummy, fiveMB); + assertTrue(cache.put("four", fourMB)); + assertNull(cache.get("two")); + assertEquals(cache.get("five"), fiveMB); + assertEquals(cache.get("four"), fourMB); + + // Same, without the access, just to check + cache=new Cache<>(10*1024*1024,3600, 100*1024*1024); // 10 MB + assertTrue(cache.put("five", fiveMB)); + assertTrue(cache.put("two", twoMB)); + assertTrue(cache.put("four", fourMB)); + assertEquals(cache.get("two"), twoMB); + assertNull(cache.get("five")); + assertEquals(cache.get("four"), fourMB); + } + + public void testPutSameKey() { + Cache cache=new Cache<>(10*1024*1024,3600, 100*1024*1024); // 10 MB + byte[] fiveMB = new byte[5*1024*1024]; + for (int i = 0 ; i <5*1024*1024 ; i++) { + fiveMB[i]=127; + } + + byte[] twoMB = new byte[2*1024*1024]; + for (int i = 0 ; i <2*1024*1024 ; i++) { + twoMB[i]=127; + } + + byte[] fourMB = new byte[4*1024*1024]; + for (int i = 0 ; i <4*1024*1024 ; i++) { + fourMB[i]=127; + } + assertTrue(cache.put("five", fiveMB)); + assertTrue(cache.put("two", twoMB)); + assertEquals(cache.get("two"), twoMB); + assertEquals(cache.get("five"), fiveMB); + assertTrue(cache.put("five", twoMB)); + assertEquals(cache.get("five"), twoMB); + assertEquals(cache.get("two"), twoMB); + } + + public void testExpire() throws InterruptedException { + Cache cache=new Cache<>(10*1024*1024,400, 10000); // 10 MB, .4 sec expire + cache.put("foo", "bar"); + cache.put("hey", "ho"); + assertEquals(cache.get("foo"), "bar"); + assertEquals(cache.get("hey"), "ho"); + Thread.sleep(600); + assertNull(cache.get("foo")); + assertNull(cache.get("hey")); + } + + public void testInsertSame() { + Cache cache=new Cache<>(10*1024*1024,500, 10000); // 10 MB, .5 sec expire + String k = "foo"; + String r = "bar"; + cache.put(k, r); + assertEquals(cache.size(), 1); + cache.put(k, r); + assertEquals(cache.size(), 1); + } + + public void testMaxSize() { + Cache cache=new Cache<>(20*1024*1024,500, 3*1024*1024); + byte[] fourMB = new byte[4*1024*1024]; + for (int i = 0 ; i <4*1024*1024 ; i++) { + fourMB[i]=127; + } + byte[] twoMB = new byte[2*1024*1024]; + for (int i = 0 ; i <2*1024*1024 ; i++) { + twoMB[i]=127; + } + assertFalse(cache.put("four", fourMB)); + assertTrue(cache.put("two", twoMB)); + assertNull(cache.get("four")); + assertNotNull(cache.get("two")); + } + + public void testMaxSizeNoLimit() { + Cache cache=new Cache<>(20*1024*1024,500, -1); + byte[] fourMB = new byte[4*1024*1024]; + for (int i = 0 ; i <4*1024*1024 ; i++) { + fourMB[i]=127; + } + byte[] twoMB = new byte[2*1024*1024]; + for (int i = 0 ; i <2*1024*1024 ; i++) { + twoMB[i]=127; + } + assertTrue(cache.put("four", fourMB)); + assertTrue(cache.put("two", twoMB)); + assertNotNull(cache.get("four")); + assertNotNull(cache.get("two")); + } + + public void testGetKeysAndValuesAndClear() { + Cache cache=new Cache<>(10*1024*1024,500, 10000); // 10 MB, .5 sec expire + assertEquals(cache.getKeys().size(), 0); + assertEquals(cache.getValues().size(), 0); + cache.put("a", "b"); + cache.put("c", "d"); + cache.put("e", "f"); + Collection keys = new ArrayList<>(); + keys.add("a"); + keys.add("c"); + keys.add("e"); + Collection values = new ArrayList<>(); + values.add("b"); + values.add("d"); + values.add("f"); + assertEquals(cache.getKeys().size(), 3); + assertEquals(cache.getValues().size(), 3); + assertTrue(cache.getKeys().containsAll(keys)); + assertTrue(cache.getValues().containsAll(values)); + cache.clear(); + assertEquals(cache.getKeys().size(), 0); + assertEquals(cache.getValues().size(), 0); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/cache/CalcTestCase.java b/vespajlib/src/test/java/com/yahoo/cache/CalcTestCase.java new file mode 100644 index 00000000000..fbec483debb --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/cache/CalcTestCase.java @@ -0,0 +1,176 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.cache; + +import java.util.ArrayList; +import java.util.List; + +public class CalcTestCase extends junit.framework.TestCase { + + private SizeCalculator calc; + + + public CalcTestCase (String name) { + super(name); + } + + public void setUp() { + calc = new SizeCalculator(); + } + + public void testCalc1() { + assertEquals(calc.sizeOf(new Object()), 8); + } + + public void testCalc2() { + assertEquals(calc.sizeOf(new SixtyFourBooleans()), 8+64); + } + + public void testBoolean() { + assertEquals(8+1, calc.sizeOf(new Boolean(true))); + } + + public void testArrayPrimitive() { + byte[] eightBytes = new byte[]{1,1,1,1,1,1,1,1,}; + assertEquals(16+8, calc.sizeOf(eightBytes)); + } + + public void testArrayObjects() { + SixtyFourBooleans[] bunchOfBooleans = new SixtyFourBooleans[]{new SixtyFourBooleans(), + new SixtyFourBooleans(), new SixtyFourBooleans()}; + assertEquals(16+(3*(8+64)+(3*4)), calc.sizeOf(bunchOfBooleans)); + + } + + public void testSizeOfList() { + SixtyFourBooleans sfb = new SixtyFourBooleans(); + List dupList1 = new ArrayList<>(); + dupList1.add(new Object()); + dupList1.add(sfb); + dupList1.add(sfb); + dupList1.add(sfb); + List dupList2 = new ArrayList<>(); + dupList2.addAll(dupList1); + dupList2.add(sfb); + dupList2.add(sfb); + dupList2.add(sfb); + dupList2.add(new Object()); + dupList2.add(new Object()); + assertEquals(calc.sizeOf(dupList2), calc.sizeOf(dupList1)+8+8); + } + + public void testSizeOfTuple() { + SixtyFourBooleans[] bunchOfBooleans = new SixtyFourBooleans[]{new SixtyFourBooleans(), + new SixtyFourBooleans(), new SixtyFourBooleans()}; + SixtyFourBooleans[] bunchOfBooleans2 = new SixtyFourBooleans[]{new SixtyFourBooleans(), + new SixtyFourBooleans(), new SixtyFourBooleans()}; + assertEquals(16+(3*(8+64)+(3*4)), calc.sizeOf(bunchOfBooleans)); + assertEquals(2* (16+(3*(8+64)+(3*4))), calc.sizeOf(bunchOfBooleans, bunchOfBooleans2)); + } + + /*public void testEmptyArrayList() { + assertEquals(80, calc.sizeOf(new ArrayList())); + }*/ + + /*public void testFullArrayList() { + ArrayList arrayList = new ArrayList(10000); + + for (int i = 0; i < 10000; i++) { + arrayList.add(new Object()); + } + + assertEquals(120040, calc.sizeOf(arrayList)); + }*/ + + /*public void testHashMap() { + assertEquals(120, calc.sizeOf(new HashMap())); + + Byte[] all = new Byte[256]; + for (int i = -128; i < 128; i++) { + all[i + 128] = new Byte((byte) i); + } + assertEquals(5136, calc.sizeOf(all)); + + HashMap hm = new HashMap(); + for (int i = -128; i < 128; i++) { + hm.put("" + i, new Byte((byte) i)); + } + assertEquals(30776, calc.sizeOf(hm)); + }*/ + + /*public void testThousandBooleansObjects() { + Boolean[] booleans = new Boolean[1000]; + + for (int i = 0; i < booleans.length; i++) + booleans[i] = new Boolean(true); + + assertEquals(20016, calc.sizeOf(booleans)); + }*/ + + @SuppressWarnings("unused") + private static class SixtyFourBooleans { + boolean a0; + boolean a1; + boolean a2; + boolean a3; + boolean a4; + boolean a5; + boolean a6; + boolean a7; + boolean b0; + boolean b1; + boolean b2; + boolean b3; + boolean b4; + boolean b5; + boolean b6; + boolean b7; + boolean c0; + boolean c1; + boolean c2; + boolean c3; + boolean c4; + boolean c5; + boolean c6; + boolean c7; + boolean d0; + boolean d1; + boolean d2; + boolean d3; + boolean d4; + boolean d5; + boolean d6; + boolean d7; + boolean e0; + boolean e1; + boolean e2; + boolean e3; + boolean e4; + boolean e5; + boolean e6; + boolean e7; + boolean f0; + boolean f1; + boolean f2; + boolean f3; + boolean f4; + boolean f5; + boolean f6; + boolean f7; + boolean g0; + boolean g1; + boolean g2; + boolean g3; + boolean g4; + boolean g5; + boolean g6; + boolean g7; + boolean h0; + boolean h1; + boolean h2; + boolean h3; + boolean h4; + boolean h5; + boolean h6; + boolean h7; + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/ArraySetTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/ArraySetTestCase.java new file mode 100644 index 00000000000..5bb15f57420 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/ArraySetTestCase.java @@ -0,0 +1,303 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.junit.Test; + +/** + * Check ArraySet seems to work. :) + * + * @author Steinar Knutsen + */ +public final class ArraySetTestCase { + + @Test + public void testAdd() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final ArraySet t = new ArraySet<>(3); + t.add(a); + t.add(b); + assertEquals(1, t.size()); + t.add(string); + assertEquals(1, t.size()); + t.add("abd"); + t.add("abc"); + t.add("abd"); + assertEquals(2, t.size()); + + } + + @Test + public void testAddAll() { + final List stuff = doubleAdd(); + final ArraySet t = new ArraySet<>( + stuff.size()); + t.addAll(stuff); + assertEquals(stuff.size() / 2, t.size()); + } + + private List doubleAdd() { + final List stuff = new ArrayList<>(); + stuff.add("abc"); + stuff.add("abd"); + stuff.add("abe"); + stuff.add("abc"); + stuff.add("abd"); + stuff.add("abe"); + return stuff; + } + + @Test + public void testContains() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final ArraySet t = new ArraySet<>(2); + t.add(string); + t.add(a); + assertEquals(1, t.size()); + assertTrue(t.contains(a)); + assertTrue(t.contains(string)); + assertTrue(t.contains(b)); + } + + @Test + public void testContainsAll() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final String c = "c"; + final List stuff = new ArrayList<>(); + stuff.add(string); + stuff.add(a); + stuff.add(b); + final ArraySet t = new ArraySet<>( + stuff.size()); + t.addAll(stuff); + assertTrue(t.containsAll(stuff)); + stuff.add(c); + assertFalse(t.containsAll(stuff)); + } + + @Test + public void testRemove() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final ArraySet t = new ArraySet<>(2); + t.add("abc"); + t.add("abd"); + t.add("abe"); + assertEquals(3, t.size()); + assertFalse(t.remove("ab")); + assertTrue(t.remove("abd")); + assertFalse(t.remove("abd")); + assertEquals(2, t.size()); + assertTrue(t.remove("abe")); + assertFalse(t.remove("abe")); + assertTrue(t.remove("abc")); + assertTrue(t.isEmpty()); + } + + @Test + public void testRetainAll() { + final List stuff = doubleAdd(); + final ArraySet t = new ArraySet<>( + stuff.size()); + t.addAll(stuff); + assertFalse(t.retainAll(stuff)); + assertEquals(stuff.size() / 2, t.size()); + t.add("nalle"); + assertEquals(stuff.size() / 2 + 1, t.size()); + assertTrue(t.retainAll(stuff)); + assertEquals(stuff.size() / 2, t.size()); + } + + @Test + public void testToArrayTArray() { + final List stuff = doubleAdd(); + final ArraySet t = new ArraySet<>( + stuff.size()); + t.addAll(stuff); + final String[] s = t.toArray(new String[0]); + assertEquals(t.size(), s.length); + assertEquals(stuff.size() / 2, s.length); + } + + @Test + public void testGrow() { + final ArraySet t = new ArraySet<>(5); + final int targetSize = 100; + for (int i = 0; i < targetSize; ++i) { + t.add(i); + } + assertEquals(targetSize, t.size()); + int n = 0; + for (final Iterator i = t.iterator(); i.hasNext();) { + assertEquals(Integer.valueOf(n++), i.next()); + } + assertEquals(targetSize, n); + } + + @Test + public void testBiggerRemoveAll() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>( + targetSize); + final Integer[] instances = new Integer[targetSize]; + final List remove = buildSubSet(targetSize, t, instances); + t.removeAll(remove); + assertEquals(targetSize / 2, t.size()); + for (final Iterator i = t.iterator(); i.hasNext();) { + final Integer n = i.next(); + assertTrue(n % 2 == 0); + assertFalse(remove.contains(n)); + + } + } + + @Test + public void testBiggerRetainAll() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>( + targetSize); + final Integer[] instances = new Integer[targetSize]; + final List retain = buildSubSet(targetSize, t, instances); + t.retainAll(retain); + assertEquals(targetSize / 2, t.size()); + for (final Iterator i = t.iterator(); i.hasNext();) { + final Integer n = i.next(); + assertTrue(n % 2 != 0); + assertTrue(retain.contains(n)); + } + } + + private List buildSubSet(final int targetSize, + final ArraySet t, final Integer[] instances) { + for (int i = 0; i < targetSize; ++i) { + instances[i] = Integer.valueOf(i); + t.add(instances[i]); + } + final List subset = new ArrayList<>(50); + for (int i = 0; i < targetSize; ++i) { + if (i % 2 != 0) { + subset.add(instances[i]); + } + } + return subset; + } + + @Test + public void testMuckingAbout() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>(3); + final Integer[] instances = new Integer[targetSize]; + final List retain = buildSubSet(targetSize, t, instances); + for (final Integer n : retain) { + t.remove(n); + assertEquals(targetSize - 1, t.size()); + t.add(n); + assertEquals(targetSize, t.size()); + } + assertEquals(targetSize, t.size()); + final Integer[] contents = t.toArray(new Integer[0]); + Arrays.sort(contents, 0, targetSize); + for (int i = 0; i < targetSize; ++i) { + assertEquals(instances[i], contents[i]); + } + } + + @Test + public void testMoreDuplicates() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>(3); + final Integer[] instances = new Integer[targetSize]; + final List add = buildSubSet(targetSize, t, instances); + assertEquals(targetSize, t.size()); + t.addAll(add); + assertEquals(targetSize, t.size()); + } + + @Test + public void testEmptySet() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>(0); + final Integer[] instances = new Integer[targetSize]; + final List add = buildSubSet(targetSize, t, instances); + for (Integer i : instances) { + t.remove(i); + } + assertEquals(0, t.size()); + for (Integer i : add) { + t.add(i); + } + assertEquals(targetSize / 2, t.size()); + } + + @Test + public void testSmallEmptySet() { + final ArraySet t = new ArraySet<>(3); + Integer a = new Integer(0), b = new Integer(1), c = new Integer(2); + t.add(a); + t.add(b); + t.add(c); + assertEquals(3, t.size()); + t.remove(a); + assertEquals(2, t.size()); + t.remove(c); + assertEquals(1, t.size()); + t.remove(c); + assertEquals(1, t.size()); + t.remove(b); + assertEquals(0, t.size()); + t.add(b); + assertEquals(1, t.size()); + t.add(b); + assertEquals(1, t.size()); + t.add(a); + assertEquals(2, t.size()); + t.add(a); + assertEquals(2, t.size()); + t.add(c); + assertEquals(3, t.size()); + t.add(c); + assertEquals(3, t.size()); + } + + @Test + public void testIterator() { + final int targetSize = 100; + final ArraySet t = new ArraySet<>(0); + final Integer[] instances = new Integer[targetSize]; + final List remove = buildSubSet(targetSize, t, instances); + int traversed = 0; + for (Iterator i = t.iterator(); i.hasNext();) { + Integer n = i.next(); + if (remove.contains(n)) { + i.remove(); + } + ++traversed; + } + assertEquals(targetSize, traversed); + assertEquals(targetSize / 2, t.size()); + for (int i = 0; i < instances.length; ++i) { + Integer n = instances[i]; + if (remove.contains(n)) { + assertFalse(t.contains(n)); + } else { + assertTrue(t.contains(n)); + } + } + } +} + diff --git a/vespajlib/src/test/java/com/yahoo/collections/BobHashTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/BobHashTestCase.java new file mode 100644 index 00000000000..820adffcfc5 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/BobHashTestCase.java @@ -0,0 +1,45 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + + +import com.yahoo.collections.BobHash; + + +/** + * Basic consistency check of BobHash implementation + * + * @author Steinar Knutsen + */ +public class BobHashTestCase extends junit.framework.TestCase { + + public BobHashTestCase(String name) { + super(name); + } + + public void testit() { + // Teststring: minprice + // Basic ASCII string + byte[] minprice = { 109, 105, 110, 112, 114, 105, 99, 101 }; + + assertEquals(BobHash.hash(minprice, 0), 0x90188543); + // Teststring: a\u00FFa\u00FF + // String with non-ASCII characters + byte[] ayay = { 97, -1, 97, -1 }; + + assertEquals(BobHash.hash(ayay, 0), 0x1C798331); + // lots of a's to ensure testing unsigned type emulation + byte[] aa = { + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97 }; + + assertEquals(BobHash.hash(aa, 0), 0xE09ED5E9); + // A string which caused problems during developmen of another + // feature + byte[] lastnamefirstinitial = { + 0x6c, 0x61, 0x73, 0x74, 0x6e, 0x61, 0x6d, + 0x65, 0x66, 0x69, 0x72, 0x73, 0x74, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c }; + + assertEquals(BobHash.hash(lastnamefirstinitial, 0), 0xF36B4BD3); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/ByteArrayComparatorTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/ByteArrayComparatorTestCase.java new file mode 100644 index 00000000000..68b5812dd1e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/ByteArrayComparatorTestCase.java @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Einar M R Rosenvinge + */ +public class ByteArrayComparatorTestCase { + @Test + public void arrayLength() { + byte[] shortArr = new byte[]{(byte) 1, (byte) 2}; + byte[] longArr = new byte[]{(byte) 0, (byte) 3, (byte) 3, (byte) 3, (byte) 3, (byte) 3}; + + assertEquals(-1, ByteArrayComparator.compare(shortArr, longArr)); + } + + @Test + public void compareArrays() { + byte[] one = new byte[]{(byte) 1, (byte) 2, (byte) 3, (byte) 3, (byte) 3, (byte) 3}; + byte[] two = new byte[]{(byte) 0, (byte) 3, (byte) 3, (byte) 3, (byte) 3, (byte) 3}; + + assertEquals(1, ByteArrayComparator.compare(one, two)); + assertEquals(-1, ByteArrayComparator.compare(two, one)); + } + + @Test + public void compareEqualArrays() { + byte[] one = new byte[]{(byte) 1, (byte) 2, (byte) 3, (byte) 3, (byte) 3, (byte) 3, (byte) 9}; + byte[] two = new byte[]{(byte) 1, (byte) 2, (byte) 3, (byte) 3, (byte) 3, (byte) 3, (byte) 9}; + + assertEquals(0, ByteArrayComparator.compare(one, two)); + assertEquals(0, ByteArrayComparator.compare(two, one)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/CollectionComparatorTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/CollectionComparatorTestCase.java new file mode 100644 index 00000000000..d77636b907f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/CollectionComparatorTestCase.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Einar M R Rosenvinge + */ +public class CollectionComparatorTestCase { + @Test + public void arrayLength() { + List shortArr = Arrays.asList("x", "y"); + List longArr = Arrays.asList("a", "b", "c", "d", "e"); + + assertEquals(-1, CollectionComparator.compare(shortArr, longArr)); + } + + @Test + public void compareArrays() { + List one = Arrays.asList("b", "c", "d", "d", "e"); + List two = Arrays.asList("a", "b", "c", "d", "e"); + + assertEquals(1, CollectionComparator.compare(one, two)); + assertEquals(-1, CollectionComparator.compare(two, one)); + } + + @Test + public void compareEqualArrays() { + List one = Arrays.asList("a", "b", "c", "d", "e"); + List two = Arrays.asList("a", "b", "c", "d", "e"); + + assertEquals(0, CollectionComparator.compare(one, two)); + assertEquals(0, CollectionComparator.compare(two, one)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/CollectionUtilTest.java b/vespajlib/src/test/java/com/yahoo/collections/CollectionUtilTest.java new file mode 100644 index 00000000000..c5a20a4684c --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/CollectionUtilTest.java @@ -0,0 +1,50 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author tonytv + */ +public class CollectionUtilTest { + List l1 = Arrays.asList(1, 2, 4, 5, 6, 7); + List l2 = Arrays.asList(3, 4, 5, 6, 7); + + @Before + public void shuffle() { + Collections.shuffle(l1); + Collections.shuffle(l2); + } + + @Test + public void testMkString() { + assertEquals("1, 2, 3, 4", + CollectionUtil.mkString(Arrays.asList(1, 2, 3, 4), ", ")); + } + + @Test + public void testEqualContentsIgnoreOrder() { + List l2Copy = new ArrayList<>(); + l2Copy.addAll(l2); + shuffle(); + assertTrue(CollectionUtil.equalContentsIgnoreOrder( + l2, l2Copy)); + assertFalse(CollectionUtil.equalContentsIgnoreOrder( + l1, l2)); + } + + @Test + public void testSymmetricDifference() { + assertTrue(CollectionUtil.equalContentsIgnoreOrder( + Arrays.asList(1, 2, 3), + CollectionUtil.symmetricDifference(l1, l2))); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/CollectionsBenchMark.java b/vespajlib/src/test/java/com/yahoo/collections/CollectionsBenchMark.java new file mode 100644 index 00000000000..51cdd11bb7d --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/CollectionsBenchMark.java @@ -0,0 +1,204 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by balder on 1/20/14. + */ +public class CollectionsBenchMark { + abstract static class BenchMark { + protected BenchMark(int numWarmup, int repetitions) { + this.numWarmup = numWarmup; + this.repetitions = repetitions; + } + abstract void runOnce(); + abstract String getEndComment(); + protected void run() { + System.out.println("Starting benchmark warmup '" + getClass().getName() + "'."); + for (int i=0; i < numWarmup; i++) { + runOnce(); + } + System.out.println("Starting benchmark '" + getClass().getName() + "'."); + long startTime=System.currentTimeMillis(); + for (int i=0; i < repetitions; i++) { + runOnce(); + } + long endTime=System.currentTimeMillis(); + long totalTime=(endTime-startTime); + System.out.println("Done in " + totalTime + " ms (" + ((float) totalTime * 1000 / repetitions + " microsecond per repetition.)")); // *2 because we do 2 gets + System.out.println("Final remark: " + getEndComment()); + } + + + final private int repetitions; + final private int numWarmup; + } + + static class MapFilterBenchMark extends BenchMark { + MapFilterBenchMark(Map s, int numWarmup, int numRepetitions, int numObjects) { + super(numWarmup, numRepetitions); + this.s = s; + objects = new Integer[numObjects]; + for (int i=0; i < numObjects; i++) { + objects[i] = i; + } + } + void runOnce() { + for (Integer o : objects) { + if (s.put(o, o) == null) { + uniqueCount += o; + } + } + } + String getEndComment() { return " Unique sum is '" + uniqueCount + "'"; } + private final Map s; + final Integer [] objects; + long uniqueCount = 0; + } + + static class SetFilterBenchMark extends BenchMark { + SetFilterBenchMark(Set s, int numWarmup, int numRepetitions, int numObjects) { + super(numWarmup, numRepetitions); + this.s = s; + objects = new Integer[numObjects]; + for (int i=0; i < numObjects; i++) { + objects[i] = i; + } + } + void runOnce() { + for (Integer o : objects) { + if ( s.add(o) ) { + uniqueCount += o; + } + } + } + String getEndComment() { return " Unique sum is '" + uniqueCount + "'"; } + private final Set s; + final Integer [] objects; + long uniqueCount = 0; + } + + static abstract class SmallMapsBenchMark extends BenchMark { + SmallMapsBenchMark(int numWarmup, int numRepetitions, int numObjects, int numUnique) { + super(numWarmup, numRepetitions); + objects = new Integer[numObjects]; + for (int i=0; i < numObjects; i++) { + objects[i] = i%numUnique; + } + } + void runOnce() { + Set s = createSet(); + for (Integer o : objects) { + if ( s.add(o) ) { + uniqueCount += o; + } + } + } + abstract Set createSet(); + String getEndComment() { return " Unique sum is '" + uniqueCount + "'"; } + final Integer [] objects; + long uniqueCount = 0; + } + + static class SmallHashSetBenchMark extends SmallMapsBenchMark + { + SmallHashSetBenchMark(int numWarmup, int numRepetitions, int numObjects, int numUnique) { + super(numWarmup, numRepetitions, numObjects, numUnique); + } + Set createSet() { return new HashSet();} + } + + static class SmallLazySetBenchMark extends SmallMapsBenchMark + { + SmallLazySetBenchMark(int numWarmup, int numRepetitions, int numObjects, int numUnique) { + super(numWarmup, numRepetitions, numObjects, numUnique); + } + Set createSet() { return new LazySet() { + @Override + protected Set newDelegate() { + return new HashSet(); + } + }; + } + } + + static class SmallLazyTinyBenchMark extends SmallMapsBenchMark + { + SmallLazyTinyBenchMark(int numWarmup, int numRepetitions, int numObjects, int numUnique) { + super(numWarmup, numRepetitions, numObjects, numUnique); + } + Set createSet() { return new LazySet() { + @Override + protected Set newDelegate() { + return new TinyIdentitySet(10); + } + }; + } + } + + static void benchMarkAll() { + + new MapFilterBenchMark(new HashMap(), 100000, 10000000, 10).run(); + new MapFilterBenchMark(new IdentityHashMap(10), 100000, 10000000, 10).run(); + new SetFilterBenchMark(new HashSet(), 100000, 10000000, 10).run(); + new SetFilterBenchMark(new TinyIdentitySet(10), 100000, 10000000, 10).run(); + new SetFilterBenchMark(new TinyIdentitySet(10), 100000, 10000000, 15).run(); + new SetFilterBenchMark(new TinyIdentitySet(10), 100000, 10000000, 20).run(); + new SetFilterBenchMark(new TinyIdentitySet(20), 100000, 10000000, 20).run(); + new SmallHashSetBenchMark(100000, 10000000, 10, 1).run(); + new SmallLazySetBenchMark(100000, 10000000, 10, 1).run(); + new SmallHashSetBenchMark(100000, 10000000, 10, 2).run(); + new SmallLazySetBenchMark(100000, 10000000, 10, 2).run(); + new SmallLazyTinyBenchMark(100000, 10000000, 10, 2).run(); + new SmallHashSetBenchMark(100000, 10000000, 10, 10).run(); + new SmallLazySetBenchMark(100000, 10000000, 10, 10).run(); + + new SetFilterBenchMark(new HashSet(), 100000, 10000000, 12).run(); + + new SetFilterBenchMark(new HashSet(), 100000, 10000000, 20).run(); + new SetFilterBenchMark(new HashSet(), 100000, 10000000, 25).run(); + new SetFilterBenchMark(new HashSet(), 100000, 10000000, 30).run(); + new SmallHashSetBenchMark(100000, 10000000, 1, 1).run(); + + } + + static void benchMark() { + + //new MapFilterBenchMark(new HashMap(), 100000, 10000000, 10).run(); + //new MapFilterBenchMark(new IdentityHashMap(10), 100000, 10000000, 10).run(); + //new SetFilterBenchMark(new HashSet(), 100000, 10000000, 10).run(); + //new SetFilterBenchMark(new TinyIdentitySet(10), 100000, 10000000, 10).run(); + //new SmallHashSetBenchMark(100000, 10000000, 10, 1).run(); + //new SmallLazySetBenchMark(100000, 10000000, 10, 1).run(); + //new SmallHashSetBenchMark(100000, 10000000, 10, 2).run(); + //new SmallLazySetBenchMark(100000, 10000000, 10, 2).run(); + new SmallLazyTinyBenchMark(100000, 10000000, 10, 2).run(); + //new SmallHashSetBenchMark(100000, 10000000, 10, 10).run(); + //new SmallLazySetBenchMark(100000, 10000000, 10, 10).run(); + + //new SetFilterBenchMark(new HashSet(), 100000, 10000000, 12).run(); + + //new SetFilterBenchMark(new HashSet(), 100000, 10000000, 20).run(); + //new SetFilterBenchMark(new HashSet(), 100000, 10000000, 25).run(); + //new SetFilterBenchMark(new HashSet(), 100000, 10000000, 30).run(); + //new SmallHashSetBenchMark(100000, 10000000, 1, 1).run(); + + } + + + static public void main(String argv[]) { + benchMarkAll(); + ExecutorService tp = Executors.newFixedThreadPool(16); + + for (int i=0; i < 16; i++) { + tp.execute(new Runnable() { + @Override + public void run() { + benchMark(); + } + }); + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/CopyOnWriteHashMapTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/CopyOnWriteHashMapTestCase.java new file mode 100644 index 00000000000..4370a9b46b0 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/CopyOnWriteHashMapTestCase.java @@ -0,0 +1,64 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * @author Jon Bratseth + */ +public class CopyOnWriteHashMapTestCase { + + @Test + public void testModifySourceFirst() { + CopyOnWriteHashMap map = new CopyOnWriteHashMap<>(); + map.put("a", "a1"); + map.put("b", "b1"); + CopyOnWriteHashMap clone = map.clone(); + map.put("c", "c1"); + clone.remove("a"); + clone.put("b", "b2"); + clone.put("d", "d2"); + + assertEquals(3, map.size()); + assertEquals("a1", map.get("a")); + assertEquals("b1", map.get("b")); + assertEquals("c1", map.get("c")); + + assertEquals(2, clone.size()); + assertEquals("b2", clone.get("b")); + assertEquals("d2", clone.get("d")); + } + + @Test + public void testModifyTargetFirst() { + CopyOnWriteHashMap map = new CopyOnWriteHashMap<>(); + map.put("a", "a1"); + map.put("b", "b1"); + CopyOnWriteHashMap clone = map.clone(); + clone.remove("a"); + map.put("c", "c1"); + clone.put("b", "b2"); + clone.put("d", "d2"); + + assertEquals(3, map.size()); + assertEquals("a1", map.get("a")); + assertEquals("b1", map.get("b")); + assertEquals("c1", map.get("c")); + + assertEquals(2, clone.size()); + assertEquals("b2", clone.get("b")); + assertEquals("d2", clone.get("d")); + } + + @Test + public void testCallEntrySetThenModify() { + CopyOnWriteHashMap map = new CopyOnWriteHashMap<>(); + map.put("a", "a1"); + map.entrySet(); + CopyOnWriteHashMap clone = map.clone(); + clone.put("b", "b1"); + assertEquals(2, clone.size()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/FreezableArrayListListener.java b/vespajlib/src/test/java/com/yahoo/collections/FreezableArrayListListener.java new file mode 100644 index 00000000000..762ae9d5b60 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/FreezableArrayListListener.java @@ -0,0 +1,74 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; +import static org.junit.Assert.fail; + +/** + * @author Jon Bratseth + */ +public class FreezableArrayListListener { + + @Test + public void testPermitAdd() { + FreezableArrayList l = new FreezableArrayList<>(true); + l.add("1"); + l.add("2"); + l.remove(1); + l.freeze(); + try { + l.remove(0); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + try { + l.set(0, "2"); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + try { + l.add(0, "2"); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + + l.add("2"); + } + + @Test + public void testDontPermitAdd() { + FreezableArrayList l = new FreezableArrayList<>(); + l.add("1"); + l.add("2"); + l.remove(1); + l.freeze(); + try { + l.remove(0); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + try { + l.set(0, "2"); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + try { + l.add(0, "2"); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + try { + l.add("2"); + fail("Expected exception"); + } + catch (UnsupportedOperationException expected) { + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/HashletTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/HashletTestCase.java new file mode 100644 index 00000000000..1a198726994 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/HashletTestCase.java @@ -0,0 +1,186 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +public class HashletTestCase { + + @Test + public void testCopyEmptyHashlet() { + Hashlet hash = new Hashlet<>(); + Hashlet hash2 = new Hashlet<>(hash); + assertThat(hash.size(), is(0)); + assertThat(hash2.size(), is(0)); + hash.put("foo", 5); + hash2.put("bar", 7); + assertThat(hash.get("foo"), is(5)); + assertThat(hash.get("bar"), nullValue()); + assertThat(hash2.get("foo"), nullValue()); + assertThat(hash2.get("bar"), is(7)); + } + + private void verifyEquals(Object a, Object b) { + assertEquals(a, b); + assertEquals(b, a); + } + private void verifyNotEquals(Object a, Object b) { + assertNotEquals(a, b); + assertNotEquals(b, a); + } + + @Test + public void testThatDifferentGenericsDoesNotEqual() { + Hashlet a = new Hashlet<>(); + Hashlet b = new Hashlet<>(); + verifyEquals(a, b); + b.put("a", 1); + verifyNotEquals(a, b); + a.put(1L, 1L); + verifyNotEquals(a, b); + } + @Test + public void testHashCodeAndEquals() { + Hashlet h1 = new Hashlet<>(); + Hashlet h2 = new Hashlet<>(); + assertEquals(h1.hashCode(), h2.hashCode()); + verifyEquals(h1, h2); + + h1.put("a", 7); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h2.put("b", 8); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h2.put("a", 7); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h1.put("b", 8); + assertEquals(h1.hashCode(), h2.hashCode()); + verifyEquals(h1, h2); + + h1.put("c", null); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h2.put("d", null); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h2.put("c", null); + assertNotEquals(h1.hashCode(), h2.hashCode()); + verifyNotEquals(h1, h2); + + h1.put("d", null); + assertEquals(h1.hashCode(), h2.hashCode()); + verifyEquals(h1, h2); + } + + @Test + public void testSetValue() { + String A = "a"; + Hashlet h = new Hashlet<>(); + h.put(A, 1); + int indexOfA = h.getIndexOfKey(A); + assertEquals(new Integer(1), h.value(indexOfA)); + h.setValue(indexOfA, 2); + assertEquals(new Integer(2), h.value(indexOfA)); + assertEquals(new Integer(2), h.get(A)); + } + + @Test + public void testGet() { + Hashlet h = new Hashlet<>(); + h.put("a", 1); + h.put("b", null); + assertEquals(0, h.getIndexOfKey("a")); + assertEquals(h.get("a"), h.value(h.getIndexOfKey("a"))); + assertEquals(1, h.getIndexOfKey("b")); + assertEquals(h.get("b"), h.value(h.getIndexOfKey("b"))); + assertEquals(-1, h.getIndexOfKey("c")); + assertNull(h.get("c")); + } + + @Test + public void testCopyNonEmptyHashlet() { + Hashlet hash = new Hashlet<>(); + hash.put("foo", 5); + hash.put("bar", 7); + Hashlet hash2 = new Hashlet<>(hash); + assertThat(hash2.size(), is(2)); + assertThat(hash2.get("foo"), is(5)); + assertThat(hash2.get("bar"), is(7)); + assertThat(hash2.key(0), is("foo")); + assertThat(hash2.key(1), is("bar")); + assertThat(hash2.value(0), is(5)); + assertThat(hash2.value(1), is(7)); + assertThat(hash2.key(0), sameInstance(hash.key(0))); + assertThat(hash2.key(1), sameInstance(hash.key(1))); + assertThat(hash2.value(0), sameInstance(hash.value(0))); + assertThat(hash2.value(1), sameInstance(hash.value(1))); + } + + @Test + public void testSetValueToNull() { + Hashlet hash = new Hashlet<>(); + hash.put("foo", 5); + hash.put("bar", 7); + assertThat(hash.size(), is(2)); + assertThat(hash.get("foo"), is(5)); + assertThat(hash.get("bar"), is(7)); + assertThat(hash.key(0), is("foo")); + assertThat(hash.key(1), is("bar")); + assertThat(hash.value(0), is(5)); + assertThat(hash.value(1), is(7)); + hash.put("foo", null); + assertThat(hash.size(), is(2)); + assertThat(hash.get("foo"), nullValue()); + assertThat(hash.get("bar"), is(7)); + assertThat(hash.key(0), is("foo")); + assertThat(hash.key(1), is("bar")); + assertThat(hash.value(0), nullValue()); + assertThat(hash.value(1), is(7)); + } + + @Test + public void testIterate() { + int n = 100; + Hashlet hash = new Hashlet<>(); + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + hash.put(str, i); + } + assertThat(hash.size(), is(n)); + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + assertThat(hash.key(i), is(str)); + assertThat(hash.value(i), is(i)); + } + } + + @Test + public void testManyEntries() { + int n = 5000; + Hashlet hash = new Hashlet<>(); + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + assertThat(hash.get(str), nullValue()); + switch (i % 2) { + case 1: assertThat(hash.put(str, new Integer(i)), nullValue()); + } + } + assertThat(hash.size(), is(n / 2)); + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + switch (i % 2) { + case 0: assertThat(hash.get(str), nullValue()); break; + case 1: assertThat(hash.get(str), is(new Integer(i))); break; + } + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/IntArrayComparatorTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/IntArrayComparatorTestCase.java new file mode 100644 index 00000000000..c4808a6605c --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/IntArrayComparatorTestCase.java @@ -0,0 +1,37 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Einar M R Rosenvinge + */ +public class IntArrayComparatorTestCase { + @Test + public void arrayLength() { + int[] shortArr = new int[]{1, 2}; + int[] longArr = new int[]{0, 3, 3, 3, 3, 3}; + + assertEquals(-1, IntArrayComparator.compare(shortArr, longArr)); + } + + @Test + public void compareArrays() { + int[] one = new int[]{1, 2, 3, 3, 3, 3}; + int[] two = new int[]{0, 3, 3, 3, 3, 3}; + + assertEquals(1, IntArrayComparator.compare(one, two)); + assertEquals(-1, IntArrayComparator.compare(two, one)); + } + + @Test + public void compareEqualArrays() { + int[] one = new int[]{1, 2, 3, 3, 3, 3, 9}; + int[] two = new int[]{1, 2, 3, 3, 3, 3, 9}; + + assertEquals(0, IntArrayComparator.compare(one, two)); + assertEquals(0, IntArrayComparator.compare(two, one)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/LazyMapTest.java b/vespajlib/src/test/java/com/yahoo/collections/LazyMapTest.java new file mode 100644 index 00000000000..2890d73ebaf --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/LazyMapTest.java @@ -0,0 +1,285 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +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 Simon Thoresen Hult + */ +public class LazyMapTest { + + @Test + public void requireThatInitialDelegateIsEmpty() { + LazyMap map = newLazyMap(new HashMap()); + assertEquals(LazyMap.EmptyMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatEmptyMapPutUpgradesToSingletonMap() { + LazyMap map = newLazyMap(new HashMap()); + assertNull(map.put("foo", "bar")); + assertEquals(LazyMap.SingletonMap.class, map.getDelegate().getClass()); + + map = newLazyMap(new HashMap()); + map.putAll(Collections.singletonMap("foo", "bar")); + assertEquals(LazyMap.SingletonMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatEmptyMapPutAllEmptyMapDoesNotUpgradeToSingletonMap() { + LazyMap map = newLazyMap(new HashMap()); + map.putAll(Collections.emptyMap()); + assertEquals(LazyMap.EmptyMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatEmptyMapPutAllUpgradesToFinalMap() { + Map delegate = new HashMap<>(); + LazyMap map = newLazyMap(delegate); + map.putAll(new HashMapBuilder() + .put("foo", "bar") + .put("baz", "cox").map); + assertSame(delegate, map.getDelegate()); + assertEquals(2, delegate.size()); + assertEquals("bar", delegate.get("foo")); + assertEquals("cox", delegate.get("baz")); + } + + @Test + public void requireThatSingletonMapRemoveEntryDowngradesToEmptyMap() { + LazyMap map = newSingletonMap("foo", "bar"); + assertEquals("bar", map.remove("foo")); + assertEquals(LazyMap.EmptyMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonMapRemoveUnknownDoesNotDowngradesToEmptyMap() { + LazyMap map = newSingletonMap("foo", "bar"); + assertNull(map.remove("baz")); + assertEquals(LazyMap.SingletonMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonMapValueMayBeChangedInPlace() { + LazyMap map = newSingletonMap("foo", "bar"); + Map delegate = map.getDelegate(); + assertEquals("bar", map.put("foo", "baz")); + assertEquals("baz", map.get("foo")); + assertSame(delegate, map.getDelegate()); + map.putAll(Collections.singletonMap("foo", "cox")); + assertSame(delegate, map.getDelegate()); + assertEquals("cox", map.get("foo")); + } + + @Test + public void requireThatSingletonMapPutAllEmptyMapDoesNotUpgradeToFinalMap() { + LazyMap map = newSingletonMap("foo", "bar"); + map.putAll(Collections.emptyMap()); + assertEquals(LazyMap.SingletonMap.class, map.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonMapPutUpgradesToFinalMap() { + Map delegate = new HashMap<>(); + LazyMap map = newSingletonMap(delegate, "fooKey", "fooVal"); + map.put("barKey", "barVal"); + assertSame(delegate, map.getDelegate()); + assertEquals(2, delegate.size()); + assertEquals("fooVal", delegate.get("fooKey")); + assertEquals("barVal", delegate.get("barKey")); + } + + @Test + public void requireThatSingletonMapPutAllUpgradesToFinalMap() { + Map delegate = new HashMap<>(); + LazyMap map = newSingletonMap(delegate, "fooKey", "fooVal"); + map.putAll(new HashMapBuilder() + .put("barKey", "barVal") + .put("bazKey", "bazVal").map); + assertSame(delegate, map.getDelegate()); + assertEquals(3, delegate.size()); + assertEquals("fooVal", delegate.get("fooKey")); + assertEquals("barVal", delegate.get("barKey")); + assertEquals("bazVal", delegate.get("bazKey")); + } + + @Test + public void requireThatSingletonEntryIsMutable() { + LazyMap map = newSingletonMap("foo", "bar"); + Map.Entry entry = map.entrySet().iterator().next(); + entry.setValue("baz"); + assertEquals("baz", map.get("foo")); + } + + @Test + public void requireThatSingletonEntryImplementsHashCode() { + assertEquals(newSingletonMap("foo", "bar").entrySet().iterator().next().hashCode(), + newSingletonMap("foo", "bar").entrySet().iterator().next().hashCode()); + } + + @Test + public void requireThatSingletonEntryImplementsEquals() { + Map.Entry map = newSingletonMap("foo", "bar").entrySet().iterator().next(); + assertNotEquals(map, null); + assertNotEquals(map, new Object()); + assertEquals(map, map); + assertNotEquals(map, newSingletonMap("baz", "cox").entrySet().iterator().next()); + assertNotEquals(map, newSingletonMap("foo", "cox").entrySet().iterator().next()); + assertEquals(map, newSingletonMap("foo", "bar").entrySet().iterator().next()); + } + + @Test + public void requireThatSingletonEntrySetIteratorNextThrowsIfInvokedMoreThanOnce() { + LazyMap map = newSingletonMap("foo", "bar"); + Iterator> it = map.entrySet().iterator(); + it.next(); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + + } + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + + } + } + + @Test + public void requireThatSingletonEntrySetIteratorRemoveThrowsIfInvokedBeforeNext() { + LazyMap map = newSingletonMap("foo", "bar"); + Iterator> it = map.entrySet().iterator(); + try { + it.remove(); + fail(); + } catch (IllegalStateException e) { + + } + } + + @SuppressWarnings("unchecked") + private static Map makeMockMap() { + return Mockito.mock(Map.class); + } + + @Test + public void requireThatMapDelegates() { + Map delegate = makeMockMap(); + Map map = newLazyMap(delegate); + map.put("foo", "bar"); + map.put("baz", "cox"); // trigger the assignment of the delegate + Mockito.verify(delegate).put("foo", "bar"); + Mockito.verify(delegate).put("baz", "cox"); + + Map arg = Collections.singletonMap("baz", "cox"); + map.putAll(arg); + Mockito.verify(delegate).putAll(arg); + + assertEquals(0, map.size()); + Mockito.verify(delegate).size(); + + assertFalse(map.isEmpty()); + Mockito.verify(delegate).isEmpty(); + + assertFalse(map.containsKey("foo")); + Mockito.verify(delegate).containsKey("foo"); + + assertFalse(map.containsValue("bar")); + Mockito.verify(delegate).containsValue("bar"); + + assertNull(map.get("foo")); + Mockito.verify(delegate).get("foo"); + + assertNull(map.remove("foo")); + Mockito.verify(delegate).remove("foo"); + + map.clear(); + Mockito.verify(delegate).clear(); + + assertTrue(map.keySet().isEmpty()); + Mockito.verify(delegate).keySet(); + + assertTrue(map.values().isEmpty()); + Mockito.verify(delegate).values(); + + assertTrue(map.entrySet().isEmpty()); + Mockito.verify(delegate).entrySet(); + } + + @Test + public void requireThatHashCodeIsImplemented() { + assertEquals(newLazyMap(null).hashCode(), + newLazyMap(null).hashCode()); + } + + @Test + public void requireThatEqualsIsImplemented() { + Map lhs = newLazyMap(new HashMap<>()); + Map rhs = newLazyMap(new HashMap<>()); + assertEquals(lhs, lhs); + assertEquals(lhs, rhs); + + Object key = new Object(); + Object val = new Object(); + lhs.put(key, val); + assertEquals(lhs, lhs); + assertFalse(lhs.equals(rhs)); + rhs.put(key, val); + assertEquals(lhs, rhs); + } + + @Test + public void requireThatHashMapFactoryDelegatesToAHashMap() { + LazyMap map = LazyMap.newHashMap(); + map.put("foo", "bar"); + map.put("baz", "cox"); + assertEquals(HashMap.class, map.getDelegate().getClass()); + } + + private static LazyMap newSingletonMap(K key, V value) { + return newSingletonMap(new HashMap(), key, value); + } + + private static LazyMap newSingletonMap(Map delegate, K key, V value) { + LazyMap map = newLazyMap(delegate); + map.put(key, value); + return map; + } + + private static LazyMap newLazyMap(final Map delegate) { + return new LazyMap() { + + @Override + protected Map newDelegate() { + return delegate; + } + }; + } + + private static class HashMapBuilder { + + final Map map = new HashMap<>(); + + public HashMapBuilder put(K key, V value) { + map.put(key, value); + return this; + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/LazySetTest.java b/vespajlib/src/test/java/com/yahoo/collections/LazySetTest.java new file mode 100644 index 00000000000..d71e7ca6e26 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/LazySetTest.java @@ -0,0 +1,265 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +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 Simon Thoresen Hult + */ +public class LazySetTest { + + @Test + public void requireThatInitialDelegateIsEmpty() { + LazySet set = newLazySet(new HashSet()); + assertEquals(LazySet.EmptySet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatEmptySetAddUpgradesToSingletonSet() { + LazySet set = newLazySet(new HashSet()); + assertTrue(set.add("foo")); + assertEquals(LazySet.SingletonSet.class, set.getDelegate().getClass()); + + set = newLazySet(new HashSet()); + assertTrue(set.addAll(Arrays.asList("foo"))); + assertEquals(LazySet.SingletonSet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatEmptySetAddAllEmptySetDoesNotUpgradeToSingletonSet() { + LazySet set = newLazySet(new HashSet()); + assertFalse(set.addAll(Collections.emptySet())); + assertEquals(LazySet.EmptySet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatEmptySetAddAllUpgradesToFinalSet() { + Set delegate = new HashSet<>(); + LazySet set = newLazySet(delegate); + assertTrue(set.addAll(Arrays.asList("foo", "bar"))); + assertSame(delegate, set.getDelegate()); + assertEquals(2, delegate.size()); + assertTrue(delegate.contains("foo")); + assertTrue(delegate.contains("bar")); + } + + @Test + public void requireThatSingletonSetRemoveEntryDowngradesToEmptySet() { + LazySet set = newSingletonSet("foo"); + assertTrue(set.remove("foo")); + assertEquals(LazySet.EmptySet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonSetRemoveUnknownDoesNotDowngradesToEmptySet() { + LazySet set = newSingletonSet("foo"); + assertFalse(set.remove("bar")); + assertEquals(LazySet.SingletonSet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonSetAddAllEmptySetDoesNotUpgradeToFinalSet() { + LazySet set = newSingletonSet("foo"); + assertFalse(set.addAll(Collections.emptySet())); + assertEquals(LazySet.SingletonSet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonSetAddKnownDoesNotUpgradeToFinalSet() { + LazySet set = newSingletonSet("foo"); + assertFalse(set.add("foo")); + assertEquals(LazySet.SingletonSet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonSetAddUpgradesToFinalSet() { + Set delegate = new HashSet<>(); + LazySet set = newSingletonSet(delegate, "foo"); + assertTrue(set.add("bar")); + assertSame(delegate, set.getDelegate()); + assertEquals(2, delegate.size()); + assertTrue(delegate.contains("foo")); + assertTrue(delegate.contains("bar")); + } + + @Test + public void requireThatSingletonSetAddAllUpgradesToFinalSet() { + Set delegate = new HashSet<>(); + LazySet set = newSingletonSet(delegate, "foo"); + assertTrue(set.addAll(Arrays.asList("bar"))); + assertSame(delegate, set.getDelegate()); + assertEquals(2, delegate.size()); + assertTrue(delegate.contains("foo")); + assertTrue(delegate.contains("bar")); + + delegate = new HashSet<>(); + set = newSingletonSet(delegate, "foo"); + assertTrue(set.addAll(Arrays.asList("bar", "baz"))); + assertSame(delegate, set.getDelegate()); + assertEquals(3, delegate.size()); + assertTrue(delegate.contains("foo")); + assertTrue(delegate.contains("bar")); + assertTrue(delegate.contains("baz")); + } + + @Test + public void requireThatSingletonIteratorNextThrowsIfInvokedMoreThanOnce() { + LazySet set = newSingletonSet("foo"); + Iterator it = set.iterator(); + it.next(); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + + } + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + + } + } + + @Test + public void requireThatSingletonIteratorRemoveDowngradesToEmptySet() { + LazySet set = newSingletonSet("foo"); + Iterator it = set.iterator(); + it.next(); + it.remove(); + assertEquals(LazySet.EmptySet.class, set.getDelegate().getClass()); + } + + @Test + public void requireThatSingletonIteratorRemoveThrowsIfInvokedBeforeNext() { + LazySet set = newSingletonSet("foo"); + Iterator it = set.iterator(); + try { + it.remove(); + fail(); + } catch (IllegalStateException e) { + + } + } + + @SuppressWarnings("unchecked") + private static Set makeMockSet() { + return Mockito.mock(Set.class); + } + + @Test + public void requireThatSetDelegates() { + Set delegate = makeMockSet(); + Set set = newLazySet(delegate); + set.add("foo"); + set.add("bar"); // trigger the assignment of the delegate + Mockito.verify(delegate).add("foo"); + Mockito.verify(delegate).add("bar"); + + Set addAllArg = Collections.singleton("foo"); + set.addAll(addAllArg); + Mockito.verify(delegate).addAll(addAllArg); + + assertEquals(0, set.size()); + Mockito.verify(delegate).size(); + + assertFalse(set.isEmpty()); + Mockito.verify(delegate).isEmpty(); + + assertFalse(set.contains("foo")); + Mockito.verify(delegate).contains("foo"); + + assertNull(set.iterator()); + Mockito.verify(delegate).iterator(); + + assertNull(set.toArray()); + Mockito.verify(delegate).toArray(); + + String[] toArrayArg = new String[69]; + assertNull(set.toArray(toArrayArg)); + Mockito.verify(delegate).toArray(toArrayArg); + + assertFalse(set.remove("foo")); + Mockito.verify(delegate).remove("foo"); + + Collection containsAllArg = Collections.singletonList("foo"); + assertFalse(set.containsAll(containsAllArg)); + Mockito.verify(delegate).containsAll(containsAllArg); + + Collection retainAllArg = Collections.singletonList("foo"); + assertFalse(set.retainAll(retainAllArg)); + Mockito.verify(delegate).retainAll(retainAllArg); + + Collection removeAllArg = Collections.singletonList("foo"); + assertFalse(set.removeAll(removeAllArg)); + Mockito.verify(delegate).removeAll(removeAllArg); + + set.clear(); + Mockito.verify(delegate).clear(); + } + + @Test + public void requireThatHashCodeIsImplemented() { + assertEquals(newLazySet(null).hashCode(), + newLazySet(null).hashCode()); + } + + @Test + public void requireThatEqualsIsImplemented() { + Set lhs = newLazySet(new HashSet<>()); + Set rhs = newLazySet(new HashSet<>()); + assertEquals(lhs, lhs); + assertEquals(lhs, rhs); + + Object obj = new Object(); + lhs.add(obj); + assertEquals(lhs, lhs); + assertFalse(lhs.equals(rhs)); + rhs.add(obj); + assertEquals(lhs, rhs); + } + + @Test + public void requireThatHashSetFactoryDelegatesToAHashSet() { + LazySet set = LazySet.newHashSet(); + set.add(6); + set.add(9); + assertEquals(HashSet.class, set.getDelegate().getClass()); + } + + private static LazySet newSingletonSet(E element) { + return newSingletonSet(new HashSet(), element); + } + + private static LazySet newSingletonSet(Set delegate, E element) { + LazySet set = newLazySet(delegate); + set.add(element); + return set; + } + + private static LazySet newLazySet(final Set delegate) { + return new LazySet() { + + @Override + protected Set newDelegate() { + return delegate; + } + }; + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/ListMapTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/ListMapTestCase.java new file mode 100644 index 00000000000..29668676222 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/ListMapTestCase.java @@ -0,0 +1,153 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +/** + * @author Einar M R Rosenvinge + */ +public class ListMapTestCase { + + @Test + public void testSimple() { + ListMap stringMap = new ListMap<>(); + stringMap.put("foo", "bar"); + stringMap.put("foo", "far"); + stringMap.put("bar", "rab"); + + List fooValues = stringMap.get("foo"); + assertEquals(2, fooValues.size()); + assertEquals("bar", fooValues.get(0)); + assertEquals("far", fooValues.get(1)); + + List barValues = stringMap.get("bar"); + assertEquals(1, barValues.size()); + assertEquals("rab", barValues.get(0)); + } + + @Test + public void testAnotherImplementation() { + ListMap stringMap = new ListMap<>(IdentityHashMap.class); + String foo = "foo"; + String bar = "bar"; + String far = "far"; + String rab = "rab"; + + stringMap.put(foo, bar); + stringMap.put(foo, far); + stringMap.put(bar, rab); + + List fooValues = stringMap.get(new String("foo")); + assertEquals(0, fooValues.size()); + fooValues = stringMap.get(foo); + assertEquals(2, fooValues.size()); + assertEquals("bar", fooValues.get(0)); + assertEquals("far", fooValues.get(1)); + + + List barValues = stringMap.get(new String("bar")); + assertEquals(0, barValues.size()); + barValues = stringMap.get(bar); + assertEquals(1, barValues.size()); + assertEquals("rab", barValues.get(0)); + } + + @SuppressWarnings("serial") + private static class BoomMap extends HashMap { + @SuppressWarnings("unused") + BoomMap() { + throw new RuntimeException(); + } + } + + @Test + public void testExplodingImplementation() { + boolean illegalArgument = false; + try { + new ListMap(BoomMap.class); + } catch (IllegalArgumentException e) { + assertTrue(e.getCause().getClass() == RuntimeException.class); + illegalArgument = true; + } + assertTrue(illegalArgument); + } + + private static final String A = "A"; + private static final String B = "B"; + private static final String B0 = "b0"; + + private ListMap initSimpleMap() { + ListMap lm = new ListMap<>(); + lm.put(A, "a0"); + lm.put(A, "a1"); + lm.put(B, B0); + lm.put(B, "b1"); + lm.put("C", "c"); + lm.put("D", "d"); + return lm; + } + + @Test + public void testRemoval() { + ListMap lm = initSimpleMap(); + assertEquals(2, lm.getList(A).size()); + assertEquals(4, lm.entrySet().size()); + lm.removeAll(A); + assertEquals(3, lm.entrySet().size()); + assertEquals(0, lm.getList(A).size()); + assertEquals(2, lm.getList(B).size()); + assertTrue(lm.removeValue(B, B0)); + assertFalse(lm.removeValue(B, B0)); + assertEquals(1, lm.getList(B).size()); + assertEquals(3, lm.entrySet().size()); + } + + @Test + public void testGetSet() { + ListMap lm = initSimpleMap(); + lm.removeAll(B); + Set>> l = lm.entrySet(); + assertEquals(3, l.size()); + boolean hasA = false; + boolean hasB = false; + for (Map.Entry> e : l) { + if (e.getKey().equals(A)) { + hasA = true; + } else if (e.getKey().equals(B)) { + hasB = true; + } + } + assertTrue(hasA); + assertFalse(hasB); + } + + @Test + public void testFreeze() { + ListMap map = initSimpleMap(); + map.freeze(); + try { + map.put("key", "value"); + fail("Expected exception"); + } + catch (Exception expected) { + } + try { + map.entrySet().iterator().next().getValue().add("foo"); + fail("Expected exception"); + } + catch (Exception expected) { + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/ListenableArrayListTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/ListenableArrayListTestCase.java new file mode 100644 index 00000000000..e3fb48c7a0e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/ListenableArrayListTestCase.java @@ -0,0 +1,50 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.ListIterator; + +/** + * @author Jon Bratseth + */ +public class ListenableArrayListTestCase { + + @Test + public void testIt() { + ListenableArrayList list = new ListenableArrayList<>(); + ArrayListListener listener = new ArrayListListener(); + list.addListener(listener); + assertEquals(0,listener.invoked); + list.add("a"); + assertEquals(1,listener.invoked); + list.add(0,"b"); + assertEquals(2,listener.invoked); + list.addAll(Arrays.asList(new String[]{"c", "d"})); + assertEquals(3,listener.invoked); + list.addAll(1,Arrays.asList(new String[]{"e", "f"})); + assertEquals(4,listener.invoked); + list.set(0,"g"); + assertEquals(5,listener.invoked); + ListIterator i = list.listIterator(); + i.add("h"); + assertEquals(6,listener.invoked); + i.next(); + i.set("i"); + assertEquals(7,listener.invoked); + } + + private static class ArrayListListener implements Runnable { + + int invoked; + + @Override + public void run() { + invoked++; + } + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/MD5TestCase.java b/vespajlib/src/test/java/com/yahoo/collections/MD5TestCase.java new file mode 100644 index 00000000000..a107b21abb1 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/MD5TestCase.java @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +/** + * @author Einar M R Rosenvinge + */ +public class MD5TestCase extends junit.framework.TestCase { + public void testMD5() { + MD5 md5 = new MD5(); + int a = md5.hash("foobar"); + int b = md5.hash("foobar"); + + assertEquals(a, b); + + int c = md5.hash("foo"); + + assertTrue(a != c); + assertTrue(b != c); + + //rudimentary check; see that all four bytes contain something: + + assertTrue((a & 0xFF000000) != 0); + assertTrue((a & 0x00FF0000) != 0); + assertTrue((a & 0x0000FF00) != 0); + assertTrue((a & 0x000000FF) != 0); + + + assertTrue((c & 0xFF000000) != 0); + assertTrue((c & 0x00FF0000) != 0); + assertTrue((c & 0x0000FF00) != 0); + assertTrue((c & 0x000000FF) != 0); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/PredicateSplitTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/PredicateSplitTestCase.java new file mode 100644 index 00000000000..d1c040809de --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/PredicateSplitTestCase.java @@ -0,0 +1,30 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import org.junit.Test; + +import java.util.List; +import java.util.ArrayList; + +import static org.junit.Assert.assertEquals; + +public class PredicateSplitTestCase { + @Test + public void requireThatSplitWorks() { + List l = new ArrayList(); + l.add(1); + l.add(6); + l.add(2); + l.add(4); + l.add(5); + PredicateSplit result = PredicateSplit.partition(l, x -> (x % 2 == 0)); + assertEquals((long) result.falseValues.size(), 2L); + assertEquals((long) result.falseValues.get(0), 1L); + assertEquals((long) result.falseValues.get(1), 5L); + + assertEquals((long) result.trueValues.size(), 3L); + assertEquals((long) result.trueValues.get(0), 6L); + assertEquals((long) result.trueValues.get(1), 2L); + assertEquals((long) result.trueValues.get(2), 4L); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/TinyIdentitySetTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/TinyIdentitySetTestCase.java new file mode 100644 index 00000000000..2ba7262530b --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/TinyIdentitySetTestCase.java @@ -0,0 +1,302 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.junit.Test; + +/** + * Check TinyIdentitySet seems to work. :) + * + * @author Steinar Knutsen + */ +public final class TinyIdentitySetTestCase { + + @Test + public void testAdd() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final TinyIdentitySet t = new TinyIdentitySet<>(3); + t.add(a); + t.add(b); + assertEquals(2, t.size()); + t.add(string); + assertEquals(3, t.size()); + t.add(string); + t.add(a); + t.add(b); + assertEquals(3, t.size()); + + } + + @Test + public void testAddAll() { + final List stuff = doubleAdd(); + final TinyIdentitySet t = new TinyIdentitySet<>( + stuff.size()); + t.addAll(stuff); + assertEquals(stuff.size() / 2, t.size()); + } + + private List doubleAdd() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final String c = "c"; + final List stuff = new ArrayList<>(); + stuff.add(string); + stuff.add(a); + stuff.add(b); + stuff.add(c); + stuff.add(string); + stuff.add(a); + stuff.add(b); + stuff.add(c); + return stuff; + } + + @Test + public void testContains() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final TinyIdentitySet t = new TinyIdentitySet<>(2); + t.add(string); + t.add(a); + assertTrue(t.contains(a)); + assertTrue(t.contains(string)); + assertFalse(t.contains(b)); + } + + @Test + public void testContainsAll() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final String c = "c"; + final List stuff = new ArrayList<>(); + stuff.add(string); + stuff.add(a); + stuff.add(b); + final TinyIdentitySet t = new TinyIdentitySet<>( + stuff.size()); + t.addAll(stuff); + assertTrue(t.containsAll(stuff)); + stuff.add(c); + assertFalse(t.containsAll(stuff)); + } + + @Test + public void testRemove() { + final String string = "abc"; + final String a = new String(string); + final String b = new String(string); + final TinyIdentitySet t = new TinyIdentitySet<>(2); + t.add(string); + t.add(a); + assertFalse(t.remove(b)); + assertTrue(t.remove(a)); + assertFalse(t.remove(a)); + assertTrue(t.remove(string)); + assertFalse(t.remove(b)); + } + + @Test + public void testRetainAll() { + final List stuff = doubleAdd(); + final TinyIdentitySet t = new TinyIdentitySet<>( + stuff.size()); + t.addAll(stuff); + assertFalse(t.retainAll(stuff)); + assertEquals(stuff.size() / 2, t.size()); + t.add("nalle"); + assertEquals(stuff.size() / 2 + 1, t.size()); + assertTrue(t.retainAll(stuff)); + assertEquals(stuff.size() / 2, t.size()); + } + + @Test + public void testToArrayTArray() { + final List stuff = doubleAdd(); + final TinyIdentitySet t = new TinyIdentitySet<>( + stuff.size()); + t.addAll(stuff); + final String[] s = t.toArray(new String[0]); + assertEquals(t.size(), s.length); + assertEquals(stuff.size() / 2, s.length); + } + + @Test + public void testGrow() { + final TinyIdentitySet t = new TinyIdentitySet<>(5); + final int targetSize = 100; + for (int i = 0; i < targetSize; ++i) { + t.add(i); + } + assertEquals(targetSize, t.size()); + int n = 0; + for (final Iterator i = t.iterator(); i.hasNext();) { + assertEquals(Integer.valueOf(n++), i.next()); + } + assertEquals(targetSize, n); + } + + @Test + public void testBiggerRemoveAll() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>( + targetSize); + final Integer[] instances = new Integer[targetSize]; + final List remove = buildSubSet(targetSize, t, instances); + t.removeAll(remove); + assertEquals(targetSize / 2, t.size()); + for (final Iterator i = t.iterator(); i.hasNext();) { + final Integer n = i.next(); + assertTrue(n % 2 == 0); + assertFalse(remove.contains(n)); + + } + } + + @Test + public void testBiggerRetainAll() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>( + targetSize); + final Integer[] instances = new Integer[targetSize]; + final List retain = buildSubSet(targetSize, t, instances); + t.retainAll(retain); + assertEquals(targetSize / 2, t.size()); + for (final Iterator i = t.iterator(); i.hasNext();) { + final Integer n = i.next(); + assertTrue(n % 2 != 0); + assertTrue(retain.contains(n)); + } + } + + private List buildSubSet(final int targetSize, + final TinyIdentitySet t, final Integer[] instances) { + for (int i = 0; i < targetSize; ++i) { + instances[i] = Integer.valueOf(i); + t.add(instances[i]); + } + final List subset = new ArrayList<>(50); + for (int i = 0; i < targetSize; ++i) { + if (i % 2 != 0) { + subset.add(instances[i]); + } + } + return subset; + } + + @Test + public void testMuckingAbout() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>(3); + final Integer[] instances = new Integer[targetSize]; + final List retain = buildSubSet(targetSize, t, instances); + for (final Integer n : retain) { + t.remove(n); + assertEquals(targetSize - 1, t.size()); + t.add(n); + assertEquals(targetSize, t.size()); + } + assertEquals(targetSize, t.size()); + final Integer[] contents = t.toArray(new Integer[0]); + Arrays.sort(contents, 0, targetSize); + for (int i = 0; i < targetSize; ++i) { + assertEquals(instances[i], contents[i]); + } + } + + @Test + public void testMoreDuplicates() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>(3); + final Integer[] instances = new Integer[targetSize]; + final List add = buildSubSet(targetSize, t, instances); + assertEquals(targetSize, t.size()); + t.addAll(add); + assertEquals(targetSize, t.size()); + } + + @Test + public void testEmptySet() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>(0); + final Integer[] instances = new Integer[targetSize]; + final List add = buildSubSet(targetSize, t, instances); + for (Integer i : instances) { + t.remove(i); + } + assertEquals(0, t.size()); + for (Integer i : add) { + t.add(i); + } + assertEquals(targetSize / 2, t.size()); + } + + @Test + public void testSmallEmptySet() { + final TinyIdentitySet t = new TinyIdentitySet<>(3); + Integer a = new Integer(0), b = new Integer(1), c = new Integer(2); + t.add(a); + t.add(b); + t.add(c); + assertEquals(3, t.size()); + t.remove(a); + assertEquals(2, t.size()); + t.remove(c); + assertEquals(1, t.size()); + t.remove(c); + assertEquals(1, t.size()); + t.remove(b); + assertEquals(0, t.size()); + t.add(b); + assertEquals(1, t.size()); + t.add(b); + assertEquals(1, t.size()); + t.add(a); + assertEquals(2, t.size()); + t.add(a); + assertEquals(2, t.size()); + t.add(c); + assertEquals(3, t.size()); + t.add(c); + assertEquals(3, t.size()); + } + + @Test + public void testIterator() { + final int targetSize = 100; + final TinyIdentitySet t = new TinyIdentitySet<>(0); + final Integer[] instances = new Integer[targetSize]; + final List remove = buildSubSet(targetSize, t, instances); + int traversed = 0; + for (Iterator i = t.iterator(); i.hasNext();) { + Integer n = i.next(); + if (remove.contains(n)) { + i.remove(); + } + ++traversed; + } + assertEquals(targetSize, traversed); + assertEquals(targetSize / 2, t.size()); + for (int i = 0; i < instances.length; ++i) { + Integer n = instances[i]; + if (remove.contains(n)) { + assertFalse(t.contains(n)); + } else { + assertTrue(t.contains(n)); + } + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/TupleTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/TupleTestCase.java new file mode 100644 index 00000000000..8c7d25431a2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/TupleTestCase.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.collections; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Test case used for testing and experimenting with the tuple APIs. It seems + * Tuple4 is just as horrible as I first assumed, but using quick-fix funtions + * in the IDE made writing the code less painful than I guessed.. + * + * @author Steinar Knutsen + */ +public class TupleTestCase { + + private static final String _12 = "12"; + private static final Integer _11 = Integer.valueOf(11); + + Tuple2 instance = new Tuple2<>(_11, _12); + + + @Test + public final void objectStuff() { + boolean hashException = false; + boolean equalsException = false; + assertEquals("Tuple2(11, 12)", instance.toString()); + try { + instance.hashCode(); + } catch (UnsupportedOperationException e) { + hashException = true; + } + assertTrue(hashException); + try { + instance.equals(null); + } catch (UnsupportedOperationException e) { + equalsException = true; + } + assertTrue(equalsException); + } + + @Test + public final void basicUse() { + assertSame(_11, instance.first); + assertSame(_12, instance.second); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/compress/IntegerCompressorTest.java b/vespajlib/src/test/java/com/yahoo/compress/IntegerCompressorTest.java new file mode 100644 index 00000000000..46a70a4c956 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/compress/IntegerCompressorTest.java @@ -0,0 +1,105 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.compress; + +import org.junit.Test; + +import java.nio.ByteBuffer; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * TODO: balder + */ +public class IntegerCompressorTest { + private void verifyPositiveNumber(int n, byte [] expected) { + ByteBuffer buf = ByteBuffer.allocate(expected.length); + IntegerCompressor.putCompressedPositiveNumber(n, buf); + assertArrayEquals(expected, buf.array()); + } + private void verifyNumber(int n, byte [] expected) { + ByteBuffer buf = ByteBuffer.allocate(expected.length); + IntegerCompressor.putCompressedNumber(n, buf); + assertArrayEquals(expected, buf.array()); + } + + @Test + public void requireThatPositiveNumberCompressCorrectly() { + byte [] zero = {0}; + verifyPositiveNumber(0, zero); + byte [] one = {0x01}; + verifyPositiveNumber(1, one); + byte [] x3f = {0x3f}; + verifyPositiveNumber(0x3f, x3f); + byte [] x40 = {(byte)0x80,0x40}; + verifyPositiveNumber(0x40, x40); + byte [] x3fff = {(byte)0xbf, (byte)0xff}; + verifyPositiveNumber(0x3fff, x3fff); + byte [] x4000 = {(byte)0xc0, 0x00, 0x40, 0x00}; + verifyPositiveNumber(0x4000, x4000); + byte [] x3fffffff = {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}; + verifyPositiveNumber(0x3fffffff, x3fffffff); + byte [] x40000000 = {0,0,0,0}; + try { + verifyPositiveNumber(0x40000000, x40000000); + assertTrue(false); + } catch (IllegalArgumentException e) { + assertEquals("Number '1073741824' too big, must extend encoding", e.getMessage()); + } + try { + verifyPositiveNumber(-1, x40000000); + assertTrue(false); + } catch (IllegalArgumentException e) { + assertEquals("Number '-1' must be positive", e.getMessage()); + } + } + + @Test + public void requireThatNumberCompressCorrectly() { + byte [] zero = {0}; + verifyNumber(0, zero); + byte [] one = {0x01}; + verifyNumber(1, one); + byte [] x1f = {0x1f}; + verifyNumber(0x1f, x1f); + byte [] x20 = {0x40,0x20}; + verifyNumber(0x20, x20); + byte [] x1fff = {0x5f, (byte)0xff}; + verifyNumber(0x1fff, x1fff); + byte [] x2000 = {0x60, 0x00, 0x20, 0x00}; + verifyNumber(0x2000, x2000); + byte [] x1fffffff = {0x7f, (byte)0xff, (byte)0xff, (byte)0xff}; + verifyNumber(0x1fffffff, x1fffffff); + byte [] x20000000 = {0,0,0,0}; + try { + verifyNumber(0x20000000, x20000000); + assertTrue(false); + } catch (IllegalArgumentException e) { + assertEquals("Number '536870912' too big, must extend encoding", e.getMessage()); + } + byte [] mzero = {(byte)0x81}; + verifyNumber(-1, mzero); + byte [] mone = {(byte)0x82}; + verifyNumber(-2, mone); + byte [] mx1f = {(byte)0x9f}; + verifyNumber(-0x1f, mx1f); + byte [] mx20 = {(byte)0xc0,0x20}; + verifyNumber(-0x20, mx20); + byte [] mx1fff = {(byte)0xdf, (byte)0xff}; + verifyNumber(-0x1fff, mx1fff); + byte [] mx2000 = {(byte)0xe0, 0x00, 0x20, 0x00}; + verifyNumber(-0x2000, mx2000); + byte [] mx1fffffff = {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}; + verifyNumber(-0x1fffffff, mx1fffffff); + byte [] mx20000000 = {0,0,0,0}; + try { + verifyNumber(-0x20000000, mx20000000); + assertTrue(false); + } catch (IllegalArgumentException e) { + assertEquals("Number '-536870912' too big, must extend encoding", e.getMessage()); + } + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/CopyOnWriteHashMapTest.java b/vespajlib/src/test/java/com/yahoo/concurrent/CopyOnWriteHashMapTest.java new file mode 100644 index 00000000000..22619e3865e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/CopyOnWriteHashMapTest.java @@ -0,0 +1,106 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.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 Henning Baldersheim + * @since 5.2 + */ +public class CopyOnWriteHashMapTest { + + @Test + public void requireThatAccessorsWork() { + Map 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 map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator> it = map.entrySet().iterator(); + assertEquals("fooVal", map.remove("fooKey")); + + assertTrue(it.hasNext()); + Map.Entry entry = it.next(); + assertEquals("fooKey", entry.getKey()); + assertEquals("fooVal", entry.getValue()); + } + + @Test + public void requireThatKeySetDoesNotReflectConcurrentModifications() { + Map map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator it = map.keySet().iterator(); + assertEquals("fooVal", map.remove("fooKey")); + + assertTrue(it.hasNext()); + assertEquals("fooKey", it.next()); + } + + @Test + public void requireThatValuesDoNotReflectConcurrentModifications() { + Map map = new CopyOnWriteHashMap<>(); + map.put("fooKey", "fooVal"); + + Iterator 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/concurrent/EventBarrierTestCase.java b/vespajlib/src/test/java/com/yahoo/concurrent/EventBarrierTestCase.java new file mode 100644 index 00000000000..eae792effd4 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/EventBarrierTestCase.java @@ -0,0 +1,168 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import junit.framework.TestCase; + +/** + * @author Simon Thoresen + */ +public class EventBarrierTestCase extends TestCase { + + public void testEmpty() { + // waiting for an empty set of events + Barrier b = new Barrier(); + EventBarrier eb = new EventBarrier(); + + assertTrue(!eb.startBarrier(b)); + assertTrue(!b.done); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + + int token = eb.startEvent(); + eb.completeEvent(token); + + assertTrue(!eb.startBarrier(b)); + assertTrue(!b.done); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + } + + public void testSimple() { + // a single barrier waiting for a single event + Barrier b = new Barrier(); + EventBarrier eb = new EventBarrier(); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + + int token = eb.startEvent(); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 0); + + assertTrue(eb.startBarrier(b)); + assertTrue(!b.done); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 1); + + eb.completeEvent(token); + assertTrue(b.done); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + } + + public void testBarrierChain() { + // more than one barrier waiting for the same set of events + Barrier b1 = new Barrier(); + Barrier b2 = new Barrier(); + Barrier b3 = new Barrier(); + EventBarrier eb = new EventBarrier(); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + + int token = eb.startEvent(); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 0); + + assertTrue(eb.startBarrier(b1)); + assertTrue(eb.startBarrier(b2)); + assertTrue(eb.startBarrier(b3)); + assertTrue(!b1.done); + assertTrue(!b2.done); + assertTrue(!b3.done); + + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 3); + + eb.completeEvent(token); + assertTrue(b1.done); + assertTrue(b2.done); + assertTrue(b3.done); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + } + + public void testEventAfter() { + // new events starting after the start of a barrier + Barrier b = new Barrier(); + EventBarrier eb = new EventBarrier(); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + + int token = eb.startEvent(); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 0); + + assertTrue(eb.startBarrier(b)); + assertTrue(!b.done); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 1); + + int t2 = eb.startEvent(); + assertTrue(!b.done); + assertEquals(eb.getNumEvents(), 2); + assertEquals(eb.getNumBarriers(), 1); + + eb.completeEvent(token); + assertTrue(b.done); + assertEquals(eb.getNumEvents(), 1); + assertEquals(eb.getNumBarriers(), 0); + + eb.completeEvent(t2); + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + } + + public void testReorder() { + // events completing in a different order than they started + Barrier b1 = new Barrier(); + Barrier b2 = new Barrier(); + Barrier b3 = new Barrier(); + EventBarrier eb = new EventBarrier(); + + int t1 = eb.startEvent(); + eb.startBarrier(b1); + int t2 = eb.startEvent(); + eb.startBarrier(b2); + int t3 = eb.startEvent(); + eb.startBarrier(b3); + int t4 = eb.startEvent(); + + assertEquals(eb.getNumEvents(), 4); + assertEquals(eb.getNumBarriers(), 3); + + assertTrue(!b1.done); + assertTrue(!b2.done); + assertTrue(!b3.done); + + eb.completeEvent(t4); + assertTrue(!b1.done); + assertTrue(!b2.done); + assertTrue(!b3.done); + + eb.completeEvent(t3); + assertTrue(!b1.done); + assertTrue(!b2.done); + assertTrue(!b3.done); + + eb.completeEvent(t1); + assertTrue(b1.done); + assertTrue(!b2.done); + assertTrue(!b3.done); + + eb.completeEvent(t2); + assertTrue(b1.done); + assertTrue(b2.done); + assertTrue(b3.done); + + assertEquals(eb.getNumEvents(), 0); + assertEquals(eb.getNumBarriers(), 0); + } + + private static class Barrier implements EventBarrier.BarrierWaiter { + boolean done = false; + + @Override + public void completeBarrier() { + done = true; + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/ExecutorsTestCase.java b/vespajlib/src/test/java/com/yahoo/concurrent/ExecutorsTestCase.java new file mode 100644 index 00000000000..b8f2b0e5c58 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/ExecutorsTestCase.java @@ -0,0 +1,139 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Ignore; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class ExecutorsTestCase { + static private class Runner implements Runnable { + static private AtomicInteger threadCount = new AtomicInteger(0); + static private class ThreadId extends ThreadLocal { + @Override + protected Integer initialValue() { + return new Integer(threadCount.getAndIncrement()); + } + } + static private ThreadId threadId = new ThreadId(); + private volatile int runBy = -1; + @Override + public void run() { + runBy = threadId.get(); + } + int getRunBy() { return runBy; } + } + + private static class Producer implements Runnable { + private volatile int maxThreadId = 0; + private final long timeOutMS; + private final ExecutorService consumer; + Producer(ExecutorService consumer, long timeOutMS) { + this.timeOutMS = timeOutMS; + this.consumer = consumer; + } + @Override + public void run() { + long now = System.currentTimeMillis(); + Runner r = new Runner(); + try { + while (now + timeOutMS > System.currentTimeMillis()) { + Future f = consumer.submit(r); + f.get(); + maxThreadId = Math.max(maxThreadId, r.getRunBy()); + Thread.sleep(1); + + } + } catch (InterruptedException e) { + assertTrue(false); + } catch (ExecutionException e) { + assertTrue(false); + } + + } + } + + private void assertThreadId(ExecutorService s, int id) throws InterruptedException, ExecutionException { + Runner r = new Runner(); + Future f = s.submit(r); + assertNull(f.get()); + assertEquals(id, r.getRunBy()); + } + private void assertRoundRobinOrder(ExecutorService s) throws InterruptedException, ExecutionException { + assertThreadId(s, 0); + assertThreadId(s, 1); + assertThreadId(s, 2); + assertThreadId(s, 0); + assertThreadId(s, 1); + assertThreadId(s, 2); + assertThreadId(s, 0); + assertThreadId(s, 1); + } + private int measureMaxNumThreadsUsage(ThreadPoolExecutor s, long durationMS, int maxProducers) throws InterruptedException, ExecutionException { + s.prestartAllCoreThreads(); + ExecutorService consumers = Executors.newCachedThreadPool(); + LinkedList> futures = new LinkedList<>(); + for (int i = 0; i < maxProducers; i++) { + Producer p = new Producer(s, durationMS); + futures.add(consumers.submit(p, p)); + } + int maxThreadId = 0; + try { + while (! futures.isEmpty()) { + Producer p = futures.remove().get(); + maxThreadId = Math.max(maxThreadId, p.maxThreadId); + } + } catch (InterruptedException e) { + assertTrue(false); + } catch (ExecutionException e) { + assertTrue(false); + } + return maxThreadId; + } + private void assertStackOrder(ThreadPoolExecutor s) throws InterruptedException, ExecutionException { + s.prestartAllCoreThreads(); + Thread.sleep(10); //Sleep to allow last executing thread to get back on the stack + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + Thread.sleep(10); + assertThreadId(s, 0); + } + + @Ignore // Ignored as it is not deterministic, and probably hard to make deterministic to. + @Test + public void requireThatExecutionOrderIsPredictable() throws InterruptedException, ExecutionException { + Runner.threadCount.set(0); + assertRoundRobinOrder(new ThreadPoolExecutor(3, 3, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue())); + Runner.threadCount.set(0); + assertRoundRobinOrder(new ThreadPoolExecutor(3, 3, 0L, TimeUnit.SECONDS, new SynchronousQueue(true))); + Runner.threadCount.set(0); + assertStackOrder(new ThreadPoolExecutor(3, 3, 0L, TimeUnit.SECONDS, new SynchronousQueue(false))); + } + + @Ignore // Ignored as it might not be deterministic + public void requireThatExecutionOrderIsPredictableUnderLoad() throws InterruptedException, ExecutionException { + Runner.threadCount.set(0); + assertEquals(99, measureMaxNumThreadsUsage(new ThreadPoolExecutor(100, 100, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue()), 3000, 10)); + Runner.threadCount.set(0); + assertEquals(99, measureMaxNumThreadsUsage(new ThreadPoolExecutor(100, 100, 0L, TimeUnit.SECONDS, new SynchronousQueue(true)), 3000, 10)); + Runner.threadCount.set(0); + //Max 9 concurrent tasks. Might not be deterministic + assertEquals(9, measureMaxNumThreadsUsage(new ThreadPoolExecutor(100, 100, 0L, TimeUnit.SECONDS, new SynchronousQueue(false)), 3000, 10)); + Runner.threadCount.set(0); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/ReceiverTestCase.java b/vespajlib/src/test/java/com/yahoo/concurrent/ReceiverTestCase.java new file mode 100644 index 00000000000..88d5283f46a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/ReceiverTestCase.java @@ -0,0 +1,59 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.yahoo.collections.Tuple2; + +/** + * Check for com.yahoo.concurrent.Receiver. + * + * @author Steinar Knutsen + */ +public class ReceiverTestCase { + + private static class Worker implements Runnable { + private static final String HELLO_WORLD = "Hello, World!"; + private final Receiver receiver; + private final long timeToWait; + + Worker(Receiver receiver, long timeToWait) { + this.receiver = receiver; + this.timeToWait = timeToWait; + } + + @Override + public void run() { + try { + Thread.sleep(timeToWait); + } catch (InterruptedException e) { + fail("Test was interrupted."); + } + receiver.put(HELLO_WORLD); + } + } + + @Test + public void testPut() throws InterruptedException { + Receiver receiver = new Receiver<>(); + Worker runnable = new Worker(receiver, 0); + Thread worker = new Thread(runnable); + worker.start(); + Tuple2 answer = receiver.get(1000L * 1000L * 1000L); + assertEquals(Receiver.MessageState.VALID, answer.first); + assertEquals(answer.second, Worker.HELLO_WORLD); + } + + @Test + public void testTimeOut() throws InterruptedException { + Receiver receiver = new Receiver<>(); + Worker runnable = new Worker(receiver, 1000L * 1000L * 1000L); + Thread worker = new Thread(runnable); + worker.start(); + Tuple2 answer = receiver.get(500L); + assertEquals(Receiver.MessageState.TIMEOUT, answer.first); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/ThreadFactoryFactoryTest.java b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadFactoryFactoryTest.java new file mode 100644 index 00000000000..7fc6a9cc390 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadFactoryFactoryTest.java @@ -0,0 +1,44 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import org.junit.Test; + + +import java.util.concurrent.ThreadFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +/** + * Created with IntelliJ IDEA. + * User: balder + * Date: 26.04.13 + * Time: 12:01 + * To change this template use File | Settings | File Templates. + */ +public class ThreadFactoryFactoryTest { + + static class Runner implements Runnable { + @Override + public void run() { + + } + } + + @Test + public void requireThatFactoryCreatesCorrectlyNamedThreads() { + Thread thread = ThreadFactoryFactory.getThreadFactory("a").newThread(new Runner()); + assertEquals("a-1-thread-1", thread.getName()); + thread = ThreadFactoryFactory.getThreadFactory("a").newThread(new Runner()); + assertEquals("a-2-thread-1", thread.getName()); + thread = ThreadFactoryFactory.getThreadFactory("b").newThread(new Runner()); + assertEquals("b-1-thread-1", thread.getName()); + ThreadFactory factory = ThreadFactoryFactory.getThreadFactory("a"); + thread = factory.newThread(new Runner()); + assertEquals("a-3-thread-1", thread.getName()); + thread = factory.newThread(new Runner()); + assertEquals("a-3-thread-2", thread.getName()); + thread = factory.newThread(new Runner()); + assertEquals("a-3-thread-3", thread.getName()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/ThreadLocalDirectoryTestCase.java b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadLocalDirectoryTestCase.java new file mode 100644 index 00000000000..d813ae1e18d --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadLocalDirectoryTestCase.java @@ -0,0 +1,125 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +/** + * Smoke test for multi producer data structure. + * + *

+ * TODO sorely needs nastier cases + *

+ * + * @author Steinar Knutsen + */ +public class ThreadLocalDirectoryTestCase { + private static class SumUpdater implements ThreadLocalDirectory.Updater { + + @Override + public Integer update(Integer current, Integer x) { + return Integer.valueOf(current.intValue() + x.intValue()); + } + + @Override + public Integer createGenerationInstance(Integer previous) { + return Integer.valueOf(0); + } + } + + private static class ObservableSumUpdater extends SumUpdater implements ThreadLocalDirectory.ObservableUpdater { + + @Override + public Integer copy(Integer current) { + return current; + } + } + + + private static class Counter implements Runnable { + ThreadLocalDirectory r; + + Counter(ThreadLocalDirectory r) { + this.r = r; + } + + @Override + public void run() { + LocalInstance s = r.getLocalInstance(); + for (int i = 0; i < 500; ++i) { + put(s, i); + } + } + + void put(LocalInstance s, int i) { + r.update(Integer.valueOf(i), s); + } + } + + private static class CounterAndViewer extends Counter { + CounterAndViewer(ThreadLocalDirectory r) { + super(r); + } + + @Override + void put(LocalInstance s, int i) { + super.put(s, i); + if (i % 10 == 0) { + r.view(); + } + } + } + + @Test + public void sumFromMultipleThreads() { + SumUpdater updater = new SumUpdater(); + ThreadLocalDirectory s = new ThreadLocalDirectory<>(updater); + Thread[] threads = new Thread[500]; + for (int i = 0; i < 500; ++i) { + Counter c = new Counter(s); + threads[i] = new Thread(c); + } + runAll(threads); + List measurements = s.fetch(); + int sum = 0; + for (Integer i : measurements) { + sum += i.intValue(); + } + assertTrue("Data lost.", 62375000 == sum); + } + + @Test + public void sumAndViewFromMultipleThreads() { + ObservableSumUpdater updater = new ObservableSumUpdater(); + ThreadLocalDirectory s = new ThreadLocalDirectory<>(updater); + Thread[] threads = new Thread[500]; + for (int i = 0; i < 500; ++i) { + CounterAndViewer c = new CounterAndViewer(s); + threads[i] = new Thread(c); + } + runAll(threads); + List measurements = s.fetch(); + int sum = 0; + for (Integer i : measurements) { + sum += i.intValue(); + } + assertTrue("Data lost.", 62375000 == sum); + } + + + private void runAll(Thread[] threads) { + for (Thread t : threads) { + t.start(); + } + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + // nop + } + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/concurrent/ThreadRobustListTestCase.java b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadRobustListTestCase.java new file mode 100644 index 00000000000..88c7a962c95 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/concurrent/ThreadRobustListTestCase.java @@ -0,0 +1,103 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.concurrent; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import java.util.Iterator; + +import org.junit.Test; + +/** + * Check we keep the consistent view when reading and writing in parallell. + * + * @author Steinar Knutsen + */ +public class ThreadRobustListTestCase { + + private static class Writer implements Runnable { + private final ThreadRobustList l; + private final Receiver sharedLock; + + public Writer(final ThreadRobustList l, + final Receiver sharedLock) { + this.sharedLock = sharedLock; + this.l = l; + } + + @Override + public void run() { + for (int i = 0; i < 5; ++i) { + l.add(String.valueOf(i)); + } + sharedLock.put(Boolean.TRUE); + for (int i = 5; i < 100 * 1000; ++i) { + l.add(String.valueOf(i)); + } + } + + } + + private static class Reader implements Runnable { + private final ThreadRobustList l; + private final Receiver sharedLock; + + public Reader(final ThreadRobustList l, + final Receiver sharedLock) { + this.sharedLock = sharedLock; + this.l = l; + } + + @Override + public void run() { + int n; + int previous; + + try { + sharedLock.get(5 * 60 * 1000); + } catch (final InterruptedException e) { + fail("Test interrupted."); + } + n = countElements(); + assertFalse(n < 5); + previous = n; + for (int i = 0; i < 1000; ++i) { + int reverse = reverseCountElements(); + n = countElements(); + assertFalse(n < reverse); + assertFalse(n < previous); + previous = n; + } + } + + private int reverseCountElements() { + int n = 0; + for (final Iterator j = l.reverseIterator(); j.hasNext(); j.next()) { + ++n; + } + return n; + } + + private int countElements() { + int n = 0; + for (final Iterator j = l.iterator(); j.hasNext(); j.next()) { + ++n; + } + return n; + } + } + + @Test + public final void test() throws InterruptedException { + final ThreadRobustList container = new ThreadRobustList<>(); + final Receiver lock = new Receiver<>(); + final Reader r = new Reader(container, lock); + final Writer w = new Writer(container, lock); + final Thread wt = new Thread(w); + wt.start(); + r.run(); + wt.join(); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/data/access/InspectorConformanceTestBase.java b/vespajlib/src/test/java/com/yahoo/data/access/InspectorConformanceTestBase.java new file mode 100644 index 00000000000..4cf449fbf4f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/data/access/InspectorConformanceTestBase.java @@ -0,0 +1,365 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.data.access; + +import org.junit.Test; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; +import com.yahoo.data.access.Inspector; +import com.yahoo.data.access.ArrayTraverser; +import com.yahoo.data.access.ObjectTraverser; +import com.yahoo.data.access.Type; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +abstract public class InspectorConformanceTestBase { + + public abstract static class Try { + abstract void f(); + public Exception call() { + try { + f(); + } catch (Exception e) { + return e; + } + return null; + } + } + + public static class Entries implements ArrayTraverser { + List entries = new ArrayList<>(); + public void entry(int idx, Inspector inspector) { + entries.add(inspector); + } + public Entries traverse(Inspector value) { + value.traverse(this); + return this; + } + public Entries iterate(Inspector value) { + for (Inspector itr: value.entries()) { + entries.add(itr); + } + return this; + } + public Entries add(Inspector value) { + entries.add(value); + return this; + } + } + + public static class Fields implements ObjectTraverser { + Map fields = new HashMap<>(); + public void field(String name, Inspector inspector) { + fields.put(name, inspector); + } + public Fields traverse(Inspector value) { + value.traverse(this); + return this; + } + public Fields iterate(Inspector value) { + for (Map.Entry itr: value.fields()) { + fields.put(itr.getKey(), itr.getValue()); + } + return this; + } + public Fields add(String name, Inspector value) { + fields.put(name, value); + return this; + } + } + + // This method must be implemented by all tests of concrete + // implementations to return an inspector to a structured object + // on the following form (for an example, take a look at + // com.yahoo.data.access.simple.InspectorConformanceTestCase): + // + // ARRAY { + // [0]: EMPTY + // [1]: BOOL: true + // [2]: LONG: 10 + // [3]: DOUBLE: 5.75 + // [4]: OBJECT { + // "foo": STRING: "foo_value" + // "bar": DATA: 0x04 0x02 + // "nested": ARRAY { + // [0]: OBJECT { + // "hidden": STRING: "treasure" + // } + // } + // } + // } + public abstract Inspector getData(); + + @Test + public void testSelfInspectableInspector() throws Exception { + final Inspector value = getData(); + final Inspector self = value.inspect(); + assertThat(self, is(value)); + } + + @Test + public void testInvalidValue() throws Exception { + final Inspector value = getData().entry(10).field("bogus").entry(0); + assertThat(value.valid(), is(false)); + assertThat(value.type(), is(Type.EMPTY)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testEmptyValue() throws Exception { + final Inspector value = getData().entry(0); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.EMPTY)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(value.asBool(), is(false)); + assertThat(value.asLong(), is(0L)); + assertThat(value.asDouble(), is(0.0)); + assertThat(value.asString(), is("")); + assertThat(value.asUtf8(), is(new byte[0])); + assertThat(value.asData(), is(new byte[0])); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testBoolValue() throws Exception { + final Inspector value = getData().entry(1); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.BOOL)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(value.asBool(), is(true)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(false), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testLongValue() throws Exception { + final Inspector value = getData().entry(2); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.LONG)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asLong(), is(10L)); + assertThat(value.asDouble(), is(10.0)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(10L)); + assertThat(value.asDouble(20.25), is(10.0)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testDoubleValue() throws Exception { + final Inspector value = getData().entry(3); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.DOUBLE)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asLong(), is(5L)); + assertThat(value.asDouble(), is(5.75)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(5L)); + assertThat(value.asDouble(20.25), is(5.75)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testStringValue() throws Exception { + final Inspector value = getData().entry(4).field("foo"); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.STRING)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asString(), is("foo_value")); + assertThat(value.asUtf8(), is("foo_value".getBytes("UTF-8"))); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("foo_value")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("foo_value".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testDataValue() throws Exception { + final Inspector value = getData().entry(4).field("bar"); + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.DATA)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asData(), is(new byte[] { (byte)4, (byte)2 })); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is(new byte[] { (byte)4, (byte)2 })); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testArrayValue() throws Exception { + final Inspector value = getData(); + List expected_entries = new Entries() + .add(value.entry(0)) + .add(value.entry(1)) + .add(value.entry(2)) + .add(value.entry(3)) + .add(value.entry(4)).entries; + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.ARRAY)); + assertThat(value.entryCount(), is(expected_entries.size())); + assertThat(value.fieldCount(), is(0)); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries, is(expected_entries)); + assertThat(new Fields().traverse(value).fields.size(), is(0)); + assertThat(value.entry(10).valid(), is(false)); + assertThat(value.field("foo").valid(), is(false)); + assertThat(new Entries().iterate(value).entries, is(expected_entries)); + assertThat(new Fields().iterate(value).fields.size(), is(0)); + } + + @Test + public void testObjectValue() throws Exception { + final Inspector value = getData().entry(4); + Map expected_fields = new Fields() + .add("foo", value.field("foo")) + .add("bar", value.field("bar")) + .add("nested", value.field("nested")).fields; + assertThat(value.valid(), is(true)); + assertThat(value.type(), is(Type.OBJECT)); + assertThat(value.entryCount(), is(0)); + assertThat(value.fieldCount(), is(expected_fields.size())); + assertThat(new Try(){void f() { value.asBool(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asLong(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asDouble(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asString(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asUtf8(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(new Try(){void f() { value.asData(); }}.call(), instanceOf(IllegalStateException.class)); + assertThat(value.asBool(true), is(true)); + assertThat(value.asLong(50), is(50L)); + assertThat(value.asDouble(20.25), is(20.25)); + assertThat(value.asString("default"), is("default")); + assertThat(value.asUtf8("utf8".getBytes("UTF-8")), is("utf8".getBytes("UTF-8"))); + assertThat(value.asData("data".getBytes("UTF-8")), is("data".getBytes("UTF-8"))); + assertThat(new Entries().traverse(value).entries.size(), is(0)); + assertThat(new Fields().traverse(value).fields, is(expected_fields)); + assertThat(value.entry(0).valid(), is(false)); + assertThat(value.field("bogus").valid(), is(false)); + assertThat(new Entries().iterate(value).entries.size(), is(0)); + assertThat(new Fields().iterate(value).fields, is(expected_fields)); + } + + @Test + public void testNesting() throws Exception { + Inspector value1 = getData().entry(4).field("nested"); + assertThat(value1.type(), is(Type.ARRAY)); + Inspector value2 = value1.entry(0); + assertThat(value2.type(), is(Type.OBJECT)); + Inspector value3 = value2.field("hidden"); + assertThat(value3.type(), is(Type.STRING)); + assertThat(value3.asString(), is("treasure")); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/data/access/simple/SimpleConformanceTestCase.java b/vespajlib/src/test/java/com/yahoo/data/access/simple/SimpleConformanceTestCase.java new file mode 100644 index 00000000000..4db5d0afde7 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/data/access/simple/SimpleConformanceTestCase.java @@ -0,0 +1,55 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.data.access.simple; + + +import org.junit.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + + +public class SimpleConformanceTestCase extends com.yahoo.data.access.InspectorConformanceTestBase { + + // ARRAY { + // [0]: EMPTY + // [1]: BOOL: true + // [2]: LONG: 10 + // [3]: DOUBLE: 5.75 + // [4]: OBJECT { + // "foo": STRING: "foo_value" + // "bar": DATA: 0x04 0x02 + // "nested": ARRAY { + // [0]: OBJECT { + // "hidden": STRING: "treasure" + // } + // } + // } + // } + public com.yahoo.data.access.Inspector getData() { + return new Value.ArrayValue() + .add(new Value.EmptyValue()) + .add(new Value.BoolValue(true)) + .add(new Value.LongValue(10L)) + .add(new Value.DoubleValue(5.75)) + .add(new Value.ObjectValue() + .put("foo", new Value.StringValue("foo_value")) + .put("bar", new Value.DataValue(new byte[] { (byte)4, (byte)2 })) + .put("nested", new Value.ArrayValue() + .add(new Value.ObjectValue() + .put("hidden", new Value.StringValue("treasure"))))); + } + + @Test + public void testSingletons() { + assertThat(Value.empty().valid(), is(true)); + assertThat(Value.empty().type(), is(com.yahoo.data.access.Type.EMPTY)); + assertThat(Value.invalid().valid(), is(false)); + assertThat(Value.invalid().type(), is(com.yahoo.data.access.Type.EMPTY)); + } + + @Test + public void testToString() { + String json = getData().toString(); + String correct = "[null,true,10,5.75,{\"foo\":\"foo_value\",\"bar\":\"0x0402\",\"nested\":[{\"hidden\":\"treasure\"}]}]"; + assertThat(json, is(correct)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/data/access/slime/SlimeConformanceTestCase.java b/vespajlib/src/test/java/com/yahoo/data/access/slime/SlimeConformanceTestCase.java new file mode 100644 index 00000000000..ff6e98cfa37 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/data/access/slime/SlimeConformanceTestCase.java @@ -0,0 +1,45 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.data.access.slime; + + +public class SlimeConformanceTestCase extends com.yahoo.data.access.InspectorConformanceTestBase { + + // ARRAY { + // [0]: EMPTY + // [1]: BOOL: true + // [2]: LONG: 10 + // [3]: DOUBLE: 5.75 + // [4]: OBJECT { + // "foo": STRING: "foo_value" + // "bar": DATA: 0x04 0x02 + // "nested": ARRAY { + // [0]: OBJECT { + // "hidden": STRING: "treasure" + // } + // } + // } + // } + public com.yahoo.data.access.Inspector getData() { + com.yahoo.slime.Slime slime = new com.yahoo.slime.Slime(); + { + com.yahoo.slime.Cursor arr = slime.setArray(); + arr.addNix(); + arr.addBool(true); + arr.addLong(10); + arr.addDouble(5.75); + { + com.yahoo.slime.Cursor obj = arr.addObject(); + obj.setString("foo", "foo_value"); + obj.setData("bar", new byte[] { (byte)4, (byte)2 }); + { + com.yahoo.slime.Cursor nested_array = obj.setArray("nested"); + { + com.yahoo.slime.Cursor nested_object = nested_array.addObject(); + nested_object.setString("hidden", "treasure"); + } + } + } + } + return new SlimeAdapter(slime.get()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/data/inspect/slime/.gitignore b/vespajlib/src/test/java/com/yahoo/data/inspect/slime/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vespajlib/src/test/java/com/yahoo/geo/BoundingBoxParserTestCase.java b/vespajlib/src/test/java/com/yahoo/geo/BoundingBoxParserTestCase.java new file mode 100644 index 00000000000..47a8ade2235 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/geo/BoundingBoxParserTestCase.java @@ -0,0 +1,162 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.geo; + +/** + * Tests for the BoundingBoxParser class. + * + * @author Arne J + */ +public class BoundingBoxParserTestCase extends junit.framework.TestCase { + + private BoundingBoxParser parser; + + public BoundingBoxParserTestCase(String name) { + super(name); + } + + private void allZero(BoundingBoxParser data) { + assertEquals(0d, data.n); + assertEquals(0d, data.s); + assertEquals(0d, data.e); + assertEquals(0d, data.w); + } + + private void all1234(BoundingBoxParser data) { + assertEquals(1d, data.n); + assertEquals(2d, data.s); + assertEquals(3d, data.e); + assertEquals(4d, data.w); + } + + /** + * Tests different inputs that should all produce 0 + */ + public void testZero() { + parser = new BoundingBoxParser("n=0,s=0,e=0,w=0"); + allZero(parser); + parser = new BoundingBoxParser("N=0,S=0,E=0,W=0"); + allZero(parser); + parser = new BoundingBoxParser("NORTH=0,SOUTH=0,EAST=0,WEST=0"); + allZero(parser); + parser = new BoundingBoxParser("north=0,south=0,east=0,west=0"); + allZero(parser); + parser = new BoundingBoxParser("n=0.0,s=0.0e-17,e=0.0e0,w=0.0e100"); + allZero(parser); + parser = new BoundingBoxParser("s:0.0,w:0.0,n:0.0,e:0.0"); + allZero(parser); + parser = new BoundingBoxParser("s:0.0,w:0.0,n:0.0,e:0.0"); + allZero(parser); + } + + public void testOneTwoThreeFour() { + parser = new BoundingBoxParser("n=1,s=2,e=3,w=4"); + all1234(parser); + parser = new BoundingBoxParser("n=1.0,s=2.0,e=3.0,w=4.0"); + all1234(parser); + parser = new BoundingBoxParser("s=2,w=4,n=1,e=3"); + all1234(parser); + parser = new BoundingBoxParser("N=1,S=2,E=3,W=4"); + all1234(parser); + parser = new BoundingBoxParser("S=2,W=4,N=1,E=3"); + all1234(parser); + parser = new BoundingBoxParser("north=1.0,south=2.0,east=3.0,west=4.0"); + all1234(parser); + parser = new BoundingBoxParser("South=2.0 West=4.0 North=1.0 East=3.0"); + all1234(parser); + } + + /** + * Tests various legal inputs and print the output + */ + public void testPrint() { + String here = "n=63.418417 E=10.433033 S=37.7 W=-122.02"; + parser = new BoundingBoxParser(here); + System.out.println(here+" -> "+parser); + } + + public void testGeoPlanetExample() { + /* example XML: + + + 40.183868 + -74.819519 + + + 40.248291 + -74.728798 + + + + can be input as: + + s=40.183868,w=-74.819519,n=40.248291,e=-74.728798 + */ + parser = new BoundingBoxParser("south=40.183868,west=-74.819519,north=40.248291,east=-74.728798"); + assertEquals(40.183868d, parser.s, 0.0000001); + assertEquals(-74.819519d, parser.w, 0.0000001); + assertEquals(40.248291d, parser.n, 0.0000001); + assertEquals(-74.728798d, parser.e, 0.0000001); + } + + public void testGwsExample() { + /* example XML: + + 37.4489937.3323-121.98241-122.06566 + + can be input as: north:37.44899 south:37.3323, east:-121.98241 west:-122.06566 + */ + parser = new BoundingBoxParser(" north:37.44899 south:37.3323, east:-121.98241 west:-122.06566 "); + assertEquals(37.44899d, parser.n, 0.000001); + assertEquals(37.33230d, parser.s, 0.000001); + assertEquals(-121.98241d, parser.e, 0.000001); + assertEquals(-122.06566d, parser.w, 0.000001); + } + + /** + * Tests various inputs that contain syntax errors. + */ + public void testInputErrors() { + String message = ""; + try { + parser = new BoundingBoxParser("n=10.11,e=2.02"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("Missing bounding box limits, n=true s=false e=true w=false", message); + + try { + parser = new BoundingBoxParser("n=11.01,s=10.11,e=xyzzy,w=-122.2"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("Could not parse e limit 'xyzzy' as a number", message); + + try { + parser = new BoundingBoxParser("n=11.01,n=10.11,e=-122.0,w=-122.2"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("multiple limits for 'n' boundary", message); + + try { + parser = new BoundingBoxParser("s=11.01,s=10.11,e=-122.0,w=-122.2"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("multiple limits for 's' boundary", message); + + try { + parser = new BoundingBoxParser("n=11.01,s=10.11,e=-122.0,e=-122.2"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("multiple limits for 'e' boundary", message); + + try { + parser = new BoundingBoxParser("n=11.01,s=10.11,w=-122.0,w=-122.2"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("multiple limits for 'w' boundary", message); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/geo/DegreesParserTestCase.java b/vespajlib/src/test/java/com/yahoo/geo/DegreesParserTestCase.java new file mode 100644 index 00000000000..ed6fed5cbc7 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/geo/DegreesParserTestCase.java @@ -0,0 +1,282 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.geo; + +/** + * Tests for the DegreesParser class. + * + * @author Gunnar Gauslaa Bergem + */ +public class DegreesParserTestCase extends junit.framework.TestCase { + + private DegreesParser parser; + + public DegreesParserTestCase(String name) { + super(name); + } + + /** + * Tests different inputs that should all produce 0 or -0. + */ + public void testZero() { + parser = new DegreesParser("N0;E0"); + assertEquals(0d, parser.latitude); + assertEquals(0d, parser.longitude); + parser = new DegreesParser("S0;W0"); + assertEquals(-0d, parser.latitude); + assertEquals(-0d, parser.longitude); + parser = new DegreesParser("N0.0;E0.0"); + assertEquals(0d, parser.latitude); + assertEquals(0d, parser.longitude); + parser = new DegreesParser("S0.0;W0.0"); + assertEquals(-0d, parser.latitude); + assertEquals(-0d, parser.longitude); + parser = new DegreesParser("N0\u00B00'0;E0\u00B00'0"); + assertEquals(0d, parser.latitude); + assertEquals(0d, parser.longitude); + parser = new DegreesParser("S0\u00B00'0;W0\u00B00'0"); + assertEquals(-0d, parser.latitude); + assertEquals(-0d, parser.longitude); + parser = new DegreesParser("S0o0'0;W0o0'0"); + assertEquals(-0d, parser.latitude); + assertEquals(-0d, parser.longitude); + } + + /** + * Tests various legal inputs and print the output + */ + public void testPrint() { + String here = "63N025.105;010E25.982"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "N63.418417 E10.433033"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "N63o025.105;E010o25.982"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "N63.418417;E10.433033"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "63.418417N;10.433033E"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "N37.417075;W122.025358"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + + here = "N37\u00B024.983;W122\u00B001.481"; + parser = new DegreesParser(here); + System.out.println(here+" -> "+parser.latitude+"/"+parser.longitude+" (lat/long)"); + } + + /** + * Tests inputs that are close to 0. + */ + public void testNearZero() { + parser = new DegreesParser("N0.0001;E0.0001"); + assertEquals(0.0001, parser.latitude); + assertEquals(0.0001, parser.longitude); + parser = new DegreesParser("S0.0001;W0.0001"); + assertEquals(-0.0001, parser.latitude); + assertEquals(-0.0001, parser.longitude); + + parser = new DegreesParser("N0.000001;E0.000001"); + assertEquals(0.000001, parser.latitude); + assertEquals(0.000001, parser.longitude); + parser = new DegreesParser("S0.000001;W0.000001"); + assertEquals(-0.000001, parser.latitude); + assertEquals(-0.000001, parser.longitude); + + parser = new DegreesParser("N0\u00B00'1;E0\u00B00'1"); + assertEquals(1/3600d, parser.latitude); + assertEquals(1/3600d, parser.longitude); + parser = new DegreesParser("S0\u00B00'1;W0\u00B00'1"); + assertEquals(-1/3600d, parser.latitude); + assertEquals(-1/3600d, parser.longitude); + } + + /** + * Tests inputs that are close to latitude 90/-90 degrees and longitude 180/-180 degrees. + */ + public void testNearBoundary() { + + parser = new DegreesParser("N89.9999;E179.9999"); + assertEquals(89.9999, parser.latitude); + assertEquals(179.9999, parser.longitude); + parser = new DegreesParser("S89.9999;W179.9999"); + assertEquals(-89.9999, parser.latitude); + assertEquals(-179.9999, parser.longitude); + + parser = new DegreesParser("N89.999999;E179.999999"); + assertEquals(89.999999, parser.latitude); + assertEquals(179.999999, parser.longitude); + parser = new DegreesParser("S89.999999;W179.999999"); + assertEquals(-89.999999, parser.latitude); + assertEquals(-179.999999, parser.longitude); + + parser = new DegreesParser("N89\u00B059'59;E179\u00B059'59"); + assertEquals(89+59/60d+59/3600d, parser.latitude); + assertEquals(179+59/60d+59/3600d, parser.longitude); + parser = new DegreesParser("S89\u00B059'59;W179\u00B059'59"); + assertEquals(-(89+59/60d+59/3600d), parser.latitude); + assertEquals(-(179+59/60d+59/3600d), parser.longitude); + } + + /** + * Tests inputs that are on latitude 90/-90 degrees and longitude 180/-180 degrees. + */ + public void testOnBoundary() { + parser = new DegreesParser("N90;E180"); + assertEquals(90d, parser.latitude); + assertEquals(180d, parser.longitude); + parser = new DegreesParser("S90;W180"); + assertEquals(-90d, parser.latitude); + assertEquals(-180d, parser.longitude); + + parser = new DegreesParser("N90\u00B00'0;E180\u00B00'0"); + assertEquals(90d, parser.latitude); + assertEquals(180d, parser.longitude); + parser = new DegreesParser("S90\u00B00'0;W180\u00B00'0"); + assertEquals(-90d, parser.latitude); + assertEquals(-180d, parser.longitude); + } + + /** + * Tests inputs that are above latitude 90/-90 degrees and longitude 180/-180 degrees. + */ + public void testAboveBoundary() { + String message = ""; + try { + parser = new DegreesParser("N90.0001;E0"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-90,+90]: 90.0001", message); + try { + parser = new DegreesParser("S90.0001;E0"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-90,+90]: -90.0001", message); + try { + parser = new DegreesParser("N0;E180.0001"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-180,+180]: 180.0001", message); + try { + parser = new DegreesParser("N0;W180.0001"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-180,+180]: -180.0001", message); + try { + parser = new DegreesParser("N90.000001;E0"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-90,+90]: 90.000001", message); + try { + parser = new DegreesParser("S90.000001;E0"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-90,+90]: -90.000001", message); + try { + parser = new DegreesParser("N0;E180.000001"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-180,+180]: 180.000001", message); + try { + parser = new DegreesParser("N0;W180.000001"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("out of range [-180,+180]: -180.000001", message); + } + + /** + * Tests various inputs that contain syntax errors. + */ + public void testInputErrors() { + String message = ""; + try { + parser = new DegreesParser("N90;S90"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("found latitude (N or S) twice", message); + try { + parser = new DegreesParser("E120;W120"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("found longitude (E or W) twice", message); + try { + parser = new DegreesParser("N90;90"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("end of field without any compass direction seen", message); + try { + parser = new DegreesParser("N90;E"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("end of field without any number seen", message); + try { + parser = new DegreesParser(";"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("end of field without any compass direction seen", message); + try { + parser = new DegreesParser("25;60"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("end of field without any compass direction seen", message); + try { + parser = new DegreesParser("NW25;SW60"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("already set direction once, cannot add direction: W", message); + try { + parser = new DegreesParser("N16.25\u00B0;W60"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("cannot have fractional degrees before degrees sign", message); + try { + parser = new DegreesParser("N16\u00B022.40';W60"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("cannot have fractional minutes before minutes sign", message); + try { + parser = new DegreesParser(""); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("end of field without any compass direction seen", message); + try { + parser = new DegreesParser("Yahoo!"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("invalid character: Y", message); + try { + parser = new DegreesParser("N63O025.105;E010O25.982"); + } catch (IllegalArgumentException e) { + message = e.getMessage(); + } + assertEquals("invalid character: O", message); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/geo/ZCurveTestCase.java b/vespajlib/src/test/java/com/yahoo/geo/ZCurveTestCase.java new file mode 100644 index 00000000000..b5536fca510 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/geo/ZCurveTestCase.java @@ -0,0 +1,204 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.geo; + +/** + * Tests for the ZCurve class. + * + * @author gjoranv + */ +public class ZCurveTestCase extends junit.framework.TestCase { + + public ZCurveTestCase(String name) { + super(name); + } + + /** + * Verify that encoded values return the expected bit pattern + */ + public void testEncoding() { + int x = 0; + int y = 0; + long z = ZCurve.encode(x, y); + assertEquals(0, z); + + x = Integer.MAX_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode(x, y); + assertEquals(0x3fffffffffffffffL, z); + + x = Integer.MIN_VALUE; + y = Integer.MIN_VALUE; + z = ZCurve.encode(x, y); + assertEquals(0xc000000000000000L, z); + + x = Integer.MIN_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode(x, y); + assertEquals(0x6aaaaaaaaaaaaaaaL, z); + + x = -1; + y = -1; + z = ZCurve.encode(x, y); + assertEquals(0xffffffffffffffffL, z); + + x = Integer.MAX_VALUE / 2; + y = Integer.MIN_VALUE / 2; + z = ZCurve.encode(x, y); + assertEquals(0xa555555555555555L, z); + } + + /** + * Verify that decoded values are equal to inputs in different cases + */ + public void testDecoding() { + int x = 0; + int y = 0; + long z = ZCurve.encode(x, y); + int[] xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + + x = Integer.MAX_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode(x, y); + xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + + x = Integer.MIN_VALUE; + y = Integer.MIN_VALUE; + z = ZCurve.encode(x, y); + xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + + x = Integer.MIN_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode(x, y); + xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + + x = -18; + y = 1333; + z = ZCurve.encode(x, y); + xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + + x = -1333; + y = 18; + z = ZCurve.encode(x, y); + xy = ZCurve.decode(z); + assertEquals(x, xy[0]); + assertEquals(y, xy[1]); + } + + + + /** + * Verify that encoded values return the expected bit pattern + */ + public void testEncoding_slow() { + int x = 0; + int y = 0; + long z = ZCurve.encode_slow(x, y); + assertEquals(0, z); + + x = Integer.MIN_VALUE; + y = Integer.MIN_VALUE; + z = ZCurve.encode_slow(x, y); + assertEquals(0xc000000000000000L, z); + + x = Integer.MIN_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode_slow(x, y); + assertEquals(0x6aaaaaaaaaaaaaaaL, z); + + x = Integer.MAX_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode_slow(x, y); + assertEquals(0x3fffffffffffffffL, z); + + x = -1; + y = -1; + z = ZCurve.encode_slow(x, y); + assertEquals(0xffffffffffffffffL, z); + + x = Integer.MAX_VALUE / 2; + y = Integer.MIN_VALUE / 2; + z = ZCurve.encode_slow(x, y); + assertEquals(0xa555555555555555L, z); + } + + /** + * Verify that decoded values are equal to inputs in different cases + */ + public void testDecoding_slow() { + int x = 0; + int y = 0; + long z = ZCurve.encode_slow(x, y); + int[] xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + + x = Integer.MAX_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode_slow(x, y); + xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + + x = Integer.MIN_VALUE; + y = Integer.MIN_VALUE; + z = ZCurve.encode_slow(x, y); + xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + + x = Integer.MIN_VALUE; + y = Integer.MAX_VALUE; + z = ZCurve.encode_slow(x, y); + xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + + x = -18; + y = 1333; + z = ZCurve.encode_slow(x, y); + xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + + x = -1333; + y = 18; + z = ZCurve.encode_slow(x, y); + xy = ZCurve.decode_slow(z); + assertEquals(xy[0], x); + assertEquals(xy[1], y); + } + + public void testBenchmarkEncoding() { + int limit = 2000000; + + long z1 = 0L; + long start = System.currentTimeMillis(); + for (int i=0; iSteinar Knutsen + */ +public class ByteWriterTestCase extends junit.framework.TestCase { + private CharsetEncoder encoder; + private ByteArrayOutputStream stream; + + // TODO split BufferChain tests from ByteWriter tests + public ByteWriterTestCase (String name) { + super(name); + Charset cs = Charset.forName("UTF-8"); + encoder = cs.newEncoder(); + stream = new ByteArrayOutputStream(); + + } + + /** + * A stream which does nothing, but complains if it is called and asked to + * do nothing. + */ + private static class CurmudgeonlyStream extends OutputStream { + + static final String ZERO_LENGTH_WRITE = "Was asked to do zero length write."; + + @Override + public void write(int b) throws IOException { + // NOP + + } + + @Override + public void close() throws IOException { + // NOP + } + + @Override + public void flush() throws IOException { + // NOP + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (len == 0) { + throw new IOException(ZERO_LENGTH_WRITE); + } + } + + @Override + public void write(byte[] b) throws IOException { + if (b.length == 0) { + throw new IOException(ZERO_LENGTH_WRITE); + } + } + + } + + public void testMuchData() throws java.io.IOException { + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER * APPENDS); + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + stream.reset(); + byte[] c = new byte[SINGLE_BUFFER]; + Arrays.fill(c, (byte) 'a'); + ByteWriter bw = new ByteWriter(stream, encoder); + for (int i = APPENDS; i > 0; --i) { + bw.append(c); + } + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals("BufferChain has duplicated or lost a buffer.", SINGLE_BUFFER * APPENDS, res.length); + byte[] completeData = new byte[SINGLE_BUFFER * APPENDS]; + Arrays.fill(completeData, (byte) 'a'); + assertTrue("ByteWriter seems to have introduced data errors.", Arrays.equals(completeData, res)); + } + + public void testLongString() throws IOException { + final int length = BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS * 3; + StringBuilder b = new StringBuilder(length); + String s; + for (int i = length; i > 0; --i) { + b.append("\u00E5"); + } + s = b.toString(); + stream.reset(); + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(s); + bw.close(); + String res = stream.toString("UTF-8"); + assertEquals(s, res); + } + + public void testNoSpuriousWrite() throws IOException { + OutputStream grumpy = new CurmudgeonlyStream(); + ByteWriter bw = new ByteWriter(grumpy, encoder); + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER * APPENDS); + assertTrue("Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + stream.reset(); + byte[] c = new byte[SINGLE_BUFFER]; + for (int i = APPENDS; i > 0; --i) { + try { + bw.append(c); + } catch (IOException e) { + if (e.getMessage() == CurmudgeonlyStream.ZERO_LENGTH_WRITE) { + fail(CurmudgeonlyStream.ZERO_LENGTH_WRITE); + } else { + throw e; + } + } + } + try { + bw.close(); + } catch (IOException e) { + if (e.getMessage() == CurmudgeonlyStream.ZERO_LENGTH_WRITE) { + fail(CurmudgeonlyStream.ZERO_LENGTH_WRITE); + } else { + throw e; + } + } + } + + public void testDoubleFlush() throws IOException { + stream.reset(); + byte[] c = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c); + bw.flush(); + bw.flush(); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testCharArrays() throws java.io.IOException { + stream.reset(); + char[] c = new char[] { 'a', 'b', 'c', '\u00F8' }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8 }, res)); + } + + public void testByteBuffers() throws java.io.IOException { + stream.reset(); + ByteBuffer b = ByteBuffer.allocate(16); + b.put((byte) 97); + b.put((byte) 98); + b.put((byte) 99); + ByteWriter bw = new ByteWriter(stream, encoder); + b.flip(); + bw.append(b); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testByteArrays() throws java.io.IOException { + stream.reset(); + byte[] c = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, res)); + } + + public void testByteArrayWithOffset() throws java.io.IOException { + final int length = BufferChain.BUFFERSIZE * 3 / 2; + final int offset = 1; + final byte invalid = 3; + final byte valid = 2; + stream.reset(); + byte[] c = new byte[length]; + c[0] = invalid; + for (int i = offset; i < length; ++i) { + c[i] = valid; + } + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(c, offset, length - offset); + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals(length - offset, res.length); + assertEquals(valid, res[0]); + } + + public void testStrings() throws java.io.IOException { + stream.reset(); + String c = "abc\u00F8"; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8 }, res)); + } + + public void testStringsAndByteArrays() throws java.io.IOException { + stream.reset(); + String c = "abc\u00F8"; + byte[] b = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.write(c); + bw.append(b); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, (byte) 0xc3, (byte) 0xb8, 97, 98, 99 }, res)); + } + + public void testByteBuffersAndByteArrays() throws java.io.IOException { + stream.reset(); + ByteBuffer b = ByteBuffer.allocate(16); + b.put((byte) 97); + b.put((byte) 98); + b.put((byte) 99); + b.flip(); + byte[] c = new byte[] { 100, 101, 102 }; + ByteWriter bw = new ByteWriter(stream, encoder); + bw.append(b); + bw.append(c); + bw.close(); + byte[] res = stream.toByteArray(); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99, 100, 101, 102 }, res)); + } + + public void testOverFlow() throws java.io.IOException { + stream.reset(); + byte[] b = new byte[] { 97, 98, 99 }; + ByteWriter bw = new ByteWriter(stream, encoder); + int i = 0; + while (i < 5000) { + bw.append(b); + ++i; + } + bw.close(); + byte[] res = stream.toByteArray(); + assertEquals(15000, res.length); + i = 0; + int base = 0; + while (i < 5000) { + byte[] sub = new byte[3]; + System.arraycopy(res, base, sub, 0, 3); + assertTrue(Arrays.equals(new byte[] { 97, 98, 99 }, sub)); + base += 3; + ++i; + } + } + + public void testUnMappableCharacter() throws java.io.IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ByteWriter writer = new ByteWriter(stream, Charset.forName("ascii").newEncoder()); + writer.write("yahoo\u9999bahoo"); + writer.close(); + assertTrue(stream.toString("ascii").contains("yahoo")); + assertTrue(stream.toString("ascii").contains("bahoo")); + } + + public void testNoRecycling() throws IOException { + final int SINGLE_BUFFER = 500; + final int APPENDS = 500; + assertTrue( + "Code has been changed making constants in this test meaningless, review test.", + BufferChain.BUFFERSIZE * BufferChain.MAXBUFFERS < SINGLE_BUFFER + * APPENDS); + assertTrue( + "Code has been changed making constants in this test meaningless, review test.", + BufferChain.WATERMARK > SINGLE_BUFFER); + byte[] c = new byte[SINGLE_BUFFER]; + Arrays.fill(c, (byte) 'a'); + OnlyUniqueBuffers b = new OnlyUniqueBuffers(); + try { + for (int i = APPENDS; i > 0; --i) { + b.insert(ByteBuffer.wrap(c)); + } + b.flush(); + } catch (IOException e) { + if (e.getMessage() == OnlyUniqueBuffers.RECYCLED_BYTE_BUFFER) { + fail(OnlyUniqueBuffers.RECYCLED_BYTE_BUFFER); + } else { + throw e; + } + } + } + + public void testGetEncoding() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + assertEquals(Utf8.getCharset(), b.getEncoding()); + b.close(); + } + + public void testWriteLong() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(1000L * 1000L * 1000L * 1000L); + b.close(); + assertArrayEquals(Utf8.toBytes("1000000000000"), stream.toByteArray()); + } + + public void testWriteInt() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write((int) 'z'); + b.close(); + assertArrayEquals(Utf8.toBytes("z"), stream.toByteArray()); + } + + public void testSurrogatePairs() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(0xD800); + b.write(0xDFD0); + b.close(); + assertArrayEquals(Utf8.toBytes("\uD800\uDFD0"), stream.toByteArray()); + } + + public void testSurrogatePairsMixedWithSingleCharacters() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(0x00F8); + b.write(0xD800); + b.write(0xDFD0); + b.write(0x00F8); + b.write(0xD800); + b.write((int) 'a'); + b.write(0xDFD0); + b.write((int) 'b'); + b.close(); + assertArrayEquals(Utf8.toBytes("\u00F8\uD800\uDFD0\u00F8ab"), stream.toByteArray()); + } + + + public void testWriteDouble() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(12.0d); + b.close(); + assertArrayEquals(Utf8.toBytes("12.0"), stream.toByteArray()); + } + + public void testWriteFloat() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(12.0f); + b.close(); + assertArrayEquals(Utf8.toBytes("12.0"), stream.toByteArray()); + } + + public void testWriteShort() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write((short) 12); + b.close(); + assertArrayEquals(Utf8.toBytes("12"), stream.toByteArray()); + } + + public void testWriteBoolean() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.write(true); + b.close(); + assertArrayEquals(Utf8.toBytes("true"), stream.toByteArray()); + } + + public void testAppendSingleByte() throws java.io.IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + b.append((byte) 'a'); + b.close(); + assertArrayEquals(new byte[] { (byte) 'a' }, stream.toByteArray()); + } + + public void testAppended() throws IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + final String s = "nalle"; + b.write(s); + b.close(); + final byte[] bytes = Utf8.toBytes(s); + assertArrayEquals(bytes, stream.toByteArray()); + assertEquals(bytes.length, b.appended()); + } + + public void testWriteUtf8Array() throws IOException { + stream.reset(); + ByteWriter b = new ByteWriter(stream, encoder); + final byte[] bytes = Utf8.toBytes("nalle"); + b.write(new Utf8Array(bytes)); + b.close(); + assertArrayEquals(bytes, stream.toByteArray()); + } + + private static class OnlyUniqueBuffers implements WritableByteTransmitter { + static final String RECYCLED_BYTE_BUFFER = "Got a ByteBuffer instance twice."; + private final IdentityHashMap buffers = new IdentityHashMap(); + private final BufferChain datastore; + + public OnlyUniqueBuffers() { + datastore = new BufferChain(this); + } + + public void insert(ByteBuffer b) throws IOException { + datastore.append(b); + } + + @Override + public void send(ByteBuffer src) throws IOException { + if (buffers.containsKey(src)) { + throw new IOException(RECYCLED_BYTE_BUFFER); + } else { + buffers.put(src, null); + } + } + + public void flush() throws IOException { + datastore.flush(); + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java b/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java new file mode 100644 index 00000000000..d4889c1fa96 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/FatalErrorHandlerTestCase.java @@ -0,0 +1,55 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.security.Permission; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Just to remove noise from the coverage report. + * + * @author Steinar Knutsen + */ +public class FatalErrorHandlerTestCase { + private static final class AvoidExiting extends SecurityManager { + + @Override + public void checkPermission(Permission perm) { + } + + @Override + public void checkExit(int status) { + throw new SecurityException(); + } + + } + + private FatalErrorHandler h; + + @Before + public void setUp() throws Exception { + h = new FatalErrorHandler(); + System.setSecurityManager(new AvoidExiting()); + } + + @After + public void tearDown() throws Exception { + System.setSecurityManager(null); + } + + @Test + public final void testHandle() { + boolean caught = false; + try { + h.handle(new Throwable(), "abc"); + } catch (SecurityException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java b/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java new file mode 100644 index 00000000000..5ebdeeb797e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/FileReadTestCase.java @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.Charset; + + +public class FileReadTestCase extends junit.framework.TestCase { + + @Test + public void testReadByteArray() throws IOException { + byte[] thisFile = IOUtils.readFileBytes(new File("src/test/java/com/yahoo/io/FileReadTestCase.java")); + String str = new String(thisFile, Charset.forName("US-ASCII")); + assertTrue(str.startsWith("// Copyright 2016 Yahoo Inc.")); + assertTrue(str.endsWith("// Yeppers\n")); + } + + @Test + public void testReadString() throws IOException { + String str = IOUtils.readFile(new File("src/test/java/com/yahoo/io/FileReadTestCase.java")); + assertTrue(str.startsWith("// Copyright 2016 Yahoo Inc.")); + assertTrue(str.endsWith("// Yeppers\n")); + } + + @Test + public void testReadAllFromReader() throws IOException { + assertEquals(IOUtils.readAll(new StringReader("")), ""); + assertEquals(IOUtils.readAll(new StringReader("hei")), "hei"); + assertEquals(IOUtils.readAll(new StringReader("hei\nhaa")), "hei\nhaa"); + assertEquals(IOUtils.readAll(new StringReader("hei\nhaa\n")), "hei\nhaa\n"); + } + +} + +// Yeppers diff --git a/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java b/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java new file mode 100644 index 00000000000..71568a3cfbc --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/GrowableBufferOutputStreamTestCase.java @@ -0,0 +1,126 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.nio.channels.WritableByteChannel; +import java.nio.ByteBuffer; +import java.io.IOException; +import com.yahoo.io.GrowableBufferOutputStream; + + +/** + * Tests the GrowableBufferOutputStream + * + * @author Bjorn Borud + */ +public class GrowableBufferOutputStreamTestCase extends junit.framework.TestCase { + private byte[] testData; + + static class DummyWritableByteChannel implements WritableByteChannel { + private ByteBuffer buffer; + + public DummyWritableByteChannel(ByteBuffer buffer) { + this.buffer = buffer; + } + + public int write(ByteBuffer src) throws IOException { + int written = Math.min(src.remaining(), buffer.remaining()); + + if (buffer.remaining() < src.remaining()) { + ByteBuffer tmp = src.slice(); + + tmp.limit(written); + src.position(src.position() + written); + } else { + buffer.put(src); + } + return written; + } + + public boolean isOpen() { + return true; + } + + public void close() throws IOException {} + } + + public GrowableBufferOutputStreamTestCase(String name) { + super(name); + } + + public void setUp() { + testData = new byte[100]; + for (int i = 0; i < 100; ++i) { + testData[i] = (byte) i; + } + } + + public void testSimple() throws IOException { + GrowableBufferOutputStream g = new GrowableBufferOutputStream(10, 5); + + g.write(testData, 0, 100); + g.flush(); + assertEquals(10, g.numWritableBuffers()); + assertEquals(100, g.writableSize()); + + ByteBuffer sink = ByteBuffer.allocate(60); + DummyWritableByteChannel channel = new DummyWritableByteChannel(sink); + int written = g.channelWrite(channel); + + assertEquals(60, written); + assertEquals(60, sink.position()); + assertEquals(40, g.writableSize()); + + // there should be 4 buffers left now + assertEquals(4, g.numWritableBuffers()); + + // ensure that we got what we expected + for (int i = 0; i < 60; ++i) { + if (((int) sink.get(i)) != i) { + fail(); + } + } + + // then we write more data + g.write(testData, 0, 100); + g.flush(); + assertEquals(140, g.writableSize()); + + // ...which implies that we should now have 14 writable buffers + assertEquals(14, g.numWritableBuffers()); + + // reset the sink so it can consume more data + sink.clear(); + + // then write more to the DummyWritableByteChannel + written = g.channelWrite(channel); + assertEquals(60, written); + assertEquals(60, sink.position()); + assertEquals(80, g.writableSize()); + + // now there should be 8 buffers + assertEquals(8, g.numWritableBuffers()); + + // ensure that we got what we expected + for (int i = 0; i < 60; ++i) { + int val = (int) sink.get(i); + int expected = (i + 60) % 100; + + if (val != expected) { + fail("Value was " + val + " and not " + i); + } + } + + // when we clear there should be no buffers + g.clear(); + assertEquals(0, g.numWritableBuffers()); + assertEquals(0, g.writableSize()); + + // ditto after flush after clear + g.flush(); + assertEquals(0, g.numWritableBuffers()); + + // flush the cache too + g.clearAll(); + assertEquals(0, g.numWritableBuffers()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java b/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java new file mode 100644 index 00000000000..ffc3d6dfe64 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/GrowableByteBufferTestCase.java @@ -0,0 +1,756 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.InvalidMarkException; +import java.nio.ReadOnlyBufferException; +import java.util.Arrays; + +import static org.junit.Assert.assertArrayEquals;; + +/** + * Tests GrowableByteBuffer. + * + * @author Einar M R Rosenvinge + */ +public class GrowableByteBufferTestCase extends junit.framework.TestCase { + public void testBuffer() { + GrowableByteBuffer buf = new GrowableByteBuffer(20, 1.5f); + + buf.putChar((char) 5); + assertEquals(2, buf.position()); + + buf.putDouble(983.982d); + assertEquals(10, buf.position()); + + buf.putFloat(94.322f); + assertEquals(14, buf.position()); + + buf.putInt(98); + assertEquals(18, buf.position()); + + assertEquals(20, buf.capacity()); + + buf.putLong(983L); + assertEquals(26, buf.position()); + + // Adding fudge factors and other fun to the growth rate, + // makes capacity() suboptimal to test, so this should perhaps + // be removed + // TODO: Better test of growth rate + assertEquals(130, buf.capacity()); + + buf.putShort((short) 4); + assertEquals(28, buf.position()); + + + buf.position(0); + assertEquals((char) 5, buf.getChar()); + assertEquals(2, buf.position()); + + assertEquals((int) (983.982d * 1000d), (int) (buf.getDouble() * 1000d)); + assertEquals(10, buf.position()); + + assertEquals((int) (94.322f * 1000f), (int) (buf.getFloat() * 1000f)); + assertEquals(14, buf.position()); + + assertEquals(98, buf.getInt()); + assertEquals(18, buf.position()); + + assertEquals(983L, buf.getLong()); + assertEquals(26, buf.position()); + + assertEquals((short) 4, buf.getShort()); + assertEquals(28, buf.position()); + + + byte[] twoBytes = new byte[2]; + buf.put(twoBytes); + assertEquals(30, buf.position()); + assertEquals(130, buf.capacity()); + + buf.put((byte) 1); + assertEquals(31, buf.position()); + assertEquals(130, buf.capacity()); + + ByteBuffer tmpBuf = ByteBuffer.allocate(15); + tmpBuf.putInt(56); + tmpBuf.position(0); + buf.put(tmpBuf); + assertEquals(46, buf.position()); + assertEquals(130, buf.capacity()); + } + + public void testGrowth() { + GrowableByteBuffer buf = new GrowableByteBuffer(256, 2.0f); + + //add bytes almost to the boundary + for (int i = 0; i < 255; i++) { + buf.put((byte) 0); + } + + //We are just before the boundary now. + assertEquals(255, buf.position()); + assertEquals(256, buf.capacity()); + assertEquals(256, buf.limit()); + + //Test adding one more byte. + buf.put((byte) 0); + //The buffer is full. + assertEquals(256, buf.position()); + assertEquals(256, buf.capacity()); + assertEquals(256, buf.limit()); + + //Adding one more byte should make it grow. + buf.put((byte) 0); + assertEquals(257, buf.position()); + assertEquals(612, buf.capacity()); + assertEquals(612, buf.limit()); + + //add a buffer exactly to the boundary + byte[] bytes = new byte[355]; + buf.put(bytes); + assertEquals(612, buf.position()); + assertEquals(612, buf.capacity()); + assertEquals(612, buf.limit()); + + //adding a one-byte buffer should make it grow again + byte[] oneByteBuf = new byte[1]; + buf.put(oneByteBuf); + assertEquals(613, buf.position()); + assertEquals(1324, buf.capacity()); + assertEquals(1324, buf.limit()); + + //add a large buffer that goes waaay past the boundary and makes it grow yet again, + //but that is not enough + byte[] largeBuf = new byte[3000]; + buf.put(largeBuf); + //the buffer should be doubled twice now + assertEquals(3613, buf.position()); + assertEquals(5596, buf.capacity()); + assertEquals(5596, buf.limit()); + + //let's try that again, and make the buffer double three times + byte[] veryLargeBuf = new byte[20000]; + buf.put(veryLargeBuf); + //the buffer should be doubled three times now + assertEquals(23613, buf.position()); + assertEquals(45468, buf.capacity()); + assertEquals(45468, buf.limit()); + } + + public void testBadGrowthFactors() { + try { + new GrowableByteBuffer(100, 1.0f); + assertTrue(false); + } catch (IllegalArgumentException iae) { + //we're OK + } + GrowableByteBuffer buf = new GrowableByteBuffer(16, 1.0000001f); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + buf.putInt(1); + assertEquals(16, buf.capacity()); + + buf.putInt(1); + assertEquals(116, buf.capacity()); + + } + + public void testPropertiesNonDirect() { + GrowableByteBuffer buf = new GrowableByteBuffer(10, 1.5f); + buf.order(ByteOrder.LITTLE_ENDIAN); + + assertEquals(0, buf.position()); + // GrowableByteBuffer never makes a buffer smaller than 16 bytes + assertEquals(16, buf.capacity()); + assertEquals(16, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(false, buf.isDirect()); + + buf.put(new byte[17]); + + assertEquals(17, buf.position()); + assertEquals(124, buf.capacity()); + assertEquals(124, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(false, buf.isDirect()); + } + + public void testPropertiesDirect() { + // allocate* are simply encapsulated, so don't add logic to them, + // therefore minimum size becomes what it says + GrowableByteBuffer buf = GrowableByteBuffer.allocateDirect(10, 1.5f); + buf.order(ByteOrder.LITTLE_ENDIAN); + + assertEquals(0, buf.position()); + assertEquals(10, buf.capacity()); + assertEquals(10, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(true, buf.isDirect()); + + buf.put(new byte[11]); + + assertEquals(11, buf.position()); + assertEquals(115, buf.capacity()); + assertEquals(115, buf.limit()); + assertEquals(false, buf.isReadOnly()); + assertEquals(ByteOrder.LITTLE_ENDIAN, buf.order()); + assertEquals(true, buf.isDirect()); + } + + public void testNumberEncodings() { + GrowableByteBuffer buf = new GrowableByteBuffer(); + buf.putInt1_2_4Bytes(124); + buf.putInt2_4_8Bytes(124); + buf.putInt1_4Bytes(124); + + buf.putInt1_2_4Bytes(127); + buf.putInt2_4_8Bytes(127); + buf.putInt1_4Bytes(127); + + buf.putInt1_2_4Bytes(128); + buf.putInt2_4_8Bytes(128); + buf.putInt1_4Bytes(128); + + buf.putInt1_2_4Bytes(255); + buf.putInt2_4_8Bytes(255); + buf.putInt1_4Bytes(255); + + buf.putInt1_2_4Bytes(256); + buf.putInt2_4_8Bytes(256); + buf.putInt1_4Bytes(256); + + buf.putInt1_2_4Bytes(0); + buf.putInt2_4_8Bytes(0); + buf.putInt1_4Bytes(0); + + buf.putInt1_2_4Bytes(1); + buf.putInt2_4_8Bytes(1); + buf.putInt1_4Bytes(1); + + try { + buf.putInt1_2_4Bytes(Integer.MAX_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + buf.putInt2_4_8Bytes(Integer.MAX_VALUE); + buf.putInt1_4Bytes(Integer.MAX_VALUE); + + try { + buf.putInt2_4_8Bytes(Long.MAX_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + buf.putInt1_2_4Bytes(Short.MAX_VALUE); + buf.putInt2_4_8Bytes(Short.MAX_VALUE); + buf.putInt1_4Bytes(Short.MAX_VALUE); + + buf.putInt1_2_4Bytes(Byte.MAX_VALUE); + buf.putInt2_4_8Bytes(Byte.MAX_VALUE); + buf.putInt1_4Bytes(Byte.MAX_VALUE); + + try { + buf.putInt1_2_4Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt2_4_8Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt1_4Bytes(-1); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + try { + buf.putInt1_2_4Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt2_4_8Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + try { + buf.putInt1_4Bytes(Integer.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + try { + buf.putInt2_4_8Bytes(Long.MIN_VALUE); + fail("Should have gotten exception here..."); + } catch (Exception e) { } + + int endWritePos = buf.position(); + buf.position(0); + + assertEquals(124, buf.getInt1_2_4Bytes()); + assertEquals(124, buf.getInt2_4_8Bytes()); + assertEquals(124, buf.getInt1_4Bytes()); + + assertEquals(127, buf.getInt1_2_4Bytes()); + assertEquals(127, buf.getInt2_4_8Bytes()); + assertEquals(127, buf.getInt1_4Bytes()); + + assertEquals(128, buf.getInt1_2_4Bytes()); + assertEquals(128, buf.getInt2_4_8Bytes()); + assertEquals(128, buf.getInt1_4Bytes()); + + assertEquals(255, buf.getInt1_2_4Bytes()); + assertEquals(255, buf.getInt2_4_8Bytes()); + assertEquals(255, buf.getInt1_4Bytes()); + + assertEquals(256, buf.getInt1_2_4Bytes()); + assertEquals(256, buf.getInt2_4_8Bytes()); + assertEquals(256, buf.getInt1_4Bytes()); + + assertEquals(0, buf.getInt1_2_4Bytes()); + assertEquals(0, buf.getInt2_4_8Bytes()); + assertEquals(0, buf.getInt1_4Bytes()); + + assertEquals(1, buf.getInt1_2_4Bytes()); + assertEquals(1, buf.getInt2_4_8Bytes()); + assertEquals(1, buf.getInt1_4Bytes()); + + assertEquals(Integer.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Integer.MAX_VALUE, buf.getInt1_4Bytes()); + + assertEquals(Short.MAX_VALUE, buf.getInt1_2_4Bytes()); + assertEquals(Short.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Short.MAX_VALUE, buf.getInt1_4Bytes()); + + assertEquals(Byte.MAX_VALUE, buf.getInt1_2_4Bytes()); + assertEquals(Byte.MAX_VALUE, buf.getInt2_4_8Bytes()); + assertEquals(Byte.MAX_VALUE, buf.getInt1_4Bytes()); + + int endReadPos = buf.position(); + + assertEquals(endWritePos, endReadPos); + } + public void testNumberLengths() { + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(0)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(1)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(4)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(31)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(126)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_4Bytes(127)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(128)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(129)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(255)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(256)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_4Bytes(0x7FFFFFFF)); + + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(1)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(4)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(31)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(126)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(127)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(128)); + assertEquals(2, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32767)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32768)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(32769)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(1030493)); + assertEquals(4, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x3FFFFFFF)); + assertEquals(8, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x40000000)); + assertEquals(8, GrowableByteBuffer.getSerializedSize2_4_8Bytes(0x40000001)); + + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(0)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(1)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(4)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(31)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(126)); + assertEquals(1, GrowableByteBuffer.getSerializedSize1_2_4Bytes(127)); + assertEquals(2, GrowableByteBuffer.getSerializedSize1_2_4Bytes(128)); + assertEquals(2, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16383)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16384)); + assertEquals(4, GrowableByteBuffer.getSerializedSize1_2_4Bytes(16385)); + } + + public void testSize0() { + GrowableByteBuffer buf = new GrowableByteBuffer(0, 2.0f); + buf.put((byte) 1); + buf.put((byte) 1); + } + + public void testExceptionSafety() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + ByteBuffer b = ByteBuffer.allocate(232); + for (int i = 0; i < 232; ++i) { + b.put((byte) 32); + } + b.flip(); + g.put(b); + b.flip(); + g.put(b); + assertEquals(464, g.position()); + g.flip(); + for (int i = 0; i < 464; ++i) { + assertEquals(32, (int) g.get()); + } + } + + public void testGrowthFactorAccessor() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + assertEquals(GrowableByteBuffer.DEFAULT_GROW_FACTOR, g.getGrowFactor()); + } + + public void testGrowthWithNonZeroMark() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + final int mark = 16; + byte[] stuff = new byte[mark]; + Arrays.fill(stuff, (byte) 37); + g.put(stuff); + g.mark(); + stuff = new byte[637]; + Arrays.fill(stuff, (byte) 38); + g.put(stuff); + assertEquals(mark, g.getByteBuffer().reset().position()); + } + + public void testPutInt2_4_8BytesMore() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + g.putInt2_4_8Bytes(0x9000); + assertEquals(4, g.position()); + } + + public void testPutInt2_4_8BytesAs4() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt2_4_8BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + g.putInt2_4_8BytesAs4(1L << 37); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + g.putInt2_4_8BytesAs4(37); + assertEquals(4, g.position()); + } + + public void testGetInt2_4_8Bytes() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + final long expected3 = 37L; + g.putInt2_4_8Bytes(expected3); + final long expected2 = 0x9000L; + g.putInt2_4_8Bytes(expected2); + final long expected = 1L << 56; + g.putInt2_4_8Bytes(expected); + g.flip(); + assertEquals(expected3, g.getInt2_4_8Bytes()); + assertEquals(expected2, g.getInt2_4_8Bytes()); + assertEquals(expected, g.getInt2_4_8Bytes()); + } + + public void testSerializedSize2_4_8BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize2_4_8Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + GrowableByteBuffer.getSerializedSize2_4_8Bytes((1L << 62) + 1L); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testPutInt1_2_4BytesAs4IllegalValues() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt1_2_4BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + g.putInt1_2_4BytesAs4((1 << 30) + 1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testSerializedSize1_2_4BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize1_2_4Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + caught = false; + try { + GrowableByteBuffer.getSerializedSize1_2_4Bytes((1 << 30) + 1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testPutInt1_4BytesAs4() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + boolean caught = false; + try { + g.putInt1_4BytesAs4(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + g.putInt1_4BytesAs4(37); + assertEquals(4, g.position()); + } + + public void testSerializedSize1_4BytesIllegalValues() { + boolean caught = false; + try { + GrowableByteBuffer.getSerializedSize1_4Bytes(-1); + } catch (IllegalArgumentException e) { + caught = true; + } + assertTrue(caught); + } + + public void testBuilders() { + GrowableByteBuffer g = GrowableByteBuffer.allocate(1063); + assertEquals(1063, g.capacity()); + g = GrowableByteBuffer.allocate(1063, 37.0f); + assertEquals(1063, g.capacity()); + assertEquals(37.0f, g.getGrowFactor()); + g = GrowableByteBuffer.allocateDirect(1063); + assertTrue(g.isDirect()); + } + + public void testForwarding() { + GrowableByteBuffer g = new GrowableByteBuffer(1063); + int first = g.arrayOffset(); + g.put(0, (byte) 37); + assertTrue(g.hasArray()); + assertEquals((byte) 37, g.array()[first]); + g.putChar(0, 'a'); + assertEquals('a', g.getChar(0)); + assertEquals('a', g.asCharBuffer().get(0)); + g.putDouble(0, 10.0d); + assertEquals(10.0d, g.getDouble(0)); + assertEquals(10.0d, g.asDoubleBuffer().get(0)); + g.putFloat(0, 10.0f); + assertEquals(10.0f, g.getFloat(0)); + assertEquals(10.0f, g.asFloatBuffer().get(0)); + g.putInt(0, 10); + assertEquals(10, g.getInt(0)); + assertEquals(10, g.asIntBuffer().get(0)); + g.putLong(0, 10L); + assertEquals(10L, g.getLong(0)); + assertEquals(10L, g.asLongBuffer().get(0)); + boolean caught = false; + try { + g.asReadOnlyBuffer().put((byte) 10); + } catch (ReadOnlyBufferException e) { + caught = true; + } + assertTrue(caught); + g.putShort(0, (short) 10); + assertEquals((short) 10, g.getShort(0)); + assertEquals((short) 10, g.asShortBuffer().get(0)); + g.position(0); + g.put((byte) 0); + g.put((byte) 10); + g.limit(2); + g.position(1); + g.compact(); + assertEquals((byte) 10, g.get(0)); + } + + public void testComparison() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = new GrowableByteBuffer(32); + assertEquals(g0.hashCode(), g1.hashCode()); + assertFalse(g0.equals(Integer.valueOf(12))); + assertFalse(g0.hashCode() == new GrowableByteBuffer(1063).hashCode()); + assertTrue(g0.equals(g1)); + assertEquals(0, g0.compareTo(g1)); + g0.put((byte) 9); + assertFalse(g0.equals(g1)); + assertEquals(-1, g0.compareTo(g1)); + } + + public void testDuplicate() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = g0.duplicate(); + g0.put((byte) 12); + assertEquals(12, g1.get()); + } + + public void testGetByteArrayOffsetLen() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + for (int i = 0; i < expected.length; ++i) { + g.put(expected[i]); + } + byte[] got = new byte[3]; + g.flip(); + g.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + public void testPutByteArrayOffsetLen() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + g.put(expected, 0, expected.length); + byte[] got = new byte[3]; + g.flip(); + g.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + public void testPutGrowableBuffer() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + byte[] expected = new byte[] { (byte) 1, (byte) 2, (byte) 3 }; + GrowableByteBuffer g1 = new GrowableByteBuffer(32); + g0.put(expected, 0, expected.length); + byte[] got = new byte[3]; + g0.flip(); + g1.put(g0); + g1.flip(); + g1.get(got, 0, got.length); + assertArrayEquals(expected, got); + } + + private GrowableByteBuffer fullBuffer() { + GrowableByteBuffer g = new GrowableByteBuffer(32); + byte[] stuffer = new byte[g.remaining()]; + Arrays.fill(stuffer, (byte) 'a'); + g.put(stuffer); + return g; + } + + public void testPutWithGrow() { + GrowableByteBuffer g = fullBuffer(); + final int capacity = g.capacity(); + byte[] b = new byte[] { (byte) 'b' }; + g.put(b, 0, b.length); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + GrowableByteBuffer toPut = fullBuffer(); + toPut.flip(); + g.put(toPut); + + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.put(g.position(), (byte) 'b'); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putChar('b'); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putChar(g.position(), 'b'); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putDouble(1.0d); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putDouble(g.position(), 1.0d); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putFloat(1.0f); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putFloat(g.position(), 1.0f); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putInt(g.position(), 1); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putLong(g.position(), 1L); + assertTrue(capacity < g.capacity()); + + g = fullBuffer(); + g.putShort((short) 1); + assertTrue(capacity < g.capacity()); + g = fullBuffer(); + g.putShort(g.position(), (short) 1); + assertTrue(capacity < g.capacity()); + } + + public void testSlice() { + GrowableByteBuffer g0 = new GrowableByteBuffer(32); + GrowableByteBuffer g1 = g0.slice(); + final int expected = 37; + g0.putInt(expected); + assertEquals(expected, g1.getInt()); + } + + public void testToString() { + assertEquals("GrowableByteBuffer[pos=32 lim=32 cap=32 grow=2.0]", + fullBuffer().toString()); + } + + public void testWrappers() { + final byte expected = (byte) 2; + byte[] data = new byte[] { (byte) 1, expected, (byte) 3 }; + final float grow = 9e5f; + GrowableByteBuffer g = GrowableByteBuffer.wrap(data, grow); + assertEquals(expected, g.get(1)); + assertEquals(grow, g.getGrowFactor()); + g = GrowableByteBuffer.wrap(data, 1, 1); + assertEquals(expected, g.get()); + assertEquals(2, g.limit()); + g = GrowableByteBuffer.wrap(data, 1, 1, grow); + assertEquals(expected, g.get()); + assertEquals(2, g.limit()); + assertEquals(grow, g.getGrowFactor()); + } + + public void testByteBufferMethods() { + GrowableByteBuffer g = fullBuffer(); + assertFalse(g.hasRemaining()); + g.clear(); + assertTrue(g.hasRemaining()); + g = fullBuffer(); + g.mark(); + g.limit(16); + boolean caught = false; + try { + g.reset(); + } catch (InvalidMarkException e) { + caught = true; + } + assertTrue(caught); + caught = false; + g = fullBuffer(); + g.mark(); + g.position(16); + try { + g.reset(); + } catch (InvalidMarkException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java b/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java new file mode 100644 index 00000000000..940f0150540 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/HexDumpTestCase.java @@ -0,0 +1,40 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import org.junit.Test; + +import com.yahoo.text.Utf8; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * @author Simon Thoresen Hult + * @author Steinar Knutsen + */ +public class HexDumpTestCase { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + private static final Charset UTF16 = Charset.forName("UTF-16"); + + @Test + public void requireThatToHexStringAcceptsNull() { + assertNull(HexDump.toHexString(null)); + } + + @Test + public void requireThatToHexStringIsUnformatted() { + assertEquals("6162636465666768696A6B6C6D6E6F707172737475767778797A", + HexDump.toHexString("abcdefghijklmnopqrstuvwxyz".getBytes(UTF8))); + assertEquals("FEFF006100620063006400650066006700680069006A006B006C00" + + "6D006E006F0070007100720073007400750076007700780079007A", + HexDump.toHexString("abcdefghijklmnopqrstuvwxyz".getBytes(UTF16))); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java b/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java new file mode 100644 index 00000000000..7f89cccc6c8 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/IOUtilsTestCase.java @@ -0,0 +1,149 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import java.io.*; +import java.util.Arrays; +import java.util.List; + +/** + * @author Jon Bratseth + */ +public class IOUtilsTestCase extends junit.framework.TestCase { + + public void testCloseNUllDoesNotFail() { + IOUtils.closeWriter(null); + IOUtils.closeReader(null); + IOUtils.closeInputStream(null); + IOUtils.closeOutputStream(null); + } + + public void testFileWriter() throws IOException { + IOUtils.writeFile("temp1.txt", "hello",false); + assertEquals("hello", IOUtils.readFile(new File("temp1.txt"))); + new File("temp1.txt").delete(); + } + + public void testFileWriterWithoutEncoding() throws IOException { + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter(new File("temp2.txt"),false); + writer.write("hello"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello", IOUtils.readFile(new File("temp2.txt"))); + new File("temp2.txt").delete(); + } + + public void testFileWriterWithoutEncodingFromFileName() throws IOException { + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter("temp3.txt",false); + writer.write("hello"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello",IOUtils.readFile(new File("temp3.txt"))); + new File("temp3.txt").delete(); + } + + public void testFileCounting() throws IOException { + IOUtils.writeFile("temp4.txt","hello\nworld",false); + assertEquals(2,IOUtils.countLines("temp4.txt")); + new File("temp4.txt").delete(); + } + + public void testFileCopy() throws IOException { + IOUtils.writeFile("temp5.txt","hello",false); + IOUtils.copy(new File("temp5.txt"), new File("temp5copy.txt")); + assertEquals("hello", IOUtils.readFile(new File("temp5copy.txt"))); + new File("temp5.txt").delete(); + new File("temp5copy.txt").delete(); + } + + public void testFileCopyWithLineCap() throws IOException { + IOUtils.writeFile("temp6.txt","hello\nyou\nworld",false); + IOUtils.copy("temp6.txt","temp6copy.txt",2); + assertEquals("hello\nyou\n", IOUtils.readFile(new File("temp6copy.txt"))); + new File("temp6.txt").delete(); + new File("temp6copy.txt").delete(); + } + + public void testGetLines() throws IOException { + IOUtils.writeFile("temp7.txt","hello\nworld",false); + List lines=IOUtils.getLines("temp7.txt"); + assertEquals(2,lines.size()); + assertEquals("hello",lines.get(0)); + assertEquals("world",lines.get(1)); + new File("temp7.txt").delete(); + } + + public void testFileWriterAppend() throws IOException { + boolean append=true; + IOUtils.writeFile("temp8.txt", "hello",!append); + BufferedWriter writer=null; + try { + writer=IOUtils.createWriter(new File("temp8.txt"),append); + writer.write("\nworld"); + } + finally { + IOUtils.closeWriter(writer); + } + assertEquals("hello\nworld", IOUtils.readFile(new File("temp8.txt"))); + new File("temp8.txt").delete(); + } + + public void testCloseAllReaders() throws IOException { + StringReader reader1=new StringReader("hello"); + StringReader reader2=new StringReader("world"); + IOUtils.closeAll(Arrays.asList(reader1, reader2)); + try { + reader1.ready(); + fail("Expected exception due to reader closed"); + } + catch (IOException e) { + // Expected + } + try { + reader2.ready(); + fail("Expected exception due to reader closed"); + } + catch (IOException e) { + // Expected + } + } + + public void testDirCopying() throws IOException { + IOUtils.writeFile("temp1/temp1.txt","hello",false); + IOUtils.writeFile("temp1/temp2.txt","world",false); + IOUtils.copyDirectory(new File("temp1"), new File("temp2")); + assertEquals("hello", IOUtils.readFile(new File("temp2/temp1.txt"))); + assertEquals("world", IOUtils.readFile(new File("temp2/temp2.txt"))); + IOUtils.recursiveDeleteDir(new File("temp1")); + IOUtils.recursiveDeleteDir(new File("temp2")); + assertTrue(!new File("temp1").exists()); + assertTrue(!new File("temp2").exists()); + } + + public void testDirCopyingWithFilter() throws IOException { + IOUtils.writeFile("temp1/temp1.txt","hello",false); + IOUtils.writeFile("temp1/temp2.txt","world",false); + IOUtils.writeFile("temp1/temp3.json", "world", false); + IOUtils.copyDirectory(new File("temp1"), new File("temp2"), -1, new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".json"); + } + }); + assertEquals("world", IOUtils.readFile(new File("temp2/temp3.json"))); + assertFalse(new File("temp2/temp1.txt").exists()); + assertFalse(new File("temp2/temp2.txt").exists()); + IOUtils.recursiveDeleteDir(new File("temp1")); + IOUtils.recursiveDeleteDir(new File("temp2")); + assertTrue(!new File("temp1").exists()); + assertTrue(!new File("temp2").exists()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java b/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java new file mode 100644 index 00000000000..e2049017076 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/ListenerTestCase.java @@ -0,0 +1,108 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.yahoo.collections.Tuple2; +import com.yahoo.concurrent.Receiver; +import com.yahoo.concurrent.Receiver.MessageState; + +/** + * Test a NIO based Reactor pattern implementation, com.yahoo.io.Listener. + * + * @author Steinar Knutsen + */ +public class ListenerTestCase { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + Receiver r = new Receiver<>(); + + private final class MockConnection implements Connection { + + private SocketChannel channel; + + MockConnection(SocketChannel channel, Listener listener) { + this.channel = channel; + } + + @Override + public void write() throws IOException { + } + + @Override + public void read() throws IOException { + ByteBuffer b = ByteBuffer.allocate(1); + channel.read(b); + b.flip(); + r.put(b.get()); + } + + @Override + public void close() throws IOException { + channel.close(); + + } + + @Override + public void connect() throws IOException { + } + + @Override + public int selectOps() { + return SelectionKey.OP_READ; + } + + @Override + public SocketChannel socketChannel() { + return channel; + } + } + + private final class GetConnection implements ConnectionFactory { + + @Override + public Connection newConnection(SocketChannel channel, Listener listener) { + return new MockConnection(channel, listener); + } + } + + @Test + public final void testRun() throws IOException, InterruptedException { + Listener l = new Listener("ListenerTestCase"); + l.listen(new GetConnection(), 0); + l.start(); + int port = ((InetSocketAddress) l.acceptors.get(0).socket.getLocalAddress()).getPort(); + Socket s = new Socket("127.0.0.1", port); + final byte expected = 42; + s.getOutputStream().write(expected); + s.getOutputStream().flush(); + s.close(); + Tuple2 received = r.get(60 * 1000); + l.acceptors.get(0).interrupt(); + l.acceptors.get(0).socket.close(); + l.acceptors.get(0).join(); + l.interrupt(); + l.join(); + assertTrue("Test timed out.", received.first == MessageState.VALID); + assertEquals(expected, received.second.byteValue()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java b/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java new file mode 100644 index 00000000000..48d8e8cdffe --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/SlowInflateTestCase.java @@ -0,0 +1,61 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.zip.Deflater; + +import org.junit.Before; +import org.junit.Test; + +import com.yahoo.text.Utf8; + +/** + * Check decompressor used among other things for packed summary fields. + * + * @author Steinar Knutsen + */ +public class SlowInflateTestCase { + + private String value; + private byte[] raw; + private byte[] output; + private byte[] compressed; + private int compressedDataLength; + + @Before + public void setUp() throws Exception { + value = "000000000000000000000000000000000000000000000000000000000000000"; + raw = Utf8.toBytesStd(value); + output = new byte[raw.length * 2]; + Deflater compresser = new Deflater(); + compresser.setInput(raw); + compresser.finish(); + compressedDataLength = compresser.deflate(output); + compresser.end(); + compressed = Arrays.copyOf(output, compressedDataLength); + } + + @Test + public final void test() { + byte[] unpacked = new SlowInflate().unpack(compressed, raw.length); + assertArrayEquals(raw, unpacked); + } + + @Test + public final void testCorruptData() { + compressed[0] = (byte) (compressed[0] ^ compressed[1]); + compressed[1] = (byte) (compressed[1] ^ compressed[2]); + compressed[2] = (byte) (compressed[2] ^ compressed[3]); + compressed[3] = (byte) (compressed[3] ^ compressed[4]); + boolean caught = false; + try { + new SlowInflate().unpack(compressed, raw.length); + } catch (RuntimeException e) { + caught = true; + } + assertTrue(caught); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java b/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java new file mode 100644 index 00000000000..280d0782bd2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/io/reader/NamedReaderTestCase.java @@ -0,0 +1,131 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.io.reader; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.CharBuffer; +import java.util.Collections; + +import com.yahoo.io.reader.NamedReader; +import com.yahoo.protect.ClassValidator; + +/** + * Tests all method of NamedReader. + * + * @author Jon Bratseth + * @author Steinar Knutsen + */ +public class NamedReaderTestCase extends junit.framework.TestCase { + + public void testIt() { + StringReader stringReader=new StringReader("hello world"); + NamedReader r=new NamedReader("test1",stringReader); + assertEquals("test1",r.getName()); + assertEquals("test1",r.toString()); + assertEquals(stringReader,r.getReader()); + NamedReader.closeAll(Collections.singletonList(r)); + NamedReader.closeAll(null); // noop, nor exception + } + + public void testMethodMasking() { + assertEquals(0, + ClassValidator.unmaskedMethodsFromSuperclass(NamedReader.class).size()); + } + + private static class MarkerReader extends Reader { + static final String READ_CHAR_BUFFER = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(CharBuffer)"; + static final String READ = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read()"; + static final String READ_CHAR = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(char[])"; + static final String READ_CHAR_INT_INT = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.read(char[], int, int)"; + static final String SKIP_LONG = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.skip(long)"; + static final String READY = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.ready()"; + static final String MARK_SUPPORTED = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.markSupported()"; + static final String MARK_INT = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.mark(int)"; + static final String RESET = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.reset()"; + static final String CLOSE = "com.yahoo.io.reader.NamedReaderTestCase.MarkerReader.close()"; + String lastMethodHit = null; + + @Override + public int read(CharBuffer target) throws IOException { + lastMethodHit = READ_CHAR_BUFFER; + return 0; + } + + @Override + public int read() throws IOException { + lastMethodHit = READ; + return -1; + } + + @Override + public int read(char[] cbuf) throws IOException { + lastMethodHit = READ_CHAR; + return 0; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + lastMethodHit = READ_CHAR_INT_INT; + return 0; + } + + @Override + public long skip(long n) throws IOException { + lastMethodHit = SKIP_LONG; + return 0; + } + + @Override + public boolean ready() throws IOException { + lastMethodHit = READY; + return false; + } + + @Override + public boolean markSupported() { + lastMethodHit = MARK_SUPPORTED; + return false; + } + + @Override + public void mark(int readAheadLimit) throws IOException { + lastMethodHit = MARK_INT; + } + + @Override + public void reset() throws IOException { + lastMethodHit = RESET; + } + + @Override + public void close() throws IOException { + lastMethodHit = CLOSE; + } + } + + public void testAllDelegators() throws IOException { + MarkerReader m = new MarkerReader(); + NamedReader r = new NamedReader("nalle", m); + r.read(CharBuffer.allocate(5000)); + assertEquals(MarkerReader.READ_CHAR_BUFFER, m.lastMethodHit); + r.read(); + assertEquals(MarkerReader.READ, m.lastMethodHit); + r.read(new char[5]); + assertEquals(MarkerReader.READ_CHAR, m.lastMethodHit); + r.read(new char[5], 0, 5); + assertEquals(MarkerReader.READ_CHAR_INT_INT, m.lastMethodHit); + r.skip(5L); + assertEquals(MarkerReader.SKIP_LONG, m.lastMethodHit); + r.ready(); + assertEquals(MarkerReader.READY, m.lastMethodHit); + r.markSupported(); + assertEquals(MarkerReader.MARK_SUPPORTED, m.lastMethodHit); + r.mark(5); + assertEquals(MarkerReader.MARK_INT, m.lastMethodHit); + r.reset(); + assertEquals(MarkerReader.RESET, m.lastMethodHit); + r.close(); + assertEquals(MarkerReader.CLOSE, m.lastMethodHit); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/java7compat/UtilTest.java b/vespajlib/src/test/java/com/yahoo/java7compat/UtilTest.java new file mode 100644 index 00000000000..1f919978b7a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/java7compat/UtilTest.java @@ -0,0 +1,29 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.java7compat; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * @author Henning Baldersheim + * @since 5.2 + */ + +public class UtilTest { + + @Test + public void requireJava7CompatibleDoublePrinting() { + if (Util.isJava7Compatible()) { + assertEquals("0.004", String.valueOf(0.0040)); + }else { + assertEquals("0.0040", String.valueOf(0.0040)); + } + assertEquals("0.004", Util.toJava7String(0.0040) ); + } + + @Test + public void nonCompatible() { + assertEquals(Util.nonJava7CompatibleString("0.0040"), "0.004"); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/javacc/FastCharStreamTestCase.java b/vespajlib/src/test/java/com/yahoo/javacc/FastCharStreamTestCase.java new file mode 100644 index 00000000000..a73fffc6c5c --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/javacc/FastCharStreamTestCase.java @@ -0,0 +1,181 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.javacc; + +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author Simon Thoresen Hult + */ +public class FastCharStreamTestCase { + + @Test + public void requireThatInputCanBeRead() throws IOException { + FastCharStream input = new FastCharStream("foo"); + assertEquals('f', input.readChar()); + assertEquals('o', input.readChar()); + assertEquals('o', input.readChar()); + try { + input.readChar(); + fail(); + } catch (IOException e) { + + } + } + + @Test + public void requireThatColumnIsTracked() throws IOException { + FastCharStream input = new FastCharStream("foo"); + assertEquals(1, input.getColumn()); + input.readChar(); + assertEquals(2, input.getColumn()); + input.readChar(); + assertEquals(3, input.getColumn()); + input.readChar(); + assertEquals(4, input.getColumn()); + } + + @Test + public void requireThatLineIsNotTracked() throws IOException { + FastCharStream input = new FastCharStream("f\no"); + assertEquals(-1, input.getLine()); + input.readChar(); + assertEquals(-1, input.getLine()); + input.readChar(); + assertEquals(-1, input.getLine()); + input.readChar(); + assertEquals(-1, input.getLine()); + } + + + @Test + public void requireThatBackupIsSupported() throws IOException { + FastCharStream input = new FastCharStream("foo"); + assertEquals('f', input.readChar()); + input.backup(1); + assertEquals('f', input.readChar()); + assertEquals('o', input.readChar()); + input.backup(2); + assertEquals('f', input.readChar()); + assertEquals('o', input.readChar()); + assertEquals('o', input.readChar()); + input.backup(3); + assertEquals('f', input.readChar()); + assertEquals('o', input.readChar()); + assertEquals('o', input.readChar()); + input.backup(2); + assertEquals('o', input.readChar()); + assertEquals('o', input.readChar()); + input.backup(1); + assertEquals('o', input.readChar()); + } + + @Test + public void requireThatSuffixIsNotSupported() { + try { + new FastCharStream("foo").GetSuffix(0); + fail(); + } catch (UnsupportedOperationException e) { + + } + } + + @Test + public void requireThatDoneDoesNotThrowException() { + FastCharStream input = new FastCharStream("foo"); + input.Done(); + } + + @Test + public void requireThatTokensCanBeRetrieved() throws IOException { + FastCharStream input = new FastCharStream("foo bar baz"); + input.readChar(); + input.readChar(); + input.readChar(); + input.readChar(); + assertEquals('b', input.BeginToken()); + assertEquals(5, input.getBeginColumn()); + assertEquals(-1, input.getBeginLine()); + assertEquals(6, input.getEndColumn()); + assertEquals(-1, input.getEndLine()); + assertEquals('a', input.readChar()); + assertEquals('r', input.readChar()); + assertEquals(8, input.getEndColumn()); + assertEquals(-1, input.getEndLine()); + assertEquals("bar", input.GetImage()); + } + + @Test + public void requireThatExceptionsDetectLineNumber() { + FastCharStream input = new FastCharStream("foo\nbar"); + assertEquals("line 2, column 1\n" + + "At position:\n" + + "bar\n" + + "^", + input.formatException("line -1, column 5")); + assertEquals("line 2, column 2\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("line -1, column 6")); + assertEquals("line 2, column 3\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("line -1, column 7")); + assertEquals("line 2, column 4\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("line -1, column 8")); + assertEquals("foo line 2, column 2\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("foo line -1, column 6")); + assertEquals("foo line 2, column 2 bar\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("foo line -1, column 6 bar")); + assertEquals("line 2, column 2 bar\n" + + "At position:\n" + + "bar\n" + + " ^", + input.formatException("line -1, column 6 bar")); + } + + @Test + public void requireErrorMsgExceptionAtEOF() { + FastCharStream input = new FastCharStream("\n"); + assertEquals("line 1, column 1\n" + + "At position:\n" + + "EOF\n" + + "^", + input.formatException("line -1, column 1")); + } + + @Test + public void requireThatUnknownExceptionFormatIsIgnored() { + FastCharStream input = new FastCharStream("foo\nbar"); + assertEquals("", + input.formatException("")); + assertEquals("foo", + input.formatException("foo")); + assertEquals("foo line -1, column ", + input.formatException("foo line -1, column ")); + assertEquals("foo line -1, column bar", + input.formatException("foo line -1, column bar")); + } + + @Test + public void requireThatIllegalExceptionColumnIsIgnored() { + FastCharStream input = new FastCharStream("foo\nbar"); + assertEquals("line -1, column 9", + input.formatException("line -1, column 9")); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/javacc/UnicodeUtilitiesTestCase.java b/vespajlib/src/test/java/com/yahoo/javacc/UnicodeUtilitiesTestCase.java new file mode 100644 index 00000000000..81329e06308 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/javacc/UnicodeUtilitiesTestCase.java @@ -0,0 +1,112 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.javacc; + +import org.junit.Test; + +import static com.yahoo.javacc.UnicodeUtilities.quote; +import static com.yahoo.javacc.UnicodeUtilities.unquote; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author Simon Thoresen + */ +public class UnicodeUtilitiesTestCase { + + @Test + public void testQuote() { + assertEquals("'\\f'", quote("\f", '\'')); + assertEquals("'\\n'", quote("\n", '\'')); + assertEquals("'\\r'", quote("\r", '\'')); + assertEquals("'\\t'", quote("\t", '\'')); + + for (char c = 'a'; c <= 'z'; ++c) { + assertEquals("'" + c + "'", quote(String.valueOf(c), '\'')); + } + + assertEquals("'\\u4f73'", quote("\u4f73", '\'')); + assertEquals("'\\u80fd'", quote("\u80fd", '\'')); + assertEquals("'\\u7d22'", quote("\u7d22", '\'')); + assertEquals("'\\u5c3c'", quote("\u5c3c", '\'')); + assertEquals("'\\u60e0'", quote("\u60e0", '\'')); + assertEquals("'\\u666e'", quote("\u666e", '\'')); + + assertEquals("\"foo\"", quote("foo", '"')); + assertEquals("\"'foo\"", quote("'foo", '"')); + assertEquals("\"foo'\"", quote("foo'", '"')); + assertEquals("\"'foo'\"", quote("'foo'", '"')); + assertEquals("\"\\\"foo\"", quote("\"foo", '"')); + assertEquals("\"foo\\\"\"", quote("foo\"", '"')); + assertEquals("\"\\\"foo\\\"\"", quote("\"foo\"", '"')); + assertEquals("\"\\\"'foo'\\\"\"", quote("\"'foo'\"", '"')); + assertEquals("\"'\\\"foo\\\"'\"", quote("'\"foo\"'", '"')); + assertEquals("\"'f\\\\'o\\\"o\\\\\\\\'\"", quote("'f\\'o\"o\\\\'", '"')); + + assertEquals("\"\\female \\nude fa\\rt fe\\tish\"", quote("\female \nude fa\rt fe\tish", '"')); + assertEquals("\"\\u666e\"", quote("\u666e", '"')); + } + + @Test + public void testQuoteUnquote() { + assertEquals("\"foo\"", quote(unquote("'foo'"), '"')); + assertEquals("\"\\foo\"", quote(unquote(quote("\foo", '"')), '"')); + assertEquals("\u666e", unquote(quote("\u666e", '"'))); + } + + @Test + public void testUnquote() { + assertEquals("foo", unquote("foo")); + assertEquals("'foo", unquote("'foo")); + assertEquals("foo'", unquote("foo'")); + assertEquals("foo", unquote("'foo'")); + assertEquals("\"foo", unquote("\"foo")); + assertEquals("foo\"", unquote("foo\"")); + assertEquals("foo", unquote("\"foo\"")); + assertEquals("'foo'", unquote("\"'foo'\"")); + assertEquals("\"foo\"", unquote("'\"foo\"'")); + assertEquals("f'o\"o\\", unquote("'f\\'o\"o\\\\'")); + + assertEquals("\female \nude fa\rt fe\tish", unquote("'\\female \\nude fa\\rt fe\\tish'")); + assertEquals("\u666e", unquote("\"\\u666e\"")); + + try { + unquote("\"\\uSiM0N\""); + fail(); + } catch (IllegalArgumentException e) { + + } + assertEquals("simo\n", unquote("'\\s\\i\\m\\o\\n'")); + try { + unquote("\"foo\"bar\""); + fail(); + } catch (IllegalArgumentException e) { + + } + try { + unquote("'foo'bar'"); + fail(); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void requireThatTokenIncludesOnlyAcceptedChars() { + assertEquals("\"\\u0000\",\"\\u7777\",\"\\uffff\",", + UnicodeUtilities.generateToken(new UnicodeUtilities.Predicate() { + + @Override + public boolean accepts(char c) { + return c == 0x0000 || c == 0x7777 || c == 0xffff; + } + })); + assertEquals("\"\\u0006\",\"\\u0009\",\"\\u0060\"-\"\\u0069\",", + UnicodeUtilities.generateToken(new UnicodeUtilities.Predicate() { + + @Override + public boolean accepts(char c) { + return c == 0x6 || c == 0x9 || (c >= 0x60 && c <= 0x69); + } + })); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/net/HostNameTestCase.java b/vespajlib/src/test/java/com/yahoo/net/HostNameTestCase.java new file mode 100644 index 00000000000..98be9f0ef6f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/HostNameTestCase.java @@ -0,0 +1,16 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; + +/** + * @author lulf + */ +public class HostNameTestCase { + @Test + public void testHostnameIsFound() { + assertFalse(HostName.getLocalhost().isEmpty()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/net/LinuxInetAddressTestCase.java b/vespajlib/src/test/java/com/yahoo/net/LinuxInetAddressTestCase.java new file mode 100755 index 00000000000..fc1945d2d39 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/LinuxInetAddressTestCase.java @@ -0,0 +1,41 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import java.net.UnknownHostException; +import java.net.InetAddress; +import java.net.Inet4Address; + +/** + * @author Simon Thoresen + */ +public class LinuxInetAddressTestCase extends junit.framework.TestCase { + + public void testPreferIPv4() throws UnknownHostException { + try { + // This test only works if there is at least one inet address returned. + InetAddress[] arr = LinuxInetAddress.getAllLocal(); + if (arr.length > 0) { + // System.out.println("Got " + arr.length + " addresses."); + + // And it can only make sure it is preferred if there is at least one ip v4 address. + boolean ipv4 = false; + for (int i = 0; i < arr.length; ++i) { + // System.out.println("Address " + i + " is an instance of " + arr[i].getClass() + "."); + if (arr[i] instanceof Inet4Address) { + ipv4 = true; + } + } + + // And the only thing we test is that an ip v4 address is preferred. + if (ipv4) { + InetAddress addr = LinuxInetAddress.getLocalHost(); + assertNotNull("IPv4 is prefered", addr instanceof Inet4Address); + } + } + } + catch (java.net.UnknownHostException e) { + // We're on vpn or have no network + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/net/URITestCase.java b/vespajlib/src/test/java/com/yahoo/net/URITestCase.java new file mode 100644 index 00000000000..7bb2303d7bb --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/URITestCase.java @@ -0,0 +1,512 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + + +import java.util.List; + + +/** + * Tests the URI class + * + * @author Jon S Bratseth + */ +public class URITestCase extends junit.framework.TestCase { + + public URITestCase(String name) { + super(name); + } + + public void testEquality() { + URI one = new URI("http://www.nils.arne.com"); + URI two = new URI("http://www.nils.arne.com"); + + assertEquals(one, two); + assertEquals(one.hashCode(), two.hashCode()); + assertEquals("http://www.nils.arne.com/", one.toString()); + + assertEqualURIs( + "http://info.t.fast.no/art.php?sid=29&mode=thread&order=0", + "http://info.t.fast.no/art.php?sid=29&mode=thread&order=0"); + assertEqualURIs("http://a/g/", "http://a/g/"); + assertEquals("http://a/g;x?y#s", + new URI("http://a/g;x?y#s", true).stringValue()); + assertEquals("http://a/g?y#s", + new URI("http://a/g?y#s", true).stringValue()); + assertEqualURIs("http://a/b/c/.g", "http://a/b/c/.g"); + assertEqualURIs("http://a/b/c/..g", "http://a/b/c/..g"); + assertEqualURIs("http://a/b/c/g;x=1/y", "http://a/b/c/g;x=1/y"); + assertEquals("http://a/b/c/g#s/../x", + new URI("http://a/b/c/g#s/../x", true).stringValue()); + assertEquals("http://www.strange_host.com/b", + new URI("http://www.strange_host.com/b", true).stringValue()); + } + + public void testOpaque() { + URI uri = new URI("mailto:knut"); + + assertEquals("mailto:knut", uri.toString()); + assertTrue(uri.isOpaque()); + } + + public void testValid() { + assertTrue( + new URI("http://www.one.com/isValid?even=if&theres=args").isValid()); + assertTrue( + !new URI("http://www.one.com/isValid?even=if&theres=args").isOpaque()); + + assertTrue(!(new URI("not\\uri?", false, true).isValid())); + + assertTrue(new URI("http://www.strange_host.com/b").isValid()); + assertTrue(!new URI("http://www.strange_host.com/b").isOpaque()); + } + + public void testSorting() { + URI first = new URI("http://aisfirst.kanoo.com"); + URI second = new URI("www.thentheresw.com"); + + assertTrue(first.compareTo(second) < 0); + assertTrue(second.compareTo(second) == 0); + assertTrue(second.compareTo(first) > 1); + } + + public void testHost() { + assertEquals("a.b.c", new URI("http://A.B.C:567").getHost()); + assertEquals("www.kanoo.com", + new URI("www.kanoo.com/foo", false, true).getHost()); + assertEquals("a.b.c", new URI("http://a.b.C/foo").getHost()); + assertEquals("a.b.c", new URI("http://a.b.C").getHost()); + assertEquals("a", new URI("http://A").getHost()); + assertEquals("a", new URI("http://A:80").getHost()); + } + + public void testUnfragmenting() { + assertEquals("http://www.sng.no/a/b/dee?kanoos&at=nught#chapter3", + new URI("http://www.sng.no/a/b/cee/../dee?kanoos&at=nught#chapter3", true).stringValue()); + assertEquals("http://www.sng.no/a/b/dee?kanoos&at=nught", + new URI("http://www.sng.no/a/b/cee/../dee?kanoos&at=nught#chapter3", false).stringValue()); + } + + public void testNormalizing() { + // Abbreviation resolving heuristics + assertEquals("http://www.a.b/c", + new URI("www.a.b/c", false, true).toString()); + assertEquals("file://x:\\a", new URI("x:\\a", false, true).toString()); + assertEquals("file://c:/a", new URI("c:/a", false, true).toString()); + + // RFC 2396 normalizing + assertEqualURIs("http://a/c/d", "http://a/b/../c/d"); + assertEqualURIs("http://a/b", "http://a/./b"); + + // FAST normalizing + assertEqualURIs("http://a/", " http://a "); + assertEqualURIs("http://a/%e6;m%e5;ha%f8;l", "http://a/\u00E6m\u00E5ha\u00F8l"); + assertEqualURIs("http://a/&b", "http://a/&b"); + assertEqualURIs("http://a/", "http://A"); + assertEqualURIs("http://a/", "http://a:80"); + assertEqualURIs("https://a/", "https://a:443"); + assertEqualURIs("http://a/", "http://a."); + assertEqualURIs("http://a/b", "http://a//b"); + assertEqualURIs("http://a/b/", "http://A/b/"); + assertEqualURIs("http://a/b/", "http://a./b/"); + assertEqualURIs("http://a/", "http://a/b/../"); + assertEqualURIs("http://a/../", "http://a/b/../a/../../"); + assertEqualURIs("http://a/", "http://a/b/../"); + assertEqualURIs("http://a/b/c/d", "http://a/b/c/d"); + assertEqualURIs("http://a/b/c", "http://a/b/c#kanoo"); + + // Everything combined + assertEquals("http://www.a.b/m%e5;l/&/%f8;l&&/", + new URI(" WWW.a.B:80//m\u00E5l/.//&/./\u00F8l&&/foo/../upp/./..", true, true).toString()); + } + + public void testParemeterAdding() { + assertEquals("http://a/?knug=zagg", + new URI("http://a/").addParameter("knug", "zagg").stringValue()); + assertEquals("http://a/b?knug=zagg&fjukk=barra", + new URI("http://a/b?knug=zagg").addParameter("fjukk", "barra").stringValue()); + } + + private void assertEqualURIs(String fasit, String test) { + assertEquals(fasit, new URI(test).toString()); + } + + public void testDepth() { + assertEquals(0, new URI("test:hit").getDepth()); + assertEquals(0, new URI("test://hit").getDepth()); + assertEquals(0, new URI("test://hit/").getDepth()); + assertEquals(1, new URI("test://hit.test/hello ").getDepth()); + assertEquals(1, new URI("test://hit.test/hello/").getDepth()); + assertEquals(0, new URI("test:// ").getDepth()); + assertEquals(0, new URI("test:///").getDepth()); + assertEquals(1, new URI("test:////").getDepth()); + assertEquals(2, new URI("test://hit.test/hello/test2/").getDepth()); + } + + public void testURLEmpty() { + URI uri = new URI("", true); + assertTrue(uri.isValid()); + assertNull(uri.getScheme()); + assertNull(uri.getHost()); + assertNull(uri.getDomain()); + assertNull(uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertNull(uri.getPath()); + assertNull(uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLDot() { + URI uri = new URI(".", true); + assertTrue(uri.isValid()); + assertNull(uri.getScheme()); + assertNull(uri.getHost()); + assertNull(uri.getDomain()); + assertNull(uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertNull(uri.getPath()); //differs from FastS_URL, "." + assertNull(uri.getFilename()); //differs from FastS_URL, "." + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLDotDot() { + URI uri = new URI("..", true); + assertTrue(uri.isValid()); + assertNull(uri.getScheme()); + assertNull(uri.getHost()); + assertNull(uri.getDomain()); + assertNull(uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertNull(uri.getPath()); //differs from FastS_URL, ".." + assertNull(uri.getFilename()); //differs from FastS_URL, ".." + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLUninett() { + URI uri = new URI("http://180.uninett.no/servlet/online.Bransje", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("180.uninett.no", uri.getHost()); + assertEquals("uninett.no", uri.getDomain()); + assertEquals("no", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/servlet/online.Bransje", uri.getPath()); + assertEquals("online.Bransje", uri.getFilename()); + assertEquals("Bransje", uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLUnderdusken() { + URI uri = new URI("http://www.underdusken.no", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("www.underdusken.no", uri.getHost()); + assertEquals("underdusken.no", uri.getDomain()); + assertEquals("no", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("", uri.getPath()); + assertEquals("", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLUnderduskenUholdbar() { + URI uri = + new URI("http://www.underdusken.no/?page=dusker/html/0008/Uholdbar.html", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("www.underdusken.no", uri.getHost()); + assertEquals("underdusken.no", uri.getDomain()); + assertEquals("no", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/", uri.getPath()); + assertEquals("", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertEquals("page=dusker/html/0008/Uholdbar.html", uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLUniKarlsruhe() { + URI uri = new URI("http://www.uni-karlsruhe.de/~ig25/ssh-faq/", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("www.uni-karlsruhe.de", uri.getHost()); + assertEquals("uni-karlsruhe.de", uri.getDomain()); + assertEquals("de", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/~ig25/ssh-faq/", uri.getPath()); + assertEquals("", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLDetteErEn() { + URI uri = new URI("https://dette.er.en:2020/~janie/index.htm?param1=q¶m2=r", true); + assertTrue(uri.isValid()); + assertEquals("https", uri.getScheme()); + assertEquals("dette.er.en", uri.getHost()); + assertEquals("er.en", uri.getDomain()); + assertEquals("en", uri.getMainTld()); + assertEquals(2020, uri.getPort()); + assertEquals("/~janie/index.htm", uri.getPath()); + assertEquals("index.htm", uri.getFilename()); + assertEquals("htm", uri.getExtension()); + assertNull(uri.getParams()); + assertEquals("param1=q¶m2=r", uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLSonyCoUk() { + URI uri = new URI("http://www.sony.co.uk/", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("www.sony.co.uk", uri.getHost()); + assertEquals("sony.co.uk", uri.getDomain()); + assertEquals("uk", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/", uri.getPath()); + assertEquals("", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLSonyCoUk2() { + URI uri = new URI("http://sony.co.uk/", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("sony.co.uk", uri.getHost()); + //TODO: Fix when tldlist is implemented: + //assertEquals("sony.co.uk", uri.getDomain()); + assertEquals("co.uk", uri.getDomain()); + assertEquals("uk", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/", uri.getPath()); + assertEquals("", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLSomehostSomedomain() { + URI uri = new URI("http://somehost.somedomain/this!is!it/boom", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("somehost.somedomain", uri.getHost()); + assertEquals("somehost.somedomain", uri.getDomain()); + assertEquals("somedomain", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/this!is!it/boom", uri.getPath()); + assertEquals("boom", uri.getFilename()); + assertNull(uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLTestCom() { + URI uri = new URI("http://test.com/index.htm?p1=q%20test&p2=r%10d", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("test.com", uri.getHost()); + assertEquals("test.com", uri.getDomain()); + assertEquals("com", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/index.htm", uri.getPath()); + assertEquals("index.htm", uri.getFilename()); + assertEquals("htm", uri.getExtension()); + assertNull(uri.getParams()); + assertEquals("p1=q%20test&p2=r%10d", uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLArthur() { + URI uri = new URI("http://arthur/qm/images/qm1.gif", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("arthur", uri.getHost()); + assertEquals("arthur", uri.getDomain()); + assertNull(uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/qm/images/qm1.gif", uri.getPath()); + assertEquals("qm1.gif", uri.getFilename()); + assertEquals("gif", uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLFooCom() { + URI uri = new URI("http://foo.com/ui;.gif", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("foo.com", uri.getHost()); + assertEquals("foo.com", uri.getDomain()); + assertEquals("com", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/ui;.gif", uri.getPath()); + assertEquals("ui", uri.getFilename()); + assertNull(uri.getExtension()); + assertEquals(".gif", uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLFooCom2() { + URI uri = new URI("http://foo.com/ui;par1=1/par2=2", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("foo.com", uri.getHost()); + assertEquals("foo.com", uri.getDomain()); + assertEquals("com", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/ui;par1=1/par2=2", uri.getPath()); + assertEquals("ui", uri.getFilename()); + assertNull(uri.getExtension()); + assertEquals("par1=1/par2=2", uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testURLFooNo() { + URI uri = new URI( + "http://www.foo.no:8080/path/filename.ext;par1=hello/par2=world?query=test#fragment", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("www.foo.no", uri.getHost()); + assertEquals("foo.no", uri.getDomain()); + assertEquals("no", uri.getMainTld()); + assertEquals(8080, uri.getPort()); + assertEquals("/path/filename.ext;par1=hello/par2=world", uri.getPath()); + assertEquals("filename.ext", uri.getFilename()); + assertEquals("ext", uri.getExtension()); + assertEquals("par1=hello/par2=world", uri.getParams()); + assertEquals("query=test", uri.getQuery()); + assertEquals("fragment", uri.getFragment()); + } + + public void testURLAmpersand() { + URI uri = new URI("http://canonsarang.com/zboard/data/gallery04/HU&BANG.jpg", true); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("canonsarang.com", uri.getHost()); + assertEquals("canonsarang.com", uri.getDomain()); + assertEquals("com", uri.getMainTld()); + assertEquals(-1, uri.getPort()); + assertEquals("/zboard/data/gallery04/HU&BANG.jpg", uri.getPath()); + assertEquals("HU&BANG.jpg", uri.getFilename()); + assertEquals("jpg", uri.getExtension()); + assertNull(uri.getParams()); + assertNull(uri.getQuery()); + assertNull(uri.getFragment()); + } + + public void testQMark() { + URI uri = new URI("http://foobar/?"); + assertTrue(uri.isValid()); + assertEquals("http", uri.getScheme()); + assertEquals("foobar", uri.getHost()); + assertEquals("", uri.getQuery()); + } + + public void testTokenization() { + URI uri = new URI("http://this.i_s:5000/wo_ho;ba-lo?gobo#banana", true); + List tokens = uri.tokenize(); + URI.Token token; + + token = tokens.get(0); + assertEquals("http", token.getToken()); + assertEquals(URI.URLContext.URL_SCHEME, token.getContext()); + + token = tokens.get(1); + assertEquals("this", token.getToken()); + assertEquals(URI.URLContext.URL_HOST, token.getContext()); + + token = tokens.get(2); + assertEquals("i_s", token.getToken()); + assertEquals(URI.URLContext.URL_HOST, token.getContext()); + + token = tokens.get(3); + assertEquals("5000", token.getToken()); + assertEquals(URI.URLContext.URL_PORT, token.getContext()); + + token = tokens.get(4); + assertEquals("wo_ho", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(5); + assertEquals("ba-lo", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(6); + assertEquals("gobo", token.getToken()); + assertEquals(URI.URLContext.URL_QUERY, token.getContext()); + + token = tokens.get(7); + assertEquals("banana", token.getToken()); + assertEquals(URI.URLContext.URL_FRAGMENT, token.getContext()); + + try { + tokens.get(8); + fail(); + } catch (IndexOutOfBoundsException ioobe) { + } + } + + // Error reported int bug #2466528 + public void testFileURIEmptyHost() { + URI uri = new URI("file:///C:/Inetpub/wwwroot/DW_SHORTCUTS.htm"); + List tokens = uri.tokenize(); + URI.Token token; + token = tokens.get(0); + assertEquals("file", token.getToken()); + assertEquals(URI.URLContext.URL_SCHEME, token.getContext()); + + token = tokens.get(1); + assertEquals("localhost", token.getToken()); + assertEquals(URI.URLContext.URL_HOST, token.getContext()); + + token = tokens.get(2); + assertEquals("C", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(3); + assertEquals("Inetpub", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(4); + assertEquals("wwwroot", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(5); + assertEquals("DW_SHORTCUTS", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + token = tokens.get(6); + assertEquals("htm", token.getToken()); + assertEquals(URI.URLContext.URL_PATH, token.getContext()); + + try { + tokens.get(7); + fail(); + } catch (IndexOutOfBoundsException ioobe) { + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/net/UriToolsTestCase.java b/vespajlib/src/test/java/com/yahoo/net/UriToolsTestCase.java new file mode 100644 index 00000000000..9a17fa341be --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/UriToolsTestCase.java @@ -0,0 +1,25 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import static org.junit.Assert.*; + +import java.net.URISyntaxException; + +import org.junit.Test; + +/** + * Check validity of the URI helper methods. + * + * @author Steinar Knutsen + */ +public class UriToolsTestCase { + + private static final String SEARCH_QUERY = "/search/?query=sddocname:music#trick"; + + @Test + public final void testRawRequest() throws URISyntaxException { + java.net.URI uri = new java.net.URI("http://localhost:" + 8080 + SEARCH_QUERY); + assertEquals(SEARCH_QUERY, UriTools.rawRequest(uri)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/net/UrlTestCase.java b/vespajlib/src/test/java/com/yahoo/net/UrlTestCase.java new file mode 100644 index 00000000000..7cf99cf2c5a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/UrlTestCase.java @@ -0,0 +1,192 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author Simon Thoresen + */ +public class UrlTestCase { + + @Test + public void requireThatAccessorsWork() { + Url url = Url.fromString("scheme://user:pass@host:69/path?query#fragment"); + assertEquals("scheme://user:pass@host:69/path?query#fragment", url.toString()); + assertEquals("scheme", url.getScheme()); + assertEquals(0, url.getSchemeBegin()); + assertEquals(6, url.getSchemeEnd()); + assertEquals("user", url.getUserInfo()); + assertEquals(9, url.getUserInfoBegin()); + assertEquals(13, url.getUserInfoEnd()); + assertEquals("pass", url.getPassword()); + assertEquals(14, url.getPasswordBegin()); + assertEquals(18, url.getPasswordEnd()); + assertEquals("host", url.getHost()); + assertEquals(19, url.getHostBegin()); + assertEquals(23, url.getHostEnd()); + assertEquals("69", url.getPortString()); + assertEquals(24, url.getPortBegin()); + assertEquals(26, url.getPortEnd()); + assertEquals(Integer.valueOf(69), url.getPort()); + assertEquals("/path", url.getPath()); + assertEquals(26, url.getPathBegin()); + assertEquals(31, url.getPathEnd()); + assertEquals("query", url.getQuery()); + assertEquals(32, url.getQueryBegin()); + assertEquals(37, url.getQueryEnd()); + assertEquals("fragment", url.getFragment()); + assertEquals(38, url.getFragmentBegin()); + assertEquals(46, url.getFragmentEnd()); + } + + @Test + public void requireThatOffsetsAreNeverOutOfBounds() { + Url url = Url.fromString("http:"); + assertEquals(0, url.getSchemeBegin()); + assertEquals(4, url.getSchemeEnd()); + assertEquals(5, url.getUserInfoBegin()); + assertEquals(5, url.getUserInfoEnd()); + assertEquals(5, url.getPasswordBegin()); + assertEquals(5, url.getPasswordEnd()); + assertEquals(5, url.getHostBegin()); + assertEquals(5, url.getHostEnd()); + assertEquals(5, url.getPortBegin()); + assertEquals(5, url.getPortEnd()); + assertEquals(5, url.getPathBegin()); + assertEquals(5, url.getPathEnd()); + assertEquals(5, url.getQueryBegin()); + assertEquals(5, url.getQueryEnd()); + assertEquals(5, url.getFragmentBegin()); + assertEquals(5, url.getFragmentEnd()); + + url = Url.fromString("//host"); + assertEquals(0, url.getSchemeBegin()); + assertEquals(0, url.getSchemeEnd()); + assertEquals(2, url.getUserInfoBegin()); + assertEquals(2, url.getUserInfoEnd()); + assertEquals(2, url.getPasswordBegin()); + assertEquals(2, url.getPasswordEnd()); + assertEquals(2, url.getHostBegin()); + assertEquals(6, url.getHostEnd()); + assertEquals(6, url.getPortBegin()); + assertEquals(6, url.getPortEnd()); + assertEquals(6, url.getPathBegin()); + assertEquals(6, url.getPathEnd()); + assertEquals(6, url.getQueryBegin()); + assertEquals(6, url.getQueryEnd()); + assertEquals(6, url.getFragmentBegin()); + assertEquals(6, url.getFragmentEnd()); + } + + @Test + public void requireThatCommonSchemesCanBeParsed() { + assertParse("ftp://ftp.is.co.za/rfc/rfc1808.txt", + "ftp", null, null, "ftp.is.co.za", null, "/rfc/rfc1808.txt", null, null); + assertParse("http://www.ietf.org/rfc/rfc 2396.txt", + "http", null, null, "www.ietf.org", null, "/rfc/rfc 2396.txt", null, null); + assertParse("ldap://[2001:db8::7]/c=GB?objectClass?one", + "ldap", null, null, "2001:db8::7", null, "/c=GB", "objectClass?one", null); + assertParse("mailto:John.Doe@example.com", + "mailto", null, null, null, null, "John.Doe@example.com", null, null); + assertParse("news:comp.infosystems.www.servers.unix", + "news", null, null, null, null, "comp.infosystems.www.servers.unix", null, null); + assertParse("tel:+1-816-555-1212", + "tel", null, null, null, null, "+1-816-555-1212", null, null); + assertParse("telnet://192.0.2.16:80/", + "telnet", null, null, "192.0.2.16", 80, "/", null, null); + assertParse("urn:oasis:names:specification:docbook:dtd:xml:4.1.2", + "urn", null, null, null, null, "oasis:names:specification:docbook:dtd:xml:4.1.2", null, null); + } + + @Test + public void requireThatAllComponentsCanBeParsed() { + assertParse("scheme:", + "scheme", null, null, null, null, null, null, null); + assertParse("scheme://", + "scheme", null, null, null, null, "//", null, null); + assertParse("scheme://host", + "scheme", null, null, "host", null, null, null, null); + try { + assertParse("scheme://host:foo", + null, null, null, null, null, null, null, null); + fail(); + } catch (NumberFormatException e) { + // expected + } + assertParse("scheme://host:69", + "scheme", null, null, "host", 69, null, null, null); + assertParse("scheme://user@host:69", + "scheme", "user", null, "host", 69, null, null, null); + assertParse("scheme://user:pass@host:69", + "scheme", "user", "pass", "host", 69, null, null, null); + assertParse("scheme://user:pass@host:69", + "scheme", "user", "pass", "host", 69, null, null, null); + assertParse("scheme://user:pass@host:69/", + "scheme", "user", "pass", "host", 69, "/", null, null); + assertParse("scheme://user:pass@host:69/path", + "scheme", "user", "pass", "host", 69, "/path", null, null); + assertParse("scheme://user:pass@host:69/path?query", + "scheme", "user", "pass", "host", 69, "/path", "query", null); + assertParse("scheme://user:pass@host:69/path?query#fragment", + "scheme", "user", "pass", "host", 69, "/path", "query", "fragment"); + assertParse("scheme://user@host:69/path?query#fragment", + "scheme", "user", null, "host", 69, "/path", "query", "fragment"); + assertParse("scheme://host:69/path?query#", + "scheme", null, null, "host", 69, "/path", "query", null); + assertParse("scheme://host:69/path?query#fragment", + "scheme", null, null, "host", 69, "/path", "query", "fragment"); + assertParse("scheme://host/path?query#fragment", + "scheme", null, null, "host", null, "/path", "query", "fragment"); + assertParse("scheme:///path?query#fragment", + "scheme", null, null, null, null, "///path", "query", "fragment"); + assertParse("scheme://?query#fragment", + "scheme", null, null, null, null, "//", "query", "fragment"); + assertParse("scheme://#fragment", + "scheme", null, null, null, null, "//", null, "fragment"); + } + + @Test + public void requireThatIPv6CanBeParsed() { + assertParse("http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", + "http", null, null, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", null, null, null, null); + assertParse("http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/path", + "http", null, null, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", null, "/path", null, null); + + assertParse("http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80", + "http", null, null, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", 80, null, null, null); + assertParse("http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80/path", + "http", null, null, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", 80, "/path", null, null); + } + + private static void assertParse(String input, String scheme, String userInfo, String password, String host, + Integer port, String path, String query, String fragment) + { + Url urlA = Url.fromString(input); + assertEquals("Image", input, urlA.toString()); + assertUrl(urlA, scheme, userInfo, password, host, port, path, query, fragment); + + Url urlB = new Url(urlA.getScheme(), urlA.getUserInfo(), urlA.getPassword(), urlA.getHost(), urlA.getPort(), + urlA.getPath(), urlA.getQuery(), urlA.getFragment()); + assertUrl(urlB, scheme, userInfo, password, host, port, path, query, fragment); + + Url urlC = Url.fromString(urlB.toString()); + assertEquals(urlB, urlC); + assertUrl(urlC, scheme, userInfo, password, host, port, path, query, fragment); + } + + private static void assertUrl(Url url, String scheme, String userInfo, String password, String host, Integer port, + String path, String query, String fragment) + { + assertEquals("Scheme", scheme, url.getScheme()); + assertEquals("User", userInfo, url.getUserInfo()); + assertEquals("Password", password, url.getPassword()); + assertEquals("Host", host, url.getHost()); + assertEquals("Port", port, url.getPort()); + assertEquals("Path", path, url.getPath()); + assertEquals("Query", query, url.getQuery()); + assertEquals("Fragment", fragment, url.getFragment()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/net/UrlTokenTestCase.java b/vespajlib/src/test/java/com/yahoo/net/UrlTokenTestCase.java new file mode 100644 index 00000000000..ca42a701655 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/UrlTokenTestCase.java @@ -0,0 +1,47 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Simon Thoresen + */ +public class UrlTokenTestCase { + + @Test + public void requireThatAccessorsWork() { + UrlToken token = new UrlToken(UrlToken.Type.FRAGMENT, 69, "foo", "bar"); + assertEquals(UrlToken.Type.FRAGMENT, token.getType()); + assertEquals(69, token.getOffset()); + assertEquals(3, token.getLength()); + assertEquals("foo", token.getOrig()); + assertEquals("bar", token.getTerm()); + } + + @Test + public void requireThatTypeCanNotBeNull() { + try { + new UrlToken(null, 0, "foo", "bar"); + fail(); + } catch (NullPointerException e) { + + } + } + + @Test + public void requireThatOrigAndTermCanBeNull() { + UrlToken token = new UrlToken(UrlToken.Type.SCHEME, 0, null, "foo"); + assertNull(token.getOrig()); + assertEquals("foo", token.getTerm()); + + token = new UrlToken(UrlToken.Type.SCHEME, 0, "foo", null); + assertEquals("foo", token.getOrig()); + assertNull(token.getTerm()); + + token = new UrlToken(UrlToken.Type.SCHEME, 0, null, null); + assertNull(token.getOrig()); + assertNull(token.getTerm()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/net/UrlTokenizerTestCase.java b/vespajlib/src/test/java/com/yahoo/net/UrlTokenizerTestCase.java new file mode 100644 index 00000000000..d192c0901a6 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/net/UrlTokenizerTestCase.java @@ -0,0 +1,385 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.net; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; + +import static com.yahoo.text.Lowercase.toLowerCase; + +/** + * @author Simon Thoresen + */ +public class UrlTokenizerTestCase { + + @Test + public void requireThatAllTokenCharactersAreAccepted() { + assertTerms("a", "a"); + assertTerms("aa", "aa"); + assertTerms("aaa", "aaa"); + for (int c = Character.MIN_VALUE; c < Character.MAX_VALUE; ++c) { + if (c == '%') { + continue; // escape + } + String img = String.format("a%ca", c); + if ((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c == '-' || c == '_')) + { + assertTerms(img, toLowerCase(img)); + } else { + assertTerms(img, "a", "a"); + } + } + } + + @Test + public void requireThatUrlCanBeTokenized() { + assertTokenize("", + new UrlToken(UrlToken.Type.SCHEME, 0, null, "http"), + new UrlToken(UrlToken.Type.PORT, 0, null, "80")); + assertTokenize("scheme:", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme")); + assertTokenize("scheme://host", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.HOST, 9, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 9, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 13, null, UrlTokenizer.TERM_ENDHOST)); + assertTokenize("scheme://user@host", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.HOST, 14, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 14, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 18, null, UrlTokenizer.TERM_ENDHOST)); + assertTokenize("scheme://user:pass@host", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST)); + assertTokenize("scheme://user:pass@host:69", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "69", "69")); + assertTokenize("scheme://user:pass@host:69/path", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path")); + assertTokenize("scheme://user:pass@host:69/path?query", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 32, "query", "query")); + assertTokenize("scheme://user:pass@host:69/path?query#fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 32, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 38, "fragment", "fragment")); + } + + @Test + public void requireThatComponentsCanHaveMultipleTokens() { + assertTokenize("sch+eme://us+er:pa+ss@ho+st:69/pa/th?que+ry#frag+ment", + new UrlToken(UrlToken.Type.SCHEME, 0, "sch", "sch"), + new UrlToken(UrlToken.Type.SCHEME, 4, "eme", "eme"), + new UrlToken(UrlToken.Type.USERINFO, 10, "us", "us"), + new UrlToken(UrlToken.Type.USERINFO, 13, "er", "er"), + new UrlToken(UrlToken.Type.PASSWORD, 16, "pa", "pa"), + new UrlToken(UrlToken.Type.PASSWORD, 19, "ss", "ss"), + new UrlToken(UrlToken.Type.HOST, 22, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 22, "ho", "ho"), + new UrlToken(UrlToken.Type.HOST, 25, "st", "st"), + new UrlToken(UrlToken.Type.HOST, 27, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 28, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 31, "pa", "pa"), + new UrlToken(UrlToken.Type.PATH, 34, "th", "th"), + new UrlToken(UrlToken.Type.QUERY, 37, "que", "que"), + new UrlToken(UrlToken.Type.QUERY, 41, "ry", "ry"), + new UrlToken(UrlToken.Type.FRAGMENT, 44, "frag", "frag"), + new UrlToken(UrlToken.Type.FRAGMENT, 49, "ment", "ment")); + } + @Test + public void requireThatSequencesOfDelimitersAreCollapsed() { + assertTokenize("sch++eme://us++er:pa++ss@ho++st:69/pa/th?que++ry#frag++ment", + new UrlToken(UrlToken.Type.SCHEME, 0, "sch", "sch"), + new UrlToken(UrlToken.Type.SCHEME, 5, "eme", "eme"), + new UrlToken(UrlToken.Type.USERINFO, 11, "us", "us"), + new UrlToken(UrlToken.Type.USERINFO, 15, "er", "er"), + new UrlToken(UrlToken.Type.PASSWORD, 18, "pa", "pa"), + new UrlToken(UrlToken.Type.PASSWORD, 22, "ss", "ss"), + new UrlToken(UrlToken.Type.HOST, 25, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 25, "ho", "ho"), + new UrlToken(UrlToken.Type.HOST, 29, "st", "st"), + new UrlToken(UrlToken.Type.HOST, 31, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 32, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 35, "pa", "pa"), + new UrlToken(UrlToken.Type.PATH, 38, "th", "th"), + new UrlToken(UrlToken.Type.QUERY, 41, "que", "que"), + new UrlToken(UrlToken.Type.QUERY, 46, "ry", "ry"), + new UrlToken(UrlToken.Type.FRAGMENT, 49, "frag", "frag"), + new UrlToken(UrlToken.Type.FRAGMENT, 55, "ment", "ment")); + } + + @Test + public void requireThatIPv6CanBeTokenized() { + assertTokenize("scheme://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.HOST, 10, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 10, "2001", "2001"), + new UrlToken(UrlToken.Type.HOST, 15, "0db8", "0db8"), + new UrlToken(UrlToken.Type.HOST, 20, "85a3", "85a3"), + new UrlToken(UrlToken.Type.HOST, 25, "0000", "0000"), + new UrlToken(UrlToken.Type.HOST, 30, "0000", "0000"), + new UrlToken(UrlToken.Type.HOST, 35, "8a2e", "8a2e"), + new UrlToken(UrlToken.Type.HOST, 40, "0370", "0370"), + new UrlToken(UrlToken.Type.HOST, 45, "7334", "7334"), + new UrlToken(UrlToken.Type.HOST, 49, null, UrlTokenizer.TERM_ENDHOST)); + } + + @Test + public void requireThatTermsAreLowerCased() { + assertTokenize("SCHEME://USER:PASS@HOST:69/PATH?QUERY#FRAGMENT", + new UrlToken(UrlToken.Type.SCHEME, 0, "SCHEME", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "USER", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "PASS", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "HOST", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 27, "PATH", "path"), + new UrlToken(UrlToken.Type.QUERY, 32, "QUERY", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 38, "FRAGMENT", "fragment")); + } + + @Test + public void requireThatEscapedCharsAreDecoded() { + assertTokenize("sch%65me://%75ser:p%61ss@h%6fst:69/p%61th?q%75ery#fr%61gment", + new UrlToken(UrlToken.Type.SCHEME, 0, "sch%65me", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 11, "%75ser", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 18, "p%61ss", "pass"), + new UrlToken(UrlToken.Type.HOST, 25, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 25, "h%6fst", "host"), + new UrlToken(UrlToken.Type.HOST, 31, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 32, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 35, "p%61th", "path"), + new UrlToken(UrlToken.Type.QUERY, 42, "q%75ery", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 50, "fr%61gment", "fragment")); + } + + @Test + public void requireThatDecodedCharsAreLowerCased() { + assertTokenize("sch%45me://%55ser:p%41ss@h%4fst:69/p%41th?q%55ery#fr%41gment", + new UrlToken(UrlToken.Type.SCHEME, 0, "sch%45me", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 11, "%55ser", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 18, "p%41ss", "pass"), + new UrlToken(UrlToken.Type.HOST, 25, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 25, "h%4fst", "host"), + new UrlToken(UrlToken.Type.HOST, 31, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 32, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 35, "p%41th", "path"), + new UrlToken(UrlToken.Type.QUERY, 42, "q%55ery", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 50, "fr%41gment", "fragment")); + } + + @Test + public void requireThatDecodedCharsCanSplitTokens() { + assertTokenize("sch%2beme://us%2ber:pa%2bss@ho%2bst:69/pa/th?que%2bry#frag%2bment", + new UrlToken(UrlToken.Type.SCHEME, 0, "sch", "sch"), + new UrlToken(UrlToken.Type.SCHEME, 6, "eme", "eme"), + new UrlToken(UrlToken.Type.USERINFO, 12, "us", "us"), + new UrlToken(UrlToken.Type.USERINFO, 17, "er", "er"), + new UrlToken(UrlToken.Type.PASSWORD, 20, "pa", "pa"), + new UrlToken(UrlToken.Type.PASSWORD, 25, "ss", "ss"), + new UrlToken(UrlToken.Type.HOST, 28, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 28, "ho", "ho"), + new UrlToken(UrlToken.Type.HOST, 33, "st", "st"), + new UrlToken(UrlToken.Type.HOST, 35, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 36, "69", "69"), + new UrlToken(UrlToken.Type.PATH, 39, "pa", "pa"), + new UrlToken(UrlToken.Type.PATH, 42, "th", "th"), + new UrlToken(UrlToken.Type.QUERY, 45, "que", "que"), + new UrlToken(UrlToken.Type.QUERY, 51, "ry", "ry"), + new UrlToken(UrlToken.Type.FRAGMENT, 54, "frag", "frag"), + new UrlToken(UrlToken.Type.FRAGMENT, 61, "ment", "ment")); + } + + @Test + public void requireThatSchemeCanBeGuessed() { + assertTokenize("//host:80", + new UrlToken(UrlToken.Type.SCHEME, 0, null, "http"), + new UrlToken(UrlToken.Type.HOST, 2, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 2, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 6, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 7, "80", "80")); + } + + @Test + public void requireThatHostCanBeGuessed() { + assertTokenize("file:/path", + new UrlToken(UrlToken.Type.SCHEME, 0, "file", "file"), + new UrlToken(UrlToken.Type.HOST, 4, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 4, null, "localhost"), + new UrlToken(UrlToken.Type.HOST, 4, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PATH, 6, "path", "path")); + } + + @Test + public void requireThatPortCanBeGuessed() { + assertTokenize("http://host", + new UrlToken(UrlToken.Type.SCHEME, 0, "http", "http"), + new UrlToken(UrlToken.Type.HOST, 7, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 7, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 11, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 11, null, "80")); + } + + @Test + public void requireThatComponentsAreOptional() { + assertTokenize("scheme", "user", "pass", "host", 99, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 32, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 38, "fragment", "fragment")); + assertTokenize(null, "user", "pass", "host", 99, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, null, "http"), + new UrlToken(UrlToken.Type.USERINFO, 2, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 7, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 12, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 12, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 16, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 17, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 20, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 25, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 31, "fragment", "fragment")); + assertTokenize("scheme", null, "pass", "host", 99, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.PASSWORD, 10, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 15, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 15, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 20, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 23, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 28, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 34, "fragment", "fragment")); + assertTokenize("scheme", null, null, "host", 99, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.HOST, 9, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 9, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 13, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 14, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 17, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 22, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 28, "fragment", "fragment")); + assertTokenize("scheme", null, null, null, 99, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.PORT, 8, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 11, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 16, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 22, "fragment", "fragment")); + assertTokenize("scheme", "user", "pass", "host", null, "/path", "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PATH, 24, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 29, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 35, "fragment", "fragment")); + assertTokenize("scheme", "user", "pass", "host", 99, null, "query", "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "99", "99"), + new UrlToken(UrlToken.Type.QUERY, 27, "query", "query"), + new UrlToken(UrlToken.Type.FRAGMENT, 33, "fragment", "fragment")); + assertTokenize("scheme", "user", "pass", "host", 99, "/path", null, "fragment", + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path"), + new UrlToken(UrlToken.Type.FRAGMENT, 32, "fragment", "fragment")); + assertTokenize("scheme", "user", "pass", "host", 99, "/path", "query", null, + new UrlToken(UrlToken.Type.SCHEME, 0, "scheme", "scheme"), + new UrlToken(UrlToken.Type.USERINFO, 9, "user", "user"), + new UrlToken(UrlToken.Type.PASSWORD, 14, "pass", "pass"), + new UrlToken(UrlToken.Type.HOST, 19, null, UrlTokenizer.TERM_STARTHOST), + new UrlToken(UrlToken.Type.HOST, 19, "host", "host"), + new UrlToken(UrlToken.Type.HOST, 23, null, UrlTokenizer.TERM_ENDHOST), + new UrlToken(UrlToken.Type.PORT, 24, "99", "99"), + new UrlToken(UrlToken.Type.PATH, 27, "path", "path"), + new UrlToken(UrlToken.Type.QUERY, 32, "query", "query")); + } + + private static void assertTokenize(String scheme, String userInfo, String password, String host, Integer port, + String path, String query, String fragment, UrlToken... expected) + { + assertTokenize(new Url(scheme, userInfo, password, host, port, path, query, fragment), expected); + } + + private static void assertTokenize(String url, UrlToken... expected) { + assertTokenize(Url.fromString(url), expected); + } + + private static void assertTokenize(Url url, UrlToken... expected) { + Iterator expectedIt = Arrays.asList(expected).iterator(); + Iterator actualIt = new UrlTokenizer(url).tokenize().iterator(); + while (expectedIt.hasNext()) { + assertTrue(actualIt.hasNext()); + assertEquals(expectedIt.next(), actualIt.next()); + } + assertFalse(expectedIt.hasNext()); + assertFalse(actualIt.hasNext()); + } + + private static void assertTerms(String img, String... expected) { + List actual = new LinkedList<>(); + UrlTokenizer.addTokens(actual, UrlToken.Type.PATH, 0, img, true); + + Iterator expectedIt = Arrays.asList(expected).iterator(); + Iterator actualIt = actual.iterator(); + while (expectedIt.hasNext()) { + assertTrue(actualIt.hasNext()); + assertEquals(expectedIt.next(), actualIt.next().getTerm()); + } + assertFalse(expectedIt.hasNext()); + assertFalse(actualIt.hasNext()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/path/PathTest.java b/vespajlib/src/test/java/com/yahoo/path/PathTest.java new file mode 100644 index 00000000000..4d78df0f4e9 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/path/PathTest.java @@ -0,0 +1,128 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.path; + +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author lulf + * @since 5.1 + */ +public class PathTest { + @Test + public void testGetName() { + assertThat(getAbsolutePath().getName(), is("baz")); + assertThat(getRelativePath().getName(), is("baz")); + assertThat(getWithSlashes().getName(), is("baz")); + assertThat(getAppended().getName(), is("baz")); + assertThat(getOne().getName(), is("foo")); + } + + @Test + public void testEquals() { + assertTrue(getAbsolutePath().equals(getAbsolutePath())); + assertTrue(getAbsolutePath().equals(getRelativePath())); + assertTrue(getAbsolutePath().equals(getWithSlashes())); + assertTrue(getAbsolutePath().equals(getAppended())); + assertFalse(getAbsolutePath().equals(getOne())); + + assertTrue(getRelativePath().equals(getAbsolutePath())); + assertTrue(getRelativePath().equals(getRelativePath())); + assertTrue(getRelativePath().equals(getWithSlashes())); + assertTrue(getRelativePath().equals(getAppended())); + assertFalse(getRelativePath().equals(getOne())); + + assertTrue(getWithSlashes().equals(getAbsolutePath())); + assertTrue(getWithSlashes().equals(getRelativePath())); + assertTrue(getWithSlashes().equals(getWithSlashes())); + assertTrue(getWithSlashes().equals(getAppended())); + assertFalse(getWithSlashes().equals(getOne())); + + assertTrue(getAppended().equals(getAbsolutePath())); + assertTrue(getAppended().equals(getRelativePath())); + assertTrue(getAppended().equals(getWithSlashes())); + assertTrue(getAppended().equals(getAppended())); + assertFalse(getAppended().equals(getOne())); + + assertFalse(getOne().equals(getAbsolutePath())); + assertFalse(getOne().equals(getRelativePath())); + assertFalse(getOne().equals(getWithSlashes())); + assertFalse(getOne().equals(getAppended())); + assertTrue(getOne().equals(getOne())); + } + + @Test + public void testGetPath() { + assertThat(getAbsolutePath().getRelative(), is("foo/bar/baz")); + assertThat(getRelativePath().getRelative(), is("foo/bar/baz")); + assertThat(getWithSlashes().getRelative(), is("foo/bar/baz")); + assertThat(getAppended().getRelative(), is("foo/bar/baz")); + assertThat(getOne().getRelative(), is("foo")); + } + + @Test + public void testGetParentPath() { + assertThat(getAbsolutePath().getParentPath().getRelative(), is("foo/bar")); + assertThat(getRelativePath().getParentPath().getRelative(), is("foo/bar")); + assertThat(getWithSlashes().getParentPath().getRelative(), is("foo/bar")); + assertThat(getAppended().getParentPath().getRelative(), is("foo/bar")); + assertThat(getOne().getParentPath().getRelative(), is("")); + } + + @Test + public void testGetAbsolutePath() { + assertThat(getAbsolutePath().getAbsolute(), is("/foo/bar/baz")); + assertThat(getAbsolutePath().getParentPath().getAbsolute(), is("/foo/bar")); + } + + @Test + public void testEmptyPath() { + assertThat(Path.createRoot().getName(), is("")); + assertThat(Path.createRoot().getRelative(), is("")); + assertThat(Path.createRoot().getParentPath().getRelative(), is("")); + assertTrue(Path.createRoot().isRoot()); + } + + @Test + public void testDelimiters() { + assertThat(Path.fromString("foo/bar", ",").getName(), is("foo/bar")); + assertThat(Path.fromString("foo/bar", "/").getName(), is("bar")); + assertThat(Path.fromString("foo,bar", "/").getName(), is("foo,bar")); + assertThat(Path.fromString("foo,bar", ",").getName(), is("bar")); + assertThat(Path.createRoot(",").append("foo").append("bar").getRelative(), is("foo,bar")); + } + + @Test + public void testAppendPath() { + Path p1 = getAbsolutePath(); + Path p2 = getAbsolutePath(); + Path p3 = p1.append(p2); + assertThat(p1.getAbsolute(), is("/foo/bar/baz")); + assertThat(p2.getAbsolute(), is("/foo/bar/baz")); + assertThat(p3.getAbsolute(), is("/foo/bar/baz/foo/bar/baz")); + } + + private Path getRelativePath() { + return Path.fromString("foo/bar/baz"); + } + + private Path getAbsolutePath() { + return Path.fromString("/foo/bar/baz"); + } + + private Path getWithSlashes() { + return Path.fromString("/foo//bar///baz/"); + } + + private Path getAppended() { + return Path.createRoot().append("foo").append("bar").append("baz"); + } + + private Path getOne() { + return Path.fromString("foo"); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/protect/TestErrorMessage.java b/vespajlib/src/test/java/com/yahoo/protect/TestErrorMessage.java new file mode 100644 index 00000000000..fa611d8fd71 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/protect/TestErrorMessage.java @@ -0,0 +1,31 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + +/** + * @author Jon Bratseth + */ +public class TestErrorMessage extends junit.framework.TestCase { + + public void testErrorMessages() { + ErrorMessage m1=new ErrorMessage(17,"Message"); + ErrorMessage m2=new ErrorMessage(17,"Message","Detail"); + ErrorMessage m3=new ErrorMessage(17,"Message","Detail",new Exception("Throwable message")); + assertEquals(17,m1.getCode()); + assertEquals("Message",m1.getMessage()); + assertEquals("Detail",m2.getDetailedMessage()); + assertEquals("Throwable message",m3.getCause().getMessage()); + assertEquals("error : Message (Detail: Throwable message)",m3.toString()); + } + + public void testErrorMessageEquality() { + assertEquals(new ErrorMessage(17,"Message"),new ErrorMessage(17,"Message")); + assertFalse(new ErrorMessage(16,"Message").equals(new ErrorMessage(17,"Message"))); + assertFalse(new ErrorMessage(17,"Message").equals(new ErrorMessage(17,"Other message"))); + assertFalse(new ErrorMessage(17,"Message").equals(new ErrorMessage(17,"Message","Detail"))); + assertFalse(new ErrorMessage(17,"Message","Detail").equals(new ErrorMessage(17,"Message"))); + assertEquals(new ErrorMessage(17,"Message","Detail"),new ErrorMessage(17,"Message","Detail",new Exception())); + assertTrue(new ErrorMessage(17,"Message","Detail").equals(new ErrorMessage(17,"Message","Detail"))); + assertFalse(new ErrorMessage(17,"Message","Detail").equals(new ErrorMessage(17,"Message","Other detail"))); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/protect/ValidatorTestCase.java b/vespajlib/src/test/java/com/yahoo/protect/ValidatorTestCase.java new file mode 100644 index 00000000000..6acbda729e5 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/protect/ValidatorTestCase.java @@ -0,0 +1,88 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.protect; + +/** + * @author Jon Bratseth + */ +public class ValidatorTestCase extends junit.framework.TestCase { + + public void testEnsureNotNull() { + try { + Validator.ensureNotNull("Description",null); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testEnsureNotInitialized() { + try { + Validator.ensureNotInitialized("Description","Field-owner","Initialized-field-value"); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testEnsureInRange() { + try { + Validator.ensureInRange("Description",2,4,5); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testSmallerInts() { + try { + Validator.ensureSmaller("Small-description",3,"Large-description",2); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testSmallerComparables() { + try { + Validator.ensureSmaller("Small-description","b","Large-description","a"); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testEnsure() { + try { + Validator.ensure("Description",false); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testEnsureInstanceOf() { + try { + Validator.ensureInstanceOf("Description","item",Integer.class); + fail("No exception"); + } + catch (Exception e) { + // success + } + } + + public void testVarArgsEnsure() { + Validator.ensure(true, "ignored"); + try { + Validator.ensure(false, "a", "b", "c"); + } catch (Exception e) { + assertEquals("abc", e.getMessage()); + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/reflection/CastingTest.java b/vespajlib/src/test/java/com/yahoo/reflection/CastingTest.java new file mode 100644 index 00000000000..32b506b206f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/reflection/CastingTest.java @@ -0,0 +1,36 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.reflection; + +import org.junit.Test; + +import java.util.Optional; + +import static com.yahoo.text.StringUtilities.quote; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; +import static com.yahoo.reflection.Casting.cast; + +public class CastingTest { + @Test + public void valid_cast_gives_present_optional() { + Object objectToCast = 12; + Optional value = cast(Integer.class, objectToCast); + assertTrue("Value is not present", value.isPresent()); + assertThat(value.get(), is(objectToCast)); + } + + @Test + public void invalid_cast_gives_empty_optional() { + Object objectToCast = "string"; + Optional value = cast(Integer.class, objectToCast); + assertTrue("Value is present", !value.isPresent()); + } + + @Test(expected = IllegalArgumentException.class) + public void cast_sample_usage() { + Object objectToCast = "illegal"; + int result = cast(Integer.class, objectToCast). + filter(i -> !i.equals(0)). + orElseThrow(() -> new IllegalArgumentException("Expected non-zero integer, got " + quote(objectToCast))); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/rmi/.gitignore b/vespajlib/src/test/java/com/yahoo/rmi/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vespajlib/src/test/java/com/yahoo/slime/BinaryFormatTestCase.java b/vespajlib/src/test/java/com/yahoo/slime/BinaryFormatTestCase.java new file mode 100644 index 00000000000..7b42d4e6bda --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/BinaryFormatTestCase.java @@ -0,0 +1,567 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; + +import static com.yahoo.slime.BinaryFormat.*; + +public class BinaryFormatTestCase { + + static final int TYPE_LIMIT = 8; + static final int META_LIMIT = 32; + static final int MAX_CMPR_SIZE = 10; + static final int MAX_NUM_SIZE = 8; + + static final byte enc_t_and_sz(Type t, int size) { + assert size <= 30; + return encode_type_and_meta(t.ID, size + 1); + } + static final byte enc_t_and_m(Type t, int meta) { + assert meta <= 31; + return encode_type_and_meta(t.ID, meta); + } + + void verify_cmpr_long(long value, byte[] expect) { + BinaryEncoder bof = new BinaryEncoder(); + bof.encode_cmpr_long(value); + byte[] actual = bof.out.toArray(); + assertThat(actual, is(expect)); + + BinaryDecoder bif = new BinaryDecoder(); + bif.in = new BufferedInput(expect); + long got = bif.read_cmpr_long(); + assertThat(got, is(value)); + } + + // was verifyBasic + void verifyEncoding(Slime slime, byte[] expect) { + assertThat(BinaryFormat.encode(slime), is(expect)); + verifyMultiEncode(expect); + } + + void verifyMultiEncode(byte[] expect) { + byte[][] buffers = new byte[6][]; + buffers[0] = expect; + + for (int i = 0; i < 5; ++i) { + Slime slime = BinaryFormat.decode(buffers[i]); + buffers[i+1] = BinaryFormat.encode(slime); + assertThat(buffers[i+1], is(expect)); + } + } + + @Test + public void testZigZagConversion() { + System.out.println("test zigzag conversion"); + assertThat(encode_zigzag(0), is((long)0)); + assertThat(decode_zigzag(encode_zigzag(0)), is(0L)); + + assertThat(encode_zigzag(-1), is(1L)); + assertThat(decode_zigzag(encode_zigzag(-1)), is(-1L)); + + assertThat(encode_zigzag(1), is(2L)); + assertThat(decode_zigzag(encode_zigzag(1)), is(1L)); + + assertThat(encode_zigzag(-2), is(3L)); + assertThat(decode_zigzag(encode_zigzag(-2)), is(-2L)); + + assertThat(encode_zigzag(2), is(4L)); + assertThat(decode_zigzag(encode_zigzag(2)), is(2L)); + + assertThat(encode_zigzag(-1000), is(1999L)); + assertThat(decode_zigzag(encode_zigzag(-1000)), is(-1000L)); + + assertThat(encode_zigzag(1000), is(2000L)); + assertThat(decode_zigzag(encode_zigzag(1000)), is(1000L)); + + assertThat(encode_zigzag(-0x8000000000000000L), is(-1L)); + assertThat(decode_zigzag(encode_zigzag(-0x8000000000000000L)), is(-0x8000000000000000L)); + + assertThat(encode_zigzag(0x7fffffffffffffffL), is(-2L)); + assertThat(decode_zigzag(encode_zigzag(0x7fffffffffffffffL)), is(0x7fffffffffffffffL)); + } + + @Test + public void testDoubleConversion() { + System.out.println("test double conversion"); + assertThat(encode_double(0.0), is(0L)); + assertThat(decode_double(encode_double(0.0)), is(0.0)); + + assertThat(encode_double(1.0), is(0x3ff0000000000000L)); + assertThat(decode_double(encode_double(1.0)), is(1.0)); + + assertThat(encode_double(-1.0), is(0xbff0000000000000L)); + assertThat(decode_double(encode_double(-1.0)), is(-1.0)); + + assertThat(encode_double(2.0), is(0x4000000000000000L)); + assertThat(decode_double(encode_double(2.0)), is(2.0)); + + assertThat(encode_double(-2.0), is(0xc000000000000000L)); + assertThat(decode_double(encode_double(-2.0)), is(-2.0)); + + assertThat(encode_double(-0.0), is(0x8000000000000000L)); + assertThat(decode_double(encode_double(-0.0)), is(-0.0)); + + assertThat(encode_double(3.5), is(0x400c000000000000L)); + assertThat(decode_double(encode_double(3.5)), is(3.5)); + + assertThat(encode_double(65535.875), is(0x40EFFFFC00000000L)); + assertThat(decode_double(encode_double(65535.875)), is(65535.875)); + } + + @Test + public void testTypeAndMetaMangling() { + System.out.println("test type and meta mangling"); + for (byte type = 0; type < TYPE_LIMIT; ++type) { + for (int meta = 0; meta < META_LIMIT; ++meta) { + byte mangled = encode_type_and_meta(type, meta); + assertThat(decode_type(mangled).ID, is(type)); + assertThat(decode_meta(mangled), is(meta)); + } + } + } + + // was testCmprUlong + @Test + public void testCmprLong() { + System.out.println("test compressed long"); + { + long value = 0; + byte[] wanted = { 0 }; + verify_cmpr_long(value, wanted); + }{ + long value = 127; + byte[] wanted = { 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 128; + byte[] wanted = { -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 16383; + byte[] wanted = { -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 16384; + byte[] wanted = { -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 2097151; + byte[] wanted = { -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 2097152; + byte[] wanted = { -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 268435455; + byte[] wanted = { -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 268435456; + byte[] wanted = { -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 34359738367L; + byte[] wanted = { -1, -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 34359738368L; + byte[] wanted = { -128, -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 4398046511103L; + byte[] wanted = { -1, -1, -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 4398046511104L; + byte[] wanted = { -128, -128, -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 562949953421311L; + byte[] wanted = { -1, -1, -1, -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 562949953421312L; + byte[] wanted = { -128, -128, -128, -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 72057594037927935L; + byte[] wanted = { -1, -1, -1, -1, -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = 72057594037927936L; + byte[] wanted = { -128, -128, -128, -128, -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = 9223372036854775807L; + byte[] wanted = { -1, -1, -1, -1, -1, -1, -1, -1, 127 }; + verify_cmpr_long(value, wanted); + }{ + long value = -9223372036854775808L; + byte[] wanted = { -128, -128, -128, -128, -128, -128, -128, -128, -128, 1 }; + verify_cmpr_long(value, wanted); + }{ + long value = -1; + byte[] wanted = { -1, -1, -1, -1, -1, -1, -1, -1, -1, 1 }; + verify_cmpr_long(value, wanted); + } + } + + // testWriteByte -> buffered IO test + // testWriteBytes -> buffered IO test + // testReadByte -> buffered IO test + // testReadBytes -> buffered IO test + + @Test + public void testTypeAndSize() { + System.out.println("test type and size conversion"); + + for (byte type = 0; type < TYPE_LIMIT; ++type) { + for (long size = 0; size < 500; ++size) { + BufferedOutput expect = new BufferedOutput(); + BufferedOutput actual = new BufferedOutput(); + + if ((size + 1) < META_LIMIT) { + expect.put(encode_type_and_meta((int)type, (int)(size +1))); + } else { + expect.put(type); + BinaryEncoder encoder = new BinaryEncoder(); + encoder.out = expect; + encoder.encode_cmpr_long(size); + } + { + BinaryEncoder encoder = new BinaryEncoder(); + encoder.out = actual; + encoder.write_type_and_size(type, size); + } + assertThat(actual.toArray(), is(expect.toArray())); + + byte[] got = expect.toArray(); + BinaryDecoder bif = new BinaryDecoder(); + bif.in = new BufferedInput(got); + byte b = bif.in.getByte(); + Type decodedType = decode_type(b); + long decodedSize = bif.read_size(decode_meta(b)); + assertThat(decodedType.ID, is(type)); + assertThat(decodedSize, is(size)); + assertThat(bif.in.getConsumedSize(), is(got.length)); + assertThat(bif.in.failed(), is(false)); + } + } + + } + + static long build_bits(int type, int n, int pre, boolean hi, BufferedOutput expect) { + long value = 0; + expect.put(encode_type_and_meta(type, n)); + for (int i = 0; i < n; ++i) { + byte b = (i < pre) ? 0x00 : (byte)(0x11 * (i - pre + 1)); + expect.put(b); + int shift = hi ? ((7 - i) * 8) : (i * 8); + long bits = b & 0xff; + value |= bits << shift; + } + return value; + } + + @Test + public void testTypeAndBytes() { + System.out.println("test encoding and decoding of type and bytes"); + for (byte type = 0; type < TYPE_LIMIT; ++type) { + for (int n = 0; n < MAX_NUM_SIZE; ++n) { + for (int pre = 0; (pre == 0) || (pre < n); ++pre) { + for (int hi = 0; hi < 2; ++hi) { + BufferedOutput expbuf = new BufferedOutput(); + long bits = build_bits(type, n, pre, (hi != 0), expbuf); + byte[] expect = expbuf.toArray(); + + // test output: + BinaryEncoder bof = new BinaryEncoder(); + bof.out = new BufferedOutput(); + if (hi != 0) { + bof.write_type_and_bytes_be(type, bits); + } else { + bof.write_type_and_bytes_le(type, bits); + } + byte[] actual = bof.out.toArray(); + assertThat(actual, is(expect)); + + // test input: + BinaryDecoder bif = new BinaryDecoder(); + bif.in = new BufferedInput(expect); + int size = decode_meta(bif.in.getByte()); + long decodedBits = (hi != 0) ? bif.read_bytes_be(size) : bif.read_bytes_le(size); + assertThat(decodedBits, is(bits)); + assertThat(bif.in.getConsumedSize(), is(expect.length)); + assertThat(bif.in.failed(), is(false)); + } + } + } + } + } + + @Test + public void testEmpty() { + System.out.println("test encoding empty slime"); + + Slime slime = new Slime(); + BufferedOutput expect = new BufferedOutput(); + expect.put((byte)0); // num symbols + expect.put((byte)0); // nix + byte[] actual = BinaryFormat.encode(slime); + + assertThat(actual, is(expect.toArray())); + verifyMultiEncode(expect.toArray()); + } + + @Test + public void testBasic() { + System.out.println("test encoding slime holding a single basic value"); + { + Slime slime = new Slime(); + slime.setBool(false); + byte[] expect = { 0, Type.BOOL.ID }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setBool(true); + byte[] expect = { 0, enc_t_and_m(Type.BOOL, 1) }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setLong(0); + byte[] expect = { 0, Type.LONG.ID }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setLong(13); + byte[] expect = { 0, enc_t_and_m(Type.LONG, 1), 13*2 }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setLong(-123456789); + final long ev = (2 * 123456789) - 1; + byte b1 = (byte)(ev); + byte b2 = (byte)(ev >> 8); + byte b3 = (byte)(ev >> 16); + byte b4 = (byte)(ev >> 24); + + byte[] expect = { 0, enc_t_and_m(Type.LONG, 4), b1, b2, b3, b4 }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setDouble(0.0); + byte[] expect = { 0, Type.DOUBLE.ID }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setDouble(1.0); + byte[] expect = { 0, enc_t_and_m(Type.DOUBLE, 2), (byte)0x3f, (byte)0xf0 }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setString(""); + byte[] expect = { 0, enc_t_and_sz(Type.STRING, 0) }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setString("fo"); + byte[] expect = { 0, enc_t_and_sz(Type.STRING, 2), 'f', 'o' }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + byte[] expect = { 0, Type.STRING.ID, 26*2, + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z' + }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + slime.setData(new byte[0]); + byte[] expect = { 0, enc_t_and_sz(Type.DATA, 0) }; + verifyEncoding(slime, expect); + } + { + Slime slime = new Slime(); + byte[] data = { 42, -123 }; + slime.setData(data); + byte[] expect = { 0, enc_t_and_sz(Type.DATA, 2), 42, -123 }; + verifyEncoding(slime, expect); + } + } + + @Test + public void testBufferedInputWithOffset() { + Slime slime = new Slime(); + byte[] data = { 42, -123 }; + slime.setData(data); + byte[] expect = { 0, enc_t_and_sz(Type.DATA, 2), 42, -123 }; + verifyEncoding(slime, expect); + byte [] overlappingBuffer = new byte [expect.length + 2]; + System.arraycopy(expect, 0, overlappingBuffer, 1, expect.length); + overlappingBuffer[overlappingBuffer.length - 1] = 0; + Slime copy = BinaryFormat.decode(overlappingBuffer, 1, expect.length); + assertThat(BinaryFormat.encode(slime), is(BinaryFormat.encode(copy))); + } + + @Test + public void testArray() { + System.out.println("test encoding slime holding an array of various basic values"); + Slime slime = new Slime(); + Cursor c = slime.setArray(); + byte[] data = { 'd', 'a', 't', 'a' }; + c.addNix(); + c.addBool(true); + c.addLong(42); + c.addDouble(3.5); + c.addString("string"); + c.addData(data); + byte[] expect = { + 0, // num symbols + enc_t_and_sz(Type.ARRAY, 6), // value type and size + 0, // nix + enc_t_and_m(Type.BOOL, 1), + enc_t_and_m(Type.LONG, 1), 42*2, + enc_t_and_m(Type.DOUBLE, 2), 0x40, 0x0c, // 3.5 + enc_t_and_sz(Type.STRING, 6), 's', 't', 'r', 'i', 'n', 'g', + enc_t_and_sz(Type.DATA, 4), 'd', 'a', 't', 'a' + }; + verifyEncoding(slime, expect); + } + + @Test + public void testObject() { + System.out.println("test encoding slime holding an object of various basic values"); + Slime slime = new Slime(); + Cursor c = slime.setObject(); + byte[] data = { 'd', 'a', 't', 'a' }; + c.setNix("a"); + c.setBool("b", true); + c.setLong("c", 42); + c.setDouble("d", 3.5); + c.setString("e", "string"); + c.setData("f", data); + byte[] expect = { + 6, // num symbols + 1, 'a', 1, 'b', 1, 'c', 1, 'd', 1, 'e', 1, 'f', // symbol table + enc_t_and_sz(Type.OBJECT, 6), // value type and size + 0, 0, // nix + 1, enc_t_and_m(Type.BOOL, 1), + 2, enc_t_and_m(Type.LONG, 1), 42*2, + 3, enc_t_and_m(Type.DOUBLE, 2), 0x40, 0x0c, // 3.5 + 4, enc_t_and_sz(Type.STRING, 6), 's', 't', 'r', 'i', 'n', 'g', + 5, enc_t_and_sz(Type.DATA, 4), 'd', 'a', 't', 'a' + }; + verifyEncoding(slime, expect); + } + + @Test + public void testNesting() { + System.out.println("test encoding slime holding a more complex structure"); + Slime slime = new Slime(); + Cursor c1 = slime.setObject(); + c1.setLong("bar", 10); + Cursor c2 = c1.setArray("foo"); + c2.addLong(20); + Cursor c3 = c2.addObject(); + c3.setLong("answer", 42); + byte[] expect = { + 3, // num symbols + 3, 'b', 'a', 'r', + 3, 'f', 'o', 'o', + 6, 'a', 'n', 's', 'w', 'e', 'r', + enc_t_and_sz(Type.OBJECT, 2), // value type and size + 0, enc_t_and_m(Type.LONG, 1), 10*2, + 1, enc_t_and_sz(Type.ARRAY, 2), // nested value type and size + enc_t_and_m(Type.LONG, 1), 20*2, + enc_t_and_sz(Type.OBJECT, 1), // doubly nested value + 2, enc_t_and_m(Type.LONG, 1), 42*2 + }; + verifyEncoding(slime, expect); + } + + @Test + public void testSymbolReuse() { + System.out.println("test encoding slime reusing symbols"); + Slime slime = new Slime(); + Cursor c1 = slime.setArray(); + { + Cursor c2 = c1.addObject(); + c2.setLong("foo", 10); + c2.setLong("bar", 20); + } + { + Cursor c2 = c1.addObject(); + c2.setLong("foo", 100); + c2.setLong("bar", 200); + } + byte[] expect = { + 2, // num symbols + 3, 'f', 'o', 'o', + 3, 'b', 'a', 'r', + enc_t_and_sz(Type.ARRAY, 2), // value type and size + enc_t_and_sz(Type.OBJECT, 2), // nested value + 0, enc_t_and_m(Type.LONG, 1), 10*2, // foo + 1, enc_t_and_m(Type.LONG, 1), 20*2, // bar + enc_t_and_sz(Type.OBJECT, 2), // nested value + 0, enc_t_and_m(Type.LONG, 1), (byte)(100*2), // foo + 1, enc_t_and_m(Type.LONG, 2), (byte)144, 1 // bar: 2*200 = 400 = 256 + 144 + }; + verifyEncoding(slime, expect); + } + + @Test + public void testOptionalDecodeOrder() { + System.out.println("test decoding slime with different symbol order"); + byte[] data = { + 5, // num symbols + 1, 'd', 1, 'e', 1, 'f', 1, 'b', 1, 'c', // symbol table + enc_t_and_sz(Type.OBJECT, 5), // value type and size + 3, enc_t_and_m(Type.BOOL, 1), // b + 1, enc_t_and_sz(Type.STRING, 6), // e + 's', 't', 'r', 'i', 'n', 'g', + 0, enc_t_and_m(Type.DOUBLE, 2), 0x40, 0x0c, // d + 4, enc_t_and_m(Type.LONG, 1), 5*2, // c + 2, enc_t_and_sz(Type.DATA, 4), // f + 'd', 'a', 't', 'a' + }; + Slime slime = new Slime(); + BinaryDecoder decoder = new BinaryDecoder(); + slime = decoder.decode(data); + int consumed = decoder.in.getConsumedSize(); + assertThat(consumed, is(data.length)); + Cursor c = slime.get(); + assertThat(c.valid(), is(true)); + assertThat(c.type(), is(Type.OBJECT)); + assertThat(c.children(), is(5)); + assertThat(c.field("b").asBool(), is(true)); + assertThat(c.field("c").asLong(), is(5L)); + assertThat(c.field("d").asDouble(), is(3.5)); + assertThat(c.field("e").asString(), is("string")); + byte[] expd = { 'd', 'a', 't', 'a' }; + assertThat(c.field("f").asData(), is(expd)); + assertThat(c.entry(5).valid(), is(false)); // not ARRAY + } +} diff --git a/vespajlib/src/test/java/com/yahoo/slime/JsonBenchmark.java b/vespajlib/src/test/java/com/yahoo/slime/JsonBenchmark.java new file mode 100644 index 00000000000..8ee1a91c970 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/JsonBenchmark.java @@ -0,0 +1,114 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.Integer; + +/** + * Created by balder on 2/26/14. + */ +public class JsonBenchmark { + private static byte [] createJson(int numElements) { + Slime slime = new Slime(); + Cursor a = slime.setArray(); + for (int i=0; i < numElements; i++) { + Cursor e = a.addObject(); + e.setString("key", "i"); + e.setLong("weight", i); + } + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + JsonFormat json = new JsonFormat(false); + try { + json.encode(bs, slime); + } catch (IOException e) { + throw new RuntimeException(e); + } + return bs.toByteArray(); + } + private static long benchmarkJacksonStreaming(byte [] json, int numIterations) { + long count = 0; + JsonFactory jsonFactory = new JsonFactory(); + + try { + for (int i=0; i < numIterations; i++) { + JsonParser jsonParser = jsonFactory.createParser(json); + JsonToken array = jsonParser.nextToken(); + for (JsonToken token = jsonParser.nextToken(); ! JsonToken.END_ARRAY.equals(token); token = jsonParser.nextToken()) { + if (JsonToken.FIELD_NAME.equals(token) && "weight".equals(jsonParser.getCurrentName())) { + token = jsonParser.nextToken(); + count += jsonParser.getLongValue(); + } + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return count; + } + private static long benchmarkJacksonTree(byte [] json, int numIterations) { + long count = 0; + ObjectMapper mapper = new ObjectMapper(); + // use the ObjectMapper to read the json string and create a tree + try { + for (int i=0; i < numIterations; i++) { + JsonNode node = mapper.readTree(json); + for(JsonNode item : node) { + count += item.get("weight").asLong(); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return count; + } + private static long benchmarkSlime(byte [] json, int numIterations) { + long count = 0; + for (int i=0; i < numIterations; i++) { + JsonDecoder decoder = new JsonDecoder(); + Slime slime = decoder.decode(new Slime(), json); + + Cursor array = slime.get(); + int weightSymbol = slime.lookup("weight"); + for (int j=0, m=slime.get().children(); j < m; j++) { + count += array.entry(j).field(weightSymbol).asLong(); + } + } + return count; + } + private static void warmup(byte [] json) { + System.out.println(System.currentTimeMillis() + " Warming up"); + benchmarkSlime(json, 5000); + System.out.println(System.currentTimeMillis() + " Done Warming up"); + } + + /** + * jacksons 1000 40000 = 5.6 seconds + * jacksont 1000 40000 = 11.0 seconds + * slime 1000 40000 = 17.5 seconds + * @param argv type, num elements in weigted set, num iterations + */ + static public void main(String argv[]) { + String type = argv[0]; + byte [] json = createJson(Integer.valueOf(argv[1])); + warmup(json); + int count = Integer.valueOf(argv[2]); + System.out.println(System.currentTimeMillis() + " Start"); + long start = System.currentTimeMillis(); + long numValues; + if ("jacksons".equals(type)) { + numValues = benchmarkJacksonStreaming(json, count); + } else if ("jacksont".equals(type)) { + numValues = benchmarkJacksonTree(json, count); + } else{ + numValues = benchmarkSlime(json, count); + } + System.out.println(System.currentTimeMillis() + " End with " + numValues + " values in " + (System.currentTimeMillis() - start) + " milliseconds."); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/slime/JsonFormatTestCase.java b/vespajlib/src/test/java/com/yahoo/slime/JsonFormatTestCase.java new file mode 100644 index 00000000000..e48a717f150 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/JsonFormatTestCase.java @@ -0,0 +1,273 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import com.yahoo.text.Utf8; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class JsonFormatTestCase { + + @Test + public void testBasic() { + System.out.println("test encoding slime holding a single basic value"); + { + Slime slime = new Slime(); + slime.setBool(false); + verifyEncoding(slime, "false"); + } + + { + Slime slime = new Slime(); + slime.setBool(true); + verifyEncoding(slime, "true"); + } + + { + Slime slime = new Slime(); + slime.setLong(0); + verifyEncoding(slime, "0"); + } + { + Slime slime = new Slime(); + slime.setLong(13); + verifyEncoding(slime, "13"); + } + { + Slime slime = new Slime(); + slime.setLong(-123456789); + verifyEncoding(slime, "-123456789"); + } + { + Slime slime = new Slime(); + slime.setDouble(0.0); + verifyEncoding(slime, "0.0"); + } + { + Slime slime = new Slime(); + slime.setDouble(1.5); + verifyEncoding(slime, "1.5"); + } + { + Slime slime = new Slime(); + slime.setString(""); + verifyEncoding(slime, "\"\""); + } + { + Slime slime = new Slime(); + slime.setString("fo"); + verifyEncoding(slime, "\"fo\""); + } + { + Slime slime = new Slime(); + slime.setString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + verifyEncoding(slime, "\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\""); + } + { + Slime slime = new Slime(); + slime.setData(new byte[0]); + verifyEncoding(slime, "\"0x\""); + } + + { + Slime slime = new Slime(); + byte[] data = { 42, -123 }; + slime.setData(data); + String expect = "\"0x2A85\""; + verifyEncoding(slime, expect); + } + + { + Slime slime = new Slime(); + String expected = "\"my\\nencoded\\rsting\\\\is\\bthe\\fnicest\\t\\\"string\\\"\\u0005\""; + slime.setString("my\nencoded\rsting\\is\bthe\fnicest\t\"string\"" + Character.toString((char) 5)); + verifyEncoding(slime, expected); + } + + { + Slime slime = new Slime(); + slime.setDouble(Double.NaN); + verifyEncoding(slime, "null"); + slime.setDouble(Double.NEGATIVE_INFINITY); + verifyEncoding(slime, "null"); + slime.setDouble(Double.POSITIVE_INFINITY); + verifyEncoding(slime, "null"); + } + } + + @Test + public void testArray() { + System.out.println("test encoding slime holding an array of various basic values"); + Slime slime = new Slime(); + Cursor c = slime.setArray(); + byte[] data = { 'd', 'a', 't', 'a' }; + c.addNix(); + c.addBool(true); + c.addLong(42); + c.addDouble(3.5); + c.addString("string"); + c.addData(data); + + verifyEncoding(slime, "[null,true,42,3.5,\"string\",\"0x64617461\"]"); + } + + @Test + public void testObject() { + System.out.println("test encoding slime holding an object of various basic values"); + Slime slime = new Slime(); + Cursor c = slime.setObject(); + byte[] data = { 'd', 'a', 't', 'a' }; + c.setNix("a"); + c.setBool("b", true); + c.setLong("c", 42); + c.setDouble("d", 3.5); + c.setString("e", "string"); + c.setData("f", data); + verifyEncoding(slime, "{\"a\":null,\"b\":true,\"c\":42,\"d\":3.5,\"e\":\"string\",\"f\":\"0x64617461\"}"); + String expected = "{\n" + + " \"a\": null,\n" + + " \"b\": true,\n" + + " \"c\": 42,\n" + + " \"d\": 3.5,\n" + + " \"e\": \"string\",\n" + + " \"f\": \"0x64617461\"\n" + + "}\n"; + verifyEncoding(slime, expected, false); + } + + @Test + public void testNesting() { + System.out.println("test encoding slime holding a more complex structure"); + Slime slime = new Slime(); + Cursor c1 = slime.setObject(); + c1.setLong("bar", 10); + Cursor c2 = c1.setArray("foo"); + c2.addLong(20); + Cursor c3 = c2.addObject(); + c3.setLong("answer", 42); + verifyEncoding(slime, "{\"bar\":10,\"foo\":[20,{\"answer\":42}]}"); + } + + @Test + public void testDecodeEncode() { + System.out.println("test decoding and encoding a json string yields the same string"); + verifyEncodeDecode("{\"bar\":10,\"foo\":[20,{\"answer\":42}]}", true); + String expected = "{\n" + + " \"a\": null,\n" + + " \"b\": true,\n" + + " \"c\": 42,\n" + + " \"d\": 3.5,\n" + + " \"e\": \"string\",\n" + + " \"f\": \"0x64617461\"\n" + + "}\n"; + verifyEncodeDecode(expected, false); + } + + @Test + public void testDecodeEncodeUtf8() { + final String json = "{\n" + + " \"rules\": \"# Use unicode equivalents in java source:\\n" + + " #\\n" + + " # ä½³:\u4f73\"\n" + + "}\n"; + verifyEncodeDecode(json, false); + } + + @Test + public void testDecodeUtf8() { + final String str = "\u4f73:\u4f73"; + final String json = " {\n" + + " \"rules\": \"" + str + "\"\n" + + " }\n"; + + Slime slime = new Slime(); + slime = new JsonDecoder().decode(slime, Utf8.toBytesStd(json)); + Cursor a = slime.get().field("rules"); + assertThat(a.asString(), is(str)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testThatDecodeIsNotImplemented() throws IOException { + new JsonFormat(true).decode(null, null); + } + + private void verifyEncoding(Slime slime, String expected) { + verifyEncoding(slime, expected, true); + } + + @Test + public void testEncodingUTF8() throws IOException { + Slime slime = new Slime(); + slime.setString("M\u00E6L"); + ByteArrayOutputStream a = new ByteArrayOutputStream(); + new JsonFormat(true).encode(a, slime); + String val = new String(a.toByteArray(), "UTF-8"); + assertEquals("\"M\u00E6L\"", val); + + // TODO Some issues with newline + /* + slime = new Slime(); + final String str = "# Use unicode equivalents in java source:\n" + + " #\n" + + " #\n" + + " # ä½³:\u4f73\n"; + slime.setString(str); + a = new ByteArrayOutputStream(); + new JsonFormat(true).encode(a, slime); + val = new String(a.toByteArray(), "UTF-8"); + assertEquals(str, val); + */ + } + + private void verifyEncoding(Slime slime, String expected, boolean compact) { + try { + ByteArrayOutputStream a = new ByteArrayOutputStream(); + new JsonFormat(compact).encode(a, slime); + assertEquals(expected, new String(a.toByteArray(), StandardCharsets.UTF_8)); + } catch (Exception e) { + fail("Exception thrown when encoding slime: " + e.getMessage()); + } + } + + private void verifyEncodeDecode(String json, boolean compact) { + try { + Slime slime = new Slime(); + new JsonDecoder().decode(slime, Utf8.toBytesStd(json)); + ByteArrayOutputStream a = new ByteArrayOutputStream(); + new JsonFormat(compact).encode(a, slime); + assertEquals(json, Utf8.toString(a.toByteArray())); + } catch (Exception e) { + fail("Exception thrown when encoding slime: " + e.getMessage()); + } + } + + private String formatDecimal(double value) { + try { + Slime slime = new Slime(); + slime.setDouble(value); + ByteArrayOutputStream a = new ByteArrayOutputStream(); + new JsonFormat(true).encode(a, slime); + return new String(a.toByteArray(), StandardCharsets.UTF_8); + } catch (Exception e) { + return ""; + } + } + + @Test + public void testDecimalFormat() { + assertEquals("0.0", formatDecimal(0.0)); + assertEquals("1.0", formatDecimal(1.0)); + assertEquals("2.0", formatDecimal(2.0)); + assertEquals("1.2", formatDecimal(1.2)); + assertEquals("3.333333", formatDecimal(3.333333)); + assertEquals("1.0E20", formatDecimal(1e20)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/slime/SlimeTestCase.java b/vespajlib/src/test/java/com/yahoo/slime/SlimeTestCase.java new file mode 100644 index 00000000000..371668d3821 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/SlimeTestCase.java @@ -0,0 +1,330 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import org.junit.Test; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; + +public class SlimeTestCase { + + @Test + public void testTypeIds() { + System.out.println("testing type identifiers..."); + + assertThat(Type.NIX.ID, is((byte)0)); + assertThat(Type.BOOL.ID, is((byte)1)); + assertThat(Type.LONG.ID, is((byte)2)); + assertThat(Type.DOUBLE.ID, is((byte)3)); + assertThat(Type.STRING.ID, is((byte)4)); + assertThat(Type.DATA.ID, is((byte)5)); + assertThat(Type.ARRAY.ID, is((byte)6)); + assertThat(Type.OBJECT.ID, is((byte)7)); + + assertThat(Type.values().length, is(8)); + + assertThat(Type.values()[0], sameInstance(Type.NIX)); + assertThat(Type.values()[1], sameInstance(Type.BOOL)); + assertThat(Type.values()[2], sameInstance(Type.LONG)); + assertThat(Type.values()[3], sameInstance(Type.DOUBLE)); + assertThat(Type.values()[4], sameInstance(Type.STRING)); + assertThat(Type.values()[5], sameInstance(Type.DATA)); + assertThat(Type.values()[6], sameInstance(Type.ARRAY)); + assertThat(Type.values()[7], sameInstance(Type.OBJECT)); + } + + @Test + public void testEmpty() { + System.out.println("testing empty slime..."); + Slime slime = new Slime(); + Cursor cur; + for (int i = 0; i < 2; i++) { + if (i == 0) { + cur = slime.get(); + assertThat(cur.valid(), is(true)); + } else { + cur = NixValue.invalid(); + assertThat(cur.valid(), is(false)); + } + assertThat(cur.type(), is(Type.NIX)); + assertThat(cur.children(), is(0)); + assertThat(cur.asBool(), is(false)); + assertThat(cur.asLong(), is((long)0)); + assertThat(cur.asDouble(), is(0.0)); + assertThat(cur.asString(), is("")); + assertThat(cur.asData(), is(new byte[0])); + assertThat(cur.entry(0).valid(), is(false)); + assertThat(cur.field(0).valid(), is(false)); + assertThat(cur.field("foo").valid(), is(false)); + } + Inspector insp; + for (int i = 0; i < 2; i++) { + if (i == 0) { + insp = slime.get(); + assertThat(insp.valid(), is(true)); + } else { + insp = NixValue.invalid(); + assertThat(insp.valid(), is(false)); + } + assertThat(insp.type(), is(Type.NIX)); + assertThat(insp.children(), is(0)); + assertThat(insp.asBool(), is(false)); + assertThat(insp.asLong(), is((long)0)); + assertThat(insp.asDouble(), is(0.0)); + assertThat(insp.asString(), is("")); + assertThat(insp.asData(), is(new byte[0])); + assertThat(insp.entry(0).valid(), is(false)); + assertThat(insp.field(0).valid(), is(false)); + assertThat(insp.field("foo").valid(), is(false)); + } + } + + @Test + public void testBasic() { + System.out.println("testing basic values..."); + Slime slime = new Slime(); + + System.out.println("testing boolean value"); + slime.setBool(true); + Inspector insp = slime.get(); + assertThat(insp.valid(), is(true)); + assertThat(insp.type(), sameInstance(Type.BOOL)); + assertThat(insp.asBool(), is(true)); + Cursor cur = slime.get(); + assertThat(cur.valid(), is(true)); + assertThat(cur.type(), sameInstance(Type.BOOL)); + assertThat(cur.asBool(), is(true)); + + System.out.println("testing long value"); + slime.setLong(42); + cur = slime.get(); + insp = slime.get(); + assertThat(cur.valid(), is(true)); + assertThat(insp.valid(), is(true)); + assertThat(cur.type(), sameInstance(Type.LONG)); + assertThat(insp.type(), sameInstance(Type.LONG)); + assertThat(cur.asLong(), is((long)42)); + assertThat(insp.asLong(), is((long)42)); + + System.out.println("testing double value"); + slime.setDouble(4.2); + cur = slime.get(); + insp = slime.get(); + assertThat(cur.valid(), is(true)); + assertThat(insp.valid(), is(true)); + assertThat(cur.type(), sameInstance(Type.DOUBLE)); + assertThat(insp.type(), sameInstance(Type.DOUBLE)); + assertThat(cur.asDouble(), is(4.2)); + assertThat(insp.asDouble(), is(4.2)); + + System.out.println("testing string value"); + slime.setString("fortytwo"); + cur = slime.get(); + insp = slime.get(); + assertThat(cur.valid(), is(true)); + assertThat(insp.valid(), is(true)); + assertThat(cur.type(), sameInstance(Type.STRING)); + assertThat(insp.type(), sameInstance(Type.STRING)); + assertThat(cur.asString(), is("fortytwo")); + assertThat(insp.asString(), is("fortytwo")); + + System.out.println("testing data value"); + byte[] data = { (byte)4, (byte)2 }; + slime.setData(data); + cur = slime.get(); + insp = slime.get(); + assertThat(cur.valid(), is(true)); + assertThat(insp.valid(), is(true)); + assertThat(cur.type(), sameInstance(Type.DATA)); + assertThat(insp.type(), sameInstance(Type.DATA)); + assertThat(cur.asData(), is(data)); + assertThat(insp.asData(), is(data)); + data[0] = 10; + data[1] = 20; + byte[] data2 = { 10, 20 }; + assertThat(cur.asData(), is(data2)); + assertThat(insp.asData(), is(data2)); + } + + @Test + public void testArray() { + System.out.println("testing array values..."); + Slime slime = new Slime(); + Cursor c = slime.setArray(); + assertThat(c.valid(), is(true)); + assertThat(c.type(), is(Type.ARRAY)); + assertThat(c.children(), is(0)); + Inspector i = slime.get(); + assertThat(i.valid(), is(true)); + assertThat(i.type(), is(Type.ARRAY)); + assertThat(i.children(), is(0)); + c.addNix(); + c.addBool(true); + c.addLong(5); + c.addDouble(3.5); + c.addString("string"); + byte[] data = { (byte)'d', (byte)'a', (byte)'t', (byte)'a' }; + c.addData(data); + assertThat(c.children(), is(6)); + assertThat(c.entry(0).valid(), is(true)); + assertThat(c.entry(1).asBool(), is(true)); + assertThat(c.entry(2).asLong(), is((long)5)); + assertThat(c.entry(3).asDouble(), is(3.5)); + assertThat(c.entry(4).asString(), is("string")); + assertThat(c.entry(5).asData(), is(data)); + assertThat(c.field(5).valid(), is(false)); // not OBJECT + + assertThat(i.children(), is(6)); + assertThat(i.entry(0).valid(), is(true)); + assertThat(i.entry(1).asBool(), is(true)); + assertThat(i.entry(2).asLong(), is((long)5)); + assertThat(i.entry(3).asDouble(), is(3.5)); + assertThat(i.entry(4).asString(), is("string")); + assertThat(i.entry(5).asData(), is(data)); + assertThat(i.field(5).valid(), is(false)); // not OBJECT + } + + @Test + public void testObject() { + System.out.println("testing object values..."); + Slime slime = new Slime(); + Cursor c = slime.setObject(); + + assertThat(c.valid(), is(true)); + assertThat(c.type(), is(Type.OBJECT)); + assertThat(c.children(), is(0)); + Inspector i = slime.get(); + assertThat(i.valid(), is(true)); + assertThat(i.type(), is(Type.OBJECT)); + assertThat(i.children(), is(0)); + + c.setNix("a"); + c.setBool("b", true); + c.setLong("c", 5); + c.setDouble("d", 3.5); + c.setString("e", "string"); + byte[] data = { (byte)'d', (byte)'a', (byte)'t', (byte)'a' }; + c.setData("f", data); + + assertThat(c.children(), is(6)); + assertThat(c.field("a").valid(), is(true)); + assertThat(c.field("b").asBool(), is(true)); + assertThat(c.field("c").asLong(), is((long)5)); + assertThat(c.field("d").asDouble(), is(3.5)); + assertThat(c.field("e").asString(), is("string")); + assertThat(c.field("f").asData(), is(data)); + assertThat(c.entry(4).valid(), is(false)); // not ARRAY + + assertThat(i.children(), is(6)); + assertThat(i.field("a").valid(), is(true)); + assertThat(i.field("b").asBool(), is(true)); + assertThat(i.field("c").asLong(), is((long)5)); + assertThat(i.field("d").asDouble(), is(3.5)); + assertThat(i.field("e").asString(), is("string")); + assertThat(i.field("f").asData(), is(data)); + assertThat(i.entry(4).valid(), is(false)); // not ARRAY + } + + @Test + public void testChaining() { + System.out.println("testing cursor chaining..."); + { + Slime slime = new Slime(); + Cursor c = slime.setArray(); + assertThat(c.addLong(5).asLong(), is((long)5)); + } + { + Slime slime = new Slime(); + Cursor c = slime.setObject(); + assertThat(c.setLong("a", 5).asLong(), is((long)5)); + } + } + + @Test + public void testCursorToInspector() { + System.out.println("testing proxy conversion..."); + + Slime slime = new Slime(); + Cursor c = slime.setLong(10); + Inspector i1 = c; + assertThat(i1.asLong(), is((long)10)); + + Inspector i2 = slime.get(); + assertThat(i2.asLong(), is((long)10)); + } + + @Test + public void testNesting() { + System.out.println("testing data nesting..."); + Slime slime = new Slime(); + { + Cursor c1 = slime.setObject(); + c1.setLong("bar", 10); + Cursor c2 = c1.setArray("foo"); + c2.addLong(20); + Cursor c3 = c2.addObject(); + c3.setLong("answer", 42); + } + Inspector i = slime.get(); + assertThat(i.field("bar").asLong(), is((long)10)); + assertThat(i.field("foo").entry(0).asLong(), is((long)20)); + assertThat(i.field("foo").entry(1).field("answer").asLong(), is((long)42)); + + Cursor c = slime.get(); + assertThat(c.field("bar").asLong(), is((long)10)); + assertThat(c.field("foo").entry(0).asLong(), is((long)20)); + assertThat(c.field("foo").entry(1).field("answer").asLong(), is((long)42)); + } + + @Test + public void testLotsOfSymbolsAndFields() { + // put pressure on symbol table and object fields + int n = 1000; + Slime slime = new Slime(); + Cursor c = slime.setObject(); + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + assertThat(slime.lookup(str), is(SymbolTable.INVALID)); + assertThat(c.field(str).type(), sameInstance(Type.NIX)); + switch (i % 2) { + case 0: assertThat((int)c.setLong(str, i).asLong(), is(i)); break; + case 1: assertThat(slime.insert(str), is(i)); break; + } + } + for (int i = 0; i < n; i++) { + String str = ("" + i + "_str_" + i); + assertThat(slime.lookup(str), is(i)); + switch (i % 2) { + case 0: assertThat((int)c.field(str).asLong(), is(i)); break; + case 1: assertThat((int)c.field(str).asLong(), is(0)); break; + } + } + } + + @Test + public void testLotsOfEntries() { + // put pressure on array entries + int n = 1000; + Slime slime = new Slime(); + Cursor c = slime.setArray(); + for (int i = 0; i < n; i++) { + assertThat((int)c.addLong(i).asLong(), is(i)); + } + for (int i = 0; i < n; i++) { + assertThat((int)c.entry(i).asLong(), is(i)); + } + assertThat((int)c.entry(n).asLong(), is(0)); + } + + @Test + public void testToString() { + Slime slime = new Slime(); + Cursor c1 = slime.setArray(); + c1.addLong(20); + Cursor c2 = c1.addObject(); + c2.setLong("answer", 42); + assertThat(slime.get().toString(), is("[20,{\"answer\":42}]")); + c1.addString("\u2008"); + assertThat(slime.get().toString(), is("[20,{\"answer\":42},\"\u2008\"]")); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/slime/VisitorTestCase.java b/vespajlib/src/test/java/com/yahoo/slime/VisitorTestCase.java new file mode 100644 index 00000000000..949cb4eecf2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/slime/VisitorTestCase.java @@ -0,0 +1,101 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.slime; + +import org.junit.Test; +import org.mockito.Mockito; + +import static org.mockito.Matchers.argThat; +import static org.hamcrest.CoreMatchers.sameInstance; + +public class VisitorTestCase { + + @Test + public void testVisitInvalid() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().get().field("invalid"); + inspector.accept(visitor); + Mockito.verify(visitor).visitInvalid(); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitNix() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().get(); + inspector.accept(visitor); + Mockito.verify(visitor).visitNix(); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitBool() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setBool(true); + inspector.accept(visitor); + Mockito.verify(visitor).visitBool(true); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitLong() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setLong(123); + inspector.accept(visitor); + Mockito.verify(visitor).visitLong(123); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitDouble() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setDouble(123.0); + inspector.accept(visitor); + Mockito.verify(visitor).visitDouble(123.0); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitStringUtf16() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setString("abc"); + inspector.accept(visitor); + Mockito.verify(visitor).visitString("abc"); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitStringUtf8() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setString(new byte[] {65,66,67}); + inspector.accept(visitor); + Mockito.verify(visitor).visitString(new byte[] {65,66,67}); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitData() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setData(new byte[] {1,2,3}); + inspector.accept(visitor); + Mockito.verify(visitor).visitData(new byte[] {1,2,3}); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitArray() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setArray(); + inspector.accept(visitor); + Mockito.verify(visitor).visitArray(argThat(sameInstance(inspector))); + Mockito.verifyNoMoreInteractions(visitor); + } + + @Test + public void testVisitObject() { + Visitor visitor = Mockito.mock(Visitor.class); + Inspector inspector = new Slime().setObject(); + inspector.accept(visitor); + Mockito.verify(visitor).visitObject(argThat(sameInstance(inspector))); + Mockito.verifyNoMoreInteractions(visitor); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/system/Bar.java b/vespajlib/src/test/java/com/yahoo/system/Bar.java new file mode 100644 index 00000000000..747b19edaee --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/Bar.java @@ -0,0 +1,7 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +/** + * Dummy class to be used to test force loading + **/ +public class Bar {} diff --git a/vespajlib/src/test/java/com/yahoo/system/CatchSigTermTestCase.java b/vespajlib/src/test/java/com/yahoo/system/CatchSigTermTestCase.java new file mode 100644 index 00000000000..dfe508eb2d6 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/CatchSigTermTestCase.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +import com.yahoo.system.CatchSigTerm; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author arnej27959 + */ +public class CatchSigTermTestCase extends junit.framework.TestCase { + + public CatchSigTermTestCase(String name) { + super(name); + } + + public void testThatSetupCompiles() { + CatchSigTerm.setup(new AtomicBoolean(false)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/system/CommandLineParserTestCase.java b/vespajlib/src/test/java/com/yahoo/system/CommandLineParserTestCase.java new file mode 100644 index 00000000000..a2a086e4c65 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/CommandLineParserTestCase.java @@ -0,0 +1,125 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +import junit.framework.TestCase; + +public class CommandLineParserTestCase extends TestCase { + + public void testParse1() { + String[] args = new String[] {"-d", "-f", "hello.txt"}; + CommandLineParser parser = new CommandLineParser(args); + parser.addLegalBinarySwitch("-f"); + parser.addLegalUnarySwitch("-d"); + parser.parse(); + assertNull(parser.getBinarySwitches().get("-g")); + assertFalse(parser.getUnarySwitches().contains("-e")); + assertEquals(parser.getBinarySwitches().get("-f"), "hello.txt"); + assertTrue(parser.getUnarySwitches().contains("-d")); + assertFalse(parser.getArguments().contains("-d")); + assertFalse(parser.getArguments().contains("-f")); + assertFalse(parser.getArguments().contains("-hello.txt")); + assertEquals(parser.getArguments().size(), 0); + } + + public void testParse2() { + String[] args = new String[] {"-d", "-f", "hello.txt", "-XX", "myName", "-o", "output file", "myLastField"}; + CommandLineParser parser = new CommandLineParser("progname", args); + parser.setArgumentExplanation("Bla bla1"); + parser.setExtendedHelpText("Bla bla blaaaaaaa bla2"); + parser.addLegalBinarySwitch("-f"); + parser.addLegalBinarySwitch("-o"); + parser.addLegalUnarySwitch("-d"); + parser.addLegalUnarySwitch("-XX"); + parser.parse(); + assertNull(parser.getBinarySwitches().get("-g")); + assertFalse(parser.getUnarySwitches().contains("-e")); + assertEquals(parser.getBinarySwitches().get("-f"), "hello.txt"); + assertTrue(parser.getUnarySwitches().contains("-d")); + assertTrue(parser.getUnarySwitches().contains("-XX")); + assertEquals(parser.getBinarySwitches().get("-o"), "output file"); + assertTrue(parser.getArguments().contains("myName")); + assertTrue(parser.getArguments().contains("myLastField")); + assertEquals(parser.getUnarySwitches().size(), 2); + assertEquals(parser.getBinarySwitches().size(), 2); + assertEquals(parser.getArguments().size(), 2); + assertEquals(parser.getArguments().get(0), "myName"); + assertEquals(parser.getArguments().get(1), "myLastField"); + assertEquals(parser.getUnarySwitches().get(0), "-d"); + assertEquals(parser.getUnarySwitches().get(1), "-XX"); + + try { + parser.usageAndThrow(); + fail("usageAndThrow didn't throw"); + } catch (Exception e) { + assertTrue(e.getMessage().replaceAll("\n", "").matches(".*bla1.*")); + assertTrue(e.getMessage().replaceAll("\n", "").matches(".*bla2.*")); + } + } + + public void testIllegal() { + String[] args = new String[] {"-d", "-f", "hello.txt", "-XX", "myName", "-o", "output file", "myLastField"}; + CommandLineParser parser = new CommandLineParser(args); + parser.addLegalBinarySwitch("-f"); + parser.addLegalBinarySwitch("-o"); + parser.addLegalUnarySwitch("-d"); + try { + parser.parse(); + fail("Parse of cmd line with illegal arg worked"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().startsWith("\nusage")); + } + + args = new String[] {"-d", "-f", "hello.txt", "-XX", "myName", "-o", "output file", "myLastField"}; + parser = new CommandLineParser(args); + parser.addLegalBinarySwitch("-f"); + parser.addLegalUnarySwitch("-d"); + parser.addLegalUnarySwitch("-XX"); + try { + parser.parse(); + fail("Parse of cmd line with illegal arg worked"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().startsWith("\nusage")); + } + } + + public void testRequired() { + String[] args1 = new String[] {"-d", "-f", "hello.txt", "-XX", "myName", "-o", "output file", "myLastField"}; + String[] args2 = new String[] {"-XX", "myName", "-o", "output file", "myLastField"}; + CommandLineParser parser = new CommandLineParser(args1); + parser.addLegalBinarySwitch("-f", "test1"); + parser.addRequiredBinarySwitch("-o", "test2"); + parser.addLegalUnarySwitch("-d", "test3"); + parser.addLegalUnarySwitch("-XX", "test4"); + parser.parse(); + + parser = new CommandLineParser(args2); + parser.addRequiredBinarySwitch("-o", "test2"); + parser.addLegalUnarySwitch("-XX", "test4"); + parser.parse(); + assertEquals(parser.getBinarySwitches().size(),1); + assertEquals(parser.getUnarySwitches().size(),1); + + parser = new CommandLineParser(args2); + parser.addLegalUnarySwitch("-XX", "test4"); + parser.addRequiredBinarySwitch("-f", "test5"); + parser.addRequiredBinarySwitch("-o", "test6"); + try { + parser.parse(); + fail("Illegal cmd line parsed"); + } catch (Exception e) { + assertTrue(e.getMessage().startsWith("\nusage")); + } + + args1 = new String[] {"-d"}; + parser = new CommandLineParser(args1); + parser.addRequiredUnarySwitch("-d", "(required, there are so many bugs)"); + try { + parser.addLegalBinarySwitch("-d"); + fail("Switch clobber didn't throw"); + } catch (Exception e) { + assertTrue(e.getMessage().matches(".*already.*")); + } + parser.parse(); + assertEquals(parser.getUnarySwitches().get(0), "-d"); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/system/Foo.java b/vespajlib/src/test/java/com/yahoo/system/Foo.java new file mode 100644 index 00000000000..ea51a80caaa --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/Foo.java @@ -0,0 +1,7 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +/** + * Dummy class to be used to test force loading + **/ +public class Foo {} diff --git a/vespajlib/src/test/java/com/yahoo/system/ForceLoadTestCase.java b/vespajlib/src/test/java/com/yahoo/system/ForceLoadTestCase.java new file mode 100644 index 00000000000..ec4f716247e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/ForceLoadTestCase.java @@ -0,0 +1,27 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +public class ForceLoadTestCase extends junit.framework.TestCase { + + public ForceLoadTestCase(String name) { + super(name); + } + + public void testLoadClasses() { + try { + ForceLoad.forceLoad(getClass().getPackage().getName(), new String[] { "Foo", "Bar" }); + } catch (ForceLoadError e) { + e.printStackTrace(); + assertTrue(false); + } + } + + public void testLoadBogusClass() { + try { + ForceLoad.forceLoad(getClass().getPackage().getName(), new String[] { "Foo", "Bar", "Baz" }); + } catch (ForceLoadError e) { + return; + } + assertTrue(false); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/system/ProcessExecuterTestCase.java b/vespajlib/src/test/java/com/yahoo/system/ProcessExecuterTestCase.java new file mode 100644 index 00000000000..2bf1d8c094a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/system/ProcessExecuterTestCase.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.system; + +import com.yahoo.collections.Pair; +import com.yahoo.io.IOUtils; + +import java.io.File; +import java.io.IOException; + +/** + * @author Jon Bratseth + */ +public class ProcessExecuterTestCase extends junit.framework.TestCase { + + public void testIt() throws IOException { + IOUtils.writeFile("tmp123.txt","hello\nworld",false); + ProcessExecuter exec=new ProcessExecuter(); + assertEquals(new Pair<>(0, "hello\nworld"), exec.exec("cat tmp123.txt")); + assertEquals(new Pair<>(0, "hello\nworld"), exec.exec(new String[]{"cat", "tmp123.txt"})); + new File("tmp123.txt").delete(); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/tensor/MapTensorBuilderTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/MapTensorBuilderTestCase.java new file mode 100644 index 00000000000..92f0e71c7f5 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/tensor/MapTensorBuilderTestCase.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.tensor; + +import com.google.common.collect.Sets; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Geir Storli + */ +public class MapTensorBuilderTestCase { + + @Test + public void requireThatEmptyTensorCanBeBuilt() { + Tensor tensor = new MapTensorBuilder().build(); + assertEquals(0, tensor.dimensions().size()); + assertEquals("{}", tensor.toString()); + } + + @Test + public void requireThatOneDimensionalTensorCanBeBuilt() { + Tensor tensor = new MapTensorBuilder(). + cell().label("x", "0").value(1). + cell().label("x", "1").value(2).build(); + assertEquals(Sets.newHashSet("x"), tensor.dimensions()); + assertEquals("{{x:0}:1.0,{x:1}:2.0}", tensor.toString()); + } + + @Test + public void requireThatTwoDimensionalTensorCanBeBuilt() { + Tensor tensor = new MapTensorBuilder(). + cell().label("x", "0").label("y", "0").value(1). + cell().label("x", "1").label("y", "0").value(2).build(); + assertEquals(Sets.newHashSet("x", "y"), tensor.dimensions()); + assertEquals("{{x:1,y:0}:2.0,{x:0,y:0}:1.0}", tensor.toString()); + } + + @Test + public void requireThatExtraDimensionsCanBeSpecified() { + Tensor tensor = new MapTensorBuilder().dimension("y").dimension("z"). + cell().label("x", "0").value(1).build(); + assertEquals(Sets.newHashSet("x", "y", "z"), tensor.dimensions()); + assertEquals("( {{y:-,z:-}:1.0} * {{x:0}:1.0} )", tensor.toString()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/tensor/MapTensorTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/MapTensorTestCase.java new file mode 100644 index 00000000000..13ea0e95dc8 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/tensor/MapTensorTestCase.java @@ -0,0 +1,69 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.tensor; + +import org.junit.Test; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Basic tensor tests. Tensor operations are tested in EvaluationTestCase + * + * @author bratseth + */ +public class MapTensorTestCase { + + @Test + public void testStringForm() { + assertEquals("{}", MapTensor.from("{}").toString()); + assertEquals("{{d1:l1}:5.0,{d1:l1,d2:l2}:6.0}", MapTensor.from("{ {d1:l1}:5, {d2:l2, d1:l1}:6.0} ").toString()); + assertEquals("{{d1:l1}:-5.3,{d1:l1,d2:l2}:0.0}", MapTensor.from("{ {d1:l1}:-5.3, {d2:l2, d1:l1}:0}").toString()); + } + + @Test + public void testParseError() { + try { + MapTensor.from("--"); + fail("Expected parse error"); + } + catch (IllegalArgumentException expected) { + assertEquals("Excepted a string starting by { or (, got '--'", expected.getMessage()); + } + } + + @Test + public void testConstruction() { + assertEquals("{}", new MapTensor(Collections.emptyMap()).toString()); + assertEquals("{{}:5.0}", new MapTensor(Collections.singletonMap(TensorAddress.empty, 5.0)).toString()); + + Map cells = new LinkedHashMap<>(); + cells.put(TensorAddress.fromSorted(Collections.singletonList(new TensorAddress.Element("d1","l1"))), 5.0); + cells.put(TensorAddress.fromSorted(Collections.singletonList(new TensorAddress.Element("d2","l1"))), 6.0); + cells.put(TensorAddress.empty, 7.0); + assertEquals("{{}:7.0,{d1:l1}:5.0,{d2:l1}:6.0}", new MapTensor(cells).toString()); + } + + @Test + public void testDimensions() { + Set dimensions1 = MapTensor.from("{} ").dimensions(); + assertEquals(0, dimensions1.size()); + + Set dimensions2 = MapTensor.from("{ {d1:l1}:5, {d2:l2, d1:l1}:6.0} ").dimensions(); + assertEquals(2, dimensions2.size()); + assertTrue(dimensions2.contains("d1")); + assertTrue(dimensions2.contains("d2")); + + Set dimensions3 = MapTensor.from("{ {d1:l1, d2:l1}:5, {d2:l2, d3:l1}:6.0} ").dimensions(); + assertEquals(3, dimensions3.size()); + assertTrue(dimensions3.contains("d1")); + assertTrue(dimensions3.contains("d2")); + assertTrue(dimensions3.contains("d3")); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/tensor/TensorTypeTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/TensorTypeTestCase.java new file mode 100644 index 00000000000..59d77f6569a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/tensor/TensorTypeTestCase.java @@ -0,0 +1,89 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.tensor; + +import org.junit.Test; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * @author Geir Storli + */ +public class TensorTypeTestCase { + + @Test + public void requireThatAnEmptyTensorTypeCanBeSpecified() { + assertTensorType("tensor()"); + } + + @Test + public void requireThatBoundIndexedDimensionsCanBeSpecified() { + assertTensorType("tensor(x[5])"); + assertTensorType("tensor(x[5],y[10],z[100])"); + assertTensorType("tensor(x[5],y[10],z[100])", "tensor( x[5] , y[10] , z[100] )"); + assertTensorType("tensor(baR_09[10])"); + } + + @Test + public void requireThatUnboundIndexedDimensionsCanBeSpecified() { + assertTensorType("tensor(x[])"); + assertTensorType("tensor(x[],y[],z[])"); + assertTensorType("tensor(x[],y[],z[])", "tensor( x[] , y[] , z[] )"); + assertTensorType("tensor(baR_09[])"); + } + + @Test + public void requireThatMappedDimensionsCanBeSpecified() { + assertTensorType("tensor(x{})"); + assertTensorType("tensor(x{},y{},z{})"); + assertTensorType("tensor(x{},y{},z{})", "tensor( x{} , y{} , z{} )"); + assertTensorType("tensor(baR_09{})"); + } + + @Test + public void requireThatIndexedBoundDimensionMustHaveNonZeroSize() { + assertIllegalTensorType("tensor(x[0])", "Size of bound dimension 'x' must be at least 1"); + } + + @Test + public void requireThatDimensionsMustHaveUniqueNames() { + assertIllegalTensorType("tensor(x[10],y[20],x[30])", "'x[10]' and 'x[30]' have the same name"); + assertIllegalTensorType("tensor(x{},y{},x{})", "'x{}' and 'x{}' have the same name"); + } + + @Test + public void requireThatDimensionsAreOfSameType() { + assertIllegalTensorType("tensor(x[10],y[])", "'x[10]' does not have the same type as 'y[]'"); + assertIllegalTensorType("tensor(x[10],y{})", "'x[10]' does not have the same type as 'y{}'"); + assertIllegalTensorType("tensor(x[10],y[20],z{})", "'y[20]' does not have the same type as 'z{}'"); + assertIllegalTensorType("tensor(x[],y{})", "'x[]' does not have the same type as 'y{}'"); + } + + @Test + public void requireThatIllegalSyntaxInSpecThrowsException() { + assertIllegalTensorType("foo(x[10])", "Tensor type spec must start with 'tensor(' and end with ')', but was 'foo(x[10])'"); + assertIllegalTensorType("tensor(x_@[10])", "Failed parsing element 'x_@[10]' in type spec 'tensor(x_@[10])'"); + assertIllegalTensorType("tensor(x[10a])", "Failed parsing element 'x[10a]' in type spec 'tensor(x[10a])'"); + assertIllegalTensorType("tensor(x{10})", "Failed parsing element 'x{10}' in type spec 'tensor(x{10})'"); + } + + private static void assertTensorType(String typeSpec) { + assertTensorType(typeSpec, typeSpec); + } + + private static void assertTensorType(String expected, String typeSpec) { + assertEquals(expected, TensorType.fromSpec(typeSpec).toString()); + } + + private static void assertIllegalTensorType(String typeSpec, String messageSubstring) { + try { + TensorType.fromSpec(typeSpec); + fail("Exception exception to be thrown with message: '" + messageSubstring + "'"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage(), containsString(messageSubstring)); + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/tensor/serialization/CompactBinaryFormatTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/serialization/CompactBinaryFormatTestCase.java new file mode 100644 index 00000000000..23589577c0c --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/tensor/serialization/CompactBinaryFormatTestCase.java @@ -0,0 +1,78 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.tensor.serialization; + +import com.google.common.collect.Sets; +import com.yahoo.tensor.MapTensor; +import com.yahoo.tensor.Tensor; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for the compact binary format. + * + * TODO: When new formats are added we should refactor this test to test all formats + * with the same set of tensor inputs (if feasible). + * + * @author Geir Storli + */ +public class CompactBinaryFormatTestCase { + + private static void assertSerialization(String tensorString) { + assertSerialization(MapTensor.from(tensorString)); + } + + private static void assertSerialization(String tensorString, Set dimensions) { + Tensor tensor = MapTensor.from(tensorString); + assertEquals(dimensions, tensor.dimensions()); + assertSerialization(tensor); + } + + private static void assertSerialization(Tensor tensor) { + byte[] encodedTensor = TypedBinaryFormat.encode(tensor); + Tensor decodedTensor = TypedBinaryFormat.decode(encodedTensor); + assertEquals(tensor, decodedTensor); + } + + @Test + public void testSerializationOfTensorsWithDenseTensorAddresses() { + assertSerialization("{}"); + assertSerialization("{{x:0}:2.0}"); + assertSerialization("{{x:0}:2.0,{x:1}:3.0}"); + assertSerialization("{{x:0,y:0}:2.0}"); + assertSerialization("{{x:0,y:0}:2.0,{x:0,y:1}:3.0}"); + assertSerialization("{{y:0,x:0}:2.0}"); + assertSerialization("{{y:0,x:0}:2.0,{y:1,x:0}:3.0}"); + assertSerialization("{{dimX:labelA,dimY:labelB}:2.0,{dimY:labelC,dimX:labelD}:3.0}"); + } + + @Test + public void testSerializationOfTensorsWithSparseTensorAddresses() { + assertSerialization("{{x:0}:2.0, {}:3.0}", Sets.newHashSet("x")); + assertSerialization("({{y:-}:1} * {{x:0}:2.0})", Sets.newHashSet("x", "y")); + assertSerialization("({{y:-}:1} * {{x:0}:2.0, {}:3.0})", Sets.newHashSet("x", "y")); + assertSerialization("({{y:-}:1} * {{x:0}:2.0,{x:1}:3.0})", Sets.newHashSet("x", "y")); + assertSerialization("({{z:-}:1} * {{x:0,y:0}:2.0})", Sets.newHashSet("x", "y", "z")); + assertSerialization("({{z:-}:1} * {{x:0,y:0}:2.0,{x:0,y:1}:3.0})", Sets.newHashSet("x", "y", "z")); + assertSerialization("({{z:-}:1} * {{y:0,x:0}:2.0})", Sets.newHashSet("x", "y", "z")); + assertSerialization("({{z:-}:1} * {{y:0,x:0}:2.0,{y:1,x:0}:3.0})", Sets.newHashSet("x", "y", "z")); + assertSerialization("({{z:-}:1} * {{}:2.0,{x:0}:3.0,{x:0,y:0}:5.0})", Sets.newHashSet("x", "y", "z")); + } + + @Test + public void requireThatCompactSerializationFormatDoNotChange() { + byte[] encodedTensor = new byte[] {1, // binary format type + 2, // num dimensions + 2, (byte)'x', (byte)'y', 1, (byte)'z', // dimensions + 2, // num cells, + 2, (byte)'a', (byte)'b', 0, 64, 0, 0, 0, 0, 0, 0, 0, // cell 0 + 2, (byte)'c', (byte)'d', 1, (byte)'e', 64, 8, 0, 0, 0, 0, 0, 0}; // cell 1 + assertEquals(Arrays.toString(encodedTensor), + Arrays.toString(TypedBinaryFormat.encode(MapTensor.from("{{xy:ab}:2.0,{xy:cd,z:e}:3.0}")))); + } + +} + diff --git a/vespajlib/src/test/java/com/yahoo/text/AsciiTest.java b/vespajlib/src/test/java/com/yahoo/text/AsciiTest.java new file mode 100644 index 00000000000..4d598e7b1bb --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/AsciiTest.java @@ -0,0 +1,187 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Simon Thoresen Hult + */ +public class AsciiTest { + + @Test + public void requireThatAdditionalCodePointsCanBeEscaped() { + assertEquals("\\x66\\x6F\\x6F \\x62ar \\x62az", + Ascii.newEncoder(StandardCharsets.UTF_8, 'f', 'o', 'b').encode("foo bar baz")); + } + + @Test + public void requireThatReadableCharactersAreNotEscaped() { + StringBuilder str = new StringBuilder(); + for (int i = 0x20; i < 0x7F; ++i) { + if (i != '\\') { + str.appendCodePoint(i); + } + } + assertEncodeUtf8(str.toString(), str.toString()); + } + + @Test + public void requireThatNonReadableCharactersAreEscapedAsUtf8() { + for (int i = Character.MIN_CODE_POINT; i < 0x20; ++i) { + String expected; + switch (i) { + case '\f': + expected = "\\f"; + break; + case '\n': + expected = "\\n"; + break; + case '\r': + expected = "\\r"; + break; + case '\t': + expected = "\\t"; + break; + default: + expected = String.format("\\x%02X", i); + break; + } + assertEncodeUtf8(expected, new StringBuilder().appendCodePoint(i).toString()); + } + for (int i = 0x80; i < 0xC0; ++i) { + String expected = String.format("\\xC2\\x%02X", i); + assertEncodeUtf8(expected, new StringBuilder().appendCodePoint(i).toString()); + } + for (int i = 0xC0; i < 0x0100; ++i) { + String expected = String.format("\\xC3\\x%02X", i - 0x40); + assertEncodeUtf8(expected, new StringBuilder().appendCodePoint(i).toString()); + } + for (int i = 0x0100; i < 0x0140; ++i) { + String expected = String.format("\\xC4\\x%02X", i - 0x80); + assertEncodeUtf8(expected, new StringBuilder().appendCodePoint(i).toString()); + } + } + + @Test + public void requireThatBackslashIsEscaped() { + assertEncodeUtf8("\\\\", "\\"); + } + + @Test + public void requireThatQuoteIsEscaped() { + assertEncodeUtf8("\\x62az", "baz", 'b'); + assertEncodeUtf8("b\\x61z", "baz", 'a'); + assertEncodeUtf8("ba\\x7A", "baz", 'z'); + } + + @Test + public void requireThatAnyEscapedCharacterCanBeUnescaped() { + assertDecodeUtf8("baz", "\\baz"); + assertDecodeUtf8("baz", "b\\az"); + assertDecodeUtf8("baz", "ba\\z"); + } + + @Test + public void requireThatUtf8SequencesAreUnescaped() { + for (int i = 0x80; i < 0xC0; ++i) { + String str = String.format("\\xC2\\x%02X", i); + assertDecodeUtf8(new StringBuilder().appendCodePoint(i).toString(), str); + } + for (int i = 0xC0; i < 0x0100; ++i) { + String str = String.format("\\xC3\\x%02X", i - 0x40); + assertDecodeUtf8(new StringBuilder().appendCodePoint(i).toString(), str); + } + for (int i = 0x0100; i < 0x0140; ++i) { + String str = String.format("\\xC4\\x%02X", i - 0x80); + assertDecodeUtf8(new StringBuilder().appendCodePoint(i).toString(), str); + } + } + + @Test + public void requireThatUtf8CanBeEncoded() { + // First possible sequence of a certain length + assertEncodeUtf8("\\x00", "\u0000"); + assertEncodeUtf8("\\xC2\\x80", "\u0080"); + assertEncodeUtf8("\\xE0\\xA0\\x80", "\u0800"); + assertEncodeUtf8("\\x01\\x00", "\u0001\u0000"); + assertEncodeUtf8("\\x20\\x00", "\u0020\u0000", ' '); + assertEncodeUtf8("\\xD0\\x80\\x00", "\u0400\u0000"); + + // Last possible sequence of a certain length + assertEncodeUtf8("\\x7F", "\u007F"); + assertEncodeUtf8("\\xDF\\xBF", "\u07FF"); + assertEncodeUtf8("\\xEF\\xBF\\xBF", "\uFFFF"); + assertEncodeUtf8("\\x1F\\xEF\\xBF\\xBF", "\u001F\uFFFF"); + assertEncodeUtf8("\\xCF\\xBF\\xEF\\xBF\\xBF", "\u03FF\uFFFF"); + assertEncodeUtf8("\\xE7\\xBF\\xBF\\xEF\\xBF\\xBF", "\u7FFF\uFFFF"); + + // Other boundary conditions + assertEncodeUtf8("\\xED\\x9F\\xBF", "\uD7FF"); + assertEncodeUtf8("\\xEE\\x80\\x80", "\uE000"); + assertEncodeUtf8("\\xEF\\xBF\\xBD", "\uFFFD"); + assertEncodeUtf8("\\x10\\xEF\\xBF\\xBF", "\u0010\uFFFF"); + assertEncodeUtf8("\\x11\\x00", "\u0011\u0000"); + } + + @Test + public void requireThatUTf8CanBeDecoded() { + // First possible sequence of a certain length + assertDecodeUtf8("\u0000", "\\x00"); + assertDecodeUtf8("\u0080", "\\xC2\\x80"); + assertDecodeUtf8("\u0800", "\\xE0\\xA0\\x80"); + assertDecodeUtf8("\u0001\u0000", "\\x01\\x00"); + assertDecodeUtf8("\u0020\u0000", "\\x20\\x00"); + assertDecodeUtf8("\u0400\u0000", "\\xD0\\x80\\x00"); + + // Last possible sequence of a certain length + assertDecodeUtf8("\u007F", "\\x7F"); + assertDecodeUtf8("\u07FF", "\\xDF\\xBF"); + assertDecodeUtf8("\uFFFF", "\\xEF\\xBF\\xBF"); + assertDecodeUtf8("\u001F\uFFFF", "\\x1F\\xEF\\xBF\\xBF"); + assertDecodeUtf8("\u03FF\uFFFF", "\\xCF\\xBF\\xEF\\xBF\\xBF"); + assertDecodeUtf8("\u7FFF\uFFFF", "\\xE7\\xBF\\xBF\\xEF\\xBF\\xBF"); + + // Other boundary conditions + assertDecodeUtf8("\uD7FF", "\\xED\\x9F\\xBF"); + assertDecodeUtf8("\uE000", "\\xEE\\x80\\x80"); + assertDecodeUtf8("\uFFFD", "\\xEF\\xBF\\xBD"); + assertDecodeUtf8("\u0010\uFFFF", "\\x10\\xEF\\xBF\\xBF"); + assertDecodeUtf8("\u0011\u0000", "\\x11\\x00"); + } + + @Test + public void requireThatUnicodeCanBeEncoded() { + assertEncodeUtf8("\\xE4\\xB8\\x9C\\xE8\\xA5\\xBF\\xE8\\x87\\xAA\\xE8\\xA1\\x8C\\xE8\\xBD\\xA6", + "\u4E1C\u897F\u81EA\u884C\u8F66"); + } + + @Test + public void requireThatUnicodeCanBeDecoded() { + assertDecodeUtf8("\u4E1C\u897F\u81EA\u884C\u8F66", + "\\xE4\\xB8\\x9C\\xE8\\xA5\\xBF\\xE8\\x87\\xAA\\xE8\\xA1\\x8C\\xE8\\xBD\\xA6"); + } + + @Test + public void requireThatUnicodeIsAllowedInInputString() { + assertDecodeUtf8("\u4E1C\u897F\u81EA\u884C\u8F66", + "\u4E1C\u897F\u81EA\u884C\u8F66"); + } + + private static void assertEncodeUtf8(String expected, String str, int... requiresEscape) { + String actual = Ascii.encode(str, StandardCharsets.UTF_8, requiresEscape); + for (int i = 0; i < actual.length(); i += actual.offsetByCodePoints(i, 1)) { + int c = actual.codePointAt(i); + assertTrue(Integer.toHexString(c), c >= 0x20 && c <= 0x7F); + } + assertEquals(expected, actual); + } + + private static void assertDecodeUtf8(String expected, String str) { + assertEquals(expected, Ascii.decode(str, StandardCharsets.UTF_8)); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/Benchmark.java b/vespajlib/src/test/java/com/yahoo/text/Benchmark.java new file mode 100644 index 00000000000..caa4b57c099 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/Benchmark.java @@ -0,0 +1,106 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +// import com.google.common.base.Preconditions; +// import com.google.inject.Provider; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * @author Simon Thoresen Hult + */ +class Benchmark { + + public static interface Task { + public long run(CyclicBarrier barrier, int numIterations) throws Exception; + } + + + public static class TaskProvider { + final Class taskClass; + public Task get() { + try { + return taskClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + public TaskProvider(final Class taskClass) { + this.taskClass = taskClass; + } + } + + private final TaskProvider taskProvider; + private final int numIterationsPerThread; + private final int numThreads; + + private Benchmark(Builder builder) { + Objects.requireNonNull(builder.taskProvider, "taskProvider"); +/* + Preconditions.checkArgument(builder.numIterationsPerThread > 0, "numIterationsPerThread; %s", + builder.numIterationsPerThread); + Preconditions.checkArgument(builder.numThreads > 0, "numThreads; %s", + builder.numThreads); +*/ + taskProvider = builder.taskProvider; + numIterationsPerThread = builder.numIterationsPerThread; + numThreads = builder.numThreads; + } + + public long run() throws Exception { + final CyclicBarrier barrier = new CyclicBarrier(numThreads); + List> clients = new ArrayList<>(numThreads); + for (int i = 0; i < numThreads; ++i) { + final Task task = taskProvider.get(); + clients.add(new Callable() { + + @Override + public Long call() throws Exception { + return task.run(barrier, numIterationsPerThread); + } + }); + } + long maxNanosPerClient = 0; + for (Future result : Executors.newFixedThreadPool(numThreads).invokeAll(clients)) { + maxNanosPerClient = Math.max(maxNanosPerClient, result.get()); + } + return TimeUnit.SECONDS.toNanos(1) * numThreads * numIterationsPerThread / maxNanosPerClient; + } + + public static class Builder { + + private TaskProvider taskProvider; + private int numIterationsPerThread = 1000; + private int numThreads = 1; + + public Builder setNumThreads(int numThreads) { + this.numThreads = numThreads; + return this; + } + + public Builder setNumIterationsPerThread(int numIterationsPerThread) { + this.numIterationsPerThread = numIterationsPerThread; + return this; + } + + public Builder setTaskClass(final Class taskClass) { + return setTaskProvider(new TaskProvider(taskClass)); + } + + public Builder setTaskProvider(TaskProvider taskProvider) { + this.taskProvider = taskProvider; + return this; + } + + public Benchmark build() { + return new Benchmark(this); + } + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/BooleanParserTestCase.java b/vespajlib/src/test/java/com/yahoo/text/BooleanParserTestCase.java new file mode 100644 index 00000000000..756d0cd23ff --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/BooleanParserTestCase.java @@ -0,0 +1,35 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Control argument checking in BooleanParser. + * + * @author Steinar Knutsen + */ +public class BooleanParserTestCase { + + @Test + public final void testParseBoolean() { + boolean gotException = false; + try { + BooleanParser.parseBoolean(null); + } catch (final NullPointerException e) { + gotException = true; + } + assertTrue(gotException); + gotException = false; + try { + BooleanParser.parseBoolean("nalle"); + } catch (final IllegalArgumentException e) { + gotException = true; + } + assertTrue(BooleanParser.parseBoolean("true")); + assertFalse(BooleanParser.parseBoolean("false")); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/CaseInsensitiveIdentifierTestCase.java b/vespajlib/src/test/java/com/yahoo/text/CaseInsensitiveIdentifierTestCase.java new file mode 100644 index 00000000000..6c6b5b62506 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/CaseInsensitiveIdentifierTestCase.java @@ -0,0 +1,46 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * Created with IntelliJ IDEA. + * User: balder + * Date: 11.11.12 + * Time: 11:37 + * To change this template use File | Settings | File Templates. + */ +public class CaseInsensitiveIdentifierTestCase { + @Test + public void testCaseInsentivitity() { + assertEquals(new CaseInsensitiveIdentifier("").toString(), ""); + assertEquals(new CaseInsensitiveIdentifier("a").toString(), "a"); + assertEquals(new CaseInsensitiveIdentifier("z").toString(), "z"); + assertEquals(new CaseInsensitiveIdentifier("B").toString(), "B"); + assertEquals(new CaseInsensitiveIdentifier("Z").toString(), "Z"); + assertEquals(new CaseInsensitiveIdentifier("_").toString(), "_"); + try { + assertEquals(new CaseInsensitiveIdentifier("0").toString(), "0"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '0' of identifier '0'."); + } + try { + assertEquals(new CaseInsensitiveIdentifier("-").toString(), "-"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '-' of identifier '-'."); + } + assertEquals(new CaseInsensitiveIdentifier("a0_9").toString(), "a0_9"); + assertEquals(new Identifier("a9Z_").toString(), "a9Z_"); + try { + assertEquals(new CaseInsensitiveIdentifier("a-b").toString(), "a-b"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal character '-' of identifier 'a-b'."); + } + assertEquals(new CaseInsensitiveIdentifier("AbC"), new CaseInsensitiveIdentifier("ABC")); + assertEquals(new CaseInsensitiveIdentifier("AbC").hashCode(), new CaseInsensitiveIdentifier("ABC").hashCode()); + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/DataTypeIdentifierTestCase.java b/vespajlib/src/test/java/com/yahoo/text/DataTypeIdentifierTestCase.java new file mode 100644 index 00000000000..b79f65d9eb2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/DataTypeIdentifierTestCase.java @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * Created with IntelliJ IDEA. + * User: balder + * Date: 12.11.12 + * Time: 08:10 + * To change this template use File | Settings | File Templates. + */ +public class DataTypeIdentifierTestCase { + @Test + public void testDataTypeIdentifier() { + assertEquals("", new DataTypeIdentifier("").toString()); + assertEquals("a", new DataTypeIdentifier("a").toString()); + assertEquals("_", new DataTypeIdentifier("_").toString()); + try { + assertEquals("aB", new DataTypeIdentifier("aB").toString()); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal character 'B' of identifier 'aB'."); + } + try { + assertEquals("1", new DataTypeIdentifier("1").toString()); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '1' of identifier '1'."); + } + assertEquals("a1", new DataTypeIdentifier("a1").toString()); + assertEquals("array", DataTypeIdentifier.createArrayDataTypeIdentifier(new DataTypeIdentifier("b")).toString()); + assertEquals("weightedset", DataTypeIdentifier.createWeightedSetTypeIdentifier(new DataTypeIdentifier("b"), false, false).toString()); + assertEquals("weightedset;add", DataTypeIdentifier.createWeightedSetTypeIdentifier(new DataTypeIdentifier("b"), true, false).toString()); + assertEquals("weightedset;remove", DataTypeIdentifier.createWeightedSetTypeIdentifier(new DataTypeIdentifier("b"), false, true).toString()); + assertEquals("weightedset;add;remove", DataTypeIdentifier.createWeightedSetTypeIdentifier(new DataTypeIdentifier("b"), true, true).toString()); + assertEquals("annotationreference", DataTypeIdentifier.createAnnotationReferenceDataTypeIdentifier(new DataTypeIdentifier("b")).toString()); + assertEquals("map", DataTypeIdentifier.createMapDataTypeIdentifier(new DataTypeIdentifier("k"), new DataTypeIdentifier("v")).toString()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java b/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java new file mode 100644 index 00000000000..21be58e5fd2 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleFormatterTestCase.java @@ -0,0 +1,204 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * @author arnej27959 + */ +public class DoubleFormatterTestCase { + + @Test + public void testZero() { + String zero = DoubleFormatter.stringValue(0.0); + //assertEquals("0.0", zero); + } + + @Test + public void testOne() { + String one = DoubleFormatter.stringValue(1.0); + assertEquals("1.0", one); + } + + @Test + public void testMinusOne() { + String one = DoubleFormatter.stringValue(-1.0); + assertEquals("-1.0", one); + } + + @Test + public void testNanInf() { + String plusInf = DoubleFormatter.stringValue(Double.POSITIVE_INFINITY); + assertEquals("Infinity", plusInf); + + String notAnum = DoubleFormatter.stringValue(Double.NaN); + assertEquals("NaN", notAnum); + + String negInf = DoubleFormatter.stringValue(Double.NEGATIVE_INFINITY); + assertEquals("-Infinity", negInf); + } + + @Test + public void testSeven() { + String seven = DoubleFormatter.stringValue(7.0); + assertEquals("7.0", seven); + + seven = DoubleFormatter.stringValue(77.0); + assertEquals("77.0", seven); + + seven = DoubleFormatter.stringValue(7777.0); + assertEquals("7777.0", seven); + + seven = DoubleFormatter.stringValue(7777007777.0); + assertEquals("7.777007777E9", seven); + } + + + @Test + public void testSomeChosenNumbers() { + String s = DoubleFormatter.stringValue(4097.0); + assertEquals("4097.0", s); + + s = DoubleFormatter.stringValue(4097.5); + assertEquals("4097.5", s); + + s = DoubleFormatter.stringValue(1073741823.0); + assertEquals("1.073741823E9", s); + + s = DoubleFormatter.stringValue(1073741823.5); + assertEquals("1.0737418235E9", s); + + s = DoubleFormatter.stringValue(1073741825.5); + assertEquals("1.0737418255E9", s); + + s = DoubleFormatter.stringValue(1.23456789012345669); + assertEquals("1.234567890123457", s); + s = DoubleFormatter.stringValue(12.3456789012345673); + assertEquals("12.34567890123457", s); + s = DoubleFormatter.stringValue(123.456789012345666); + assertEquals("123.4567890123457", s); + s = DoubleFormatter.stringValue(1234.56789012345666); + assertEquals("1234.567890123457", s); + s = DoubleFormatter.stringValue(12345.6789012345670); + assertEquals("12345.67890123457", s); + s = DoubleFormatter.stringValue(123456.789012345674); + assertEquals("123456.7890123457", s); + s = DoubleFormatter.stringValue(1234567.89012345671); + assertEquals("1234567.890123457", s); + + s = DoubleFormatter.stringValue(0.99); + // assertEquals("0.99", s); + + s = DoubleFormatter.stringValue(0.5); + assertEquals("0.5", s); + + s = DoubleFormatter.stringValue(0.1); + // assertEquals("0.1", s); + + s = DoubleFormatter.stringValue(0.00123456789); + // assertEquals("0.00123456789", s); + + s = DoubleFormatter.stringValue(0.0000000000001); + // assertEquals("0.0000000000001", s); + } + + @Test + public void testPowersOfTwo() { + String twos = DoubleFormatter.stringValue(2.0); + assertEquals("2.0", twos); + + twos = DoubleFormatter.stringValue(128.0); + assertEquals("128.0", twos); + + twos = DoubleFormatter.stringValue(1048576.0); + assertEquals("1048576.0", twos); + + twos = DoubleFormatter.stringValue(1073741824.0); + assertEquals("1.073741824E9", twos); + } + + @Test + public void testSmallNumbers() { + for (double d = 1.0; d > 1.0e-200; d *= 0.75) { + String fs = DoubleFormatter.stringValue(d); + String vs = String.valueOf(d); + double rp = Double.valueOf(fs); + if (d != rp) { + // System.err.println("differs: "+d+" became "+fs+" then instead: "+rp+" diff: "+(d-rp)); + } else if (! fs.equals(vs)) { + // System.err.println("string rep differs: "+vs+" became "+fs); + } + assertEquals(d, rp, 1.0e-7*d); + } + } + + @Test + public void testVerySmallNumbers() { + for (double d = 1.0; d > 1.0e-200; d *= 0.5) { + String fs = DoubleFormatter.stringValue(d); + String vs = String.valueOf(d); + double rp = Double.valueOf(fs); + if (d != rp) { + // System.err.println("differs: "+d+" became "+fs+" then instead: "+rp+" diff: "+(d-rp)); + } else if (! fs.equals(vs)) { + // System.err.println("string rep differs: "+vs+" became "+fs); + } + assertEquals(d, rp, 1.0e-13*d); + } + } + + @Test + public void testVeryVerySmallNumbers() { + for (double d = 1.0e-200; d > 0; d *= 0.5) { + String fs = DoubleFormatter.stringValue(d); + String vs = String.valueOf(d); + double rp = Double.valueOf(fs); + if (d != rp) { + // System.err.println("differs: "+d+" became "+fs+" then instead: "+rp+" diff: "+(d-rp)); + } else if (! fs.equals(vs)) { + // System.err.println("string rep differs: "+vs+" became "+fs); + } + assertEquals(d, rp, 1.0e-13*d); + } + } + + @Test + public void testVeryBigNumbers() { + for (double d = 1.0; d < Double.POSITIVE_INFINITY; d *= 2.0) { + String fs = DoubleFormatter.stringValue(d); + String vs = String.valueOf(d); + double rp = Double.valueOf(fs); + if (d != rp) { + // System.err.println("differs: "+d+" became "+fs+" then instead: "+rp); + } else if (! fs.equals(vs)) { + // System.err.println("string rep differs: "+vs+" became "+fs); + } + assertEquals(d, rp, 1.0e-13*d); + } + + assertEquals("1.0E200", String.valueOf(1.0e+200)); + + String big = DoubleFormatter.stringValue(1.0e+200); + assertEquals("1.0E200", big); + + big = DoubleFormatter.stringValue(1.0e+298); + assertEquals("1.0E298", big); + + big = DoubleFormatter.stringValue(1.0e+299); + assertEquals("1.0E299", big); + + big = DoubleFormatter.stringValue(1.0e+300); + assertEquals("1.0E300", big); + + } + + @Test + public void testRandomNumbers() { + java.util.Random rgen = new java.util.Random(0xCafeBabe); + for (int i = 0; i < 123456; i++) { + double d = rgen.nextDouble(); + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java b/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java new file mode 100644 index 00000000000..88e253e3425 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleParserTestCase.java @@ -0,0 +1,158 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * @author arnej27959 + */ +public class DoubleParserTestCase { + + @Test + public void testZero() { + String[] zeros = { + "0", + "0.", + ".0", + "0.0", + "0.0e0", + "0.0e99", + "0.0e+300", + "0.0e-42" + }; + for (String s : zeros) { + double d = DoubleParser.parse(s); + assertEquals(0.0, d, 0); + } + } + + @Test + public void testOne() { + String[] ones = { + "1", + "1.", + "1.0", + "+1", + "10.0e-1", + "0.1e1", + "1000.0e-3", + ".001e+3", + }; + for (String s : ones) { + System.out.println("parsing: '"+s+"' now"); + double d = DoubleParser.parse(s); + System.out.println("expected: 1.0"); + System.out.println("actual: "+d); + assertEquals(1.0, d, 0); + } + } + + @Test + public void testMinusOne() { + String[] numbers = { + "-1", + "-1.0", + "-1.", + "-1e0", + "-10e-1", + }; + for (String s : numbers) { + System.out.println("parsing: '"+s+"' now"); + double d = DoubleParser.parse(s); + System.out.println("expected: -1.0"); + System.out.println("actual: "+d); + assertEquals(-1.0, d, 0); + } + } + + @Test + public void testNanInf() { + String[] numbers = { + "NaN", + "Infinity", + "-Infinity", + "+Infinity", + "+NaN", + "-NaN" + }; + for (String s : numbers) { + System.out.println("parsing: '"+s+"' now"); + double d1 = Double.parseDouble(s); + double d2 = DoubleParser.parse(s); + long lb1 = Double.doubleToRawLongBits(d1); + long lb2 = Double.doubleToRawLongBits(d2); + assertEquals(lb1, lb2, 0); + } + } + + @Test + public void testSeven() { + String[] sevens = { + "7", + "7.", + "7.0", + "70.0e-1", + "0.7e1", + "7000.0e-3", + ".007e+3", + }; + for (String s : sevens) { + System.out.println("parsing: '"+s+"' now"); + double d = DoubleParser.parse(s); + System.out.println("expected: 7.0"); + System.out.println("actual: "+d); + assertEquals(7.0, d, 0); + } + } + + @Test + public void testVerySmallNumbers() { + String[] numbers = { + "1.e-320", + "-1.e-320", + "1.0013378241589014e-303" + }; + for (String s : numbers) { + System.out.println("parsing: '"+s+"' now"); + double d1 = Double.parseDouble(s); + double d2 = DoubleParser.parse(s); + System.out.println("expected: "+d1); + System.out.println("actual: "+d2); + assertEquals(d1, d2, 0); + } + } + + @Test + public void testRandomNumbers() { + java.util.Random rgen = new java.util.Random(0xCafeBabe); + for (int i = 0; i < 123456; i++) { + double d = rgen.nextDouble(); + int exp = rgen.nextInt(); + d *= Math.pow(1.0000006, exp); + String s = Double.toString(d); + double d2 = Double.parseDouble(s); + double d3 = DoubleParser.parse(s); + + if (d != d2) { + System.out.println("WARNING: value ["+d+"] parses as ["+d2+"] by Java"); + } + double allow = 1.0e-14 * d2; + if (allow < 0) { + allow = -allow; + } + if (d2 != d3) { + long lb2 = Double.doubleToRawLongBits(d2); + long lb3 = Double.doubleToRawLongBits(d3); + if (lb2 - lb3 > 15 || lb3 - lb2 > 15) { + System.out.println("WARNING: string '"+s+"' parses as"); + System.out.println("["+d2+"] by Java, ["+d3+"] by our method"); + System.out.println("["+Long.toHexString(lb2)+"] bits vs ["+Long.toHexString(lb3)+"]"); + System.out.println("==> "+(lb2 - lb3)+" <== diff value"); + } + } + assertEquals(d2, d3, allow); + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java b/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java new file mode 100644 index 00000000000..2e0af153fc7 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/DoubleToStringBenchmark.java @@ -0,0 +1,123 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Ignore; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; + +/** + * @author arnej27959 + */ +public class DoubleToStringBenchmark { + + @Test + @Ignore + public void benchmarkStringConstruction() throws Exception { + List> taskList = Arrays.asList(UseStringValueOf.class, + UseDoubleFormatter.class, + UseDoubleFormatter.class, + UseStringValueOf.class, + UseStringValueOf.class, + UseDoubleFormatter.class, + UseDoubleFormatter.class, + UseStringValueOf.class, + UseDoubleFormatter.class, + UseStringValueOf.class); + + int maxThreads = 256; + int dummy = 0; + System.out.print("warmup"); + for (Class taskClass : taskList) { + dummy += runBenchmark(maxThreads, taskClass); + System.out.print("."); + } + System.out.println(" " + dummy); + + System.out.format("%-35s", ""); + for (int numThreads = 1; numThreads <= maxThreads; numThreads *= 2) { + System.out.format("%13s t ", numThreads); + } + System.out.println(); + for (Class taskClass : taskList) { + System.out.format("%-35s", taskClass.getSimpleName()); + for (int numThreads = 1; numThreads <= maxThreads; numThreads *= 2) { + System.out.format("%15d ", runBenchmark(numThreads, taskClass)); + } + System.out.println(); + } + } + + private long runBenchmark(int numThreads, Class taskClass) throws Exception { + return new Benchmark.Builder() + .setNumIterationsPerThread(80000) + .setNumThreads(numThreads) + .setTaskClass(taskClass) + .build() + .run(); + } + + public static class UseStringValueOf implements Benchmark.Task { + + private long timeIt(Random randomGen, int num) { + long before = System.nanoTime(); + + String str = null; + double v = 0.0; + for (int i = 0; i < num; ++i) { + v = randomGen.nextDouble() * 1.0e-2; + str = String.valueOf(v); + } + + long after = System.nanoTime(); + assertEquals(""+v, str); + return after - before; + } + + @Override + public long run(CyclicBarrier barrier, int numIterations) throws Exception { + Random randomGen = new Random(0xDeadBeef); + barrier.await(600, TimeUnit.SECONDS); + long t1 = timeIt(randomGen, numIterations / 4); + long t2 = timeIt(randomGen, numIterations / 2); + long t3 = timeIt(randomGen, numIterations / 4); + return t2; + } + } + + public static class UseDoubleFormatter implements Benchmark.Task { + + private long timeIt(Random randomGen, int num) { + long before = System.nanoTime(); + + String str = null; + double v = 0.0; + for (int i = 0; i < num; ++i) { + v = randomGen.nextDouble() * 1.0e-2; + str = DoubleFormatter.stringValue(v); + } + + long after = System.nanoTime(); + // assertEquals(""+v, str); + return after - before; + } + + + @Override + public long run(CyclicBarrier barrier, int numIterations) throws Exception { + Random randomGen = new Random(0xDeadBeef); + barrier.await(600, TimeUnit.SECONDS); + long t1 = timeIt(randomGen, numIterations / 4); + long t2 = timeIt(randomGen, numIterations / 2); + long t3 = timeIt(randomGen, numIterations / 4); + return t2; + } + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/ForwardWriterTestCase.java b/vespajlib/src/test/java/com/yahoo/text/ForwardWriterTestCase.java new file mode 100644 index 00000000000..6984c2ec6a8 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/ForwardWriterTestCase.java @@ -0,0 +1,435 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.yahoo.protect.ClassValidator; + +/** + * Check all methods forward correctly and wrap exceptions as documented. + * + * @author Steinar Knutsen + * + */ +public class ForwardWriterTestCase { + private static final String WRITE_ABSTRACT_UTF8_ARRAY = "write(AbstractUtf8Array)"; + private static final String WRITE_BOOLEAN = "write(boolean)"; + private static final String WRITE_CHAR = "write(char)"; + private static final String WRITE_DOUBLE = "write(double)"; + private static final String WRITE_FLOAT = "write(float)"; + private static final String WRITE_CHAR_SEQUENCE = "write(CharSequence)"; + private static final String WRITE_CHAR_INT_INT = "write(char[], int, int)"; + private static final String FLUSH = "flush()"; + private static final String CLOSE = "close()"; + private static final String WRITE_STRING = "write(String)"; + private static final String WRITE_LONG = "write(long)"; + private static final String WRITE_SHORT = "write(short)"; + private static final String WRITE_BYTE = "write(byte)"; + + private static class Boom extends GenericWriter { + @Override + public GenericWriter write(final char c) throws IOException { + method(WRITE_CHAR); + final GenericWriter w = super.write(c); + explode(); + return w; + } + + @Override + public GenericWriter write(final CharSequence s) throws IOException { + method(WRITE_CHAR_SEQUENCE); + final GenericWriter w = super.write(s); + explode(); + return w; + } + + @Override + public void write(final String s) throws IOException { + method(WRITE_STRING); + super.write(s); + explode(); + } + + @Override + public GenericWriter write(final long i) throws IOException { + method(WRITE_LONG); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public void write(final int i) throws IOException { + method("write(int)"); + super.write(i); + explode(); + } + + @Override + public GenericWriter write(final short i) throws IOException { + method(WRITE_SHORT); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public GenericWriter write(final byte i) throws IOException { + method(WRITE_BYTE); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public GenericWriter write(final double i) throws IOException { + method(WRITE_DOUBLE); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public GenericWriter write(final float i) throws IOException { + method(WRITE_FLOAT); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public GenericWriter write(final boolean i) throws IOException { + method(WRITE_BOOLEAN); + final GenericWriter w = super.write(i); + explode(); + return w; + } + + @Override + public GenericWriter write(final AbstractUtf8Array v) + throws IOException { + method(WRITE_ABSTRACT_UTF8_ARRAY); + final GenericWriter w = super.write(v); + explode(); + return w; + } + + StringBuilder last = new StringBuilder(); + private boolean explode = false; + private boolean toplevel; + private String method; + + @Override + public void write(final char[] cbuf, final int off, final int len) + throws IOException { + method(WRITE_CHAR_INT_INT); + last.append(cbuf, off, len); + explode(); + } + + @Override + public void flush() throws IOException { + method(FLUSH); + explode(); + + } + + @Override + public void close() throws IOException { + method(CLOSE); + explode(); + } + + private void method(final String method) { + if (toplevel) { + this.method = method; + toplevel = false; + } + } + + private void explode() throws IOException { + if (explode) { + throw new IOException(method); + } + } + + void arm() { + explode = true; + toplevel = true; + } + } + + private Boom wrapped; + private ForwardWriter forward; + private boolean gotException; + + @Before + public void setUp() throws Exception { + wrapped = new Boom(); + forward = new ForwardWriter(wrapped); + gotException = false; + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void requireForwardWriterIsComplete() { + final List methods = ClassValidator + .unmaskedMethodsFromSuperclass(ForwardWriter.class); + assertEquals(0, methods.size()); + } + + @Test + public final void testWriteInt() { + forward.write(0x1ECD); + assertEquals("\u1ECD", wrapped.last.toString()); + wrapped.arm(); + try { + forward.write(0); + } catch (final RuntimeException e) { + assertEquals("write(int)", e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + @Test + public final void testWriteCharArrayIntInt() { + writeCharArrayIntInt(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeCharArrayIntInt(); + } catch (final RuntimeException e) { + assertEquals(WRITE_CHAR_INT_INT, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeCharArrayIntInt() { + forward.write(new char[] { '0' }, 0, 1); + } + + @Test + public final void testFlush() { + wrapped.arm(); + try { + forward.flush(); + } catch (final RuntimeException e) { + assertEquals(FLUSH, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + @Test + public final void testClose() { + wrapped.arm(); + try { + forward.close(); + } catch (final RuntimeException e) { + assertEquals(CLOSE, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + @Test + public final void testWriteString() { + writeString(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeString(); + } catch (final RuntimeException e) { + assertEquals(WRITE_STRING, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeString() { + forward.write("0"); + } + + @Test + public final void testWriteCharSequence() { + writeCharSequence(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeCharSequence(); + } catch (final RuntimeException e) { + assertEquals(WRITE_CHAR_SEQUENCE, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeCharSequence() { + forward.write((CharSequence) "0"); + } + + @Test + public final void testWriteLong() { + writeLong(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeLong(); + } catch (final RuntimeException e) { + assertEquals(WRITE_LONG, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeLong() { + forward.write((long) 0); + } + + @Test + public final void testWriteFloat() { + writeFloat(); + assertEquals("0.0", wrapped.last.toString()); + wrapped.arm(); + try { + writeFloat(); + } catch (final RuntimeException e) { + assertEquals(WRITE_FLOAT, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeFloat() { + forward.write(0.0f); + } + + @Test + public final void testWriteDouble() { + writeDouble(); + assertEquals("0.0", wrapped.last.toString()); + wrapped.arm(); + try { + writeDouble(); + } catch (final RuntimeException e) { + assertEquals(WRITE_DOUBLE, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeDouble() { + forward.write(0.0d); + } + + @Test + public final void testWriteShort() { + writeShort(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeShort(); + } catch (final RuntimeException e) { + assertEquals(WRITE_SHORT, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeShort() { + forward.write((short) 0); + } + + @Test + public final void testWriteChar() { + writeChar(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeChar(); + } catch (final RuntimeException e) { + assertEquals(WRITE_CHAR, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeChar() { + forward.write('0'); + } + + @Test + public final void testWriteByte() { + writeByte(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeByte(); + } catch (final RuntimeException e) { + assertEquals(WRITE_BYTE, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeByte() { + forward.write((byte) 0); + } + + @Test + public final void testWriteBoolean() { + writeBoolean(); + assertEquals("true", wrapped.last.toString()); + wrapped.arm(); + try { + writeBoolean(); + } catch (final RuntimeException e) { + assertEquals(WRITE_BOOLEAN, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + } + + public void writeBoolean() { + forward.write(true); + } + + @Test + public final void testWriteAbstractUtf8Array() { + writeUtf8Array(); + assertEquals("0", wrapped.last.toString()); + wrapped.arm(); + try { + writeUtf8Array(); + } catch (final RuntimeException e) { + assertEquals(WRITE_ABSTRACT_UTF8_ARRAY, e.getCause().getMessage()); + gotException = true; + } + assertTrue(gotException); + + } + + public void writeUtf8Array() { + forward.write(new Utf8Array(Utf8.toBytes("0"))); + } + + @Test + public final void testGetWriter() { + assertSame(wrapped, forward.getWriter()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/GenericWriterTestCase.java b/vespajlib/src/test/java/com/yahoo/text/GenericWriterTestCase.java new file mode 100644 index 00000000000..619065ff7bf --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/GenericWriterTestCase.java @@ -0,0 +1,107 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +/** + * Completeness check for GenericWriter. + * + * @author Steinar Knutsen + */ +public class GenericWriterTestCase { + private static class MockWriter extends GenericWriter { + private StringBuilder written = new StringBuilder(); + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + written.append(String.copyValueOf(cbuf, off, len)); + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + } + + MockWriter mock; + + @Before + public void setUp() throws Exception { + mock = new MockWriter(); + } + + @Test + public final void testWriteInt() throws Exception { + mock.write(0xa); + assertEquals("\n", mock.written.toString()); + } + + @Test + public final void testWriteChar() throws IOException { + mock.write('\u0020'); + assertEquals(" ", mock.written.toString()); + } + + @Test + public final void testWriteCharSequence() throws IOException { + mock.write((CharSequence) "abc"); + assertEquals("abc", mock.written.toString()); + } + + @Test + public final void testWriteString() throws IOException { + mock.write("abc"); + assertEquals("abc", mock.written.toString()); + } + + @Test + public final void testWriteLong() throws IOException { + mock.write(42L); + assertEquals("42", mock.written.toString()); + } + + @Test + public final void testWriteShort() throws IOException { + mock.write((short) 42); + assertEquals("42", mock.written.toString()); + } + + @Test + public final void testWriteByte() throws IOException { + mock.write((byte) 42); + assertEquals("42", mock.written.toString()); + } + + @Test + public final void testWriteDouble() throws IOException { + mock.write(0.0d); + assertEquals("0.0", mock.written.toString()); + } + + @Test + public final void testWriteFloat() throws IOException { + mock.write(0.0f); + assertEquals("0.0", mock.written.toString()); + } + + @Test + public final void testWriteBoolean() throws IOException { + mock.write(true); + assertEquals("true", mock.written.toString()); + } + + @Test + public final void testWriteAbstractUtf8Array() throws IOException { + mock.write(new Utf8Array(Utf8.toBytes("abc"))); + assertEquals("abc", mock.written.toString()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/HTMLTestCase.java b/vespajlib/src/test/java/com/yahoo/text/HTMLTestCase.java new file mode 100644 index 00000000000..2eab7d42aed --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/HTMLTestCase.java @@ -0,0 +1,49 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * @author Bjorn Borud + */ +public class HTMLTestCase { + + @Test + public void testSimpleEscape() { + assertEquals(""this <&> that"", + HTML.htmlescape("\"this <&> that\"")); + } + + @Test + public void testBunchOfEscapes() { + assertEquals( + "©®ÀÁÂÃÄÅÆÇ", + HTML.htmlescape("\u00A9\u00AE\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7")); + + assertEquals( + "ÈÉÊËÌÍÎÏÐÑ", + HTML.htmlescape("\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1")); + + assertEquals( + "ÒÓÔÕÖØÙÚÛÜ", + HTML.htmlescape("\u00D2\u00D3\u00D4\u00D5\u00D6\u00D8\u00D9\u00DA\u00DB\u00DC")); + + assertEquals( + "ÝÞßàáâãäåæ", + HTML.htmlescape("\u00DD\u00DE\u00DF\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6")); + + assertEquals( + "çèéêëìíîïì", + HTML.htmlescape("\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00EC")); + + assertEquals( + "íîïðñòóôõö", + HTML.htmlescape("\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6")); + + assertEquals( + "øùúûüýþÿ", + HTML.htmlescape("\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF")); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/IdentifierTestCase.java b/vespajlib/src/test/java/com/yahoo/text/IdentifierTestCase.java new file mode 100644 index 00000000000..447b109983e --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/IdentifierTestCase.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * Created with IntelliJ IDEA. + * User: balder + * Date: 11.11.12 + * Time: 10:58 + * To change this template use File | Settings | File Templates. + */ +public class IdentifierTestCase { + @Test + public void testIdentifier() { + assertEquals(new Identifier("").toString(), ""); + assertEquals(new Identifier("a").toString(), "a"); + assertEquals(new Identifier("z").toString(), "z"); + assertEquals(new Identifier("B").toString(), "B"); + assertEquals(new Identifier("Z").toString(), "Z"); + assertEquals(new Identifier("_").toString(), "_"); + try { + assertEquals(new Identifier("0").toString(), "0"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '0' of identifier '0'."); + } + try { + assertEquals(new Identifier("-").toString(), "-"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '-' of identifier '-'."); + } + assertEquals(new Identifier("a0_9").toString(), "a0_9"); + assertEquals(new Identifier("a9Z_").toString(), "a9Z_"); + try { + assertEquals(new Identifier("a-b").toString(), "a-b"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal character '-' of identifier 'a-b'."); + } + + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/JSONTest.java b/vespajlib/src/test/java/com/yahoo/text/JSONTest.java new file mode 100644 index 00000000000..53be5a1bda5 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/JSONTest.java @@ -0,0 +1,25 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Jon Bratseth + */ +public class JSONTest { + + @Test + public void testMapToString() { + Map map = new LinkedHashMap<>(); + map.put("a \"key\"", 3); + map.put("key2", "value"); + map.put("key3", 3.3); + + assertEquals("{\"a \\\"key\\\"\":3,\"key2\":\"value\",\"key3\":3.3}", JSON.encode(map)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/JSONWriterTestCase.java b/vespajlib/src/test/java/com/yahoo/text/JSONWriterTestCase.java new file mode 100644 index 00000000000..16d9fe65769 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/JSONWriterTestCase.java @@ -0,0 +1,114 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import static org.junit.Assert.*; + +/** + * Tests the JSON writer + * + * @author Jon Bratseth + */ +@SuppressWarnings("deprecation") +public class JSONWriterTestCase { + + @Test + public void testJSONWriter() throws IOException { + OutputStream out = new ByteArrayOutputStream(); + JSONWriter w = new JSONWriter(out); + + w.beginObject(); + + w.beginField("string").value("a string").endField(); + w.beginField("number").value(37).endField(); + w.beginField("true").value(true).endField(); + w.beginField("false").value(false).endField(); + w.beginField("null").value().endField(); + + w.beginField("object").beginObject(); + w.beginField("nested-array").beginArray().beginArrayValue().value(1).endArrayValue().endArray().endField(); + w.endObject().endField(); + + w.beginField("array").beginArray(); + w.beginArrayValue().value("item1").endArrayValue(); + w.beginArrayValue().value("item2").endArrayValue(); + w.beginArrayValue().beginObject().beginField("nested").value("item3").endField().endObject().endArrayValue(); + w.endArray().endField(); + + w.endObject(); + + assertEquals("{\"string\":\"a string\"," + + "\"number\":37," + + "\"true\":true," + + "\"false\":false," + + "\"null\":null," + + "\"object\":{\"nested-array\":[1]}," + + "\"array\":[\"item1\",\"item2\",{\"nested\":\"item3\"}]}", + out.toString()); + } + + @Test + public void testJSONWriterEmptyObject() throws IOException { + OutputStream out = new ByteArrayOutputStream(); + JSONWriter w = new JSONWriter(out); + w.beginObject(); + w.endObject(); + + assertEquals("{}",out.toString()); + } + + @Test + public void testJSONWriterEmptyArray() throws IOException { + OutputStream out = new ByteArrayOutputStream(); + JSONWriter w = new JSONWriter(out); + w.beginArray(); + w.endArray(); + + assertEquals("[]",out.toString()); + } + + @Test + public void testJSONWriterStringOnly() throws IOException { + OutputStream out = new ByteArrayOutputStream(); + JSONWriter w = new JSONWriter(out); + w.value("Hello, world!"); + + assertEquals("\"Hello, world!\"",out.toString()); + } + + @Test + public void testJSONWriterNestedArrays() throws IOException { + OutputStream out = new ByteArrayOutputStream(); + JSONWriter w = new JSONWriter(out); + w.beginArray(); + + w.beginArrayValue().beginArray(); + w.endArray().endArrayValue(); + + w.beginArrayValue().beginArray(); + w.beginArrayValue().value("hello").endArrayValue(); + w.beginArrayValue().value("world").endArrayValue(); + w.endArray().endArrayValue(); + + w.beginArrayValue().beginArray(); + w.endArray().endArrayValue(); + + w.beginArrayValue().beginArray(); + w.beginArrayValue().beginArray(); + w.endArray().endArrayValue(); + w.endArray().endArrayValue(); + + w.beginArrayValue().beginArray(); + w.endArray().endArrayValue(); + + w.endArray(); + + assertEquals("[[],[\"hello\",\"world\"],[],[[]],[]]",out.toString()); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/JsonMicroBenchmarkTestCase.java b/vespajlib/src/test/java/com/yahoo/text/JsonMicroBenchmarkTestCase.java new file mode 100644 index 00000000000..c2c1774ca1d --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/JsonMicroBenchmarkTestCase.java @@ -0,0 +1,563 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import static org.junit.Assert.*; + +import java.io.ByteArrayOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TreeMap; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +@SuppressWarnings("deprecation") +public class JsonMicroBenchmarkTestCase { + + private static final long RUNTIME = 20L * 60L * 1000L; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + enum Strategy { + VESPAJLIB, JACKSON; + } + + private static abstract class BenchFactory { + abstract Bench produce(); + } + + private static class VespajlibFactory extends BenchFactory { + + @Override + Bench produce() { + return new OutputWithWriter(); + } + + } + + private static class JacksonFactory extends BenchFactory { + @Override + Bench produce() { + return new OutputWithGenerator(); + } + } + + private static abstract class Bench implements Runnable { + public volatile long runs; + public volatile long start; + public volatile long end; + public volatile long metric; + + /** + * Object identity is used to differentiate between different implementation strategies, toString() is used to print a report. + * + * @return an object with a descriptive toString() for the implementation under test + */ + abstract Object category(); + + @Override + public final void run() { + Random random = new Random(42L); + long localBytesWritten = 0L; + long localRuns = 0; + + start = System.currentTimeMillis(); + long target = start + JsonMicroBenchmarkTestCase.RUNTIME; + + while (System.currentTimeMillis() < target) { + for (int i = 0; i < 1000; ++i) { + localBytesWritten += iterate(random); + } + localRuns += 1000L; + } + end = System.currentTimeMillis(); + runs = localRuns; + metric = localBytesWritten; + } + + abstract int iterate(Random random); + } + + private static final class OutputWithGenerator extends Bench { + + public OutputWithGenerator() { + } + + + int iterate(Random random) { + JsonGenerator generator; + ByteArrayOutputStream generatorOut = new ByteArrayOutputStream(); + try { + generator = new JsonFactory().createJsonGenerator(generatorOut, + JsonEncoding.UTF8); + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + try { + serialize(generatedDoc(random), generator); + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + try { + generator.close(); + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + return generatorOut.toByteArray().length; + } + + static void serialize(Map m, JsonGenerator g) throws IOException { + g.writeStartObject(); + for (Map.Entry e : m.entrySet()) { + g.writeFieldName(e.getKey()); + serializeField(g, e.getValue()); + } + g.writeEndObject(); + } + + @SuppressWarnings("unchecked") + static void serializeField(JsonGenerator g, final Object value) + throws IOException { + if (value instanceof Map) { + serialize((Map) value, g); + } else if (value instanceof Number) { + g.writeNumber(((Number) value).intValue()); + } else if (value instanceof String) { + g.writeString((String) value); + } else if (value instanceof List) { + g.writeStartArray(); + for (Object o : (List) value) { + serializeField(g, o); + } + g.writeEndArray(); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + Object category() { + return Strategy.JACKSON; + } + + } + + private static final class OutputWithWriter extends Bench { + + OutputWithWriter() { + } + + int iterate(Random random) { + ByteArrayOutputStream writerOut = new ByteArrayOutputStream(); + JSONWriter writer = new JSONWriter(writerOut); + try { + serialize(generatedDoc(random), writer); + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + return writerOut.toByteArray().length; + } + + static void serialize(Map m, JSONWriter w) throws IOException { + w.beginObject(); + for (Map.Entry e : m.entrySet()) { + w.beginField(e.getKey()); + final Object value = e.getValue(); + serializeField(w, value); + w.endField(); + } + w.endObject(); + } + + @SuppressWarnings("unchecked") + static void serializeField(JSONWriter w, final Object value) + throws IOException { + if (value instanceof Map) { + serialize((Map) value, w); + } else if (value instanceof Number) { + w.value((Number) value); + } else if (value instanceof String) { + w.value((String) value); + } else if (value instanceof List) { + w.beginArray(); + for (Object o : (List) value) { + w.beginArrayValue(); + serializeField(w, o); + w.endArrayValue(); + } + w.endArray(); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + Object category() { + return Strategy.VESPAJLIB; + } + + } + + @Test + @Ignore + public final void test() throws InterruptedException { + final OutputWithWriter forWriter = new OutputWithWriter(); + Thread writerThread = new Thread(forWriter); + final OutputWithGenerator forGenerator = new OutputWithGenerator(); + Thread generatorThread = new Thread(forGenerator); + writerThread.start(); + generatorThread.start(); + writerThread.join(); + generatorThread.join(); + System.out.println("Generator time: " + (forGenerator.end - forGenerator.start)); + System.out.println("Writer time: " + (forWriter.end - forWriter.start)); + System.out.println("Output length from generator: " + forGenerator.metric); + System.out.println("Output length from writer: " + forWriter.metric); + System.out.println("Iterations with generator: " + forGenerator.runs); + System.out.println("Iterations with writer: " + forWriter.runs); + System.out.println("Iterations/s with generator: " + ((double) forGenerator.runs / (double) (forGenerator.end - forGenerator.start)) * 1000.0d); + System.out.println("Iterations/s with writer: " + ((double) forWriter.runs / (double) (forWriter.end - forWriter.start)) * 1000.0d); + } + + @Test + @Ignore + public final void test16Threads() throws InterruptedException { + List threads = new ArrayList<>(16); + List benches = createBenches(8, new VespajlibFactory(), new JacksonFactory()); + + for (Bench bench : benches) { + threads.add(new Thread(bench)); + } + for (Thread t : threads) { + t.start(); + } + for (Thread t : threads) { + t.join(); + } + + System.out.println("8 Jackson threads competing with 8 VespaJLib threads."); + metrics(benches, Strategy.JACKSON); + metrics(benches, Strategy.VESPAJLIB); + } + + @Test + @Ignore + public final void test16ThreadsJacksonOnly() throws InterruptedException { + List threads = new ArrayList<>(16); + List benches = createBenches(16, new JacksonFactory()); + + for (Bench bench : benches) { + threads.add(new Thread(bench)); + } + for (Thread t : threads) { + t.start(); + } + for (Thread t : threads) { + t.join(); + } + + System.out.println("16 Jackson threads."); + metrics(benches, Strategy.JACKSON); + } + + @Test + @Ignore + public final void test16ThreadsVespaJlibOnly() throws InterruptedException { + List threads = new ArrayList<>(16); + List benches = createBenches(16, new VespajlibFactory()); + + for (Bench bench : benches) { + threads.add(new Thread(bench)); + } + for (Thread t : threads) { + t.start(); + } + for (Thread t : threads) { + t.join(); + } + + System.out.println("16 VespaJLib threads."); + metrics(benches, Strategy.VESPAJLIB); + } + + + private void metrics(List benches, Strategy choice) { + List chosen = new ArrayList<>(); + + for (Bench b : benches) { + if (b.category() == choice) { + chosen.add(b); + } + } + + long[] rawTime = new long[chosen.size()]; + long[] rawOutputLength = new long[chosen.size()]; + long[] rawIterations = new long[chosen.size()]; + double[] rawIterationsPerSecond = new double[chosen.size()]; + + for (int i = 0; i < chosen.size(); ++i) { + Bench b = chosen.get(i); + rawTime[i] = b.end - b.start; + rawOutputLength[i] = b.metric; + rawIterations[i] = b.runs; + rawIterationsPerSecond[i] = ((double) b.runs) / (((double) (b.end - b.start)) / 1000.0d); + } + + double avgTime = mean(rawTime); + double avgOutputLength = mean(rawOutputLength); + double avgIterations = mean(rawIterations); + double avgIterationsPerSecond = mean(rawIterationsPerSecond); + + System.out.println("For " + choice + ":"); + dumpMetric("run time", rawTime, avgTime, "s", 0.001d); + dumpMetric("output length", rawOutputLength, avgOutputLength, "bytes", 1.0d); + dumpMetric("iterations", rawIterations, avgIterations, "", 1.0d); + dumpMetric("iterations per second", rawIterationsPerSecond, avgIterationsPerSecond, "s**-1", 1.0d); + } + + private void dumpMetric(String name, long[] raw, double mean, String unit, double scale) { + System.out.println("Average " + name + ": " + mean * scale + " " + unit); + System.out.println("Mean absolute deviation of " + name + ": " + averageAbsoluteDeviationFromMean(raw, mean) * scale + " " + unit); + System.out.println("Minimum " + name + ": " + min(raw) * scale + " " + unit); + System.out.println("Maximum " + name + ": " + max(raw) * scale + " " + unit); + } + + private void dumpMetric(String name, double[] raw, double mean, String unit, double scale) { + System.out.println("Average " + name + ": " + mean * scale + " " + unit); + System.out.println("Mean absolute deviation of " + name + ": " + averageAbsoluteDeviationFromMean(raw, mean) * scale + " " + unit); + System.out.println("Minimum " + name + ": " + min(raw) * scale + " " + unit); + System.out.println("Maximum " + name + ": " + max(raw) * scale + " " + unit); + } + + private List createBenches(int ofEach, BenchFactory... factories) { + List l = new ArrayList<>(ofEach * factories.length); + + // note how the bench objects of different objects become intermingled, this is by design + for (int i = 0; i < ofEach; ++i) { + for (BenchFactory factory : factories) { + l.add(factory.produce()); + } + } + return l; + } + + private double mean(long[] values) { + long sum = 0L; + + // ignore overflow :) + for (long v : values) { + sum += v; + } + return ((double) sum / (double) values.length); + } + + private double mean(double[] values) { + double sum = 0L; + + for (double v : values) { + sum += v; + } + return sum / (double) values.length; + } + + private double averageAbsoluteDeviationFromMean(long[] values, double mean) { + double sum = 0.0d; + + for (long v : values) { + sum += Math.abs(mean - (double) v); + } + + return sum / (double) values.length; + } + + private double averageAbsoluteDeviationFromMean(double[] values, double mean) { + double sum = 0.0d; + + for (double v : values) { + sum += Math.abs(mean - v); + } + + return sum / (double) values.length; + } + + private long min(long[] values) { + long min = Long.MAX_VALUE; + + for (long v : values) { + min = Math.min(min, v); + } + return min; + } + + private double min(double[] values) { + double min = Double.MAX_VALUE; + + for (double v : values) { + min = Math.min(min, v); + } + return min; + } + + private long max(long[] values) { + long max = Long.MIN_VALUE; + + for (long v : values) { + max = Math.max(max, v); + } + return max; + } + + private double max(double[] values) { + double max = Double.MIN_VALUE; + + for (double v : values) { + max = Math.max(max, v); + } + return max; + } + + @SuppressWarnings("null") + @Test + @Ignore + public final void testSanity() throws IOException { + @SuppressWarnings("unused") + String a, b; + { + Random random = new Random(42L); + JsonGenerator generator = null; + ByteArrayOutputStream generatorOut = new ByteArrayOutputStream(); + try { + generator = new JsonFactory().createJsonGenerator(generatorOut, + JsonEncoding.UTF8); + } catch (IOException e) { + e.printStackTrace(); + fail(); + } + try { + OutputWithGenerator.serialize(generatedDoc(random), generator); + } catch (IOException e) { + e.printStackTrace(); + fail(); + } + try { + generator.close(); + } catch (IOException e) { + e.printStackTrace(); + fail(); + } + a = generatorOut.toString("UTF-8"); + } + { + Random random = new Random(42L); + ByteArrayOutputStream writerOut = new ByteArrayOutputStream(); + JSONWriter writer = new JSONWriter(writerOut); + try { + OutputWithWriter.serialize(generatedDoc(random), writer); + } catch (IOException e) { + e.printStackTrace(); + fail(); + } + b = writerOut.toString("UTF-8"); + } + // dumpToFile("/tmp/a", a); + // dumpToFile("/tmp/b", b); + } + + @SuppressWarnings("unused") + private void dumpToFile(String path, String b) throws IOException { + FileWriter f = new FileWriter(path); + f.write(b); + f.close(); + } + + static Map generatedDoc(Random random) { + return generateObject(random, 0, random.nextInt(8)); + } + + static String generateFieldName(Random random) { + int len = random.nextInt(100) + 3; + char[] base = new char[len]; + for (int i = 0; i < len; ++i) { + base[i] = (char) (random.nextInt(26) + 'a'); + } + return new String(base); + } + + static byte[] generateByteArrayPayload(Random random) { + return null; + } + + static String generateStringPayload(Random random) { + int len = random.nextInt(100) + random.nextInt(100) + random.nextInt(100) + random.nextInt(100); + char[] base = new char[len]; + for (int i = 0; i < len; ++i) { + base[i] = (char) random.nextInt(0xd800); + } + return new String(base); + } + + static Number generateInt(Random random) { + return Integer.valueOf(random.nextInt()); + } + + static List generateArray(Random random, int nesting, int maxNesting) { + int len = random.nextInt(10) + random.nextInt(10) + random.nextInt(10) + random.nextInt(10); + List list = new ArrayList<>(len); + for (int i = 0; i < len; ++i) { + list.add(generateStuff(random, nesting, maxNesting)); + } + return list; + } + + private static Object generateStuff(Random random, int nesting, int maxNesting) { + if (nesting >= maxNesting) { + return generatePrimitive(random); + } else { + final int die = random.nextInt(10); + if (die == 9) { + return generateObject(random, nesting + 1, maxNesting); + } else if (die == 8) { + return generateArray(random, nesting + 1, maxNesting); + } else { + return generatePrimitive(random); + } + } + } + + private static Object generatePrimitive(Random random) { + if (random.nextInt(2) == 0) { + return generateStringPayload(random); + } else { + return generateInt(random); + } + } + + static Map generateObject(Random random, int nesting, int maxNesting) { + int len = random.nextInt(5) + random.nextInt(5) + random.nextInt(5) + random.nextInt(5); + Map m = new TreeMap<>(); + for (int i = 0; i < len; ++i) { + m.put(generateFieldName(random), generateStuff(random, nesting, maxNesting)); + } + return m; + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/LanguageHacksTestCase.java b/vespajlib/src/test/java/com/yahoo/text/LanguageHacksTestCase.java new file mode 100644 index 00000000000..7b322e44583 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/LanguageHacksTestCase.java @@ -0,0 +1,28 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Test for LanguageHacks. + * $Id$ + */ +@SuppressWarnings("deprecation") +public class LanguageHacksTestCase { + + @Test + public void isCJK() { + assertFalse("NULL language", LanguageHacks.isCJK(null)); + assertTrue(LanguageHacks.isCJK("zh")); + assertFalse("Norwegian is CJK", LanguageHacks.isCJK("no")); + } + + @Test + public void yellDesegments() { + assertFalse("NULL language", LanguageHacks.yellDesegments(null)); + assertTrue(LanguageHacks.yellDesegments("de")); + assertFalse("Norwegian desegments", LanguageHacks.yellDesegments("no")); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/LowercaseIdentifierTestCase.java b/vespajlib/src/test/java/com/yahoo/text/LowercaseIdentifierTestCase.java new file mode 100644 index 00000000000..7d6b066a499 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/LowercaseIdentifierTestCase.java @@ -0,0 +1,41 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created with IntelliJ IDEA. + * User: balder + * Date: 11.11.12 + * Time: 20:54 + * To change this template use File | Settings | File Templates. + */ +public class LowercaseIdentifierTestCase { + @Test + public void testLowercaseIdentifier() { + assertEquals(new LowercaseIdentifier("").toString(), ""); + assertEquals(new LowercaseIdentifier("a").toString(), "a"); + assertEquals(new LowercaseIdentifier("z").toString(), "z"); + assertEquals(new LowercaseIdentifier("_").toString(), "_"); + try { + assertEquals(new Identifier("0").toString(), "0"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal starting character '0' of identifier '0'."); + } + try { + assertEquals(new LowercaseIdentifier("Z").toString(), "z"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal uppercase character 'Z' of identifier 'Z'."); + } + try { + assertEquals(new LowercaseIdentifier("aZb").toString(), "azb"); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "Illegal uppercase character 'Z' of identifier 'aZb'."); + } + + + + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/LowercaseTestCase.java b/vespajlib/src/test/java/com/yahoo/text/LowercaseTestCase.java new file mode 100644 index 00000000000..420d058892b --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/LowercaseTestCase.java @@ -0,0 +1,96 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Ignore; +import org.junit.Test; + +import java.util.Locale; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * @author Einar M R Rosenvinge + * @since 5.1.14 + */ +public class LowercaseTestCase { + + @Test + public void testAZ() { + { + String lowercase = Lowercase.toLowerCase("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + assertThat(lowercase, equalTo("abcdefghijklmnopqrstuvwxyz")); + } + { + String lowercase = Lowercase.toLowerCase("abcdefghijklmnopqrstuvwxyz"); + assertThat(lowercase, equalTo("abcdefghijklmnopqrstuvwxyz")); + } + { + String lowercase = Lowercase.toLowerCase("AbCDEfGHIJklmnoPQRStuvwXyz"); + assertThat(lowercase, equalTo("abcdefghijklmnopqrstuvwxyz")); + } + + { + String lowercase = Lowercase.toLowerCase("@+#"); + assertThat(lowercase, equalTo("@+#")); + } + { + String lowercase = Lowercase.toLowerCase("[]"); + assertThat(lowercase, equalTo("[]")); + } + { + String lowercase = Lowercase.toLowerCase("{}"); + assertThat(lowercase, equalTo("{}")); + } + { + String lowercase = Lowercase.toLowerCase("\u00cd\u00f4"); + assertThat(lowercase, equalTo("\u00ed\u00f4")); + } + } + + @Test + @Ignore + public void performance() { + Lowercase.toLowerCase("warmup"); + String lowercaseInput = "abcdefghijklmnopqrstuvwxyz"; + String uppercaseInput = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + String mixedcaseInput = "AbCDEfGHIJklmnoPQRStuvwXyz"; + + System.err.println("Lowercase input: "); + testPerformance(lowercaseInput); + + System.err.println("Uppercase input: "); + testPerformance(uppercaseInput); + + System.err.println("Mixed-case input: "); + testPerformance(mixedcaseInput); + } + + private void testPerformance(String input) { + final int NUM = 10000000; + long elapsedTimeOwnImpl; + { + long startTimeOwnImpl = System.currentTimeMillis(); + for (int i = 0; i < NUM; i++) { + Lowercase.toLowerCase(input); + } + elapsedTimeOwnImpl = System.currentTimeMillis() - startTimeOwnImpl; + System.err.println("Own implementation: " + elapsedTimeOwnImpl); + } + + long elapsedTimeJava; + { + long startTimeJava = System.currentTimeMillis(); + for (int i = 0; i < NUM; i++) { + input.toLowerCase(Locale.ENGLISH); + } + elapsedTimeJava = System.currentTimeMillis() - startTimeJava; + System.err.println("Java's implementation: " + elapsedTimeJava); + } + + long diff = elapsedTimeJava - elapsedTimeOwnImpl; + double diffPercentage = (((double) diff) / ((double) elapsedTimeJava)) * 100.0; + System.err.println("Own implementation is " + diffPercentage + " % faster."); + + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/MapParserMicroBenchmark.java b/vespajlib/src/test/java/com/yahoo/text/MapParserMicroBenchmark.java new file mode 100644 index 00000000000..21ab4fd4309 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/MapParserMicroBenchmark.java @@ -0,0 +1,62 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import java.util.HashMap; +import java.util.Map; + +/** + * A benchmark of map parsing. + * Expected time on Jon's mac: 200 microseconds per 1k size map. + * + * @author Jon Bratseth + */ +public class MapParserMicroBenchmark { + + private static String generateValues(int size) { + StringBuilder b = new StringBuilder("{"); + for (int i=0; i map = new HashMap<>(); + for (int i=0; i rankingExpressionParserParse(String values, Map map) { + return new DoubleMapParser().parse(values,map); + } + + public static void main(String[] args) { + new MapParserMicroBenchmark().benchmark(100*1000,1000); + } + + private static class DoubleMapParser extends MapParser { + + @Override + protected Double parseValue(String s) { + return Double.parseDouble(s); + } + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/MapParserTestCase.java b/vespajlib/src/test/java/com/yahoo/text/MapParserTestCase.java new file mode 100644 index 00000000000..7bf11c277e1 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/MapParserTestCase.java @@ -0,0 +1,71 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; +import java.util.Map; +import static org.junit.Assert.*; + +/** + * @author Jon Bratseth + */ +public class MapParserTestCase { + + private static final double delta=0.0001; + + @Test + public void testEmpty() { + assertEquals(0, new DoubleMapParser().parseToMap("{}").size()); + } + + @Test + public void testPlain() { + Map values=new DoubleMapParser().parseToMap("{a:0.33,foo:-1.13,bar:1}"); + assertEquals(3, values.size()); + assertEquals(0.33d,values.get("a"),delta); + assertEquals(-1.13d,values.get("foo"),delta); + assertEquals(1.0d,values.get("bar"),delta); + } + + @Test + public void testNoisy() { + Map values=new DoubleMapParser().parseToMap(" { a:0.33, foo:-1.13,bar:1,\"key:colon,\":1.2, '}':0}"); + assertEquals(5, values.size()); + assertEquals(0.33d,values.get("a"),delta); + assertEquals(-1.13d,values.get("foo"),delta); + assertEquals(1.0d,values.get("bar"),delta); + assertEquals(1.2,values.get("key:colon,"),delta); + assertEquals(0,values.get("}"),delta); + } + + @Test + public void testInvalid() { + assertException("Missing quoted string termination","Expected a string terminated by '\"' starting at position 9 but was 'f'","{a:0.33,\"foo:1,bar:1}"); + assertException("Missing map termination","Expected a value followed by ',' or '}' starting at position 10 but was '1'","{a:0.33,b:1"); + assertException("Missing map start","Expected '{' starting at position 0 but was 'a'","a:0.33,b:1}"); + assertException("Missing comma separator","Expected a legal value from position 3 to 11 but was '0.33 b:1'","{a:0.33 b:1}"); + assertException("A single key with no value","Expected a key followed by ':' starting at position 1 but was 'f'","{foo}"); + assertException("A key with no value","Expected ':' starting at position 4 but was ','","{foo,a:2}"); + assertException("Invalid value","Expected a legal value from position 9 to 19 but was 'notanumber'","{invalid:notanumber}"); + assertException("Double key","Expected a legal value from position 3 to 6 but was 'a:1'","{a:a:1}"); + } + + private void assertException(String explanation,String exceptionString,String invalidMapString) { + try { + Map map=new DoubleMapParser().parseToMap(invalidMapString); + fail("Expected exception on: " + explanation + " but parsed to " + map); + } + catch (IllegalArgumentException e) { + assertEquals("Expected message on: " + explanation,exceptionString,e.getCause().getMessage()); + } + } + + public static final class DoubleMapParser extends MapParser { + + @Override + protected Double parseValue(String value) { + return Double.parseDouble(value); + } + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/StringAppendMicroBenchmarkTest.java b/vespajlib/src/test/java/com/yahoo/text/StringAppendMicroBenchmarkTest.java new file mode 100644 index 00000000000..69d62d59be5 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/StringAppendMicroBenchmarkTest.java @@ -0,0 +1,77 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; + +/** + * Compares alternative ways of appending strings + * + * @author Jon Bratseth + */ +public class StringAppendMicroBenchmarkTest { + + private static abstract class Benchmark { + + private int repetitions=10000000; + + public void execute() { + System.out.println("Executing benchmark '" + getName() + "' ..."); + append(100000); // warm-up + long start=System.currentTimeMillis(); + append(repetitions); + long duration=System.currentTimeMillis()-start; + System.out.println("Completed " + repetitions + " repetitions in " + duration + " ms\n"); + } + + private int append(int repetitions) { + String prefix="hello"; + int totalSize=0; + for (int i=0; iSteinar Knutsen + */ +public class Utf8ArrayTestCase { + private String raw; + private byte[] rawBytes; + private Utf8Array toCheck; + + @Before + public void setUp() { + raw = "0123456789"; + rawBytes = Utf8.toBytes(raw); + toCheck = new Utf8Array(rawBytes); + } + + @Test + public final void testGetByteLength() { + assertEquals(rawBytes.length, toCheck.getByteLength()); + } + + @Test + public final void testGetBytes() { + assertSame(rawBytes, toCheck.getBytes()); + } + + @Test + public final void testGetByteOffset() { + assertEquals(0, toCheck.getByteOffset()); + } + + @Test + public final void testUtf8ArrayByteArrayIntInt() { + Utf8Array otherConstructed = new Utf8Array(rawBytes, 0, rawBytes.length); + assertNotSame(rawBytes, otherConstructed.getBytes()); + assertArrayEquals(rawBytes, otherConstructed.getBytes()); + } + + @Test + public final void testUtf8ArrayByteBufferInt() { + final ByteBuffer wrapper = ByteBuffer.wrap(rawBytes); + Utf8Array otherConstructed = new Utf8Array(wrapper, wrapper.remaining()); + assertNotSame(rawBytes, otherConstructed.getBytes()); + assertArrayEquals(rawBytes, otherConstructed.getBytes()); + } + + @Test + public final void testHashCode() { + Utf8Array other = new Utf8Array(Utf8.toBytes(" a23456789")); + assertFalse(other.hashCode() == toCheck.hashCode()); + } + + @Test + public final void testWriteTo() { + ByteBuffer b = ByteBuffer.allocate(rawBytes.length * 2); + byte[] copy = new byte[rawBytes.length]; + toCheck.writeTo(b); + assertEquals(rawBytes.length, b.position()); + b.position(0); + b.limit(rawBytes.length); + b.get(copy); + assertArrayEquals(rawBytes, copy); + } + + @Test + public final void testGetByte() { + assertEquals('8', toCheck.getByte(8)); + } + + @Test + public final void testWrap() { + ByteBuffer b1 = toCheck.wrap(); + ByteBuffer b2 = ByteBuffer.wrap(rawBytes); + byte[] c1 = new byte[b1.remaining()]; + byte[] c2 = new byte[b2.remaining()]; + b1.get(c1); + b2.get(c2); + assertArrayEquals(c2, c1); + } + + @Test + public final void testIsEmpty() { + assertFalse(toCheck.isEmpty()); + assertTrue(new Utf8Array(new byte[] {}).isEmpty()); + } + + @Test + public final void testEqualsObject() { + assertTrue(toCheck.equals(raw)); + assertFalse(toCheck.equals(new Utf8Array(new byte[] {}))); + assertFalse(toCheck.equals(new Utf8Array(Utf8.toBytes(" " + raw.substring(1))))); + assertTrue(toCheck.equals(toCheck)); + assertTrue(toCheck.equals(new Utf8Array(rawBytes))); + } + + @Test + public final void testToString() { + assertEquals(raw, toCheck.toString()); + } + + @Test + public final void testCompareTo() { + assertTrue(toCheck.compareTo(new Utf8Array(new byte[] {})) > 0); + assertTrue(toCheck.compareTo(new Utf8Array(Utf8.toBytes(raw + raw))) < 0); + assertTrue(toCheck.compareTo(new Utf8Array(Utf8.toBytes(" " + raw.substring(1)))) > 0); + assertTrue(toCheck.compareTo(new Utf8Array(Utf8.toBytes("a" + raw.substring(1)))) < 0); + assertTrue(toCheck.compareTo(new Utf8Array(rawBytes)) == 0); + } + + @Test + public final void testPartial() { + final int length = 3; + final int offset = 1; + Utf8PartialArray partial = new Utf8PartialArray(rawBytes, offset, length); + assertEquals(length, partial.getByteLength()); + assertEquals(offset, partial.getByteOffset()); + byte[] expected = new byte[length]; + ByteBuffer intermediate = ByteBuffer.allocate(rawBytes.length * 2); + System.arraycopy(rawBytes, offset, expected, 0, length); + partial.writeTo(intermediate); + intermediate.flip(); + byte written[] = new byte[intermediate.remaining()]; + intermediate.get(written); + assertArrayEquals(expected, written); + } + + @Test + public final void testUtf8Strings() { + String nalle = "nalle"; + Utf8String utf = new Utf8String(new Utf8Array(Utf8.toBytes(nalle))); + assertEquals('n', utf.charAt(0)); + assertEquals(nalle.length(), utf.length()); + assertEquals("alle", utf.subSequence(1, 5)); + assertTrue(utf.equals(new Utf8String(new Utf8Array(Utf8.toBytes(nalle))))); + assertTrue(utf.equals(nalle)); + } + + @Test + public final void testAscii7bitLowercase() { + final byte [] expected = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 ,0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 ,0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26 ,0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 ,0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 ,0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76 ,0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 ,0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76 ,0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f + }; + byte [] org = new byte[128]; + for (byte b = 0; b >= 0; b++) { + org[b] = b; + } + assertArrayEquals(expected, new Utf8Array(org).ascii7BitLowerCase().getBytes()); + } +} diff --git a/vespajlib/src/test/java/com/yahoo/text/Utf8TestCase.java b/vespajlib/src/test/java/com/yahoo/text/Utf8TestCase.java new file mode 100644 index 00000000000..53ee1bb004a --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/Utf8TestCase.java @@ -0,0 +1,554 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Ignore; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharsetEncoder; +import java.util.Arrays; + +import static com.yahoo.text.Lowercase.toLowerCase; +import static com.yahoo.text.Utf8.calculateBytePositions; +import static com.yahoo.text.Utf8.calculateStringPositions; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author Bjorn Borud + * @author Steinar Knutsen + */ +public class Utf8TestCase { + + private static final String TEST_STRING = "This is just sort of random mix. \u5370\u57df\u60c5\u5831\u53EF\u4EE5\u6709x\u00e9\u00e8"; + private static final int[] TEST_CODEPOINTS = {0x0, 0x7f, 0x80, 0x7ff, 0x800, 0xd7ff, 0xe000, 0xffff, 0x10000, 0x10ffff, + 0x34, 0x355, 0x2567, 0xfff, 0xe987, 0x100abc + }; + + public void dumpSome() throws java.io.IOException { + int i = 32; + int j = 3; + int cnt = 0; + while (i < 0x110000) { + if (i < 0xD800 || i >= 0xE000) ++cnt; + i += j; + ++j; + } + System.out.println("allocate "+cnt+" array entries"); + int codes[] = new int[cnt]; + i = 32; + j = 3; + cnt = 0; + while (i < 0x110000) { + if (i < 0xD800 || i >= 0xE000) codes[cnt++] = i; + i += j; + ++j; + } + assertEquals(cnt, codes.length); + System.out.println("fill "+cnt+" array entries"); + String str = new String(codes, 0, cnt); + byte[] arr = Utf8.toBytes(str); + java.io.FileOutputStream fos = new java.io.FileOutputStream("random-long-utf8.dat"); + fos.write(arr); + fos.close(); + } + + public void dumpMore() throws java.io.IOException { + java.text.Normalizer.Form form = java.text.Normalizer.Form.NFKC; + + java.io.FileOutputStream fos = new java.io.FileOutputStream("lowercase-table.dat"); + for (int i = 0; i < 0x110000; i++) { + StringBuilder b = new StringBuilder(); + b.appendCodePoint(i); + String n1 = b.toString(); + String n2 = java.text.Normalizer.normalize(b, form); + if (n1.equals(n2)) { + String l = toLowerCase(n1); + int chars = l.length(); + int codes = l.codePointCount(0, chars); + if (codes != 1) { + System.out.println("codepoint "+i+" transformed into "+codes+" codepoints: "+n1+" -> "+l); + } else { + int lc = l.codePointAt(0); + if (lc != i) { + String o = "lowercase( "+i+" )= "+lc+"\n"; + byte[] arr = Utf8.toBytes(o); + fos.write(arr); + } + } + } + } + fos.close(); + } + + @Test + public void testSimple() { + String s1 = "test"; + String s2 = "f\u00F8rst"; + String s3 = "\u00C5pen"; + byte[] b4 = { (byte) 0xE5, (byte) 0xA4, (byte) 0x89, (byte) 0xE6, + (byte) 0x85, (byte) 0x8B }; + + byte[] b1 = Utf8.toBytes(s1); + byte[] b2 = Utf8.toBytes(s2); + byte[] b3 = Utf8.toBytes(s3); + String s4 = Utf8.toString(b4); + + assertEquals('t', b1[0]); + assertEquals('e', b1[1]); + assertEquals('s', b1[2]); + assertEquals('t', b1[3]); + + assertEquals('f', b2[0]); + assertEquals((byte) 0xC3, b2[1]); + assertEquals((byte) 0xB8, b2[2]); + assertEquals('r', b2[3]); + assertEquals('s', b2[4]); + assertEquals('t', b2[5]); + + assertEquals((byte) 0xC3, b3[0]); + assertEquals((byte) 0x85, b3[1]); + assertEquals('p', b3[2]); + assertEquals('e', b3[3]); + assertEquals('n', b3[4]); + + assertEquals('\u5909', s4.charAt(0)); + assertEquals('\u614B', s4.charAt(1)); + + String ss1 = Utf8.toString(b1); + String ss2 = Utf8.toString(b2); + String ss3 = Utf8.toString(b3); + byte[] bb4 = Utf8.toBytes(s4); + + assertEquals(s1, ss1); + assertEquals(s3, ss3); + assertEquals(s2, ss2); + assertEquals(Utf8.toString(b4), Utf8.toString(bb4)); + } + + private int javaCountBytes(String str) { + byte[] octets = Utf8.toBytes(str); + return octets.length; + } + + private String makeString(int codePoint) { + char[] chars = Character.toChars(codePoint); + return String.valueOf(chars); + } + + @Test + public void testByteCounting() { + for (int c : TEST_CODEPOINTS) { + String testCharacter = makeString(c); + assertEquals(javaCountBytes(testCharacter), Utf8.byteCount(testCharacter)); + } + assertEquals(javaCountBytes(TEST_STRING), Utf8.byteCount(TEST_STRING)); + } + + @Test + public void testTotalBytes() { + //Test with a random mix of + assertEquals(1,Utf8.totalBytes((byte)0x05)); + assertEquals(4,Utf8.totalBytes((byte)0xF3)); + assertEquals(4,Utf8.totalBytes((byte)0xF0)); + assertEquals(1,Utf8.totalBytes((byte)0x7F)); + assertEquals(2,Utf8.totalBytes((byte)0xC2)); + assertEquals(3,Utf8.totalBytes((byte)0xE0)); + } + + @Test + public void testUnitCounting() { + for (int c : TEST_CODEPOINTS) { + String testCharacter = makeString(c); + byte[] utf8 = Utf8.toBytes(testCharacter); + assertEquals(testCharacter.length(), Utf8.unitCount(utf8)); + assertEquals(testCharacter.length(), Utf8.unitCount(utf8[0])); + } + byte[] stringAsUtf8 = Utf8.toBytes(TEST_STRING); + assertEquals(TEST_STRING.length(), Utf8.unitCount(stringAsUtf8)); + + + } + + @Test + public void testCumbersomeEncoding() { + String[] a = {"abc", "def", "ghi\u00e8"}; + int[] aLens = {3, 3, 5}; + CharsetEncoder ce = Utf8.getNewEncoder(); + ByteBuffer forWire = ByteBuffer.allocate(500); + + for (int i = 0; i < a.length; i++) { + forWire.putInt(aLens[i]); + Utf8.toBytes(a[i], 0, + a[i].length(), forWire, ce); + } + forWire.flip(); + int totalLimit = forWire.limit(); + for (String anA : a) { + int len = forWire.getInt(); + forWire.limit(forWire.position() + len); + String s = Utf8.toString(forWire); + assertEquals(anA, s); + forWire.limit(totalLimit); + } + assertEquals(0, forWire.remaining()); + } + + @Test + public void basic() { + String foo = "Washington"; + int[] indexes = calculateBytePositions(foo); + assertThat(indexes.length, is(foo.length() + 1)); + for (int i = 0; i < indexes.length; i++) { + assertThat(indexes[i], is(i)); + } + } + + @Test + public void decodeBasic() { + byte[] foo = Utf8.toBytes("Washington"); + int[] indexes = calculateStringPositions(foo); + assertThat(indexes.length, is(foo.length + 1)); + for (int i = 0; i < indexes.length; i++) { + assertThat(indexes[i], is(i)); + } + } + + @Test + public void highBytes() { + String foo = "\u0128st\u0200e"; + //utf-8 + // 0xC4A8 0x73 0x74 0xC880 0x65 + int[] indexes = calculateBytePositions(foo); + assertThat(indexes.length, is(foo.length() + 1)); + assertThat(indexes[0], is(0)); //128 + assertThat(indexes[1], is(2)); //s + assertThat(indexes[2], is(3)); //t + assertThat(indexes[3], is(4)); //200 + assertThat(indexes[4], is(6)); //e + } + + @Test + public void decodeHighBytes() { + byte[] foo = Utf8.toBytes("\u0128st\u0200e"); + //utf-8 + // 0xC4A8 0x73 0x74 0xC880 0x65 + int[] indexes = calculateStringPositions(foo); + assertThat(indexes.length, is(foo.length + 1)); + assertThat(indexes[0], is(0)); //128 + assertThat(indexes[1], is(0)); //128 + assertThat(indexes[2], is(1)); //s + assertThat(indexes[3], is(2)); //t + assertThat(indexes[4], is(3)); //200 + assertThat(indexes[5], is(3)); //200 + assertThat(indexes[6], is(4)); //e + } + + @Test + public void moreHighBytes() { + String foo = "\u0200\u0201\u0202abc\u0300def\u0301g\u07ff\u0800a\uffffa"; + //utf-8 + //0xC880 0xC881 0xC882 0x61 0x62 0x63 0xCC80 0x64 0x65 0x66 0xCC81 0x67 0xDFBF 0xE0A080 0x61 0xEFBFBF 0x61 + int[] indexes = calculateBytePositions(foo); + assertThat(indexes.length, is(foo.length() + 1)); + assertThat(indexes[0], is(0)); //200 + assertThat(indexes[1], is(2)); //201 + assertThat(indexes[2], is(4)); //202 + assertThat(indexes[3], is(6)); //a + assertThat(indexes[4], is(7)); //b + assertThat(indexes[5], is(8)); //c + assertThat(indexes[6], is(9)); //300 + assertThat(indexes[7], is(11)); //d + assertThat(indexes[8], is(12)); //e + assertThat(indexes[9], is(13)); //f + assertThat(indexes[10], is(14)); //301 + assertThat(indexes[11], is(16)); //g + assertThat(indexes[12], is(17)); //7ff + assertThat(indexes[13], is(19)); //800 + assertThat(indexes[14], is(22)); //a + assertThat(indexes[15], is(23)); //ffff + assertThat(indexes[16], is(26)); //a + } + + @Test + public void decodeMoreHighBytes() { + String foo = "\u0200\u0201\u0202abc\u0300def\u0301g\u07ff\u0800a\uffffa"; + //utf-8 + //0xC880 0xC881 0xC882 0x61 0x62 0x63 0xCC80 0x64 0x65 0x66 0xCC81 0x67 0xDFBF 0xE0A080 0x61 0xEFBFBF 0x61 + int[] indexes = calculateStringPositions(Utf8.toBytes(foo)); + assertThat(indexes.length, is(28)); + assertThat(indexes[0], is(0)); //200 + assertThat(indexes[1], is(0)); //200 + assertThat(indexes[2], is(1)); //201 + assertThat(indexes[3], is(1)); //201 + assertThat(indexes[4], is(2)); //202 + assertThat(indexes[5], is(2)); //202 + assertThat(indexes[6], is(3)); //a + assertThat(indexes[7], is(4)); //b + assertThat(indexes[8], is(5)); //c + assertThat(indexes[9], is(6)); //300 + assertThat(indexes[10], is(6)); //300 + assertThat(indexes[11], is(7)); //d + assertThat(indexes[12], is(8)); //e + assertThat(indexes[13], is(9)); //f + assertThat(indexes[14], is(10)); //301 + assertThat(indexes[15], is(10)); //301 + assertThat(indexes[16], is(11)); //g + assertThat(indexes[17], is(12)); //7ff + assertThat(indexes[18], is(12)); //7ff + assertThat(indexes[19], is(13)); //800 + assertThat(indexes[20], is(13)); //800 + assertThat(indexes[21], is(13)); //800 + assertThat(indexes[22], is(14)); //a + assertThat(indexes[23], is(15)); //ffff + assertThat(indexes[24], is(15)); //ffff + assertThat(indexes[25], is(15)); //ffff + assertThat(indexes[26], is(16)); //a + } + + @Test + public void testOptimisticEncoder() { + for (char i=0; i < 256; i++) { + StringBuilder sb = new StringBuilder(); + for (char c=0; c < i; c++) { + sb.append(c); + } + assertTrue(Arrays.equals(Utf8.toBytesStd(sb.toString()), Utf8.toBytes(sb.toString()))); + } + } + + @Test + public void testLong() + { + for (long l=-0x10000; l < 0x10000; l++) { + assertLongEquals(l); + } + assertLongEquals(Long.MAX_VALUE); + assertLongEquals(Long.MIN_VALUE); + } + + private void assertLongEquals(long l) { + byte [] a = Utf8.toBytes(String.valueOf(l)); + byte [] b = Utf8.toAsciiBytes(l); + if (!Arrays.equals(a, b)) { + assertTrue(Arrays.equals(a, b)); + } + } + + @Test + public void testBoolean() { + assertEquals("true", String.valueOf(true)); + assertEquals("false", String.valueOf(false)); + assertTrue(Arrays.equals(Utf8.toAsciiBytes(true), new Utf8String(String.valueOf(true)).getBytes())); + assertTrue(Arrays.equals(Utf8.toAsciiBytes(false), new Utf8String(String.valueOf(false)).getBytes())); + } + @Test + public void testInt() + { + for (int l=-0x10000; l < 0x10000; l++) { + byte [] a = Utf8.toBytes(String.valueOf(l)); + byte [] b = Utf8.toAsciiBytes(l); + if (!Arrays.equals(a, b)) { + assertTrue(Arrays.equals(a, b)); + } + } + } + @Test + public void testShort() + { + for (short l=-0x1000; l < 0x1000; l++) { + byte [] a = Utf8.toBytes(String.valueOf(l)); + byte [] b = Utf8.toAsciiBytes(l); + if (!Arrays.equals(a, b)) { + assertTrue(Arrays.equals(a, b)); + } + } + } + + @Test + public void surrogatePairs() { + String foo = "a\uD800\uDC00b"; + //unicode + //0x61 0x10000 0x62 + //utf-16 + //0x61 0xD800DC00 0x62 + //utf-8 + //0x61 0xF0908080 0x62 + int[] indexes = calculateBytePositions(foo); + assertThat(indexes.length, is(foo.length() + 1)); + assertThat(indexes[0], is(0)); //a + assertThat(indexes[1], is(1)); //10000 + assertThat(indexes[2], is(1)); //10000, second of surrogate pair + assertThat(indexes[3], is(5)); //b + } + + @Test + public void decodeSurrogatePairs() { + String foo = "a\uD800\uDC00b"; + //unicode + //0x61 0x10000 0x62 + //utf-16 + //0x61 0xD800DC00 0x62 + //utf-8 + //0x61 0xF0908080 0x62 + int[] indexes = calculateStringPositions(Utf8.toBytes(foo)); + assertThat(indexes.length, is(7)); + assertThat(indexes[0], is(0)); //a + assertThat(indexes[1], is(1)); //10000 + assertThat(indexes[2], is(1)); //10000 + assertThat(indexes[3], is(1)); //10000 + assertThat(indexes[4], is(1)); //10000 + assertThat(indexes[5], is(2)); //b + } + + @Test + public void encodeStartEndPositions() { + String foo = "abcde"; + int start = 0; + int length = foo.length(); //5 + int end = start + length; + + int[] indexes = calculateBytePositions(foo); + int byteStart = indexes[start]; + int byteEnd = indexes[end]; + int byteLength = byteEnd - byteStart; + + assertThat(byteStart, equalTo(start)); + assertThat(byteEnd, equalTo(end)); + assertThat(byteLength, equalTo(length)); + } + + @Test + public void encodeStartEndPositionsMultibyteCharsAtEnd() { + String foo = "\u0200abcde\uD800\uDC00"; + int start = 0; + int length = foo.length(); //8 + int end = start + length; + + int[] indexes = calculateBytePositions(foo); + int byteStart = indexes[start]; + int byteEnd = indexes[end]; + int byteLength = byteEnd - byteStart; + + //utf-8 + //0xC880 a b c d e 0xD800DC00 + + assertThat(byteStart, equalTo(start)); + assertThat(byteEnd, equalTo(11)); + assertThat(byteLength, equalTo(11)); + } + + @Test + public void decodeStartEndPositions() { + byte[] foo = Utf8.toBytes("abcde"); + int start = 0; + int length = foo.length; //5 + int end = start + length; + + int[] indexes = calculateStringPositions(foo); + int stringStart = indexes[start]; + int stringEnd = indexes[end]; + int stringLength = stringEnd - stringStart; + + assertThat(stringStart, equalTo(start)); + assertThat(stringEnd, equalTo(end)); + assertThat(stringLength, equalTo(length)); + } + + @Test + public void decodeStartEndPositionsMultibyteCharsAtEnd() { + byte[] foo = Utf8.toBytes("\u0200abcde\uD800\uDC00"); + int start = 0; + int length = foo.length; //11 + int end = start + length; + + int[] indexes = calculateStringPositions(foo); + int stringStart = indexes[start]; + int stringEnd = indexes[end]; + int stringLength = stringEnd - stringStart; + + //utf-8 + //0xC880 a b c d e 0xD800DC00 + + assertThat(stringStart, equalTo(start)); + assertThat(stringEnd, equalTo(8)); + assertThat(stringLength, equalTo(8)); + } + + @Test + public void emptyInputStringResultsInArrayWithSingleZero() { + byte[] empty = new byte[] {}; + int[] indexes = calculateStringPositions(empty); + assertThat(indexes.length, is(1)); + assertThat(indexes[0], is(0)); + } + + @Test + public void testEncoding() { + for (int c : TEST_CODEPOINTS) { + byte[] encoded = Utf8.encode(c); + String testCharacter = makeString(c); + byte[] utf8 = Utf8.toBytes(testCharacter); + assertArrayEquals(utf8, encoded); + } + byte[] stringAsUtf8 = Utf8.toBytes(TEST_STRING); + byte[] handEncoded = new byte[Utf8.byteCount(TEST_STRING)]; + for (int i = 0, j = 0; i < TEST_STRING.length(); i = TEST_STRING.offsetByCodePoints(i, 1)) { + j = Utf8.encode(TEST_STRING.codePointAt(i), handEncoded, j); + } + assertArrayEquals(stringAsUtf8, handEncoded); + } + + @Test + public void testStreamEncoding() throws IOException { + for (int c : TEST_CODEPOINTS) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + Utf8.encode(c, buffer); + byte[] encoded = buffer.toByteArray(); + String testCharacter = makeString(c); + byte[] utf8 = Utf8.toBytes(testCharacter); + assertArrayEquals(utf8, encoded); + } + byte[] stringAsUtf8 = Utf8.toBytes(TEST_STRING); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + for (int i = 0; i < TEST_STRING.length(); i = TEST_STRING.offsetByCodePoints(i, 1)) { + Utf8.encode(TEST_STRING.codePointAt(i), buffer); + } + byte[] handEncoded = buffer.toByteArray(); + assertArrayEquals(stringAsUtf8, handEncoded); + } + + @Test + public void testByteBufferEncoding() { + for (int c : TEST_CODEPOINTS) { + ByteBuffer buffer = ByteBuffer.allocate(4); + Utf8.encode(c, buffer); + byte[] encoded = new byte[buffer.position()]; + buffer.flip(); + for (int i = 0; i < encoded.length; ++i) { + encoded[i] = buffer.get(); + } + String testCharacter = makeString(c); + byte[] utf8 = Utf8.toBytes(testCharacter); + assertArrayEquals(utf8, encoded); + } + byte[] stringAsUtf8 = Utf8.toBytes(TEST_STRING); + ByteBuffer buffer = ByteBuffer.allocate(TEST_STRING.length() * 4); + for (int i = 0; i < TEST_STRING.length(); i = TEST_STRING.offsetByCodePoints(i, 1)) { + Utf8.encode(TEST_STRING.codePointAt(i), buffer); + } + byte[] handEncoded = new byte[buffer.position()]; + buffer.flip(); + for (int i = 0; i < handEncoded.length; ++i) { + handEncoded[i] = buffer.get(); + } + assertArrayEquals(stringAsUtf8, handEncoded); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/text/XMLTestCase.java b/vespajlib/src/test/java/com/yahoo/text/XMLTestCase.java new file mode 100644 index 00000000000..6320efc2f11 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/text/XMLTestCase.java @@ -0,0 +1,115 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.text; + +import org.junit.Test; + +import java.io.StringReader; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + + +/** + * @author Bjorn Borud + * @author Steinar Knutsen + */ +public class XMLTestCase { + + @Test + public void testSimple() { + String s1 = "this is a < test"; + String s2 = "this is a & test"; + String s3 = "this is a \" test"; + String s4 = "this is a <\" test"; + String s5 = "this is a low \u001F test"; + + assertEquals("this is a < test", XML.xmlEscape(s1, true)); + assertEquals("this is a & test", XML.xmlEscape(s2, true)); + + // quotes are only escaped in attributes + // + assertEquals("this is a " test", XML.xmlEscape(s3, true)); + assertEquals("this is a \" test", XML.xmlEscape(s3, false)); + + // quotes are only escaped in attributes. prevent bug + // no. 187006 from happening again! + // + assertEquals("this is a <" test", XML.xmlEscape(s4, true)); + assertEquals("this is a <\" test", XML.xmlEscape(s4, false)); + + assertEquals("this is a low \uFFFD test", XML.xmlEscape(s5, false)); + String s = XML.xmlEscape(s5, false, false); + assertEquals(0x1F, s.toCharArray()[14]); + } + + @Test + public void testInvalidUnicode() { + assertEquals("a\ufffd\ufffdb",XML.xmlEscape("a\uffff\uffffb", false)); + } + + @Test + public void testInvalidUnicodeAlongWithEscaping() { + assertEquals("a\ufffd\ufffdb&",XML.xmlEscape("a\ufffe\uffffb&", false)); + } + + @Test + public void testWhenFirstCharacterMustBeEscaped() { + assertEquals("&co", XML.xmlEscape("&co", false)); + assertEquals("\ufffd is a perfectly fine character;", + XML.xmlEscape("\u0000 is a perfectly fine character;", false)); + } + + @Test + public void testLineNoise() { + assertEquals("\ufffda\ufffd\ufffd\ufffdb&\u380c\ufb06\uD87E\uDDF2\ufffd \ufffd", + XML.xmlEscape("\u0001a\u0000\ufffe\uffffb&\u380c\ufb06\uD87E\uDDF2\uD87E \uD87E", false)); + } + + @Test + public void testZeroLength() { + assertEquals("", XML.xmlEscape("", false)); + } + + @Test + public void testAllEscaped() { + assertEquals("&\ufffd\ufffd", XML.xmlEscape("&\u0000\uffff", false)); + } + + @Test + public void testNoneEscaped() { + assertEquals("a\ud87e\uddf2\u00e5", XML.xmlEscape("a\ud87e\uddf2\u00e5", false)); + } + + @Test + public void testReturnSameIfNoQuoting() { + String a = "abc"; + String b = XML.xmlEscape(a, false); + assertSame("xmlEscape should return its input if no change is necessary.", + a, b); + } + + @Test + public void testValidAttributeNames() { + assertTrue(XML.isName(":A_a\u00C0\u00D8\u00F8\u0370\u037F\u200C\u2070\u2C00\u3001\uF900\uFDF0\uD800\uDC00")); + assertFalse(XML.isName(" ")); + assertFalse(XML.isName(": ")); + assertTrue(XML.isName("sss")); + } + + @Test + public void testExceptionContainingLineNumberAndColumnNumber() { + final String invalidXml = "\n" + + "Jon Bratseth + */ +@SuppressWarnings("deprecation") +public class XMLWriterTestCase { + + private XMLWriter xml; + + @Before + public void setUp() { + xml = new XMLWriter(new StringWriter()); + } + + @After + public void tearDown() { + } + + @Test + public void test3Levels() { + xml.openTag("l1").openTag("l2").openTag("l3").closeTag().closeTag().closeTag(); + assertEquals( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + "\n" + + "\n" + , getWritten()); + } + + private String getWritten() { + xml.close(); + return xml.getWrapped().toString(); + } + + @Test + public void test3LevelsCustomFormatting() { + xml=new XMLWriter(new StringWriter(),1,-1); + xml.openTag("l1").openTag("l2").openTag("l3").closeTag().closeTag().closeTag(); + assertEquals( + "\n" + + " \n" + + " \n" + + " \n" + + "\n" + , getWritten()); + } + + @Test + public void test4LevelsA() { + xml.openTag("l1"); + xml.openTag("l21").closeTag(); + xml.openTag("l22"); + xml.openTag("l31").openTag("l4").closeTag().closeTag(); + xml.openTag("l32").closeTag(); + xml.closeTag(); + xml.closeTag(); + assertEquals( + "\n" + + "\n" + + " \n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n" + + "\n" + , getWritten()); + } + + @Test + public void test4LevelsB() { + xml.openTag("l1"); + xml.openTag("l21"); + xml.openTag("l31").closeTag(); + xml.openTag("l32").openTag("l4").closeTag().closeTag(); + xml.closeTag(); + xml.openTag("l22").closeTag(); + xml.closeTag(); + assertEquals( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n" + + " \n" + + "\n" + + "\n" + , getWritten()); + } + + @Test + public void testEmpty() { + xml.openTag("l1").closeTag(); + assertEquals( + "\n" + , getWritten()); + } + + @Test + public void checkHeader() { + xml.xmlHeader("utf-8"); + assertEquals("\n", getWritten()); + } + + @Test + public void forcedAttribute() { + xml.openTag("a").forceAttribute(new Utf8String("nalle"), "\"").closeTag(); + assertEquals("\n", getWritten()); + } + + @Test + public void attributeString() { + xml.openTag("a").attribute(new Utf8String("nalle"), new Utf8String("b")).closeTag(); + assertEquals("\n", getWritten()); + } + + @Test + public void attributeLong() { + xml.openTag("a").attribute(new Utf8String("nalle"), 5L).closeTag(); + assertEquals("\n", getWritten()); + } + + @Test + public void attributeBoolean() { + xml.openTag("a").attribute(new Utf8String("nalle"), true).closeTag(); + assertEquals("\n", getWritten()); + } + + @Test + public void content() { + xml.content("a\na", false).content("a\na", true); + assertEquals("a\naa\na", getWritten()); + } + + @Test + public void escapedContent() { + xml.escapedContent("a&\na", false).escapedContent("a&\na", true); + assertEquals("a&\naa&\na", getWritten()); + } + + @Test + public void escapedAsciiContent() { + xml.escapedAsciiContent("a&\na", false).escapedAsciiContent("a&\na", true); + assertEquals("a&\naa&\na", getWritten()); + } + + @Test + public void isIn() { + assertFalse(xml.isIn("a")); + xml.openTag("a"); + assertTrue(xml.isIn("a")); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/time/WallClockSourceTestCase.java b/vespajlib/src/test/java/com/yahoo/time/WallClockSourceTestCase.java new file mode 100644 index 00000000000..e26591c9c64 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/time/WallClockSourceTestCase.java @@ -0,0 +1,86 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.time; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +public class WallClockSourceTestCase { + + @Test + public void testSimple() { + long actualBefore = System.currentTimeMillis(); + WallClockSource clock = new WallClockSource(); + long nanos = clock.currentTimeNanos(); + long micros = nanos / 1000; + long millis = micros / 1000; + long actualAfter = System.currentTimeMillis(); + + assertTrue(actualBefore <= millis); + assertTrue(millis <= actualAfter); + } + + @Test + public void testWithAdjust() { + WallClockSource clock = new WallClockSource(); + long diffB = 0; + long diffA = 0; + for (int i = 0; i < 66666; i++) { + long actualB = System.currentTimeMillis(); + clock.adjust(); + long nanos = clock.currentTimeNanos(); + long actualA = System.currentTimeMillis(); + long micros = nanos / 1000; + long millis = micros / 1000; + diffB = Math.max(diffB, actualB - millis); + diffA = Math.max(diffA, millis - actualA); + // System.out.println("adj Timing values, before: "+actualB+" <= guess: "+millis+" <= after: "+actualA); + } + System.out.println("adjust test: biggest difference (beforeTime - guess): "+diffB); + System.out.println("adjust test: biggest difference (guess - afterTime): "+diffA); + assertTrue("actual time before sample must be <= wallclocksource, diff: " + diffB, diffB < 2); + assertTrue("actual time after sample must be >= wallclocksource, diff: " + diffA, diffA < 2); + } + + @Test + public void testNoAdjust() { + WallClockSource clock = new WallClockSource(); + long diffB = 0; + long diffA = 0; + for (int i = 0; i < 66666; i++) { + long actualB = System.currentTimeMillis(); + long nanos = clock.currentTimeNanos(); + long actualA = System.currentTimeMillis(); + long micros = nanos / 1000; + long millis = micros / 1000; + diffB = Math.max(diffB, actualB - millis); + diffA = Math.max(diffA, millis - actualA); + // System.out.println("noadj Timing values, before: "+actualB+" <= guess: "+millis+" <= after: "+actualA); + } + System.out.println("noadjust test: biggest difference (beforeTime - guess): "+diffB); + System.out.println("noadjust test: biggest difference (guess - afterTime): "+diffA); + assertTrue("actual time before sample must be <= wallclocksource, diff: " + diffB, diffB < 3); + assertTrue("actual time after sample must be >= wallclocksource, diff: " + diffA, diffA < 3); + } + + @Test + public void testAutoAdjust() { + WallClockSource clock = WallClockSource.get(); + long diffB = 0; + long diffA = 0; + for (int i = 0; i < 66666; i++) { + long actualB = System.currentTimeMillis(); + long nanos = clock.currentTimeNanos(); + long actualA = System.currentTimeMillis(); + long micros = nanos / 1000; + long millis = micros / 1000; + diffB = Math.max(diffB, actualB - millis); + diffA = Math.max(diffA, millis - actualA); + // System.out.println("noadj Timing values, before: "+actualB+" <= guess: "+millis+" <= after: "+actualA); + } + System.out.println("autoadjust test: biggest difference (beforeTime - guess): "+diffB); + System.out.println("autoadjust test: biggest difference (guess - afterTime): "+diffA); + assertTrue("actual time before sample must be <= wallclocksource, diff: " + diffB, diffB < 3); + assertTrue("actual time after sample must be >= wallclocksource, diff: " + diffA, diffA < 3); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java b/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java new file mode 100644 index 00000000000..d75daa506b4 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/transaction/NestedTransactionTestCase.java @@ -0,0 +1,181 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.transaction; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author bratseth + */ +public class NestedTransactionTestCase { + + @Test + public void testNestedTransaction() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class); + t.add(new TransactionTypeC("C1")); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class); + t.add(new TransactionTypeA("A2")); + t.add(new TransactionTypeC("C2")); + + // Add two tasks to run after commit + MutableInteger tasksRun = new MutableInteger(); + t.onCommitted(() -> { tasksRun.value++; }); + t.onCommitted(() -> { tasksRun.value++; }); + + assertEquals(3, t.transactions().size()); + assertEquals(TransactionTypeA.class, t.transactions().get(0).getClass()); + assertEquals(TransactionTypeB.class, t.transactions().get(1).getClass()); + assertEquals(TransactionTypeC.class, t.transactions().get(2).getClass()); + + assertEquals("A1", ((MockOperation)t.transactions().get(0).operations().get(0)).name); + assertEquals("A2", ((MockOperation)t.transactions().get(0).operations().get(1)).name); + assertEquals("B1", ((MockOperation)t.transactions().get(1).operations().get(0)).name); + assertEquals("C1", ((MockOperation)t.transactions().get(2).operations().get(0)).name); + assertEquals("C2", ((MockOperation)t.transactions().get(2).operations().get(1)).name); + + t.commit(); + assertTrue(((MockTransaction)t.transactions().get(0)).committed); + assertTrue(((MockTransaction)t.transactions().get(1)).committed); + assertTrue(((MockTransaction)t.transactions().get(2)).committed); + assertEquals("After commit tasks are run", 2, tasksRun.value); + } + + @Test + public void testNestedTransactionFailingOnCommit() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeC("C1")); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class, FailAtCommitTransactionType.class); + t.add(new TransactionTypeA("A2")); + t.add(new FailAtCommitTransactionType("Fail"), TransactionTypeC.class); + t.add(new TransactionTypeC("C2")); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class, FailAtCommitTransactionType.class); + + // Add task to run after commit + MutableInteger tasksRun = new MutableInteger(); + t.onCommitted(() -> { + tasksRun.value++; + }); + + assertEquals(4, t.transactions().size()); + assertEquals(TransactionTypeA.class, t.transactions().get(0).getClass()); + assertEquals(TransactionTypeB.class, t.transactions().get(1).getClass()); + assertEquals(FailAtCommitTransactionType.class, t.transactions().get(2).getClass()); + assertEquals(TransactionTypeC.class, t.transactions().get(3).getClass()); + + try { t.commit(); } catch (IllegalStateException expected) { } + assertTrue(((MockTransaction)t.transactions().get(0)).rolledback); + assertTrue(((MockTransaction)t.transactions().get(1)).rolledback); + assertFalse(((MockTransaction) t.transactions().get(2)).committed); + assertEquals("After commit tasks are not run", 0, tasksRun.value); + } + + @Test + public void testConflictingOrdering() { + NestedTransaction t = new NestedTransaction(); + t.add(new TransactionTypeA("A1"), TransactionTypeB.class); + t.add(new TransactionTypeB("B1"), TransactionTypeC.class); + t.add(new TransactionTypeC("C1"), TransactionTypeA.class); + try { + t.commit(); + fail("Expected exception"); + } + catch (IllegalStateException expected) { + } + } + + private static class TransactionTypeA extends MockTransaction { + public TransactionTypeA(String name) { super(name); } + } + + private static class TransactionTypeB extends MockTransaction { + public TransactionTypeB(String name) { super(name); } + } + + private static class TransactionTypeC extends MockTransaction { + public TransactionTypeC(String name) { super(name); } + } + + private static class FailAtCommitTransactionType extends MockTransaction { + public FailAtCommitTransactionType(String name) { super(name); } + @Override + public void commit() { + throw new RuntimeException(); + } + } + + private static class MockTransaction implements Transaction { + + public boolean prepared = false, committed = false, rolledback = false; + private List operations = new ArrayList<>(); + + public MockTransaction(String name) { + operations.add(new MockOperation(name)); + } + + @Override + public Transaction add(Operation operation) { + operations.add(operation); + return this; + } + + @Override + public Transaction add(List operation) { + operations.addAll(operation); + return this; + } + + @Override + public List operations() { + return operations; + } + + @Override + public void prepare() { + prepared = true; + } + + @Override + public void commit() { + if ( ! prepared) + throw new IllegalStateException("Commit before prepare"); + committed = true; + } + + @Override + public void rollbackOrLog() { + if ( ! committed) + throw new IllegalStateException("Rollback before commit"); + rolledback = true; + } + + @Override + public void close() { + } + + } + + private static class MockOperation implements Transaction.Operation { + + public String name; + + public MockOperation(String name) { + this.name = name; + } + + } + + private static class MutableInteger { + + public int value = 0; + + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/BigIdClass.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/BigIdClass.java new file mode 100644 index 00000000000..3c1065369ca --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/BigIdClass.java @@ -0,0 +1,183 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +import java.nio.ByteBuffer; + +public class BigIdClass extends Identifiable +{ + public static final int classId = registerClass(42, BigIdClass.class); + + static public final FieldBase fByte = new FieldBase("myByte"); + static public final FieldBase fShort = new FieldBase("myShort"); + static public final FieldBase fInt = new FieldBase("myInt"); + static public final FieldBase fLong = new FieldBase("myLong"); + static public final FieldBase fFloat = new FieldBase("myFloat"); + static public final FieldBase fDouble = new FieldBase("myDouble"); + static public final FieldBase fArrayOne = new FieldBase("myArrayOne"); + static public final FieldBase fArrayTwo = new FieldBase("myArrayTwo"); + static public final FieldBase fByteBuffer = new FieldBase("myByteBuffer"); + static public final FieldBase fString = new FieldBase("myString"); + static public final FieldBase fAlternate = new FieldBase("myAlternate"); + static public final FieldBase fChildOne = new FieldBase("childOne"); + static public final FieldBase fChildTwo = new FieldBase("childTwo"); + + private byte myByte = 42; + private short myShort = 4242; + private int myInt = 424242; + private long myLong = 9876543210L; + private float myFloat = 42.42f; + private double myDouble = 42.4242e-42; + + private byte[] myArrayOne = new byte[5]; + private byte[] myArrayTwo = new byte[10]; + private ByteBuffer myByteBuffer; + + private String myString = "default-value"; + private String myAlternate = "some \u2603 Utf8"; + + private Identifiable childOne = null; + private Identifiable childTwo = new FooBarIdClass(); + + @Override + public void visitMembers(ObjectVisitor visitor) { + super.visitMembers(visitor); + visitor.visit("", childOne); + visitor.visit("one", childOne); + visitor.visit("two", childTwo); + visitor.visit(null, childTwo); + visitor.visit("myArrayOne", myArrayOne); + } + + public BigIdClass() { + myArrayOne[0] = 1; + myArrayOne[1] = 2; + myArrayOne[2] = 3; + myArrayOne[3] = 4; + myArrayOne[4] = 5; + + myArrayTwo[0] = 6; + myArrayTwo[1] = 7; + myArrayTwo[2] = 8; + + myArrayTwo[9] = 9; + } + + public BigIdClass(int value) { + myByte = (byte)value; + myShort = (short)value; + myInt = value; + myLong = value; + myLong <<= 30; + myLong ^= value; + myFloat = (float)(value + 0.000001*value); + myDouble = 123456.789*value + 0.987654321*value; + myArrayOne[1] = (byte)(value >> 1); + myArrayOne[2] = (byte)(value >> 5); + myArrayOne[3] = (byte)(value >> 9); + + myArrayTwo[3] = (byte)(value >> 2); + myArrayTwo[4] = (byte)(value >> 4); + myArrayTwo[5] = (byte)(value >> 6); + myArrayTwo[6] = (byte)(value >> 8); + + myString = Integer.toString(value); + myAlternate = "a \u2603 " + Integer.toString(value) + " b"; + + childOne = new FooBarIdClass(); + childTwo = null; + } + + @Override + protected int onGetClassId() { + return classId; + } + + @Override + protected void onSerialize(Serializer buf) { + buf.putByte(fByte, myByte); + buf.putShort(fShort, myShort); + buf.putInt(fInt, myInt); + buf.putLong(fLong, myLong); + buf.putFloat(fFloat, myFloat); + buf.putDouble(fDouble, myDouble); + buf.put(fArrayOne, myArrayOne); + buf.put(fArrayTwo, myArrayTwo); + /* buf.put(fByteBuffer, myByteBuffer); */ + buf.put(fString, myString); + putUtf8(buf, myAlternate); + + serializeOptional(buf, childOne); + serializeOptional(buf, childTwo); + } + + @Override + protected void onDeserialize(Deserializer buf) { + + myByte = buf.getByte(fByte); + myShort = buf.getShort(fShort); + myInt = buf.getInt(fInt); + myLong = buf.getLong(fLong); + myFloat = buf.getFloat(fFloat); + myDouble = buf.getDouble(fDouble); + + myArrayOne = buf.getBytes(fArrayOne, 5); + myArrayTwo = buf.getBytes(fArrayTwo, 10); + + myString = buf.getString(fString); + myAlternate = getUtf8(buf); + + childOne = deserializeOptional(buf); + childTwo = deserializeOptional(buf); + } + + public boolean equals(Object other) { + if (super.equals(other) && other instanceof BigIdClass) { + boolean allEq = true; + BigIdClass o = (BigIdClass)other; + if (myByte != o.myByte) { allEq = false; } + if (myShort != o.myShort) { allEq = false; } + if (myInt != o.myInt) { allEq = false; } + if (myLong != o.myLong) { allEq = false; } + if (myFloat != o.myFloat) { allEq = false; } + if (myDouble != o.myDouble) { allEq = false; } + if (! myString.equals(o.myString)) { allEq = false; } + if (! equals(childOne, o.childOne)) { allEq = false; } + if (! equals(childTwo, o.childTwo)) { allEq = false; } + if (childTwo != null && o.childTwo == null) { allEq = false; } + return allEq; + } + return false; + } + +/*** + public boolean diff(BigIdClass o) { + boolean allEq = true; + + if (myByte != o.myByte) { System.out.println("myByte differ: "+myByte+" != "+o.myByte); allEq = false; } + if (myShort != o.myShort) { System.out.println("myShort differ: "+myShort+" != "+o.myShort); allEq = false; } + if (myInt != o.myInt) { System.out.println("myInt differ: "+myInt+" != "+o.myInt); allEq = false; } + if (myLong != o.myLong) { System.out.println("myLong differ: "+myLong+" != "+o.myLong); allEq = false; } + if (myFloat != o.myFloat) { System.out.println("myFloat differ: "+myFloat+" != "+o.myFloat); allEq = false; } + if (myDouble != o.myDouble) { System.out.println("myDouble differ: "+myDouble+" != "+o.myDouble); allEq = false; } + if (! myString.equals(o.myString)) { System.out.println("myString differ: "+myString+" != "+o.myString); allEq = false; } + if (childOne == null && o.childOne != null) { + System.err.println("childOne is null, o.childOne is: "+o.childOne); + allEq = false; + } + if (childOne != null && o.childOne == null) { + System.err.println("o.childOne is null, childOne is: "+childOne); + allEq = false; + } + if (childTwo == null && o.childTwo != null) { + System.err.println("childTwo is null, o.childTwo is: "+o.childTwo); + allEq = false; + } + if (childTwo != null && o.childTwo == null) { + System.err.println("o.childTwo is null, childTwo is: "+childTwo); + allEq = false; + } + return allEq; + } +***/ + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/FieldBaseTestCase.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/FieldBaseTestCase.java new file mode 100644 index 00000000000..d60184c5616 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/FieldBaseTestCase.java @@ -0,0 +1,50 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author arnej27959 + */ +public class FieldBaseTestCase { + + @Test + public void testFieldBaseAPI() { + String s1 = "test"; + FieldBase f1 = new FieldBase(s1); + FieldBase f2 = new FieldBase("tESt"); + FieldBase f3 = new FieldBase("TEST"); + + assertThat(f1.getName(), is(s1)); + assertThat(f1, equalTo(f1)); + assertThat(f1, equalTo(new FieldBase("test"))); + assertThat(f1, equalTo(f2)); + assertThat(f1, equalTo(f3)); + + assertThat(f1.hashCode(), equalTo(s1.hashCode())); + assertThat(f1.hashCode(), equalTo(f2.hashCode())); + assertThat(f1.hashCode(), equalTo(f3.hashCode())); + + assertThat(f1.toString(), equalTo("field test")); + + FieldBase f4 = new FieldBase("foo"); + FieldBase f5 = new FieldBase("bar"); + FieldBase f6 = new FieldBase("qux"); + + assertThat(f1, not(equalTo(f4))); + assertThat(f1, not(equalTo(f5))); + assertThat(f1, not(equalTo(f6))); + + assertThat(f1.hashCode(), not(equalTo(f4.hashCode()))); + assertThat(f1.hashCode(), not(equalTo(f5.hashCode()))); + assertThat(f1.hashCode(), not(equalTo(f6.hashCode()))); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/FooBarIdClass.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/FooBarIdClass.java new file mode 100644 index 00000000000..9aa5716d4ee --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/FooBarIdClass.java @@ -0,0 +1,35 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +import java.util.List; +import java.util.ArrayList; + +public class FooBarIdClass extends Identifiable +{ + public static final int classId = registerClass(17, FooBarIdClass.class); + + private String foo = "def-foo"; + private int bar = 42; + + private List lst = new ArrayList<>(); + + public FooBarIdClass() { + lst.add(17); + lst.add(42); + lst.add(666); + } + + @Override + protected int onGetClassId() { + return classId; + } + + @Override + public void visitMembers(ObjectVisitor visitor) { + super.visitMembers(visitor); + visitor.visit("foo", foo); + visitor.visit("bar", bar); + visitor.visit("lst", lst); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/ObjectDumperTestCase.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/ObjectDumperTestCase.java new file mode 100644 index 00000000000..03a03ba063f --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/ObjectDumperTestCase.java @@ -0,0 +1,161 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +import org.junit.Test; + +import java.nio.ByteBuffer; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author arnej27959 + */ +public class ObjectDumperTestCase { + + @Test + public void testSimple() { + String s1 = "test"; + + ObjectDumper defOD = new ObjectDumper(); + ObjectDumper oneOD = new ObjectDumper(1); + + defOD.visit("s1", s1); + oneOD.visit("s2", s1); + + assertEquals("s1: 'test'\n", defOD.toString()); + assertEquals("s2: 'test'\n", oneOD.toString()); + } + + @Test + public void testBig() { + BigIdClass b = new BigIdClass(); + ObjectDumper oneOD = new ObjectDumper(1); + + oneOD.visit("biggie", b); + + assertThat(oneOD.toString(), equalTo( +"biggie: BigIdClass {\n"+ +" classId: 42\n"+ +" : \n"+ +" one: \n"+ +" two: FooBarIdClass {\n"+ +" classId: 17\n"+ +" foo: 'def-foo'\n"+ +" bar: 42\n"+ +" lst: List {\n"+ +" [0]: 17\n"+ +" [1]: 42\n"+ +" [2]: 666\n"+ +" }\n"+ +" }\n"+ +" FooBarIdClass {\n"+ +" classId: 17\n"+ +" foo: 'def-foo'\n"+ +" bar: 42\n"+ +" lst: List {\n"+ +" [0]: 17\n"+ +" [1]: 42\n"+ +" [2]: 666\n"+ +" }\n"+ +" }\n"+ +" myArrayOne: byte[] {\n"+ +" [0]: 1\n"+ +" [1]: 2\n"+ +" [2]: 3\n"+ +" [3]: 4\n"+ +" [4]: 5\n"+ +" }\n"+ +"}\n")); + + ObjectDumper defOD = new ObjectDumper(); + defOD.visit("", b); + assertThat(b.toString(), equalTo(b.toString())); + } + + @Test + public void testOne() { + SomeIdClass s3 = new SomeIdClass(); + + ObjectDumper defOD = new ObjectDumper(); + ObjectDumper oneOD = new ObjectDumper(1); + + defOD.visit("s3", s3); + oneOD.visit("s4", s3); + + assertEquals("s3: SomeIdClass {\n classId: 1234321\n}\n", defOD.toString()); + assertEquals("s4: SomeIdClass {\n classId: 1234321\n}\n", oneOD.toString()); + } + + @Test + public void testTwo() { + FooBarIdClass s5 = new FooBarIdClass(); + + ObjectDumper defOD = new ObjectDumper(); + ObjectDumper oneOD = new ObjectDumper(1); + + defOD.visit("s5", s5); + oneOD.visit("s6", s5); + + assertThat(defOD.toString(), is("s5: FooBarIdClass {\n"+ + " classId: 17\n"+ + " foo: 'def-foo'\n"+ + " bar: 42\n"+ + " lst: List {\n"+ + " [0]: 17\n"+ + " [1]: 42\n"+ + " [2]: 666\n"+ + " }\n"+ + "}\n")); + assertThat(oneOD.toString(), is("s6: FooBarIdClass {\n"+ + " classId: 17\n"+ + " foo: 'def-foo'\n"+ + " bar: 42\n"+ + " lst: List {\n"+ + " [0]: 17\n"+ + " [1]: 42\n"+ + " [2]: 666\n"+ + " }\n"+ + "}\n")); + + } + + @Test + public void testRegistry() { + assertThat(FooBarIdClass.classId, is(17)); + int x = Identifiable.registerClass(17, FooBarIdClass.class); + assertThat(x, is(17)); + boolean caught = false; + try { + x = Identifiable.registerClass(17, SomeIdClass.class); + } catch (IllegalArgumentException e) { + caught = true; + assertThat(e.getMessage(), is( +"Can not register class 'class com.yahoo.vespa.objects.SomeIdClass' with id 17,"+ +" because it already maps to class 'class com.yahoo.vespa.objects.FooBarIdClass'.")); + } + assertThat(x, is(17)); + assertThat(caught, is(true)); + + Identifiable s7 = Identifiable.createFromId(17); + ObjectDumper defOD = new ObjectDumper(); + defOD.visit("s7", s7); + assertThat(defOD.toString(), is("s7: FooBarIdClass {\n"+ + " classId: 17\n"+ + " foo: 'def-foo'\n"+ + " bar: 42\n"+ + " lst: List {\n"+ + " [0]: 17\n"+ + " [1]: 42\n"+ + " [2]: 666\n"+ + " }\n"+ + "}\n")); + + Identifiable nsi = Identifiable.createFromId(717273); + assertThat(nsi, is((Identifiable)null)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/SerializeTestCase.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/SerializeTestCase.java new file mode 100644 index 00000000000..122cdf24a89 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/SerializeTestCase.java @@ -0,0 +1,143 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +import com.yahoo.io.GrowableByteBuffer; +import java.nio.ByteOrder; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author arnej27959 + */ +public class SerializeTestCase { + + @Test + public void testSimple() { + SomeIdClass s = new SomeIdClass(); + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + s.serialize(buf); + buf.flip(); + s.deserialize(buf); + } + + @Test + public void testOne() { + SomeIdClass s = new SomeIdClass(); + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + s.serializeWithId(buf); + buf.flip(); + Identifiable s2 = Identifiable.create(buf); + assertThat((s2 instanceof SomeIdClass), is(true)); + } + + @Test + public void testUnderflow() { + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + buf.putByte(null, (byte)123); + buf.flip(); + boolean caught = false; + try { + byte[] val = buf.getBytes(null, 2); + } catch (IllegalArgumentException e) { + // System.out.println(e); + caught = true; + } + assertThat(caught, is(true)); + } + + @Test + public void testIdNotFound() { + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + buf.putInt(null, 717273); + buf.flip(); + boolean caught = false; + try { + Identifiable nsi = Identifiable.create(buf); + } catch (IllegalArgumentException e) { + // System.out.println(e); + caught = true; + } + assertThat(caught, is(true)); + } + + @Test + public void testOrdering() { + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + assertThat(buf.order(), is(ByteOrder.BIG_ENDIAN)); + buf.putInt(null, 0x11223344); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(null, 0x55667788); + assertThat(buf.order(), is(ByteOrder.LITTLE_ENDIAN)); + buf.flip(); + assertThat(buf.getByte(null), is((byte)0x11)); + assertThat(buf.getByte(null), is((byte)0x22)); + assertThat(buf.getShort(null), is((short)0x4433)); + buf.order(ByteOrder.BIG_ENDIAN); + assertThat(buf.getByte(null), is((byte)0x88)); + assertThat(buf.getByte(null), is((byte)0x77)); + assertThat(buf.getShort(null), is((short)0x6655)); + } + + @Test + public void testBig() { + BigIdClass dv = new BigIdClass(); + BigIdClass ov = new BigIdClass(6667666); + BigIdClass bv = new BigIdClass(123456789); + + assertThat(BigIdClass.classId, is(42)); + assertThat(dv.getClassId(), is(42)); + assertThat(ov.getClassId(), is(42)); + assertThat(bv.getClassId(), is(42)); + + assertThat(ov.equals(dv), is(false)); + assertThat(dv.equals(bv), is(false)); + assertThat(bv.equals(ov), is(false)); + + BufferSerializer buf = new BufferSerializer(new GrowableByteBuffer()); + ov.serialize(buf); + buf.flip(); + dv.deserialize(buf); + assertThat(ov, equalTo(dv)); + assertThat(dv, equalTo(ov)); + buf = new BufferSerializer(new GrowableByteBuffer()); + bv.serializeWithId(buf); + buf.flip(); + dv.deserializeWithId(buf); + assertThat(bv, equalTo(dv)); + assertThat(dv, equalTo(bv)); + + buf = new BufferSerializer(new GrowableByteBuffer()); + SomeIdClass s = new SomeIdClass(); + assertThat(dv.equals(s), is(false)); + assertThat(ov.equals(s), is(false)); + assertThat(bv.equals(s), is(false)); + assertThat(dv.equals(new Object()), is(false)); + + s.serializeWithId(buf); + buf.flip(); + boolean caught = false; + try { + dv.deserializeWithId(buf); + } catch (IllegalArgumentException ex) { + caught = true; + // System.out.println(ex); + } + assertThat(caught, is(true)); + buf = new BufferSerializer(new GrowableByteBuffer()); + buf.putLong(null, 0x7777777777777777L); + buf.flip(); + caught = false; + try { + dv.deserializeWithId(buf); + } catch (IllegalArgumentException ex) { + caught = true; + // System.out.println(ex); + } + assertThat(caught, is(true)); + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/vespa/objects/SomeIdClass.java b/vespajlib/src/test/java/com/yahoo/vespa/objects/SomeIdClass.java new file mode 100644 index 00000000000..6c24ba1367d --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/vespa/objects/SomeIdClass.java @@ -0,0 +1,13 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.objects; + +public class SomeIdClass extends Identifiable +{ + public static final int classId = registerClass(1234321, SomeIdClass.class); + + @Override + protected int onGetClassId() { + return classId; + } + +} -- cgit v1.2.3