summaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'vespalib/src/tests')
-rw-r--r--vespalib/src/tests/array/.gitignore1
-rw-r--r--vespalib/src/tests/array/CMakeLists.txt7
-rw-r--r--vespalib/src/tests/array/sort_benchmark.cpp184
-rw-r--r--vespalib/src/tests/benchmark/.gitignore4
-rw-r--r--vespalib/src/tests/benchmark/CMakeLists.txt12
-rw-r--r--vespalib/src/tests/benchmark/benchmark.cpp30
-rwxr-xr-xvespalib/src/tests/benchmark/benchmark_test.sh21
-rw-r--r--vespalib/src/tests/benchmark/testbase.cpp279
-rw-r--r--vespalib/src/tests/benchmark/testbase.h168
-rw-r--r--vespalib/src/tests/bits/.gitignore4
-rw-r--r--vespalib/src/tests/bits/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/bits/bits_test.cpp63
-rw-r--r--vespalib/src/tests/clock/.gitignore5
-rw-r--r--vespalib/src/tests/clock/CMakeLists.txt14
-rw-r--r--vespalib/src/tests/clock/clock_benchmark.cpp178
-rw-r--r--vespalib/src/tests/clock/clock_test.cpp29
-rw-r--r--vespalib/src/tests/crc/.gitignore4
-rw-r--r--vespalib/src/tests/crc/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/crc/crc_test.cpp78
-rw-r--r--vespalib/src/tests/directio/.gitignore1
-rw-r--r--vespalib/src/tests/directio/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/directio/directio.cpp57
-rw-r--r--vespalib/src/tests/floatingpointtype/.gitignore4
-rw-r--r--vespalib/src/tests/floatingpointtype/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp73
-rw-r--r--vespalib/src/tests/growablebytebuffer/.gitignore4
-rw-r--r--vespalib/src/tests/growablebytebuffer/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp37
-rw-r--r--vespalib/src/tests/json/.gitignore1
-rw-r--r--vespalib/src/tests/json/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/json/json.cpp470
-rw-r--r--vespalib/src/tests/memorydatastore/.gitignore1
-rw-r--r--vespalib/src/tests/memorydatastore/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/memorydatastore/memorydatastore.cpp72
-rw-r--r--vespalib/src/tests/objects/identifiable/.gitignore5
-rw-r--r--vespalib/src/tests/objects/identifiable/CMakeLists.txt9
-rw-r--r--vespalib/src/tests/objects/identifiable/identifiable_test.cpp338
-rw-r--r--vespalib/src/tests/objects/identifiable/namedobject.cpp19
-rw-r--r--vespalib/src/tests/objects/identifiable/namedobject.h23
-rw-r--r--vespalib/src/tests/objects/objectdump/.gitignore4
-rw-r--r--vespalib/src/tests/objects/objectdump/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/objects/objectdump/objectdump.cpp115
-rw-r--r--vespalib/src/tests/objects/objectselection/.gitignore4
-rw-r--r--vespalib/src/tests/objects/objectselection/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/objects/objectselection/objectselection.cpp94
-rw-r--r--vespalib/src/tests/polymorphicarray/.gitignore1
-rw-r--r--vespalib/src/tests/polymorphicarray/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp123
-rw-r--r--vespalib/src/tests/programoptions/.gitignore4
-rw-r--r--vespalib/src/tests/programoptions/CMakeLists.txt9
-rw-r--r--vespalib/src/tests/programoptions/programoptions_test.cpp361
-rw-r--r--vespalib/src/tests/programoptions/programoptions_testutils.cpp48
-rw-r--r--vespalib/src/tests/programoptions/programoptions_testutils.h32
-rw-r--r--vespalib/src/tests/rusage/.gitignore1
-rw-r--r--vespalib/src/tests/rusage/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/rusage/rusage_test.cpp57
-rw-r--r--vespalib/src/tests/shutdownguard/.gitignore1
-rw-r--r--vespalib/src/tests/shutdownguard/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/shutdownguard/shutdownguard_test.cpp43
-rw-r--r--vespalib/src/tests/stllike/CMakeLists.txt14
-rw-r--r--vespalib/src/tests/stllike/cache_test.cpp139
-rw-r--r--vespalib/src/tests/stllike/lrucache.cpp190
-rw-r--r--vespalib/src/tests/util/process_memory_stats/.gitignore2
-rw-r--r--vespalib/src/tests/util/process_memory_stats/CMakeLists.txt9
-rw-r--r--vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp92
-rwxr-xr-xvespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh6
-rw-r--r--vespalib/src/tests/xmlserializable/.gitignore4
-rw-r--r--vespalib/src/tests/xmlserializable/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/xmlserializable/xmlserializabletest.cpp163
69 files changed, 3815 insertions, 0 deletions
diff --git a/vespalib/src/tests/array/.gitignore b/vespalib/src/tests/array/.gitignore
index 952bc0ecdf2..dd07c7d9777 100644
--- a/vespalib/src/tests/array/.gitignore
+++ b/vespalib/src/tests/array/.gitignore
@@ -1,3 +1,4 @@
/sort_benchmark
/allocinarray_benchmark
vespalib_array_test_app
+vespalib_sort_benchmark_app
diff --git a/vespalib/src/tests/array/CMakeLists.txt b/vespalib/src/tests/array/CMakeLists.txt
index 18cb5c2b95e..fae7b32cd7e 100644
--- a/vespalib/src/tests/array/CMakeLists.txt
+++ b/vespalib/src/tests/array/CMakeLists.txt
@@ -6,3 +6,10 @@ vespa_add_executable(vespalib_array_test_app TEST
vespalib
)
vespa_add_test(NAME vespalib_array_test_app COMMAND vespalib_array_test_app)
+vespa_add_executable(vespalib_sort_benchmark_app
+ SOURCES
+ sort_benchmark.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_sort_benchmark_app COMMAND vespalib_sort_benchmark_app BENCHMARK)
diff --git a/vespalib/src/tests/array/sort_benchmark.cpp b/vespalib/src/tests/array/sort_benchmark.cpp
new file mode 100644
index 00000000000..5d8a1efaa7a
--- /dev/null
+++ b/vespalib/src/tests/array/sort_benchmark.cpp
@@ -0,0 +1,184 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/rusage.h>
+#include <vespa/vespalib/util/array.hpp>
+#include <csignal>
+#include <algorithm>
+
+#include <vespa/log/log.h>
+LOG_SETUP("sort_benchmark");
+
+using namespace vespalib;
+
+class Test : public TestApp
+{
+public:
+private:
+ template<typename T>
+ vespalib::Array<T> create(size_t count);
+ template<typename T>
+ void sortDirect(size_t count);
+ template<typename T>
+ void sortInDirect(size_t count);
+ int Main() override;
+};
+
+template<size_t N>
+class TT
+{
+public:
+ TT(uint64_t v) : _v(v) { }
+ bool operator < (const TT & rhs) const { return _v < rhs._v; }
+private:
+ uint64_t _v;
+ uint8_t _payLoad[N - sizeof(uint64_t)];
+};
+
+template <typename T>
+class I
+{
+public:
+ I(const T * p) : _p(p) { }
+ bool operator < (const I & rhs) const { return *_p < *rhs._p; }
+private:
+ const T * _p;
+};
+
+template<typename T>
+vespalib::Array<T>
+Test::create(size_t count)
+{
+ vespalib::Array<T> v;
+ v.reserve(count);
+ srand(0);
+ for (size_t i(0); i < count; i++) {
+ v.push_back(rand());
+ }
+ return v;
+}
+
+template<typename T>
+void Test::sortDirect(size_t count)
+{
+ vespalib::Array<T> v(create<T>(count));
+ LOG(info, "Running sortDirect with %ld count and payload of %ld", v.size(), sizeof(T));
+ for (size_t j=0; j < 10; j++) {
+ vespalib::Array<T> t(v);
+ std::sort(t.begin(), t.end());
+ }
+}
+
+template<typename T>
+void Test::sortInDirect(size_t count)
+{
+ vespalib::Array<T> k(create<T>(count));
+ LOG(info, "Running sortInDirect with %ld count and payload of %ld", k.size(), sizeof(T));
+ vespalib::Array< I<T> > v;
+ v.reserve(k.size());
+ for (size_t i(0), m(k.size()); i < m; i++) {
+ v.push_back(&k[i]);
+ }
+ for (size_t j=0; j < 10; j++) {
+ vespalib::Array< I<T> > t(v);
+ std::sort(t.begin(), t.end());
+ }
+}
+
+int
+Test::Main()
+{
+ std::string type("sortdirect");
+ size_t count = 1000000;
+ size_t payLoad = 0;
+ if (_argc > 1) {
+ type = _argv[1];
+ }
+ if (_argc > 2) {
+ count = strtol(_argv[2], NULL, 0);
+ }
+ if (_argc > 3) {
+ payLoad = strtol(_argv[3], NULL, 0);
+ }
+ TEST_INIT("sort_benchmark");
+ steady_time start(steady_clock::now());
+ if (payLoad < 8) {
+ typedef TT<8> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 16) {
+ typedef TT<16> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 32) {
+ typedef TT<32> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 64) {
+ typedef TT<64> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 128) {
+ typedef TT<128> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 256) {
+ typedef TT<256> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else if (payLoad < 512) {
+ typedef TT<512> T;
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ } else {
+ typedef TT<1024> T;
+ LOG(info, "Payload %ld is too big to make any sense. Using %ld.", payLoad, sizeof(T));
+ if (type == "sortdirect") {
+ sortDirect<T>(count);
+ } else if (type == "sortindirect") {
+ sortInDirect<T>(count);
+ } else {
+ LOG(warning, "type '%s' is unknown", type.c_str());
+ }
+ }
+ LOG(info, "rusage = {\n%s\n}", vespalib::RUsage::createSelf(start).toString().c_str());
+ ASSERT_EQUAL(0, kill(0, SIGPROF));
+ TEST_DONE();
+}
+
+TEST_APPHOOK(Test);
+
diff --git a/vespalib/src/tests/benchmark/.gitignore b/vespalib/src/tests/benchmark/.gitignore
new file mode 100644
index 00000000000..3280cb17888
--- /dev/null
+++ b/vespalib/src/tests/benchmark/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+benchmark_test
+vespalib_benchmark_test_app
diff --git a/vespalib/src/tests/benchmark/CMakeLists.txt b/vespalib/src/tests/benchmark/CMakeLists.txt
new file mode 100644
index 00000000000..7003a5c4183
--- /dev/null
+++ b/vespalib/src/tests/benchmark/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_benchmark_test_app
+ SOURCES
+ benchmark.cpp
+ testbase.cpp
+ DEPENDS
+ vespalib
+ EXTERNAL_DEPENDS
+ ${VESPA_GLIBC_RT_LIB}
+)
+vespa_add_test(NAME vespalib_benchmark_test NO_VALGRIND COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_test.sh BENCHMARK
+ DEPENDS vespalib_benchmark_test_app)
diff --git a/vespalib/src/tests/benchmark/benchmark.cpp b/vespalib/src/tests/benchmark/benchmark.cpp
new file mode 100644
index 00000000000..f1e69758c8c
--- /dev/null
+++ b/vespalib/src/tests/benchmark/benchmark.cpp
@@ -0,0 +1,30 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/testapp.h>
+#include "testbase.h"
+
+#include <vespa/log/log.h>
+LOG_SETUP("benchmark_test");
+
+using namespace vespalib;
+
+TEST_SETUP(Test)
+
+int
+Test::Main()
+{
+ TEST_INIT("benchmark_test");
+
+ if (_argc > 1) {
+ size_t concurrency(1);
+ size_t numRuns(1000);
+ if (_argc > 2) {
+ numRuns = strtoul(_argv[2], NULL, 0);
+ if (_argc > 3) {
+ concurrency = strtoul(_argv[3], NULL, 0);
+ }
+ }
+ Benchmark::run(_argv[1], numRuns, concurrency);
+ }
+
+ TEST_DONE();
+}
diff --git a/vespalib/src/tests/benchmark/benchmark_test.sh b/vespalib/src/tests/benchmark/benchmark_test.sh
new file mode 100755
index 00000000000..28dc6b518be
--- /dev/null
+++ b/vespalib/src/tests/benchmark/benchmark_test.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+set -e
+TIME=time
+
+$TIME ./vespalib_benchmark_test_app vespalib::ParamByReferenceVectorInt 200000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ParamByValueVectorInt 4000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ParamByReferenceVectorString 30000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ParamByValueVectorString 40 1
+$TIME ./vespalib_benchmark_test_app vespalib::ReturnByReferenceVectorString 10 1
+$TIME ./vespalib_benchmark_test_app vespalib::ReturnByValueVectorString 10 1
+$TIME ./vespalib_benchmark_test_app vespalib::ReturnByValueMultiVectorString 10 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockSystem 1000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockGToD 1000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockGToD 20000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockREALTIME 1000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockMONOTONIC 1000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockMONOTONIC_RAW 1000 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockPROCESS_CPUTIME_ID 2500 1
+$TIME ./vespalib_benchmark_test_app vespalib::ClockTHREAD_CPUTIME_ID 2500 1
+$TIME ./vespalib_benchmark_test_app vespalib::CreateVespalibString 20000 1
diff --git a/vespalib/src/tests/benchmark/testbase.cpp b/vespalib/src/tests/benchmark/testbase.cpp
new file mode 100644
index 00000000000..6b5f8d7d627
--- /dev/null
+++ b/vespalib/src/tests/benchmark/testbase.cpp
@@ -0,0 +1,279 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "testbase.h"
+#include <vespa/vespalib/util/time.h>
+#include <cassert>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".testbase");
+
+using namespace std::chrono;
+
+namespace vespalib {
+
+IMPLEMENT_IDENTIFIABLE_ABSTRACT_NS(vespalib, Benchmark, Identifiable);
+
+IMPLEMENT_BENCHMARK(ParamByReferenceVectorInt, Benchmark);
+IMPLEMENT_BENCHMARK(ParamByValueVectorInt, Benchmark);
+IMPLEMENT_BENCHMARK(ParamByReferenceVectorString, Benchmark);
+IMPLEMENT_BENCHMARK(ParamByValueVectorString, Benchmark);
+IMPLEMENT_BENCHMARK(ReturnByReferenceVectorString, Benchmark);
+IMPLEMENT_BENCHMARK(ReturnByValueVectorString, Benchmark);
+IMPLEMENT_BENCHMARK(ReturnByValueMultiVectorString, Benchmark);
+IMPLEMENT_BENCHMARK(ClockSystem, Benchmark);
+IMPLEMENT_BENCHMARK(ClockREALTIME, Benchmark);
+IMPLEMENT_BENCHMARK(ClockMONOTONIC, Benchmark);
+IMPLEMENT_BENCHMARK(ClockMONOTONIC_RAW, Benchmark);
+IMPLEMENT_BENCHMARK(ClockPROCESS_CPUTIME_ID, Benchmark);
+IMPLEMENT_BENCHMARK(ClockTHREAD_CPUTIME_ID, Benchmark);
+IMPLEMENT_BENCHMARK(CreateVespalibString, Benchmark);
+
+void Benchmark::run(const char *name, size_t numRuns, size_t concurrency)
+{
+ const Identifiable::RuntimeClass * cInfo = Identifiable::classFromName(name);
+ if (cInfo) {
+ std::unique_ptr<Benchmark> test(static_cast<Benchmark *>(cInfo->create()));
+ test->run(numRuns, concurrency);
+ } else {
+ LOG(warning, "Could not find any test with the name %s", name);
+ }
+}
+void Benchmark::run(size_t numRuns, size_t concurrency)
+{
+ LOG(info, "Starting benchmark %s with %ld threads and %ld rep", getClass().name(), concurrency, numRuns);
+ for (size_t i(0); i < numRuns; i++) {
+ onRun();
+ }
+ LOG(info, "Stopping benchmark %s", getClass().name());
+}
+
+size_t ParamByReferenceVectorInt::callByReference(const Vector & values) const
+{
+ return values.size();
+}
+
+size_t ParamByReferenceVectorInt::onRun()
+{
+ Vector values(1000);
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += callByReference(values);
+ }
+ return sum;
+}
+
+size_t ParamByValueVectorInt::callByValue(Vector values) const
+{
+ return values.size();
+}
+
+size_t ParamByValueVectorInt::onRun()
+{
+ Vector values(1000);
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += callByValue(values);
+ }
+ return sum;
+}
+
+size_t ParamByReferenceVectorString::callByReference(const Vector & values) const
+{
+ return values.size();
+}
+
+size_t ParamByReferenceVectorString::onRun()
+{
+ Vector values(1000, "This is a simple string copy test");
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += callByReference(values);
+ }
+ return sum;
+}
+
+size_t ParamByValueVectorString::callByValue(Vector values) const
+{
+ return values.size();
+}
+
+size_t ParamByValueVectorString::onRun()
+{
+ Vector values(1000, "This is a simple string copy test");
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += callByValue(values);
+ }
+ return sum;
+}
+
+const ReturnByReferenceVectorString::Vector & ReturnByReferenceVectorString::returnByReference(Vector & param) const
+{
+ Vector values(1000, "return by value");
+ param.swap(values);
+ return param;
+}
+
+size_t ReturnByReferenceVectorString::onRun()
+{
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ Vector values;
+ sum += returnByReference(values).size();
+ }
+ return sum;
+}
+
+ReturnByValueVectorString::Vector ReturnByValueVectorString::returnByValue() const
+{
+ Vector values;
+ if (rand() % 7) {
+ Vector tmp(1000, "return by value");
+ values.swap(tmp);
+ } else {
+ Vector tmp(1000, "Return by value");
+ values.swap(tmp);
+ }
+ return values;
+}
+
+size_t ReturnByValueVectorString::onRun()
+{
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += returnByValue().size();
+ }
+ return sum;
+}
+
+ReturnByValueMultiVectorString::Vector ReturnByValueMultiVectorString::returnByValue() const
+{
+ if (rand() % 7) {
+ Vector values(1000, "return by value");
+ return values;
+ } else {
+ Vector values(1000, "Return by value");
+ return values;
+ }
+}
+
+size_t ReturnByValueMultiVectorString::onRun()
+{
+ size_t sum(0);
+ for (size_t i=0; i < 1000; i++) {
+ sum += returnByValue().size();
+ }
+ return sum;
+}
+
+size_t ClockSystem::onRun()
+{
+ vespalib::system_time start(vespalib::system_clock::now());
+ vespalib::system_time end(start);
+ for (size_t i=0; i < 1000; i++) {
+ end = vespalib::system_clock::now();
+ }
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(start - end).count();
+}
+
+size_t ClockREALTIME::onRun()
+{
+ struct timespec ts;
+ int foo = clock_gettime(CLOCK_REALTIME, &ts);
+ assert(foo == 0);
+ (void) foo;
+ nanoseconds start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ nanoseconds end(start);
+ for (size_t i=0; i < 1000; i++) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ end = nanoseconds(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ }
+ return count_ns(start - end);
+}
+
+size_t ClockMONOTONIC::onRun()
+{
+ struct timespec ts;
+ int foo = clock_gettime(CLOCK_MONOTONIC, &ts);
+ assert(foo == 0);
+ (void) foo;
+ nanoseconds start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ nanoseconds end(start);
+ for (size_t i=0; i < 1000; i++) {
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ end = nanoseconds(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ }
+ return count_ns(start - end);;
+}
+
+ClockMONOTONIC_RAW::ClockMONOTONIC_RAW()
+{
+#ifndef CLOCK_MONOTONIC_RAW
+ LOG(warning, "CLOCK_MONOTONIC_RAW is not defined, using CLOCK_MONOTONIC instead.");
+#endif
+}
+
+#ifndef CLOCK_MONOTONIC_RAW
+ #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+
+size_t ClockMONOTONIC_RAW::onRun()
+{
+ struct timespec ts;
+ int foo = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ assert(foo == 0);
+ (void) foo;
+ nanoseconds start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ nanoseconds end(start);
+ for (size_t i=0; i < 1000; i++) {
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ end = nanoseconds(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ }
+ return count_ns(start - end);
+}
+
+size_t ClockPROCESS_CPUTIME_ID::onRun()
+{
+ struct timespec ts;
+ int foo = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ assert(foo == 0);
+ (void) foo;
+ nanoseconds start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ nanoseconds end(start);
+ for (size_t i=0; i < 1000; i++) {
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ end =nanoseconds(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ }
+ return count_ns(start - end);
+}
+
+size_t ClockTHREAD_CPUTIME_ID::onRun()
+{
+ struct timespec ts;
+ int foo = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+ assert(foo == 0);
+ (void) foo;
+ nanoseconds start(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ nanoseconds end(start);
+ for (size_t i=0; i < 1000; i++) {
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+ end = nanoseconds(ts.tv_sec*1000L*1000L*1000L + ts.tv_nsec);
+ }
+ return count_ns(start - end);
+}
+
+size_t CreateVespalibString::onRun()
+{
+ size_t sum(0);
+ const char * text1("Dette er en passe");
+ const char * text2(" kort streng som passer paa stacken");
+ char text[100];
+ strcpy(text, text1);
+ strcat(text, text2);
+ for (size_t i=0; i < 1000; i++) {
+ string s(text);
+ sum += s.size();
+ }
+ return sum;
+}
+
+}
diff --git a/vespalib/src/tests/benchmark/testbase.h b/vespalib/src/tests/benchmark/testbase.h
new file mode 100644
index 00000000000..95621f52471
--- /dev/null
+++ b/vespalib/src/tests/benchmark/testbase.h
@@ -0,0 +1,168 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/objects/identifiable.h>
+#include <vector>
+#include <string>
+
+#define BENCHMARK_BASE_CID(n) (0x1000000 + n)
+
+#define CID_vespalib_Benchmark BENCHMARK_BASE_CID(0)
+#define CID_vespalib_ParamByReferenceVectorInt BENCHMARK_BASE_CID(1)
+#define CID_vespalib_ParamByReferenceVectorString BENCHMARK_BASE_CID(2)
+#define CID_vespalib_ParamByValueVectorInt BENCHMARK_BASE_CID(3)
+#define CID_vespalib_ParamByValueVectorString BENCHMARK_BASE_CID(4)
+#define CID_vespalib_ReturnByReferenceVectorString BENCHMARK_BASE_CID(5)
+#define CID_vespalib_ReturnByValueVectorString BENCHMARK_BASE_CID(6)
+#define CID_vespalib_ReturnByValueMultiVectorString BENCHMARK_BASE_CID(7)
+#define CID_vespalib_ClockSystem BENCHMARK_BASE_CID(8)
+#define CID_vespalib_ClockREALTIME BENCHMARK_BASE_CID(10)
+#define CID_vespalib_ClockMONOTONIC BENCHMARK_BASE_CID(11)
+#define CID_vespalib_ClockMONOTONIC_RAW BENCHMARK_BASE_CID(12)
+#define CID_vespalib_ClockPROCESS_CPUTIME_ID BENCHMARK_BASE_CID(13)
+#define CID_vespalib_ClockTHREAD_CPUTIME_ID BENCHMARK_BASE_CID(14)
+#define CID_vespalib_CreateVespalibString BENCHMARK_BASE_CID(15)
+
+#define DECLARE_BENCHMARK(a) DECLARE_IDENTIFIABLE_NS(vespalib, a)
+#define IMPLEMENT_BENCHMARK(a, d) IMPLEMENT_IDENTIFIABLE_NS(vespalib, a, d)
+
+namespace vespalib {
+
+class Benchmark : public Identifiable
+{
+public:
+ DECLARE_IDENTIFIABLE_ABSTRACT_NS(vespalib, Benchmark);
+ void run(size_t numRuns, size_t concurrency=1);
+ static void run(const char * testName, size_t numRuns, size_t concurrency);
+private:
+ virtual size_t onRun() = 0;
+};
+
+class ParamByReferenceVectorInt : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ParamByReferenceVectorInt);
+private:
+ typedef std::vector<int> Vector;
+ size_t callByReference(const Vector & values) const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ParamByValueVectorInt : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ParamByValueVectorInt);
+private:
+ typedef std::vector<int> Vector;
+ size_t callByValue(Vector values) const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ParamByReferenceVectorString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ParamByReferenceVectorString);
+private:
+ typedef std::vector<std::string> Vector;
+ size_t callByReference(const Vector & values) const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ParamByValueVectorString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ParamByValueVectorString);
+private:
+ typedef std::vector<std::string> Vector;
+ size_t callByValue(Vector values) const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ReturnByReferenceVectorString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ReturnByReferenceVectorString);
+private:
+ typedef std::vector<std::string> Vector;
+ const Vector & returnByReference(Vector & values) const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ReturnByValueVectorString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ReturnByValueVectorString);
+private:
+ typedef std::vector<std::string> Vector;
+ Vector returnByValue() const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class ReturnByValueMultiVectorString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ReturnByValueMultiVectorString);
+private:
+ typedef std::vector<std::string> Vector;
+ Vector returnByValue() const __attribute__((noinline));
+ size_t onRun() override;
+};
+
+class CreateVespalibString : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(CreateVespalibString);
+private:
+ size_t onRun() override;
+};
+
+class ClockSystem : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockSystem);
+private:
+ size_t onRun() override;
+};
+
+class ClockREALTIME : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockREALTIME);
+private:
+ size_t onRun() override;
+};
+
+class ClockMONOTONIC : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockMONOTONIC);
+private:
+ size_t onRun() override;
+};
+
+class ClockMONOTONIC_RAW : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockMONOTONIC_RAW);
+ ClockMONOTONIC_RAW();
+private:
+ size_t onRun() override;
+};
+
+class ClockPROCESS_CPUTIME_ID : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockPROCESS_CPUTIME_ID);
+private:
+ size_t onRun() override;
+};
+
+class ClockTHREAD_CPUTIME_ID : public Benchmark
+{
+public:
+ DECLARE_BENCHMARK(ClockTHREAD_CPUTIME_ID);
+private:
+ size_t onRun() override;
+};
+
+}
diff --git a/vespalib/src/tests/bits/.gitignore b/vespalib/src/tests/bits/.gitignore
new file mode 100644
index 00000000000..b5330fc2580
--- /dev/null
+++ b/vespalib/src/tests/bits/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+bits_test
+vespalib_bits_test_app
diff --git a/vespalib/src/tests/bits/CMakeLists.txt b/vespalib/src/tests/bits/CMakeLists.txt
new file mode 100644
index 00000000000..f63196bc489
--- /dev/null
+++ b/vespalib/src/tests/bits/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_bits_test_app TEST
+ SOURCES
+ bits_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_bits_test_app COMMAND vespalib_bits_test_app)
diff --git a/vespalib/src/tests/bits/bits_test.cpp b/vespalib/src/tests/bits/bits_test.cpp
new file mode 100644
index 00000000000..47d691c739d
--- /dev/null
+++ b/vespalib/src/tests/bits/bits_test.cpp
@@ -0,0 +1,63 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/bits.h>
+#include <boost/crc.hpp>
+#include <boost/version.hpp>
+
+#if BOOST_VERSION < 106900
+ #define REFLECT reflect
+#else
+ #define REFLECT reflect_q
+#endif
+
+using namespace vespalib;
+
+class Test : public TestApp
+{
+public:
+ int Main() override;
+ template <typename T>
+ void testFixed(const T * v, size_t sz);
+ void testBuffer();
+};
+
+int
+Test::Main()
+{
+ TEST_INIT("bits_test");
+ uint8_t u8[5] = { 0, 1, 127, 135, 255 };
+ testFixed(u8, sizeof(u8)/sizeof(u8[0]));
+ uint16_t u16[5] = { 0, 1, 127, 135, 255 };
+ testFixed(u16, sizeof(u16)/sizeof(u16[0]));
+ uint32_t u32[5] = { 0, 1, 127, 135, 255 };
+ testFixed(u32, sizeof(u32)/sizeof(u32[0]));
+ uint64_t u64[5] = { 0, 1, 127, 135, 255 };
+ testFixed(u64, sizeof(u64)/sizeof(u64[0]));
+ testBuffer();
+ TEST_DONE();
+}
+
+template <typename T>
+void Test::testFixed(const T * v, size_t sz)
+{
+ EXPECT_EQUAL(0u, Bits::reverse(static_cast<T>(0)));
+ EXPECT_EQUAL(1ul << (sizeof(T)*8 - 1), Bits::reverse(static_cast<T>(1)));
+ EXPECT_EQUAL(static_cast<T>(-1), Bits::reverse(static_cast<T>(-1)));
+ for (size_t i(0); i < sz; i++) {
+ EXPECT_EQUAL(Bits::reverse(v[i]), boost::detail::reflector<sizeof(T)*8>::REFLECT(v[i]));
+ EXPECT_EQUAL(Bits::reverse(Bits::reverse(v[i])), v[i]);
+ }
+}
+
+void Test::testBuffer()
+{
+ uint64_t a(0x0102040810204080ul);
+ uint64_t b(a);
+ Bits::reverse(&a, sizeof(a));
+ EXPECT_EQUAL(a, Bits::reverse(b));
+ Bits::reverse(&a, sizeof(a));
+ EXPECT_EQUAL(a, b);
+}
+
+TEST_APPHOOK(Test)
diff --git a/vespalib/src/tests/clock/.gitignore b/vespalib/src/tests/clock/.gitignore
new file mode 100644
index 00000000000..96861fcc5d3
--- /dev/null
+++ b/vespalib/src/tests/clock/.gitignore
@@ -0,0 +1,5 @@
+.depend
+Makefile
+clock_test
+vespalib_clock_test_app
+vespalib_clock_benchmark_app
diff --git a/vespalib/src/tests/clock/CMakeLists.txt b/vespalib/src/tests/clock/CMakeLists.txt
new file mode 100644
index 00000000000..d3ee3178163
--- /dev/null
+++ b/vespalib/src/tests/clock/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_clock_benchmark_app TEST
+ SOURCES
+ clock_benchmark.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_executable(vespalib_clock_test_app TEST
+ SOURCES
+ clock_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_clock_test_app COMMAND vespalib_clock_test_app)
diff --git a/vespalib/src/tests/clock/clock_benchmark.cpp b/vespalib/src/tests/clock/clock_benchmark.cpp
new file mode 100644
index 00000000000..249add4bc1a
--- /dev/null
+++ b/vespalib/src/tests/clock/clock_benchmark.cpp
@@ -0,0 +1,178 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/util/clock.h>
+#include <vespa/vespalib/util/invokeserviceimpl.h>
+#include <vespa/fastos/thread.h>
+#include <cassert>
+#include <vector>
+#include <atomic>
+#include <cinttypes>
+#include <cstring>
+#include <condition_variable>
+#include <mutex>
+
+using vespalib::Clock;
+using vespalib::steady_time;
+using vespalib::steady_clock;
+using vespalib::duration;
+using vespalib::to_s;
+
+struct UpdateClock {
+ virtual ~UpdateClock() {}
+ virtual void update() = 0;
+};
+
+struct NSValue : public UpdateClock {
+ void update() override { _value = std::chrono::steady_clock::now().time_since_epoch().count(); }
+ int64_t _value;
+};
+
+struct NSVolatile : public UpdateClock {
+ void update() override { _value = std::chrono::steady_clock::now().time_since_epoch().count(); }
+ volatile int64_t _value;
+};
+struct NSAtomic : public UpdateClock {
+ void update() override { _value.store(std::chrono::steady_clock::now().time_since_epoch().count()); }
+ std::atomic<int64_t> _value;
+};
+
+class TestClock : public FastOS_Runnable
+{
+private:
+ int _timePeriodMS;
+ std::mutex _lock;
+ std::condition_variable _cond;
+ UpdateClock &_clock;
+ bool _stop;
+
+ void Run(FastOS_ThreadInterface *thisThread, void *arguments) override;
+
+public:
+ TestClock(UpdateClock & clock, double timePeriod)
+ : _timePeriodMS(static_cast<uint32_t>(timePeriod*1000)),
+ _lock(),
+ _cond(),
+ _clock(clock),
+ _stop(false)
+ { }
+ ~TestClock() {
+ std::lock_guard<std::mutex> guard(_lock);
+ _stop = true;
+ _cond.notify_all();
+ }
+};
+
+void TestClock::Run(FastOS_ThreadInterface *thread, void *)
+{
+ std::unique_lock<std::mutex> guard(_lock);
+ while ( ! thread->GetBreakFlag() && !_stop) {
+ _clock.update();
+ _cond.wait_for(guard, std::chrono::milliseconds(_timePeriodMS));
+ }
+}
+
+struct SamplerBase : public FastOS_Runnable {
+ SamplerBase(uint32_t threadId)
+ : _thread(nullptr),
+ _threadId(threadId),
+ _samples(0),
+ _count()
+ {
+ memset(_count, 0, sizeof(_count));
+ }
+ FastOS_ThreadInterface * _thread;
+ uint32_t _threadId;
+ uint64_t _samples;
+ uint64_t _count[3];
+};
+
+template<typename Func>
+struct Sampler : public SamplerBase {
+ Sampler(Func func, uint32_t threadId)
+ : SamplerBase(threadId),
+ _func(func)
+ { }
+ void Run(FastOS_ThreadInterface *, void *) override {
+ uint64_t samples;
+ steady_time prev = _func();
+ for (samples = 0; (samples < _samples); samples++) {
+ steady_time now = _func();
+ duration diff = now - prev;
+ if (diff > duration::zero()) prev = now;
+ _count[1 + ((diff == duration::zero()) ? 0 : (diff > duration::zero()) ? 1 : -1)]++;
+ }
+
+ }
+ Func _func;
+};
+
+template<typename Func>
+void benchmark(const char * desc, FastOS_ThreadPool & pool, uint64_t samples, uint32_t numThreads, Func func) {
+ std::vector<std::unique_ptr<SamplerBase>> threads;
+ threads.reserve(numThreads);
+ steady_time start = steady_clock::now();
+ for (uint32_t i(0); i < numThreads; i++) {
+ SamplerBase * sampler = new Sampler<Func>(func, i);
+ sampler->_samples = samples;
+ sampler->_thread = pool.NewThread(sampler, nullptr);
+ threads.emplace_back(sampler);
+ }
+ uint64_t count[3];
+ memset(count, 0, sizeof(count));
+ for (const auto & sampler : threads) {
+ sampler->_thread->Join();
+ for (uint32_t i(0); i < 3; i++) {
+ count[i] += sampler->_count[i];
+ }
+ }
+ printf("%s: Took %" PRId64 " clock samples in %2.3f with [%" PRId64 ", %" PRId64 ", %" PRId64 "] counts\n", desc, samples, to_s(steady_clock::now() - start), count[0], count[1], count[2]);
+}
+
+int
+main(int , char *argv[])
+{
+ uint64_t frequency = atoll(argv[1]);
+ uint32_t numThreads = atoi(argv[2]);
+ uint64_t samples = atoll(argv[3]);
+ FastOS_ThreadPool pool(0x10000);
+ NSValue nsValue;
+ NSVolatile nsVolatile;
+ NSAtomic nsAtomic;
+ vespalib::InvokeServiceImpl invoker(vespalib::from_s(1.0/frequency));
+ Clock clock(invoker.nowRef());
+ TestClock nsClock(nsValue, 1.0/frequency);
+ TestClock nsVolatileClock(nsVolatile, 1.0/frequency);
+ TestClock nsAtomicClock(nsAtomic, 1.0/frequency);
+ assert(pool.NewThread(&nsClock, nullptr) != nullptr);
+ assert(pool.NewThread(&nsVolatileClock, nullptr) != nullptr);
+ assert(pool.NewThread(&nsAtomicClock, nullptr) != nullptr);
+
+ benchmark("vespalib::Clock", pool, samples, numThreads, [&clock]() {
+ return clock.getTimeNS();
+ });
+ benchmark("uint64_t", pool, samples, numThreads, [&nsValue]() {
+ return steady_time (duration(nsValue._value));
+ });
+ benchmark("volatile uint64_t", pool, samples, numThreads, [&nsVolatile]() {
+ return steady_time(duration(nsVolatile._value));
+ });
+ benchmark("memory_order_relaxed", pool, samples, numThreads, [&nsAtomic]() {
+ return steady_time(duration(nsAtomic._value.load(std::memory_order_relaxed)));
+ });
+ benchmark("memory_order_consume", pool, samples, numThreads, [&nsAtomic]() {
+ return steady_time(duration(nsAtomic._value.load(std::memory_order_consume)));
+ });
+ benchmark("memory_order_acquire", pool, samples, numThreads, [&nsAtomic]() {
+ return steady_time(duration(nsAtomic._value.load(std::memory_order_acquire)));
+ });
+ benchmark("memory_order_seq_cst", pool, samples, numThreads, [&nsAtomic]() {
+ return steady_time(duration(nsAtomic._value.load(std::memory_order_seq_cst)));
+ });
+
+ benchmark("vespalib::steady_time::now()", pool, samples, numThreads, []() {
+ return steady_clock::now();
+ });
+
+ pool.Close();
+ return 0;
+}
diff --git a/vespalib/src/tests/clock/clock_test.cpp b/vespalib/src/tests/clock/clock_test.cpp
new file mode 100644
index 00000000000..f2de085da84
--- /dev/null
+++ b/vespalib/src/tests/clock/clock_test.cpp
@@ -0,0 +1,29 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/clock.h>
+#include <vespa/vespalib/util/invokeserviceimpl.h>
+#include <thread>
+
+using vespalib::Clock;
+using vespalib::duration;
+using vespalib::steady_time;
+using vespalib::steady_clock;
+
+void waitForMovement(steady_time start, Clock & clock, vespalib::duration timeout) {
+ steady_time startOsClock = steady_clock::now();
+ while ((clock.getTimeNS() <= start) && ((steady_clock::now() - startOsClock) < timeout)) {
+ std::this_thread::sleep_for(1ms);
+ }
+}
+
+TEST("Test that clock is ticking forward") {
+ vespalib::InvokeServiceImpl invoker(50ms);
+ Clock clock(invoker.nowRef());
+ steady_time start = clock.getTimeNS();
+ waitForMovement(start, clock, 10s);
+ steady_time stop = clock.getTimeNS();
+ EXPECT_TRUE(stop > start);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); } \ No newline at end of file
diff --git a/vespalib/src/tests/crc/.gitignore b/vespalib/src/tests/crc/.gitignore
new file mode 100644
index 00000000000..cd64c20e0a4
--- /dev/null
+++ b/vespalib/src/tests/crc/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+crc_test
+vespalib_crc_test_app
diff --git a/vespalib/src/tests/crc/CMakeLists.txt b/vespalib/src/tests/crc/CMakeLists.txt
new file mode 100644
index 00000000000..30adfd131f1
--- /dev/null
+++ b/vespalib/src/tests/crc/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_crc_test_app TEST
+ SOURCES
+ crc_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_crc_test_app COMMAND vespalib_crc_test_app boost)
diff --git a/vespalib/src/tests/crc/crc_test.cpp b/vespalib/src/tests/crc/crc_test.cpp
new file mode 100644
index 00000000000..8afeed487ee
--- /dev/null
+++ b/vespalib/src/tests/crc/crc_test.cpp
@@ -0,0 +1,78 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/crc.h>
+#include <boost/crc.hpp>
+#include <vector>
+
+using namespace vespalib;
+
+class Test : public TestApp
+{
+public:
+ int Main() override;
+ void testCorrectNess();
+ void testBenchmark(bool our, size_t bufSz, size_t numRep);
+};
+
+int
+Test::Main()
+{
+ TEST_INIT("crc_test");
+ testCorrectNess();
+ if (_argc >= 2) {
+ testBenchmark(false, 1024, 1000*1000);
+ } else {
+ testBenchmark(true, 1024, 1000*1000);
+ }
+ TEST_DONE();
+}
+
+void Test::testCorrectNess()
+{
+ const char *a[7] = { "", "a", "ab", "abc", "abcd", "abcde", "doc:crawler:http://www.ntnu.no/" };
+ for (size_t i(0); i < sizeof(a)/sizeof(a[0]); i++) {
+ uint32_t vespaCrc32 = crc_32_type::crc(a[i], strlen(a[i]));
+ boost::crc_32_type calculator;
+ calculator.process_bytes(a[i], strlen(a[i]));
+ EXPECT_EQUAL(vespaCrc32, calculator.checksum());
+ vespalib::crc_32_type calculator2;
+ calculator2.process_bytes(a[i], strlen(a[i]));
+ EXPECT_EQUAL(vespaCrc32, calculator2.checksum());
+ EXPECT_EQUAL(calculator.checksum(), calculator2.checksum());
+ }
+ vespalib::crc_32_type calculator2;
+ boost::crc_32_type calculator;
+ for (size_t i(0); i < sizeof(a)/sizeof(a[0]); i++) {
+ calculator.process_bytes(a[i], strlen(a[i]));
+ calculator2.process_bytes(a[i], strlen(a[i]));
+ EXPECT_EQUAL(calculator.checksum(), calculator2.checksum());
+ }
+ EXPECT_EQUAL(calculator.checksum(), calculator2.checksum());
+}
+
+void Test::testBenchmark(bool our, size_t bufSz, size_t numRep)
+{
+ std::vector<char> a(numRep+bufSz);
+ for(size_t i(0), m(a.size()); i < m; i++) {
+ a[i] = i&0xff;
+ }
+ uint32_t sum(0);
+ if (our) {
+ for (size_t i(0); i < (numRep); i++) {
+ //sum ^= crc_32_type::crc(&a[i], bufSz);
+ vespalib::crc_32_type calculator;
+ calculator.process_bytes(&a[i], bufSz);
+ sum ^=calculator.checksum();
+ }
+ } else {
+ for (size_t i(0); i < (numRep); i++) {
+ boost::crc_32_type calculator;
+ calculator.process_bytes(&a[i], bufSz);
+ sum ^=calculator.checksum();
+ }
+ }
+ printf("sum = %x\n", sum);
+}
+
+TEST_APPHOOK(Test)
diff --git a/vespalib/src/tests/directio/.gitignore b/vespalib/src/tests/directio/.gitignore
new file mode 100644
index 00000000000..ad19022dfc3
--- /dev/null
+++ b/vespalib/src/tests/directio/.gitignore
@@ -0,0 +1 @@
+vespalib_directio_test_app
diff --git a/vespalib/src/tests/directio/CMakeLists.txt b/vespalib/src/tests/directio/CMakeLists.txt
new file mode 100644
index 00000000000..41a8dca85b9
--- /dev/null
+++ b/vespalib/src/tests/directio/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_directio_test_app TEST
+ SOURCES
+ directio.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_directio_test_app COMMAND vespalib_directio_test_app)
diff --git a/vespalib/src/tests/directio/directio.cpp b/vespalib/src/tests/directio/directio.cpp
new file mode 100644
index 00000000000..77374f6f926
--- /dev/null
+++ b/vespalib/src/tests/directio/directio.cpp
@@ -0,0 +1,57 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vespalib/util/size_literals.h>
+#include <vespa/vespalib/data/databuffer.h>
+#include <vespa/fastos/file.h>
+
+using namespace vespalib;
+
+TEST("that DirectIOException propagates the correct information.") {
+ const char *msg("The buffer");
+ DirectIOException e("file.a", msg, 10, 3);
+ EXPECT_EQUAL(10u, e.getLength());
+ EXPECT_EQUAL(3u, e.getOffset());
+ EXPECT_EQUAL(msg, e.getBuffer());
+ EXPECT_EQUAL(0u, string(e.what()).find("DirectIO failed for file 'file.a' buffer="));
+ EXPECT_EQUAL(string("file.a"), e.getFileName());
+}
+
+TEST("that DirectIOException is thrown on unaligned buf.") {
+ FastOS_File f("vespalib_directio_test_app");
+ f.EnableDirectIO();
+ EXPECT_TRUE(f.OpenReadOnly());
+ DataBuffer buf(10000, 4_Ki);
+ bool caught(false);
+ try {
+ f.ReadBuf(buf.getFree()+1, 4_Ki, 0);
+ } catch (const DirectIOException & e) {
+ EXPECT_EQUAL(4_Ki, e.getLength());
+ EXPECT_EQUAL(0u, e.getOffset());
+ EXPECT_EQUAL(buf.getFree()+1, e.getBuffer());
+ EXPECT_EQUAL(string(f.GetFileName()), e.getFileName());
+ caught = true;
+ }
+ EXPECT_TRUE(caught);
+}
+
+TEST("that DirectIOException is thrown on unaligned offset.") {
+ FastOS_File f("vespalib_directio_test_app");
+ f.EnableDirectIO();
+ EXPECT_TRUE(f.OpenReadOnly());
+ DataBuffer buf(10000, 4_Ki);
+ bool caught(false);
+ try {
+ f.ReadBuf(buf.getFree(), 4_Ki, 1);
+ } catch (const DirectIOException & e) {
+ EXPECT_EQUAL(4_Ki, e.getLength());
+ EXPECT_EQUAL(1u, e.getOffset());
+ EXPECT_EQUAL(buf.getFree(), e.getBuffer());
+ EXPECT_EQUAL(string(f.GetFileName()), e.getFileName());
+ caught = true;
+ }
+ EXPECT_TRUE(caught);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/floatingpointtype/.gitignore b/vespalib/src/tests/floatingpointtype/.gitignore
new file mode 100644
index 00000000000..abe8249f33a
--- /dev/null
+++ b/vespalib/src/tests/floatingpointtype/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+floatingpointtype_test
+vespalib_floatingpointtype_test_app
diff --git a/vespalib/src/tests/floatingpointtype/CMakeLists.txt b/vespalib/src/tests/floatingpointtype/CMakeLists.txt
new file mode 100644
index 00000000000..3f0ec8eab69
--- /dev/null
+++ b/vespalib/src/tests/floatingpointtype/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_floatingpointtype_test_app TEST
+ SOURCES
+ floatingpointtypetest.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_floatingpointtype_test_app COMMAND vespalib_floatingpointtype_test_app)
diff --git a/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp b/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp
new file mode 100644
index 00000000000..d26385f23bf
--- /dev/null
+++ b/vespalib/src/tests/floatingpointtype/floatingpointtypetest.cpp
@@ -0,0 +1,73 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/objects/floatingpointtype.h>
+
+class Test : public vespalib::TestApp
+{
+public:
+ void testFloatingPoint();
+ int Main() override;
+};
+
+void
+Test::testFloatingPoint()
+{
+ vespalib::Double d1(1.0);
+ vespalib::Double d2(1.000000000000001);
+ vespalib::Double d3(-1.00000000000001);
+ vespalib::Double d4(4.0);
+
+ EXPECT_TRUE(d1.getValue() != d2.getValue());
+
+ EXPECT_EQUAL(d1, d2);
+ EXPECT_EQUAL(d2, d1);
+
+ EXPECT_NOT_EQUAL(d1, d3);
+ EXPECT_NOT_EQUAL(d1, d4);
+
+ EXPECT_TRUE(d1 - d2 == 0);
+ EXPECT_TRUE(d2 - d1 == 0);
+
+ EXPECT_TRUE(d1 - 1 == 0);
+ EXPECT_TRUE(d1 + 1 != 0);
+
+ EXPECT_TRUE(d2 * d4 == 4.0);
+ EXPECT_TRUE(d2 / d4 == 0.25);
+
+ EXPECT_TRUE(d1 >= 1);
+ EXPECT_TRUE(d1 <= 1);
+ EXPECT_TRUE(!(d1 < 1));
+ EXPECT_TRUE(!(d1 > 1));
+
+ EXPECT_EQUAL(d2 * 4, d4);
+
+ EXPECT_EQUAL(++d4, 5.0);
+ EXPECT_EQUAL(d4++, 5.0);
+ EXPECT_EQUAL(d4, 6.0);
+
+ d4 /= 3;
+ EXPECT_EQUAL(d4, 2.00000000001);
+ d4 *= 2;
+ EXPECT_EQUAL(d4, 4.000000000001);
+
+ EXPECT_EQUAL(--d4, 3.0);
+ EXPECT_EQUAL(d4--, 3.0);
+ EXPECT_EQUAL(d4, 2.0);
+ d4 /= 0.50000000001;
+
+ EXPECT_EQUAL(d4, 4.0);
+
+ EXPECT_TRUE(!(d3 + 1 > 0));
+ EXPECT_TRUE(!(d3 + 1 < 0));
+}
+
+int
+Test::Main()
+{
+ TEST_INIT("floatingpointtype_test");
+ testFloatingPoint();
+ TEST_DONE();
+}
+
+TEST_APPHOOK(Test)
diff --git a/vespalib/src/tests/growablebytebuffer/.gitignore b/vespalib/src/tests/growablebytebuffer/.gitignore
new file mode 100644
index 00000000000..76218df9168
--- /dev/null
+++ b/vespalib/src/tests/growablebytebuffer/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+growablebytebuffer_test
+vespalib_growablebytebuffer_test_app
diff --git a/vespalib/src/tests/growablebytebuffer/CMakeLists.txt b/vespalib/src/tests/growablebytebuffer/CMakeLists.txt
new file mode 100644
index 00000000000..b518206ae56
--- /dev/null
+++ b/vespalib/src/tests/growablebytebuffer/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_growablebytebuffer_test_app TEST
+ SOURCES
+ growablebytebuffer_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_growablebytebuffer_test_app COMMAND vespalib_growablebytebuffer_test_app)
diff --git a/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp b/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp
new file mode 100644
index 00000000000..0a616745023
--- /dev/null
+++ b/vespalib/src/tests/growablebytebuffer/growablebytebuffer_test.cpp
@@ -0,0 +1,37 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/growablebytebuffer.h>
+
+using namespace vespalib;
+
+class Test : public TestApp
+{
+public:
+ void testGrowing();
+ int Main() override;
+};
+
+void
+Test::testGrowing()
+{
+ GrowableByteBuffer buf(10);
+
+ buf.putInt(3);
+ buf.putInt(7);
+ buf.putLong(1234);
+ buf.putDouble(1234);
+ buf.putString("hei der");
+
+ EXPECT_EQUAL(35u, buf.position());
+}
+
+int
+Test::Main()
+{
+ TEST_INIT("guard_test");
+ testGrowing();
+ TEST_DONE();
+}
+
+TEST_APPHOOK(Test)
diff --git a/vespalib/src/tests/json/.gitignore b/vespalib/src/tests/json/.gitignore
new file mode 100644
index 00000000000..9918fbce6e8
--- /dev/null
+++ b/vespalib/src/tests/json/.gitignore
@@ -0,0 +1 @@
+vespalib_json_test_app
diff --git a/vespalib/src/tests/json/CMakeLists.txt b/vespalib/src/tests/json/CMakeLists.txt
new file mode 100644
index 00000000000..0ea216b189b
--- /dev/null
+++ b/vespalib/src/tests/json/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_json_test_app TEST
+ SOURCES
+ json.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_json_test_app COMMAND vespalib_json_test_app boost)
diff --git a/vespalib/src/tests/json/json.cpp b/vespalib/src/tests/json/json.cpp
new file mode 100644
index 00000000000..1a707ae1776
--- /dev/null
+++ b/vespalib/src/tests/json/json.cpp
@@ -0,0 +1,470 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/testapp.h>
+
+#include <vespa/vespalib/util/jsonstream.h>
+#include <vespa/vespalib/util/jsonexception.h>
+#include <vespa/vespalib/stllike/asciistream.h>
+
+using namespace vespalib;
+
+class JSONTest : public vespalib::TestApp
+{
+private:
+ void testJSONWriterValues();
+ void testJSONWriterObject();
+ void testJSONWriterArray();
+ void testJSONWriterComplex();
+ void testJsonStream();
+ void testJsonStreamErrors();
+ void testJsonStreamStateReporting();
+
+public:
+ int Main() override;
+};
+
+void
+JSONTest::testJSONWriterValues()
+{
+ JSONStringer js;
+
+ { // bool
+ js.appendBool(true);
+ EXPECT_EQUAL(js.toString(), "true");
+ js.clear().appendBool(false);
+ EXPECT_EQUAL(js.toString(), "false");
+ }
+ { // double
+ js.clear().appendDouble(1234.5678);
+ EXPECT_EQUAL(js.toString(), "1234.5678");
+ js.clear().appendDouble(-1234.5678);
+ EXPECT_EQUAL(js.toString(), "-1234.5678");
+ js.clear().appendDouble(0.0);
+ EXPECT_EQUAL(js.toString(), "0.0");
+ js.clear().appendDouble(0.00000000012345678912356789123456789);
+ EXPECT_EQUAL(js.toString(), "1.234567891235679e-10");
+ js.clear().appendDouble(std::numeric_limits<double>::max());
+ EXPECT_EQUAL(js.toString(), "1.797693134862316e+308");
+ js.clear().appendDouble(std::numeric_limits<double>::min());
+ EXPECT_EQUAL(js.toString(), "2.225073858507201e-308");
+ js.clear().appendDouble(1.0 * (uint64_t(1) << 53));
+ EXPECT_EQUAL(js.toString(), "9007199254740992.0");
+ js.clear().appendDouble(1000);
+ EXPECT_EQUAL(js.toString(), "1000.0");
+ }
+ { // float
+ js.clear().appendFloat(1234.5678f);
+ EXPECT_EQUAL(js.toString(), "1234.5677");
+ js.clear().appendFloat(-1234.5678f);
+ EXPECT_EQUAL(js.toString(), "-1234.5677");
+ js.clear().appendFloat(0.0f);
+ EXPECT_EQUAL(js.toString(), "0.0");
+ js.clear().appendFloat(0.00000000012345678912356789123456789f);
+ EXPECT_EQUAL(js.toString(), "1.2345679e-10");
+ js.clear().appendFloat(std::numeric_limits<float>::max());
+ EXPECT_EQUAL(js.toString(), "3.4028235e+38");
+ js.clear().appendFloat(std::numeric_limits<float>::min());
+ EXPECT_EQUAL(js.toString(), "1.1754944e-38");
+ js.clear().appendFloat(1.0 * (uint64_t(1) << 24));
+ EXPECT_EQUAL(js.toString(), "16777216.0");
+ js.clear().appendFloat(1000);
+ EXPECT_EQUAL(js.toString(), "1000.0");
+ }
+ { // long
+ js.clear().appendInt64(4294967296ll);
+ EXPECT_EQUAL(js.toString(), "4294967296");
+ js.clear().appendInt64(-4294967296ll);
+ EXPECT_EQUAL(js.toString(), "-4294967296");
+ }
+ { // string
+ js.clear().appendString("string");
+ EXPECT_EQUAL(js.toString(), "\"string\"");
+ }
+ { // NULL
+ js.clear().appendNull();
+ EXPECT_EQUAL(js.toString(), "null");
+ }
+ { // quote
+ js.clear().appendString("x\"y");
+ EXPECT_EQUAL(js.toString(), "\"x\\\"y\"");
+ js.clear().appendString("x\\y");
+ EXPECT_EQUAL(js.toString(), "\"x\\\\y\"");
+ js.clear().appendString("x/y");
+ EXPECT_EQUAL(js.toString(), "\"x/y\"");
+ js.clear().appendString("x\by");
+ EXPECT_EQUAL(js.toString(), "\"x\\by\"");
+ js.clear().appendString("x\fy");
+ EXPECT_EQUAL(js.toString(), "\"x\\fy\"");
+ js.clear().appendString("x\ny");
+ EXPECT_EQUAL(js.toString(), "\"x\\ny\"");
+ js.clear().appendString("x\ry");
+ EXPECT_EQUAL(js.toString(), "\"x\\ry\"");
+ js.clear().appendString("x\ty");
+ EXPECT_EQUAL(js.toString(), "\"x\\ty\"");
+ }
+}
+
+void
+JSONTest::testJSONWriterObject()
+{
+ JSONStringer js;
+
+ { // single pair
+ js.beginObject().appendKey("k1").appendInt64(1l).endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":1}");
+ }
+ { // multiple pairs
+ js.clear().beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":1,\"k2\":2}");
+ }
+ { // object in object
+ js.clear().beginObject().appendKey("k1").beginObject().appendKey("k1.1").appendInt64(11l).endObject().endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11}}");
+ }
+ { // object in object (multiple pairs)
+ js.clear().beginObject().
+ appendKey("k1").
+ beginObject().
+ appendKey("k1.1").appendInt64(11l).
+ appendKey("k1.2").appendInt64(12l).
+ endObject().
+ appendKey("k2").
+ beginObject().
+ appendKey("k2.1").appendInt64(21l).
+ appendKey("k2.2").appendInt64(22l).
+ endObject().
+ endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":11,\"k1.2\":12},\"k2\":{\"k2.1\":21,\"k2.2\":22}}");
+ }
+ { // array in object
+ js.clear().beginObject().appendKey("k1").
+ beginArray().appendInt64(1l).appendInt64(2l).endArray().endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2]}");
+ }
+ { // array in object (multiple pairs)
+ js.clear().beginObject().
+ appendKey("k1").beginArray().appendInt64(1l).appendInt64(2l).endArray().
+ appendKey("k2").beginArray().appendInt64(3l).appendInt64(4l).endArray().
+ endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":[1,2],\"k2\":[3,4]}");
+ }
+}
+
+
+void
+JSONTest::testJSONWriterArray()
+{
+ JSONStringer js;
+
+ { // single element
+ js.beginArray().appendInt64(1l).endArray();
+ EXPECT_EQUAL(js.toString(), "[1]");
+ }
+ { // multiple elements
+ js.clear().beginArray().appendInt64(1l).appendInt64(2l).endArray();
+ EXPECT_EQUAL(js.toString(), "[1,2]");
+ }
+ { // array in array
+ js.clear().beginArray().beginArray().appendInt64(1l).endArray().endArray();
+ EXPECT_EQUAL(js.toString(), "[[1]]");
+ }
+ { // array in array (multiple elements)
+ js.clear().beginArray().
+ beginArray().appendInt64(1l).appendInt64(2l).endArray().
+ beginArray().appendInt64(3l).appendInt64(4l).endArray().
+ endArray();
+ EXPECT_EQUAL(js.toString(), "[[1,2],[3,4]]");
+ }
+ { // object in array
+ js.clear().beginArray().
+ beginObject().appendKey("k1").appendInt64(1l).endObject().
+ endArray();
+ EXPECT_EQUAL(js.toString(), "[{\"k1\":1}]");
+ }
+ { // object in array (multiple elements)
+ js.clear().beginArray().
+ beginObject().appendKey("k1").appendInt64(1l).appendKey("k2").appendInt64(2l).endObject().
+ beginObject().appendKey("k3").appendInt64(3l).appendKey("k4").appendInt64(4l).endObject().
+ endArray();
+ EXPECT_EQUAL(js.toString(), "[{\"k1\":1,\"k2\":2},{\"k3\":3,\"k4\":4}]");
+ }
+}
+
+
+void
+JSONTest::testJSONWriterComplex()
+{
+ JSONStringer js;
+
+ js.beginObject();
+ { // object
+ js.appendKey("k1");
+ js.beginObject();
+ {
+ js.appendKey("k1.1");
+ js.appendInt64(1l);
+ }
+ {
+ js.appendKey("k1.2");
+ js.beginArray();
+ js.appendInt64(2l);
+ js.appendInt64(3l);
+ js.endArray();
+ }
+ js.endObject();
+ }
+ { // object of object
+ js.appendKey("k2");
+ js.beginObject();
+ {
+ js.appendKey("k2.1");
+ js.beginObject();
+ {
+ js.appendKey("k2.1.1");
+ js.appendInt64(4l);
+ }
+ {
+ js.appendKey("k2.1.2");
+ js.beginArray();
+ js.appendInt64(5l);
+ js.appendInt64(6l);
+ js.endArray();
+ }
+ js.endObject();
+ }
+ js.endObject();
+ }
+ { // array of object
+ js.appendKey("k3");
+ js.beginArray();
+ {
+ js.beginObject();
+ {
+ js.appendKey("k3.1");
+ js.appendInt64(7l);
+ }
+ {
+ js.appendKey("k3.2");
+ js.beginArray();
+ js.appendInt64(8l);
+ js.appendInt64(9l);
+ js.endArray();
+ }
+ js.endObject();
+ }
+ {
+ js.beginObject();
+ {
+ js.appendKey("k3.1");
+ js.appendInt64(10l);
+ }
+ {
+ js.appendKey("k3.2");
+ js.beginArray();
+ js.appendInt64(11l);
+ js.appendInt64(12l);
+ js.endArray();
+ }
+ js.endObject();
+ }
+ js.endArray();
+ }
+ js.endObject();
+ EXPECT_EQUAL(js.toString(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":7,\"k3.2\":[8,9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}");
+}
+
+namespace {
+ struct Builder : public vespalib::JsonStreamTypes {
+ void build(JsonStream& s) {
+ s << Object() << "k1" << Object()
+ << "k1.1" << 1
+ << "k1.2" << Array()
+ << 2l << 3ll << End()
+ << End()
+ << "k2" << Object()
+ << "k2.1" << Object()
+ << "k2.1.1" << 4u
+ << "k2.1.2" << Array()
+ << 5ul << 6ull << End()
+ << End()
+ << End()
+ << "k3" << Array()
+ << Object()
+ << "k3.1" << -7
+ << "k3.2" << Array()
+ << -8l << -9ll << End()
+ << End()
+ << Object()
+ << "k3.1" << 10l
+ << "k3.2" << Array()
+ << 11l << 12l << End()
+ << End()
+ << End()
+ << End();
+ }
+ };
+}
+
+void
+JSONTest::testJsonStream()
+{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ Builder b;
+ b.build(stream);
+ stream.finalize();
+ EXPECT_EQUAL(as.str(), "{\"k1\":{\"k1.1\":1,\"k1.2\":[2,3]},\"k2\":{\"k2.1\":{\"k2.1.1\":4,\"k2.1.2\":[5,6]}},\"k3\":[{\"k3.1\":-7,\"k3.2\":[-8,-9]},{\"k3.1\":10,\"k3.2\":[11,12]}]}");
+}
+
+void
+JSONTest::testJsonStreamErrors()
+{
+ using namespace vespalib::jsonstream;
+ // Unsupported object keys
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << Object();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: An object value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << true;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: A bool value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << 13;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: An int64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << uint64_t(13);
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: A uint64_t value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << 0.5;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: A double value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << jsonstream::Array();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: An array value cannot be an object key ({}(ObjectExpectingKey))", e.getReason());
+ }
+ // Invalid points to add End()
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << "foo" << End();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Object got key but not value. Cannot end it now ({foo}(ObjectExpectingValue))", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << End();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: No tag to end. At root ((RootExpectingArrayOrObjectStart))", e.getReason());
+ }
+ // Adding to finalized stream
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << "foo";
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a string value. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << false;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a bool value. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << 13;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a long long value. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << 13u;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add an unsigned long long value. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << 0.2;
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't add a double value. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << Object();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new object. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << jsonstream::Array();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't start a new array. (Finalized)", e.getReason());
+ }
+ try{
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << Object() << End() << End();
+ } catch (vespalib::JsonStreamException& e) {
+ EXPECT_EQUAL("Invalid state on call: Stream already finalized. Can't end it. (Finalized)", e.getReason());
+ }
+}
+
+void
+JSONTest::testJsonStreamStateReporting()
+{
+ using namespace vespalib::jsonstream;
+ vespalib::asciistream as;
+ vespalib::JsonStream stream(as);
+ stream << jsonstream::Array() << 13
+ << "foo"
+ << Object() << "key" << "value" << End()
+ << false
+ << End();
+ EXPECT_EQUAL("Current: Finalized", stream.getJsonStreamState());
+}
+
+int
+JSONTest::Main()
+{
+ TEST_INIT("json_test");
+
+ testJSONWriterValues();
+ testJSONWriterObject();
+ testJSONWriterArray();
+ testJSONWriterComplex();
+ testJsonStream();
+ testJsonStreamErrors();
+ testJsonStreamStateReporting();
+
+ TEST_DONE();
+}
+
+TEST_APPHOOK(JSONTest);
+
diff --git a/vespalib/src/tests/memorydatastore/.gitignore b/vespalib/src/tests/memorydatastore/.gitignore
new file mode 100644
index 00000000000..6809bff5d3d
--- /dev/null
+++ b/vespalib/src/tests/memorydatastore/.gitignore
@@ -0,0 +1 @@
+vespalib_memorydatastore_test_app
diff --git a/vespalib/src/tests/memorydatastore/CMakeLists.txt b/vespalib/src/tests/memorydatastore/CMakeLists.txt
new file mode 100644
index 00000000000..65d9231455a
--- /dev/null
+++ b/vespalib/src/tests/memorydatastore/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_memorydatastore_test_app TEST
+ SOURCES
+ memorydatastore.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_memorydatastore_test_app COMMAND vespalib_memorydatastore_test_app)
diff --git a/vespalib/src/tests/memorydatastore/memorydatastore.cpp b/vespalib/src/tests/memorydatastore/memorydatastore.cpp
new file mode 100644
index 00000000000..1d49b0af91b
--- /dev/null
+++ b/vespalib/src/tests/memorydatastore/memorydatastore.cpp
@@ -0,0 +1,72 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/data/memorydatastore.h>
+#include <vespa/vespalib/stllike/asciistream.h>
+
+using namespace vespalib;
+
+class MemoryDataStoreTest : public vespalib::TestApp
+{
+private:
+ void testMemoryDataStore();
+ void testVariableSizeVector();
+public:
+ int Main() override;
+};
+
+void
+MemoryDataStoreTest::testMemoryDataStore()
+{
+ MemoryDataStore s(alloc::Alloc::alloc(256));
+ std::vector<MemoryDataStore::Reference> v;
+ v.push_back(s.push_back("mumbo", 5));
+ for (size_t i(0); i < 50; i++) {
+ v.push_back(s.push_back("mumbo", 5));
+ EXPECT_EQUAL(static_cast<const char *>(v[i].data()) + 5, v[i+1].data());
+ }
+ v.push_back(s.push_back("mumbo", 5));
+ EXPECT_EQUAL(52ul, v.size());
+ EXPECT_NOT_EQUAL(static_cast<const char *>(v[50].data()) + 5, v[51].data());
+ for (size_t i(0); i < v.size(); i++) {
+ EXPECT_EQUAL(0, memcmp("mumbo", v[i].data(), 5));
+ }
+}
+
+void
+MemoryDataStoreTest::testVariableSizeVector()
+{
+ VariableSizeVector v(20000, 5*20000);
+ for (size_t i(0); i < 10000; i++) {
+ asciistream os;
+ os << i;
+ v.push_back(os.str().data(), os.str().size());
+ }
+ for (size_t i(0); i < v.size(); i++) {
+ asciistream os;
+ os << i;
+ EXPECT_EQUAL(os.str().size(), v[i].size());
+ EXPECT_EQUAL(0, memcmp(os.str().data(), v[i].data(), os.str().size()));
+ }
+ size_t i(0);
+ for (auto it(v.begin()), mt(v.end()); it != mt; it++, i++) {
+ asciistream os;
+ os << i;
+ EXPECT_EQUAL(os.str().size(), it->size());
+ EXPECT_EQUAL(0, memcmp(os.str().data(), (*it).data(), os.str().size()));
+ }
+
+}
+
+int
+MemoryDataStoreTest::Main()
+{
+ TEST_INIT("data_test");
+ testMemoryDataStore();
+ testVariableSizeVector();
+
+ TEST_DONE();
+}
+
+TEST_APPHOOK(MemoryDataStoreTest);
+
diff --git a/vespalib/src/tests/objects/identifiable/.gitignore b/vespalib/src/tests/objects/identifiable/.gitignore
new file mode 100644
index 00000000000..a547ace8ee4
--- /dev/null
+++ b/vespalib/src/tests/objects/identifiable/.gitignore
@@ -0,0 +1,5 @@
+.depend
+Makefile
+asciistream_test
+identifiable_test
+vespalib_identifiable_test_app
diff --git a/vespalib/src/tests/objects/identifiable/CMakeLists.txt b/vespalib/src/tests/objects/identifiable/CMakeLists.txt
new file mode 100644
index 00000000000..c4aefa44350
--- /dev/null
+++ b/vespalib/src/tests/objects/identifiable/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_identifiable_test_app TEST
+ SOURCES
+ identifiable_test.cpp
+ namedobject.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_identifiable_test_app COMMAND vespalib_identifiable_test_app)
diff --git a/vespalib/src/tests/objects/identifiable/identifiable_test.cpp b/vespalib/src/tests/objects/identifiable/identifiable_test.cpp
new file mode 100644
index 00000000000..b3adfbfa9e2
--- /dev/null
+++ b/vespalib/src/tests/objects/identifiable/identifiable_test.cpp
@@ -0,0 +1,338 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "namedobject.h"
+#include <vespa/vespalib/objects/identifiable.hpp>
+#include <vespa/vespalib/objects/nbostream.h>
+#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/vespalib/testkit/testapp.h>
+
+using namespace vespalib;
+
+class IdentifiableTest : public TestApp {
+ void requireThatIdentifiableCastCanCastPointers();
+ void requireThatIdentifiableCastCanCastReferences();
+ void testNamedObject();
+ void testNboStream();
+ template <typename T>
+ void testStream(const T & a);
+ void testNboSerializer();
+ template <typename T>
+ void testSerializer(const T & a);
+public:
+ int Main() override;
+};
+
+#define CID_Abstract 0x700000
+#define CID_A 0x700001
+#define CID_B 0x700002
+#define CID_C 0x700003
+
+class Abstract : public Identifiable
+{
+public:
+ DECLARE_IDENTIFIABLE_ABSTRACT(Abstract);
+ virtual ~Abstract() { }
+ virtual void someAbstractVirtualMethod() = 0;
+};
+
+class A : public Abstract
+{
+public:
+ DECLARE_IDENTIFIABLE(A);
+ A() { }
+ void someAbstractVirtualMethod() override { };
+};
+
+class B : public A
+{
+public:
+ DECLARE_IDENTIFIABLE(B);
+ B() { }
+};
+
+class C : public Identifiable
+{
+private:
+ int _value;
+
+public:
+ DECLARE_IDENTIFIABLE(C);
+ C() : _value(0) {}
+ C(int value) : _value(value) {}
+ C *clone() const { return new C(*this); }
+ virtual int cmp(const Identifiable &rhs) const {
+ int result(cmpClassId(rhs));
+ if (result == 0) {
+ result = _value - static_cast<const C &>(rhs)._value;
+ }
+ return result;
+ }
+};
+
+IMPLEMENT_IDENTIFIABLE_ABSTRACT(Abstract, Identifiable);
+IMPLEMENT_IDENTIFIABLE(A, Abstract);
+IMPLEMENT_IDENTIFIABLE(B, A);
+IMPLEMENT_IDENTIFIABLE(C, Identifiable);
+
+void
+IdentifiableTest::testNamedObject()
+{
+ NamedObject a("first"), b("second");;
+ nbostream os;
+ NBOSerializer nos(os);
+ nos << a << b;
+ EXPECT_EQUAL(27u,os.size());
+ Identifiable::UP o1;
+ o1 = Identifiable::create(nos);
+ EXPECT_EQUAL(14u, os.size());
+ ASSERT_TRUE(o1->inherits(NamedObject::classId));
+ ASSERT_TRUE(o1->getClass().id() == NamedObject::classId);
+ EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "first");
+ o1 = Identifiable::create(nos);
+ EXPECT_EQUAL(0u, os.size());
+ ASSERT_TRUE(o1->inherits(NamedObject::classId));
+ ASSERT_TRUE(o1->getClass().id() == NamedObject::classId);
+ EXPECT_TRUE(static_cast<const NamedObject &>(*o1).getName() == "second");
+}
+
+template <typename T>
+void IdentifiableTest::testStream(const T & a)
+{
+ nbostream s;
+ s << a;
+ T b;
+ s >> b;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQUAL(a, b);
+ EXPECT_EQUAL(nbostream::ok, s.state());
+ EXPECT_TRUE(s.good());
+}
+
+template <typename T>
+void IdentifiableTest::testSerializer(const T & a)
+{
+ nbostream t;
+ NBOSerializer s(t);
+ s << a;
+ T b;
+ s >> b;
+ EXPECT_TRUE(s.getStream().empty());
+ EXPECT_EQUAL(a, b);
+ EXPECT_EQUAL(nbostream::ok, s.getStream().state());
+}
+
+void IdentifiableTest::testNboSerializer()
+{
+ testSerializer(true);
+ testSerializer(false);
+ testSerializer(static_cast<int8_t>('a'));
+ testSerializer(static_cast<uint8_t>(156));
+ testSerializer(static_cast<int16_t>(156));
+ testSerializer(static_cast<int32_t>(156));
+ testSerializer(static_cast<int64_t>(156));
+ testSerializer(static_cast<uint16_t>(156));
+ testSerializer(static_cast<uint32_t>(156));
+ testSerializer(static_cast<uint64_t>(156));
+ testSerializer(static_cast<float>(156));
+ testSerializer(static_cast<double>(156));
+ testSerializer(vespalib::string("abcdefgh"));
+}
+
+void IdentifiableTest::testNboStream()
+{
+ testStream(true);
+ testStream(false);
+ testStream('a');
+ testStream(static_cast<unsigned char>(156));
+ testStream(static_cast<int16_t>(156));
+ testStream(static_cast<int32_t>(156));
+ testStream(static_cast<int64_t>(156));
+ testStream(static_cast<uint16_t>(156));
+ testStream(static_cast<uint32_t>(156));
+ testStream(static_cast<uint64_t>(156));
+ testStream(static_cast<float>(156));
+ testStream(static_cast<double>(156));
+ testStream(std::string("abcdefgh"));
+ testStream(vespalib::string("abcdefgh"));
+ {
+ nbostream s(4);
+ EXPECT_EQUAL(4u, s.capacity());
+ s << "abcdef";
+ EXPECT_EQUAL(nbostream::ok, s.state());
+ EXPECT_EQUAL(10u, s.size());
+ EXPECT_EQUAL(16u, s.capacity());
+ EXPECT_EQUAL(0, strncmp(s.data() + 4, "abcdef", 6));
+ }
+ {
+ nbostream s(8);
+ EXPECT_EQUAL(0u, s.size());
+ EXPECT_EQUAL(8u, s.capacity());
+ const char * prev = s.data();
+ s << "ABCD";
+ EXPECT_EQUAL(8u, s.size());
+ EXPECT_EQUAL(8u, s.capacity());
+ EXPECT_EQUAL(prev, s.data());
+ s << "A long string that will cause resizing";
+ EXPECT_EQUAL(50u, s.size());
+ EXPECT_EQUAL(64u, s.capacity());
+ EXPECT_NOT_EQUAL(prev, s.data());
+ }
+ {
+ nbostream s(8);
+ EXPECT_EQUAL(0u, s.size());
+ EXPECT_EQUAL(8u, s.capacity());
+ const char * prev = s.data();
+ s << "ABCD";
+ EXPECT_EQUAL(8u, s.size());
+ EXPECT_EQUAL(8u, s.capacity());
+ EXPECT_EQUAL(prev, s.data());
+ s.reserve(50);
+ EXPECT_NOT_EQUAL(prev, s.data());
+ EXPECT_EQUAL(8u, s.size());
+ EXPECT_EQUAL(64u, s.capacity());
+ prev = s.data();
+ s << "A long string that will cause resizing";
+ EXPECT_EQUAL(50u, s.size());
+ EXPECT_EQUAL(64u, s.capacity());
+ EXPECT_EQUAL(prev, s.data());
+ }
+ {
+ nbostream s;
+ s << int64_t(9);
+ EXPECT_EQUAL(8u, s.size());
+ EXPECT_EQUAL(0u, s.rp());
+ int64_t a(7), b(1);
+ s >> a;
+ EXPECT_EQUAL(0u, s.size());
+ EXPECT_EQUAL(8u, s.rp());
+ EXPECT_TRUE(s.empty());
+ EXPECT_TRUE(s.good());
+ EXPECT_EQUAL(9, a);
+ try {
+ s >> b;
+ EXPECT_TRUE(false);
+ } catch (const IllegalStateException & e) {
+ EXPECT_EQUAL("Stream failed bufsize(1024), readp(8), writep(8)", e.getMessage());
+ }
+ EXPECT_EQUAL(0u, s.size());
+ EXPECT_EQUAL(8u, s.rp());
+ EXPECT_TRUE(s.empty());
+ EXPECT_FALSE(s.good());
+ EXPECT_EQUAL(1, b);
+ EXPECT_EQUAL(nbostream::eof, s.state());
+ }
+}
+
+int
+IdentifiableTest::Main()
+{
+ TEST_INIT("identifiable_test");
+
+ TEST_DO(requireThatIdentifiableCastCanCastPointers());
+ TEST_DO(requireThatIdentifiableCastCanCastReferences());
+ testNamedObject();
+ testNboStream();
+ testNboSerializer();
+
+ A a;
+ B b;
+
+ const Identifiable::RuntimeClass & rtcA = a.getClass();
+ EXPECT_EQUAL(rtcA.id(), static_cast<unsigned int>(A::classId));
+ EXPECT_EQUAL(strcmp(rtcA.name(), "A"), 0);
+
+ const Identifiable::RuntimeClass & rtcB = b.getClass();
+ EXPECT_EQUAL(rtcB.id(), static_cast<unsigned int>(B::classId));
+ EXPECT_EQUAL(strcmp(rtcB.name(), "B"), 0);
+
+ const Identifiable::RuntimeClass * rt(Identifiable::classFromId(0x1ab76245));
+ ASSERT_TRUE(rt == NULL);
+ rt = Identifiable::classFromId(Abstract::classId);
+ ASSERT_TRUE(rt != NULL);
+ Identifiable * u = rt->create();
+ ASSERT_TRUE(u == NULL);
+ rt = Identifiable::classFromId(A::classId);
+ ASSERT_TRUE(rt != NULL);
+ rt = Identifiable::classFromId(B::classId);
+ ASSERT_TRUE(rt != NULL);
+
+ Identifiable * o = rt->create();
+ ASSERT_TRUE(o != NULL);
+
+ const Identifiable::RuntimeClass & rtc = o->getClass();
+ ASSERT_TRUE(rtc.id() == B::classId);
+ ASSERT_TRUE(strcmp(rtc.name(), "B") == 0);
+ ASSERT_TRUE(o->inherits(B::classId));
+ ASSERT_TRUE(o->inherits(A::classId));
+ ASSERT_TRUE(o->inherits(Abstract::classId));
+ ASSERT_TRUE(o->inherits(Identifiable::classId));
+ ASSERT_TRUE(o->getClass().id() == B::classId);
+ nbostream os;
+ NBOSerializer nos(os);
+ nos << *o;
+ EXPECT_EQUAL(os.size(), 4u);
+ Identifiable::UP o2 = Identifiable::create(nos);
+ EXPECT_TRUE(os.empty());
+ ASSERT_TRUE(o->inherits(B::classId));
+ ASSERT_TRUE(o->getClass().id() == B::classId);
+ delete o;
+
+ rt = Identifiable::classFromName("NotBNorA");
+ ASSERT_TRUE(rt == NULL);
+ rt = Identifiable::classFromName("B");
+ ASSERT_TRUE(rt != NULL);
+ o = rt->create();
+ ASSERT_TRUE(o != NULL);
+ const Identifiable::RuntimeClass & rtc2 = o->getClass();
+ ASSERT_TRUE(rtc2.id() == B::classId);
+ ASSERT_TRUE(strcmp(rtc2.name(), "B") == 0);
+ ASSERT_TRUE(o->inherits(B::classId));
+ ASSERT_TRUE(o->inherits(A::classId));
+ ASSERT_TRUE(o->inherits(Abstract::classId));
+ ASSERT_TRUE(o->inherits(Identifiable::classId));
+ ASSERT_TRUE(o->getClass().id() == B::classId);
+ delete o;
+
+ IdentifiablePtr<C> c0(NULL);
+ IdentifiablePtr<C> c1(new C(10));
+ IdentifiablePtr<C> c2(new C(20));
+
+ EXPECT_LESS(c0.cmp(c1), 0);
+ EXPECT_EQUAL(c0.cmp(c0), 0);
+ EXPECT_GREATER(c1.cmp(c0), 0);
+
+ EXPECT_LESS(c1.cmp(c2), 0);
+ EXPECT_EQUAL(c1.cmp(c1), 0);
+ EXPECT_GREATER(c2.cmp(c1), 0);
+
+ TEST_DONE();
+}
+
+void IdentifiableTest::requireThatIdentifiableCastCanCastPointers() {
+ A a;
+ B b;
+ EXPECT_TRUE(Identifiable::cast<A *>(&a));
+ EXPECT_TRUE(Identifiable::cast<A *>(&b));
+ EXPECT_TRUE(!Identifiable::cast<B *>(&a));
+ EXPECT_TRUE(Identifiable::cast<B *>(&b));
+ EXPECT_TRUE(Identifiable::cast<Abstract *>(&a));
+ EXPECT_TRUE(Identifiable::cast<Abstract *>(&b));
+}
+
+void IdentifiableTest::requireThatIdentifiableCastCanCastReferences() {
+ A a;
+ B b;
+ try {
+ // These should not throw.
+ Identifiable::cast<A &>(a);
+ Identifiable::cast<A &>(b);
+ Identifiable::cast<B &>(b);
+ Identifiable::cast<Abstract &>(a);
+ Identifiable::cast<Abstract &>(b);
+ } catch (std::bad_cast &e) {
+ TEST_FATAL(e.what());
+ }
+ EXPECT_EXCEPTION(Identifiable::cast<B &>(a), std::bad_cast, "bad_cast");
+}
+
+TEST_APPHOOK(IdentifiableTest)
diff --git a/vespalib/src/tests/objects/identifiable/namedobject.cpp b/vespalib/src/tests/objects/identifiable/namedobject.cpp
new file mode 100644
index 00000000000..3e8d3291177
--- /dev/null
+++ b/vespalib/src/tests/objects/identifiable/namedobject.cpp
@@ -0,0 +1,19 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include "namedobject.h"
+
+namespace vespalib {
+
+IMPLEMENT_IDENTIFIABLE_NS(vespalib, NamedObject, Identifiable);
+
+
+Serializer & NamedObject::onSerialize(Serializer & os) const
+{
+ return os.put(_name);
+}
+
+Deserializer & NamedObject::onDeserialize(Deserializer & is)
+{
+ return is.get(_name);
+}
+
+}
diff --git a/vespalib/src/tests/objects/identifiable/namedobject.h b/vespalib/src/tests/objects/identifiable/namedobject.h
new file mode 100644
index 00000000000..784715a66f6
--- /dev/null
+++ b/vespalib/src/tests/objects/identifiable/namedobject.h
@@ -0,0 +1,23 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/objects/identifiable.h>
+#include <string>
+
+namespace vespalib
+{
+
+class NamedObject : public Identifiable
+{
+public:
+ DECLARE_IDENTIFIABLE_NS(vespalib, NamedObject);
+ DECLARE_NBO_SERIALIZE;
+ NamedObject() : _name() { }
+ NamedObject(const string & name) : _name(name) { }
+ const string & getName() const { return _name; }
+private:
+ string _name;
+};
+
+}
+
diff --git a/vespalib/src/tests/objects/objectdump/.gitignore b/vespalib/src/tests/objects/objectdump/.gitignore
new file mode 100644
index 00000000000..6ddd515391d
--- /dev/null
+++ b/vespalib/src/tests/objects/objectdump/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+objectdump_test
+vespalib_objectdump_test_app
diff --git a/vespalib/src/tests/objects/objectdump/CMakeLists.txt b/vespalib/src/tests/objects/objectdump/CMakeLists.txt
new file mode 100644
index 00000000000..67395998b39
--- /dev/null
+++ b/vespalib/src/tests/objects/objectdump/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_objectdump_test_app TEST
+ SOURCES
+ objectdump.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_objectdump_test_app COMMAND vespalib_objectdump_test_app)
diff --git a/vespalib/src/tests/objects/objectdump/objectdump.cpp b/vespalib/src/tests/objects/objectdump/objectdump.cpp
new file mode 100644
index 00000000000..812b1e79e17
--- /dev/null
+++ b/vespalib/src/tests/objects/objectdump/objectdump.cpp
@@ -0,0 +1,115 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/objects/identifiable.h>
+#include <vespa/vespalib/objects/visit.hpp>
+
+#define CID_Base 10000000
+#define CID_Foo 10000001
+#define CID_Bar 10000002
+#define CID_Baz 10000003
+
+using vespalib::ObjectVisitor;
+using vespalib::IdentifiablePtr;
+
+struct Base : public vespalib::Identifiable
+{
+ DECLARE_IDENTIFIABLE(Base);
+ virtual Base *clone() const { return new Base(*this); }
+};
+IMPLEMENT_IDENTIFIABLE(Base, vespalib::Identifiable);
+
+struct Baz : public Base
+{
+ DECLARE_IDENTIFIABLE(Baz);
+ Baz *clone() const override { return new Baz(*this); }
+};
+IMPLEMENT_IDENTIFIABLE(Baz, Base);
+
+struct Bar : public Base
+{
+ DECLARE_IDENTIFIABLE(Bar);
+ bool _bool;
+ int8_t _int8;
+ uint8_t _uint8;
+ int16_t _int16;
+ uint16_t _uint16;
+ int32_t _int32;
+ uint32_t _uint32;
+ int64_t _int64;
+ uint64_t _uint64;
+ float _float;
+ double _double;
+ vespalib::string _string;
+ Bar() : _bool(true), _int8(-1), _uint8(1), _int16(-2), _uint16(2),
+ _int32(-4), _uint32(4), _int64(-8), _uint64(8),
+ _float(2.5), _double(2.75), _string("bla bla") {}
+
+ Bar *clone() const override { return new Bar(*this); }
+
+ void visitMembers(ObjectVisitor &v) const override {
+ visit(v, "_bool", _bool);
+ visit(v, "_int8", _int8);
+ visit(v, "_uint8", _uint8);
+ visit(v, "_int16", _int16);
+ visit(v, "_uint16", _uint16);
+ visit(v, "_int32", _int32);
+ visit(v, "_uint32", _uint32);
+ visit(v, "_int64", _int64);
+ visit(v, "_uint64", _uint64);
+ visit(v, "_float", _float);
+ visit(v, "_double", _double);
+ visit(v, "_string", _string);
+ visit(v, "info", "a dummy string");
+ visit(v, "(const char*)0", (const char*)0);
+ }
+};
+IMPLEMENT_IDENTIFIABLE(Bar, Base);
+
+struct Foo : public Base
+{
+ DECLARE_IDENTIFIABLE(Foo);
+ Bar _objMember;
+ Baz _objMember2;
+ Baz *_objPtr;
+ std::vector<Bar> _list;
+ std::vector<IdentifiablePtr<Base> > _list2;
+
+ Foo();
+ ~Foo();
+ Foo *clone() const override { return new Foo(*this); }
+ void visitMembers(ObjectVisitor &v) const override;
+};
+
+Foo::~Foo() { }
+Foo::Foo()
+ : _objMember(), _objMember2(), _objPtr(0), _list(), _list2()
+{
+ _list.push_back(Bar());
+ _list.push_back(Bar());
+ _list.push_back(Bar());
+ _list2.push_back(Bar());
+ _list2.push_back(Baz());
+}
+
+void
+Foo::visitMembers(ObjectVisitor &v) const {
+ visit(v, "_objMember", _objMember);
+ visit(v, "_objMember2", _objMember2);
+ visit(v, "_objPtr", _objPtr);
+ visit(v, "_list", _list);
+ visit(v, "_list2", _list2);
+}
+
+IMPLEMENT_IDENTIFIABLE(Foo, Base);
+
+TEST_SETUP(Test);
+
+int
+Test::Main()
+{
+ TEST_INIT("objectdump_test");
+ Foo foo;
+ fprintf(stderr, "%s", foo.asString().c_str());
+ TEST_DONE();
+}
diff --git a/vespalib/src/tests/objects/objectselection/.gitignore b/vespalib/src/tests/objects/objectselection/.gitignore
new file mode 100644
index 00000000000..f6aefd07270
--- /dev/null
+++ b/vespalib/src/tests/objects/objectselection/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+objectselection_test
+vespalib_objectselection_test_app
diff --git a/vespalib/src/tests/objects/objectselection/CMakeLists.txt b/vespalib/src/tests/objects/objectselection/CMakeLists.txt
new file mode 100644
index 00000000000..94f43078820
--- /dev/null
+++ b/vespalib/src/tests/objects/objectselection/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_objectselection_test_app TEST
+ SOURCES
+ objectselection.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_objectselection_test_app COMMAND vespalib_objectselection_test_app)
diff --git a/vespalib/src/tests/objects/objectselection/objectselection.cpp b/vespalib/src/tests/objects/objectselection/objectselection.cpp
new file mode 100644
index 00000000000..aa9c841f2dc
--- /dev/null
+++ b/vespalib/src/tests/objects/objectselection/objectselection.cpp
@@ -0,0 +1,94 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/objects/identifiable.hpp>
+#include <vespa/vespalib/objects/objectpredicate.h>
+#include <vespa/vespalib/objects/objectoperation.h>
+
+using namespace vespalib;
+
+#define CID_Foo 60000005
+#define CID_Bar 60000010
+
+struct Foo : public Identifiable
+{
+ typedef IdentifiablePtr<Foo> CP;
+ std::vector<CP> nodes;
+
+ DECLARE_IDENTIFIABLE(Foo);
+ virtual Foo *clone() const { return new Foo(*this); }
+ void selectMembers(const ObjectPredicate &p, ObjectOperation &o) override {
+ for (uint32_t i = 0; i < nodes.size(); ++i) {
+ nodes[i]->select(p, o);
+ }
+ }
+};
+IMPLEMENT_IDENTIFIABLE(Foo, Identifiable);
+
+struct Bar : public Foo
+{
+ int value;
+
+ DECLARE_IDENTIFIABLE(Bar);
+ Bar() : value(0) {}
+ Bar(int v) { value = v; }
+ Bar *clone() const override { return new Bar(*this); }
+};
+IMPLEMENT_IDENTIFIABLE(Bar, Identifiable);
+
+struct ObjectType : public ObjectPredicate
+{
+ uint32_t cid;
+ ObjectType(uint32_t id) : cid(id) {}
+ bool check(const Identifiable &obj) const override {
+ return (obj.getClass().id() == cid);
+ }
+};
+
+struct ObjectCollect : public ObjectOperation
+{
+ std::vector<Identifiable*> nodes;
+ ~ObjectCollect() override;
+ void execute(Identifiable &obj) override {
+ nodes.push_back(&obj);
+ }
+};
+
+ObjectCollect::~ObjectCollect() = default;
+
+TEST_SETUP(Test);
+
+int
+Test::Main()
+{
+ TEST_INIT("objectselection_test");
+ {
+ Foo f1;
+ Foo f2;
+ Foo f3;
+ Bar b1(1);
+ Bar b2(2);
+ Bar b3(3);
+ Bar b4(4);
+ f2.nodes.push_back(b1);
+ f2.nodes.push_back(b2);
+ f3.nodes.push_back(b3);
+ f3.nodes.push_back(b4);
+ f1.nodes.push_back(f2);
+ f1.nodes.push_back(f3);
+
+ ObjectType predicate(Bar::classId);
+ ObjectCollect operation;
+ f1.select(predicate, operation);
+ ASSERT_TRUE(operation.nodes.size() == 4);
+ ASSERT_TRUE(operation.nodes[0]->getClass().id() == Bar::classId);
+ ASSERT_TRUE(operation.nodes[1]->getClass().id() == Bar::classId);
+ ASSERT_TRUE(operation.nodes[2]->getClass().id() == Bar::classId);
+ ASSERT_TRUE(operation.nodes[3]->getClass().id() == Bar::classId);
+ ASSERT_TRUE(((Bar*)operation.nodes[0])->value == 1);
+ ASSERT_TRUE(((Bar*)operation.nodes[1])->value == 2);
+ ASSERT_TRUE(((Bar*)operation.nodes[2])->value == 3);
+ ASSERT_TRUE(((Bar*)operation.nodes[3])->value == 4);
+ }
+ TEST_DONE();
+}
diff --git a/vespalib/src/tests/polymorphicarray/.gitignore b/vespalib/src/tests/polymorphicarray/.gitignore
new file mode 100644
index 00000000000..e0decc87f2c
--- /dev/null
+++ b/vespalib/src/tests/polymorphicarray/.gitignore
@@ -0,0 +1 @@
+vespalib_polymorphicarray_test_app
diff --git a/vespalib/src/tests/polymorphicarray/CMakeLists.txt b/vespalib/src/tests/polymorphicarray/CMakeLists.txt
new file mode 100644
index 00000000000..14edfbec4b4
--- /dev/null
+++ b/vespalib/src/tests/polymorphicarray/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_polymorphicarray_test_app TEST
+ SOURCES
+ polymorphicarray_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_polymorphicarray_test_app COMMAND vespalib_polymorphicarray_test_app)
diff --git a/vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp b/vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp
new file mode 100644
index 00000000000..d4ec8f3ed7c
--- /dev/null
+++ b/vespalib/src/tests/polymorphicarray/polymorphicarray_test.cpp
@@ -0,0 +1,123 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/util/polymorphicarrays.h>
+
+using namespace vespalib;
+
+class A {
+public:
+ virtual ~A() = default;
+ virtual void assign(const A & rhs) { (void) rhs; assert(false); } // Required by the primitive array.
+ virtual A * clone() const { assert(false); return nullptr; } // Required for the complex array.
+
+ // For testing
+ virtual bool operator == (const A & rhs) const = 0;
+ virtual void print(std::ostream & os) const = 0;
+};
+
+class Primitive : public A
+{
+public:
+ Primitive(size_t v=11) noexcept : _v(v) { }
+ size_t value() const { return _v; }
+ bool operator == (const A & rhs) const override {
+ return dynamic_cast<const Primitive &>(rhs).value() == value();
+ }
+ void assign(const A & rhs) override {
+ _v = dynamic_cast<const Primitive &>(rhs).value();
+ }
+ void print(std::ostream & os) const override {
+ os << _v;
+ }
+private:
+ size_t _v;
+};
+
+
+class Complex : public A
+{
+public:
+ Complex(size_t v=11) noexcept : _v(v) { }
+ size_t value() const { return _v; }
+ bool operator == (const A & rhs) const override {
+ return dynamic_cast<const Complex &>(rhs).value() == value();
+ }
+ Complex * clone() const override {
+ return new Complex(_v);
+ }
+ void print(std::ostream & os) const override {
+ os << _v;
+ }
+private:
+ size_t _v;
+};
+
+std::ostream & operator << (std::ostream & os, const A & v) {
+ v.print(os);
+ return os;
+}
+
+
+template <typename T>
+void
+verifyArray(IArrayT<A> & array)
+{
+ EXPECT_EQUAL(0u, array.size());
+ for (size_t i(0); i < 10; i++) {
+ array.push_back(T(i));
+ }
+ EXPECT_EQUAL(10u, array.size());
+ for (size_t i(0); i < 10; i++) {
+ EXPECT_EQUAL(T(i), array[i]);
+ }
+ IArrayT<A>::UP copy(array.clone());
+ array.clear();
+ EXPECT_EQUAL(0u, array.size());
+
+ for (size_t i(0); i < copy->size(); i++) {
+ array.push_back((*copy)[i]);
+ }
+
+ array.resize(19);
+ EXPECT_EQUAL(19u, array.size());
+ for (size_t i(0); i < 10; i++) {
+ EXPECT_EQUAL(T(i), array[i]);
+ }
+ for (size_t i(10); i < array.size(); i++) {
+ EXPECT_EQUAL(T(11), array[i]);
+ }
+ array.resize(13);
+ EXPECT_EQUAL(13u, array.size());
+ for (size_t i(0); i < 10; i++) {
+ EXPECT_EQUAL(T(i), array[i]);
+ }
+ for (size_t i(10); i < array.size(); i++) {
+ EXPECT_EQUAL(T(11), array[i]);
+ }
+ dynamic_cast<T &>(array[1]) = T(17);
+ EXPECT_EQUAL(T(0), array[0]);
+ EXPECT_EQUAL(T(17), array[1]);
+ EXPECT_EQUAL(T(2), array[2]);
+}
+
+
+TEST("require that primitive arrays conforms") {
+ PrimitiveArrayT<Primitive, A> a;
+ verifyArray<Primitive>(a);
+ EXPECT_EQUAL(7u, a[7].value());
+}
+
+class Factory : public ComplexArrayT<A>::Factory
+{
+public:
+ A * create() override { return new Complex(); }
+ Factory * clone() const override { return new Factory(*this); }
+};
+
+TEST("require that complex arrays conforms") {
+ ComplexArrayT<A> a(Factory::UP(new Factory()));
+ verifyArray<Complex>(a);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/programoptions/.gitignore b/vespalib/src/tests/programoptions/.gitignore
new file mode 100644
index 00000000000..f083a1e093d
--- /dev/null
+++ b/vespalib/src/tests/programoptions/.gitignore
@@ -0,0 +1,4 @@
+.depend
+Makefile
+programoptions_test
+vespalib_programoptions_test_app
diff --git a/vespalib/src/tests/programoptions/CMakeLists.txt b/vespalib/src/tests/programoptions/CMakeLists.txt
new file mode 100644
index 00000000000..fb2fdb48dd7
--- /dev/null
+++ b/vespalib/src/tests/programoptions/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_programoptions_test_app TEST
+ SOURCES
+ programoptions_test.cpp
+ programoptions_testutils.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_programoptions_test_app COMMAND vespalib_programoptions_test_app)
diff --git a/vespalib/src/tests/programoptions/programoptions_test.cpp b/vespalib/src/tests/programoptions/programoptions_test.cpp
new file mode 100644
index 00000000000..4b63eae949b
--- /dev/null
+++ b/vespalib/src/tests/programoptions/programoptions_test.cpp
@@ -0,0 +1,361 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "programoptions_testutils.h"
+#include <vespa/vespalib/util/programoptions.h>
+#include <vespa/vespalib/testkit/testapp.h>
+#include <iostream>
+
+namespace vespalib {
+
+class Test : public vespalib::TestApp
+{
+public:
+ void testSyntaxPage();
+ void testNormalUsage();
+ void testFailures();
+ void testVectorArgument();
+ void testAllHiddenOption();
+ void testOptionsAfterArguments();
+ int Main() override;
+};
+
+int
+Test::Main()
+{
+ TEST_INIT("programoptions_test");
+ srandom(1);
+ testSyntaxPage();
+ testNormalUsage();
+ testFailures();
+ testVectorArgument();
+ testAllHiddenOption();
+ // Currently not supported
+ // testOptionsAfterArguments();
+ TEST_DONE();
+}
+
+struct MyOptions : public ProgramOptions {
+ bool boolOpt;
+ bool boolWithDefOpt;
+ int intOpt;
+ uint32_t uintOpt;
+ float floatOpt;
+ std::string stringOpt;
+ std::string argString;
+ int argInt;
+ std::string argOptionalString;
+ std::map<std::string, std::string> properties;
+ int anotherOptionalArg;
+
+ MyOptions(int argc, const char *const *argv);
+ ~MyOptions();
+};
+
+MyOptions::MyOptions(int argc, const char* const* argv)
+ : ProgramOptions(argc, argv)
+{
+ // Required options
+ addOption("uintopt u", uintOpt, "Sets an unsigned int");
+ // Optional options
+ addOption("b bool", boolOpt, "Enables a flag");
+ addOption("boolwithdef", boolWithDefOpt, true, "If set turns to false");
+
+ addOption("intopt i", intOpt, 5, "Sets a signed int");
+ addOption("floatopt", floatOpt, 4.0f, "Sets a float\nMultiline baby");
+ addOption("string s", stringOpt, std::string("ballalaika"),
+ "Sets a string value. This is a very long description that "
+ "should be broken down into multiple lines in some sensible "
+ "way.");
+ addOptionHeader("Advanced options");
+ addOption("p properties", properties, "Property map");
+ addHiddenIdentifiers("prop");
+ setArgumentTypeName("key");
+ setArgumentTypeName("value", 1);
+
+ addArgument("argString", argString, "Required string argument.");
+ addArgument("argInt", argInt, "Required int argument.");
+ addArgument("argOptionalString", argOptionalString, std::string("foo"),
+ "Optional string argument with a long description so we "
+ "can see that it will be broken correctly.");
+ addArgument("argSecondOptional", anotherOptionalArg, 3,
+ "Yet another optional argument");
+
+ setSyntaxMessage("A test program to see if this utility works.");
+ setSyntaxPageMaxLeftColumnSize(25);
+}
+
+MyOptions::~MyOptions() { }
+
+void Test::testSyntaxPage() {
+ AppOptions opts("myapp");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ std::ostringstream actual;
+ options.writeSyntaxPage(actual);
+
+ std::string expected(
+"\nA test program to see if this utility works.\n\n"
+"Usage: myapp [options] <argString> <argInt> [argOptionalString] [argSecondOptional]\n\n"
+"Arguments:\n"
+" argString (string) : Required string argument.\n"
+" argInt (int) : Required int argument.\n"
+" argOptionalString (string)\n"
+" : Optional string argument with a long description so\n"
+" we can see that it will be broken correctly.\n"
+" (optional)\n"
+" argSecondOptional (int) : Yet another optional argument (optional)\n\n"
+"Options:\n"
+" --uintopt -u <uint> : Sets an unsigned int (required)\n"
+" -b --bool : Enables a flag\n"
+" --boolwithdef : If set turns to false\n"
+" --intopt -i <int> : Sets a signed int (default 5)\n"
+" --floatopt <float> : Sets a float\n"
+" Multiline baby (default 4)\n"
+" --string -s <string> : Sets a string value. This is a very long description\n"
+" that should be broken down into multiple lines in some\n"
+" sensible way. (default \"ballalaika\")\n\n"
+"Advanced options:\n"
+" -p --properties <key> <value> : Property map (default empty)\n"
+ );
+ EXPECT_EQUAL(expected, actual.str());
+}
+
+void Test::testNormalUsage() {
+ {
+ AppOptions opts("myapp -b --uintopt 4 -s foo tit 1 tei 6");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ options.parse();
+ EXPECT_EQUAL(true, options.boolOpt);
+ EXPECT_EQUAL(true, options.boolWithDefOpt);
+ EXPECT_EQUAL(5, options.intOpt);
+ EXPECT_EQUAL(4u, options.uintOpt);
+ EXPECT_APPROX(4, options.floatOpt, 0.00001);
+ EXPECT_EQUAL("foo", options.stringOpt);
+ EXPECT_EQUAL("tit", options.argString);
+ EXPECT_EQUAL(1, options.argInt);
+ EXPECT_EQUAL("tei", options.argOptionalString);
+ EXPECT_EQUAL(0u, options.properties.size());
+ EXPECT_EQUAL(6, options.anotherOptionalArg);
+ }
+ {
+ AppOptions opts("myapp --uintopt 6 tit 1");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ options.parse();
+ EXPECT_EQUAL(false, options.boolOpt);
+ EXPECT_EQUAL(true, options.boolWithDefOpt);
+ EXPECT_EQUAL(5, options.intOpt);
+ EXPECT_EQUAL(6u, options.uintOpt);
+ EXPECT_APPROX(4, options.floatOpt, 0.00001);
+ EXPECT_EQUAL("ballalaika", options.stringOpt);
+ EXPECT_EQUAL("tit", options.argString);
+ EXPECT_EQUAL(1, options.argInt);
+ EXPECT_EQUAL("foo", options.argOptionalString);
+ EXPECT_EQUAL(0u, options.properties.size());
+ EXPECT_EQUAL(3, options.anotherOptionalArg);
+ }
+ // Arguments coming after options.
+ // (Required for nesting of short options)
+ {
+ AppOptions opts("myapp --uintopt --intopt 6 -8 tit 1 tei");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ options.parse();
+ EXPECT_EQUAL(false, options.boolOpt);
+ EXPECT_EQUAL(true, options.boolWithDefOpt);
+ EXPECT_EQUAL(-8, options.intOpt);
+ EXPECT_EQUAL(6u, options.uintOpt);
+ EXPECT_APPROX(4, options.floatOpt, 0.00001);
+ EXPECT_EQUAL("ballalaika", options.stringOpt);
+ EXPECT_EQUAL("tit", options.argString);
+ EXPECT_EQUAL(1, options.argInt);
+ EXPECT_EQUAL("tei", options.argOptionalString);
+ EXPECT_EQUAL(0u, options.properties.size());
+ }
+ {
+ AppOptions opts( "myapp -uib 6 -8 --boolwithdef tit 1 tei");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ options.parse();
+ EXPECT_EQUAL(true, options.boolOpt);
+ EXPECT_EQUAL(false, options.boolWithDefOpt);
+ EXPECT_EQUAL(-8, options.intOpt);
+ EXPECT_EQUAL(6u, options.uintOpt);
+ EXPECT_APPROX(4, options.floatOpt, 0.00001);
+ EXPECT_EQUAL("ballalaika", options.stringOpt);
+ EXPECT_EQUAL("tit", options.argString);
+ EXPECT_EQUAL(1, options.argInt);
+ EXPECT_EQUAL("tei", options.argOptionalString);
+ EXPECT_EQUAL(0u, options.properties.size());
+ }
+ // Properties
+ {
+ AppOptions opts("myapp -u 6 -p foo bar --prop hmm brr tit 1 tei");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ options.parse();
+ EXPECT_EQUAL(false, options.boolOpt);
+ EXPECT_EQUAL(true, options.boolWithDefOpt);
+ EXPECT_EQUAL(5, options.intOpt);
+ EXPECT_EQUAL(6u, options.uintOpt);
+ EXPECT_APPROX(4, options.floatOpt, 0.00001);
+ EXPECT_EQUAL("ballalaika", options.stringOpt);
+ EXPECT_EQUAL("tit", options.argString);
+ EXPECT_EQUAL(1, options.argInt);
+ EXPECT_EQUAL("tei", options.argOptionalString);
+ EXPECT_EQUAL(2u, options.properties.size());
+ EXPECT_EQUAL("bar", options.properties["foo"]);
+ EXPECT_EQUAL("brr", options.properties["hmm"]);
+ }
+}
+
+void Test::testFailures() {
+ // Non-existing long option
+ {
+ AppOptions opts("myapp -b --uintopt 4 -s foo --none");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("Invalid option 'none'.", e.getMessage());
+ }
+ }
+ // Non-existing short option
+ {
+ AppOptions opts("myapp -b --uintopt 4 -s foo -q");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("Invalid option 'q'.", e.getMessage());
+ }
+ }
+ // Lacking option argument
+ {
+ AppOptions opts("myapp -b --uintopt 4 -s");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("Option 's' needs 1 arguments. Only 0 available.",
+ e.getMessage());
+ }
+ }
+ // Out of signed ranged
+ {
+ AppOptions opts("myapp -b --uintopt 4 -intopt 3000000000");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("The argument '3000000000' can not be interpreted as a "
+ "number of type int.", e.getMessage());
+ }
+ }
+ // Negative value to unsigned var (Currently doesnt fail)
+/*
+ {
+ AppOptions opts("myapp -b --uintopt -1 foo 0");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("The argument '-1' can not be interpreted as a "
+ "number of type uint.", e.getMessage());
+ }
+ }
+ */
+ // Lacking required option
+ {
+ AppOptions opts("myapp -b");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("Option 'uintopt' has no default and must be set.",
+ e.getMessage());
+ }
+ }
+ // Lacking required argument
+ {
+ AppOptions opts("myapp --uintopt 1 tit");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("Insufficient data is given to set required argument "
+ "'argInt'.",
+ e.getMessage());
+ }
+ }
+ // Argument of wrong type
+ {
+ AppOptions opts("myapp --uintopt 1 tit en");
+ MyOptions options(opts.getArgCount(), opts.getArguments());
+ try{
+ options.parse();
+ TEST_FATAL("Expected exception");
+ } catch (InvalidCommandLineArgumentsException& e) {
+ EXPECT_EQUAL("The argument 'en' can not be interpreted as a number "
+ "of type int.",
+ e.getMessage());
+ }
+ }
+}
+
+void Test::testVectorArgument()
+{
+ AppOptions opts("myapp foo bar baz");
+ std::vector<std::string> args;
+ ProgramOptions options(opts.getArgCount(), opts.getArguments());
+ options.addListArgument("ids", args, "Vector element");
+ std::ostringstream actual;
+ options.writeSyntaxPage(actual);
+ std::string expected(
+"\nUsage: myapp [ids...]\n\n"
+"Arguments:\n"
+" ids (string[]) : Vector element\n"
+ );
+ EXPECT_EQUAL(expected, actual.str());
+
+ options.parse();
+ EXPECT_EQUAL(3u, args.size());
+ EXPECT_EQUAL("foo", args[0]);
+ EXPECT_EQUAL("bar", args[1]);
+ EXPECT_EQUAL("baz", args[2]);
+}
+
+void Test::testAllHiddenOption()
+{
+ AppOptions opts("myapp --foo bar");
+ std::string option;
+ ProgramOptions options(opts.getArgCount(), opts.getArguments());
+ options.addOption("", option, "Description");
+ options.addHiddenIdentifiers("foo");
+ std::ostringstream actual;
+ options.writeSyntaxPage(actual);
+ std::string expected("\nUsage: myapp\n");
+ EXPECT_EQUAL(expected, actual.str());
+
+ options.parse();
+ EXPECT_EQUAL("bar", option);
+}
+
+void Test::testOptionsAfterArguments()
+{
+ AppOptions opts("myapp bar --foo baz");
+ std::string option;
+ std::string argument;
+ ProgramOptions options(opts.getArgCount(), opts.getArguments());
+ options.addOption("foo", option, "Description");
+ options.addArgument("arg", argument, "Description");
+ options.parse();
+ EXPECT_EQUAL("baz", option);
+ EXPECT_EQUAL("bar", argument);
+}
+
+} // vespalib
+
+TEST_APPHOOK(vespalib::Test)
diff --git a/vespalib/src/tests/programoptions/programoptions_testutils.cpp b/vespalib/src/tests/programoptions/programoptions_testutils.cpp
new file mode 100644
index 00000000000..948413c36db
--- /dev/null
+++ b/vespalib/src/tests/programoptions/programoptions_testutils.cpp
@@ -0,0 +1,48 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "programoptions_testutils.h"
+
+namespace vespalib {
+
+namespace {
+ std::vector<std::string> splitString(const std::string& source) {
+ std::vector<std::string> target;
+ std::string::size_type start = 0;
+ std::string::size_type stop = source.find(' ');
+ while (stop != std::string::npos) {
+ target.push_back(source.substr(start, stop - start));
+ start = stop + 1;
+ stop = source.find(' ', start);
+ }
+ target.push_back(source.substr(start));
+ return target;
+ }
+} // anonymous
+
+AppOptions::AppOptions(const std::string& optString)
+ : _argc(0), _argv(0), _source()
+{
+ _source = splitString(optString);
+ _argc = _source.size();
+ _argv = new const char*[_source.size()];
+ for (int i=0; i<_argc; ++i) {
+ if (_source[i].size() > 1
+ && _source[i][0] == _source[i][_source[i].size() - 1]
+ && (_source[i][0] == '\'' || _source[i][0] == '"'))
+ {
+ if (_source[i].size() == 2) {
+ _source[i] = "";
+ } else {
+ _source[i] = _source[i].substr(1, _source.size() - 2);
+ }
+ }
+ _argv[i] = _source[i].c_str();
+ }
+}
+
+AppOptions::~AppOptions()
+{
+ delete[] _argv;
+}
+
+} // vespalib
diff --git a/vespalib/src/tests/programoptions/programoptions_testutils.h b/vespalib/src/tests/programoptions/programoptions_testutils.h
new file mode 100644
index 00000000000..a6f103f3e95
--- /dev/null
+++ b/vespalib/src/tests/programoptions/programoptions_testutils.h
@@ -0,0 +1,32 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * This class contains some test utilities, to create argc/argv inputs for
+ * application tests.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace vespalib {
+
+class AppOptions {
+ int _argc;
+ const char** _argv;
+ std::vector<std::string> _source;
+
+ AppOptions(const AppOptions&);
+ AppOptions& operator=(const AppOptions&);
+
+public:
+ AppOptions(const std::string& optString);
+ ~AppOptions();
+
+ int getArgCount() const { return _argc; }
+ const char* const* getArguments() const { return _argv; }
+
+};
+
+} // vespalib
+
diff --git a/vespalib/src/tests/rusage/.gitignore b/vespalib/src/tests/rusage/.gitignore
new file mode 100644
index 00000000000..c01c01ed328
--- /dev/null
+++ b/vespalib/src/tests/rusage/.gitignore
@@ -0,0 +1 @@
+vespalib_rusage_test_app
diff --git a/vespalib/src/tests/rusage/CMakeLists.txt b/vespalib/src/tests/rusage/CMakeLists.txt
new file mode 100644
index 00000000000..1c1ab85facd
--- /dev/null
+++ b/vespalib/src/tests/rusage/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_rusage_test_app TEST
+ SOURCES
+ rusage_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_rusage_test_app COMMAND vespalib_rusage_test_app)
diff --git a/vespalib/src/tests/rusage/rusage_test.cpp b/vespalib/src/tests/rusage/rusage_test.cpp
new file mode 100644
index 00000000000..7e30f3b968b
--- /dev/null
+++ b/vespalib/src/tests/rusage/rusage_test.cpp
@@ -0,0 +1,57 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/rusage.h>
+
+using namespace vespalib;
+
+TEST("testRUsage")
+{
+ RUsage r1;
+ EXPECT_EQUAL("", r1.toString());
+ RUsage r2;
+ EXPECT_EQUAL(r2.toString(), r1.toString());
+ RUsage diff = r2-r1;
+ EXPECT_EQUAL(diff.toString(), r2.toString());
+ {
+ RUsage then = RUsage::createSelf(steady_time(7ns));
+ RUsage now = RUsage::createSelf();
+ EXPECT_NOT_EQUAL(now.toString(), then.toString());
+ }
+ {
+ RUsage then = RUsage::createChildren(steady_time(1337583ns));
+ RUsage now = RUsage::createChildren();
+ EXPECT_NOT_EQUAL(now.toString(), then.toString());
+ }
+ {
+ timeval a, b, c, d, r;
+ a.tv_usec = 7;
+ a.tv_sec = 7;
+ b.tv_usec = 7;
+ b.tv_sec = 7;
+ c.tv_usec = 1;
+ c.tv_sec = 8;
+ d.tv_usec = 9;
+ d.tv_sec = 4;
+ r = a - b;
+ EXPECT_EQUAL(0, r.tv_sec);
+ EXPECT_EQUAL(0, r.tv_usec);
+ r = b - a;
+ EXPECT_EQUAL(0, r.tv_sec);
+ EXPECT_EQUAL(0, r.tv_usec);
+ r = a - c;
+ EXPECT_EQUAL(-1, r.tv_sec);
+ EXPECT_EQUAL( 6, r.tv_usec);
+ r = c - a;
+ EXPECT_EQUAL(0, r.tv_sec);
+ EXPECT_EQUAL(999994, r.tv_usec);
+ r = a - d;
+ EXPECT_EQUAL(2, r.tv_sec);
+ EXPECT_EQUAL(999998, r.tv_usec);
+ r = d - a;
+ EXPECT_EQUAL(-3, r.tv_sec);
+ EXPECT_EQUAL( 2, r.tv_usec);
+ }
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/shutdownguard/.gitignore b/vespalib/src/tests/shutdownguard/.gitignore
new file mode 100644
index 00000000000..c167d4784ca
--- /dev/null
+++ b/vespalib/src/tests/shutdownguard/.gitignore
@@ -0,0 +1 @@
+vespalib_shutdownguard_test_app
diff --git a/vespalib/src/tests/shutdownguard/CMakeLists.txt b/vespalib/src/tests/shutdownguard/CMakeLists.txt
new file mode 100644
index 00000000000..6714842fbbf
--- /dev/null
+++ b/vespalib/src/tests/shutdownguard/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_shutdownguard_test_app TEST
+ SOURCES
+ shutdownguard_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_shutdownguard_test_app NO_VALGRIND COMMAND vespalib_shutdownguard_test_app)
diff --git a/vespalib/src/tests/shutdownguard/shutdownguard_test.cpp b/vespalib/src/tests/shutdownguard/shutdownguard_test.cpp
new file mode 100644
index 00000000000..348e9bbd503
--- /dev/null
+++ b/vespalib/src/tests/shutdownguard/shutdownguard_test.cpp
@@ -0,0 +1,43 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/shutdownguard.h>
+#include <vespa/vespalib/util/malloc_mmap_guard.h>
+#include <thread>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <cstdlib>
+
+using namespace vespalib;
+
+TEST("test shutdown guard")
+{
+ {
+ ShutdownGuard farFuture(1000000s);
+ std::this_thread::sleep_for(20ms);
+ }
+ EXPECT_TRUE(true);
+ pid_t child = fork();
+ if (child == 0) {
+ ShutdownGuard soon(30ms);
+ for (int i = 0; i < 1000; ++i) {
+ std::this_thread::sleep_for(20ms);
+ }
+ std::_Exit(0);
+ }
+ for (int i = 0; i < 1000; ++i) {
+ std::this_thread::sleep_for(20ms);
+ int stat = 0;
+ if (waitpid(child, &stat, WNOHANG) == child) {
+ EXPECT_TRUE(WIFEXITED(stat));
+ EXPECT_EQUAL(1, WEXITSTATUS(stat));
+ break;
+ }
+ EXPECT_TRUE(i < 800);
+ }
+}
+
+TEST("test malloc mmap guard") {
+ MallocMmapGuard guard(0x100000);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/stllike/CMakeLists.txt b/vespalib/src/tests/stllike/CMakeLists.txt
index 80509c565c6..005ef3d1ed0 100644
--- a/vespalib/src/tests/stllike/CMakeLists.txt
+++ b/vespalib/src/tests/stllike/CMakeLists.txt
@@ -55,3 +55,17 @@ vespa_add_executable(vespalib_replace_variable_test_app TEST
GTest::GTest
)
vespa_add_test(NAME vespalib_replace_variable_test_app COMMAND vespalib_replace_variable_test_app)
+vespa_add_executable(vespalib_lrucache_test_app TEST
+ SOURCES
+ lrucache.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_lrucache_test_app COMMAND vespalib_lrucache_test_app)
+vespa_add_executable(vespalib_cache_test_app TEST
+ SOURCES
+ cache_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_cache_test_app COMMAND vespalib_cache_test_app)
diff --git a/vespalib/src/tests/stllike/cache_test.cpp b/vespalib/src/tests/stllike/cache_test.cpp
new file mode 100644
index 00000000000..35f04d91510
--- /dev/null
+++ b/vespalib/src/tests/stllike/cache_test.cpp
@@ -0,0 +1,139 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vespalib/stllike/cache.hpp>
+#include <map>
+
+using namespace vespalib;
+
+template<typename K, typename V>
+class Map : public std::map<K, V> {
+ typedef typename std::map<K, V>::const_iterator const_iterator;
+ typedef std::map<K, V> M;
+public:
+ bool read(const K & k, V & v) const {
+ const_iterator found = M::find(k);
+ bool ok(found != this->end());
+ if (ok) {
+ v = found->second;
+ }
+ return ok;
+ }
+ void write(const K & k, const V & v) {
+ (*this)[k] = v;
+ }
+ void erase(const K & k) {
+ M::erase(k);
+ }
+};
+
+using P = LruParam<uint32_t, string>;
+using B = Map<uint32_t, string>;
+
+TEST("testCache") {
+ B m;
+ cache< CacheParam<P, B> > cache(m, -1);
+ // Verfify start conditions.
+ EXPECT_TRUE(cache.size() == 0);
+ EXPECT_TRUE( ! cache.hasKey(1) );
+ cache.write(1, "First inserted string");
+ EXPECT_TRUE( cache.hasKey(1) );
+ m[2] = "String inserted beneath";
+ EXPECT_TRUE( ! cache.hasKey(2) );
+ EXPECT_EQUAL( cache.read(2), "String inserted beneath");
+ EXPECT_TRUE( cache.hasKey(2) );
+ cache.erase(1);
+ EXPECT_TRUE( ! cache.hasKey(1) );
+ EXPECT_TRUE(cache.size() == 1);
+}
+
+TEST("testCacheSize")
+{
+ B m;
+ cache< CacheParam<P, B> > cache(m, -1);
+ cache.write(1, "10 bytes string");
+ EXPECT_EQUAL(80u, cache.sizeBytes());
+ cache.write(1, "10 bytes string"); // Still the same size
+ EXPECT_EQUAL(80u, cache.sizeBytes());
+}
+
+TEST("testCacheSizeDeep")
+{
+ B m;
+ cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, -1);
+ cache.write(1, "15 bytes string");
+ EXPECT_EQUAL(95u, cache.sizeBytes());
+ cache.write(1, "10 bytes s");
+ EXPECT_EQUAL(90u, cache.sizeBytes());
+ cache.write(1, "20 bytes string ssss");
+ EXPECT_EQUAL(100u, cache.sizeBytes());
+}
+
+TEST("testCacheEntriesHonoured") {
+ B m;
+ cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, -1);
+ cache.maxElements(1);
+ cache.write(1, "15 bytes string");
+ EXPECT_EQUAL(1u, cache.size());
+ EXPECT_EQUAL(95u, cache.sizeBytes());
+ cache.write(2, "16 bytes stringg");
+ EXPECT_EQUAL(1u, cache.size());
+ EXPECT_TRUE( cache.hasKey(2) );
+ EXPECT_FALSE( cache.hasKey(1) );
+ EXPECT_EQUAL(96u, cache.sizeBytes());
+}
+
+TEST("testCacheMaxSizeHonoured") {
+ B m;
+ cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, 200);
+ cache.write(1, "15 bytes string");
+ EXPECT_EQUAL(1u, cache.size());
+ EXPECT_EQUAL(95u, cache.sizeBytes());
+ cache.write(2, "16 bytes stringg");
+ EXPECT_EQUAL(2u, cache.size());
+ EXPECT_EQUAL(191u, cache.sizeBytes());
+ cache.write(3, "17 bytes stringgg");
+ EXPECT_EQUAL(3u, cache.size());
+ EXPECT_EQUAL(288u, cache.sizeBytes());
+ cache.write(4, "18 bytes stringggg");
+ EXPECT_EQUAL(3u, cache.size());
+ EXPECT_EQUAL(291u, cache.sizeBytes());
+}
+
+TEST("testThatMultipleRemoveOnOverflowIsFine") {
+ B m;
+ cache< CacheParam<P, B, zero<uint32_t>, size<string> > > cache(m, 2000);
+
+ for (size_t j(0); j < 5; j++) {
+ for (size_t i(0); cache.size() == i; i++) {
+ cache.write(j*53+i, "a");
+ }
+ }
+ EXPECT_EQUAL(25u, cache.size());
+ EXPECT_EQUAL(2025u, cache.sizeBytes());
+ EXPECT_FALSE( cache.hasKey(0) );
+ string ls("long string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+ string vls=ls+ls+ls+ls+ls+ls;
+ cache.write(53+5, ls);
+ EXPECT_EQUAL(25u, cache.size());
+ EXPECT_EQUAL(2498u, cache.sizeBytes());
+ EXPECT_FALSE( cache.hasKey(1) );
+ cache.write(53*7+5, ls);
+ EXPECT_EQUAL(19u, cache.size());
+ EXPECT_EQUAL(2485u, cache.sizeBytes());
+ EXPECT_FALSE( cache.hasKey(2) );
+ cache.write(53*8+5, vls);
+ EXPECT_EQUAL(14u, cache.size());
+ EXPECT_EQUAL(4923u, cache.sizeBytes());
+ cache.write(53*9+6, vls);
+ EXPECT_EQUAL(1u, cache.size());
+ EXPECT_EQUAL(2924u, cache.sizeBytes());
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/stllike/lrucache.cpp b/vespalib/src/tests/stllike/lrucache.cpp
new file mode 100644
index 00000000000..2cc6f2b4ee8
--- /dev/null
+++ b/vespalib/src/tests/stllike/lrucache.cpp
@@ -0,0 +1,190 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vespalib/stllike/lrucache_map.hpp>
+
+using namespace vespalib;
+
+TEST("testCache") {
+ lrucache_map< LruParam<int, string> > cache(7);
+ // Verfify start conditions.
+ EXPECT_TRUE(cache.size() == 0);
+ cache.insert(1, "First inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 1);
+ EXPECT_TRUE(cache.hasKey(1));
+ cache.insert(2, "Second inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 2);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ cache.insert(3, "Third inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 3);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ cache.insert(4, "Fourth inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 4);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ cache.insert(5, "Fifth inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 5);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ EXPECT_TRUE(cache.hasKey(5));
+ cache.insert(6, "Sixt inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(cache.size() == 6);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ EXPECT_TRUE(cache.hasKey(5));
+ EXPECT_TRUE(cache.hasKey(6));
+ cache.insert(7, "Seventh inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_EQUAL(cache.size(), 7u);
+ EXPECT_TRUE(cache.hasKey(1));
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ EXPECT_TRUE(cache.hasKey(5));
+ EXPECT_TRUE(cache.hasKey(6));
+ EXPECT_TRUE(cache.hasKey(7));
+ cache.insert(8, "Eighth inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_EQUAL(cache.size(), 7u);
+ EXPECT_TRUE(cache.hasKey(2));
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ EXPECT_TRUE(cache.hasKey(5));
+ EXPECT_TRUE(cache.hasKey(6));
+ EXPECT_TRUE(cache.hasKey(7));
+ EXPECT_TRUE(cache.hasKey(8));
+ cache.insert(15, "Eighth inserted string");
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_EQUAL(cache.size(), 7u);
+ EXPECT_TRUE(cache.hasKey(3));
+ EXPECT_TRUE(cache.hasKey(4));
+ EXPECT_TRUE(cache.hasKey(5));
+ EXPECT_TRUE(cache.hasKey(6));
+ EXPECT_TRUE(cache.hasKey(7));
+ EXPECT_TRUE(cache.hasKey(8));
+ EXPECT_TRUE(cache.hasKey(15));
+ // Test get and erase
+ cache.get(3);
+ EXPECT_TRUE(cache.verifyInternals());
+ cache.erase(3);
+ EXPECT_TRUE(cache.verifyInternals());
+ EXPECT_TRUE(!cache.hasKey(3));
+}
+
+typedef std::shared_ptr<std::string> MyKey;
+typedef std::shared_ptr<std::string> MyData;
+
+struct SharedEqual {
+ bool operator()(const MyKey & a, const MyKey & b) {
+ return ((*a) == (*b));
+ }
+};
+
+struct SharedHash {
+ size_t operator() (const MyKey & arg) const { return arg->size(); }
+};
+
+
+TEST("testCacheInsertOverResize") {
+ using LS = std::shared_ptr<std::string>;
+ using Cache = lrucache_map< LruParam<int, LS> >;
+
+ Cache cache(100);
+ size_t sum(0);
+ for (size_t i(0); i < cache.capacity()*10; i++) {
+ LS s(new std::string("abc"));
+ cache[random()] = s;
+ sum += strlen(s->c_str());
+ EXPECT_EQUAL(strlen(s->c_str()), s->size());
+ }
+ EXPECT_EQUAL(sum, cache.capacity()*10*3);
+}
+
+TEST("testCacheErase") {
+ lrucache_map< LruParam<MyKey, MyData, SharedHash, SharedEqual> > cache(4);
+
+ MyData d(new std::string("foo"));
+ MyKey k(new std::string("barlol"));
+ // Verfify start conditions.
+ EXPECT_TRUE(cache.size() == 0);
+ EXPECT_TRUE(d.use_count() == 1);
+ EXPECT_TRUE(k.use_count() == 1);
+ cache.insert(k, d);
+ EXPECT_TRUE(d.use_count() == 2);
+ EXPECT_TRUE(k.use_count() == 2);
+ cache.erase(k);
+ EXPECT_TRUE(d.use_count() == 1);
+ EXPECT_TRUE(k.use_count() == 1);
+}
+
+TEST("testCacheIterator") {
+ typedef lrucache_map< LruParam<int, string> > Cache;
+ Cache cache(3);
+ cache.insert(1, "first");
+ cache.insert(2, "second");
+ cache.insert(3, "third");
+ Cache::iterator it(cache.begin());
+ Cache::iterator mt(cache.end());
+ ASSERT_TRUE(it != mt);
+ ASSERT_EQUAL("third", *it);
+ ASSERT_TRUE(it != mt);
+ ASSERT_EQUAL("second", *(++it));
+ ASSERT_TRUE(it != mt);
+ ASSERT_EQUAL("second", *it++);
+ ASSERT_TRUE(it != mt);
+ ASSERT_EQUAL("first", *it);
+ ASSERT_TRUE(it != mt);
+ it++;
+ ASSERT_TRUE(it == mt);
+ cache.insert(4, "fourth");
+ Cache::iterator it2(cache.begin());
+ Cache::iterator it3(cache.begin());
+ ASSERT_EQUAL("fourth", *it2);
+ ASSERT_TRUE(it2 == it3);
+ it2++;
+ ASSERT_TRUE(it2 != it3);
+ it2++;
+ it2++;
+ ASSERT_TRUE(it2 == mt);
+ Cache::iterator it4 = cache.erase(it3);
+ ASSERT_EQUAL("third", *it4);
+ ASSERT_EQUAL("third", *cache.begin());
+ Cache::iterator it5(cache.erase(cache.end()));
+ ASSERT_TRUE(it5 == cache.end());
+}
+
+TEST("testCacheIteratorErase") {
+ typedef lrucache_map< LruParam<int, string> > Cache;
+ Cache cache(3);
+ cache.insert(1, "first");
+ cache.insert(8, "second");
+ cache.insert(15, "third");
+ cache.insert(15, "third");
+ cache.insert(8, "second");
+ cache.insert(1, "first");
+ Cache::iterator it(cache.begin());
+ ASSERT_EQUAL("first", *it);
+ it++;
+ ASSERT_EQUAL("second", *it);
+ it = cache.erase(it);
+ ASSERT_EQUAL("third", *it);
+ cache.erase(it);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/util/process_memory_stats/.gitignore b/vespalib/src/tests/util/process_memory_stats/.gitignore
new file mode 100644
index 00000000000..81af04ee64f
--- /dev/null
+++ b/vespalib/src/tests/util/process_memory_stats/.gitignore
@@ -0,0 +1,2 @@
+mapfile
+vespalib_process_memory_stats_test_app
diff --git a/vespalib/src/tests/util/process_memory_stats/CMakeLists.txt b/vespalib/src/tests/util/process_memory_stats/CMakeLists.txt
new file mode 100644
index 00000000000..30a0f90d952
--- /dev/null
+++ b/vespalib/src/tests/util/process_memory_stats/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_process_memory_stats_test_app TEST
+ SOURCES
+ process_memory_stats_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_process_memory_stats_test_app COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/process_memory_stats_test.sh
+ DEPENDS vespalib_process_memory_stats_test_app)
diff --git a/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp b/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp
new file mode 100644
index 00000000000..6d0917e6d15
--- /dev/null
+++ b/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.cpp
@@ -0,0 +1,92 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/util/process_memory_stats.h>
+#include <vespa/vespalib/util/size_literals.h>
+#include <iostream>
+#include <fstream>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+using namespace vespalib;
+
+namespace {
+
+constexpr uint64_t SIZE_EPSILON = 4095;
+
+std::string toString(const ProcessMemoryStats &stats)
+{
+ std::ostringstream os;
+ os << "Mapped("
+ << stats.getMappedVirt() << "," << stats.getMappedRss() <<
+ "), Anonymous("
+ << stats.getAnonymousVirt() << "," << stats.getAnonymousRss() << ")";
+ return os.str();
+}
+
+}
+
+TEST("Simple stats")
+{
+ ProcessMemoryStats stats(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats) << std::endl;
+ EXPECT_LESS(0u, stats.getMappedVirt());
+ EXPECT_LESS(0u, stats.getMappedRss());
+ EXPECT_LESS(0u, stats.getAnonymousVirt());
+ EXPECT_LESS(0u, stats.getAnonymousRss());
+}
+
+TEST("grow anonymous memory")
+{
+ ProcessMemoryStats stats1(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats1) << std::endl;
+ size_t mapLen = 64_Ki;
+ void *mapAddr = mmap(nullptr, mapLen, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ EXPECT_NOT_EQUAL(reinterpret_cast<void *>(-1), mapAddr);
+ ProcessMemoryStats stats2(ProcessMemoryStats::create());
+ std::cout << toString(stats2) << std::endl;
+ EXPECT_LESS_EQUAL(stats1.getAnonymousVirt() + mapLen,
+ stats2.getAnonymousVirt());
+ memset(mapAddr, 1, mapLen);
+ ProcessMemoryStats stats3(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats3) << std::endl;
+ // Cannot check that resident grows if swap is enabled and system loaded
+ munmap(mapAddr, mapLen);
+}
+
+TEST("grow mapped memory")
+{
+ std::ofstream of("mapfile");
+ size_t mapLen = 64_Ki;
+ std::vector<char> buf(mapLen, 4);
+ of.write(&buf[0], buf.size());
+ of.close();
+ int mapfileFileDescriptor = open("mapfile", O_RDONLY, 0666);
+ EXPECT_LESS_EQUAL(0, mapfileFileDescriptor);
+ ProcessMemoryStats stats1(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats1) << std::endl;
+ void *mapAddr = mmap(nullptr, mapLen, PROT_READ, MAP_SHARED,
+ mapfileFileDescriptor, 0);
+ EXPECT_NOT_EQUAL(reinterpret_cast<void *>(-1), mapAddr);
+ ProcessMemoryStats stats2(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats2) << std::endl;
+ EXPECT_LESS_EQUAL(stats1.getMappedVirt() + mapLen, stats2.getMappedVirt());
+ EXPECT_EQUAL(0, memcmp(mapAddr, &buf[0], mapLen));
+ ProcessMemoryStats stats3(ProcessMemoryStats::create(SIZE_EPSILON));
+ std::cout << toString(stats3) << std::endl;
+ // Cannot check that resident grows if swap is enabled and system loaded
+ munmap(mapAddr, mapLen);
+}
+
+TEST("order samples")
+{
+ ProcessMemoryStats a(0,0,0,7,0);
+ ProcessMemoryStats b(0,0,0,8,0);
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(b < a);
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh b/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh
new file mode 100755
index 00000000000..7fe5261ab2d
--- /dev/null
+++ b/vespalib/src/tests/util/process_memory_stats/process_memory_stats_test.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+set -e
+rm -f mapfile
+$VALGRIND ./vespalib_process_memory_stats_test_app
+rm -f mapfile
diff --git a/vespalib/src/tests/xmlserializable/.gitignore b/vespalib/src/tests/xmlserializable/.gitignore
new file mode 100644
index 00000000000..8573da1cd93
--- /dev/null
+++ b/vespalib/src/tests/xmlserializable/.gitignore
@@ -0,0 +1,4 @@
+*_test
+.depend
+Makefile
+vespalib_xmlserializable_test_app
diff --git a/vespalib/src/tests/xmlserializable/CMakeLists.txt b/vespalib/src/tests/xmlserializable/CMakeLists.txt
new file mode 100644
index 00000000000..119a1294253
--- /dev/null
+++ b/vespalib/src/tests/xmlserializable/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_xmlserializable_test_app TEST
+ SOURCES
+ xmlserializabletest.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_xmlserializable_test_app COMMAND vespalib_xmlserializable_test_app)
diff --git a/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp b/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp
new file mode 100644
index 00000000000..cc8d61cb7c2
--- /dev/null
+++ b/vespalib/src/tests/xmlserializable/xmlserializabletest.cpp
@@ -0,0 +1,163 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/vespalib/util/xmlstream.h>
+
+namespace vespalib {
+
+class Test : public vespalib::TestApp
+{
+public:
+ void testNormalUsage();
+ void testEscaping();
+ void testNesting();
+ void testIndent();
+
+ int Main() override;
+};
+
+int
+Test::Main()
+{
+ TEST_INIT("xmlserializables_test");
+ srandom(1);
+ testNormalUsage();
+ testEscaping();
+ testNesting();
+ testIndent();
+ TEST_DONE();
+}
+
+void
+Test::testNormalUsage()
+{
+ std::ostringstream ost;
+ XmlOutputStream xos(ost);
+ using namespace vespalib::xml;
+ xos << XmlTag("car")
+ << XmlTag("door")
+ << XmlAttribute("windowstate", "up")
+ << XmlEndTag()
+ << XmlTag("description")
+ << "This is a car description used to test"
+ << XmlEndTag()
+ << XmlEndTag();
+ std::string expected =
+ "<car>\n"
+ "<door windowstate=\"up\"/>\n"
+ "<description>This is a car description used to test</description>\n"
+ "</car>";
+ EXPECT_EQUAL(expected, ost.str());
+}
+
+void
+Test::testEscaping()
+{
+ std::ostringstream ost;
+ XmlOutputStream xos(ost);
+ using namespace vespalib::xml;
+ xos << XmlTag("!#trash%-", XmlTagFlags::CONVERT_ILLEGAL_CHARACTERS)
+ << XmlTag("foo")
+ << XmlAttribute("bar", "<100%\" &\n>")
+ << XmlEndTag()
+ << XmlTag("escaped")
+ << XmlEscapedContent()
+ << XmlContentWrapper("<>&\"'% \r\n\t\f\0", 12)
+ << XmlEndTag()
+ << XmlTag("encoded")
+ << XmlBase64Content()
+ << XmlContentWrapper("<>&\"'% \t\f\0", 10)
+ << XmlEndTag()
+ << XmlTag("auto1")
+ << XmlContentWrapper("<>&\t\f\r\nfoo", 10)
+ << XmlEndTag()
+ << XmlTag("auto2")
+ << XmlContentWrapper("<>&\t\0\r\nfoo", 10)
+ << XmlEndTag()
+ << XmlEndTag();
+ std::string expected =
+ "<__trash_->\n"
+ "<foo bar=\"&lt;100%&quot; &amp;&#10;&gt;\"/>\n"
+ "<escaped>&lt;&gt;&amp;\"'% &#13;\n&#9;&#12;&#0;</escaped>\n"
+ "<encoded binaryencoding=\"base64\">PD4mIiclIAkMAA==</encoded>\n"
+ "<auto1>&lt;&gt;&amp;&#9;&#12;&#13;\nfoo</auto1>\n"
+ "<auto2 binaryencoding=\"base64\">PD4mCQANCmZvbw==</auto2>\n"
+ "</__trash_->";
+ EXPECT_EQUAL(expected, ost.str());
+}
+
+namespace {
+ struct LookAndFeel : public XmlSerializable {
+
+ LookAndFeel() {}
+
+ void printXml(XmlOutputStream& out) const override {
+ using namespace vespalib::xml;
+ out << XmlAttribute("color", "blue")
+ << XmlTag("other")
+ << XmlAttribute("count", 5)
+ << XmlTag("something") << "foo" << XmlEndTag()
+ << XmlTag("else") << "bar" << XmlEndTag()
+ << XmlEndTag();
+ }
+ };
+}
+
+void
+Test::testNesting()
+{
+ std::ostringstream ost;
+ XmlOutputStream xos(ost);
+ using namespace vespalib::xml;
+ xos << XmlTag("car")
+ << XmlTag("door")
+ << LookAndFeel()
+ << XmlEndTag()
+ << XmlTag("description")
+ << "This is a car description used to test"
+ << XmlEndTag()
+ << XmlEndTag();
+ std::string expected =
+ "<car>\n"
+ "<door color=\"blue\">\n"
+ "<other count=\"5\">\n"
+ "<something>foo</something>\n"
+ "<else>bar</else>\n"
+ "</other>\n"
+ "</door>\n"
+ "<description>This is a car description used to test</description>\n"
+ "</car>";
+ EXPECT_EQUAL(expected, ost.str());
+}
+
+void
+Test::testIndent()
+{
+ std::ostringstream ost;
+ XmlOutputStream xos(ost, " ");
+ using namespace vespalib::xml;
+ xos << XmlTag("foo")
+ << XmlTag("bar") << 2.14 << XmlEndTag()
+ << "Litt innhold"
+ << XmlTag("nytag")
+ << "Mer innhold"
+ << XmlTag("base")
+ << XmlBase64Content() << "foobar"
+ << XmlEndTag()
+ << XmlEndTag()
+ << XmlEndTag();
+ std::string expected =
+ "<foo>\n"
+ " <bar>2.14</bar>\n"
+ " Litt innhold\n"
+ " <nytag>\n"
+ " Mer innhold\n"
+ " <base binaryencoding=\"base64\">Zm9vYmFy</base>\n"
+ " </nytag>\n"
+ "</foo>";
+ EXPECT_EQUAL(expected, ost.str());
+}
+
+} // vespalib
+
+TEST_APPHOOK(vespalib::Test)