summaryrefslogtreecommitdiffstats
path: root/src/lib/util/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:36:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 11:36:04 +0000
commit040eee1aa49b49df4698d83a05af57c220127fd1 (patch)
treef635435954e6ccde5eee9893889e24f30ca68346 /src/lib/util/tests
parentInitial commit. (diff)
downloadisc-kea-upstream.tar.xz
isc-kea-upstream.zip
Adding upstream version 2.2.0.upstream/2.2.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/util/tests')
-rw-r--r--src/lib/util/tests/Makefile.am74
-rw-r--r--src/lib/util/tests/Makefile.in1688
-rw-r--r--src/lib/util/tests/base32hex_unittest.cc158
-rw-r--r--src/lib/util/tests/base64_unittest.cc93
-rw-r--r--src/lib/util/tests/boost_time_utils_unittest.cc99
-rw-r--r--src/lib/util/tests/buffer_unittest.cc341
-rw-r--r--src/lib/util/tests/chrono_time_utils_unittest.cc159
-rw-r--r--src/lib/util/tests/csv_file_unittest.cc700
-rw-r--r--src/lib/util/tests/dhcp_space_unittest.cc32
-rw-r--r--src/lib/util/tests/doubles_unittest.cc32
-rw-r--r--src/lib/util/tests/fd_share_tests.cc72
-rw-r--r--src/lib/util/tests/fd_tests.cc71
-rw-r--r--src/lib/util/tests/file_utilities_unittest.cc86
-rw-r--r--src/lib/util/tests/filename_unittest.cc225
-rw-r--r--src/lib/util/tests/hash_unittest.cc34
-rw-r--r--src/lib/util/tests/hex_unittest.cc114
-rw-r--r--src/lib/util/tests/io_utilities_unittest.cc160
-rw-r--r--src/lib/util/tests/labeled_value_unittest.cc101
-rw-r--r--src/lib/util/tests/memory_segment_common_unittest.cc100
-rw-r--r--src/lib/util/tests/memory_segment_common_unittest.h28
-rw-r--r--src/lib/util/tests/memory_segment_local_unittest.cc117
-rw-r--r--src/lib/util/tests/multi_threading_mgr_unittest.cc626
-rw-r--r--src/lib/util/tests/optional_unittest.cc162
-rw-r--r--src/lib/util/tests/pid_file_unittest.cc206
-rw-r--r--src/lib/util/tests/range_utilities_unittest.cc50
-rw-r--r--src/lib/util/tests/readwrite_mutex_unittest.cc470
-rw-r--r--src/lib/util/tests/run_unittests.cc18
-rw-r--r--src/lib/util/tests/staged_value_unittest.cc106
-rw-r--r--src/lib/util/tests/state_model_unittest.cc916
-rw-r--r--src/lib/util/tests/stopwatch_unittest.cc301
-rw-r--r--src/lib/util/tests/strutil_unittest.cc642
-rw-r--r--src/lib/util/tests/thread_pool_unittest.cc661
-rw-r--r--src/lib/util/tests/time_utilities_unittest.cc155
-rw-r--r--src/lib/util/tests/triplet_unittest.cc125
-rw-r--r--src/lib/util/tests/unlock_guard_unittests.cc236
-rw-r--r--src/lib/util/tests/utf8_unittest.cc50
-rw-r--r--src/lib/util/tests/versioned_csv_file_unittest.cc501
-rw-r--r--src/lib/util/tests/watch_socket_unittests.cc263
-rw-r--r--src/lib/util/tests/watched_thread_unittest.cc218
39 files changed, 10190 insertions, 0 deletions
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
new file mode 100644
index 0000000..56aff6a
--- /dev/null
+++ b/src/lib/util/tests/Makefile.am
@@ -0,0 +1,74 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_builddir)\"
+# XXX: we'll pollute the top builddir for creating a temporary test file
+# used to bind a UNIX domain socket so we can minimize the risk of exceeding
+# the limit of file name path size.
+AM_CPPFLAGS += -DTEST_DATA_TOPBUILDDIR=\"$(abs_top_builddir)\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+# CSV files are created by unit tests for CSVFile class.
+CLEANFILES += *.csv
+
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += base32hex_unittest.cc
+run_unittests_SOURCES += base64_unittest.cc
+run_unittests_SOURCES += boost_time_utils_unittest.cc
+run_unittests_SOURCES += buffer_unittest.cc
+run_unittests_SOURCES += chrono_time_utils_unittest.cc
+run_unittests_SOURCES += csv_file_unittest.cc
+run_unittests_SOURCES += dhcp_space_unittest.cc
+run_unittests_SOURCES += doubles_unittest.cc
+run_unittests_SOURCES += fd_share_tests.cc
+run_unittests_SOURCES += fd_tests.cc
+run_unittests_SOURCES += file_utilities_unittest.cc
+run_unittests_SOURCES += filename_unittest.cc
+run_unittests_SOURCES += hash_unittest.cc
+run_unittests_SOURCES += hex_unittest.cc
+run_unittests_SOURCES += io_utilities_unittest.cc
+run_unittests_SOURCES += labeled_value_unittest.cc
+run_unittests_SOURCES += memory_segment_local_unittest.cc
+run_unittests_SOURCES += memory_segment_common_unittest.h
+run_unittests_SOURCES += memory_segment_common_unittest.cc
+run_unittests_SOURCES += multi_threading_mgr_unittest.cc
+run_unittests_SOURCES += optional_unittest.cc
+run_unittests_SOURCES += pid_file_unittest.cc
+run_unittests_SOURCES += staged_value_unittest.cc
+run_unittests_SOURCES += state_model_unittest.cc
+run_unittests_SOURCES += strutil_unittest.cc
+run_unittests_SOURCES += thread_pool_unittest.cc
+run_unittests_SOURCES += time_utilities_unittest.cc
+run_unittests_SOURCES += triplet_unittest.cc
+run_unittests_SOURCES += range_utilities_unittest.cc
+run_unittests_SOURCES += readwrite_mutex_unittest.cc
+run_unittests_SOURCES += stopwatch_unittest.cc
+run_unittests_SOURCES += unlock_guard_unittests.cc
+run_unittests_SOURCES += utf8_unittest.cc
+run_unittests_SOURCES += versioned_csv_file_unittest.cc
+run_unittests_SOURCES += watch_socket_unittests.cc
+run_unittests_SOURCES += watched_thread_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+run_unittests_LDADD = $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libkea-util-io.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+run_unittests_LDADD += $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/util/tests/Makefile.in b/src/lib/util/tests/Makefile.in
new file mode 100644
index 0000000..6924b4c
--- /dev/null
+++ b/src/lib/util/tests/Makefile.in
@@ -0,0 +1,1688 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+TESTS = $(am__EXEEXT_1)
+@HAVE_GTEST_TRUE@am__append_1 = run_unittests
+noinst_PROGRAMS = $(am__EXEEXT_2)
+subdir = src/lib/util/tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/ax_boost_for_kea.m4 \
+ $(top_srcdir)/m4macros/ax_cpp11.m4 \
+ $(top_srcdir)/m4macros/ax_crypto.m4 \
+ $(top_srcdir)/m4macros/ax_find_library.m4 \
+ $(top_srcdir)/m4macros/ax_gssapi.m4 \
+ $(top_srcdir)/m4macros/ax_gtest.m4 \
+ $(top_srcdir)/m4macros/ax_isc_rpath.m4 \
+ $(top_srcdir)/m4macros/ax_sysrepo.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT)
+am__EXEEXT_2 = $(am__EXEEXT_1)
+PROGRAMS = $(noinst_PROGRAMS)
+am__run_unittests_SOURCES_DIST = run_unittests.cc \
+ base32hex_unittest.cc base64_unittest.cc \
+ boost_time_utils_unittest.cc buffer_unittest.cc \
+ chrono_time_utils_unittest.cc csv_file_unittest.cc \
+ dhcp_space_unittest.cc doubles_unittest.cc fd_share_tests.cc \
+ fd_tests.cc file_utilities_unittest.cc filename_unittest.cc \
+ hash_unittest.cc hex_unittest.cc io_utilities_unittest.cc \
+ labeled_value_unittest.cc memory_segment_local_unittest.cc \
+ memory_segment_common_unittest.h \
+ memory_segment_common_unittest.cc \
+ multi_threading_mgr_unittest.cc optional_unittest.cc \
+ pid_file_unittest.cc staged_value_unittest.cc \
+ state_model_unittest.cc strutil_unittest.cc \
+ thread_pool_unittest.cc time_utilities_unittest.cc \
+ triplet_unittest.cc range_utilities_unittest.cc \
+ readwrite_mutex_unittest.cc stopwatch_unittest.cc \
+ unlock_guard_unittests.cc utf8_unittest.cc \
+ versioned_csv_file_unittest.cc watch_socket_unittests.cc \
+ watched_thread_unittest.cc
+@HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = \
+@HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-base32hex_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-base64_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-boost_time_utils_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-buffer_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-chrono_time_utils_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-csv_file_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-dhcp_space_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-doubles_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-fd_share_tests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-fd_tests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-file_utilities_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-filename_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-hash_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-hex_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-io_utilities_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-labeled_value_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-memory_segment_local_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-memory_segment_common_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-multi_threading_mgr_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-optional_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-pid_file_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-staged_value_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-state_model_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-strutil_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-thread_pool_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-time_utilities_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-triplet_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-range_utilities_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-readwrite_mutex_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-stopwatch_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-unlock_guard_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-utf8_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-versioned_csv_file_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-watch_socket_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@ run_unittests-watched_thread_unittest.$(OBJEXT)
+run_unittests_OBJECTS = $(am_run_unittests_OBJECTS)
+am__DEPENDENCIES_1 =
+@HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/io/libkea-util-io.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+run_unittests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(run_unittests_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/run_unittests-base32hex_unittest.Po \
+ ./$(DEPDIR)/run_unittests-base64_unittest.Po \
+ ./$(DEPDIR)/run_unittests-boost_time_utils_unittest.Po \
+ ./$(DEPDIR)/run_unittests-buffer_unittest.Po \
+ ./$(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po \
+ ./$(DEPDIR)/run_unittests-csv_file_unittest.Po \
+ ./$(DEPDIR)/run_unittests-dhcp_space_unittest.Po \
+ ./$(DEPDIR)/run_unittests-doubles_unittest.Po \
+ ./$(DEPDIR)/run_unittests-fd_share_tests.Po \
+ ./$(DEPDIR)/run_unittests-fd_tests.Po \
+ ./$(DEPDIR)/run_unittests-file_utilities_unittest.Po \
+ ./$(DEPDIR)/run_unittests-filename_unittest.Po \
+ ./$(DEPDIR)/run_unittests-hash_unittest.Po \
+ ./$(DEPDIR)/run_unittests-hex_unittest.Po \
+ ./$(DEPDIR)/run_unittests-io_utilities_unittest.Po \
+ ./$(DEPDIR)/run_unittests-labeled_value_unittest.Po \
+ ./$(DEPDIR)/run_unittests-memory_segment_common_unittest.Po \
+ ./$(DEPDIR)/run_unittests-memory_segment_local_unittest.Po \
+ ./$(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po \
+ ./$(DEPDIR)/run_unittests-optional_unittest.Po \
+ ./$(DEPDIR)/run_unittests-pid_file_unittest.Po \
+ ./$(DEPDIR)/run_unittests-range_utilities_unittest.Po \
+ ./$(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po \
+ ./$(DEPDIR)/run_unittests-run_unittests.Po \
+ ./$(DEPDIR)/run_unittests-staged_value_unittest.Po \
+ ./$(DEPDIR)/run_unittests-state_model_unittest.Po \
+ ./$(DEPDIR)/run_unittests-stopwatch_unittest.Po \
+ ./$(DEPDIR)/run_unittests-strutil_unittest.Po \
+ ./$(DEPDIR)/run_unittests-thread_pool_unittest.Po \
+ ./$(DEPDIR)/run_unittests-time_utilities_unittest.Po \
+ ./$(DEPDIR)/run_unittests-triplet_unittest.Po \
+ ./$(DEPDIR)/run_unittests-unlock_guard_unittests.Po \
+ ./$(DEPDIR)/run_unittests-utf8_unittest.Po \
+ ./$(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po \
+ ./$(DEPDIR)/run_unittests-watch_socket_unittests.Po \
+ ./$(DEPDIR)/run_unittests-watched_thread_unittest.Po
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(run_unittests_SOURCES)
+DIST_SOURCES = $(am__run_unittests_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ASCIIDOC = @ASCIIDOC@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_INCLUDES = @BOOST_INCLUDES@
+BOOST_LIBS = @BOOST_LIBS@
+BOTAN_TOOL = @BOTAN_TOOL@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONTRIB_DIR = @CONTRIB_DIR@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPTO_CFLAGS = @CRYPTO_CFLAGS@
+CRYPTO_INCLUDES = @CRYPTO_INCLUDES@
+CRYPTO_LDFLAGS = @CRYPTO_LDFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPTO_PACKAGE = @CRYPTO_PACKAGE@
+CRYPTO_RPATH = @CRYPTO_RPATH@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_BOOST_CONFIGURE_FLAG = @DISTCHECK_BOOST_CONFIGURE_FLAG@
+DISTCHECK_CONTRIB_CONFIGURE_FLAG = @DISTCHECK_CONTRIB_CONFIGURE_FLAG@
+DISTCHECK_CRYPTO_CONFIGURE_FLAG = @DISTCHECK_CRYPTO_CONFIGURE_FLAG@
+DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@
+DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@
+DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@
+DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@
+DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GENHTML = @GENHTML@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+GTEST_CONFIG = @GTEST_CONFIG@
+GTEST_INCLUDES = @GTEST_INCLUDES@
+GTEST_LDADD = @GTEST_LDADD@
+GTEST_LDFLAGS = @GTEST_LDFLAGS@
+GTEST_SOURCE = @GTEST_SOURCE@
+HAVE_SYSREPO = @HAVE_SYSREPO@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KEA_CXXFLAGS = @KEA_CXXFLAGS@
+KEA_SRCID = @KEA_SRCID@
+KRB5_CONFIG = @KRB5_CONFIG@
+LCOV = @LCOV@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOG4CPLUS_INCLUDES = @LOG4CPLUS_INCLUDES@
+LOG4CPLUS_LIBS = @LOG4CPLUS_LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_TYPE = @PACKAGE_VERSION_TYPE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PDFLATEX = @PDFLATEX@
+PERL = @PERL@
+PGSQL_CPPFLAGS = @PGSQL_CPPFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKGPYTHONDIR = @PKGPYTHONDIR@
+PKG_CONFIG = @PKG_CONFIG@
+PLANTUML = @PLANTUML@
+PREMIUM_DIR = @PREMIUM_DIR@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SEP = @SEP@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINXBUILD = @SPHINXBUILD@
+SRPD_PLUGINS_PATH = @SRPD_PLUGINS_PATH@
+SR_REPO_PATH = @SR_REPO_PATH@
+STRIP = @STRIP@
+SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@
+SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@
+SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@
+SYSREPO_LIBS = @SYSREPO_LIBS@
+SYSREPO_VERSION = @SYSREPO_VERSION@
+USE_LCOV = @USE_LCOV@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+WARNING_GCC_44_STRICT_ALIASING_CFLAG = @WARNING_GCC_44_STRICT_ALIASING_CFLAG@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = .
+# XXX: we'll pollute the top builddir for creating a temporary test file
+# used to bind a UNIX domain socket so we can minimize the risk of exceeding
+# the limit of file name path size.
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \
+ $(BOOST_INCLUDES) -DTEST_DATA_BUILDDIR=\"$(abs_builddir)\" \
+ -DTEST_DATA_TOPBUILDDIR=\"$(abs_top_builddir)\"
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static
+# CSV files are created by unit tests for CSVFile class.
+CLEANFILES = *.gcno *.gcda *.csv
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+@HAVE_GTEST_TRUE@run_unittests_SOURCES = run_unittests.cc \
+@HAVE_GTEST_TRUE@ base32hex_unittest.cc base64_unittest.cc \
+@HAVE_GTEST_TRUE@ boost_time_utils_unittest.cc \
+@HAVE_GTEST_TRUE@ buffer_unittest.cc \
+@HAVE_GTEST_TRUE@ chrono_time_utils_unittest.cc \
+@HAVE_GTEST_TRUE@ csv_file_unittest.cc dhcp_space_unittest.cc \
+@HAVE_GTEST_TRUE@ doubles_unittest.cc fd_share_tests.cc \
+@HAVE_GTEST_TRUE@ fd_tests.cc file_utilities_unittest.cc \
+@HAVE_GTEST_TRUE@ filename_unittest.cc hash_unittest.cc \
+@HAVE_GTEST_TRUE@ hex_unittest.cc io_utilities_unittest.cc \
+@HAVE_GTEST_TRUE@ labeled_value_unittest.cc \
+@HAVE_GTEST_TRUE@ memory_segment_local_unittest.cc \
+@HAVE_GTEST_TRUE@ memory_segment_common_unittest.h \
+@HAVE_GTEST_TRUE@ memory_segment_common_unittest.cc \
+@HAVE_GTEST_TRUE@ multi_threading_mgr_unittest.cc \
+@HAVE_GTEST_TRUE@ optional_unittest.cc pid_file_unittest.cc \
+@HAVE_GTEST_TRUE@ staged_value_unittest.cc \
+@HAVE_GTEST_TRUE@ state_model_unittest.cc strutil_unittest.cc \
+@HAVE_GTEST_TRUE@ thread_pool_unittest.cc \
+@HAVE_GTEST_TRUE@ time_utilities_unittest.cc \
+@HAVE_GTEST_TRUE@ triplet_unittest.cc \
+@HAVE_GTEST_TRUE@ range_utilities_unittest.cc \
+@HAVE_GTEST_TRUE@ readwrite_mutex_unittest.cc \
+@HAVE_GTEST_TRUE@ stopwatch_unittest.cc \
+@HAVE_GTEST_TRUE@ unlock_guard_unittests.cc utf8_unittest.cc \
+@HAVE_GTEST_TRUE@ versioned_csv_file_unittest.cc \
+@HAVE_GTEST_TRUE@ watch_socket_unittests.cc \
+@HAVE_GTEST_TRUE@ watched_thread_unittest.cc
+@HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+@HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+@HAVE_GTEST_TRUE@run_unittests_LDADD = $(top_builddir)/src/lib/util/unittests/libutil_unittests.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/io/libkea-util-io.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/libkea-util.la \
+@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/exceptions/libkea-exceptions.la \
+@HAVE_GTEST_TRUE@ $(GTEST_LDADD)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/util/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib/util/tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+run_unittests$(EXEEXT): $(run_unittests_OBJECTS) $(run_unittests_DEPENDENCIES) $(EXTRA_run_unittests_DEPENDENCIES)
+ @rm -f run_unittests$(EXEEXT)
+ $(AM_V_CXXLD)$(run_unittests_LINK) $(run_unittests_OBJECTS) $(run_unittests_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-base32hex_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-base64_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-boost_time_utils_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-buffer_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-csv_file_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-dhcp_space_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-doubles_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-fd_share_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-fd_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-file_utilities_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-filename_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-hash_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-hex_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-io_utilities_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-labeled_value_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-memory_segment_common_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-memory_segment_local_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-optional_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-pid_file_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-range_utilities_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-staged_value_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-state_model_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-stopwatch_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-strutil_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-thread_pool_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-time_utilities_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-triplet_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-unlock_guard_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-utf8_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-watch_socket_unittests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-watched_thread_unittest.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+run_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+run_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+
+run_unittests-base32hex_unittest.o: base32hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-base32hex_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-base32hex_unittest.Tpo -c -o run_unittests-base32hex_unittest.o `test -f 'base32hex_unittest.cc' || echo '$(srcdir)/'`base32hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-base32hex_unittest.Tpo $(DEPDIR)/run_unittests-base32hex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base32hex_unittest.cc' object='run_unittests-base32hex_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-base32hex_unittest.o `test -f 'base32hex_unittest.cc' || echo '$(srcdir)/'`base32hex_unittest.cc
+
+run_unittests-base32hex_unittest.obj: base32hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-base32hex_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-base32hex_unittest.Tpo -c -o run_unittests-base32hex_unittest.obj `if test -f 'base32hex_unittest.cc'; then $(CYGPATH_W) 'base32hex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/base32hex_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-base32hex_unittest.Tpo $(DEPDIR)/run_unittests-base32hex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base32hex_unittest.cc' object='run_unittests-base32hex_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-base32hex_unittest.obj `if test -f 'base32hex_unittest.cc'; then $(CYGPATH_W) 'base32hex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/base32hex_unittest.cc'; fi`
+
+run_unittests-base64_unittest.o: base64_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-base64_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-base64_unittest.Tpo -c -o run_unittests-base64_unittest.o `test -f 'base64_unittest.cc' || echo '$(srcdir)/'`base64_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-base64_unittest.Tpo $(DEPDIR)/run_unittests-base64_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_unittest.cc' object='run_unittests-base64_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-base64_unittest.o `test -f 'base64_unittest.cc' || echo '$(srcdir)/'`base64_unittest.cc
+
+run_unittests-base64_unittest.obj: base64_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-base64_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-base64_unittest.Tpo -c -o run_unittests-base64_unittest.obj `if test -f 'base64_unittest.cc'; then $(CYGPATH_W) 'base64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/base64_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-base64_unittest.Tpo $(DEPDIR)/run_unittests-base64_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_unittest.cc' object='run_unittests-base64_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-base64_unittest.obj `if test -f 'base64_unittest.cc'; then $(CYGPATH_W) 'base64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/base64_unittest.cc'; fi`
+
+run_unittests-boost_time_utils_unittest.o: boost_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-boost_time_utils_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-boost_time_utils_unittest.Tpo -c -o run_unittests-boost_time_utils_unittest.o `test -f 'boost_time_utils_unittest.cc' || echo '$(srcdir)/'`boost_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-boost_time_utils_unittest.Tpo $(DEPDIR)/run_unittests-boost_time_utils_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='boost_time_utils_unittest.cc' object='run_unittests-boost_time_utils_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-boost_time_utils_unittest.o `test -f 'boost_time_utils_unittest.cc' || echo '$(srcdir)/'`boost_time_utils_unittest.cc
+
+run_unittests-boost_time_utils_unittest.obj: boost_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-boost_time_utils_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-boost_time_utils_unittest.Tpo -c -o run_unittests-boost_time_utils_unittest.obj `if test -f 'boost_time_utils_unittest.cc'; then $(CYGPATH_W) 'boost_time_utils_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/boost_time_utils_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-boost_time_utils_unittest.Tpo $(DEPDIR)/run_unittests-boost_time_utils_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='boost_time_utils_unittest.cc' object='run_unittests-boost_time_utils_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-boost_time_utils_unittest.obj `if test -f 'boost_time_utils_unittest.cc'; then $(CYGPATH_W) 'boost_time_utils_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/boost_time_utils_unittest.cc'; fi`
+
+run_unittests-buffer_unittest.o: buffer_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-buffer_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-buffer_unittest.Tpo -c -o run_unittests-buffer_unittest.o `test -f 'buffer_unittest.cc' || echo '$(srcdir)/'`buffer_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-buffer_unittest.Tpo $(DEPDIR)/run_unittests-buffer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='buffer_unittest.cc' object='run_unittests-buffer_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-buffer_unittest.o `test -f 'buffer_unittest.cc' || echo '$(srcdir)/'`buffer_unittest.cc
+
+run_unittests-buffer_unittest.obj: buffer_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-buffer_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-buffer_unittest.Tpo -c -o run_unittests-buffer_unittest.obj `if test -f 'buffer_unittest.cc'; then $(CYGPATH_W) 'buffer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/buffer_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-buffer_unittest.Tpo $(DEPDIR)/run_unittests-buffer_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='buffer_unittest.cc' object='run_unittests-buffer_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-buffer_unittest.obj `if test -f 'buffer_unittest.cc'; then $(CYGPATH_W) 'buffer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/buffer_unittest.cc'; fi`
+
+run_unittests-chrono_time_utils_unittest.o: chrono_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-chrono_time_utils_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Tpo -c -o run_unittests-chrono_time_utils_unittest.o `test -f 'chrono_time_utils_unittest.cc' || echo '$(srcdir)/'`chrono_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Tpo $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='chrono_time_utils_unittest.cc' object='run_unittests-chrono_time_utils_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-chrono_time_utils_unittest.o `test -f 'chrono_time_utils_unittest.cc' || echo '$(srcdir)/'`chrono_time_utils_unittest.cc
+
+run_unittests-chrono_time_utils_unittest.obj: chrono_time_utils_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-chrono_time_utils_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Tpo -c -o run_unittests-chrono_time_utils_unittest.obj `if test -f 'chrono_time_utils_unittest.cc'; then $(CYGPATH_W) 'chrono_time_utils_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/chrono_time_utils_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Tpo $(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='chrono_time_utils_unittest.cc' object='run_unittests-chrono_time_utils_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-chrono_time_utils_unittest.obj `if test -f 'chrono_time_utils_unittest.cc'; then $(CYGPATH_W) 'chrono_time_utils_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/chrono_time_utils_unittest.cc'; fi`
+
+run_unittests-csv_file_unittest.o: csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-csv_file_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-csv_file_unittest.Tpo -c -o run_unittests-csv_file_unittest.o `test -f 'csv_file_unittest.cc' || echo '$(srcdir)/'`csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-csv_file_unittest.Tpo $(DEPDIR)/run_unittests-csv_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_file_unittest.cc' object='run_unittests-csv_file_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-csv_file_unittest.o `test -f 'csv_file_unittest.cc' || echo '$(srcdir)/'`csv_file_unittest.cc
+
+run_unittests-csv_file_unittest.obj: csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-csv_file_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-csv_file_unittest.Tpo -c -o run_unittests-csv_file_unittest.obj `if test -f 'csv_file_unittest.cc'; then $(CYGPATH_W) 'csv_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/csv_file_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-csv_file_unittest.Tpo $(DEPDIR)/run_unittests-csv_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_file_unittest.cc' object='run_unittests-csv_file_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-csv_file_unittest.obj `if test -f 'csv_file_unittest.cc'; then $(CYGPATH_W) 'csv_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/csv_file_unittest.cc'; fi`
+
+run_unittests-dhcp_space_unittest.o: dhcp_space_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-dhcp_space_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-dhcp_space_unittest.Tpo -c -o run_unittests-dhcp_space_unittest.o `test -f 'dhcp_space_unittest.cc' || echo '$(srcdir)/'`dhcp_space_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-dhcp_space_unittest.Tpo $(DEPDIR)/run_unittests-dhcp_space_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dhcp_space_unittest.cc' object='run_unittests-dhcp_space_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-dhcp_space_unittest.o `test -f 'dhcp_space_unittest.cc' || echo '$(srcdir)/'`dhcp_space_unittest.cc
+
+run_unittests-dhcp_space_unittest.obj: dhcp_space_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-dhcp_space_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-dhcp_space_unittest.Tpo -c -o run_unittests-dhcp_space_unittest.obj `if test -f 'dhcp_space_unittest.cc'; then $(CYGPATH_W) 'dhcp_space_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/dhcp_space_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-dhcp_space_unittest.Tpo $(DEPDIR)/run_unittests-dhcp_space_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dhcp_space_unittest.cc' object='run_unittests-dhcp_space_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-dhcp_space_unittest.obj `if test -f 'dhcp_space_unittest.cc'; then $(CYGPATH_W) 'dhcp_space_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/dhcp_space_unittest.cc'; fi`
+
+run_unittests-doubles_unittest.o: doubles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-doubles_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-doubles_unittest.Tpo -c -o run_unittests-doubles_unittest.o `test -f 'doubles_unittest.cc' || echo '$(srcdir)/'`doubles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-doubles_unittest.Tpo $(DEPDIR)/run_unittests-doubles_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='doubles_unittest.cc' object='run_unittests-doubles_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-doubles_unittest.o `test -f 'doubles_unittest.cc' || echo '$(srcdir)/'`doubles_unittest.cc
+
+run_unittests-doubles_unittest.obj: doubles_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-doubles_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-doubles_unittest.Tpo -c -o run_unittests-doubles_unittest.obj `if test -f 'doubles_unittest.cc'; then $(CYGPATH_W) 'doubles_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/doubles_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-doubles_unittest.Tpo $(DEPDIR)/run_unittests-doubles_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='doubles_unittest.cc' object='run_unittests-doubles_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-doubles_unittest.obj `if test -f 'doubles_unittest.cc'; then $(CYGPATH_W) 'doubles_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/doubles_unittest.cc'; fi`
+
+run_unittests-fd_share_tests.o: fd_share_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-fd_share_tests.o -MD -MP -MF $(DEPDIR)/run_unittests-fd_share_tests.Tpo -c -o run_unittests-fd_share_tests.o `test -f 'fd_share_tests.cc' || echo '$(srcdir)/'`fd_share_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-fd_share_tests.Tpo $(DEPDIR)/run_unittests-fd_share_tests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fd_share_tests.cc' object='run_unittests-fd_share_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-fd_share_tests.o `test -f 'fd_share_tests.cc' || echo '$(srcdir)/'`fd_share_tests.cc
+
+run_unittests-fd_share_tests.obj: fd_share_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-fd_share_tests.obj -MD -MP -MF $(DEPDIR)/run_unittests-fd_share_tests.Tpo -c -o run_unittests-fd_share_tests.obj `if test -f 'fd_share_tests.cc'; then $(CYGPATH_W) 'fd_share_tests.cc'; else $(CYGPATH_W) '$(srcdir)/fd_share_tests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-fd_share_tests.Tpo $(DEPDIR)/run_unittests-fd_share_tests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fd_share_tests.cc' object='run_unittests-fd_share_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-fd_share_tests.obj `if test -f 'fd_share_tests.cc'; then $(CYGPATH_W) 'fd_share_tests.cc'; else $(CYGPATH_W) '$(srcdir)/fd_share_tests.cc'; fi`
+
+run_unittests-fd_tests.o: fd_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-fd_tests.o -MD -MP -MF $(DEPDIR)/run_unittests-fd_tests.Tpo -c -o run_unittests-fd_tests.o `test -f 'fd_tests.cc' || echo '$(srcdir)/'`fd_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-fd_tests.Tpo $(DEPDIR)/run_unittests-fd_tests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fd_tests.cc' object='run_unittests-fd_tests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-fd_tests.o `test -f 'fd_tests.cc' || echo '$(srcdir)/'`fd_tests.cc
+
+run_unittests-fd_tests.obj: fd_tests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-fd_tests.obj -MD -MP -MF $(DEPDIR)/run_unittests-fd_tests.Tpo -c -o run_unittests-fd_tests.obj `if test -f 'fd_tests.cc'; then $(CYGPATH_W) 'fd_tests.cc'; else $(CYGPATH_W) '$(srcdir)/fd_tests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-fd_tests.Tpo $(DEPDIR)/run_unittests-fd_tests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='fd_tests.cc' object='run_unittests-fd_tests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-fd_tests.obj `if test -f 'fd_tests.cc'; then $(CYGPATH_W) 'fd_tests.cc'; else $(CYGPATH_W) '$(srcdir)/fd_tests.cc'; fi`
+
+run_unittests-file_utilities_unittest.o: file_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-file_utilities_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-file_utilities_unittest.Tpo -c -o run_unittests-file_utilities_unittest.o `test -f 'file_utilities_unittest.cc' || echo '$(srcdir)/'`file_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-file_utilities_unittest.Tpo $(DEPDIR)/run_unittests-file_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='file_utilities_unittest.cc' object='run_unittests-file_utilities_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-file_utilities_unittest.o `test -f 'file_utilities_unittest.cc' || echo '$(srcdir)/'`file_utilities_unittest.cc
+
+run_unittests-file_utilities_unittest.obj: file_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-file_utilities_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-file_utilities_unittest.Tpo -c -o run_unittests-file_utilities_unittest.obj `if test -f 'file_utilities_unittest.cc'; then $(CYGPATH_W) 'file_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/file_utilities_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-file_utilities_unittest.Tpo $(DEPDIR)/run_unittests-file_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='file_utilities_unittest.cc' object='run_unittests-file_utilities_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-file_utilities_unittest.obj `if test -f 'file_utilities_unittest.cc'; then $(CYGPATH_W) 'file_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/file_utilities_unittest.cc'; fi`
+
+run_unittests-filename_unittest.o: filename_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-filename_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-filename_unittest.Tpo -c -o run_unittests-filename_unittest.o `test -f 'filename_unittest.cc' || echo '$(srcdir)/'`filename_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-filename_unittest.Tpo $(DEPDIR)/run_unittests-filename_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='filename_unittest.cc' object='run_unittests-filename_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-filename_unittest.o `test -f 'filename_unittest.cc' || echo '$(srcdir)/'`filename_unittest.cc
+
+run_unittests-filename_unittest.obj: filename_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-filename_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-filename_unittest.Tpo -c -o run_unittests-filename_unittest.obj `if test -f 'filename_unittest.cc'; then $(CYGPATH_W) 'filename_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/filename_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-filename_unittest.Tpo $(DEPDIR)/run_unittests-filename_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='filename_unittest.cc' object='run_unittests-filename_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-filename_unittest.obj `if test -f 'filename_unittest.cc'; then $(CYGPATH_W) 'filename_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/filename_unittest.cc'; fi`
+
+run_unittests-hash_unittest.o: hash_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hash_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-hash_unittest.Tpo -c -o run_unittests-hash_unittest.o `test -f 'hash_unittest.cc' || echo '$(srcdir)/'`hash_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hash_unittest.Tpo $(DEPDIR)/run_unittests-hash_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hash_unittest.cc' object='run_unittests-hash_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hash_unittest.o `test -f 'hash_unittest.cc' || echo '$(srcdir)/'`hash_unittest.cc
+
+run_unittests-hash_unittest.obj: hash_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hash_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-hash_unittest.Tpo -c -o run_unittests-hash_unittest.obj `if test -f 'hash_unittest.cc'; then $(CYGPATH_W) 'hash_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hash_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hash_unittest.Tpo $(DEPDIR)/run_unittests-hash_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hash_unittest.cc' object='run_unittests-hash_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hash_unittest.obj `if test -f 'hash_unittest.cc'; then $(CYGPATH_W) 'hash_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hash_unittest.cc'; fi`
+
+run_unittests-hex_unittest.o: hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hex_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-hex_unittest.Tpo -c -o run_unittests-hex_unittest.o `test -f 'hex_unittest.cc' || echo '$(srcdir)/'`hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hex_unittest.Tpo $(DEPDIR)/run_unittests-hex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hex_unittest.cc' object='run_unittests-hex_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hex_unittest.o `test -f 'hex_unittest.cc' || echo '$(srcdir)/'`hex_unittest.cc
+
+run_unittests-hex_unittest.obj: hex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-hex_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-hex_unittest.Tpo -c -o run_unittests-hex_unittest.obj `if test -f 'hex_unittest.cc'; then $(CYGPATH_W) 'hex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hex_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-hex_unittest.Tpo $(DEPDIR)/run_unittests-hex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='hex_unittest.cc' object='run_unittests-hex_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-hex_unittest.obj `if test -f 'hex_unittest.cc'; then $(CYGPATH_W) 'hex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/hex_unittest.cc'; fi`
+
+run_unittests-io_utilities_unittest.o: io_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_utilities_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-io_utilities_unittest.Tpo -c -o run_unittests-io_utilities_unittest.o `test -f 'io_utilities_unittest.cc' || echo '$(srcdir)/'`io_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_utilities_unittest.Tpo $(DEPDIR)/run_unittests-io_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_utilities_unittest.cc' object='run_unittests-io_utilities_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_utilities_unittest.o `test -f 'io_utilities_unittest.cc' || echo '$(srcdir)/'`io_utilities_unittest.cc
+
+run_unittests-io_utilities_unittest.obj: io_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-io_utilities_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-io_utilities_unittest.Tpo -c -o run_unittests-io_utilities_unittest.obj `if test -f 'io_utilities_unittest.cc'; then $(CYGPATH_W) 'io_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_utilities_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-io_utilities_unittest.Tpo $(DEPDIR)/run_unittests-io_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='io_utilities_unittest.cc' object='run_unittests-io_utilities_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-io_utilities_unittest.obj `if test -f 'io_utilities_unittest.cc'; then $(CYGPATH_W) 'io_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/io_utilities_unittest.cc'; fi`
+
+run_unittests-labeled_value_unittest.o: labeled_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-labeled_value_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-labeled_value_unittest.Tpo -c -o run_unittests-labeled_value_unittest.o `test -f 'labeled_value_unittest.cc' || echo '$(srcdir)/'`labeled_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-labeled_value_unittest.Tpo $(DEPDIR)/run_unittests-labeled_value_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='labeled_value_unittest.cc' object='run_unittests-labeled_value_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-labeled_value_unittest.o `test -f 'labeled_value_unittest.cc' || echo '$(srcdir)/'`labeled_value_unittest.cc
+
+run_unittests-labeled_value_unittest.obj: labeled_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-labeled_value_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-labeled_value_unittest.Tpo -c -o run_unittests-labeled_value_unittest.obj `if test -f 'labeled_value_unittest.cc'; then $(CYGPATH_W) 'labeled_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/labeled_value_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-labeled_value_unittest.Tpo $(DEPDIR)/run_unittests-labeled_value_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='labeled_value_unittest.cc' object='run_unittests-labeled_value_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-labeled_value_unittest.obj `if test -f 'labeled_value_unittest.cc'; then $(CYGPATH_W) 'labeled_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/labeled_value_unittest.cc'; fi`
+
+run_unittests-memory_segment_local_unittest.o: memory_segment_local_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-memory_segment_local_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-memory_segment_local_unittest.Tpo -c -o run_unittests-memory_segment_local_unittest.o `test -f 'memory_segment_local_unittest.cc' || echo '$(srcdir)/'`memory_segment_local_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-memory_segment_local_unittest.Tpo $(DEPDIR)/run_unittests-memory_segment_local_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='memory_segment_local_unittest.cc' object='run_unittests-memory_segment_local_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-memory_segment_local_unittest.o `test -f 'memory_segment_local_unittest.cc' || echo '$(srcdir)/'`memory_segment_local_unittest.cc
+
+run_unittests-memory_segment_local_unittest.obj: memory_segment_local_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-memory_segment_local_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-memory_segment_local_unittest.Tpo -c -o run_unittests-memory_segment_local_unittest.obj `if test -f 'memory_segment_local_unittest.cc'; then $(CYGPATH_W) 'memory_segment_local_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/memory_segment_local_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-memory_segment_local_unittest.Tpo $(DEPDIR)/run_unittests-memory_segment_local_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='memory_segment_local_unittest.cc' object='run_unittests-memory_segment_local_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-memory_segment_local_unittest.obj `if test -f 'memory_segment_local_unittest.cc'; then $(CYGPATH_W) 'memory_segment_local_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/memory_segment_local_unittest.cc'; fi`
+
+run_unittests-memory_segment_common_unittest.o: memory_segment_common_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-memory_segment_common_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-memory_segment_common_unittest.Tpo -c -o run_unittests-memory_segment_common_unittest.o `test -f 'memory_segment_common_unittest.cc' || echo '$(srcdir)/'`memory_segment_common_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-memory_segment_common_unittest.Tpo $(DEPDIR)/run_unittests-memory_segment_common_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='memory_segment_common_unittest.cc' object='run_unittests-memory_segment_common_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-memory_segment_common_unittest.o `test -f 'memory_segment_common_unittest.cc' || echo '$(srcdir)/'`memory_segment_common_unittest.cc
+
+run_unittests-memory_segment_common_unittest.obj: memory_segment_common_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-memory_segment_common_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-memory_segment_common_unittest.Tpo -c -o run_unittests-memory_segment_common_unittest.obj `if test -f 'memory_segment_common_unittest.cc'; then $(CYGPATH_W) 'memory_segment_common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/memory_segment_common_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-memory_segment_common_unittest.Tpo $(DEPDIR)/run_unittests-memory_segment_common_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='memory_segment_common_unittest.cc' object='run_unittests-memory_segment_common_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-memory_segment_common_unittest.obj `if test -f 'memory_segment_common_unittest.cc'; then $(CYGPATH_W) 'memory_segment_common_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/memory_segment_common_unittest.cc'; fi`
+
+run_unittests-multi_threading_mgr_unittest.o: multi_threading_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-multi_threading_mgr_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Tpo -c -o run_unittests-multi_threading_mgr_unittest.o `test -f 'multi_threading_mgr_unittest.cc' || echo '$(srcdir)/'`multi_threading_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Tpo $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='multi_threading_mgr_unittest.cc' object='run_unittests-multi_threading_mgr_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-multi_threading_mgr_unittest.o `test -f 'multi_threading_mgr_unittest.cc' || echo '$(srcdir)/'`multi_threading_mgr_unittest.cc
+
+run_unittests-multi_threading_mgr_unittest.obj: multi_threading_mgr_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-multi_threading_mgr_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Tpo -c -o run_unittests-multi_threading_mgr_unittest.obj `if test -f 'multi_threading_mgr_unittest.cc'; then $(CYGPATH_W) 'multi_threading_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/multi_threading_mgr_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Tpo $(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='multi_threading_mgr_unittest.cc' object='run_unittests-multi_threading_mgr_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-multi_threading_mgr_unittest.obj `if test -f 'multi_threading_mgr_unittest.cc'; then $(CYGPATH_W) 'multi_threading_mgr_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/multi_threading_mgr_unittest.cc'; fi`
+
+run_unittests-optional_unittest.o: optional_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-optional_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-optional_unittest.Tpo -c -o run_unittests-optional_unittest.o `test -f 'optional_unittest.cc' || echo '$(srcdir)/'`optional_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-optional_unittest.Tpo $(DEPDIR)/run_unittests-optional_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='optional_unittest.cc' object='run_unittests-optional_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-optional_unittest.o `test -f 'optional_unittest.cc' || echo '$(srcdir)/'`optional_unittest.cc
+
+run_unittests-optional_unittest.obj: optional_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-optional_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-optional_unittest.Tpo -c -o run_unittests-optional_unittest.obj `if test -f 'optional_unittest.cc'; then $(CYGPATH_W) 'optional_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/optional_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-optional_unittest.Tpo $(DEPDIR)/run_unittests-optional_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='optional_unittest.cc' object='run_unittests-optional_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-optional_unittest.obj `if test -f 'optional_unittest.cc'; then $(CYGPATH_W) 'optional_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/optional_unittest.cc'; fi`
+
+run_unittests-pid_file_unittest.o: pid_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-pid_file_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-pid_file_unittest.Tpo -c -o run_unittests-pid_file_unittest.o `test -f 'pid_file_unittest.cc' || echo '$(srcdir)/'`pid_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-pid_file_unittest.Tpo $(DEPDIR)/run_unittests-pid_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pid_file_unittest.cc' object='run_unittests-pid_file_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-pid_file_unittest.o `test -f 'pid_file_unittest.cc' || echo '$(srcdir)/'`pid_file_unittest.cc
+
+run_unittests-pid_file_unittest.obj: pid_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-pid_file_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-pid_file_unittest.Tpo -c -o run_unittests-pid_file_unittest.obj `if test -f 'pid_file_unittest.cc'; then $(CYGPATH_W) 'pid_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pid_file_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-pid_file_unittest.Tpo $(DEPDIR)/run_unittests-pid_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pid_file_unittest.cc' object='run_unittests-pid_file_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-pid_file_unittest.obj `if test -f 'pid_file_unittest.cc'; then $(CYGPATH_W) 'pid_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/pid_file_unittest.cc'; fi`
+
+run_unittests-staged_value_unittest.o: staged_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-staged_value_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-staged_value_unittest.Tpo -c -o run_unittests-staged_value_unittest.o `test -f 'staged_value_unittest.cc' || echo '$(srcdir)/'`staged_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-staged_value_unittest.Tpo $(DEPDIR)/run_unittests-staged_value_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='staged_value_unittest.cc' object='run_unittests-staged_value_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-staged_value_unittest.o `test -f 'staged_value_unittest.cc' || echo '$(srcdir)/'`staged_value_unittest.cc
+
+run_unittests-staged_value_unittest.obj: staged_value_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-staged_value_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-staged_value_unittest.Tpo -c -o run_unittests-staged_value_unittest.obj `if test -f 'staged_value_unittest.cc'; then $(CYGPATH_W) 'staged_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/staged_value_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-staged_value_unittest.Tpo $(DEPDIR)/run_unittests-staged_value_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='staged_value_unittest.cc' object='run_unittests-staged_value_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-staged_value_unittest.obj `if test -f 'staged_value_unittest.cc'; then $(CYGPATH_W) 'staged_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/staged_value_unittest.cc'; fi`
+
+run_unittests-state_model_unittest.o: state_model_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-state_model_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-state_model_unittest.Tpo -c -o run_unittests-state_model_unittest.o `test -f 'state_model_unittest.cc' || echo '$(srcdir)/'`state_model_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-state_model_unittest.Tpo $(DEPDIR)/run_unittests-state_model_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='state_model_unittest.cc' object='run_unittests-state_model_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-state_model_unittest.o `test -f 'state_model_unittest.cc' || echo '$(srcdir)/'`state_model_unittest.cc
+
+run_unittests-state_model_unittest.obj: state_model_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-state_model_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-state_model_unittest.Tpo -c -o run_unittests-state_model_unittest.obj `if test -f 'state_model_unittest.cc'; then $(CYGPATH_W) 'state_model_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/state_model_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-state_model_unittest.Tpo $(DEPDIR)/run_unittests-state_model_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='state_model_unittest.cc' object='run_unittests-state_model_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-state_model_unittest.obj `if test -f 'state_model_unittest.cc'; then $(CYGPATH_W) 'state_model_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/state_model_unittest.cc'; fi`
+
+run_unittests-strutil_unittest.o: strutil_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-strutil_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-strutil_unittest.Tpo -c -o run_unittests-strutil_unittest.o `test -f 'strutil_unittest.cc' || echo '$(srcdir)/'`strutil_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-strutil_unittest.Tpo $(DEPDIR)/run_unittests-strutil_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='strutil_unittest.cc' object='run_unittests-strutil_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-strutil_unittest.o `test -f 'strutil_unittest.cc' || echo '$(srcdir)/'`strutil_unittest.cc
+
+run_unittests-strutil_unittest.obj: strutil_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-strutil_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-strutil_unittest.Tpo -c -o run_unittests-strutil_unittest.obj `if test -f 'strutil_unittest.cc'; then $(CYGPATH_W) 'strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/strutil_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-strutil_unittest.Tpo $(DEPDIR)/run_unittests-strutil_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='strutil_unittest.cc' object='run_unittests-strutil_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-strutil_unittest.obj `if test -f 'strutil_unittest.cc'; then $(CYGPATH_W) 'strutil_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/strutil_unittest.cc'; fi`
+
+run_unittests-thread_pool_unittest.o: thread_pool_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-thread_pool_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-thread_pool_unittest.Tpo -c -o run_unittests-thread_pool_unittest.o `test -f 'thread_pool_unittest.cc' || echo '$(srcdir)/'`thread_pool_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-thread_pool_unittest.Tpo $(DEPDIR)/run_unittests-thread_pool_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thread_pool_unittest.cc' object='run_unittests-thread_pool_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-thread_pool_unittest.o `test -f 'thread_pool_unittest.cc' || echo '$(srcdir)/'`thread_pool_unittest.cc
+
+run_unittests-thread_pool_unittest.obj: thread_pool_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-thread_pool_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-thread_pool_unittest.Tpo -c -o run_unittests-thread_pool_unittest.obj `if test -f 'thread_pool_unittest.cc'; then $(CYGPATH_W) 'thread_pool_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/thread_pool_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-thread_pool_unittest.Tpo $(DEPDIR)/run_unittests-thread_pool_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thread_pool_unittest.cc' object='run_unittests-thread_pool_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-thread_pool_unittest.obj `if test -f 'thread_pool_unittest.cc'; then $(CYGPATH_W) 'thread_pool_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/thread_pool_unittest.cc'; fi`
+
+run_unittests-time_utilities_unittest.o: time_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-time_utilities_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-time_utilities_unittest.Tpo -c -o run_unittests-time_utilities_unittest.o `test -f 'time_utilities_unittest.cc' || echo '$(srcdir)/'`time_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-time_utilities_unittest.Tpo $(DEPDIR)/run_unittests-time_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='time_utilities_unittest.cc' object='run_unittests-time_utilities_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-time_utilities_unittest.o `test -f 'time_utilities_unittest.cc' || echo '$(srcdir)/'`time_utilities_unittest.cc
+
+run_unittests-time_utilities_unittest.obj: time_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-time_utilities_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-time_utilities_unittest.Tpo -c -o run_unittests-time_utilities_unittest.obj `if test -f 'time_utilities_unittest.cc'; then $(CYGPATH_W) 'time_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/time_utilities_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-time_utilities_unittest.Tpo $(DEPDIR)/run_unittests-time_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='time_utilities_unittest.cc' object='run_unittests-time_utilities_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-time_utilities_unittest.obj `if test -f 'time_utilities_unittest.cc'; then $(CYGPATH_W) 'time_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/time_utilities_unittest.cc'; fi`
+
+run_unittests-triplet_unittest.o: triplet_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-triplet_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-triplet_unittest.Tpo -c -o run_unittests-triplet_unittest.o `test -f 'triplet_unittest.cc' || echo '$(srcdir)/'`triplet_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-triplet_unittest.Tpo $(DEPDIR)/run_unittests-triplet_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='triplet_unittest.cc' object='run_unittests-triplet_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-triplet_unittest.o `test -f 'triplet_unittest.cc' || echo '$(srcdir)/'`triplet_unittest.cc
+
+run_unittests-triplet_unittest.obj: triplet_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-triplet_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-triplet_unittest.Tpo -c -o run_unittests-triplet_unittest.obj `if test -f 'triplet_unittest.cc'; then $(CYGPATH_W) 'triplet_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/triplet_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-triplet_unittest.Tpo $(DEPDIR)/run_unittests-triplet_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='triplet_unittest.cc' object='run_unittests-triplet_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-triplet_unittest.obj `if test -f 'triplet_unittest.cc'; then $(CYGPATH_W) 'triplet_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/triplet_unittest.cc'; fi`
+
+run_unittests-range_utilities_unittest.o: range_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-range_utilities_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-range_utilities_unittest.Tpo -c -o run_unittests-range_utilities_unittest.o `test -f 'range_utilities_unittest.cc' || echo '$(srcdir)/'`range_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-range_utilities_unittest.Tpo $(DEPDIR)/run_unittests-range_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='range_utilities_unittest.cc' object='run_unittests-range_utilities_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-range_utilities_unittest.o `test -f 'range_utilities_unittest.cc' || echo '$(srcdir)/'`range_utilities_unittest.cc
+
+run_unittests-range_utilities_unittest.obj: range_utilities_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-range_utilities_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-range_utilities_unittest.Tpo -c -o run_unittests-range_utilities_unittest.obj `if test -f 'range_utilities_unittest.cc'; then $(CYGPATH_W) 'range_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/range_utilities_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-range_utilities_unittest.Tpo $(DEPDIR)/run_unittests-range_utilities_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='range_utilities_unittest.cc' object='run_unittests-range_utilities_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-range_utilities_unittest.obj `if test -f 'range_utilities_unittest.cc'; then $(CYGPATH_W) 'range_utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/range_utilities_unittest.cc'; fi`
+
+run_unittests-readwrite_mutex_unittest.o: readwrite_mutex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-readwrite_mutex_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Tpo -c -o run_unittests-readwrite_mutex_unittest.o `test -f 'readwrite_mutex_unittest.cc' || echo '$(srcdir)/'`readwrite_mutex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Tpo $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='readwrite_mutex_unittest.cc' object='run_unittests-readwrite_mutex_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-readwrite_mutex_unittest.o `test -f 'readwrite_mutex_unittest.cc' || echo '$(srcdir)/'`readwrite_mutex_unittest.cc
+
+run_unittests-readwrite_mutex_unittest.obj: readwrite_mutex_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-readwrite_mutex_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Tpo -c -o run_unittests-readwrite_mutex_unittest.obj `if test -f 'readwrite_mutex_unittest.cc'; then $(CYGPATH_W) 'readwrite_mutex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/readwrite_mutex_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Tpo $(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='readwrite_mutex_unittest.cc' object='run_unittests-readwrite_mutex_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-readwrite_mutex_unittest.obj `if test -f 'readwrite_mutex_unittest.cc'; then $(CYGPATH_W) 'readwrite_mutex_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/readwrite_mutex_unittest.cc'; fi`
+
+run_unittests-stopwatch_unittest.o: stopwatch_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stopwatch_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-stopwatch_unittest.Tpo -c -o run_unittests-stopwatch_unittest.o `test -f 'stopwatch_unittest.cc' || echo '$(srcdir)/'`stopwatch_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stopwatch_unittest.Tpo $(DEPDIR)/run_unittests-stopwatch_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stopwatch_unittest.cc' object='run_unittests-stopwatch_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-stopwatch_unittest.o `test -f 'stopwatch_unittest.cc' || echo '$(srcdir)/'`stopwatch_unittest.cc
+
+run_unittests-stopwatch_unittest.obj: stopwatch_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stopwatch_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-stopwatch_unittest.Tpo -c -o run_unittests-stopwatch_unittest.obj `if test -f 'stopwatch_unittest.cc'; then $(CYGPATH_W) 'stopwatch_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stopwatch_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stopwatch_unittest.Tpo $(DEPDIR)/run_unittests-stopwatch_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stopwatch_unittest.cc' object='run_unittests-stopwatch_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-stopwatch_unittest.obj `if test -f 'stopwatch_unittest.cc'; then $(CYGPATH_W) 'stopwatch_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stopwatch_unittest.cc'; fi`
+
+run_unittests-unlock_guard_unittests.o: unlock_guard_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-unlock_guard_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-unlock_guard_unittests.Tpo -c -o run_unittests-unlock_guard_unittests.o `test -f 'unlock_guard_unittests.cc' || echo '$(srcdir)/'`unlock_guard_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-unlock_guard_unittests.Tpo $(DEPDIR)/run_unittests-unlock_guard_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='unlock_guard_unittests.cc' object='run_unittests-unlock_guard_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-unlock_guard_unittests.o `test -f 'unlock_guard_unittests.cc' || echo '$(srcdir)/'`unlock_guard_unittests.cc
+
+run_unittests-unlock_guard_unittests.obj: unlock_guard_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-unlock_guard_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-unlock_guard_unittests.Tpo -c -o run_unittests-unlock_guard_unittests.obj `if test -f 'unlock_guard_unittests.cc'; then $(CYGPATH_W) 'unlock_guard_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/unlock_guard_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-unlock_guard_unittests.Tpo $(DEPDIR)/run_unittests-unlock_guard_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='unlock_guard_unittests.cc' object='run_unittests-unlock_guard_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-unlock_guard_unittests.obj `if test -f 'unlock_guard_unittests.cc'; then $(CYGPATH_W) 'unlock_guard_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/unlock_guard_unittests.cc'; fi`
+
+run_unittests-utf8_unittest.o: utf8_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-utf8_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-utf8_unittest.Tpo -c -o run_unittests-utf8_unittest.o `test -f 'utf8_unittest.cc' || echo '$(srcdir)/'`utf8_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-utf8_unittest.Tpo $(DEPDIR)/run_unittests-utf8_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_unittest.cc' object='run_unittests-utf8_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-utf8_unittest.o `test -f 'utf8_unittest.cc' || echo '$(srcdir)/'`utf8_unittest.cc
+
+run_unittests-utf8_unittest.obj: utf8_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-utf8_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-utf8_unittest.Tpo -c -o run_unittests-utf8_unittest.obj `if test -f 'utf8_unittest.cc'; then $(CYGPATH_W) 'utf8_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/utf8_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-utf8_unittest.Tpo $(DEPDIR)/run_unittests-utf8_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_unittest.cc' object='run_unittests-utf8_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-utf8_unittest.obj `if test -f 'utf8_unittest.cc'; then $(CYGPATH_W) 'utf8_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/utf8_unittest.cc'; fi`
+
+run_unittests-versioned_csv_file_unittest.o: versioned_csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-versioned_csv_file_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Tpo -c -o run_unittests-versioned_csv_file_unittest.o `test -f 'versioned_csv_file_unittest.cc' || echo '$(srcdir)/'`versioned_csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Tpo $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='versioned_csv_file_unittest.cc' object='run_unittests-versioned_csv_file_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-versioned_csv_file_unittest.o `test -f 'versioned_csv_file_unittest.cc' || echo '$(srcdir)/'`versioned_csv_file_unittest.cc
+
+run_unittests-versioned_csv_file_unittest.obj: versioned_csv_file_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-versioned_csv_file_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Tpo -c -o run_unittests-versioned_csv_file_unittest.obj `if test -f 'versioned_csv_file_unittest.cc'; then $(CYGPATH_W) 'versioned_csv_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/versioned_csv_file_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Tpo $(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='versioned_csv_file_unittest.cc' object='run_unittests-versioned_csv_file_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-versioned_csv_file_unittest.obj `if test -f 'versioned_csv_file_unittest.cc'; then $(CYGPATH_W) 'versioned_csv_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/versioned_csv_file_unittest.cc'; fi`
+
+run_unittests-watch_socket_unittests.o: watch_socket_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-watch_socket_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-watch_socket_unittests.Tpo -c -o run_unittests-watch_socket_unittests.o `test -f 'watch_socket_unittests.cc' || echo '$(srcdir)/'`watch_socket_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-watch_socket_unittests.Tpo $(DEPDIR)/run_unittests-watch_socket_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='watch_socket_unittests.cc' object='run_unittests-watch_socket_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-watch_socket_unittests.o `test -f 'watch_socket_unittests.cc' || echo '$(srcdir)/'`watch_socket_unittests.cc
+
+run_unittests-watch_socket_unittests.obj: watch_socket_unittests.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-watch_socket_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-watch_socket_unittests.Tpo -c -o run_unittests-watch_socket_unittests.obj `if test -f 'watch_socket_unittests.cc'; then $(CYGPATH_W) 'watch_socket_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/watch_socket_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-watch_socket_unittests.Tpo $(DEPDIR)/run_unittests-watch_socket_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='watch_socket_unittests.cc' object='run_unittests-watch_socket_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-watch_socket_unittests.obj `if test -f 'watch_socket_unittests.cc'; then $(CYGPATH_W) 'watch_socket_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/watch_socket_unittests.cc'; fi`
+
+run_unittests-watched_thread_unittest.o: watched_thread_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-watched_thread_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-watched_thread_unittest.Tpo -c -o run_unittests-watched_thread_unittest.o `test -f 'watched_thread_unittest.cc' || echo '$(srcdir)/'`watched_thread_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-watched_thread_unittest.Tpo $(DEPDIR)/run_unittests-watched_thread_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='watched_thread_unittest.cc' object='run_unittests-watched_thread_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-watched_thread_unittest.o `test -f 'watched_thread_unittest.cc' || echo '$(srcdir)/'`watched_thread_unittest.cc
+
+run_unittests-watched_thread_unittest.obj: watched_thread_unittest.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-watched_thread_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-watched_thread_unittest.Tpo -c -o run_unittests-watched_thread_unittest.obj `if test -f 'watched_thread_unittest.cc'; then $(CYGPATH_W) 'watched_thread_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/watched_thread_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-watched_thread_unittest.Tpo $(DEPDIR)/run_unittests-watched_thread_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='watched_thread_unittest.cc' object='run_unittests-watched_thread_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-watched_thread_unittest.obj `if test -f 'watched_thread_unittest.cc'; then $(CYGPATH_W) 'watched_thread_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/watched_thread_unittest.cc'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/run_unittests-base32hex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-base64_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-boost_time_utils_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-buffer_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-csv_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-dhcp_space_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-doubles_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-fd_share_tests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-fd_tests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-file_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-filename_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hash_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-io_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-labeled_value_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-memory_segment_common_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-memory_segment_local_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-optional_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-pid_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-range_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-staged_value_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-state_model_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-stopwatch_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-strutil_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-thread_pool_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-time_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-triplet_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-unlock_guard_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-utf8_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-watch_socket_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-watched_thread_unittest.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/run_unittests-base32hex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-base64_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-boost_time_utils_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-buffer_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-chrono_time_utils_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-csv_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-dhcp_space_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-doubles_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-fd_share_tests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-fd_tests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-file_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-filename_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hash_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-hex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-io_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-labeled_value_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-memory_segment_common_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-memory_segment_local_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-multi_threading_mgr_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-optional_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-pid_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-range_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-readwrite_mutex_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-staged_value_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-state_model_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-stopwatch_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-strutil_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-thread_pool_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-time_utilities_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-triplet_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-unlock_guard_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-utf8_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-versioned_csv_file_unittest.Po
+ -rm -f ./$(DEPDIR)/run_unittests-watch_socket_unittests.Po
+ -rm -f ./$(DEPDIR)/run_unittests-watched_thread_unittest.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/lib/util/tests/base32hex_unittest.cc b/src/lib/util/tests/base32hex_unittest.cc
new file mode 100644
index 0000000..bf28f62
--- /dev/null
+++ b/src/lib/util/tests/base32hex_unittest.cc
@@ -0,0 +1,158 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <stdint.h>
+
+#include <cctype>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/base32hex.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base32HexTest : public ::testing::Test {
+protected:
+ Base32HexTest() : encoding_chars("0123456789ABCDEFGHIJKLMNOPQRSTUV=") {
+ // test vectors from RFC4648
+ test_sequence.push_back(StringPair("", ""));
+ test_sequence.push_back(StringPair("f", "CO======"));
+ test_sequence.push_back(StringPair("fo", "CPNG===="));
+ test_sequence.push_back(StringPair("foo", "CPNMU==="));
+ test_sequence.push_back(StringPair("foob", "CPNMUOG="));
+ test_sequence.push_back(StringPair("fooba", "CPNMUOJ1"));
+ test_sequence.push_back(StringPair("foobar", "CPNMUOJ1E8======"));
+
+ // the same data, encoded using lower case chars (testable only
+ // for the decode side)
+ test_sequence_lower.push_back(StringPair("f", "co======"));
+ test_sequence_lower.push_back(StringPair("fo", "cpng===="));
+ test_sequence_lower.push_back(StringPair("foo", "cpnmu==="));
+ test_sequence_lower.push_back(StringPair("foob", "cpnmuog="));
+ test_sequence_lower.push_back(StringPair("fooba", "cpnmuoj1"));
+ test_sequence_lower.push_back(StringPair("foobar",
+ "cpnmuoj1e8======"));
+ }
+ vector<StringPair> test_sequence;
+ vector<StringPair> test_sequence_lower;
+ vector<uint8_t> decoded_data;
+ const string encoding_chars;
+};
+
+void
+decodeCheck(const string& input_string, vector<uint8_t>& output,
+ const string& expected)
+{
+ decodeBase32Hex(input_string, output);
+ EXPECT_EQ(expected, string(output.begin(), output.end()));
+}
+
+TEST_F(Base32HexTest, decode) {
+ for (vector<StringPair>::const_iterator it = test_sequence.begin();
+ it != test_sequence.end();
+ ++it) {
+ decodeCheck((*it).second, decoded_data, (*it).first);
+ }
+
+ // whitespace should be allowed
+ decodeCheck("CP NM\tUOG=", decoded_data, "foob");
+ decodeCheck("CPNMU===\n", decoded_data, "foo");
+ decodeCheck(" CP NM\tUOG=", decoded_data, "foob");
+ decodeCheck(" ", decoded_data, "");
+
+ // Incomplete input
+ EXPECT_THROW(decodeBase32Hex("CPNMUOJ", decoded_data), BadValue);
+
+ // invalid number of padding characters
+ EXPECT_THROW(decodeBase32Hex("CPNMU0==", decoded_data), BadValue);
+ EXPECT_THROW(decodeBase32Hex("CO0=====", decoded_data), BadValue);
+ EXPECT_THROW(decodeBase32Hex("CO=======", decoded_data), // too many ='s
+ BadValue);
+
+ // intermediate padding isn't allowed
+ EXPECT_THROW(decodeBase32Hex("CPNMUOG=CPNMUOG=", decoded_data), BadValue);
+
+ // Non canonical form isn't allowed.
+ // P => 25(11001), so the padding byte would be 01000000
+ EXPECT_THROW(decodeBase32Hex("0P======", decoded_data), BadValue);
+}
+
+TEST_F(Base32HexTest, decodeLower) {
+ for (vector<StringPair>::const_iterator it = test_sequence_lower.begin();
+ it != test_sequence_lower.end();
+ ++it) {
+ decodeCheck((*it).second, decoded_data, (*it).first);
+ }
+}
+
+TEST_F(Base32HexTest, encode) {
+ for (vector<StringPair>::const_iterator it = test_sequence.begin();
+ it != test_sequence.end();
+ ++it) {
+ decoded_data.assign((*it).first.begin(), (*it).first.end());
+ EXPECT_EQ((*it).second, encodeBase32Hex(decoded_data));
+ }
+}
+
+// For Base32Hex we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(Base32HexTest, decodeMap) {
+ string input(8, '0'); // input placeholder
+
+ // We're going to populate an input string with only the last character
+ // not equal to the zero character ('0') for each valid base32hex encoding
+ // character. Decoding that input should result in a data stream with
+ // the last byte equal to the numeric value represented by the that
+ // character. For example, we'll generate and confirm the following:
+ // "00000000" => should be 0 (as a 40bit integer)
+ // "00000001" => should be 1 (as a 40bit integer)
+ // ...
+ // "0000000V" => should be 31 (as a 40bit integer)
+ // We also check the use of an invalid character for the last character
+ // surely fails. '=' should be accepted as a valid padding in this
+ // context; space characters shouldn't be allowed in this context.
+
+ for (int i = 0; i < 256; ++i) {
+ input[7] = i;
+
+ const char ch = toupper(i);
+ const size_t pos = encoding_chars.find(ch);
+ if (pos == string::npos) {
+ EXPECT_THROW(decodeBase32Hex(input, decoded_data), BadValue);
+ } else {
+ decodeBase32Hex(input, decoded_data);
+ if (ch == '=') {
+ EXPECT_EQ(4, decoded_data.size());
+ } else {
+ EXPECT_EQ(5, decoded_data.size());
+ EXPECT_EQ(pos, decoded_data[4]);
+ }
+ }
+ }
+}
+
+TEST_F(Base32HexTest, encodeMap) {
+ for (uint8_t i = 0; i < 32; ++i) {
+ decoded_data.assign(4, 0);
+ decoded_data.push_back(i);
+ EXPECT_EQ(encoding_chars[i], encodeBase32Hex(decoded_data)[7]);
+ }
+}
+
+}
diff --git a/src/lib/util/tests/base64_unittest.cc b/src/lib/util/tests/base64_unittest.cc
new file mode 100644
index 0000000..516925e
--- /dev/null
+++ b/src/lib/util/tests/base64_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/base64.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base64Test : public ::testing::Test {
+protected:
+ Base64Test()
+ {
+ // test vectors from RFC4648
+ test_sequence.push_back(StringPair("", ""));
+ test_sequence.push_back(StringPair("f", "Zg=="));
+ test_sequence.push_back(StringPair("fo", "Zm8="));
+ test_sequence.push_back(StringPair("foo", "Zm9v"));
+ test_sequence.push_back(StringPair("foob", "Zm9vYg=="));
+ test_sequence.push_back(StringPair("fooba", "Zm9vYmE="));
+ test_sequence.push_back(StringPair("foobar", "Zm9vYmFy"));
+ }
+ vector<StringPair> test_sequence;
+ vector<uint8_t> decoded_data;
+};
+
+void
+decodeCheck(const string& input_string, vector<uint8_t>& output,
+ const string& expected)
+{
+ decodeBase64(input_string, output);
+ EXPECT_EQ(expected, string(output.begin(), output.end()));
+}
+
+TEST_F(Base64Test, decode) {
+ for (vector<StringPair>::const_iterator it = test_sequence.begin();
+ it != test_sequence.end();
+ ++it) {
+ decodeCheck((*it).second, decoded_data, (*it).first);
+ }
+
+ // whitespace should be allowed
+ decodeCheck("Zm 9v\tYmF\ny", decoded_data, "foobar");
+ decodeCheck("Zm9vYg==", decoded_data, "foob");
+ decodeCheck("Zm9vYmE=\n", decoded_data, "fooba");
+ decodeCheck(" Zm9vYmE=\n", decoded_data, "fooba");
+ decodeCheck(" ", decoded_data, "");
+ decodeCheck("\n\t", decoded_data, "");
+
+ // incomplete input
+ EXPECT_THROW(decodeBase64("Zm9vYmF", decoded_data), BadValue);
+
+ // only up to 2 padding characters are allowed
+ EXPECT_THROW(decodeBase64("A===", decoded_data), BadValue);
+ EXPECT_THROW(decodeBase64("A= ==", decoded_data), BadValue);
+
+ // intermediate padding isn't allowed
+ EXPECT_THROW(decodeBase64("YmE=YmE=", decoded_data), BadValue);
+
+ // Non canonical form isn't allowed.
+ // Z => 25(011001), m => 38(100110), 9 => 60(111101), so the padding
+ // byte would be 0100 0000.
+ EXPECT_THROW(decodeBase64("Zm9=", decoded_data), BadValue);
+ // Same for the 1st padding byte. This would make it 01100000.
+ EXPECT_THROW(decodeBase64("Zm==", decoded_data), BadValue);
+}
+
+TEST_F(Base64Test, encode) {
+ for (vector<StringPair>::const_iterator it = test_sequence.begin();
+ it != test_sequence.end();
+ ++it) {
+ decoded_data.assign((*it).first.begin(), (*it).first.end());
+ EXPECT_EQ((*it).second, encodeBase64(decoded_data));
+ }
+}
+}
diff --git a/src/lib/util/tests/boost_time_utils_unittest.cc b/src/lib/util/tests/boost_time_utils_unittest.cc
new file mode 100644
index 0000000..e7e8c81
--- /dev/null
+++ b/src/lib/util/tests/boost_time_utils_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/boost_time_utils.h>
+
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace boost::posix_time;
+using namespace boost::gregorian;
+
+/// Check the ptimeToText() function returns a numeric month.
+/// Note durationToText() is called by ptimeToText() so is tested too.
+
+// The Posix time epoch is 1970
+TEST(BoostTimeUtilsTest, epoch) {
+ time_t tepoch = 0;
+ ptime pepoch = from_time_t(tepoch);
+
+ // We're going to loop through precision values starting with 0 through
+ // the max supported precision. Each pass should after the first, should
+ // add an additional level of precision: secs, secs/10, secs/100,
+ // secs/1000 and so on. The initial string has no fraction seconds.
+ std::string expected("1970-01-01 00:00:00");
+ std::string sepoch;
+ for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) {
+ if (precision == 1) {
+ // Adding fractional seconds so we need append a decimal point.
+ expected.push_back('.');
+ }
+
+ if (precision >= 1) {
+ // Adding an additional level of precision, append a zero.
+ expected.push_back('0');
+ }
+
+ // Now let's see if we get the correct precision in the text.
+ sepoch = ptimeToText(pepoch, precision);
+ EXPECT_EQ(expected, sepoch) << " test precision:" << precision;
+ }
+
+ // Expected string should have same precision as default, so
+ // test the default.
+ sepoch = ptimeToText(pepoch);
+ EXPECT_EQ(expected, sepoch);
+
+ // Now test a requested precision beyond default. We should
+ // get the default precision.
+ sepoch = ptimeToText(pepoch, MAX_FSECS_PRECISION + 1);
+ EXPECT_EQ(expected, sepoch);
+
+}
+
+// The 2015 Bastille day
+TEST(BoostTimeUtilsTest, bastilleDay) {
+ time_duration tdbast =
+ hours(12) + minutes(13) + seconds(14) + milliseconds(500);
+ ptime pbast(date(2015, Jul, 14), tdbast);
+
+ // We're going to loop through precision values starting with 0 through
+ // the max supported precision. Each pass should after the first, should
+ // add an additional level of precision: secs, secs/10, secs/100,
+ // secs/1000 and so on. The initial string has no fraction seconds.
+ std::string expected("2015-07-14 12:13:14");
+ std::string sbast;
+ for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) {
+ if (precision == 1) {
+ // Adding fractional seconds so we need append a decimal point
+ // and the digit 5 (i.e. 500 ms = .5 secs).
+ expected.push_back('.');
+ expected.push_back('5');
+ } else if (precision > 1) {
+ // Adding an additional level of precision, append a zero.
+ expected.push_back('0');
+ }
+
+ // Now let's see if we get the correct precision in the text.
+ sbast = ptimeToText(pbast, precision);
+ EXPECT_EQ(expected, sbast) << " test precision:" << precision;
+ }
+
+ // Expected string should have same precision as default, so
+ // test the default.
+ sbast = ptimeToText(pbast);
+ EXPECT_EQ(expected, sbast);
+
+ // Now test a requested precision beyond default. We should
+ // get the default precision.
+ sbast = ptimeToText(pbast, MAX_FSECS_PRECISION + 1);
+ EXPECT_EQ(expected, sbast);
+}
diff --git a/src/lib/util/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc
new file mode 100644
index 0000000..1f63167
--- /dev/null
+++ b/src/lib/util/tests/buffer_unittest.cc
@@ -0,0 +1,341 @@
+// Copyright (C) 2009-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#ifdef EXPECT_DEATH
+#include <util/unittests/resource.h>
+#include <util/unittests/check_valgrind.h>
+#endif /* EXPECT_DEATH */
+
+#include <util/buffer.h>
+
+using namespace isc;
+
+namespace {
+
+using isc::util::InputBuffer;
+using isc::util::OutputBuffer;
+
+class BufferTest : public ::testing::Test {
+protected:
+ BufferTest() : ibuffer(testdata, sizeof(testdata)), obuffer(0),
+ expected_size(0)
+ {
+ data16 = (2 << 8) | 3;
+ data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
+ memset(vdata, 0, sizeof(testdata));
+ }
+
+ InputBuffer ibuffer;
+ OutputBuffer obuffer;
+ static const uint8_t testdata[5];
+ uint8_t vdata[sizeof(testdata)];
+ size_t expected_size;
+ uint16_t data16;
+ uint32_t data32;
+};
+
+const uint8_t BufferTest::testdata[5] = {1, 2, 3, 4, 5};
+
+TEST_F(BufferTest, inputBufferRead) {
+ EXPECT_EQ(5, ibuffer.getLength());
+ EXPECT_EQ(1, ibuffer.readUint8());
+ EXPECT_EQ(1, ibuffer.getPosition());
+ data16 = ibuffer.readUint16();
+ EXPECT_EQ((2 << 8) | 3, data16);
+ EXPECT_EQ(3, ibuffer.getPosition());
+ ibuffer.setPosition(1);
+ EXPECT_EQ(1, ibuffer.getPosition());
+ data32 = ibuffer.readUint32();
+ EXPECT_EQ((2 << 24) | (3 << 16) | (4 << 8) | 5, data32);
+ ibuffer.setPosition(0);
+ memset(vdata, 0, sizeof(vdata));
+ ibuffer.readData(vdata, sizeof(vdata));
+ EXPECT_EQ(0, memcmp(vdata, testdata, sizeof(testdata)));
+}
+
+TEST_F(BufferTest, inputBufferException) {
+ EXPECT_THROW(ibuffer.setPosition(6), isc::util::InvalidBufferPosition);
+
+ ibuffer.setPosition(sizeof(testdata));
+ EXPECT_THROW(ibuffer.readUint8(), isc::util::InvalidBufferPosition);
+
+ ibuffer.setPosition(sizeof(testdata) - 1);
+ EXPECT_THROW(ibuffer.readUint16(), isc::util::InvalidBufferPosition);
+
+ ibuffer.setPosition(sizeof(testdata) - 3);
+ EXPECT_THROW(ibuffer.readUint32(), isc::util::InvalidBufferPosition);
+
+ ibuffer.setPosition(sizeof(testdata) - 4);
+ EXPECT_THROW(ibuffer.readData(vdata, sizeof(vdata)),
+ isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferExtend) {
+ EXPECT_EQ(0, obuffer.getCapacity());
+ EXPECT_EQ(0, obuffer.getLength());
+ obuffer.writeUint8(10);
+ EXPECT_LT(0, obuffer.getCapacity());
+ EXPECT_EQ(1, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferWrite) {
+ const uint8_t* cp;
+
+ obuffer.writeUint8(1);
+ expected_size += sizeof(uint8_t);
+ EXPECT_EQ(expected_size, obuffer.getLength());
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(1, *cp);
+
+ obuffer.writeUint16(data16);
+ expected_size += sizeof(data16);
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(expected_size, obuffer.getLength());
+ EXPECT_EQ(2, *(cp + 1));
+ EXPECT_EQ(3, *(cp + 2));
+
+ obuffer.writeUint32(data32);
+ expected_size += sizeof(data32);
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(expected_size, obuffer.getLength());
+ EXPECT_EQ(4, *(cp + 3));
+ EXPECT_EQ(5, *(cp + 4));
+ EXPECT_EQ(6, *(cp + 5));
+ EXPECT_EQ(7, *(cp + 6));
+
+ obuffer.writeData(testdata, sizeof(testdata));
+ expected_size += sizeof(testdata);
+ EXPECT_EQ(expected_size, obuffer.getLength());
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(0, memcmp(cp + 7, testdata, sizeof(testdata)));
+}
+
+TEST_F(BufferTest, outputBufferWriteat) {
+ obuffer.writeUint32(data32);
+ expected_size += sizeof(data32);
+
+ // overwrite 2nd byte
+ obuffer.writeUint8At(4, 1);
+ EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
+ const uint8_t* cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(4, *(cp + 1));
+
+ // overwrite 2nd and 3rd bytes
+ obuffer.writeUint16At(data16, 1);
+ EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(2, *(cp + 1));
+ EXPECT_EQ(3, *(cp + 2));
+
+ // overwrite 3rd and 4th bytes
+ obuffer.writeUint16At(data16, 2);
+ EXPECT_EQ(expected_size, obuffer.getLength());
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(2, *(cp + 2));
+ EXPECT_EQ(3, *(cp + 3));
+
+ EXPECT_THROW(obuffer.writeUint8At(data16, 5),
+ isc::util::InvalidBufferPosition);
+ EXPECT_THROW(obuffer.writeUint8At(data16, 4),
+ isc::util::InvalidBufferPosition);
+ EXPECT_THROW(obuffer.writeUint16At(data16, 3),
+ isc::util::InvalidBufferPosition);
+ EXPECT_THROW(obuffer.writeUint16At(data16, 4),
+ isc::util::InvalidBufferPosition);
+ EXPECT_THROW(obuffer.writeUint16At(data16, 5),
+ isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferSkip) {
+ obuffer.skip(4);
+ EXPECT_EQ(4, obuffer.getLength());
+
+ obuffer.skip(2);
+ EXPECT_EQ(6, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferTrim) {
+ obuffer.writeData(testdata, sizeof(testdata));
+ EXPECT_EQ(5, obuffer.getLength());
+
+ obuffer.trim(1);
+ EXPECT_EQ(4, obuffer.getLength());
+
+ obuffer.trim(2);
+ EXPECT_EQ(2, obuffer.getLength());
+
+ EXPECT_THROW(obuffer.trim(3), OutOfRange);
+}
+
+TEST_F(BufferTest, outputBufferReadAt) {
+ obuffer.writeData(testdata, sizeof(testdata));
+ for (int i = 0; i < sizeof(testdata); i ++) {
+ EXPECT_EQ(testdata[i], obuffer[i]);
+ }
+ EXPECT_THROW(obuffer[sizeof(testdata)], isc::util::InvalidBufferPosition);
+}
+
+TEST_F(BufferTest, outputBufferClear) {
+ const uint8_t* cp;
+
+ obuffer.writeData(testdata, sizeof(testdata));
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ obuffer.clear();
+ EXPECT_EQ(0, obuffer.getLength());
+ EXPECT_EQ(*cp, 1);
+}
+
+TEST_F(BufferTest, outputBufferWipe) {
+ const uint8_t* cp;
+
+ obuffer.writeData(testdata, sizeof(testdata));
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ obuffer.wipe();
+ EXPECT_EQ(0, obuffer.getLength());
+ EXPECT_EQ(*cp, 0);
+}
+
+TEST_F(BufferTest, emptyOutputBufferWipe) {
+ ASSERT_NO_THROW(obuffer.wipe());
+ EXPECT_EQ(0, obuffer.getLength());
+}
+
+TEST_F(BufferTest, outputBufferCopy) {
+ obuffer.writeData(testdata, sizeof(testdata));
+
+ EXPECT_NO_THROW({
+ OutputBuffer copy(obuffer);
+ ASSERT_EQ(sizeof(testdata), copy.getLength());
+ ASSERT_NE(obuffer.getData(), copy.getData());
+ for (int i = 0; i < sizeof(testdata); i ++) {
+ EXPECT_EQ(testdata[i], copy[i]);
+ if (i + 1 < sizeof(testdata)) {
+ obuffer.writeUint16At(0, i);
+ }
+ EXPECT_EQ(testdata[i], copy[i]);
+ }
+ obuffer.clear();
+ ASSERT_EQ(sizeof(testdata), copy.getLength());
+ });
+}
+
+TEST_F(BufferTest, outputEmptyBufferCopy) {
+ EXPECT_NO_THROW({
+ OutputBuffer copy(obuffer);
+ ASSERT_EQ(0, copy.getLength());
+ });
+}
+
+TEST_F(BufferTest, outputBufferAssign) {
+ OutputBuffer another(0);
+ another.clear();
+ obuffer.writeData(testdata, sizeof(testdata));
+
+ EXPECT_NO_THROW({
+ another = obuffer;
+ ASSERT_EQ(sizeof(testdata), another.getLength());
+ ASSERT_NE(obuffer.getData(), another.getData());
+ for (int i = 0; i < sizeof(testdata); i ++) {
+ EXPECT_EQ(testdata[i], another[i]);
+ if (i + 1 < sizeof(testdata)) {
+ obuffer.writeUint16At(0, i);
+ }
+ EXPECT_EQ(testdata[i], another[i]);
+ }
+ obuffer.clear();
+ ASSERT_EQ(sizeof(testdata), another.getLength());
+ });
+}
+
+TEST_F(BufferTest, outputEmptyBufferAssign) {
+ OutputBuffer copy(0);
+ ASSERT_NO_THROW({
+ copy = obuffer;
+ });
+ ASSERT_EQ(0, copy.getLength());
+ EXPECT_EQ(NULL, copy.getData());
+}
+
+// Check assign to self doesn't break stuff
+TEST_F(BufferTest, outputBufferAssignSelf) {
+ EXPECT_NO_THROW(obuffer = obuffer);
+}
+
+TEST_F(BufferTest, outputBufferZeroSize) {
+ // Some OSes might return NULL on malloc for 0 size, so check it works
+ EXPECT_NO_THROW({
+ OutputBuffer first(0);
+ OutputBuffer copy(first);
+ OutputBuffer second(0);
+ second = first;
+ });
+}
+
+TEST_F(BufferTest, inputBufferReadVectorAll) {
+ std::vector<uint8_t> vec;
+
+ // check that vector can read the whole buffer
+ ibuffer.readVector(vec, 5);
+
+ ASSERT_EQ(5, vec.size());
+ EXPECT_EQ(0, memcmp(&vec[0], testdata, 5));
+
+ // ibuffer is 5 bytes long. Can't read past it.
+ EXPECT_THROW(
+ ibuffer.readVector(vec, 1),
+ isc::util::InvalidBufferPosition
+ );
+}
+
+TEST_F(BufferTest, inputBufferReadVectorChunks) {
+ std::vector<uint8_t> vec;
+
+ // check that vector can read the whole buffer
+ ibuffer.readVector(vec, 3);
+ EXPECT_EQ(3, vec.size());
+
+ EXPECT_EQ(0, memcmp(&vec[0], testdata, 3));
+
+ EXPECT_NO_THROW(
+ ibuffer.readVector(vec, 2)
+ );
+
+ EXPECT_EQ(0, memcmp(&vec[0], testdata+3, 2));
+}
+
+// Tests whether uint64 can be written properly.
+TEST_F(BufferTest, writeUint64) {
+
+ uint64_t val1 = 0x0102030405060708ul;
+ uint64_t val2 = 0xfffffffffffffffful;
+
+ uint8_t exp_val1[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ uint8_t exp_val2[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ const uint8_t* cp;
+
+ obuffer.writeUint64(val1);
+ ASSERT_EQ(sizeof(uint64_t), obuffer.getLength());
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_TRUE(cp);
+ EXPECT_FALSE(memcmp(exp_val1, obuffer.getData(), sizeof(uint64_t)));
+
+ EXPECT_NO_THROW(obuffer.clear());
+
+ obuffer.writeUint64(val2);
+ ASSERT_EQ(sizeof(uint64_t), obuffer.getLength());
+ cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_TRUE(cp);
+ EXPECT_FALSE(memcmp(exp_val2, obuffer.getData(), sizeof(uint64_t)));
+}
+
+}
diff --git a/src/lib/util/tests/chrono_time_utils_unittest.cc b/src/lib/util/tests/chrono_time_utils_unittest.cc
new file mode 100644
index 0000000..e9d2917
--- /dev/null
+++ b/src/lib/util/tests/chrono_time_utils_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/chrono_time_utils.h>
+
+#include <string.h>
+#include <time.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace std::chrono;
+using namespace isc::util;
+
+/// Check the clockToText() function returns a numeric month.
+TEST(ChronoTimeUtilsTest, epoch) {
+ // The system clock is a wall clock using the local time zone so
+ // the epoch is zero only at some places or of course if the
+ // system is in UTC...
+ struct tm epoch;
+ memset(&epoch, 0, sizeof(epoch));
+ epoch.tm_year = 70;
+ epoch.tm_mday = 1;
+ epoch.tm_isdst = -1;
+ time_t tepoch = mktime(&epoch);
+ system_clock::time_point pepoch = system_clock::from_time_t(tepoch);
+
+ // We're going to loop through precision values starting with 0 through
+ // the max supported precision. Each pass should after the first, should
+ // add an additional level of precision: secs, secs/10, secs/100,
+ // secs/1000 and so on. The initial string has no fraction seconds.
+ std::string expected("1970-01-01 00:00:00");
+ std::string sepoch;
+ for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) {
+ if (precision == 1) {
+ // Adding fractional seconds so we need append a decimal point.
+ expected.push_back('.');
+ }
+
+ if (precision >= 1) {
+ // Adding an additional level of precision, append a zero.
+ expected.push_back('0');
+ }
+
+ // Now let's see if we get the correct precision in the text.
+ sepoch = clockToText(pepoch, precision);
+ EXPECT_EQ(expected, sepoch) << " test precision:" << precision;
+ }
+
+ // Expected string should have same precision as default, so
+ // test the default.
+ sepoch = clockToText(pepoch);
+ EXPECT_EQ(expected, sepoch);
+
+ // Now test a requested precision beyond default. We should
+ // get the default precision.
+ sepoch = clockToText(pepoch, MAX_FSECS_PRECISION + 1);
+ EXPECT_EQ(expected, sepoch);
+
+}
+
+/// Check the durationToText() works as expected.
+/// Note durationToText() is not called by clockToText().
+TEST(ChronoTimeUtilsTest, duration) {
+ system_clock::duration p123 = hours(1) + minutes(2) + seconds(3);
+
+ // We're going to loop through precision values starting with 0 through
+ // the max supported precision. Each pass should after the first, should
+ // add an additional level of precision: secs, secs/10, secs/100,
+ // secs/1000 and so on. The initial string has no fraction seconds.
+ std::string expected("01:02:03");
+ std::string s123;
+ for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) {
+ if (precision == 1) {
+ // Adding fractional seconds so we need append a decimal point.
+ expected.push_back('.');
+ }
+
+ if (precision >= 1) {
+ // Adding an additional level of precision, append a zero.
+ expected.push_back('0');
+ }
+
+ // Now let's see if we get the correct precision in the text.
+ s123 = durationToText(p123, precision);
+ EXPECT_EQ(expected, s123) << " test precision:" << precision;
+ }
+
+ // Expected string should have same precision as default, so
+ // test the default.
+ s123 = durationToText(p123);
+ EXPECT_EQ(expected, s123);
+
+ // Now test a requested precision beyond default. We should
+ // get the default precision.
+ s123 = durationToText(p123, MAX_FSECS_PRECISION + 1);
+ EXPECT_EQ(expected, s123);
+}
+
+// The 2015 Bastille day
+TEST(ChronoTimeUtilsTest, bastilleDay) {
+ struct tm tm;
+ tm.tm_year = 2015 - 1900;
+ tm.tm_mon = 7 - 1;
+ tm.tm_mday = 14;
+ tm.tm_hour = 12;
+ tm.tm_min = 13;
+ tm.tm_sec = 14;
+ tm.tm_isdst = -1;
+ time_t tbast = mktime(&tm);
+ system_clock::time_point tpbast = system_clock::from_time_t(tbast);
+ tpbast += milliseconds(500);
+
+ // We're going to loop through precision values starting with 0 through
+ // the max supported precision. Each pass should after the first, should
+ // add an additional level of precision: secs, secs/10, secs/100,
+ // secs/1000 and so on. The initial string has no fraction seconds.
+ std::string expected("2015-07-14 12:13:14");
+ std::string sbast;
+ for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) {
+ if (precision == 1) {
+ // Adding fractional seconds so we need append a decimal point
+ // and the digit 5 (i.e. 500 ms = .5 secs).
+ expected.push_back('.');
+ expected.push_back('5');
+ } else if (precision > 1) {
+ // Adding an additional level of precision, append a zero.
+ expected.push_back('0');
+ }
+
+ // Now let's see if we get the correct precision in the text.
+ sbast = clockToText(tpbast, precision);
+ EXPECT_EQ(expected, sbast) << " test precision:" << precision;
+ }
+
+ // Expected string should have same precision as default, so
+ // test the default.
+ sbast = clockToText(tpbast);
+ EXPECT_EQ(expected, sbast);
+
+ // Now test a requested precision beyond default. We should
+ // get the default precision.
+ sbast = clockToText(tpbast, MAX_FSECS_PRECISION + 1);
+ EXPECT_EQ(expected, sbast);
+}
+
+// Try steady clock duration.
+TEST(ChronoTimeUtilsTest, steadyClock) {
+ steady_clock::duration p12345 = hours(1) + minutes(2) + seconds(3) +
+ milliseconds(4) + microseconds(5);
+ std::string expected("01:02:03.004005");
+ std::string s12345 = durationToText(p12345, 6);
+ EXPECT_EQ(expected, s12345);
+}
diff --git a/src/lib/util/tests/csv_file_unittest.cc b/src/lib/util/tests/csv_file_unittest.cc
new file mode 100644
index 0000000..f55ec55
--- /dev/null
+++ b/src/lib/util/tests/csv_file_unittest.cc
@@ -0,0 +1,700 @@
+// Copyright (C) 2014-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <util/csv_file.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+namespace {
+
+using namespace isc::util;
+
+// This test exercises escaping and unescaping of characters.
+TEST(CSVRowTest, escapeUnescape) {
+ std::string orig(",FO^O\\,B?,AR,");
+
+ // We'll escape commas, question marks, and carets.
+ std::string escaped = CSVRow::escapeCharacters(orig, ",?^");
+ EXPECT_EQ ("&#x2cFO&#x5eO\\&#x2cB&#x3f&#x2cAR&#x2c", escaped);
+
+ // Now make sure we can unescape it correctly.
+ std::string unescaped = CSVRow::unescapeCharacters(escaped);
+ EXPECT_EQ (orig, unescaped);
+
+ // Make sure that an incident occurrence of just the escape tag
+ // is left intact.
+ orig = ("no&#xescape");
+ escaped = CSVRow::escapeCharacters(orig, ",");
+ unescaped = CSVRow::unescapeCharacters(orig);
+ EXPECT_EQ (orig, unescaped);
+
+ // Make sure that an incidental occurrence of a valid
+ // escape tag sequence left intact.
+ orig = ("no&#x2cescape");
+ escaped = CSVRow::escapeCharacters(orig, ",");
+ unescaped = CSVRow::unescapeCharacters(escaped);
+ EXPECT_EQ (orig, unescaped);
+}
+
+// This test checks that the single data row is parsed.
+TEST(CSVRow, parse) {
+ CSVRow row0("foo,bar,foo-bar");
+ ASSERT_EQ(3, row0.getValuesCount());
+ EXPECT_EQ("foo", row0.readAt(0));
+ EXPECT_EQ("bar", row0.readAt(1));
+ EXPECT_EQ("foo-bar", row0.readAt(2));
+
+ row0.parse("bar,,foo-bar");
+ ASSERT_EQ(3, row0.getValuesCount());
+ EXPECT_EQ("bar", row0.readAt(0));
+ EXPECT_TRUE(row0.readAt(1).empty());
+ EXPECT_EQ("foo-bar", row0.readAt(2));
+
+ row0.parse("bar,foo&#x2c-bar");
+ ASSERT_EQ(2, row0.getValuesCount());
+ EXPECT_EQ("bar", row0.readAt(0));
+ // Read the second column as-is and escaped
+ EXPECT_EQ("foo&#x2c-bar", row0.readAt(1));
+ EXPECT_EQ("foo,-bar", row0.readAtEscaped(1));
+
+ CSVRow row1("foo-bar|foo|bar|", '|');
+ ASSERT_EQ(4, row1.getValuesCount());
+ EXPECT_EQ("foo-bar", row1.readAt(0));
+ EXPECT_EQ("foo", row1.readAt(1));
+ EXPECT_EQ("bar", row1.readAt(2));
+ EXPECT_TRUE(row1.readAt(3).empty());
+
+ row1.parse("");
+ ASSERT_EQ(1, row1.getValuesCount());
+ EXPECT_TRUE(row1.readAt(0).empty());
+}
+
+// Verifies that empty columns are handled correctly.
+TEST(CSVRow, emptyColumns) {
+ // Should get four columns, all blank except column the second one.
+ CSVRow row(",one,,");
+ ASSERT_EQ(4, row.getValuesCount());
+ EXPECT_EQ("", row.readAt(0));
+ EXPECT_EQ("one", row.readAt(1));
+ EXPECT_EQ("", row.readAt(2));
+ EXPECT_EQ("", row.readAt(3));
+}
+
+// Verifies that empty columns are handled correctly.
+TEST(CSVRow, oneColumn) {
+ // Should get one column
+ CSVRow row("zero");
+ ASSERT_EQ(1, row.getValuesCount());
+ EXPECT_EQ("zero", row.readAt(0));
+}
+
+// This test checks that the text representation of the CSV row
+// is created correctly.
+TEST(CSVRow, render) {
+ CSVRow row0(3);
+ row0.writeAt(0, "foo");
+ row0.writeAt(1, "foo-bar");
+ row0.writeAt(2, "bar");
+
+ std::string text;
+ ASSERT_NO_THROW(text = row0.render());
+ EXPECT_EQ(text, "foo,foo-bar,bar");
+
+ CSVRow row1(4, ';');
+ row1.writeAt(0, "foo");
+ row1.writeAt(2, "bar");
+ row1.writeAt(3, 10);
+
+ ASSERT_NO_THROW(text = row1.render());
+ EXPECT_EQ(text, "foo;;bar;10");
+
+ CSVRow row2(0);
+ ASSERT_NO_THROW(text = row2.render());
+ EXPECT_TRUE(text.empty());
+}
+
+// This test checks that the data values can be set for the CSV row.
+TEST(CSVRow, writeAt) {
+ CSVRow row(4);
+ row.writeAt(0, 10);
+ row.writeAt(1, "foo");
+ row.writeAt(2, "bar");
+ row.writeAtEscaped(3, "bar,one,two");
+
+ EXPECT_EQ("10", row.readAt(0));
+ EXPECT_EQ("foo", row.readAt(1));
+ EXPECT_EQ("bar", row.readAt(2));
+ // Read third column as-is and unescaped
+ EXPECT_EQ("bar&#x2cone&#x2ctwo", row.readAt(3));
+ EXPECT_EQ("bar,one,two", row.readAtEscaped(3));
+
+ EXPECT_THROW(row.writeAt(4, 20), CSVFileError);
+ EXPECT_THROW(row.writeAt(4, "foo"), CSVFileError);
+}
+
+// Checks whether writeAt() and append() can be mixed together.
+TEST(CSVRow, append) {
+ CSVRow row(3);
+
+ EXPECT_EQ(3, row.getValuesCount());
+
+ row.writeAt(0, "alpha");
+ ASSERT_NO_THROW(row.append("delta"));
+ EXPECT_EQ(4, row.getValuesCount());
+ row.writeAt(1, "beta");
+ row.writeAt(2, "gamma");
+ ASSERT_NO_THROW(row.append("epsilon"));
+ EXPECT_EQ(5, row.getValuesCount());
+
+ std::string text;
+ ASSERT_NO_THROW(text = row.render());
+ EXPECT_EQ("alpha,beta,gamma,delta,epsilon", text);
+}
+
+// This test checks that a row can be trimmed of
+// a given number of elements
+TEST(CSVRow, trim) {
+ CSVRow row("zero,one,two,three,four");
+ ASSERT_EQ(5, row.getValuesCount());
+ EXPECT_EQ("zero", row.readAt(0));
+ EXPECT_EQ("one", row.readAt(1));
+ EXPECT_EQ("two", row.readAt(2));
+ EXPECT_EQ("three", row.readAt(3));
+ EXPECT_EQ("four", row.readAt(4));
+
+ ASSERT_THROW(row.trim(10), CSVFileError);
+
+ // Verify that we can erase just one
+ ASSERT_NO_THROW(row.trim(1));
+ ASSERT_EQ(4, row.getValuesCount());
+ EXPECT_EQ("zero", row.readAt(0));
+ EXPECT_EQ("one", row.readAt(1));
+ EXPECT_EQ("two", row.readAt(2));
+ EXPECT_EQ("three", row.readAt(3));
+
+ // Verify we can trim more than one
+ ASSERT_NO_THROW(row.trim(2));
+ ASSERT_EQ(2, row.getValuesCount());
+ EXPECT_EQ("zero", row.readAt(0));
+ EXPECT_EQ("one", row.readAt(1));
+}
+
+/// @brief Test fixture class for testing operations on CSV file.
+///
+/// It implements basic operations on files, such as reading writing
+/// file removal and checking presence of the file. This is used by
+/// unit tests to verify correctness of the file created by the
+/// CSVFile class.
+class CSVFileTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets the path to the CSV file used throughout the tests.
+ /// The name of the file is test.csv and it is located in the
+ /// current build folder.
+ ///
+ /// It also deletes any dangling files after previous tests.
+ CSVFileTest();
+
+ /// @brief Destructor.
+ ///
+ /// Deletes the test CSV file if any.
+ virtual ~CSVFileTest();
+
+ /// @brief Prepends the absolute path to the file specified
+ /// as an argument.
+ ///
+ /// @param filename Name of the file.
+ /// @return Absolute path to the test file.
+ static std::string absolutePath(const std::string& filename);
+
+ /// @brief Check if test file exists on disk.
+ bool exists() const;
+
+ /// @brief Reads whole CSV file.
+ ///
+ /// @return Contents of the file.
+ std::string readFile() const;
+
+ /// @brief Removes existing file (if any).
+ int removeFile() const;
+
+ /// @brief Creates file with contents.
+ ///
+ /// @param contents Contents of the file.
+ void writeFile(const std::string& contents) const;
+
+ /// @brief Absolute path to the file used in the tests.
+ std::string testfile_;
+
+};
+
+CSVFileTest::CSVFileTest()
+ : testfile_(absolutePath("test.csv")) {
+ static_cast<void>(removeFile());
+}
+
+CSVFileTest::~CSVFileTest() {
+ static_cast<void>(removeFile());
+}
+
+std::string
+CSVFileTest::absolutePath(const std::string& filename) {
+ std::ostringstream s;
+ s << TEST_DATA_BUILDDIR << "/" << filename;
+ return (s.str());
+}
+
+bool
+CSVFileTest::exists() const {
+ std::ifstream fs(testfile_.c_str());
+ bool ok = fs.good();
+ fs.close();
+ return (ok);
+}
+
+std::string
+CSVFileTest::readFile() const {
+ std::ifstream fs(testfile_.c_str());
+ if (!fs.is_open()) {
+ return ("");
+ }
+ std::string contents((std::istreambuf_iterator<char>(fs)),
+ std::istreambuf_iterator<char>());
+ fs.close();
+ return (contents);
+}
+
+int
+CSVFileTest::removeFile() const {
+ return (remove(testfile_.c_str()));
+}
+
+void
+CSVFileTest::writeFile(const std::string& contents) const {
+ std::ofstream fs(testfile_.c_str(), std::ofstream::out);
+ if (fs.is_open()) {
+ fs << contents;
+ fs.close();
+ }
+}
+
+// This test checks that the function which is used to add columns of the
+// CSV file works as expected.
+TEST_F(CSVFileTest, addColumn) {
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ // Add two columns.
+ ASSERT_NO_THROW(csv->addColumn("animal"));
+ ASSERT_NO_THROW(csv->addColumn("color"));
+ // Make sure we can't add duplicates.
+ EXPECT_THROW(csv->addColumn("animal"), CSVFileError);
+ EXPECT_THROW(csv->addColumn("color"), CSVFileError);
+ // But we should still be able to add unique columns.
+ EXPECT_NO_THROW(csv->addColumn("age"));
+ EXPECT_NO_THROW(csv->addColumn("comments"));
+ // Assert that the file is opened, because the rest of the test relies
+ // on this.
+ ASSERT_NO_THROW(csv->recreate());
+ ASSERT_TRUE(exists());
+
+ // Make sure we can't add columns (even unique) when the file is open.
+ ASSERT_THROW(csv->addColumn("zoo"), CSVFileError);
+ // Close the file.
+ ASSERT_NO_THROW(csv->close());
+ // And check that now it is possible to add the column.
+ EXPECT_NO_THROW(csv->addColumn("zoo"));
+}
+
+// This test checks that the appropriate file name is initialized.
+TEST_F(CSVFileTest, getFilename) {
+ CSVFile csv(testfile_);
+ EXPECT_EQ(testfile_, csv.getFilename());
+}
+
+// This test checks that the file can be opened, its whole content is
+// parsed correctly and data may be appended. It also checks that empty
+// row is returned when EOF is reached.
+TEST_F(CSVFileTest, openReadAllWrite) {
+ // Create a new CSV file that contains a header and two data rows.
+ writeFile("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n");
+
+ // Open this file and check that the header is parsed.
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ ASSERT_NO_THROW(csv->open());
+ ASSERT_EQ(3, csv->getColumnCount());
+ EXPECT_EQ("animal", csv->getColumnName(0));
+ EXPECT_EQ("age", csv->getColumnName(1));
+ EXPECT_EQ("color", csv->getColumnName(2));
+
+ // Read first row.
+ CSVRow row;
+ ASSERT_TRUE(csv->next(row));
+ ASSERT_EQ(3, row.getValuesCount());
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("10", row.readAt(1));
+ EXPECT_EQ("white", row.readAt(2));
+
+ // Read second row.
+ ASSERT_TRUE(csv->next(row));
+ ASSERT_EQ(3, row.getValuesCount());
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("15", row.readAt(1));
+ EXPECT_EQ("yellow", row.readAt(2));
+
+ // There is no 3rd row, so the empty one should be returned.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+
+ // It should be fine to read again, but again empty row should be returned.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+
+ // Now, let's try to append something to this file.
+ CSVRow row_write(3);
+ row_write.writeAt(0, "dog");
+ row_write.writeAt(1, 2);
+ row_write.writeAt(2, "blue");
+ ASSERT_NO_THROW(csv->append(row_write));
+
+ // Close the file.
+ ASSERT_NO_THROW(csv->flush());
+ csv->close();
+
+ // Check the file contents are correct.
+ EXPECT_EQ("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n"
+ "dog,2,blue\n",
+ readFile());
+
+ // Any attempt to read from the file or write to it should now fail.
+ EXPECT_FALSE(csv->next(row));
+ EXPECT_THROW(csv->append(row_write), CSVFileError);
+
+ CSVRow row_write2(3);
+ row_write2.writeAt(0, "bird");
+ row_write2.writeAt(1, 3);
+ row_write2.writeAt(2, "purple");
+
+ // Reopen the file, seek to the end of file so as we can append
+ // some more data.
+ ASSERT_NO_THROW(csv->open(true));
+ // The file pointer should be at the end of file, so an attempt
+ // to read should result in an empty row.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+ // We should be able to append new data.
+ ASSERT_NO_THROW(csv->append(row_write2));
+ ASSERT_NO_THROW(csv->flush());
+ csv->close();
+ // Check that new data has been appended.
+ EXPECT_EQ("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n"
+ "dog,2,blue\n"
+ "bird,3,purple\n",
+ readFile());
+}
+
+// This test checks that contents may be appended to a file which hasn't
+// been fully parsed/read.
+TEST_F(CSVFileTest, openReadPartialWrite) {
+ // Create a CSV file with two rows in it.
+ writeFile("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n");
+
+ // Open this file.
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ ASSERT_NO_THROW(csv->open());
+
+ // Read the first row.
+ CSVRow row0(0);
+ ASSERT_NO_THROW(csv->next(row0));
+ ASSERT_EQ(3, row0.getValuesCount());
+ EXPECT_EQ("cat", row0.readAt(0));
+ EXPECT_EQ("10", row0.readAt(1));
+ EXPECT_EQ("white", row0.readAt(2));
+
+ // There is still second row to be read. But, it should be possible to
+ // skip reading it and append new row to the end of file.
+ CSVRow row_write(3);
+ row_write.writeAt(0, "dog");
+ row_write.writeAt(1, 2);
+ row_write.writeAt(2, "blue");
+ ASSERT_NO_THROW(csv->append(row_write));
+
+ // At this point, the file pointer is at the end of file, so reading
+ // should return empty row.
+ CSVRow row1(0);
+ ASSERT_NO_THROW(csv->next(row1));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row1);
+
+ // Close the file.
+ ASSERT_NO_THROW(csv->flush());
+ csv->close();
+
+ // Check that there are two initial lines and one new there.
+ EXPECT_EQ("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n"
+ "dog,2,blue\n",
+ readFile());
+
+}
+
+// This test checks that the new CSV file is created and header
+// is written to it. It also checks that data rows can be
+// appended to it.
+TEST_F(CSVFileTest, recreate) {
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ csv->addColumn("animal");
+ csv->addColumn("color");
+ csv->addColumn("age");
+ csv->addColumn("comments");
+ ASSERT_NO_THROW(csv->recreate());
+ ASSERT_TRUE(exists());
+
+ CSVRow row0(4);
+ row0.writeAt(0, "dog");
+ row0.writeAt(1, "grey");
+ row0.writeAt(2, 3);
+ row0.writeAt(3, "nice one");
+ ASSERT_NO_THROW(csv->append(row0));
+
+ CSVRow row1(4);
+ row1.writeAt(0, "cat");
+ row1.writeAt(1, "black");
+ row1.writeAt(2, 2);
+ ASSERT_NO_THROW(csv->append(row1));
+
+ ASSERT_NO_THROW(csv->flush());
+ csv->close();
+
+ EXPECT_EQ("animal,color,age,comments\n"
+ "dog,grey,3,nice one\n"
+ "cat,black,2,\n",
+ readFile());
+}
+
+// This test checks that the error is reported when the size of the row being
+// read doesn't match the number of columns of the CSV file.
+TEST_F(CSVFileTest, validate) {
+ // Create CSV file with 2 invalid rows in it: one too long, one too short.
+ // Apart from that, there are two valid columns that should be read
+ // successfully.
+ writeFile("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow,black\n"
+ "dog,3,green\n"
+ "elephant,11\n");
+
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ ASSERT_NO_THROW(csv->open());
+ // First row is correct.
+ CSVRow row0;
+ ASSERT_TRUE(csv->next(row0));
+ EXPECT_EQ("cat", row0.readAt(0));
+ EXPECT_EQ("10", row0.readAt(1));
+ EXPECT_EQ("white", row0.readAt(2));
+ EXPECT_EQ("success", csv->getReadMsg());
+ // This row is too long.
+ CSVRow row1;
+ EXPECT_FALSE(csv->next(row1));
+ EXPECT_NE("success", csv->getReadMsg());
+ // This row is correct.
+ CSVRow row2;
+ ASSERT_TRUE(csv->next(row2));
+ EXPECT_EQ("dog", row2.readAt(0));
+ EXPECT_EQ("3", row2.readAt(1));
+ EXPECT_EQ("green", row2.readAt(2));
+ EXPECT_EQ("success", csv->getReadMsg());
+ // This row is too short.
+ CSVRow row3;
+ EXPECT_FALSE(csv->next(row3));
+ EXPECT_NE("success", csv->getReadMsg());
+}
+
+// Test test checks that exception is thrown when the header of the CSV file
+// parsed, doesn't match the columns specified.
+TEST_F(CSVFileTest, validateHeader) {
+ // Create CSV file with 3 columns.
+ writeFile("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow,black\n");
+
+ // Invalid order of columns.
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ csv->addColumn("color");
+ csv->addColumn("animal");
+ csv->addColumn("age");
+ EXPECT_THROW(csv->open(), CSVFileError);
+
+ // Too many columns.
+ csv.reset(new CSVFile(testfile_));
+ csv->addColumn("animal");
+ csv->addColumn("age");
+ csv->addColumn("color");
+ csv->addColumn("notes");
+ EXPECT_THROW(csv->open(), CSVFileError);
+
+ // Too few columns.
+ csv.reset(new CSVFile(testfile_));
+ csv->addColumn("animal");
+ csv->addColumn("age");
+ EXPECT_THROW(csv->open(), CSVFileError);
+}
+
+// This test checks that the exists method of the CSVFile class properly
+// checks that the file exists.
+TEST_F(CSVFileTest, exists) {
+ // Create a new CSV file that contains a header and two data rows.
+ writeFile("animal,age,color\n"
+ "cat,10,white\n"
+ "lion,15,yellow\n");
+
+ boost::scoped_ptr<CSVFile> csv(new CSVFile(testfile_));
+ // The CSVFile class should return true even if the file hasn't been
+ // opened.
+ EXPECT_TRUE(csv->exists());
+ // Now open the file and make sure it still returns true.
+ ASSERT_NO_THROW(csv->open());
+ EXPECT_TRUE(csv->exists());
+
+ // Close the file and remove it.
+ csv->close();
+ EXPECT_EQ(0, removeFile());
+
+ // The file should not exist.
+ EXPECT_FALSE(csv->exists());
+}
+
+// Check that a single header without a trailing blank line can be parsed.
+TEST_F(CSVFileTest, parseHeaderWithoutTrailingBlankLine) {
+ // Create a new CSV file that only contains a header without a new line.
+ writeFile("animal,age,color");
+
+ // Open this file and check that the header is parsed.
+ CSVFile csv(testfile_);
+ ASSERT_NO_THROW(csv.open());
+ ASSERT_EQ(3, csv.getColumnCount());
+ EXPECT_EQ("animal", csv.getColumnName(0));
+ EXPECT_EQ("age", csv.getColumnName(1));
+ EXPECT_EQ("color", csv.getColumnName(2));
+
+ // Attempt to read the next row which doesn't exist.
+ CSVRow row;
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+
+ // Close the file.
+ csv.close();
+}
+
+// Check that content without a trailing blank line can be parsed.
+TEST_F(CSVFileTest, parseContentWithoutTrailingBlankLine) {
+ // Now create a new CSV file that contains header plus data, but the last
+ // line is missing a new line.
+ writeFile("animal,age,color\n"
+ "cat,4,white\n"
+ "lion,8,yellow");
+
+ // Open this file and check that the header is parsed.
+ CSVFile csv(testfile_);
+ ASSERT_NO_THROW(csv.open());
+ ASSERT_EQ(3, csv.getColumnCount());
+ EXPECT_EQ("animal", csv.getColumnName(0));
+ EXPECT_EQ("age", csv.getColumnName(1));
+ EXPECT_EQ("color", csv.getColumnName(2));
+
+ // Check the first data row.
+ CSVRow row;
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("4", row.readAt(1));
+ EXPECT_EQ("white", row.readAt(2));
+ EXPECT_EQ("success", csv.getReadMsg());
+
+ // Check the second data row.
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("8", row.readAt(1));
+ EXPECT_EQ("yellow", row.readAt(2));
+ EXPECT_EQ("success", csv.getReadMsg());
+
+ // Attempt to read the next row which doesn't exist.
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+
+ // Close the file.
+ csv.close();
+}
+
+// Check that blank lines are skipped when reading from a file.
+TEST_F(CSVFileTest, parseContentWithBlankLines) {
+ for (char const* const& content : {
+ // Single intermediary blank line
+ "animal,age,color\n"
+ "cat,4,white\n"
+ "\n"
+ "lion,8,yellow\n",
+
+ // Blank lines all over
+ "\n"
+ "\n"
+ "animal,age,color\n"
+ "\n"
+ "\n"
+ "cat,4,white\n"
+ "\n"
+ "\n"
+ "lion,8,yellow\n"
+ "\n"
+ "\n",
+ }) {
+ // Create a new CSV file.
+ writeFile(content);
+
+ // Open this file and check that the header is parsed.
+ CSVFile csv(testfile_);
+ ASSERT_NO_THROW(csv.open());
+ ASSERT_EQ(3, csv.getColumnCount());
+ EXPECT_EQ("animal", csv.getColumnName(0));
+ EXPECT_EQ("age", csv.getColumnName(1));
+ EXPECT_EQ("color", csv.getColumnName(2));
+
+ // Check the first data row.
+ CSVRow row;
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("4", row.readAt(1));
+ EXPECT_EQ("white", row.readAt(2));
+ EXPECT_EQ("success", csv.getReadMsg());
+
+ // Check the second non-blank data row.
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("8", row.readAt(1));
+ EXPECT_EQ("yellow", row.readAt(2));
+ EXPECT_EQ("success", csv.getReadMsg());
+
+ // Attempt to read the next row which doesn't exist.
+ ASSERT_TRUE(csv.next(row));
+ EXPECT_EQ(CSVFile::EMPTY_ROW(), row);
+
+ // Close the file.
+ csv.close();
+ }
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/dhcp_space_unittest.cc b/src/lib/util/tests/dhcp_space_unittest.cc
new file mode 100644
index 0000000..e5269c4
--- /dev/null
+++ b/src/lib/util/tests/dhcp_space_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/dhcp_space.h>
+
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+using namespace isc::util;
+
+TEST(DhcpSpace, cString) {
+ EXPECT_EQ(std::strcmp(cStringDhcpSpace<DHCPv4>(), "4"), 0);
+ EXPECT_EQ(std::strcmp(cStringDhcpSpace<DHCPv6>(), "6"), 0);
+}
+
+TEST(DhcpSpace, format) {
+ EXPECT_EQ(formatDhcpSpace<DHCPv4>("dhcp{}"), "dhcp4");
+ EXPECT_EQ(formatDhcpSpace<DHCPv6>("dhcp{}"), "dhcp6");
+
+ EXPECT_EQ(formatDhcpSpace<DHCPv4>("Dhcp{}.subnet{}"), "Dhcp4.subnet4");
+ EXPECT_EQ(formatDhcpSpace<DHCPv6>("Dhcp{}.subnet{}"), "Dhcp6.subnet6");
+}
+
+} // namespace
diff --git a/src/lib/util/tests/doubles_unittest.cc b/src/lib/util/tests/doubles_unittest.cc
new file mode 100644
index 0000000..1c17f90
--- /dev/null
+++ b/src/lib/util/tests/doubles_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2019,2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/doubles.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util;
+
+namespace {
+
+// Exercises isc::util::areDoublesEquivalent().
+TEST(Doubles, areDoublesEquivalent) {
+ std::vector<uint8_t> data;
+
+ // Default tolerance is 0.000001
+ EXPECT_TRUE(areDoublesEquivalent( 1.0000000, 1.0000005));
+ EXPECT_FALSE(areDoublesEquivalent(1.0000000, 1.000005));
+
+ // Check custom tolerance.
+ EXPECT_TRUE(areDoublesEquivalent( 1.000, 1.005, 0.01));
+ EXPECT_FALSE(areDoublesEquivalent(1.000, 1.005, 0.001));
+}
+
+}
diff --git a/src/lib/util/tests/fd_share_tests.cc b/src/lib/util/tests/fd_share_tests.cc
new file mode 100644
index 0000000..f870ec2
--- /dev/null
+++ b/src/lib/util/tests/fd_share_tests.cc
@@ -0,0 +1,72 @@
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/io/fd.h>
+#include <util/io/fd_share.h>
+
+#include <util/unittests/check_valgrind.h>
+#include <util/unittests/fork.h>
+
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <cstdio>
+
+using namespace isc::util::io;
+using namespace isc::util::unittests;
+
+namespace {
+
+// We test that we can transfer a pipe over other pipe
+TEST(FDShare, transfer) {
+
+ if (!isc::util::unittests::runningOnValgrind()) {
+ // Get a pipe and fork
+ int pipes[2];
+ ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 0, pipes));
+ const pid_t sender(fork());
+ ASSERT_NE(-1, sender);
+ if (sender) { // We are in parent
+ // Close the other side of pipe, we want only writable one
+ EXPECT_NE(-1, close(pipes[0]));
+ // Get a process to check data
+ int fd(0);
+ const pid_t checker(check_output(&fd, "data", 4));
+ ASSERT_NE(-1, checker);
+ // Now, send the file descriptor, close it and close the pipe
+ EXPECT_NE(-1, send_fd(pipes[1], fd));
+ EXPECT_NE(-1, close(pipes[1]));
+ EXPECT_NE(-1, close(fd));
+ // Check both subprocesses ended well
+ EXPECT_TRUE(process_ok(sender));
+ EXPECT_TRUE(process_ok(checker));
+ } else { // We are in child. We do not use ASSERT here
+ // Close the write end, we only read
+ if (close(pipes[1])) {
+ exit(1);
+ }
+ // Get the file descriptor
+ const int fd(recv_fd(pipes[0]));
+ if (fd == -1) {
+ exit(1);
+ }
+ // This pipe is not needed
+ if (close(pipes[0])) {
+ exit(1);
+ }
+ // Send "data" through the received fd, close it and be done
+ if (!write_data(fd, "data", 4) || close(fd) == -1) {
+ exit(1);
+ }
+ exit(0);
+ }
+ }
+}
+
+}
diff --git a/src/lib/util/tests/fd_tests.cc b/src/lib/util/tests/fd_tests.cc
new file mode 100644
index 0000000..eee597c
--- /dev/null
+++ b/src/lib/util/tests/fd_tests.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/unittests/check_valgrind.h>
+
+#include <util/io/fd.h>
+
+#include <util/unittests/fork.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util::io;
+using namespace isc::util::unittests;
+
+namespace {
+
+// Make sure the test is large enough and does not fit into one
+// read or write request
+const size_t TEST_DATA_SIZE = 8 * 1024 * 1024;
+
+class FDTest : public ::testing::Test {
+public:
+ unsigned char *data, *buffer;
+
+ /// @brief Constructor
+ FDTest() :
+ // We do not care what is inside, we just need it to be the same
+ data(new unsigned char[TEST_DATA_SIZE]),
+ buffer(NULL) {
+ memset(data, 0, TEST_DATA_SIZE);
+ }
+
+ /// @brief Destructor
+ ~FDTest() {
+ delete[] data;
+ delete[] buffer;
+ }
+};
+
+// Test we read what was sent
+TEST_F(FDTest, read) {
+ if (!isc::util::unittests::runningOnValgrind()) {
+ int read_pipe(0);
+ buffer = new unsigned char[TEST_DATA_SIZE];
+ pid_t feeder(provide_input(&read_pipe, data, TEST_DATA_SIZE));
+ ASSERT_GE(feeder, 0);
+ ssize_t received(read_data(read_pipe, buffer, TEST_DATA_SIZE));
+ EXPECT_TRUE(process_ok(feeder));
+ EXPECT_EQ(TEST_DATA_SIZE, received);
+ EXPECT_EQ(0, memcmp(data, buffer, received));
+ }
+}
+
+// Test we write the correct thing
+TEST_F(FDTest, write) {
+ if (!isc::util::unittests::runningOnValgrind()) {
+ int write_pipe(0);
+ pid_t checker(check_output(&write_pipe, data, TEST_DATA_SIZE));
+ ASSERT_GE(checker, 0);
+ EXPECT_TRUE(write_data(write_pipe, data, TEST_DATA_SIZE));
+ EXPECT_EQ(0, close(write_pipe));
+ EXPECT_TRUE(process_ok(checker));
+ }
+}
+
+}
diff --git a/src/lib/util/tests/file_utilities_unittest.cc b/src/lib/util/tests/file_utilities_unittest.cc
new file mode 100644
index 0000000..4ee9093
--- /dev/null
+++ b/src/lib/util/tests/file_utilities_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <util/file_utilities.h>
+#include <gtest/gtest.h>
+#include <fstream>
+
+using namespace isc;
+using namespace isc::util::file;
+using namespace std;
+
+namespace {
+
+/// @brief Test fixture class for testing operations on files.
+class FileUtilTest : public ::testing::Test {
+public:
+
+ /// @brief Destructor.
+ ///
+ /// Deletes the test file if any.
+ virtual ~FileUtilTest();
+};
+
+FileUtilTest::~FileUtilTest() {
+ string test_file_name = string(TEST_DATA_BUILDDIR) + "/fu.test";
+ static_cast<void>(remove(test_file_name.c_str()));
+}
+
+/// @brief Check an error is returned by getContent on not existent file.
+TEST_F(FileUtilTest, notExists) {
+ string file_name("/this/does/not/exists");
+ try {
+ string c = getContent(file_name);
+ FAIL() << "this test must throw before this line";
+ } catch (const BadValue& ex) {
+ string expected = "can't open file '" + file_name;
+ expected += "': No such file or directory";
+ EXPECT_EQ(string(ex.what()), expected);
+ } catch (const std::exception& ex) {
+ FAIL() << "unexpected exception: " << ex.what();
+ }
+}
+
+/// @note No easy can't stat.
+
+/// @brief Check an error is returned by getContent on not regular file.
+TEST_F(FileUtilTest, notRegular) {
+ string file_name("/");
+ try {
+ string c = getContent(file_name);
+ FAIL() << "this test must throw before this line";
+ } catch (const BadValue& ex) {
+ string expected = "'" + file_name + "' must be a regular file";
+ EXPECT_EQ(string(ex.what()), expected);
+ } catch (const std::exception& ex) {
+ FAIL() << "unexpected exception: " << ex.what();
+ }
+}
+
+/// @brief Check getContent works.
+TEST_F(FileUtilTest, basic) {
+ string file_name = string(TEST_DATA_BUILDDIR) + "/fu.test";
+ ofstream fs(file_name.c_str(), ofstream::out | ofstream::trunc);
+ ASSERT_TRUE(fs.is_open());
+ fs << "abdc";
+ fs.close();
+ string content;
+ EXPECT_NO_THROW(content = getContent(file_name));
+ EXPECT_EQ("abdc", content);
+}
+
+/// @brief Check isDir works.
+TEST_F(FileUtilTest, isDir) {
+ EXPECT_TRUE(isDir("/dev"));
+ EXPECT_FALSE(isDir("/dev/null"));
+ EXPECT_FALSE(isDir("/this/does/not/exists"));
+ EXPECT_FALSE(isDir("/etc/hosts"));
+}
+
+}
diff --git a/src/lib/util/tests/filename_unittest.cc b/src/lib/util/tests/filename_unittest.cc
new file mode 100644
index 0000000..39ff1f9
--- /dev/null
+++ b/src/lib/util/tests/filename_unittest.cc
@@ -0,0 +1,225 @@
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <util/filename.h>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+class FilenameTest : public ::testing::Test {
+protected:
+ FilenameTest()
+ {
+ }
+};
+
+
+// Check that the name can be changed
+
+TEST_F(FilenameTest, SetName) {
+ Filename fname("/a/b/c.d");
+ EXPECT_EQ("/a/b/c.d", fname.fullName());
+
+ fname.setName("test.txt");
+ EXPECT_EQ("test.txt", fname.fullName());
+}
+
+
+// Check that the components are split correctly. This is a check of the
+// private member split() method.
+
+TEST_F(FilenameTest, Components) {
+
+ // Complete name
+ Filename fname("/alpha/beta/gamma.delta");
+ EXPECT_EQ("/alpha/beta/", fname.directory());
+ EXPECT_EQ("gamma", fname.name());
+ EXPECT_EQ(".delta", fname.extension());
+ EXPECT_EQ("gamma.delta", fname.nameAndExtension());
+
+ // Directory only
+ fname.setName("/gamma/delta/");
+ EXPECT_EQ("/gamma/delta/", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("", fname.nameAndExtension());
+
+ // Filename only
+ fname.setName("epsilon");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("epsilon", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("epsilon", fname.nameAndExtension());
+
+ // Extension only
+ fname.setName(".zeta");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ(".zeta", fname.extension());
+ EXPECT_EQ(".zeta", fname.nameAndExtension());
+
+ // Missing directory
+ fname.setName("eta.theta");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("eta", fname.name());
+ EXPECT_EQ(".theta", fname.extension());
+ EXPECT_EQ("eta.theta", fname.nameAndExtension());
+
+ // Missing filename
+ fname.setName("/iota/.kappa");
+ EXPECT_EQ("/iota/", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ(".kappa", fname.extension());
+ EXPECT_EQ(".kappa", fname.nameAndExtension());
+
+ // Missing extension
+ fname.setName("lambda/mu/nu");
+ EXPECT_EQ("lambda/mu/", fname.directory());
+ EXPECT_EQ("nu", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("nu", fname.nameAndExtension());
+
+ // Check that the decomposition can occur in the presence of leading and
+ // trailing spaces
+ fname.setName(" lambda/mu/nu\t ");
+ EXPECT_EQ("lambda/mu/", fname.directory());
+ EXPECT_EQ("nu", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("nu", fname.nameAndExtension());
+
+ // Empty string
+ fname.setName("");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("", fname.nameAndExtension());
+
+ // ... and just spaces
+ fname.setName(" ");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("", fname.nameAndExtension());
+
+ // Check corner cases - where separators are present, but strings are
+ // absent.
+ fname.setName("/");
+ EXPECT_EQ("/", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ("", fname.extension());
+ EXPECT_EQ("", fname.nameAndExtension());
+
+ fname.setName(".");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ(".", fname.extension());
+ EXPECT_EQ(".", fname.nameAndExtension());
+
+ fname.setName("/.");
+ EXPECT_EQ("/", fname.directory());
+ EXPECT_EQ("", fname.name());
+ EXPECT_EQ(".", fname.extension());
+ EXPECT_EQ(".", fname.nameAndExtension());
+
+ // Note that the space is a valid filename here; only leading and trailing
+ // spaces should be trimmed.
+ fname.setName("/ .");
+ EXPECT_EQ("/", fname.directory());
+ EXPECT_EQ(" ", fname.name());
+ EXPECT_EQ(".", fname.extension());
+ EXPECT_EQ(" .", fname.nameAndExtension());
+
+ fname.setName(" / . ");
+ EXPECT_EQ("/", fname.directory());
+ EXPECT_EQ(" ", fname.name());
+ EXPECT_EQ(".", fname.extension());
+ EXPECT_EQ(" .", fname.nameAndExtension());
+}
+
+// Check that the expansion with a default works.
+
+TEST_F(FilenameTest, ExpandWithDefault) {
+ Filename fname("a.b");
+
+ // These tests also check that the trimming of the default component is
+ // done properly.
+ EXPECT_EQ("/c/d/a.b", fname.expandWithDefault(" /c/d/ "));
+ EXPECT_EQ("/c/d/a.b", fname.expandWithDefault("/c/d/e.f"));
+ EXPECT_EQ("a.b", fname.expandWithDefault("e.f"));
+
+ fname.setName("/a/b/c");
+ EXPECT_EQ("/a/b/c.d", fname.expandWithDefault(".d"));
+ EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("x.d"));
+ EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("/s/t/u.d"));
+ EXPECT_EQ("/a/b/c", fname.expandWithDefault("/s/t/u"));
+
+ fname.setName(".h");
+ EXPECT_EQ("/a/b/c.h", fname.expandWithDefault("/a/b/c.msg"));
+}
+
+// Check that we can use this as a default in expanding a filename
+
+TEST_F(FilenameTest, UseAsDefault) {
+
+ Filename fname("a.b");
+
+ // These tests also check that the trimming of the default component is
+ // done properly.
+ EXPECT_EQ("/c/d/a.b", fname.useAsDefault(" /c/d/ "));
+ EXPECT_EQ("/c/d/e.f", fname.useAsDefault("/c/d/e.f"));
+ EXPECT_EQ("e.f", fname.useAsDefault("e.f"));
+
+ fname.setName("/a/b/c");
+ EXPECT_EQ("/a/b/c.d", fname.useAsDefault(".d"));
+ EXPECT_EQ("/a/b/x.d", fname.useAsDefault("x.d"));
+ EXPECT_EQ("/s/t/u.d", fname.useAsDefault("/s/t/u.d"));
+ EXPECT_EQ("/s/t/u", fname.useAsDefault("/s/t/u"));
+ EXPECT_EQ("/a/b/c", fname.useAsDefault(""));
+}
+
+TEST_F(FilenameTest, setDirectory) {
+ Filename fname("a.b");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("a.b", fname.fullName());
+ EXPECT_EQ("a.b", fname.expandWithDefault(""));
+
+ fname.setDirectory("/just/some/dir/");
+ EXPECT_EQ("/just/some/dir/", fname.directory());
+ EXPECT_EQ("/just/some/dir/a.b", fname.fullName());
+ EXPECT_EQ("/just/some/dir/a.b", fname.expandWithDefault(""));
+
+ fname.setDirectory("/just/some/dir");
+ EXPECT_EQ("/just/some/dir/", fname.directory());
+ EXPECT_EQ("/just/some/dir/a.b", fname.fullName());
+ EXPECT_EQ("/just/some/dir/a.b", fname.expandWithDefault(""));
+
+ fname.setDirectory("/");
+ EXPECT_EQ("/", fname.directory());
+ EXPECT_EQ("/a.b", fname.fullName());
+ EXPECT_EQ("/a.b", fname.expandWithDefault(""));
+
+ fname.setDirectory("");
+ EXPECT_EQ("", fname.directory());
+ EXPECT_EQ("a.b", fname.fullName());
+ EXPECT_EQ("a.b", fname.expandWithDefault(""));
+
+ fname = Filename("/first/a.b");
+ EXPECT_EQ("/first/", fname.directory());
+ EXPECT_EQ("/first/a.b", fname.fullName());
+ EXPECT_EQ("/first/a.b", fname.expandWithDefault(""));
+
+ fname.setDirectory("/just/some/dir");
+ EXPECT_EQ("/just/some/dir/", fname.directory());
+ EXPECT_EQ("/just/some/dir/a.b", fname.fullName());
+ EXPECT_EQ("/just/some/dir/a.b", fname.expandWithDefault(""));
+}
diff --git a/src/lib/util/tests/hash_unittest.cc b/src/lib/util/tests/hash_unittest.cc
new file mode 100644
index 0000000..f789e51
--- /dev/null
+++ b/src/lib/util/tests/hash_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/hash.h>
+
+#include <gtest/gtest.h>
+
+#include <cstring>
+#include <vector>
+
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+TEST(HashTest, empty) {
+ EXPECT_EQ(14695981039346656037ull, Hash64::hash(0, 0));
+}
+
+TEST(HashTest, foobar) {
+ EXPECT_EQ(9625390261332436968ull, Hash64::hash(string("foobar")));
+}
+
+TEST(HashTest, chongo) {
+ EXPECT_EQ(5080352029159061781ull,
+ Hash64::hash(string("chongo was here!\n")));
+}
+
+}
diff --git a/src/lib/util/tests/hex_unittest.cc b/src/lib/util/tests/hex_unittest.cc
new file mode 100644
index 0000000..1e611b5
--- /dev/null
+++ b/src/lib/util/tests/hex_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <stdint.h>
+
+#include <vector>
+#include <string>
+
+#include <exceptions/exceptions.h>
+
+#include <util/encode/hex.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util::encode;
+
+namespace {
+const string hex_txt("DEADBEEFDECADE");
+const string hex_txt_space("DEAD BEEF DECADE");
+const string hex_txt_lower("deadbeefdecade");
+
+class HexTest : public ::testing::Test {
+protected:
+ HexTest() : encoding_chars("0123456789ABCDEF") {}
+ vector<uint8_t> decoded_data;
+ const string encoding_chars;
+};
+
+TEST_F(HexTest, encodeHex) {
+ std::vector<uint8_t> data;
+
+ data.push_back(0xde);
+ data.push_back(0xad);
+ data.push_back(0xbe);
+ data.push_back(0xef);
+ data.push_back(0xde);
+ data.push_back(0xca);
+ data.push_back(0xde);
+ EXPECT_EQ(hex_txt, encodeHex(data));
+}
+
+void
+compareData(const std::vector<uint8_t>& data) {
+ EXPECT_EQ(0xde, data[0]);
+ EXPECT_EQ(0xad, data[1]);
+ EXPECT_EQ(0xbe, data[2]);
+ EXPECT_EQ(0xef, data[3]);
+ EXPECT_EQ(0xde, data[4]);
+ EXPECT_EQ(0xca, data[5]);
+ EXPECT_EQ(0xde, data[6]);
+}
+
+TEST_F(HexTest, decodeHex) {
+ std::vector<uint8_t> result;
+
+ decodeHex(hex_txt, result);
+ compareData(result);
+
+ // lower case hex digits should be accepted
+ result.clear();
+ decodeHex(hex_txt_lower, result);
+ compareData(result);
+
+ // white space should be ignored
+ result.clear();
+ decodeHex(hex_txt_space, result);
+ compareData(result);
+
+ // Bogus input: should fail
+ result.clear();
+ EXPECT_THROW(decodeHex("1x", result), BadValue);
+
+ // Bogus input: encoded string must have an even number of characters.
+ result.clear();
+ EXPECT_THROW(decodeHex("dea", result), BadValue);
+}
+
+// For Hex encode/decode we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(HexTest, decodeMap) {
+ string input("00"); // input placeholder
+
+ // See Base32HexTest.decodeMap for details of the following tests.
+ for (int i = 0; i < 256; ++i) {
+ input[1] = i;
+
+ const char ch = toupper(i);
+ const size_t pos = encoding_chars.find(ch);
+ if (pos == string::npos) {
+ EXPECT_THROW(decodeHex(input, decoded_data), BadValue);
+ } else {
+ decodeHex(input, decoded_data);
+ EXPECT_EQ(1, decoded_data.size());
+ EXPECT_EQ(pos, decoded_data[0]);
+ }
+ }
+}
+
+TEST_F(HexTest, encodeMap) {
+ for (uint8_t i = 0; i < 16; ++i) {
+ decoded_data.clear();
+ decoded_data.push_back(i);
+ EXPECT_EQ(encoding_chars[i], encodeHex(decoded_data)[1]);
+ }
+}
+
+}
diff --git a/src/lib/util/tests/io_utilities_unittest.cc b/src/lib/util/tests/io_utilities_unittest.cc
new file mode 100644
index 0000000..6ecbf18
--- /dev/null
+++ b/src/lib/util/tests/io_utilities_unittest.cc
@@ -0,0 +1,160 @@
+// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/// \brief Test of asiolink utilities
+///
+/// Tests the functionality of the asiolink utilities code by comparing them
+/// with the equivalent methods in isc::dns::[Input/Output]Buffer.
+
+#include <config.h>
+
+#include <cstddef>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+#include <util/io_utilities.h>
+
+using namespace isc::util;
+
+TEST(asioutil, readUint16) {
+
+ // Reference buffer
+ uint8_t data[2] = {0, 0};
+ InputBuffer buffer(data, sizeof(data));
+
+ // Avoid possible compiler warnings by only setting uint8_t variables to
+ // uint8_t values.
+ uint8_t i8 = 0;
+ uint8_t j8 = 0;
+ for (int i = 0; i < (2 << 8); ++i, ++i8) {
+ for (int j = 0; j < (2 << 8); ++j, ++j8) {
+ data[0] = i8;
+ data[1] = j8;
+ buffer.setPosition(0);
+ EXPECT_EQ(buffer.readUint16(), readUint16(data, sizeof(data)));
+ }
+ }
+}
+
+TEST(asioutil, readUint16OutOfRange) {
+ uint8_t data;
+ EXPECT_THROW(readUint16(&data, sizeof(data)), isc::OutOfRange);
+}
+
+TEST(asioutil, writeUint16) {
+
+ // Reference buffer
+ OutputBuffer buffer(2);
+ uint8_t test[2];
+
+ // Avoid possible compiler warnings by only setting uint16_t variables to
+ // uint16_t values.
+ uint16_t i16 = 0;
+ for (uint32_t i = 0; i < (2 << 16); ++i, ++i16) {
+
+ // Write the reference data
+ buffer.clear();
+ buffer.writeUint16(i16);
+
+ // ... and the test data
+ writeUint16(i16, test, sizeof(test));
+
+ // ... and compare
+ const uint8_t* ref = static_cast<const uint8_t*>(buffer.getData());
+ EXPECT_EQ(ref[0], test[0]);
+ EXPECT_EQ(ref[1], test[1]);
+ }
+}
+
+TEST(asioutil, writeUint16OutOfRange) {
+ uint16_t i16 = 42;
+ uint8_t data;
+ EXPECT_THROW(writeUint16(i16, &data, sizeof(data)), isc::OutOfRange);
+}
+
+// test data shared amount readUint32 and writeUint32 tests
+const static uint32_t test32[] = {
+ 0,
+ 1,
+ 2000,
+ 0x80000000,
+ 0xffffffff
+};
+
+TEST(asioutil, readUint32) {
+ uint8_t data[8];
+
+ // make sure that we can read data, regardless of
+ // the memory alignment. That' why we need to repeat
+ // it 4 times.
+ for (int offset=0; offset < 4; offset++) {
+ for (int i=0; i < sizeof(test32)/sizeof(uint32_t); i++) {
+ uint32_t tmp = htonl(test32[i]);
+ memcpy(&data[offset], &tmp, sizeof(uint32_t));
+
+ EXPECT_EQ(test32[i], readUint32(&data[offset], sizeof(uint32_t)));
+ }
+ }
+}
+
+TEST(asioutil, readUint32OutOfRange) {
+ uint8_t data[3];
+ EXPECT_THROW(readUint32(data, sizeof(data)), isc::OutOfRange);
+}
+
+TEST(asioutil, writeUint32) {
+ uint8_t data[8];
+
+ // make sure that we can write data, regardless of
+ // the memory alignment. That's why we need to repeat
+ // it 4 times.
+ for (int offset=0; offset < 4; offset++) {
+ for (int i=0; i < sizeof(test32)/sizeof(uint32_t); i++) {
+ uint8_t* ptr = writeUint32(test32[i], &data[offset],
+ sizeof(uint32_t));
+
+ EXPECT_EQ(&data[offset]+sizeof(uint32_t), ptr);
+
+ uint32_t tmp = htonl(test32[i]);
+
+ EXPECT_EQ(0, memcmp(&tmp, &data[offset], sizeof(uint32_t)));
+ }
+ }
+}
+
+TEST(asioutil, writeUint32OutOfRange) {
+ uint32_t i32 = 28;
+ uint8_t data[3];
+ EXPECT_THROW(writeUint32(i32, data, sizeof(data)), isc::OutOfRange);
+}
+
+// Tests whether uint64 can be read from a buffer properly.
+TEST(asioutil, readUint64) {
+
+ uint8_t buf[8];
+ for (int offset = 0; offset < sizeof(buf); offset++) {
+ buf[offset] = offset+1;
+ }
+
+ // Let's do some simple sanity checks first.
+ EXPECT_THROW(readUint64(NULL, 0), isc::OutOfRange);
+ EXPECT_THROW(readUint64(buf, 7), isc::OutOfRange);
+
+ // Now check if a real value could be read.
+ const uint64_t exp_val = 0x0102030405060708ul;
+ uint64_t val;
+
+ EXPECT_NO_THROW(val = readUint64(buf, 8));
+ EXPECT_EQ(val, exp_val);
+
+ // Now check if there are no buffer overflows.
+ memset(buf, 0xff, 8);
+
+ EXPECT_NO_THROW(val = readUint64(buf, 8));
+ EXPECT_EQ(0xfffffffffffffffful, val);
+}
diff --git a/src/lib/util/tests/labeled_value_unittest.cc b/src/lib/util/tests/labeled_value_unittest.cc
new file mode 100644
index 0000000..c994156
--- /dev/null
+++ b/src/lib/util/tests/labeled_value_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/labeled_value.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Verifies basic construction and accessors for LabeledValue.
+TEST(LabeledValue, construction) {
+ /// Verify that an empty label is not allowed.
+ ASSERT_THROW(LabeledValue(1, ""), LabeledValueError);
+
+ /// Verify that a valid constructor works.
+ LabeledValuePtr lvp;
+ ASSERT_NO_THROW(lvp.reset(new LabeledValue(1, "NotBlank")));
+ ASSERT_TRUE(lvp);
+
+ // Verify that the value can be accessed.
+ EXPECT_EQ(1, lvp->getValue());
+
+ // Verify that the label can be accessed.
+ EXPECT_EQ("NotBlank", lvp->getLabel());
+}
+
+/// @brief Verifies the logical operators defined for LabeledValue.
+TEST(LabeledValue, operators) {
+ LabeledValuePtr lvp1;
+ LabeledValuePtr lvp1Also;
+ LabeledValuePtr lvp2;
+
+ // Create three instances, two of which have the same numeric value.
+ ASSERT_NO_THROW(lvp1.reset(new LabeledValue(1, "One")));
+ ASSERT_NO_THROW(lvp1Also.reset(new LabeledValue(1, "OneAlso")));
+ ASSERT_NO_THROW(lvp2.reset(new LabeledValue(2, "Two")));
+
+ // Verify each of the operators.
+ EXPECT_TRUE(*lvp1 == *lvp1Also);
+ EXPECT_TRUE(*lvp1 != *lvp2);
+ EXPECT_TRUE(*lvp1 < *lvp2);
+ EXPECT_FALSE(*lvp2 < *lvp1);
+}
+
+/// @brief Verifies the default constructor for LabeledValueSet.
+TEST(LabeledValueSet, construction) {
+ ASSERT_NO_THROW (LabeledValueSet());
+}
+
+/// @brief Verifies the basic operations of a LabeledValueSet.
+/// Essentially we verify that we can define a set of valid entries and
+/// look them up without issue.
+TEST(LabeledValueSet, basicOperation) {
+ const char* labels[] = {"Zero", "One", "Two", "Three" };
+ LabeledValueSet lvset;
+ LabeledValuePtr lvp;
+
+ // Verify the we cannot add an empty pointer to the set.
+ EXPECT_THROW(lvset.add(lvp), LabeledValueError);
+
+ // Verify that we can add an entry to the set via pointer.
+ ASSERT_NO_THROW(lvp.reset(new LabeledValue(0, labels[0])));
+ EXPECT_NO_THROW(lvset.add(lvp));
+
+ // Verify that we cannot add a duplicate entry.
+ EXPECT_THROW(lvset.add(lvp), LabeledValueError);
+
+ // Add the remaining entries using add(int,char*) variant.
+ for (int i = 1; i < 3; i++) {
+ EXPECT_NO_THROW(lvset.add(i, labels[i]));
+ }
+
+ // Verify that we can't add a duplicate entry this way either.
+ EXPECT_THROW ((lvset.add(0, labels[0])), LabeledValueError);
+
+ // Verify that we can look up all of the defined entries properly.
+ for (int i = 1; i < 3; i++) {
+ EXPECT_TRUE(lvset.isDefined(i));
+ EXPECT_NO_THROW(lvp = lvset.get(i));
+ EXPECT_EQ(lvp->getValue(), i);
+ EXPECT_EQ(lvp->getLabel(), labels[i]);
+ EXPECT_EQ(lvset.getLabel(i), labels[i]);
+ }
+
+ // Verify behavior for a value that is not defined.
+ EXPECT_FALSE(lvset.isDefined(4));
+ EXPECT_NO_THROW(lvp = lvset.get(4));
+ EXPECT_FALSE(lvp);
+ EXPECT_EQ(lvset.getLabel(4), LabeledValueSet::UNDEFINED_LABEL);
+}
+
+}
diff --git a/src/lib/util/tests/memory_segment_common_unittest.cc b/src/lib/util/tests/memory_segment_common_unittest.cc
new file mode 100644
index 0000000..f95021d
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_common_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/memory_segment.h>
+
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <cstring>
+#include <stdint.h>
+
+namespace isc {
+namespace util {
+namespace test {
+
+void
+checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok) {
+ // NULL name is not allowed.
+ EXPECT_THROW(segment.getNamedAddress(NULL), InvalidParameter);
+
+ // If the name does not exist, false should be returned.
+ EXPECT_FALSE(segment.getNamedAddress("test address").first);
+
+ // Now set it
+ void* ptr32 = segment.allocate(sizeof(uint32_t));
+ const uint32_t test_val = 42;
+ *static_cast<uint32_t*>(ptr32) = test_val;
+ EXPECT_FALSE(segment.setNamedAddress("test address", ptr32));
+
+ // NULL name isn't allowed.
+ EXPECT_THROW(segment.setNamedAddress(NULL, ptr32), InvalidParameter);
+ EXPECT_THROW(segment.getNamedAddress(NULL), InvalidParameter);
+ EXPECT_THROW(segment.clearNamedAddress(NULL), InvalidParameter);
+
+ // Empty names are not allowed.
+ EXPECT_THROW(segment.setNamedAddress("", ptr32), InvalidParameter);
+ EXPECT_THROW(segment.getNamedAddress(""), InvalidParameter);
+ EXPECT_THROW(segment.clearNamedAddress(""), InvalidParameter);
+
+ // Names beginning with _ are not allowed.
+ EXPECT_THROW(segment.setNamedAddress("_foo", ptr32), InvalidParameter);
+ EXPECT_THROW(segment.getNamedAddress("_foo"), InvalidParameter);
+ EXPECT_THROW(segment.clearNamedAddress("_foo"), InvalidParameter);
+
+ // we can now get it; the stored value should be intact.
+ MemorySegment::NamedAddressResult result =
+ segment.getNamedAddress("test address");
+ EXPECT_TRUE(result.first);
+ EXPECT_EQ(test_val, *static_cast<const uint32_t*>(result.second));
+
+ // Override it.
+ void* ptr16 = segment.allocate(sizeof(uint16_t));
+ const uint16_t test_val16 = 4200;
+ *static_cast<uint16_t*>(ptr16) = test_val16;
+ EXPECT_FALSE(segment.setNamedAddress("test address", ptr16));
+ result = segment.getNamedAddress("test address");
+ EXPECT_TRUE(result.first);
+ EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(result.second));
+
+ // Clear it. Then we won't be able to find it any more.
+ EXPECT_TRUE(segment.clearNamedAddress("test address"));
+ EXPECT_FALSE(segment.getNamedAddress("test address").first);
+
+ // duplicate attempt of clear will result in false as it doesn't exist.
+ EXPECT_FALSE(segment.clearNamedAddress("test address"));
+
+ // Setting NULL is okay.
+ EXPECT_FALSE(segment.setNamedAddress("null address", NULL));
+ result = segment.getNamedAddress("null address");
+ EXPECT_TRUE(result.first);
+ EXPECT_FALSE(result.second);
+
+ // If the underlying implementation performs explicit check against
+ // out-of-segment address, confirm the behavior.
+ if (!out_of_segment_ok) {
+ uint8_t ch = 'A';
+ EXPECT_THROW(segment.setNamedAddress("local address", &ch),
+ MemorySegmentError);
+ }
+
+ // clean them up all
+ segment.deallocate(ptr32, sizeof(uint32_t));
+ EXPECT_FALSE(segment.allMemoryDeallocated()); // not fully deallocated
+ segment.deallocate(ptr16, sizeof(uint16_t)); // not yet
+ EXPECT_FALSE(segment.allMemoryDeallocated());
+ EXPECT_TRUE(segment.clearNamedAddress("null address"));
+ // null name isn't allowed:
+ EXPECT_THROW(segment.clearNamedAddress(NULL), InvalidParameter);
+ EXPECT_TRUE(segment.allMemoryDeallocated()); // now everything is gone
+}
+
+}
+}
+}
diff --git a/src/lib/util/tests/memory_segment_common_unittest.h b/src/lib/util/tests/memory_segment_common_unittest.h
new file mode 100644
index 0000000..435ff12
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_common_unittest.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <util/memory_segment.h>
+
+namespace isc {
+namespace util {
+namespace test {
+
+/// \brief Implementation dependent checks on memory segment named addresses.
+///
+/// This function contains a set of test cases for given memory segment
+/// regarding "named address" methods. The test cases basically only depend
+/// on the base class interfaces, but if the underlying implementation does
+/// not check if the given address to setNamedAddress() belongs to the segment,
+/// out_of_segment_ok should be set to true.
+void checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok);
+
+}
+}
+}
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/tests/memory_segment_local_unittest.cc b/src/lib/util/tests/memory_segment_local_unittest.cc
new file mode 100644
index 0000000..d1aa52d
--- /dev/null
+++ b/src/lib/util/tests/memory_segment_local_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/tests/memory_segment_common_unittest.h>
+
+#include <util/memory_segment_local.h>
+#include <exceptions/exceptions.h>
+#include <gtest/gtest.h>
+#include <boost/scoped_ptr.hpp>
+#include <memory>
+#include <limits.h>
+
+using namespace std;
+using namespace isc::util;
+
+namespace {
+
+TEST(MemorySegmentLocal, TestLocal) {
+ boost::scoped_ptr<MemorySegment> segment(new MemorySegmentLocal());
+
+ // By default, nothing is allocated.
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+
+ void* ptr = segment->allocate(1024);
+
+ // Now, we have an allocation:
+ EXPECT_FALSE(segment->allMemoryDeallocated());
+
+ void* ptr2 = segment->allocate(42);
+
+ // Still:
+ EXPECT_FALSE(segment->allMemoryDeallocated());
+
+ // These should not fail, because the buffers have been allocated.
+ EXPECT_NO_FATAL_FAILURE(memset(ptr, 0, 1024));
+ EXPECT_NO_FATAL_FAILURE(memset(ptr, 0, 42));
+
+ segment->deallocate(ptr, 1024);
+
+ // Still:
+ EXPECT_FALSE(segment->allMemoryDeallocated());
+
+ segment->deallocate(ptr2, 42);
+
+ // Now, we have an deallocated everything:
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+}
+
+/// @todo: disabled, see ticket #3510
+TEST(MemorySegmentLocal, DISABLED_TestTooMuchMemory) {
+ boost::scoped_ptr<MemorySegment> segment(new MemorySegmentLocal());
+
+ // Although it should be perfectly fine to use the ULONG_MAX
+ // instead of LONG_MAX as the size_t value should be unsigned,
+ // Valgrind appears to be using the signed value and hence the
+ // maximum positive value is LONG_MAX for Valgrind. But, this
+ // should be sufficient to test the "too much memory" conditions.
+ EXPECT_THROW(segment->allocate(LONG_MAX), bad_alloc);
+}
+
+TEST(MemorySegmentLocal, TestBadDeallocate) {
+ boost::scoped_ptr<MemorySegment> segment(new MemorySegmentLocal());
+
+ // By default, nothing is allocated.
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+
+ void* ptr = segment->allocate(1024);
+
+ // Now, we have an allocation:
+ EXPECT_FALSE(segment->allMemoryDeallocated());
+
+ // This should not throw
+ EXPECT_NO_THROW(segment->deallocate(ptr, 1024));
+
+ // Now, we have an deallocated everything:
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+
+ ptr = segment->allocate(1024);
+
+ // Now, we have another allocation:
+ EXPECT_FALSE(segment->allMemoryDeallocated());
+
+ // This should throw as the size passed to deallocate() is larger
+ // than what was allocated.
+ EXPECT_THROW(segment->deallocate(ptr, 2048), isc::OutOfRange);
+
+ // This should not throw
+ EXPECT_NO_THROW(segment->deallocate(ptr, 1024));
+
+ // Now, we have an deallocated everything:
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+}
+
+TEST(MemorySegmentLocal, TestNullDeallocate) {
+ boost::scoped_ptr<MemorySegment> segment(new MemorySegmentLocal());
+
+ // By default, nothing is allocated.
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+
+ // NULL deallocation is a no-op.
+ EXPECT_NO_THROW(segment->deallocate(NULL, 1024));
+
+ // This should still return true.
+ EXPECT_TRUE(segment->allMemoryDeallocated());
+}
+
+TEST(MemorySegmentLocal, namedAddress) {
+ MemorySegmentLocal segment;
+ isc::util::test::checkSegmentNamedAddress(segment, true);
+}
+
+} // anonymous namespace
diff --git a/src/lib/util/tests/multi_threading_mgr_unittest.cc b/src/lib/util/tests/multi_threading_mgr_unittest.cc
new file mode 100644
index 0000000..f2a46d9
--- /dev/null
+++ b/src/lib/util/tests/multi_threading_mgr_unittest.cc
@@ -0,0 +1,626 @@
+// Copyright (C) 2019-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <util/multi_threading_mgr.h>
+#include <testutils/gtest_utils.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+using namespace isc;
+
+/// @brief Verifies that the default mode is false (MT disabled).
+TEST(MultiThreadingMgrTest, defaultMode) {
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+}
+
+/// @brief Verifies that the mode setter works.
+TEST(MultiThreadingMgrTest, setMode) {
+ // enable MT
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(true));
+ // MT should be enabled
+ EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
+ // disable MT
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(false));
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+}
+
+/// @brief Verifies that accessing the thread pool works.
+TEST(MultiThreadingMgrTest, threadPool) {
+ // get the thread pool
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().getThreadPool());
+}
+
+/// @brief Verifies that the thread pool size setter works.
+TEST(MultiThreadingMgrTest, threadPoolSize) {
+ // default thread count is 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // set thread count to 16
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setThreadPoolSize(16));
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // set thread count to 0
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setThreadPoolSize(0));
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+}
+
+/// @brief Verifies that the packet queue size setter works.
+TEST(MultiThreadingMgrTest, packetQueueSize) {
+ // default queue size is 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 0);
+ // set queue size to 16
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setPacketQueueSize(16));
+ // queue size should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 16);
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 16);
+ // set queue size to 0
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setPacketQueueSize(0));
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPool().getMaxQueueSize(), 0);
+}
+
+/// @brief Verifies that detecting thread count works.
+TEST(MultiThreadingMgrTest, detectThreadCount) {
+ // detecting thread count should work
+ EXPECT_NE(MultiThreadingMgr::detectThreadCount(), 0);
+}
+
+/// @brief Verifies that apply settings works.
+TEST(MultiThreadingMgrTest, applyConfig) {
+ // get the thread pool
+ auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+ // default thread count is 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // enable MT with 16 threads and queue size 256
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 16, 256));
+ // MT should be enabled
+ EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // thread pool should be started
+ EXPECT_EQ(thread_pool.size(), 16);
+ // disable MT
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 16, 256));
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // enable MT with auto scaling
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 0, 0));
+ // MT should be enabled
+ EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
+ // thread count should be detected automatically
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), MultiThreadingMgr::detectThreadCount());
+ // thread pool should be started
+ EXPECT_EQ(thread_pool.size(), MultiThreadingMgr::detectThreadCount());
+ // disable MT
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 0, 0));
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+}
+
+/// @brief Verifies that the critical section flag works.
+TEST(MultiThreadingMgrTest, criticalSectionFlag) {
+ // get the thread pool
+ auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+ // critical section should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // exit critical section
+ EXPECT_THROW(MultiThreadingMgr::instance().exitCriticalSection(), InvalidOperation);
+ // critical section should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
+ // enter critical section
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().enterCriticalSection());
+ // critical section should be enabled
+ EXPECT_TRUE(MultiThreadingMgr::instance().isInCriticalSection());
+ // enable MT with 16 threads and queue size 256
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(true, 16, 256));
+ // MT should be enabled
+ EXPECT_TRUE(MultiThreadingMgr::instance().getMode());
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // exit critical section
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().exitCriticalSection());
+ // critical section should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
+ // exit critical section
+ EXPECT_THROW(MultiThreadingMgr::instance().exitCriticalSection(), InvalidOperation);
+ // critical section should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().isInCriticalSection());
+ // disable MT
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().apply(false, 0, 0));
+ // MT should be disabled
+ EXPECT_FALSE(MultiThreadingMgr::instance().getMode());
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+}
+
+/// @brief Verifies that the critical section works.
+TEST(MultiThreadingMgrTest, criticalSection) {
+ // get the thread pool instance
+ auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // apply multi-threading configuration with 16 threads and queue size 256
+ MultiThreadingMgr::instance().apply(true, 16, 256);
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 16);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection inner_cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ }
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ }
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 16);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 16
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 16);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // apply multi-threading configuration with 64 threads and queue size 4
+ MultiThreadingMgr::instance().apply(true, 64, 4);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 64
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
+ // queue size should be 4
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
+ }
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 64);
+ // thread count should be 64
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
+ // queue size should be 4
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 64
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
+ // queue size should be 4
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 4);
+ // apply multi-threading configuration with 0 threads
+ MultiThreadingMgr::instance().apply(false, 64, 256);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ }
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection inner_cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ }
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ }
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 0);
+ // queue size should be 0
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 0);
+ // use scope to test constructor and destructor
+ {
+ MultiThreadingCriticalSection cs;
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // apply multi-threading configuration with 64 threads
+ MultiThreadingMgr::instance().apply(true, 64, 256);
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+ // thread count should be 64
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ }
+ // thread count should match
+ EXPECT_EQ(thread_pool.size(), 64);
+ // thread count should be 64
+ EXPECT_EQ(MultiThreadingMgr::instance().getThreadPoolSize(), 64);
+ // queue size should be 256
+ EXPECT_EQ(MultiThreadingMgr::instance().getPacketQueueSize(), 256);
+ // apply multi-threading configuration with 0 threads
+ MultiThreadingMgr::instance().apply(false, 0, 0);
+}
+
+/// @brief Checks that the lock works only when multi-threading is enabled and
+/// only during its lifetime.
+TEST(MultiThreadingLockTest, scope) {
+ // Check that the mutex is unlocked by default at first.
+ std::mutex mutex;
+ ASSERT_TRUE(mutex.try_lock());
+ mutex.unlock();
+
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(false));
+
+ // Check that the lock does not locks the mutex if multi-threading is disabled.
+ {
+ MultiThreadingLock lock(mutex);
+ ASSERT_TRUE(mutex.try_lock());
+ mutex.unlock();
+ }
+
+ // Check that the mutex is still unlocked when the lock goes out of scope.
+ ASSERT_TRUE(mutex.try_lock());
+ mutex.unlock();
+
+ EXPECT_NO_THROW(MultiThreadingMgr::instance().setMode(true));
+
+ // Check that the lock actively locks the mutex if multi-threading is enabled.
+ {
+ MultiThreadingLock lock(mutex);
+ ASSERT_FALSE(mutex.try_lock());
+ }
+
+ // Check that the mutex is unlocked when the lock goes out of scope.
+ ASSERT_TRUE(mutex.try_lock());
+ mutex.unlock();
+}
+
+/// @brief Test fixture for exercised CriticalSection callbacks.
+class CriticalSectionCallbackTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ CriticalSectionCallbackTest() {
+ MultiThreadingMgr::instance().apply(false, 0, 0);
+ }
+
+ /// @brief Destructor.
+ ~CriticalSectionCallbackTest() {
+ MultiThreadingMgr::instance().apply(false, 0, 0);
+ }
+
+ /// @brief A callback that adds the value 1 to invocations lists.
+ void one() {
+ invocations_.push_back(1);
+ }
+
+ /// @brief A callback that adds the value 2 to invocations lists.
+ void two() {
+ invocations_.push_back(2);
+ }
+
+ /// @brief A callback that adds the value 3 to invocations lists.
+ void three() {
+ invocations_.push_back(3);
+ }
+
+ /// @brief A callback that adds the value 4 to invocations lists.
+ void four() {
+ invocations_.push_back(4);
+ }
+
+ /// @brief A callback that throws @ref isc::Exception which is ignored.
+ void ignoredException() {
+ isc_throw(isc::Exception, "ignored");
+ }
+
+ /// @brief A callback that throws @ref isc::MultiThreadingInvalidOperation
+ /// which is propagated to the scope of the
+ /// @ref MultiThreadingCriticalSection constructor.
+ void observedException() {
+ isc_throw(isc::MultiThreadingInvalidOperation, "observed");
+ }
+
+ /// @brief Indicates whether or not the DHCP thread pool is running.
+ ///
+ /// @return True if the pool is running, false otherwise.
+ bool isThreadPoolRunning() {
+ return (MultiThreadingMgr::instance().getThreadPool().size());
+ }
+
+ /// @brief Checks callback invocations over a series of nested
+ /// CriticalSections.
+ ///
+ /// @param entries A vector of the invocation values that should
+ /// be present after entry into the outermost CriticalSection. The
+ /// expected values should be in the order the callbacks were added
+ /// to the MultiThreadingMgr's list of callbacks.
+ /// @param exits A vector of the invocation values that should
+ /// be present after exiting the outermost CriticalSection. The
+ /// expected values should be in the order the callbacks were added
+ /// to the MultiThreadingMgr's list of callbacks.
+ /// @param should_throw The flag indicating if the CriticalSection should
+ /// throw, simulating a dead-lock scenario when a processing thread tries
+ /// to stop the thread pool.
+ void runCriticalSections(std::vector<int> entries, std::vector<int>exits,
+ bool should_throw = false) {
+ // Pool must be running.
+ ASSERT_TRUE(isThreadPoolRunning());
+
+ // Clear the invocations list.
+ invocations_.clear();
+
+ // Use scope to create nested CriticalSections.
+ if (!should_throw) {
+ // Enter a critical section.
+ MultiThreadingCriticalSection cs;
+
+ // Thread pool should be stopped.
+ ASSERT_FALSE(isThreadPoolRunning());
+
+ if (entries.size()) {
+ // We expect entry invocations.
+ ASSERT_EQ(invocations_.size(), entries.size());
+ ASSERT_EQ(invocations_, entries);
+ } else {
+ // We do not expect entry invocations.
+ ASSERT_FALSE(invocations_.size());
+ }
+
+ // Clear the invocations list.
+ invocations_.clear();
+
+ {
+ // Enter another CriticalSection.
+ MultiThreadingCriticalSection inner_cs;
+
+ // Thread pool should still be stopped.
+ ASSERT_FALSE(isThreadPoolRunning());
+
+ // We should not have had any callback invocations.
+ ASSERT_FALSE(invocations_.size());
+ }
+
+ // After exiting inner section, the thread pool should
+ // still be stopped.
+ ASSERT_FALSE(isThreadPoolRunning());
+
+ // We should not have had more callback invocations.
+ ASSERT_FALSE(invocations_.size());
+ } else {
+ ASSERT_THROW(MultiThreadingCriticalSection cs, MultiThreadingInvalidOperation);
+
+ if (entries.size()) {
+ // We expect entry invocations.
+ ASSERT_EQ(invocations_.size(), entries.size());
+ ASSERT_EQ(invocations_, entries);
+ } else {
+ // We do not expect entry invocations.
+ ASSERT_FALSE(invocations_.size());
+ }
+
+ // Clear the invocations list.
+ invocations_.clear();
+ }
+
+ // After exiting the outer section, the thread pool should
+ // match the thread count.
+ ASSERT_TRUE(isThreadPoolRunning());
+
+ if (exits.size()) {
+ // We expect exit invocations.
+ ASSERT_EQ(invocations_, exits);
+ } else {
+ // We do not expect exit invocations.
+ ASSERT_FALSE(invocations_.size());
+ }
+ }
+
+ /// @brief A list of values set by callback invocations.
+ std::vector<int> invocations_;
+};
+
+/// @brief Verifies critical section callback maintenance:
+/// catch invalid pairs, add pairs, remove pairs.
+TEST_F(CriticalSectionCallbackTest, addAndRemove) {
+ auto& mgr = MultiThreadingMgr::instance();
+
+ // Cannot add with a blank name.
+ ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("", [](){}, [](){}, [](){}),
+ BadValue, "CSCallbackSetList - name cannot be empty");
+
+ // Cannot add with an empty check callback.
+ ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", nullptr, [](){}, [](){}),
+ BadValue, "CSCallbackSetList - check callback for bad cannot be empty");
+
+ // Cannot add with an empty exit callback.
+ ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", [](){}, nullptr, [](){}),
+ BadValue, "CSCallbackSetList - entry callback for bad cannot be empty");
+
+ // Cannot add with an empty exit callback.
+ ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("bad", [](){}, [](){}, nullptr),
+ BadValue, "CSCallbackSetList - exit callback for bad cannot be empty");
+
+ // Should be able to add foo.
+ ASSERT_NO_THROW_LOG(mgr.addCriticalSectionCallbacks("foo", [](){}, [](){}, [](){}));
+
+ // Should not be able to add foo twice.
+ ASSERT_THROW_MSG(mgr.addCriticalSectionCallbacks("foo", [](){}, [](){}, [](){}),
+ BadValue, "CSCallbackSetList - callbacks for foo already exist");
+
+ // Should be able to add bar.
+ ASSERT_NO_THROW_LOG(mgr.addCriticalSectionCallbacks("bar", [](){}, [](){}, [](){}));
+
+ // Should be able to remove foo.
+ ASSERT_NO_THROW_LOG(mgr.removeCriticalSectionCallbacks("foo"));
+
+ // Should be able to remove foo twice without issue.
+ ASSERT_NO_THROW_LOG(mgr.removeCriticalSectionCallbacks("foo"));
+
+ // Should be able to remove all without issue.
+ ASSERT_NO_THROW_LOG(mgr.removeAllCriticalSectionCallbacks());
+}
+
+/// @brief Verifies that the critical section callbacks work.
+TEST_F(CriticalSectionCallbackTest, invocations) {
+ // get the thread pool instance
+ auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+
+ // Add two sets of CriticalSection call backs.
+ MultiThreadingMgr::instance().addCriticalSectionCallbacks("oneAndTwo",
+ std::bind(&CriticalSectionCallbackTest::ignoredException, this),
+ std::bind(&CriticalSectionCallbackTest::one, this),
+ std::bind(&CriticalSectionCallbackTest::two, this));
+
+ MultiThreadingMgr::instance().addCriticalSectionCallbacks("threeAndFour",
+ std::bind(&CriticalSectionCallbackTest::ignoredException, this),
+ std::bind(&CriticalSectionCallbackTest::three, this),
+ std::bind(&CriticalSectionCallbackTest::four, this));
+
+ // Apply multi-threading configuration with 16 threads and queue size 256.
+ MultiThreadingMgr::instance().apply(true, 16, 256);
+
+ // Make three passes over nested CriticalSections to ensure
+ // callbacks execute at the appropriate times and we can do
+ // so repeatedly.
+ for (int i = 0; i < 3; ++i) {
+ runCriticalSections({1 ,3}, {4, 2});
+ }
+
+ // Now remove the first set of callbacks.
+ MultiThreadingMgr::instance().removeCriticalSectionCallbacks("oneAndTwo");
+
+ // Retest CriticalSections.
+ runCriticalSections({3}, {4});
+
+ // Now remove the remaining callbacks.
+ MultiThreadingMgr::instance().removeAllCriticalSectionCallbacks();
+
+ // Retest CriticalSections.
+ runCriticalSections({}, {});
+}
+
+/// @brief Verifies that the critical section callbacks work.
+TEST_F(CriticalSectionCallbackTest, invocationsWithExceptions) {
+ // get the thread pool instance
+ auto& thread_pool = MultiThreadingMgr::instance().getThreadPool();
+ // thread pool should be stopped
+ EXPECT_EQ(thread_pool.size(), 0);
+
+ // Apply multi-threading configuration with 16 threads and queue size 256.
+ MultiThreadingMgr::instance().apply(true, 16, 256);
+
+ // Add two sets of CriticalSection call backs.
+ MultiThreadingMgr::instance().addCriticalSectionCallbacks("observed",
+ std::bind(&CriticalSectionCallbackTest::observedException, this),
+ std::bind(&CriticalSectionCallbackTest::one, this),
+ std::bind(&CriticalSectionCallbackTest::two, this));
+
+ MultiThreadingMgr::instance().addCriticalSectionCallbacks("ignored",
+ std::bind(&CriticalSectionCallbackTest::ignoredException, this),
+ std::bind(&CriticalSectionCallbackTest::three, this),
+ std::bind(&CriticalSectionCallbackTest::four, this));
+
+ // Make three passes over nested CriticalSections to ensure
+ // callbacks execute at the appropriate times and we can do
+ // so repeatedly.
+ for (int i = 0; i < 3; ++i) {
+ runCriticalSections({}, {}, true);
+ }
+
+ // Now remove the first set of callbacks.
+ MultiThreadingMgr::instance().removeCriticalSectionCallbacks("observed");
+
+ // Retest CriticalSections.
+ runCriticalSections({3}, {4});
+
+ // Now remove the remaining callbacks.
+ MultiThreadingMgr::instance().removeAllCriticalSectionCallbacks();
+
+ // Retest CriticalSections.
+ runCriticalSections({}, {});
+}
diff --git a/src/lib/util/tests/optional_unittest.cc b/src/lib/util/tests/optional_unittest.cc
new file mode 100644
index 0000000..71830ab
--- /dev/null
+++ b/src/lib/util/tests/optional_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <util/optional.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+using namespace isc::util;
+
+// This test checks that the constructors work correctly.
+TEST(OptionalTest, constructor) {
+ // Explicitly set a value via constructor. The value becomes
+ // specified.
+ Optional<int> value1(10);
+ EXPECT_EQ(10, value1.get());
+ EXPECT_FALSE(value1.unspecified());
+
+ // Do not set a value in a constructor. The value should be
+ // unspecified.
+ Optional<int> value2;
+ EXPECT_EQ(0, value2.get());
+ EXPECT_TRUE(value2.unspecified());
+
+ // Use the non-default value for second parameter.
+ Optional<bool> value3(true, true);
+ EXPECT_TRUE(value3.get());
+ EXPECT_TRUE(value3.unspecified());
+}
+
+// This test checks if the constructors for a string value
+// work correctly.
+TEST(OptionalTest, constructorString) {
+ Optional<std::string> value1("foo");
+ EXPECT_EQ("foo", value1.get());
+ EXPECT_FALSE(value1.unspecified());
+
+ Optional<std::string> value2;
+ EXPECT_TRUE(value2.get().empty());
+ EXPECT_TRUE(value2.unspecified());
+}
+
+// This test checks if the assignment operator assigning an actual
+// value to the optional value works as expected.
+TEST(OptionalTest, assignValue) {
+ Optional<int> value(10, true);
+ EXPECT_EQ(10, value.get());
+ EXPECT_TRUE(value.unspecified());
+
+ // Assign a new value.
+ value = 111;
+ EXPECT_EQ(111, value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ // Assign another value.
+ value = 1000;
+ EXPECT_EQ(1000, value.get());
+ EXPECT_FALSE(value.unspecified());
+}
+
+// This test checks if the assignment operator assigning an actual
+// string value to the optional value works as expected.
+TEST(OptionalTest, assignStringValue) {
+ Optional<std::string> value("foo");
+ EXPECT_EQ("foo", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ value = "bar";
+ EXPECT_EQ("bar", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ value = "foobar";
+ EXPECT_EQ("foobar", value.get());
+ EXPECT_FALSE(value.unspecified());
+}
+
+// This test checks that it is possible to modify the flag that indicates
+// if the value is specified or unspecified.
+TEST(OptionalTest, modifyUnspecified) {
+ Optional<int> value;
+ EXPECT_TRUE(value.unspecified());
+
+ value.unspecified(false);
+ EXPECT_FALSE(value.unspecified());
+
+ value.unspecified(true);
+ EXPECT_TRUE(value.unspecified());
+}
+
+// This test checks if the type case operator returns correct value.
+TEST(OptionalTest, typeCastOperator) {
+ Optional<int> value(-10);
+ EXPECT_EQ(-10, value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ int actual = value;
+ EXPECT_EQ(-10, actual);
+}
+
+// This test checks if the type case operator returns correct string
+// value.
+TEST(OptionalTest, stringCastOperator) {
+ Optional<std::string> value("xyz");
+ EXPECT_EQ("xyz", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ std::string actual = value;
+ EXPECT_EQ("xyz", actual);
+}
+
+// This test checks that the equality operators work as expected.
+TEST(OptionalTest, equality) {
+ int exp_value = 1234;
+ Optional<int> value(1234);
+ EXPECT_TRUE(value == exp_value);
+ EXPECT_FALSE(value != exp_value);
+}
+
+// This test checks that the equality operators for strings work as
+// expected.
+TEST(OptionalTest, stringEquality) {
+ const char* exp_value = "foo";
+ Optional<std::string> value("foo");
+ EXPECT_TRUE(value == exp_value);
+ EXPECT_FALSE(value != exp_value);
+}
+
+// This test checks that an exception is thrown when calling an empty()
+// method on non-string optional value.
+TEST(OptionalTest, empty) {
+ Optional<int> value(10);
+ EXPECT_THROW(value.empty(), isc::InvalidOperation);
+}
+
+// This test checks that no exception is thrown when calling an empty()
+// method on string optional value and that it returns an expected
+// boolean value.
+TEST(OptionalTest, stringEmpty) {
+ Optional<std::string> value("foo");
+ bool is_empty = true;
+ ASSERT_NO_THROW(is_empty = value.empty());
+ EXPECT_FALSE(is_empty);
+
+ value = "";
+ ASSERT_NO_THROW(is_empty = value.empty());
+ EXPECT_TRUE(is_empty);
+}
+
+// Checks that the valueOr function works correctly.
+TEST(OptionalTest, valueOr) {
+ Optional<std::string> optional("foo");
+ EXPECT_EQ(optional.valueOr("bar"), "foo");
+
+ Optional<std::string> unspecified_optional;
+ EXPECT_EQ(unspecified_optional.valueOr("bar"), "bar");
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/pid_file_unittest.cc b/src/lib/util/tests/pid_file_unittest.cc
new file mode 100644
index 0000000..5f00d72
--- /dev/null
+++ b/src/lib/util/tests/pid_file_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/pid_file.h>
+#include <gtest/gtest.h>
+#include <fstream>
+#include <signal.h>
+#include <stdint.h>
+
+namespace {
+using namespace isc::util;
+
+// Filenames used for testing.
+const char* TESTNAME = "pid_file.test";
+
+class PIDFileTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor
+ PIDFileTest() = default;
+
+ /// @brief Destructor
+ virtual ~PIDFileTest() = default;
+
+ /// @brief Prepends the absolute path to the file specified
+ /// as an argument.
+ ///
+ /// @param filename Name of the file.
+ /// @return Absolute path to the test file.
+ static std::string absolutePath(const std::string& filename);
+
+ /// @brief Generate a random number for use as a PID
+ ///
+ /// @param start - the start of the range we want the PID in
+ /// @param range - the size of the range for our PID
+ ///
+ /// @return returns a random value between start and start + range
+ int randomizePID(const uint32_t start, const uint32_t range) {
+ int pid;
+
+ for (pid = (random() % range) + start;
+ kill(pid, 0) == 0;
+ ++pid)
+ ;
+
+ return (pid);
+ }
+
+protected:
+ /// @brief Removes any old test files before the test
+ virtual void SetUp() {
+ removeTestFile();
+ }
+
+ /// @brief Removes any remaining test files after the test
+ virtual void TearDown() {
+ removeTestFile();
+ }
+
+private:
+ /// @brief Removes any remaining test files
+ void removeTestFile() const {
+ static_cast<void>(remove(absolutePath(TESTNAME).c_str()));
+ }
+
+};
+
+std::string
+PIDFileTest::absolutePath(const std::string& filename) {
+ std::ostringstream s;
+ s << TEST_DATA_BUILDDIR << "/" << filename;
+
+ return (s.str());
+}
+
+/// @brief Test file writing and deletion. Start by removing
+/// any leftover file. Then write a known PID to the file and
+/// attempt to read the file and verify the PID. Next write
+/// a second and verify a second PID to verify that an existing
+/// file is properly overwritten.
+
+TEST_F(PIDFileTest, writeAndDelete) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ std::ifstream fs;
+ int pid(0);
+
+ // Write a known process id
+ pid_file.write(10);
+
+ // Read the file and compare the pid
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ fs >> pid;
+ EXPECT_TRUE(fs.good());
+ EXPECT_EQ(pid, 10);
+ fs.close();
+
+ // Write a second known process id
+ pid_file.write(20);
+
+ // And compare the second pid
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ fs >> pid;
+ EXPECT_TRUE(fs.good());
+ EXPECT_EQ(pid, 20);
+ fs.close();
+
+ // Delete the file
+ pid_file.deleteFile();
+
+ // And verify that it's gone
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ EXPECT_FALSE(fs.good());
+ fs.close();
+}
+
+/// @brief Test checking a PID. Write the PID of the current
+/// process to the PID file then verify that check indicates
+/// the process is running.
+TEST_F(PIDFileTest, pidInUse) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Write the current PID
+ pid_file.write();
+
+ // Check if we think the process is running
+ EXPECT_EQ(getpid(), pid_file.check());
+}
+
+/// @brief Test checking a PID. Write a PID that isn't in use
+/// to the PID file and verify that check indicates the process
+/// isn't running. The PID may get used between when we select it
+/// and write the file and when we check it. To minimize false
+/// errors if the first call to check fails we try again with a
+/// different range of values and only if both attempts fail do
+/// we declare the test to have failed.
+TEST_F(PIDFileTest, pidNotInUse) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ int pid;
+
+ // get a pid between 10000 and 20000
+ pid = randomizePID(10000, 10000);
+
+ // write it
+ pid_file.write(pid);
+
+ // Check to see if we think the process is running
+ if (pid_file.check() == 0) {
+ return;
+ }
+
+ // get a pid between 40000 and 50000
+ pid = randomizePID(10000, 40000);
+
+ // write it
+ pid_file.write(pid);
+
+ // Check to see if we think the process is running
+ EXPECT_EQ(0, pid_file.check());
+}
+
+/// @brief Test checking a PID. Write garbage to the PID file
+/// and verify that check throws an error. In this situation
+/// the caller should probably log an error and may decide to
+/// continue or not depending on the requirements.
+TEST_F(PIDFileTest, pidGarbage) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ std::ofstream fs;
+
+ // Open the file and write garbage to it
+ fs.open(absolutePath(TESTNAME).c_str(), std::ofstream::out);
+ fs << "text" << std::endl;
+ fs.close();
+
+ // Run the check, we expect to get an exception
+ EXPECT_THROW(pid_file.check(), PIDCantReadPID);
+}
+
+/// @brief Test failing to write a file.
+TEST_F(PIDFileTest, pidWriteFail) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Create the test file and change it's permission bits
+ // so we can't write to it.
+ pid_file.write(10);
+ chmod(absolutePath(TESTNAME).c_str(), S_IRUSR);
+
+ // Now try a write to the file, expecting an exception
+ EXPECT_THROW(pid_file.write(10), PIDFileError);
+
+ // Don't forget to restore the write right for the next test
+ chmod(absolutePath(TESTNAME).c_str(), S_IRUSR | S_IWUSR);
+}
+
+/// @brief Test deleting a file that doesn't exist
+TEST_F(PIDFileTest, noDeleteFile) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Delete a file we haven't created
+ pid_file.deleteFile();
+}
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/range_utilities_unittest.cc b/src/lib/util/tests/range_utilities_unittest.cc
new file mode 100644
index 0000000..ce94a38
--- /dev/null
+++ b/src/lib/util/tests/range_utilities_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include <util/range_utilities.h>
+
+using namespace std;
+using namespace isc::util;
+
+TEST(RangeUtilitiesTest, isZero) {
+
+ vector<uint8_t> vec(32,0);
+
+ EXPECT_TRUE(isRangeZero(vec.begin(), vec.end()));
+
+ EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+1));
+
+ vec[5] = 1;
+ EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+5));
+ EXPECT_FALSE(isRangeZero(vec.begin(), vec.begin()+6));
+}
+
+TEST(RangeUtilitiesTest, randomFill) {
+
+ srandom(time(NULL));
+
+ vector<uint8_t> vec1(16,0);
+ vector<uint8_t> vec2(16,0);
+
+ // Testing if returned value is actually random is extraordinary difficult.
+ // Let's just generate bunch of vectors and see if we get the same
+ // value. If we manage to do that in 100 tries, pseudo-random generator
+ // really sucks.
+ fillRandom(vec1.begin(), vec1.end());
+ for (int i=0; i<100; i++) {
+ fillRandom(vec2.begin(), vec2.end());
+ if (vec1 == vec2)
+ FAIL();
+ }
+
+}
diff --git a/src/lib/util/tests/readwrite_mutex_unittest.cc b/src/lib/util/tests/readwrite_mutex_unittest.cc
new file mode 100644
index 0000000..6b4af5f
--- /dev/null
+++ b/src/lib/util/tests/readwrite_mutex_unittest.cc
@@ -0,0 +1,470 @@
+// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/readwrite_mutex.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+
+#include <chrono>
+#include <iostream>
+#include <thread>
+#include <unistd.h>
+
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief Test Fixture for testing read-write mutexes.
+///
+/// Each not basic test follows the same schema:
+/// @code
+/// main thread work thread
+/// <- started
+/// work ->
+/// enter guard
+/// <- done
+/// terminate ->
+/// return
+/// join
+/// @endcode
+class ReadWriteMutexTest : public ::testing::Test {
+public:
+
+ /// @brief Read-write mutex.
+ ReadWriteMutex rw_mutex_;
+
+ /// @brief Synchronization objects for work threads.
+ struct Sync {
+ bool started = false;
+ mutex started_mtx;
+ condition_variable started_cv;
+ bool work = false;
+ mutex work_mtx;
+ condition_variable work_cv;
+ bool done = false;
+ mutex done_mtx;
+ condition_variable done_cv;
+ bool terminate = false;
+ mutex terminate_mtx;
+ condition_variable terminate_cv;
+ } syncr_, syncw_;
+
+ /// @brief Body of the reader.
+ ///
+ /// @param rw_mutex The read-write mutex.
+ /// @param syncr The reader synchronization object.
+ void reader(ReadWriteMutex& rw_mutex, Sync& syncr) {
+ // Take mutex to wait for main thread signals.
+ unique_lock<mutex> terminate_lock(syncr.terminate_mtx);
+
+ // Signal the thread started.
+ {
+ lock_guard<mutex> lock(syncr.started_mtx);
+ syncr.started = true;
+ }
+
+ // Wait for work.
+ {
+ unique_lock<mutex> work_lock(syncr.work_mtx);
+ // When this thread starts waiting, the main thread is resumed.
+ syncr.started_cv.notify_one();
+ syncr.work_cv.wait(work_lock, [&](){ return syncr.work; });
+ }
+
+ {
+ // Enter a read lock guard.
+ ReadLockGuard rwlock(rw_mutex);
+
+ // Signal the thread holds the guard.
+ {
+ lock_guard<mutex> done_lock(syncr.done_mtx);
+ syncr.done = true;
+ }
+ syncr.done_cv.notify_one();
+ }
+
+ // Wait to terminate.
+ syncr.terminate_cv.wait(terminate_lock, [&](){ return syncr.terminate; });
+ }
+
+ /// @brief Body of the writer.
+ ///
+ /// @param rw_mutex The read-write mutex.
+ /// @param syncw The writer synchronization object.
+ void writer(ReadWriteMutex& rw_mutex, Sync& syncw) {
+ // Take mutex to wait for main thread signals.
+ unique_lock<mutex> terminate_lock(syncw.terminate_mtx);
+
+ // Signal the thread started.
+ {
+ lock_guard<mutex> lock(syncw.started_mtx);
+ syncw.started = true;
+ }
+
+ // Wait for work.
+ {
+ unique_lock<mutex> work_lock(syncw.work_mtx);
+ // When this thread starts waiting, the main thread is resumed.
+ syncw.started_cv.notify_one();
+ syncw.work_cv.wait(work_lock, [&](){ return syncw.work; });
+ }
+
+ {
+ // Enter a write lock guard.
+ WriteLockGuard rwlock(rw_mutex);
+
+ // Signal the thread holds the guard.
+ {
+ lock_guard<mutex> done_lock(syncw.done_mtx);
+ syncw.done = true;
+ }
+ syncw.done_cv.notify_one();
+ }
+
+ // Wait to terminate.
+ syncw.terminate_cv.wait(terminate_lock, [&](){ return syncw.terminate; });
+ }
+};
+
+// Verify basic read lock guard.
+TEST_F(ReadWriteMutexTest, basicRead) {
+ ReadLockGuard lock(rw_mutex_);
+}
+
+// Verify basic write lock guard.
+TEST_F(ReadWriteMutexTest, basicWrite) {
+ WriteLockGuard lock(rw_mutex_);
+}
+
+// Verify read lock guard using a thread.
+TEST_F(ReadWriteMutexTest, read) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> thread;
+ {
+ unique_lock<mutex> started_lock(syncr_.started_mtx);
+
+ // Create a work thread.
+ thread = boost::make_shared<std::thread>([this](){ reader(rw_mutex_, syncr_); });
+
+ // Wait work thread to start.
+ syncr_.started_cv.wait(started_lock, [this](){ return syncr_.started; });
+
+ unique_lock<mutex> done_lock(syncr_.done_mtx);
+
+ // Signal the thread to work.
+ {
+ lock_guard<mutex> work_lock(syncr_.work_mtx);
+ syncr_.work = true;
+ }
+ syncr_.work_cv.notify_one();
+
+ // Wait thread to hold the read lock.
+ syncr_.done_cv.wait(done_lock, [this](){ return syncr_.done; });
+ }
+
+ // Signal the thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncr_.terminate_mtx);
+ syncr_.terminate = true;
+ }
+ syncr_.terminate_cv.notify_one();
+
+ // Join the thread.
+ thread->join();
+}
+
+// Verify write lock guard using a thread.
+TEST_F(ReadWriteMutexTest, write) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> thread;
+ {
+ unique_lock<mutex> started_lock(syncw_.started_mtx);
+
+ // Create a work thread.
+ thread = boost::make_shared<std::thread>([this](){ writer(rw_mutex_, syncw_); });
+
+ // Wait work thread to start.
+ syncw_.started_cv.wait(started_lock, [this](){ return syncw_.started; });
+
+ unique_lock<mutex> done_lock(syncw_.done_mtx);
+
+ // Signal the thread to work.
+ {
+ lock_guard<mutex> work_lock(syncw_.work_mtx);
+ syncw_.work = true;
+ }
+ syncw_.work_cv.notify_one();
+
+ // Wait thread to hold the write lock.
+ syncw_.done_cv.wait(done_lock, [this](){ return syncw_.done; });
+ }
+
+ // Signal the thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncw_.terminate_mtx);
+ syncw_.terminate = true;
+ }
+ syncw_.terminate_cv.notify_one();
+
+ // Join the thread.
+ thread->join();
+}
+
+// Verify read lock guard can be acquired by multiple threads.
+TEST_F(ReadWriteMutexTest, readRead) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> thread;
+ {
+ unique_lock<mutex> started_lock(syncr_.started_mtx);
+
+ // Create a work thread.
+ thread = boost::make_shared<std::thread>([this](){ reader(rw_mutex_, syncr_); });
+
+ // Enter a read lock guard.
+ ReadLockGuard rwlock(rw_mutex_);
+
+ // Wait work thread to start.
+ syncr_.started_cv.wait(started_lock, [this](){ return syncr_.started; });
+
+ unique_lock<mutex> done_lock(syncr_.done_mtx);
+
+ // Signal the thread to work.
+ {
+ lock_guard<mutex> work_lock(syncr_.work_mtx);
+ syncr_.work = true;
+ }
+ syncr_.work_cv.notify_one();
+
+ // Wait thread to hold the read lock.
+ syncr_.done_cv.wait(done_lock, [this](){ return syncr_.done; });
+ }
+
+ // Signal the thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncr_.terminate_mtx);
+ syncr_.terminate = true;
+ }
+ syncr_.terminate_cv.notify_one();
+
+ // Join the thread.
+ thread->join();
+}
+
+// Verify write lock guard is exclusive of a reader.
+TEST_F(ReadWriteMutexTest, readWrite) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> thread;
+ {
+ unique_lock<mutex> started_lock(syncw_.started_mtx);
+
+ // Create a work thread.
+ thread = boost::make_shared<std::thread>([this](){ writer(rw_mutex_, syncw_); });
+
+ // Wait work thread to start.
+ syncw_.started_cv.wait(started_lock, [this](){ return syncw_.started; });
+
+ unique_lock<mutex> done_lock(syncw_.done_mtx);
+
+ {
+ // Enter a read lock guard.
+ ReadLockGuard rwlock(rw_mutex_);
+
+ // Signal the thread to work.
+ {
+ lock_guard<mutex> work_lock(syncw_.work_mtx);
+ syncw_.work = true;
+ }
+ syncw_.work_cv.notify_one();
+
+ // Verify the work thread is waiting for the write lock.
+ cout << "pausing for one second" << std::endl;
+ bool ret = syncw_.done_cv.wait_for(done_lock, chrono::seconds(1), [this](){ return syncw_.done; });
+
+ EXPECT_FALSE(syncw_.done);
+ EXPECT_FALSE(ret);
+
+ // Exiting the read lock guard.
+ }
+
+ // Wait thread to hold the write lock.
+ syncw_.done_cv.wait(done_lock, [this](){ return syncw_.done; });
+ }
+
+ // Signal the thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncw_.terminate_mtx);
+ syncw_.terminate = true;
+ }
+ syncw_.terminate_cv.notify_one();
+
+ // Join the thread.
+ thread->join();
+}
+
+// Verify write lock guard is exclusive of a writer.
+TEST_F(ReadWriteMutexTest, writeWrite) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> thread;
+ {
+ unique_lock<mutex> started_lock(syncw_.started_mtx);
+
+ // Create a work thread.
+ thread = boost::make_shared<std::thread>([this](){ writer(rw_mutex_, syncw_); });
+
+ // Wait work thread to start.
+ syncw_.started_cv.wait(started_lock, [this](){ return syncw_.started; });
+
+ unique_lock<mutex> done_lock(syncw_.done_mtx);
+
+ {
+ // Enter a write lock guard.
+ WriteLockGuard rwlock(rw_mutex_);
+
+ // Signal the thread to work.
+ {
+ lock_guard<mutex> work_lock(syncw_.work_mtx);
+ syncw_.work = true;
+ }
+ syncw_.work_cv.notify_one();
+
+ // Verify the work thread is waiting for the write lock.
+ cout << "pausing for one second" << std::endl;
+ bool ret = syncw_.done_cv.wait_for(done_lock, chrono::seconds(1), [this](){ return syncw_.done; });
+
+ EXPECT_FALSE(syncw_.done);
+ EXPECT_FALSE(ret);
+
+ // Exiting the write lock guard.
+ }
+
+ // Wait thread to hold the write lock.
+ syncw_.done_cv.wait(done_lock, [this](){ return syncw_.done; });
+ }
+
+ // Signal the thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncw_.terminate_mtx);
+ syncw_.terminate = true;
+ }
+ syncw_.terminate_cv.notify_one();
+
+ // Join the thread.
+ thread->join();
+}
+
+// Verify that a writer has the preference.
+TEST_F(ReadWriteMutexTest, readWriteRead) {
+ // Take mutex to wait for work thread signals.
+ boost::shared_ptr<std::thread> threadw;
+ {
+ unique_lock<mutex> startedw_lock(syncw_.started_mtx);
+
+ // First thread is a writer.
+ threadw = boost::make_shared<std::thread>([this](){ writer(rw_mutex_, syncw_); });
+
+ // Wait work thread to start.
+ syncw_.started_cv.wait(startedw_lock, [this](){ return syncw_.started; });
+ }
+
+ boost::shared_ptr<std::thread> threadr;
+ {
+ unique_lock<mutex> startedr_lock(syncr_.started_mtx);
+
+ // Second thread is a reader.
+ threadr = boost::make_shared<std::thread>([this](){ reader(rw_mutex_, syncr_); });
+
+ // Wait work thread to start.
+ syncr_.started_cv.wait(startedr_lock, [this](){ return syncr_.started; });
+ }
+
+ {
+ unique_lock<mutex> donew_lock(syncw_.done_mtx);
+ {
+ // Enter a read lock guard.
+ ReadLockGuard rwlock(rw_mutex_);
+
+ // Signal the writer thread to work.
+ {
+ lock_guard<mutex> work_lock(syncw_.work_mtx);
+ syncw_.work = true;
+ }
+ syncw_.work_cv.notify_one();
+
+ // Verify the writer thread is waiting for the write lock.
+ cout << "pausing for one second" << std::endl;
+ bool ret = syncw_.done_cv.wait_for(donew_lock, chrono::seconds(1), [this](){ return syncw_.done; });
+
+ EXPECT_FALSE(syncw_.done);
+ EXPECT_FALSE(ret);
+
+ {
+ unique_lock<mutex> doner_lock(syncr_.done_mtx);
+
+ // Signal the reader thread to work.
+ {
+ lock_guard<mutex> work_lock(syncr_.work_mtx);
+ syncr_.work = true;
+ }
+ syncr_.work_cv.notify_one();
+
+ // Verify the reader thread is waiting for the read lock.
+ cout << "pausing for one second" << std::endl;
+ bool ret = syncr_.done_cv.wait_for(doner_lock, chrono::seconds(1), [this](){ return syncr_.done; });
+
+ EXPECT_FALSE(syncr_.done);
+ EXPECT_FALSE(ret);
+ }
+ // Exiting the read lock guard.
+ }
+
+ {
+ unique_lock<mutex> doner_lock(syncr_.done_mtx);
+ // Verify the reader thread is still waiting for the read lock.
+ cout << "pausing for one second" << std::endl;
+ bool ret = syncr_.done_cv.wait_for(doner_lock, chrono::seconds(1), [this](){ return syncr_.done; });
+
+ EXPECT_FALSE(syncr_.done);
+ EXPECT_FALSE(ret);
+ }
+
+ // Wait writer thread to hold the write lock.
+ syncw_.done_cv.wait(donew_lock, [this](){ return syncw_.done; });
+ }
+
+ {
+ unique_lock<mutex> doner_lock(syncr_.done_mtx);
+ // Wait reader thread to hold the read lock.
+ syncr_.done_cv.wait(doner_lock, [this](){ return syncr_.done; });
+ }
+
+ // Signal the writer thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncw_.terminate_mtx);
+ syncw_.terminate = true;
+ }
+ syncw_.terminate_cv.notify_one();
+
+ // Join the writer thread.
+ threadw->join();
+
+ // Signal the reader thread to terminate.
+ {
+ lock_guard<mutex> terminate_lock(syncr_.terminate_mtx);
+ syncr_.terminate = true;
+ }
+ syncr_.terminate_cv.notify_one();
+
+ // Join the reader thread.
+ threadr->join();
+}
+
+}
diff --git a/src/lib/util/tests/run_unittests.cc b/src/lib/util/tests/run_unittests.cc
new file mode 100644
index 0000000..ef2a372
--- /dev/null
+++ b/src/lib/util/tests/run_unittests.cc
@@ -0,0 +1,18 @@
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+#include <util/unittests/run_all.h>
+#include <stdlib.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return (isc::util::unittests::run_all());
+}
diff --git a/src/lib/util/tests/staged_value_unittest.cc b/src/lib/util/tests/staged_value_unittest.cc
new file mode 100644
index 0000000..bcfc677
--- /dev/null
+++ b/src/lib/util/tests/staged_value_unittest.cc
@@ -0,0 +1,106 @@
+// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <util/staged_value.h>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+namespace {
+
+using namespace isc::util;
+
+// This test verifies that the value can be assigned and committed.
+TEST(StagedValueTest, assignAndCommit) {
+ // Initially the value should be set to a default
+ StagedValue<int> value;
+ ASSERT_EQ(0, value.getValue());
+
+ // Set the new value without committing it and make sure it
+ // can be retrieved.
+ value.setValue(4);
+ ASSERT_EQ(4, value.getValue());
+
+ // Commit the value and make sure it still can be retrieved.
+ value.commit();
+ ASSERT_EQ(4, value.getValue());
+
+ // Set new value and retrieve it.
+ value.setValue(10);
+ ASSERT_EQ(10, value.getValue());
+
+ // Do it again and commit it.
+ value.setValue(20);
+ ASSERT_EQ(20, value.getValue());
+ value.commit();
+ EXPECT_EQ(20, value.getValue());
+}
+
+// This test verifies that the value can be reverted if it hasn't been
+// committed.
+TEST(StagedValueTest, revert) {
+ // Set the value and commit.
+ StagedValue<int> value;
+ value.setValue(123);
+ value.commit();
+
+ // Set new value and do not commit.
+ value.setValue(500);
+ // The new value should be the one returned.
+ ASSERT_EQ(500, value.getValue());
+ // But, reverting gets us back to original value.
+ value.revert();
+ EXPECT_EQ(123, value.getValue());
+ // Reverting again doesn't have any effect.
+ value.revert();
+ EXPECT_EQ(123, value.getValue());
+}
+
+// This test verifies that the value can be restored to an original one.
+TEST(StagedValueTest, reset) {
+ // Set the new value and commit.
+ StagedValue<int> value;
+ value.setValue(123);
+ value.commit();
+
+ // Override the value but do not commit.
+ value.setValue(500);
+
+ // Resetting should take us back to default value.
+ value.reset();
+ EXPECT_EQ(0, value.getValue());
+ value.revert();
+ EXPECT_EQ(0, value.getValue());
+}
+
+// This test verifies that second commit doesn't modify a value.
+TEST(StagedValueTest, commit) {
+ // Set the value and commit.
+ StagedValue<int> value;
+ value.setValue(123);
+ value.commit();
+
+ // Second commit should have no effect.
+ value.commit();
+ EXPECT_EQ(123, value.getValue());
+}
+
+// This test checks that type conversion operator works correctly.
+TEST(StagedValueTest, conversionOperator) {
+ StagedValue<int> value;
+ value.setValue(244);
+ EXPECT_EQ(244, value);
+}
+
+// This test checks that the assignment operator works correctly.
+TEST(StagedValueTest, assignmentOperator) {
+ StagedValue<int> value;
+ value = 111;
+ EXPECT_EQ(111, value);
+}
+
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/state_model_unittest.cc b/src/lib/util/tests/state_model_unittest.cc
new file mode 100644
index 0000000..eaaba73
--- /dev/null
+++ b/src/lib/util/tests/state_model_unittest.cc
@@ -0,0 +1,916 @@
+// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/state_model.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Test derivation of StateModel for exercising state model mechanics.
+///
+/// This class facilitates testing by making non-public methods accessible so
+/// they can be invoked directly in test routines. It implements a very
+/// rudimentary state model, sufficient to test the state model mechanics
+/// supplied by the base class.
+class StateModelTest : public StateModel, public testing::Test {
+public:
+
+ ///@brief StateModelTest states
+ ///@brief Fake state used for handler mapping tests.
+ static const int DUMMY_ST = SM_DERIVED_STATE_MIN + 1;
+
+ ///@brief Starting state for the test state model.
+ static const int READY_ST = SM_DERIVED_STATE_MIN + 2;
+
+ ///@brief State which simulates doing asynchronous work.
+ static const int DO_WORK_ST = SM_DERIVED_STATE_MIN + 3;
+
+ ///@brief State which finishes off processing.
+ static const int DONE_ST = SM_DERIVED_STATE_MIN + 4;
+
+ ///@brief State in which model is always paused.
+ static const int PAUSE_ALWAYS_ST = SM_DERIVED_STATE_MIN + 5;
+
+ ///@brief State in which model is paused at most once.
+ static const int PAUSE_ONCE_ST = SM_DERIVED_STATE_MIN + 6;
+
+ // StateModelTest events
+ ///@brief Event used to trigger initiation of asynchronous work.
+ static const int WORK_START_EVT = SM_DERIVED_EVENT_MIN + 1;
+
+ ///@brief Event issued when the asynchronous work "completes".
+ static const int WORK_DONE_EVT = SM_DERIVED_EVENT_MIN + 2;
+
+ ///@brief Event issued when all the work is done.
+ static const int ALL_DONE_EVT = SM_DERIVED_EVENT_MIN + 3;
+
+ ///@brief Event used to trigger an attempt to transition to bad state
+ static const int FORCE_UNDEFINED_ST_EVT = SM_DERIVED_EVENT_MIN + 4;
+
+ ///@brief Event used to trigger an attempt to transition to bad state
+ static const int SIMULATE_ERROR_EVT = SM_DERIVED_EVENT_MIN + 5;
+
+ ///@brief Event used to indicate that state machine is unpaused.
+ static const int UNPAUSED_EVT = SM_DERIVED_EVENT_MIN + 6;
+
+ /// @brief Constructor
+ ///
+ /// Parameters match those needed by StateModel.
+ StateModelTest() : dummy_called_(false), work_completed_(false),
+ failure_explanation_("") {
+ }
+ /// @brief Destructor
+ virtual ~StateModelTest() {
+ }
+
+ /// @brief Fetches the value of the dummy called flag.
+ bool getDummyCalled() {
+ return (dummy_called_);
+ }
+
+ /// @brief StateHandler for fake state, DummyState.
+ ///
+ /// It simply sets the dummy called flag to indicate that this method
+ /// was invoked.
+ void dummyHandler() {
+ dummy_called_ = true;
+ }
+
+ /// @brief Returns the failure explanation string.
+ ///
+ /// This value is set only via onModelFailure and it stores whatever
+ /// explanation that method was passed.
+ const std::string& getFailureExplanation() {
+ return (failure_explanation_);
+ }
+
+ /// @brief Returns indication of whether or not the model succeeded.
+ ///
+ /// If true, this indicates that the test model executed correctly through
+ /// to completion. The flag is only by the DONE_ST handler.
+ bool getWorkCompleted() {
+ return (work_completed_);
+ }
+
+ /// @brief State handler for the READY_ST.
+ ///
+ /// Serves as the starting state handler, it consumes the
+ /// START_EVT "transitioning" to the state, DO_WORK_ST and
+ /// sets the next event to WORK_START_EVT.
+ void readyHandler() {
+ switch(getNextEvent()) {
+ case START_EVT:
+ transition(DO_WORK_ST, WORK_START_EVT);
+ break;
+ default:
+ // its bogus
+ isc_throw(StateModelError, "readyHandler:invalid event: "
+ << getContextStr());
+ }
+ }
+
+ /// @brief State handler for the DO_WORK_ST.
+ ///
+ /// Simulates a state that starts some form of asynchronous work.
+ /// When next event is WORK_START_EVT it sets the status to pending
+ /// and signals the state model must "wait" for an event by setting
+ /// next event to NOP_EVT.
+ ///
+ /// When next event is IO_COMPLETED_EVT, it transitions to the state,
+ /// DONE_ST, and sets the next event to WORK_DONE_EVT.
+ void doWorkHandler() {
+ switch(getNextEvent()) {
+ case WORK_START_EVT:
+ postNextEvent(NOP_EVT);
+ break;
+ case WORK_DONE_EVT:
+ work_completed_ = true;
+ transition(DONE_ST, ALL_DONE_EVT);
+ break;
+ case FORCE_UNDEFINED_ST_EVT:
+ transition(9999, ALL_DONE_EVT);
+ break;
+ case SIMULATE_ERROR_EVT:
+ throw std::logic_error("Simulated Unexpected Error");
+ break;
+ default:
+ // its bogus
+ isc_throw(StateModelError, "doWorkHandler:invalid event: "
+ << getContextStr());
+ }
+ }
+
+ /// @brief State handler for the DONE_ST.
+ ///
+ /// This is the last state in the model. Note that it sets the
+ /// status to completed and next event to NOP_EVT.
+ void doneWorkHandler() {
+ switch(getNextEvent()) {
+ case ALL_DONE_EVT:
+ endModel();
+ break;
+ default:
+ // its bogus
+ isc_throw(StateModelError, "doneWorkHandler:invalid event: "
+ << getContextStr());
+ }
+ }
+
+ /// @brief State handler for PAUSE_ALWAYS_ST and PAUSE_ONCE_ST.
+ void pauseHandler() {
+ postNextEvent(NOP_EVT);
+ }
+
+ /// @brief Construct the event dictionary.
+ virtual void defineEvents() {
+ // Invoke the base call implementation first.
+ StateModel::defineEvents();
+
+ // Define our events.
+ defineEvent(WORK_START_EVT, "WORK_START_EVT");
+ defineEvent(WORK_DONE_EVT , "WORK_DONE_EVT");
+ defineEvent(ALL_DONE_EVT, "ALL_DONE_EVT");
+ defineEvent(FORCE_UNDEFINED_ST_EVT, "FORCE_UNDEFINED_ST_EVT");
+ defineEvent(SIMULATE_ERROR_EVT, "SIMULATE_ERROR_EVT");
+ defineEvent(UNPAUSED_EVT, "UNPAUSED_EVT");
+ }
+
+ /// @brief Verify the event dictionary.
+ virtual void verifyEvents() {
+ // Invoke the base call implementation first.
+ StateModel::verifyEvents();
+
+ // Verify our events.
+ getEvent(WORK_START_EVT);
+ getEvent(WORK_DONE_EVT);
+ getEvent(ALL_DONE_EVT);
+ getEvent(FORCE_UNDEFINED_ST_EVT);
+ getEvent(SIMULATE_ERROR_EVT);
+ getEvent(UNPAUSED_EVT);
+ }
+
+ /// @brief Construct the state dictionary.
+ virtual void defineStates() {
+ // Invoke the base call implementation first.
+ StateModel::defineStates();
+
+ // Define our states.
+ defineState(DUMMY_ST, "DUMMY_ST",
+ std::bind(&StateModelTest::dummyHandler, this));
+
+ defineState(READY_ST, "READY_ST",
+ std::bind(&StateModelTest::readyHandler, this));
+
+ defineState(DO_WORK_ST, "DO_WORK_ST",
+ std::bind(&StateModelTest::doWorkHandler, this));
+
+ defineState(DONE_ST, "DONE_ST",
+ std::bind(&StateModelTest::doneWorkHandler, this));
+
+ defineState(PAUSE_ALWAYS_ST, "PAUSE_ALWAYS_ST",
+ std::bind(&StateModelTest::pauseHandler, this),
+ STATE_PAUSE_ALWAYS);
+
+ defineState(PAUSE_ONCE_ST, "PAUSE_ONCE_ST",
+ std::bind(&StateModelTest::pauseHandler, this),
+ STATE_PAUSE_ONCE);
+ }
+
+ /// @brief Verify the state dictionary.
+ virtual void verifyStates() {
+ // Invoke the base call implementation first.
+ StateModel::verifyStates();
+
+ // Verify our states.
+ getStateInternal(DUMMY_ST);
+ getStateInternal(READY_ST);
+ getStateInternal(DO_WORK_ST);
+ getStateInternal(DONE_ST);
+ getStateInternal(PAUSE_ALWAYS_ST);
+ getStateInternal(PAUSE_ONCE_ST);
+ }
+
+ /// @brief Manually construct the event and state dictionaries.
+ /// This allows testing without running startModel.
+ void initDictionaries() {
+ ASSERT_NO_THROW(defineEvents());
+ ASSERT_NO_THROW(verifyEvents());
+ ASSERT_NO_THROW(defineStates());
+ ASSERT_NO_THROW(verifyStates());
+ }
+
+ /// @brief Tests the event dictionary entry for the given event value.
+ bool checkEvent(const int value, const std::string& label) {
+ EventPtr event;
+ try {
+ event = getEvent(value);
+ EXPECT_TRUE(event);
+ EXPECT_EQ(value, event->getValue());
+ EXPECT_EQ(label, event->getLabel());
+ } catch (const std::exception& ex) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /// @brief Tests the state dictionary entry for the given state value.
+ bool checkState(const int value, const std::string& label) {
+ EventPtr state;
+ try {
+ state = getState(value);
+ EXPECT_TRUE(state);
+ EXPECT_EQ(value, state->getValue());
+ EXPECT_EQ(label, state->getLabel());
+ } catch (const std::exception& ex) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /// @brief Handler called when the model suffers an execution error.
+ virtual void onModelFailure(const std::string& explanation) {
+ failure_explanation_ = explanation;
+ }
+
+ /// @brief Indicator of whether or not the DUMMY_ST handler has been called.
+ bool dummy_called_;
+
+ /// @brief Indicator of whether or not DONE_ST handler has been called.
+ bool work_completed_;
+
+ /// @brief Stores the failure explanation
+ std::string failure_explanation_;
+};
+
+// Declare them so gtest can see them.
+const int StateModelTest::DUMMY_ST;
+const int StateModelTest::READY_ST;
+const int StateModelTest::DO_WORK_ST;
+const int StateModelTest::DONE_ST;
+const int StateModelTest::WORK_START_EVT;
+const int StateModelTest::WORK_DONE_EVT;
+const int StateModelTest::ALL_DONE_EVT;
+const int StateModelTest::PAUSE_ALWAYS_ST;
+const int StateModelTest::PAUSE_ONCE_ST;
+
+/// @brief Checks the fundamentals of defining and retrieving events.
+TEST_F(StateModelTest, eventDefinition) {
+ // After construction, the event dictionary should be empty. Verify that
+ // getEvent will throw when event is not defined.
+ EXPECT_THROW(getEvent(NOP_EVT), StateModelError);
+
+ // Verify that we can add a handler to the map.
+ ASSERT_NO_THROW(defineEvent(NOP_EVT, "NOP_EVT"));
+
+ // Verify that we can find the event by value and its content is correct.
+ EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
+
+ // Verify that we cannot add a duplicate.
+ ASSERT_THROW(defineEvent(NOP_EVT, "NOP_EVT"), StateModelError);
+
+ // Verify that we can still find the event.
+ EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
+}
+
+/// @brief Tests event dictionary construction and verification.
+TEST_F(StateModelTest, eventDictionary) {
+ // After construction, the event dictionary should be empty.
+ // Make sure that verifyEvents() throws.
+ EXPECT_THROW(verifyEvents(), StateModelError);
+
+ // Construct the dictionary and verify it.
+ EXPECT_NO_THROW(defineEvents());
+ EXPECT_NO_THROW(verifyEvents());
+
+ // Verify base class events are defined.
+ EXPECT_TRUE(checkEvent(NOP_EVT, "NOP_EVT"));
+ EXPECT_TRUE(checkEvent(START_EVT, "START_EVT"));
+ EXPECT_TRUE(checkEvent(END_EVT, "END_EVT"));
+ EXPECT_TRUE(checkEvent(FAIL_EVT, "FAIL_EVT"));
+
+ // Verify stub class events are defined.
+ EXPECT_TRUE(checkEvent(WORK_START_EVT, "WORK_START_EVT"));
+ EXPECT_TRUE(checkEvent(WORK_DONE_EVT, "WORK_DONE_EVT"));
+ EXPECT_TRUE(checkEvent(ALL_DONE_EVT, "ALL_DONE_EVT"));
+ EXPECT_TRUE(checkEvent(FORCE_UNDEFINED_ST_EVT, "FORCE_UNDEFINED_ST_EVT"));
+ EXPECT_TRUE(checkEvent(SIMULATE_ERROR_EVT, "SIMULATE_ERROR_EVT"));
+
+ // Verify that undefined events are handled correctly.
+ EXPECT_THROW(getEvent(9999), StateModelError);
+ EXPECT_EQ(LabeledValueSet::UNDEFINED_LABEL, getEventLabel(9999));
+}
+
+/// @brief General testing of event context accessors.
+/// Most if not all of these are also tested as a byproduct off larger tests.
+TEST_F(StateModelTest, eventContextAccessors) {
+ // Construct the event definitions, normally done by startModel.
+ ASSERT_NO_THROW(defineEvents());
+ ASSERT_NO_THROW(verifyEvents());
+
+ // Verify the post-construction values.
+ EXPECT_EQ(NOP_EVT, getNextEvent());
+ EXPECT_EQ(NOP_EVT, getLastEvent());
+
+ // Call setEvent which will update both next event and last event.
+ EXPECT_NO_THROW(postNextEvent(START_EVT));
+
+ // Verify the values are what we expect.
+ EXPECT_EQ(START_EVT, getNextEvent());
+ EXPECT_EQ(NOP_EVT, getLastEvent());
+
+ // Call setEvent again.
+ EXPECT_NO_THROW(postNextEvent(WORK_START_EVT));
+
+ // Verify the values are what we expect.
+ EXPECT_EQ(WORK_START_EVT, getNextEvent());
+ EXPECT_EQ(START_EVT, getLastEvent());
+
+ // Verify that posting an undefined event throws.
+ EXPECT_THROW(postNextEvent(9999), StateModelError);
+}
+
+/// @brief Tests the fundamental methods used for state handler mapping.
+/// Verifies the ability to search for and add entries in the state handler map.
+TEST_F(StateModelTest, stateDefinition) {
+ // After construction, the state dictionary should be empty. Verify that
+ // getState will throw when, state is not defined.
+ EXPECT_THROW(getState(READY_ST), StateModelError);
+
+ // Verify that we can add a state to the dictionary.
+ ASSERT_NO_THROW(defineState(READY_ST, "READY_ST",
+ std::bind(&StateModelTest::dummyHandler,
+ this)));
+
+ // Verify that we can find the state by its value.
+ StatePtr state;
+ EXPECT_NO_THROW(state = getState(READY_ST));
+ EXPECT_TRUE(state);
+
+ // Verify the state's value and label.
+ EXPECT_EQ(READY_ST, state->getValue());
+ EXPECT_EQ("READY_ST", state->getLabel());
+
+ // Now verify that retrieved state's handler executes the correct method.
+ // Make sure the dummy called flag is false prior to invocation.
+ EXPECT_FALSE(getDummyCalled());
+
+ // Invoke the state's handler.
+ EXPECT_NO_THROW(state->run());
+
+ // Verify the dummy called flag is now true.
+ EXPECT_TRUE(getDummyCalled());
+
+ // Verify that we cannot add a duplicate.
+ EXPECT_THROW(defineState(READY_ST, "READY_ST",
+ std::bind(&StateModelTest::readyHandler, this)),
+ StateModelError);
+
+ // Verify that we can still find the state.
+ EXPECT_NO_THROW(getState(READY_ST));
+}
+
+/// @brief Tests state dictionary initialization and validation.
+/// This tests the basic concept of state dictionary initialization and
+/// verification by manually invoking the methods normally called by startModel.
+TEST_F(StateModelTest, stateDictionary) {
+ // Verify that the map validation throws prior to the dictionary being
+ // initialized.
+ EXPECT_THROW(verifyStates(), StateModelError);
+
+ // Construct the dictionary and verify it.
+ ASSERT_NO_THROW(defineStates());
+ EXPECT_NO_THROW(verifyStates());
+
+ // Verify the base class states.
+ EXPECT_TRUE(checkState(NEW_ST, "NEW_ST"));
+ EXPECT_TRUE(checkState(END_ST, "END_ST"));
+
+ // Verify stub class states.
+ EXPECT_TRUE(checkState(DUMMY_ST, "DUMMY_ST"));
+ EXPECT_TRUE(checkState(READY_ST, "READY_ST"));
+ EXPECT_TRUE(checkState(DO_WORK_ST, "DO_WORK_ST"));
+ EXPECT_TRUE(checkState(DONE_ST, "DONE_ST"));
+
+ // Verify that undefined states are handled correctly.
+ EXPECT_THROW(getState(9999), StateModelError);
+ EXPECT_EQ(LabeledValueSet::UNDEFINED_LABEL, getStateLabel(9999));
+}
+
+/// @brief General testing of state context accessors.
+/// Most if not all of these are also tested as a byproduct off larger tests.
+TEST_F(StateModelTest, stateContextAccessors) {
+ // setState will throw unless we initialize the handler map.
+ ASSERT_NO_THROW(defineStates());
+ ASSERT_NO_THROW(verifyStates());
+
+ // Verify post-construction state values.
+ EXPECT_EQ(NEW_ST, getCurrState());
+ EXPECT_EQ(NEW_ST, getPrevState());
+
+ // Call setState which will update both state and previous state.
+ EXPECT_NO_THROW(setState(READY_ST));
+
+ // Verify the values are what we expect.
+ EXPECT_EQ(READY_ST, getCurrState());
+ EXPECT_EQ(NEW_ST, getPrevState());
+
+ // Call setState again.
+ EXPECT_NO_THROW(setState(DO_WORK_ST));
+
+ // Verify the values are what we expect.
+ EXPECT_EQ(DO_WORK_ST, getCurrState());
+ EXPECT_EQ(READY_ST, getPrevState());
+
+ // Verify that calling setState with an state that has no handler
+ // will throw.
+ EXPECT_THROW(setState(-1), StateModelError);
+
+ // Verify that calling setState with NEW_ST is ok.
+ EXPECT_NO_THROW(setState(NEW_ST));
+
+ // Verify that calling setState with END_ST is ok.
+ EXPECT_NO_THROW(setState(END_ST));
+
+ // Verify that calling setState with an undefined state throws.
+ EXPECT_THROW(setState(9999), StateModelError);
+}
+
+/// @brief Checks that invoking runModel prior to startModel is not allowed.
+TEST_F(StateModelTest, runBeforeStart) {
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+
+ // Attempt to call runModel before startModel. This should result in an
+ // orderly model failure.
+ ASSERT_NO_THROW(runModel(START_EVT));
+
+ // Check that state and event are correct.
+ EXPECT_EQ(END_ST, getCurrState());
+ EXPECT_EQ(FAIL_EVT, getNextEvent());
+
+ // Verify that failure explanation is not empty.
+ EXPECT_FALSE(getFailureExplanation().empty());
+}
+
+/// @brief Tests that the endModel may be used to transition the model to
+/// a normal conclusion.
+TEST_F(StateModelTest, transitionWithEnd) {
+ // Init dictionaries manually, normally done by startModel.
+ initDictionaries();
+
+ // call transition to move from NEW_ST to DUMMY_ST with START_EVT
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+ // Verify that state and event members are as expected.
+ EXPECT_EQ(DUMMY_ST, getCurrState());
+ EXPECT_EQ(NEW_ST, getPrevState());
+ EXPECT_EQ(START_EVT, getNextEvent());
+ EXPECT_EQ(NOP_EVT, getLastEvent());
+
+ // Call endModel to transition us to the end of the model.
+ EXPECT_NO_THROW(endModel());
+
+ // Verify state and event members are correctly set.
+ EXPECT_EQ(END_ST, getCurrState());
+ EXPECT_EQ(DUMMY_ST, getPrevState());
+ EXPECT_EQ(END_EVT, getNextEvent());
+ EXPECT_EQ(START_EVT, getLastEvent());
+}
+
+/// @brief Tests that the abortModel may be used to transition the model to
+/// failed conclusion.
+TEST_F(StateModelTest, transitionWithAbort) {
+ // Init dictionaries manually, normally done by startModel.
+ initDictionaries();
+
+ // call transition to move from NEW_ST to DUMMY_ST with START_EVT
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+ // Verify that state and event members are as expected.
+ EXPECT_EQ(DUMMY_ST, getCurrState());
+ EXPECT_EQ(NEW_ST, getPrevState());
+ EXPECT_EQ(START_EVT, getNextEvent());
+ EXPECT_EQ(NOP_EVT, getLastEvent());
+
+ // Call endModel to transition us to the end of the model.
+ EXPECT_NO_THROW(abortModel("test invocation"));
+
+ // Verify state and event members are correctly set.
+ EXPECT_EQ(END_ST, getCurrState());
+ EXPECT_EQ(DUMMY_ST, getPrevState());
+ EXPECT_EQ(FAIL_EVT, getNextEvent());
+ EXPECT_EQ(START_EVT, getLastEvent());
+}
+
+/// @brief Tests that the boolean indicators for on state entry and exit
+/// work properly.
+TEST_F(StateModelTest, doFlags) {
+ // Init dictionaries manually, normally done by startModel.
+ initDictionaries();
+
+ // Verify that "do" flags are false.
+ EXPECT_FALSE(doOnEntry());
+ EXPECT_FALSE(doOnExit());
+
+ // call transition to move from NEW_ST to DUMMY_ST with START_EVT
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+ // We are transitioning states, so "do" flags should be true.
+ EXPECT_TRUE(doOnEntry());
+ EXPECT_TRUE(doOnExit());
+
+ // "do" flags are one-shots, so they should now both be false.
+ EXPECT_FALSE(doOnEntry());
+ EXPECT_FALSE(doOnExit());
+
+ // call transition to re-enter same state, "do" flags should be false.
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+ // "do" flags should be false.
+ EXPECT_FALSE(doOnEntry());
+ EXPECT_FALSE(doOnExit());
+
+}
+
+/// @brief Verifies that the model status methods accurately reflect the model
+/// status. It also verifies that the dictionaries can be modified before
+/// the model is running but not after.
+TEST_F(StateModelTest, statusMethods) {
+ // Init dictionaries manually, normally done by startModel.
+ initDictionaries();
+
+ // After construction, state model is "new", all others should be false.
+ EXPECT_TRUE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_FALSE(isModelDone());
+ EXPECT_FALSE(didModelFail());
+
+ // Verify that events and states can be added before the model is started.
+ EXPECT_NO_THROW(defineEvent(9998, "9998"));
+ EXPECT_NO_THROW(defineState(9998, "9998",
+ std::bind(&StateModelTest::readyHandler,
+ this)));
+
+ // "START" the model.
+ // Fake out starting the model by calling transition to move from NEW_ST
+ // to DUMMY_ST with START_EVT. If we used startModel this would blow by
+ // the status of "running" but not "waiting".
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+
+ // Verify that events and states cannot be added after the model is started.
+ EXPECT_THROW(defineEvent(9999, "9999"), StateModelError);
+ EXPECT_THROW(defineState(9999, "9999",
+ std::bind(&StateModelTest::readyHandler, this)),
+ StateModelError);
+
+ // The state and event combos set above, should show the model as
+ // "running", all others should be false.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_TRUE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_FALSE(isModelDone());
+ EXPECT_FALSE(didModelFail());
+
+ // call transition to submit NOP_EVT to current state, DUMMY_ST.
+ EXPECT_NO_THROW(transition(DUMMY_ST, NOP_EVT));
+
+ // Verify the status methods are correct: with next event set to NOP_EVT,
+ // model should be "running" and "waiting".
+ EXPECT_FALSE(isModelNew());
+ EXPECT_TRUE(isModelRunning());
+ EXPECT_TRUE(isModelWaiting());
+ EXPECT_FALSE(isModelDone());
+ EXPECT_FALSE(didModelFail());
+
+ // Call endModel to transition us to the end of the model.
+ EXPECT_NO_THROW(endModel());
+
+ // With state set to END_ST, model should be done.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+ EXPECT_FALSE(didModelFail());
+}
+
+/// @brief Tests that the model status methods are correct after a model
+/// failure.
+TEST_F(StateModelTest, statusMethodsOnFailure) {
+ // Construct the event and state definitions, normally done by startModel.
+ ASSERT_NO_THROW(defineEvents());
+ ASSERT_NO_THROW(verifyEvents());
+ ASSERT_NO_THROW(defineStates());
+ ASSERT_NO_THROW(verifyStates());
+
+ // call transition to move from NEW_ST to DUMMY_ST with START_EVT
+ EXPECT_NO_THROW(transition(DUMMY_ST, START_EVT));
+
+ // Call endModel to transition us to the end of the model.
+ EXPECT_NO_THROW(abortModel("test invocation"));
+
+ // With state set to END_ST, model should be done.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+ EXPECT_TRUE(didModelFail());
+}
+
+/// @brief Checks that the context strings accurately reflect context and
+/// are safe to invoke.
+TEST_F(StateModelTest, contextStrs) {
+ // Verify context methods do not throw prior to dictionary init.
+ ASSERT_NO_THROW(getContextStr());
+ ASSERT_NO_THROW(getPrevContextStr());
+
+ // Construct the event and state definitions, normally done by startModel.
+ ASSERT_NO_THROW(defineEvents());
+ ASSERT_NO_THROW(verifyEvents());
+ ASSERT_NO_THROW(defineStates());
+ ASSERT_NO_THROW(verifyStates());
+
+ // transition uses setState and setEvent, testing it tests all three.
+ EXPECT_NO_THROW(transition(READY_ST, START_EVT));
+
+ // Verify the current context string depicts correct state and event.
+ std::string ctx_str;
+ ASSERT_NO_THROW(ctx_str = getContextStr());
+ EXPECT_NE(std::string::npos, ctx_str.find(getStateLabel(READY_ST)));
+ EXPECT_NE(std::string::npos, ctx_str.find(getEventLabel(START_EVT)));
+
+ // Verify the previous context string depicts correct state and event.
+ ASSERT_NO_THROW(ctx_str = getPrevContextStr());
+ EXPECT_NE(std::string::npos, ctx_str.find(getStateLabel(NEW_ST)));
+ EXPECT_NE(std::string::npos, ctx_str.find(getEventLabel(NOP_EVT)));
+}
+
+/// @brief Tests that undefined states are handled gracefully.
+/// This test verifies that attempting to transition to an undefined state,
+/// which constitutes a model violation, results in an orderly model failure.
+TEST_F(StateModelTest, undefinedState) {
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+ EXPECT_FALSE(getWorkCompleted());
+
+ // First, lets execute the state model to a known valid point, by
+ // calling startModel. This should run the model through to DO_WORK_ST.
+ ASSERT_NO_THROW(startModel(READY_ST));
+
+ // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
+ EXPECT_EQ(DO_WORK_ST, getCurrState());
+ EXPECT_EQ(NOP_EVT, getNextEvent());
+
+ // Resume the model with next event set to cause the DO_WORK_ST handler
+ // to transition to an undefined state. This should cause it to return
+ // without throwing and yield a failed model.
+ EXPECT_NO_THROW(runModel(FORCE_UNDEFINED_ST_EVT));
+
+ // Verify that status methods are correct: model is done but failed.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+ EXPECT_TRUE(didModelFail());
+
+ // Verify that failure explanation is not empty.
+ EXPECT_FALSE(getFailureExplanation().empty());
+
+ // Verify that work completed flag is still false.
+ EXPECT_FALSE(getWorkCompleted());
+}
+
+/// @brief Tests that an unexpected exception thrown by a state handler is
+/// handled gracefully. State models are supposed to account for and handle
+/// all errors that they actions (i.e. handlers) may cause. In the event they
+/// do not, this constitutes a model violation. This test verifies such
+/// violations are handled correctly and result in an orderly model failure.
+TEST_F(StateModelTest, unexpectedError) {
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+ EXPECT_FALSE(getWorkCompleted());
+
+ // First, lets execute the state model to a known valid point, by
+ // calling startModel with a start state of READY_ST.
+ // This should run the model through to DO_WORK_ST.
+ ASSERT_NO_THROW(startModel(READY_ST));
+
+ // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
+ EXPECT_EQ(DO_WORK_ST, getCurrState());
+ EXPECT_EQ(NOP_EVT, getNextEvent());
+
+ // Resume the model with next event set to cause the DO_WORK_ST handler
+ // to transition to an undefined state. This should cause it to return
+ // without throwing and yield a failed model.
+ EXPECT_NO_THROW(runModel(SIMULATE_ERROR_EVT));
+
+ // Verify that status methods are correct: model is done but failed.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+ EXPECT_TRUE(didModelFail());
+
+ // Verify that failure explanation is not empty.
+ EXPECT_FALSE(getFailureExplanation().empty());
+
+ // Verify that work completed flag is still false.
+ EXPECT_FALSE(getWorkCompleted());
+}
+
+/// @brief Tests that undefined events are handled gracefully.
+/// This test verifies that submitting an undefined event to the state machine
+/// results, which constitutes a model violation, results in an orderly model
+/// failure.
+TEST_F(StateModelTest, undefinedEvent) {
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+ EXPECT_FALSE(getWorkCompleted());
+
+ // First, lets execute the state model to a known valid point, by
+ // calling startModel with a start state of READY_ST.
+ // This should run the model through to DO_WORK_ST.
+ ASSERT_NO_THROW(startModel(READY_ST));
+
+ // Verify we are in the state of DO_WORK_ST with event of NOP_EVT.
+ EXPECT_EQ(DO_WORK_ST, getCurrState());
+ EXPECT_EQ(NOP_EVT, getNextEvent());
+
+ // Attempting to post an undefined event within runModel should cause it
+ // to return without throwing and yield a failed model.
+ EXPECT_NO_THROW(runModel(9999));
+
+ // Verify that status methods are correct: model is done but failed.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+ EXPECT_TRUE(didModelFail());
+
+ // Verify that failure explanation is not empty.
+ EXPECT_FALSE(getFailureExplanation().empty());
+
+ // Verify that work completed flag is still false.
+ EXPECT_FALSE(getWorkCompleted());
+}
+
+/// @brief Test the basic mechanics of state model execution.
+/// This test exercises the ability to execute state model from start to
+/// finish, including the handling of a asynchronous IO operation.
+TEST_F(StateModelTest, stateModelTest) {
+ // Verify that status methods are correct: model is new.
+ EXPECT_TRUE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_FALSE(isModelDone());
+
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+ EXPECT_FALSE(getWorkCompleted());
+
+ // Launch the transaction by calling startModel. The state model
+ // should run up until the simulated async work operation is initiated
+ // in DO_WORK_ST.
+ ASSERT_NO_THROW(startModel(READY_ST));
+
+ // Verify that we are now in state of DO_WORK_ST, the last event was
+ // WORK_START_EVT, the next event is NOP_EVT.
+ EXPECT_EQ(DO_WORK_ST, getCurrState());
+ EXPECT_EQ(WORK_START_EVT, getLastEvent());
+ EXPECT_EQ(NOP_EVT, getNextEvent());
+
+ // Simulate completion of async work completion by resuming runModel with
+ // an event of WORK_DONE_EVT.
+ ASSERT_NO_THROW(runModel(WORK_DONE_EVT));
+
+ // Verify that the state model has progressed through to completion:
+ // it is in the DONE_ST, the status is ST_COMPLETED, and the next event
+ // is NOP_EVT.
+ EXPECT_EQ(END_ST, getCurrState());
+ EXPECT_EQ(END_EVT, getNextEvent());
+
+ // Verify that status methods are correct: model done.
+ EXPECT_FALSE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_TRUE(isModelDone());
+
+ // Verify that failure explanation is empty.
+ EXPECT_TRUE(getFailureExplanation().empty());
+
+ // Verify that work completed flag is true.
+ EXPECT_TRUE(getWorkCompleted());
+}
+
+// This test verifies the pausing and un-pausing capabilities of the state
+// model.
+TEST_F(StateModelTest, stateModelPause) {
+ // Verify that status methods are correct: model is new.
+ EXPECT_TRUE(isModelNew());
+ EXPECT_FALSE(isModelRunning());
+ EXPECT_FALSE(isModelWaiting());
+ EXPECT_FALSE(isModelDone());
+ EXPECT_FALSE(isModelPaused());
+
+ // Verify that the failure explanation is empty and work is not done.
+ EXPECT_TRUE(getFailureExplanation().empty());
+ EXPECT_FALSE(getWorkCompleted());
+
+ // Transition straight to the state in which the model should always
+ // pause.
+ ASSERT_NO_THROW(startModel(PAUSE_ALWAYS_ST));
+
+ // Verify it was successful and that the model is paused.
+ EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
+ EXPECT_TRUE(isModelPaused());
+
+ // Run the model again. It should still be paused.
+ ASSERT_NO_THROW(runModel(NOP_EVT));
+ EXPECT_TRUE(isModelPaused());
+
+ // Unpause the model and transition to the state in which the model
+ // should be paused at most once.
+ unpauseModel();
+ transition(PAUSE_ONCE_ST, NOP_EVT);
+ EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
+ EXPECT_TRUE(isModelPaused());
+
+ // The model should still be paused until explicitly unpaused.
+ ASSERT_NO_THROW(runModel(NOP_EVT));
+ EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
+ EXPECT_TRUE(isModelPaused());
+
+ unpauseModel();
+
+ // Transition back to the first state. The model should pause again.
+ transition(PAUSE_ALWAYS_ST, NOP_EVT);
+ EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
+ EXPECT_TRUE(isModelPaused());
+
+ ASSERT_NO_THROW(runModel(NOP_EVT));
+ EXPECT_EQ(PAUSE_ALWAYS_ST, getCurrState());
+ EXPECT_TRUE(isModelPaused());
+
+ // Unpause the model and transition to the state in which the model
+ // should pause only once. This time it should not pause.
+ unpauseModel();
+ transition(PAUSE_ONCE_ST, NOP_EVT);
+ EXPECT_EQ(PAUSE_ONCE_ST, getCurrState());
+ EXPECT_FALSE(isModelPaused());
+}
+
+}
diff --git a/src/lib/util/tests/stopwatch_unittest.cc b/src/lib/util/tests/stopwatch_unittest.cc
new file mode 100644
index 0000000..28d6c99
--- /dev/null
+++ b/src/lib/util/tests/stopwatch_unittest.cc
@@ -0,0 +1,301 @@
+// Copyright (C) 2015-2017,2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/stopwatch.h>
+#include <util/stopwatch_impl.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+namespace {
+
+using namespace isc;
+using namespace isc::util;
+using namespace boost::posix_time;
+
+/// @brief @c StopwatchImpl mock object.
+///
+/// This class derives from the @c StopwatchImpl to override the
+/// @c StopwatchImpl::getCurrentTime. This method is internally called by
+/// the @c StopwatchImpl to determine the current time. By providing the
+/// implementation of this method which returns the fixed (well known)
+/// timestamp value we can obtain the deterministic values from the accessors
+/// of this class.
+///
+/// This class also includes some convenience methods to return the time
+/// durations in milliseconds.
+class StopwatchMock : public StopwatchImpl {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// @param ref_time Reference time, i.e. the arbitrary time value from
+ /// which time is measured. The @c current_time_ value returned by the
+ /// @c StopwatchMock::getCurrentTime is initialized to this value.
+ /// Subsequent calls to the @c StopwatchMock::ffwd move the value of
+ /// the @c current_time_ forward.
+ StopwatchMock(const ptime& ref_time);
+
+ /// @brief Fast forward time.
+ ///
+ /// Moves the value of the @c current_time_ forward by the specified
+ /// number of milliseconds (microseconds). As a result the timestamp
+ /// returned by the @c StopwatchMock::getCurrentTime moves by this value.
+ /// This simulates the time progress.
+ ///
+ /// @param ms Specifies the number of milliseconds to move current time.
+ /// @param us Specifies the number of fractional microseconds to move
+ /// current time.
+ void ffwd(const uint32_t ms, const uint32_t us = 0);
+
+ /// @brief Returns the last duration in milliseconds.
+ uint32_t getLastDurationInMs() const;
+
+ /// @brief Returns the total duration in milliseconds.
+ uint32_t getTotalDurationInMs() const;
+
+protected:
+
+ /// @brief Returns the current time.
+ ///
+ /// This method returns the fixed @c current_time_ timestamp.
+ virtual ptime getCurrentTime() const;
+
+private:
+
+ /// @brief Holds the current time to be returned by the
+ /// @c StopwatchMock::getCurrentTime.
+ ptime current_time_;
+
+};
+
+StopwatchMock::StopwatchMock(const ptime& ref_time)
+ : StopwatchImpl(), current_time_(ref_time) {
+}
+
+void
+StopwatchMock::ffwd(const uint32_t ms, const uint32_t us) {
+ current_time_ += milliseconds(ms);
+ current_time_ += microseconds(us);
+}
+
+uint32_t
+StopwatchMock::getLastDurationInMs() const {
+ return (getLastDuration().total_milliseconds());
+}
+
+uint32_t
+StopwatchMock::getTotalDurationInMs() const {
+ return (getTotalDuration().total_milliseconds());
+}
+
+ptime
+StopwatchMock::getCurrentTime() const {
+ return (current_time_);
+}
+
+/// @brief Test fixture class for testing @c StopwatchImpl.
+class StopwatchTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor
+ StopwatchTest() = default;
+
+ /// @brief Destructor
+ virtual ~StopwatchTest() = default;
+
+protected:
+
+ /// @brief Set up the test.
+ ///
+ /// Initializes the reference time to be used to create the instances
+ /// of the @c StopwatchMock objects.
+ virtual void SetUp();
+
+ /// @brief Holds the reference time to be used to create the instances
+ /// of the @c StopwatchMock objects.
+ ptime ref_time_;
+};
+
+void
+StopwatchTest::SetUp() {
+ ref_time_ = microsec_clock::universal_time();
+}
+
+/// This test checks the behavior of the stopwatch when it is started
+/// and stopped multiple times. It uses the StopwatchMock object to
+/// control the "time flow" by setting the current time to arbitrary
+/// values using the StopwatchMock::ffwd. In addition, this test
+/// checks that the stopwatch can be reset.
+TEST_F(StopwatchTest, multipleMeasurements) {
+ StopwatchMock stopwatch(ref_time_);
+ // The stopwatch shouldn't automatically start. The initial
+ // durations should be set to 0.
+ EXPECT_EQ(0, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
+
+ stopwatch.start();
+
+ // Even though the stopwatch is started, the time is still set to
+ // the initial value. The durations should not be affected.
+ EXPECT_EQ(0, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
+
+ // Move the time by 10 ms.
+ stopwatch.ffwd(10);
+
+ // It should be possible to retrieve the durations even when the
+ // stopwatch is running.
+ EXPECT_EQ(10, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
+
+ // Now stop it and make sure that the same values are returned.
+ stopwatch.stop();
+
+ EXPECT_EQ(10, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
+
+ // Start it again, but don't move the time forward yet.
+ stopwatch.start();
+
+ // The new duration should be 0, but the total should be equal to
+ // the previously measured duration.
+ EXPECT_EQ(0, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(10, stopwatch.getTotalDurationInMs());
+
+ // Move time by 5 ms.
+ stopwatch.ffwd(5);
+
+ // New measured duration should be 5 ms. The total should be 15 ms.
+ EXPECT_EQ(5, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
+
+ // Stop it again and make sure the values returned are the same.
+ stopwatch.stop();
+
+ EXPECT_EQ(5, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
+
+ // Move the time forward while the stopwatch is stopped.
+ stopwatch.ffwd(8);
+
+ // The measured values should not be affected.
+ EXPECT_EQ(5, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
+
+ // Stop should be no-op in this case.
+ stopwatch.stop();
+
+ EXPECT_EQ(5, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(15, stopwatch.getTotalDurationInMs());
+
+ // Start the stopwatch again.
+ stopwatch.start();
+
+ // Move time by 3 ms.
+ stopwatch.ffwd(3);
+
+ // Since the stopwatch is running, the measured duration should
+ // get updated again.
+ EXPECT_EQ(3, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(18, stopwatch.getTotalDurationInMs());
+
+ // Move the time by 2 ms.
+ stopwatch.ffwd(2);
+
+ // Start should be no-op in this case.
+ stopwatch.start();
+
+ // But the durations should be updated.
+ EXPECT_EQ(5, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(20, stopwatch.getTotalDurationInMs());
+
+ // Make sure we can reset.
+ stopwatch.reset();
+
+ EXPECT_EQ(0, stopwatch.getLastDurationInMs());
+ EXPECT_EQ(0, stopwatch.getTotalDurationInMs());
+}
+
+// This test checks that the stopwatch works when the real clock is in use.
+TEST_F(StopwatchTest, realTime) {
+ // Initially, the measured time should be 0.
+ Stopwatch stopwatch;
+ EXPECT_EQ(0, stopwatch.getLastMilliseconds());
+ EXPECT_EQ(0, stopwatch.getTotalMilliseconds());
+
+ // Start the stopwatch.
+ stopwatch.start();
+
+ // Sleep for 1 ms. The stopwatch should measure this duration.
+ usleep(1000);
+
+ stopwatch.stop();
+
+ // The measured duration should be greater or equal 1 ms.
+ long current_duration = stopwatch.getLastMilliseconds();
+ EXPECT_GE(current_duration, 1);
+ EXPECT_EQ(current_duration, stopwatch.getTotalMilliseconds());
+
+ // Sleep for another 2 ms while the stopwatch is in the stopped state.
+ usleep(2000);
+
+ // In the stopped state, we should still have old durations measured.
+ EXPECT_EQ(current_duration, stopwatch.getLastMilliseconds());
+ EXPECT_EQ(current_duration, stopwatch.getTotalMilliseconds());
+
+ // Start it again.
+ stopwatch.start();
+
+ // Sleep for 1 ms.
+ usleep(1000);
+
+ // The durations should get updated as appropriate.
+ EXPECT_GE(stopwatch.getLastMilliseconds(), 1);
+ EXPECT_GE(stopwatch.getTotalMilliseconds(), 2);
+}
+
+// Make sure that we can obtain the durations as microseconds.
+TEST_F(StopwatchTest, getLastMicroseconds) {
+ Stopwatch stopwatch;
+ stopwatch.start();
+
+ usleep(1000);
+
+ stopwatch.stop();
+
+ long current_duration = stopwatch.getLastMicroseconds();
+ EXPECT_GE(current_duration, 1000);
+ EXPECT_EQ(current_duration, stopwatch.getTotalMicroseconds());
+}
+
+// Make sure that we can use the "autostart" option to start the time
+// measurement in the constructor.
+TEST_F(StopwatchTest, autostart) {
+ Stopwatch stopwatch(true);
+ usleep(1000);
+
+ stopwatch.stop();
+
+ EXPECT_GE(stopwatch.getLastMilliseconds(), 1);
+ EXPECT_EQ(stopwatch.getLastMilliseconds(), stopwatch.getTotalMilliseconds());
+}
+
+// Make sure that the conversion to the loggable string works as expected.
+TEST_F(StopwatchTest, logFormat) {
+ time_duration duration = microseconds(223043);
+ EXPECT_EQ("223.043 ms", StopwatchImpl::logFormat(duration));
+
+ duration = microseconds(1234);
+ EXPECT_EQ("1.234 ms", StopwatchImpl::logFormat(duration));
+
+ duration = microseconds(2000);
+ EXPECT_EQ("2.000 ms", StopwatchImpl::logFormat(duration));
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/strutil_unittest.cc b/src/lib/util/tests/strutil_unittest.cc
new file mode 100644
index 0000000..8b5f78a
--- /dev/null
+++ b/src/lib/util/tests/strutil_unittest.cc
@@ -0,0 +1,642 @@
+// Copyright (C) 2011-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+#include <util/strutil.h>
+#include <util/encode/hex.h>
+
+#include <gtest/gtest.h>
+
+#include <stdint.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::util;
+using namespace isc::util::str;
+using namespace std;
+
+namespace {
+
+// Check for slash replacement
+
+TEST(StringUtilTest, Slash) {
+
+ string instring = "";
+ isc::util::str::normalizeSlash(instring);
+ EXPECT_EQ("", instring);
+
+ instring = "C:\\A\\B\\C.D";
+ isc::util::str::normalizeSlash(instring);
+ EXPECT_EQ("C:/A/B/C.D", instring);
+
+ instring = "// \\ //";
+ isc::util::str::normalizeSlash(instring);
+ EXPECT_EQ("// / //", instring);
+}
+
+// Check that leading and trailing space trimming works
+
+TEST(StringUtilTest, Trim) {
+
+ // Empty and full string.
+ EXPECT_EQ("", isc::util::str::trim(""));
+ EXPECT_EQ("abcxyz", isc::util::str::trim("abcxyz"));
+
+ // Trim right-most blanks
+ EXPECT_EQ("ABC", isc::util::str::trim("ABC "));
+ EXPECT_EQ("ABC", isc::util::str::trim("ABC\t\t \n\t"));
+
+ // Left-most blank trimming
+ EXPECT_EQ("XYZ", isc::util::str::trim(" XYZ"));
+ EXPECT_EQ("XYZ", isc::util::str::trim("\t\t \tXYZ"));
+
+ // Right and left, with embedded spaces
+ EXPECT_EQ("MN \t OP", isc::util::str::trim("\t\tMN \t OP \t"));
+}
+
+// Check tokenization. Note that ASSERT_EQ is used to check the size of the
+// returned vector; if not as expected, the following references may be invalid
+// so should not be used.
+
+TEST(StringUtilTest, Tokens) {
+ vector<string> result;
+
+ // Default delimiters
+
+ // Degenerate cases
+ result = isc::util::str::tokens(""); // Empty string
+ EXPECT_EQ(0, result.size());
+
+ result = isc::util::str::tokens(" \n "); // String is all delimiters
+ EXPECT_EQ(0, result.size());
+
+ result = isc::util::str::tokens("abc"); // String has no delimiters
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("abc"), result[0]);
+
+ // String containing leading and/or trailing delimiters, no embedded ones.
+ result = isc::util::str::tokens("\txyz"); // One leading delimiter
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("xyz"), result[0]);
+
+ result = isc::util::str::tokens("\t \nxyz"); // Multiple leading delimiters
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("xyz"), result[0]);
+
+ result = isc::util::str::tokens("xyz\n"); // One trailing delimiter
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("xyz"), result[0]);
+
+ result = isc::util::str::tokens("xyz \t"); // Multiple trailing
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("xyz"), result[0]);
+
+ result = isc::util::str::tokens("\t xyz \n"); // Leading and trailing
+ ASSERT_EQ(1, result.size());
+ EXPECT_EQ(string("xyz"), result[0]);
+
+ // Embedded delimiters
+ result = isc::util::str::tokens("abc\ndef"); // 2 tokens, one separator
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("abc"), result[0]);
+ EXPECT_EQ(string("def"), result[1]);
+
+ result = isc::util::str::tokens("abc\t\t\ndef"); // 2 tokens, 3 separators
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("abc"), result[0]);
+ EXPECT_EQ(string("def"), result[1]);
+
+ result = isc::util::str::tokens("abc\n \tdef\t\tghi");
+ ASSERT_EQ(3, result.size()); // Multiple tokens, many delims
+ EXPECT_EQ(string("abc"), result[0]);
+ EXPECT_EQ(string("def"), result[1]);
+ EXPECT_EQ(string("ghi"), result[2]);
+
+ // Embedded and non-embedded delimiters
+
+ result = isc::util::str::tokens("\t\t \nabc\n \tdef\t\tghi \n\n");
+ ASSERT_EQ(3, result.size()); // Multiple tokens, many delims
+ EXPECT_EQ(string("abc"), result[0]);
+ EXPECT_EQ(string("def"), result[1]);
+ EXPECT_EQ(string("ghi"), result[2]);
+
+ // Non-default delimiter
+ result = isc::util::str::tokens("alpha/beta/ /gamma//delta/epsilon/", "/");
+ ASSERT_EQ(6, result.size());
+ EXPECT_EQ(string("alpha"), result[0]);
+ EXPECT_EQ(string("beta"), result[1]);
+ EXPECT_EQ(string(" "), result[2]);
+ EXPECT_EQ(string("gamma"), result[3]);
+ EXPECT_EQ(string("delta"), result[4]);
+ EXPECT_EQ(string("epsilon"), result[5]);
+
+ // Non-default delimiters (plural)
+ result = isc::util::str::tokens("+*--alpha*beta+ -gamma**delta+epsilon-+**",
+ "*+-");
+ ASSERT_EQ(6, result.size());
+ EXPECT_EQ(string("alpha"), result[0]);
+ EXPECT_EQ(string("beta"), result[1]);
+ EXPECT_EQ(string(" "), result[2]);
+ EXPECT_EQ(string("gamma"), result[3]);
+ EXPECT_EQ(string("delta"), result[4]);
+ EXPECT_EQ(string("epsilon"), result[5]);
+
+ // Escaped delimiter
+ result = isc::util::str::tokens("foo\\,bar", ",", true);
+ EXPECT_EQ(1, result.size());
+ EXPECT_EQ(string("foo,bar"), result[0]);
+
+ // Escaped escape
+ result = isc::util::str::tokens("foo\\\\,bar", ",", true);
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("foo\\"), result[0]);
+ EXPECT_EQ(string("bar"), result[1]);
+
+ // Double escapes
+ result = isc::util::str::tokens("foo\\\\\\\\,\\bar", ",", true);
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("foo\\\\"), result[0]);
+ EXPECT_EQ(string("\\bar"), result[1]);
+
+ // Escaped standard character
+ result = isc::util::str::tokens("fo\\o,bar", ",", true);
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("fo\\o"), result[0]);
+ EXPECT_EQ(string("bar"), result[1]);
+
+ // Escape at the end
+ result = isc::util::str::tokens("foo,bar\\", ",", true);
+ ASSERT_EQ(2, result.size());
+ EXPECT_EQ(string("foo"), result[0]);
+ EXPECT_EQ(string("bar\\"), result[1]);
+
+ // Escape opening a token
+ result = isc::util::str::tokens("foo,\\,,bar", ",", true);
+ ASSERT_EQ(3, result.size());
+ EXPECT_EQ(string("foo"), result[0]);
+ EXPECT_EQ(string(","), result[1]);
+ EXPECT_EQ(string("bar"), result[2]);
+}
+
+// Changing case
+
+TEST(StringUtilTest, ChangeCase) {
+ string mixed("abcDEFghiJKLmno123[]{=+--+]}");
+ string upper("ABCDEFGHIJKLMNO123[]{=+--+]}");
+ string lower("abcdefghijklmno123[]{=+--+]}");
+
+ string test = mixed;
+ isc::util::str::lowercase(test);
+ EXPECT_EQ(lower, test);
+
+ test = mixed;
+ isc::util::str::uppercase(test);
+ EXPECT_EQ(upper, test);
+}
+
+// Formatting
+
+TEST(StringUtilTest, Formatting) {
+
+ vector<string> args;
+ args.push_back("arg1");
+ args.push_back("arg2");
+ args.push_back("arg3");
+
+ string format1 = "This is a string with no tokens";
+ EXPECT_EQ(format1, isc::util::str::format(format1, args));
+
+ string format2 = ""; // Empty string
+ EXPECT_EQ(format2, isc::util::str::format(format2, args));
+
+ string format3 = " "; // Empty string
+ EXPECT_EQ(format3, isc::util::str::format(format3, args));
+
+ string format4 = "String with %d non-string tokens %lf";
+ EXPECT_EQ(format4, isc::util::str::format(format4, args));
+
+ string format5 = "String with %s correct %s number of tokens %s";
+ string result5 = "String with arg1 correct arg2 number of tokens arg3";
+ EXPECT_EQ(result5, isc::util::str::format(format5, args));
+
+ string format6 = "String with %s too %s few tokens";
+ string result6 = "String with arg1 too arg2 few tokens";
+ EXPECT_EQ(result6, isc::util::str::format(format6, args));
+
+ string format7 = "String with %s too %s many %s tokens %s !";
+ string result7 = "String with arg1 too arg2 many arg3 tokens %s !";
+ EXPECT_EQ(result7, isc::util::str::format(format7, args));
+
+ string format8 = "String with embedded%s%s%stokens";
+ string result8 = "String with embeddedarg1arg2arg3tokens";
+ EXPECT_EQ(result8, isc::util::str::format(format8, args));
+
+ // Handle an empty vector
+ args.clear();
+ string format9 = "%s %s";
+ EXPECT_EQ(format9, isc::util::str::format(format9, args));
+}
+
+TEST(StringUtilTest, getToken) {
+ string s("a b c");
+ istringstream ss(s);
+ EXPECT_EQ("a", isc::util::str::getToken(ss));
+ EXPECT_EQ("b", isc::util::str::getToken(ss));
+ EXPECT_EQ("c", isc::util::str::getToken(ss));
+ EXPECT_THROW(isc::util::str::getToken(ss), isc::util::str::StringTokenError);
+}
+
+int32_t tokenToNumCall_32_16(const string& token) {
+ return isc::util::str::tokenToNum<int32_t, 16>(token);
+}
+
+int16_t tokenToNumCall_16_8(const string& token) {
+ return isc::util::str::tokenToNum<int16_t, 8>(token);
+}
+
+TEST(StringUtilTest, tokenToNum) {
+ uint32_t num32 = tokenToNumCall_32_16("0");
+ EXPECT_EQ(0, num32);
+ num32 = tokenToNumCall_32_16("123");
+ EXPECT_EQ(123, num32);
+ num32 = tokenToNumCall_32_16("65535");
+ EXPECT_EQ(65535, num32);
+
+ EXPECT_THROW(tokenToNumCall_32_16(""),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_32_16("a"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_32_16("-1"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_32_16("65536"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_32_16("1234567890"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_32_16("-1234567890"),
+ isc::util::str::StringTokenError);
+
+ uint16_t num16 = tokenToNumCall_16_8("123");
+ EXPECT_EQ(123, num16);
+ num16 = tokenToNumCall_16_8("0");
+ EXPECT_EQ(0, num16);
+ num16 = tokenToNumCall_16_8("255");
+ EXPECT_EQ(255, num16);
+
+ EXPECT_THROW(tokenToNumCall_16_8(""),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_16_8("a"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_16_8("-1"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_16_8("256"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_16_8("1234567890"),
+ isc::util::str::StringTokenError);
+ EXPECT_THROW(tokenToNumCall_16_8("-1234567890"),
+ isc::util::str::StringTokenError);
+
+}
+
+/// @brief Convenience function which calls quotedStringToBinary
+/// and converts returned vector back to string.
+///
+/// @param s Input string.
+/// @return String holding a copy of a vector returned by the
+/// quotedStringToBinary.
+std::string testQuoted(const std::string& s) {
+ std::vector<uint8_t> vec = str::quotedStringToBinary(s);
+ std::string s2(vec.begin(), vec.end());
+ return (s2);
+}
+
+TEST(StringUtilTest, quotedStringToBinary) {
+ // No opening or closing quote should result in empty string.
+ EXPECT_TRUE(str::quotedStringToBinary("'").empty());
+ EXPECT_TRUE(str::quotedStringToBinary("").empty());
+ EXPECT_TRUE(str::quotedStringToBinary(" ").empty());
+ EXPECT_TRUE(str::quotedStringToBinary("'circuit id").empty());
+ EXPECT_TRUE(str::quotedStringToBinary("circuit id'").empty());
+
+ // If there is only opening and closing quote, an empty
+ // vector should be returned.
+ EXPECT_TRUE(str::quotedStringToBinary("''").empty());
+
+ // Both opening and ending quote is present.
+ EXPECT_EQ("circuit id", testQuoted("'circuit id'"));
+ EXPECT_EQ("remote id", testQuoted(" ' remote id'"));
+ EXPECT_EQ("duid", testQuoted(" ' duid'"));
+ EXPECT_EQ("duid", testQuoted("'duid ' "));
+ EXPECT_EQ("remote'id", testQuoted(" ' remote'id '"));
+ EXPECT_EQ("remote id'", testQuoted("'remote id''"));
+ EXPECT_EQ("'remote id", testQuoted("''remote id'"));
+
+ // Multiple quotes.
+ EXPECT_EQ("'", testQuoted("'''"));
+ EXPECT_EQ("''", testQuoted("''''"));
+}
+
+/// @brief Test that hex string with colons can be decoded.
+///
+/// @param input Input string to be decoded.
+/// @param reference A string without colons representing the
+/// decoded data.
+void testColonSeparated(const std::string& input,
+ const std::string& reference) {
+ // Create a reference vector.
+ std::vector<uint8_t> reference_vector;
+ ASSERT_NO_THROW(encode::decodeHex(reference, reference_vector));
+
+ // Fill the output vector with some garbage to make sure that
+ // the data is erased when a string is decoded successfully.
+ std::vector<uint8_t> decoded(1, 10);
+ ASSERT_NO_THROW(decodeColonSeparatedHexString(input, decoded));
+
+ // Get the string representation of the decoded data for logging
+ // purposes.
+ std::string encoded;
+ ASSERT_NO_THROW(encoded = encode::encodeHex(decoded));
+
+ // Check if the decoded data matches the reference.
+ EXPECT_TRUE(decoded == reference_vector)
+ << "decoded data don't match the reference, input='"
+ << input << "', reference='" << reference << "'"
+ ", decoded='" << encoded << "'";
+}
+
+TEST(StringUtilTest, decodeColonSeparatedHexString) {
+ // Test valid strings.
+ testColonSeparated("A1:02:C3:d4:e5:F6", "A102C3D4E5F6");
+ testColonSeparated("A:02:3:d:E5:F6", "0A02030DE5F6");
+ testColonSeparated("A:B:C:D", "0A0B0C0D");
+ testColonSeparated("1", "01");
+ testColonSeparated("1e", "1E");
+ testColonSeparated("", "");
+
+ // Test invalid strings.
+ std::vector<uint8_t> decoded;
+ // Whitespaces.
+ EXPECT_THROW(decodeColonSeparatedHexString(" ", decoded),
+ isc::BadValue);
+ // Whitespace before digits.
+ EXPECT_THROW(decodeColonSeparatedHexString(" A1", decoded),
+ isc::BadValue);
+ // Two consecutive colons.
+ EXPECT_THROW(decodeColonSeparatedHexString("A::01", decoded),
+ isc::BadValue);
+ // Three consecutive colons.
+ EXPECT_THROW(decodeColonSeparatedHexString("A:::01", decoded),
+ isc::BadValue);
+ // Whitespace within a string.
+ EXPECT_THROW(decodeColonSeparatedHexString("A :01", decoded),
+ isc::BadValue);
+ // Terminating colon.
+ EXPECT_THROW(decodeColonSeparatedHexString("0A:01:", decoded),
+ isc::BadValue);
+ // Opening colon.
+ EXPECT_THROW(decodeColonSeparatedHexString(":0A:01", decoded),
+ isc::BadValue);
+ // Three digits before the colon.
+ EXPECT_THROW(decodeColonSeparatedHexString("0A1:B1", decoded),
+ isc::BadValue);
+}
+
+void testFormatted(const std::string& input,
+ const std::string& reference) {
+ // Create a reference vector.
+ std::vector<uint8_t> reference_vector;
+ ASSERT_NO_THROW(encode::decodeHex(reference, reference_vector));
+
+ // Fill the output vector with some garbage to make sure that
+ // the data is erased when a string is decoded successfully.
+ std::vector<uint8_t> decoded(1, 10);
+ ASSERT_NO_THROW(decodeFormattedHexString(input, decoded));
+
+ // Get the string representation of the decoded data for logging
+ // purposes.
+ std::string encoded;
+ ASSERT_NO_THROW(encoded = encode::encodeHex(decoded));
+
+ // Check if the decoded data matches the reference.
+ EXPECT_TRUE(decoded == reference_vector)
+ << "decoded data don't match the reference, input='"
+ << input << "', reference='" << reference << "'"
+ ", decoded='" << encoded << "'";
+}
+
+TEST(StringUtilTest, decodeFormattedHexString) {
+ // Colon separated.
+ testFormatted("1:A7:B5:4:23", "01A7B50423");
+ // Space separated.
+ testFormatted("1 A7 B5 4 23", "01A7B50423");
+ // No colons, even number of digits.
+ testFormatted("17a534", "17A534");
+ // Odd number of digits.
+ testFormatted("A3A6f78", "0A3A6F78");
+ // '0x' prefix.
+ testFormatted("0xA3A6f78", "0A3A6F78");
+ // '0x' prefix with a special value of 0.
+ testFormatted("0x0", "00");
+ // Empty string.
+ testFormatted("", "");
+
+ std::vector<uint8_t> decoded;
+ // Dangling colon.
+ EXPECT_THROW(decodeFormattedHexString("0a:", decoded),
+ isc::BadValue);
+ // Dangling space.
+ EXPECT_THROW(decodeFormattedHexString("0a ", decoded),
+ isc::BadValue);
+ // '0x' prefix and spaces.
+ EXPECT_THROW(decodeFormattedHexString("x01 02", decoded),
+ isc::BadValue);
+ // '0x' prefix and colons.
+ EXPECT_THROW(decodeFormattedHexString("0x01:02", decoded),
+ isc::BadValue);
+ // colon and spaces mixed
+ EXPECT_THROW(decodeFormattedHexString("01:02 03", decoded),
+ isc::BadValue);
+ // Missing colon.
+ EXPECT_THROW(decodeFormattedHexString("01:0203", decoded),
+ isc::BadValue);
+ // Missing space.
+ EXPECT_THROW(decodeFormattedHexString("01 0203", decoded),
+ isc::BadValue);
+ // Invalid prefix.
+ EXPECT_THROW(decodeFormattedHexString("x0102", decoded),
+ isc::BadValue);
+ // Invalid prefix again.
+ EXPECT_THROW(decodeFormattedHexString("1x0102", decoded),
+ isc::BadValue);
+}
+
+/// @brief Function used to test StringSantitizer
+/// @param original - string to sanitize
+/// @param char_set - regular expression string describing invalid
+/// characters
+/// @param char_replacement - character(s) which replace invalid
+/// characters
+/// @param expected - expected sanitized string
+void sanitizeStringTest(
+ const std::string& original,
+ const std::string& char_set,
+ const std::string& char_replacement,
+ const std::string& expected) {
+
+ StringSanitizerPtr ss;
+ std::string sanitized;
+
+ try {
+ ss.reset(new StringSanitizer(char_set, char_replacement));
+ } catch (const std::exception& ex) {
+ ADD_FAILURE() << "Could not construct sanitizer:" << ex.what();
+ return;
+ }
+
+ try {
+ sanitized = ss->scrub(original);
+ } catch (const std::exception& ex) {
+ ADD_FAILURE() << "Could not scrub string:" << ex.what();
+ return;
+ }
+
+ EXPECT_EQ(sanitized, expected);
+}
+
+// Verifies StringSantizer class
+TEST(StringUtilTest, stringSanitizer) {
+ // Bad regular expression should throw.
+ StringSanitizerPtr ss;
+ ASSERT_THROW(ss.reset(new StringSanitizer("[bogus-regex","")), BadValue);
+
+ std::string good_data(StringSanitizer::MAX_DATA_SIZE, '0');
+ std::string bad_data(StringSanitizer::MAX_DATA_SIZE + 1, '0');
+
+ ASSERT_NO_THROW(ss.reset(new StringSanitizer(good_data, good_data)));
+
+ ASSERT_THROW(ss.reset(new StringSanitizer(bad_data, "")), BadValue);
+ ASSERT_THROW(ss.reset(new StringSanitizer("", bad_data)), BadValue);
+
+ // List of invalid chars should work: (b,c,2 are invalid)
+ sanitizeStringTest("abc.123", "[b-c2]", "*",
+ "a**.1*3");
+ // Inverted list of valid chars should work: (b,c,2 are valid)
+ sanitizeStringTest("abc.123", "[^b-c2]", "*",
+ "*bc**2*");
+
+ // A string of all valid chars should return an identical string.
+ sanitizeStringTest("-_A--B__Cabc34567_-", "[^A-Ca-c3-7_-]", "x",
+ "-_A--B__Cabc34567_-");
+
+ // Replacing with a character should work.
+ sanitizeStringTest("A[b]c\12JoE3-_x!B$Y#e", "[^A-Za-z0-9_]", "*",
+ "A*b*c*JoE3*_x*B*Y*e");
+
+ // Removing (i.e.replacing with an "empty" string) should work.
+ sanitizeStringTest("A[b]c\12JoE3-_x!B$Y#e", "[^A-Za-z0-9_]", "",
+ "AbcJoE3_xBYe");
+
+ // More than one non-matching in a row should work.
+ sanitizeStringTest("%%A%%B%%C%%", "[^A-Za-z0-9_]", "x",
+ "xxAxxBxxCxx");
+
+ // Removing more than one non-matching in a row should work.
+ sanitizeStringTest("%%A%%B%%C%%", "[^A-Za-z0-9_]", "",
+ "ABC");
+
+ // Replacing with a string should work.
+ sanitizeStringTest("%%A%%B%%C%%", "[^A-Za-z0-9_]", "xyz",
+ "xyzxyzAxyzxyzBxyzxyzCxyzxyz");
+
+ // Dots as valid chars work.
+ sanitizeStringTest("abc.123", "[^A-Za-z0-9_.]", "*",
+ "abc.123");
+
+ std::string withNulls("\000ab\000c.12\0003",10);
+ sanitizeStringTest(withNulls, "[^A-Za-z0-9_.]", "*",
+ "*ab*c.12*3");
+}
+
+// Verifies templated buffer iterator seekTrimmed() function
+TEST(StringUtilTest, seekTrimmed) {
+
+ // Empty buffer should be fine.
+ std::vector<uint8_t> buffer;
+ auto begin = buffer.end();
+ auto end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 0));
+ EXPECT_EQ(0, std::distance(begin, end));
+
+ // Buffer of only trim values, should be fine.
+ buffer = { 1, 1 };
+ begin = buffer.begin();
+ end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 1));
+ EXPECT_EQ(0, std::distance(begin, end));
+
+ // One trailing null should trim off.
+ buffer = {'o', 'n', 'e', 0 };
+ begin = buffer.begin();
+ end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 0));
+ EXPECT_EQ(3, std::distance(begin, end));
+
+ // More than one trailing null should trim off.
+ buffer = { 't', 'h', 'r', 'e', 'e', 0, 0, 0 };
+ begin = buffer.begin();
+ end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 0));
+ EXPECT_EQ(5, std::distance(begin, end));
+
+ // Embedded null should be left in place.
+ buffer = { 'e', 'm', 0, 'b', 'e', 'd' };
+ begin = buffer.begin();
+ end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 0));
+ EXPECT_EQ(6, std::distance(begin, end));
+
+ // Leading null should be left in place.
+ buffer = { 0, 'l', 'e', 'a', 'd', 'i', 'n', 'g' };
+ begin = buffer.begin();
+ end = buffer.end();
+ ASSERT_NO_THROW(end = seekTrimmed(begin, end, 0));
+ EXPECT_EQ(8, std::distance(begin, end));
+}
+
+// Verifies isPrintable predicate on strings.
+TEST(StringUtilTest, stringIsPrintable) {
+ string content;
+
+ // Empty is printable.
+ EXPECT_TRUE(isPrintable(content));
+
+ // Check Abcd.
+ content = "Abcd";
+ EXPECT_TRUE(isPrintable(content));
+
+ // Add a control character (not printable).
+ content += "\a";
+ EXPECT_FALSE(isPrintable(content));
+}
+
+// Verifies isPrintable predicate on byte vectors.
+TEST(StringUtilTest, vectorIsPrintable) {
+ vector<uint8_t> content;
+
+ // Empty is printable.
+ EXPECT_TRUE(isPrintable(content));
+
+ // Check Abcd.
+ content = { 0x41, 0x62, 0x63, 0x64 };
+ EXPECT_TRUE(isPrintable(content));
+
+ // Add a control character (not printable).
+ content.push_back('\a');
+ EXPECT_FALSE(isPrintable(content));
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/thread_pool_unittest.cc b/src/lib/util/tests/thread_pool_unittest.cc
new file mode 100644
index 0000000..9c636c9
--- /dev/null
+++ b/src/lib/util/tests/thread_pool_unittest.cc
@@ -0,0 +1,661 @@
+// Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+#include <util/thread_pool.h>
+
+#include <signal.h>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief define CallBack type
+typedef function<void()> CallBack;
+
+/// @brief Test Fixture for testing isc::dhcp::ThreadPool
+class ThreadPoolTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ ThreadPoolTest() : thread_count_(0), count_(0), wait_(false) {
+ }
+
+ /// @brief task function which registers the thread id and signals main
+ /// thread to stop waiting and then waits for main thread to signal to exit
+ void runAndWait() {
+ // run task
+ run();
+ // wait for main thread signal to exit
+ unique_lock<mutex> lk(wait_mutex_);
+ wait_cv_.wait(lk, [&]() {return (wait() == false);});
+ }
+
+ /// @brief task function which registers the thread id and signals main
+ /// thread to stop waiting
+ void run() {
+ {
+ // make sure this thread has started and it is accounted for
+ lock_guard<mutex> lk(mutex_);
+ auto id = this_thread::get_id();
+ // register this thread as doing work on items
+ ids_.emplace(id);
+ // finish task
+ ++count_;
+ // register this task on the history of this thread
+ history_[id].push_back(count_);
+ }
+ // wake main thread if it is waiting for this thread to process
+ cv_.notify_all();
+ }
+
+ /// @brief task function which tries to stop the thread pool and then calls
+ /// @ref runAndWait
+ void runStopResetAndWait(ThreadPool<CallBack>* thread_pool) {
+ EXPECT_THROW(thread_pool->stop(), MultiThreadingInvalidOperation);
+ EXPECT_THROW(thread_pool->reset(), MultiThreadingInvalidOperation);
+ EXPECT_THROW(thread_pool->wait(), MultiThreadingInvalidOperation);
+ EXPECT_THROW(thread_pool->wait(0), MultiThreadingInvalidOperation);
+ sigset_t nsset;
+ pthread_sigmask(SIG_SETMASK, 0, &nsset);
+ EXPECT_EQ(1, sigismember(&nsset, SIGCHLD));
+ EXPECT_EQ(1, sigismember(&nsset, SIGINT));
+ EXPECT_EQ(1, sigismember(&nsset, SIGHUP));
+ EXPECT_EQ(1, sigismember(&nsset, SIGTERM));
+ EXPECT_NO_THROW(runAndWait());
+ }
+
+ /// @brief reset all counters and internal test state
+ void reset(uint32_t thread_count) {
+ // stop test threads
+ stopThreads();
+ // reset the internal state of the test
+ thread_count_ = thread_count;
+ count_ = 0;
+ wait_ = true;
+ ids_.clear();
+ history_.clear();
+ }
+
+ /// @brief start test threads and block main thread until all tasks have
+ /// been processed
+ ///
+ /// @param thread_count number of threads to be started
+ /// @param items_count number of items to wait for being processed
+ /// @param start create processing threads
+ /// @param signal give main thread control over the threads exit
+ void waitTasks(uint32_t thread_count, uint32_t items_count,
+ bool start = false, bool signal = true) {
+ // make sure we have all threads running when performing all the checks
+ unique_lock<mutex> lck(mutex_);
+ if (start) {
+ // start test threads if explicitly specified
+ startThreads(thread_count, signal);
+ }
+ // wait for the threads to process all the items
+ cv_.wait(lck, [&]() {return (count() == items_count);});
+ }
+
+ /// @brief start test threads
+ ///
+ /// @param thread_count number of threads to be started
+ /// @param signal give main thread control over the threads exit
+ void startThreads(uint32_t thread_count, bool signal = true) {
+ // set default task function to wait for main thread signal
+ auto runFunction = &ThreadPoolTest::runAndWait;
+ if (!signal) {
+ // set the task function to finish immediately
+ runFunction = &ThreadPoolTest::run;
+ }
+ // start test threads
+ for (uint32_t i = 0; i < thread_count; ++i) {
+ threads_.push_back(boost::make_shared<std::thread>(runFunction, this));
+ }
+ }
+
+ /// @brief stop test threads
+ void stopThreads() {
+ // signal threads that are waiting
+ signalThreads();
+ // wait for all test threads to exit
+ for (auto thread : threads_) {
+ thread->join();
+ }
+ // reset all threads
+ threads_.clear();
+ }
+
+ /// @brief function used by main thread to unblock processing threads
+ void signalThreads() {
+ {
+ lock_guard<mutex> lk(wait_mutex_);
+ // clear the wait flag so that threads will no longer wait for the main
+ // thread signal
+ wait_ = false;
+ }
+ // wake all threads if waiting for main thread signal
+ wait_cv_.notify_all();
+ }
+
+ /// @brief number of completed tasks
+ ///
+ /// @return the number of completed tasks
+ uint32_t count() {
+ return (count_);
+ }
+
+ /// @brief flag which indicates if working thread should wait for main
+ /// thread signal
+ ///
+ /// @return the wait flag
+ bool wait() {
+ return (wait_);
+ }
+
+ /// @brief check the total number of tasks that have been processed
+ /// Some of the tasks may have been run on the same thread and none may have
+ /// been processed by other threads
+ void checkRunHistory(uint32_t items_count) {
+ uint32_t count = 0;
+ // iterate over all threads history and count all the processed tasks
+ for (auto element : history_) {
+ count += element.second.size();
+ }
+ ASSERT_EQ(count, items_count);
+ }
+
+ /// @brief check the total number of threads that have processed tasks
+ void checkIds(uint32_t count) {
+ ASSERT_EQ(ids_.size(), count);
+ }
+
+private:
+ /// @brief thread count used by the test
+ uint32_t thread_count_;
+
+ /// @brief mutex used to keep the internal state consistent
+ std::mutex mutex_;
+
+ /// @brief condition variable used to signal main thread that all threads
+ /// have started processing
+ condition_variable cv_;
+
+ /// @brief mutex used to keep the internal state consistent
+ /// related to the control of the main thread over the working threads exit
+ std::mutex wait_mutex_;
+
+ /// @brief condition variable used to signal working threads to exit
+ condition_variable wait_cv_;
+
+ /// @brief number of completed tasks
+ uint32_t count_;
+
+ /// @brief flag which indicates if working thread should wait for main
+ /// thread signal
+ bool wait_;
+
+ /// @brief the set of thread ids which have completed tasks
+ set<std::thread::id> ids_;
+
+ /// @brief the list of completed tasks run by each thread
+ map<std::thread::id, list<uint32_t>> history_;
+
+ /// @brief the list of test threads
+ list<boost::shared_ptr<std::thread>> threads_;
+};
+
+/// @brief test ThreadPool add and count
+TEST_F(ThreadPoolTest, addAndCount) {
+ uint32_t items_count;
+ CallBack call_back;
+ ThreadPool<CallBack> thread_pool;
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 4;
+
+ call_back = std::bind(&ThreadPoolTest::run, this);
+
+ // add items to stopped thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+
+ // calling reset should clear all threads and should remove all queued items
+ EXPECT_NO_THROW(thread_pool.reset());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+}
+
+/// @brief test ThreadPool start and stop
+TEST_F(ThreadPoolTest, startAndStop) {
+ uint32_t items_count;
+ uint32_t thread_count;
+ CallBack call_back;
+ ThreadPool<CallBack> thread_pool;
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 4;
+ thread_count = 4;
+ // prepare setup
+ reset(thread_count);
+
+ // create tasks which block thread pool threads until signaled by main
+ // thread to force all threads of the thread pool to run exactly one task
+ call_back = std::bind(&ThreadPoolTest::runAndWait, this);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_THROW(thread_pool.start(0), InvalidParameter);
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // do it once again to check if it works
+ EXPECT_THROW(thread_pool.start(thread_count), InvalidOperation);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_NO_THROW(thread_pool.stop());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // do it once again to check if it works
+ EXPECT_THROW(thread_pool.stop(), InvalidOperation);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // add items to stopped thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_THROW(thread_pool.stop(), InvalidOperation);
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling reset should clear all threads and should remove all queued items
+ EXPECT_NO_THROW(thread_pool.reset());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // do it once again to check if it works
+ EXPECT_NO_THROW(thread_pool.reset());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // add items to running thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // wait for all items to be processed
+ waitTasks(thread_count, items_count);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+ // as each thread pool thread is still waiting on main to unblock, each
+ // thread should have been registered in ids list
+ checkIds(items_count);
+ // all items should have been processed
+ ASSERT_EQ(count(), items_count);
+
+ // check that the number of processed tasks matches the number of items
+ checkRunHistory(items_count);
+
+ // signal thread pool tasks to continue
+ signalThreads();
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_NO_THROW(thread_pool.stop());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 64;
+ thread_count = 16;
+ // prepare setup
+ reset(thread_count);
+
+ // create tasks which do not block the thread pool threads so that several
+ // tasks can be run on the same thread and some of the threads never even
+ // having a chance to run
+ call_back = std::bind(&ThreadPoolTest::run, this);
+
+ // add items to stopped thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // wait for all items to be processed
+ waitTasks(thread_count, items_count);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+ // all items should have been processed
+ ASSERT_EQ(count(), items_count);
+
+ // check that the number of processed tasks matches the number of items
+ checkRunHistory(items_count);
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_NO_THROW(thread_pool.stop());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 16;
+ thread_count = 16;
+ // prepare setup
+ reset(thread_count);
+
+ // create tasks which try to stop the thread pool and then block thread pool
+ // threads until signaled by main thread to force all threads of the thread
+ // pool to run exactly one task
+ call_back = std::bind(&ThreadPoolTest::runStopResetAndWait, this, &thread_pool);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // add items to running thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // wait for all items to be processed
+ waitTasks(thread_count, items_count);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+ // as each thread pool thread is still waiting on main to unblock, each
+ // thread should have been registered in ids list
+ checkIds(items_count);
+ // all items should have been processed
+ ASSERT_EQ(count(), items_count);
+
+ // check that the number of processed tasks matches the number of items
+ checkRunHistory(items_count);
+
+ // signal thread pool tasks to continue
+ signalThreads();
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_NO_THROW(thread_pool.stop());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ /// statistics
+ std::cout << "stat10: " << thread_pool.getQueueStat(10) << std::endl;
+ std::cout << "stat100: " << thread_pool.getQueueStat(100) << std::endl;
+ std::cout << "stat1000: " << thread_pool.getQueueStat(1000) << std::endl;
+}
+
+/// @brief test ThreadPool wait
+TEST_F(ThreadPoolTest, wait) {
+ uint32_t items_count;
+ uint32_t thread_count;
+ CallBack call_back;
+ ThreadPool<CallBack> thread_pool;
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 16;
+ thread_count = 16;
+ // prepare setup
+ reset(thread_count);
+
+ // create tasks which block thread pool threads until signaled by main
+ // thread to force all threads of the thread pool to run exactly one task
+ call_back = std::bind(&ThreadPoolTest::runAndWait, this);
+
+ // add items to stopped thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // wait for all items to be processed
+ waitTasks(thread_count, items_count);
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+ // as each thread pool thread is still waiting on main to unblock, each
+ // thread should have been registered in ids list
+ checkIds(items_count);
+ // all items should have been processed
+ ASSERT_EQ(count(), items_count);
+
+ // check that the number of processed tasks matches the number of items
+ checkRunHistory(items_count);
+
+ // check that waiting on tasks does timeout
+ ASSERT_FALSE(thread_pool.wait(1));
+
+ // signal thread pool tasks to continue
+ signalThreads();
+
+ // calling stop should clear all threads and should keep queued items
+ EXPECT_NO_THROW(thread_pool.stop());
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 64;
+ thread_count = 16;
+ // prepare setup
+ reset(thread_count);
+
+ // create tasks which do not block the thread pool threads so that several
+ // tasks can be run on the same thread and some of the threads never even
+ // having a chance to run
+ call_back = std::bind(&ThreadPoolTest::run, this);
+
+ // add items to stopped thread pool
+ for (uint32_t i = 0; i < items_count; ++i) {
+ bool ret = true;
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ // calling start should create the threads and should keep the queued items
+ EXPECT_NO_THROW(thread_pool.start(thread_count));
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+
+ // wait for all items to be processed
+ thread_pool.wait();
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should match
+ ASSERT_EQ(thread_pool.size(), thread_count);
+ // all items should have been processed
+ ASSERT_EQ(count(), items_count);
+
+ // check that the number of processed tasks matches the number of items
+ checkRunHistory(items_count);
+}
+
+/// @brief test ThreadPool max queue size
+TEST_F(ThreadPoolTest, maxQueueSize) {
+ uint32_t items_count;
+ CallBack call_back;
+ ThreadPool<CallBack> thread_pool;
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 20;
+
+ call_back = std::bind(&ThreadPoolTest::run, this);
+
+ // add items to stopped thread pool
+ bool ret = true;
+ for (uint32_t i = 0; i < items_count; ++i) {
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+
+ // change the max count
+ ASSERT_EQ(thread_pool.getMaxQueueSize(), 0);
+ size_t max_queue_size = 10;
+ thread_pool.setMaxQueueSize(max_queue_size);
+ EXPECT_EQ(thread_pool.getMaxQueueSize(), max_queue_size);
+
+ // adding an item should squeeze the queue
+ EXPECT_EQ(thread_pool.count(), items_count);
+ EXPECT_NO_THROW(ret = thread_pool.add(boost::make_shared<CallBack>(call_back)));
+ EXPECT_FALSE(ret);
+ EXPECT_EQ(thread_pool.count(), max_queue_size);
+}
+
+/// @brief test ThreadPool add front.
+TEST_F(ThreadPoolTest, addFront) {
+ uint32_t items_count;
+ CallBack call_back;
+ ThreadPool<CallBack> thread_pool;
+ // the item count should be 0
+ ASSERT_EQ(thread_pool.count(), 0);
+ // the thread count should be 0
+ ASSERT_EQ(thread_pool.size(), 0);
+
+ items_count = 20;
+
+ call_back = std::bind(&ThreadPoolTest::run, this);
+
+ // add items to stopped thread pool
+ bool ret = true;
+ for (uint32_t i = 0; i < items_count; ++i) {
+ EXPECT_NO_THROW(ret = thread_pool.addFront(boost::make_shared<CallBack>(call_back)));
+ EXPECT_TRUE(ret);
+ }
+
+ // the item count should match
+ ASSERT_EQ(thread_pool.count(), items_count);
+
+ // change the max count
+ ASSERT_EQ(thread_pool.getMaxQueueSize(), 0);
+ size_t max_queue_size = 10;
+ thread_pool.setMaxQueueSize(max_queue_size);
+ EXPECT_EQ(thread_pool.getMaxQueueSize(), max_queue_size);
+
+ // adding an item at front should change nothing queue
+ EXPECT_EQ(thread_pool.count(), items_count);
+ EXPECT_NO_THROW(ret = thread_pool.addFront(boost::make_shared<CallBack>(call_back)));
+ EXPECT_FALSE(ret);
+ EXPECT_EQ(thread_pool.count(), items_count);
+}
+
+/// @brief test ThreadPool get queue statistics.
+TEST_F(ThreadPoolTest, getQueueStat) {
+ ThreadPool<CallBack> thread_pool;
+ EXPECT_THROW(thread_pool.getQueueStat(0), InvalidParameter);
+ EXPECT_THROW(thread_pool.getQueueStat(1), InvalidParameter);
+ EXPECT_THROW(thread_pool.getQueueStat(-10), InvalidParameter);
+ EXPECT_THROW(thread_pool.getQueueStat(10000), InvalidParameter);
+ EXPECT_NO_THROW(thread_pool.getQueueStat(10));
+ EXPECT_NO_THROW(thread_pool.getQueueStat(100));
+ EXPECT_NO_THROW(thread_pool.getQueueStat(1000));
+}
+
+} // namespace
diff --git a/src/lib/util/tests/time_utilities_unittest.cc b/src/lib/util/tests/time_utilities_unittest.cc
new file mode 100644
index 0000000..1637a7a
--- /dev/null
+++ b/src/lib/util/tests/time_utilities_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <string>
+
+#include <time.h>
+
+#include <util/time_utilities.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::util;
+
+// See time_utilities.cc
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
+namespace {
+
+class DNSSECTimeTest : public ::testing::Test {
+protected:
+ ~DNSSECTimeTest() {
+ detail::gettimeFunction = NULL;
+ }
+};
+
+TEST_F(DNSSECTimeTest, fromText) {
+ // In most cases (in practice) the 32-bit and 64-bit versions should
+ // behave identically, so we'll mainly test the 32-bit version, which
+ // will be more commonly used in actual code (because many of the wire
+ // format time field are 32-bit). The subtle cases where these two
+ // return different values will be tested at the end of this test case.
+
+ // These are bogus and should be rejected
+ EXPECT_THROW(timeFromText32("2011 101120000"), InvalidTime);
+ EXPECT_THROW(timeFromText32("201101011200-0"), InvalidTime);
+
+ // Short length (or "decimal integer" version of representation;
+ // it's valid per RFC4034, but is not supported in this implementation)
+ EXPECT_THROW(timeFromText32("20100223"), InvalidTime);
+
+ // Leap year checks
+ EXPECT_THROW(timeFromText32("20110229120000"), InvalidTime);
+ EXPECT_THROW(timeFromText32("21000229120000"), InvalidTime);
+ EXPECT_NO_THROW(timeFromText32("20000229120000"));
+ EXPECT_NO_THROW(timeFromText32("20120229120000"));
+
+ // unusual case: this implementation allows SS=60 for "leap seconds"
+ EXPECT_NO_THROW(timeFromText32("20110101120060"));
+
+ // Out of range parameters
+ EXPECT_THROW(timeFromText32("19100223214617"), InvalidTime); // YY<1970
+ EXPECT_THROW(timeFromText32("20110001120000"), InvalidTime); // MM=00
+ EXPECT_THROW(timeFromText32("20111301120000"), InvalidTime); // MM=13
+ EXPECT_THROW(timeFromText32("20110100120000"), InvalidTime); // DD=00
+ EXPECT_THROW(timeFromText32("20110132120000"), InvalidTime); // DD=32
+ EXPECT_THROW(timeFromText32("20110431120000"), InvalidTime); // 'Apr31'
+ EXPECT_THROW(timeFromText32("20110101250000"), InvalidTime); // HH=25
+ EXPECT_THROW(timeFromText32("20110101126000"), InvalidTime); // mm=60
+ EXPECT_THROW(timeFromText32("20110101120061"), InvalidTime); // SS=61
+
+ // Feb 7, 06:28:15 UTC 2106 is the possible maximum time that can be
+ // represented as an unsigned 32bit integer without overflow.
+ EXPECT_EQ(4294967295LU, timeFromText32("21060207062815"));
+
+ // After that, timeFromText32() should start returning the second count
+ // modulo 2^32.
+ EXPECT_EQ(0, timeFromText32("21060207062816"));
+ EXPECT_EQ(10, timeFromText32("21060207062826"));
+
+ // On the other hand, the 64-bit version should return monotonically
+ // increasing counters.
+ EXPECT_EQ(4294967296LL, timeFromText64("21060207062816"));
+ EXPECT_EQ(4294967306LL, timeFromText64("21060207062826"));
+}
+
+// This helper templated function tells timeToText32 a faked current time.
+// The template parameter is that faked time in the form of int64_t seconds
+// since epoch.
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+// Seconds since epoch for the year 10K eve. Commonly used in some tests
+// below.
+const uint64_t YEAR10K_EVE = 253402300799LL;
+
+TEST_F(DNSSECTimeTest, toText) {
+ // Check a basic case with the default (normal) gettimeFunction
+ // based on the "real current time".
+ // Note: this will fail after year 2078, but at that point we won't use
+ // this program anyway:-)
+ EXPECT_EQ("20100311233000", timeToText32(1268350200));
+
+ // Set the current time to: Feb 18 09:04:14 UTC 2012 (an arbitrary choice
+ // in the range of the first half of uint32 since epoch).
+ detail::gettimeFunction = testGetTime<1329555854LL>;
+
+ // Test the "year 2038" problem.
+ // Check the result of toText() for "INT_MIN" in int32_t. It's in the
+ // 68-year range from the faked current time, so the result should be
+ // in year 2038, instead of 1901.
+ EXPECT_EQ("20380119031408", timeToText64(0x80000000L));
+ EXPECT_EQ("20380119031408", timeToText32(0x80000000L));
+
+ // A controversial case: what should we do with "-1"? It's out of range
+ // in future, but according to RFC time before epoch doesn't seem to be
+ // considered "in-range" either. Our toText() implementation handles
+ // this range as a special case and always treats them as future time
+ // until year 2038. This won't be a real issue in practice, though,
+ // since such too large values won't be used in actual deployment by then.
+ EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
+
+ // After the singular point of year 2038, the first half of uint32 can
+ // point to a future time.
+ // Set the current time to: Apr 1 00:00:00 UTC 2038:
+ detail::gettimeFunction = testGetTime<2153692800LL>;
+ // then time "10" is Feb 7 06:28:26 UTC 2106
+ EXPECT_EQ("21060207062826", timeToText32(10));
+ // in 64-bit, it's 2^32 + 10
+ EXPECT_EQ("21060207062826", timeToText64(0x10000000aLL));
+
+ // After year 2106, the upper half of uint32 can point to past time
+ // (as it should).
+ detail::gettimeFunction = testGetTime<0x10000000aLL>;
+ EXPECT_EQ("21060207062815", timeToText32(0xffffffffL));
+
+ // Try very large time value. Actually it's the possible farthest time
+ // that can be represented in the form of YYYYMMDDHHmmSS.
+ EXPECT_EQ("99991231235959", timeToText64(YEAR10K_EVE));
+ detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
+ EXPECT_EQ("99991231235959", timeToText32(4294197631LU));
+}
+
+TEST_F(DNSSECTimeTest, overflow) {
+ // Jan 1, Year 10,000.
+ EXPECT_THROW(timeToText64(253402300800LL), InvalidTime);
+ detail::gettimeFunction = testGetTime<YEAR10K_EVE - 10>;
+ EXPECT_THROW(timeToText32(4294197632LU), InvalidTime);
+}
+
+}
diff --git a/src/lib/util/tests/triplet_unittest.cc b/src/lib/util/tests/triplet_unittest.cc
new file mode 100644
index 0000000..9736011
--- /dev/null
+++ b/src/lib/util/tests/triplet_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/triplet.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <stdint.h>
+
+using namespace isc::util;
+using namespace isc;
+
+namespace {
+
+// constructor validation
+TEST(TripletTest, constructor) {
+
+ const uint32_t min = 10;
+ const uint32_t value = 20;
+ const uint32_t max = 30;
+
+ Triplet<uint32_t> x(min, value, max);
+
+ EXPECT_EQ(min, x.getMin());
+ EXPECT_EQ(value, x.get());
+ EXPECT_EQ(max, x.getMax());
+ EXPECT_FALSE(x.unspecified());
+
+ // requested values below min should return allowed min value
+ EXPECT_EQ(min, x.get(min - 5));
+
+ EXPECT_EQ(min, x.get(min));
+
+ // requesting a value from within the range (min < x < max) should
+ // return the requested value
+ EXPECT_EQ(17, x.get(17));
+
+ EXPECT_EQ(max, x.get(max));
+
+ EXPECT_EQ(max, x.get(max + 5));
+
+ // this will be boring. It is expected to return 42 no matter what
+ Triplet<uint32_t> y(42);
+
+ EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
+ EXPECT_EQ(42, y.get()); // it returns ...
+ EXPECT_EQ(42, y.getMax()); // the exact value...
+ EXPECT_FALSE(x.unspecified());
+
+ // requested values below or above are ignore
+ EXPECT_EQ(42, y.get(5)); // all...
+ EXPECT_EQ(42, y.get(42)); // the...
+ EXPECT_EQ(42, y.get(80)); // time!
+}
+
+TEST(TripletTest, unspecified) {
+ Triplet<uint32_t> x;
+ // When using the constructor without parameters, the triplet
+ // value is unspecified.
+ EXPECT_EQ(0, x.getMin());
+ EXPECT_EQ(0, x.get());
+ EXPECT_EQ(0, x.getMax());
+ EXPECT_TRUE(x.unspecified());
+
+ // For the triplet which has unspecified value we can call accessors
+ // without an exception.
+ uint32_t exp_unspec = 0;
+ EXPECT_EQ(exp_unspec, x);
+
+ x = 72;
+ // Check if the new value has been assigned.
+ EXPECT_EQ(72, x.getMin());
+ EXPECT_EQ(72, x.get());
+ EXPECT_EQ(72, x.getMax());
+ // Triplet is now specified.
+ EXPECT_FALSE(x.unspecified());
+}
+
+// Triplets must be easy to use.
+// Simple to/from int conversions must be done on the fly.
+TEST(TripletTest, operator) {
+
+ uint32_t x = 47;
+
+ Triplet<uint32_t> foo(1,2,3);
+ Triplet<uint32_t> bar(4,5,6);
+
+ foo = bar;
+
+ EXPECT_EQ(4, foo.getMin());
+ EXPECT_EQ(5, foo.get());
+ EXPECT_EQ(6, foo.getMax());
+ EXPECT_FALSE(foo.unspecified());
+
+ // assignment operator: uint32_t => triplet
+ Triplet<uint32_t> y(0);
+ y = x;
+
+ EXPECT_EQ(x, y.get());
+
+ // let's try the other way around: triplet => uint32_t
+ uint32_t z = 0;
+ z = y;
+
+ EXPECT_EQ(x, z);
+}
+
+// check if specified values are sane
+TEST(TripletTest, sanityCheck) {
+
+ // min is larger than default
+ EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
+
+ // max is smaller than default
+ EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
+
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/util/tests/unlock_guard_unittests.cc b/src/lib/util/tests/unlock_guard_unittests.cc
new file mode 100644
index 0000000..65d868b
--- /dev/null
+++ b/src/lib/util/tests/unlock_guard_unittests.cc
@@ -0,0 +1,236 @@
+// Copyright (C) 2020-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <util/unlock_guard.h>
+#include <exceptions/exceptions.h>
+
+#include <mutex>
+#include <thread>
+
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief test mutex class used to check the internal state of a 'fictional'
+/// mutex so that the functionality of the UnlockGuard can be tested
+/// @note the test mutex can be recursive which means that a lock can be called
+/// on the same thread and not resulting in a dead lock
+class TestMutex {
+public:
+ /// @brief Constructor
+ ///
+ /// @param recursive sets the mutex as recursive mutex
+ TestMutex(bool recursive = false) : lock_(0), dead_lock_(false),
+ lock_count_(0), unlock_count_(0), recursive_(recursive) {
+ }
+
+ /// @brief lock the mutex
+ void lock() {
+ lock_guard<mutex> lk(mutex_);
+ if (lock_ >= 1) {
+ // mutex is already locked
+ if (!recursive_) {
+ // lock on a non-recursive mutex resulting in a dead lock
+ dead_lock_ = true;
+ isc_throw(isc::InvalidOperation,
+ "recursive lock on already locked mutex resulting in "
+ "dead lock");
+ } else {
+ // lock on a recursive mutex
+ if (this_thread::get_id() != id_) {
+ // lock on a recursive mutex on a different thread resulting
+ // in a dead lock
+ dead_lock_ = true;
+ isc_throw(isc::InvalidOperation,
+ "recursive lock on a different thread on already "
+ "locked mutex resulting in dead lock");
+ }
+ }
+ }
+ // increment the total number of locks
+ lock_count_++;
+ // increment the lock state
+ lock_++;
+ // save the thread id
+ id_ = this_thread::get_id();
+ }
+
+ /// @brief unlock the mutex
+ void unlock() {
+ lock_guard<mutex> lk(mutex_);
+ if (lock_ <= 0) {
+ // unlock an unlocked mutex
+ isc_throw(isc::InvalidOperation, "unlock on non locked mutex "
+ "resulting in undefined behavior");
+ }
+ if (lock_ == 1) {
+ // only one thread has the lock
+ // self healing mutex resetting the dead lock flag
+ dead_lock_ = false;
+ // reset the thread id
+ id_ = std::thread::id();
+ }
+ // increment the total number of unlocks
+ unlock_count_++;
+ // decrement the lock state
+ lock_--;
+ }
+
+ /// @brief get the mutex lock state
+ ///
+ /// @return the mutex lock state
+ int32_t getLock() {
+ lock_guard<mutex> lk(mutex_);
+ return lock_;
+ }
+
+ /// @brief get the mutex dead lock state
+ ///
+ /// @return the mutex dead lock state
+ bool getDeadLock() {
+ lock_guard<mutex> lk(mutex_);
+ return dead_lock_;
+ }
+
+ /// @brief get the number of locks performed on mutex
+ ///
+ /// @return the mutex number of locks
+ uint32_t getLockCount() {
+ lock_guard<mutex> lk(mutex_);
+ return lock_count_;
+ }
+
+ /// @brief get the number of unlocks performed on mutex
+ ///
+ /// @return the mutex number of unlocks
+ uint32_t getUnlockCount() {
+ lock_guard<mutex> lk(mutex_);
+ return unlock_count_;
+ }
+
+ /// @brief test the internal state of the mutex
+ ///
+ /// @param expected_lock check equality of this value with lock state
+ /// @param expected_lock_count check equality of this value with lock count
+ /// @param expected_unlock_count check equality of this value with unlock count
+ /// @param expected_dead_lock check equality of this value with dead lock state
+ void testMutexState(int32_t expected_lock,
+ uint32_t expected_lock_count,
+ uint32_t expected_unlock_count,
+ bool expected_dead_lock) {
+ ASSERT_EQ(getLock(), expected_lock);
+ ASSERT_EQ(getLockCount(), expected_lock_count);
+ ASSERT_EQ(getUnlockCount(), expected_unlock_count);
+ ASSERT_EQ(getDeadLock(), expected_dead_lock);
+ }
+
+private:
+ /// @brief internal lock state of the mutex
+ int32_t lock_;
+
+ /// @brief state which indicates that the mutex is in dead lock
+ bool dead_lock_;
+
+ /// @brief total number of locks performed on the mutex
+ uint32_t lock_count_;
+
+ /// @brief total number of unlocks performed on the mutex
+ uint32_t unlock_count_;
+
+ /// @brief flag to indicate if the mutex is recursive or not
+ bool recursive_;
+
+ /// @brief mutex used to keep the internal state consistent
+ mutex mutex_;
+
+ /// @brief the id of the thread holding the mutex
+ std::thread::id id_;
+};
+
+/// @brief Test Fixture for testing isc::util::UnlockGuard
+class UnlockGuardTest : public ::testing::Test {
+};
+
+/// @brief test TestMutex functionality with non-recursive mutex, and recursive
+/// mutex
+TEST_F(UnlockGuardTest, testMutex) {
+ shared_ptr<TestMutex> test_mutex;
+ // test non-recursive lock
+ test_mutex = make_shared<TestMutex>();
+ test_mutex->testMutexState(0, 0, 0, false);
+ {
+ // call lock_guard constructor which locks mutex
+ lock_guard<TestMutex> lock(*test_mutex.get());
+ // expect lock 1 lock_count 1 unlock_count 0 dead_lock false
+ test_mutex->testMutexState(1, 1, 0, false);
+ {
+ // call lock_guard constructor which locks mutex resulting in an
+ // exception as the mutex is already locked (dead lock)
+ EXPECT_THROW(lock_guard<TestMutex> lock(*test_mutex.get()),
+ isc::InvalidOperation);
+ // expect lock 1 lock_count 1 unlock_count 0 dead_lock true
+ // you should not be able to get here...using a real mutex
+ test_mutex->testMutexState(1, 1, 0, true);
+ }
+ // expect lock 1 lock_count 1 unlock_count 0 dead_lock true
+ // you should not be able to get here...using a real mutex
+ test_mutex->testMutexState(1, 1, 0, true);
+ }
+ // expect lock 0 lock_count 1 unlock_count 1 dead_lock false
+ // the implementation is self healing when completely unlocking the mutex
+ test_mutex->testMutexState(0, 1, 1, false);
+ // test recursive lock
+ test_mutex = make_shared<TestMutex>(true);
+ test_mutex->testMutexState(0, 0, 0, false);
+ {
+ // call lock_guard constructor which locks mutex
+ lock_guard<TestMutex> lock(*test_mutex.get());
+ // expect lock 1 lock_count 1 unlock_count 0 dead_lock false
+ test_mutex->testMutexState(1, 1, 0, false);
+ {
+ // call lock_guard constructor which locks mutex but does not block
+ // as this is done on the same thread and the mutex is recursive
+ EXPECT_NO_THROW(lock_guard<TestMutex> lock(*test_mutex.get()));
+ // expect lock 1 lock_count 2 unlock_count 1 dead_lock false
+ // the destructor was already called in EXPECT_NO_THROW scope
+ test_mutex->testMutexState(1, 2, 1, false);
+ }
+ // expect lock 1 lock_count 2 unlock_count 1 dead_lock false
+ test_mutex->testMutexState(1, 2, 1, false);
+ }
+ // expect lock 0 lock_count 2 unlock_count 2 dead_lock false
+ test_mutex->testMutexState(0, 2, 2, false);
+}
+
+/// @brief test UnlockGuard functionality with non-recursive mutex
+TEST_F(UnlockGuardTest, testUnlockGuard) {
+ shared_ptr<TestMutex> test_mutex;
+ // test non-recursive lock
+ test_mutex = make_shared<TestMutex>();
+ test_mutex->testMutexState(0, 0, 0, false);
+ {
+ // call lock_guard constructor which locks mutex
+ lock_guard<TestMutex> lock(*test_mutex.get());
+ // expect lock 1 lock_count 1 unlock_count 0 dead_lock false
+ test_mutex->testMutexState(1, 1, 0, false);
+ {
+ UnlockGuard<TestMutex> unlock_guard(*test_mutex.get());
+ // expect lock 0 lock_count 1 unlock_count 1 dead_lock false
+ test_mutex->testMutexState(0, 1, 1, false);
+ }
+ // expect lock 1 lock_count 2 unlock_count 1 dead_lock false
+ test_mutex->testMutexState(1, 2, 1, false);
+ }
+ // expect lock 0 lock_count 2 unlock_count 2 dead_lock false
+ test_mutex->testMutexState(0, 2, 2, false);
+}
+
+} // namespace
diff --git a/src/lib/util/tests/utf8_unittest.cc b/src/lib/util/tests/utf8_unittest.cc
new file mode 100644
index 0000000..168f38b
--- /dev/null
+++ b/src/lib/util/tests/utf8_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/encode/utf8.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+using namespace isc::util::encode;
+using namespace std;
+
+namespace {
+
+// Verify it does nothing for ASCII.
+TEST(Utf8Test, foobar) {
+ string str("foobar");
+ vector<uint8_t> vec8 = encodeUtf8(str);
+ ASSERT_FALSE(vec8.empty());
+ const char* start = reinterpret_cast<const char*>(&vec8[0]);
+ string str8(start, start + vec8.size());
+ EXPECT_EQ(str, str8);
+}
+
+// Verify it encodes not ASCII as expected.
+TEST(Utf8Test, eightc) {
+ string str("-\x8c-");
+ vector<uint8_t> vec8 = encodeUtf8(str);
+ ASSERT_FALSE(vec8.empty());
+ const char* start = reinterpret_cast<const char*>(&vec8[0]);
+ string str8(start, start + vec8.size());
+ string expected("-\xc2\x8c-");
+ EXPECT_EQ(expected, str8);
+}
+
+// Verify it handles correctly control characters.
+TEST(Utf8Test, control) {
+ string str("fo\x00\n\bar");
+ vector<uint8_t> vec8 = encodeUtf8(str);
+ ASSERT_FALSE(vec8.empty());
+ const char* start = reinterpret_cast<const char*>(&vec8[0]);
+ string str8(start, start + vec8.size());
+ EXPECT_EQ(str, str8);
+}
+
+}
diff --git a/src/lib/util/tests/versioned_csv_file_unittest.cc b/src/lib/util/tests/versioned_csv_file_unittest.cc
new file mode 100644
index 0000000..36a1f91
--- /dev/null
+++ b/src/lib/util/tests/versioned_csv_file_unittest.cc
@@ -0,0 +1,501 @@
+// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <util/versioned_csv_file.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/constants.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+namespace {
+
+using namespace isc::util;
+
+/// @brief Test fixture class for testing operations on VersionedCSVFile.
+///
+/// It implements basic operations on files, such as reading writing
+/// file removal and checking presence of the file. This is used by
+/// unit tests to verify correctness of the file created by the
+/// CSVFile class.
+class VersionedCSVFileTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets the path to the CSV file used throughout the tests.
+ /// The name of the file is test.csv and it is located in the
+ /// current build folder.
+ ///
+ /// It also deletes any dangling files after previous tests.
+ VersionedCSVFileTest();
+
+ /// @brief Destructor.
+ ///
+ /// Deletes the test CSV file if any.
+ virtual ~VersionedCSVFileTest();
+
+ /// @brief Prepends the absolute path to the file specified
+ /// as an argument.
+ ///
+ /// @param filename Name of the file.
+ /// @return Absolute path to the test file.
+ static std::string absolutePath(const std::string& filename);
+
+ /// @brief Check if test file exists on disk.
+ bool exists() const;
+
+ /// @brief Reads whole CSV file.
+ ///
+ /// @return Contents of the file.
+ std::string readFile() const;
+
+ /// @brief Removes existing file (if any).
+ int removeFile() const;
+
+ /// @brief Creates file with contents.
+ ///
+ /// @param contents Contents of the file.
+ void writeFile(const std::string& contents) const;
+
+ /// @brief Absolute path to the file used in the tests.
+ std::string testfile_;
+
+};
+
+VersionedCSVFileTest::VersionedCSVFileTest()
+ : testfile_(absolutePath("test.csv")) {
+ static_cast<void>(removeFile());
+}
+
+VersionedCSVFileTest::~VersionedCSVFileTest() {
+ static_cast<void>(removeFile());
+}
+
+std::string
+VersionedCSVFileTest::absolutePath(const std::string& filename) {
+ std::ostringstream s;
+ s << TEST_DATA_BUILDDIR << "/" << filename;
+ return (s.str());
+}
+
+bool
+VersionedCSVFileTest::exists() const {
+ std::ifstream fs(testfile_.c_str());
+ bool ok = fs.good();
+ fs.close();
+ return (ok);
+}
+
+std::string
+VersionedCSVFileTest::readFile() const {
+ std::ifstream fs(testfile_.c_str());
+ if (!fs.is_open()) {
+ return ("");
+ }
+ std::string contents((std::istreambuf_iterator<char>(fs)),
+ std::istreambuf_iterator<char>());
+ fs.close();
+ return (contents);
+}
+
+int
+VersionedCSVFileTest::removeFile() const {
+ return (remove(testfile_.c_str()));
+}
+
+void
+VersionedCSVFileTest::writeFile(const std::string& contents) const {
+ std::ofstream fs(testfile_.c_str(), std::ofstream::out);
+ if (fs.is_open()) {
+ fs << contents;
+ fs.close();
+ }
+}
+
+// This test checks that the function which is used to add columns of the
+// CSV file works as expected.
+TEST_F(VersionedCSVFileTest, addColumn) {
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+
+ // Verify that we're not allowed to open it without the schema
+ ASSERT_THROW(csv->open(), VersionedCSVFileError);
+
+ // Add two columns.
+ ASSERT_NO_THROW(csv->addColumn("animal", "1.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "blue"));
+
+ // Make sure we can't add duplicates.
+ EXPECT_THROW(csv->addColumn("animal", "1.0", ""), CSVFileError);
+ EXPECT_THROW(csv->addColumn("color", "2.0", "blue"), CSVFileError);
+
+ // But we should still be able to add unique columns.
+ EXPECT_NO_THROW(csv->addColumn("age", "3.0", "21"));
+
+ // Assert that the file is opened, because the rest of the test relies
+ // on this.
+ ASSERT_NO_THROW(csv->recreate());
+ ASSERT_TRUE(exists());
+
+ // We should have 3 defined columns
+ // Input Header should match defined columns on new files
+ // Valid columns should match defined columns on new files
+ // Minimum valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(3, csv->getColumnCount());
+ EXPECT_EQ(3, csv->getInputHeaderCount());
+ EXPECT_EQ(3, csv->getValidColumnCount());
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Schema versions for new files should always match
+ EXPECT_EQ("3.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("3.0", csv->getSchemaVersion());
+
+ // Input Schema State should be current for new files
+ EXPECT_EQ(VersionedCSVFile::CURRENT, csv->getInputSchemaState());
+ EXPECT_FALSE(csv->needsConversion());
+
+ // Make sure we can't add columns (even unique) when the file is open.
+ ASSERT_THROW(csv->addColumn("zoo", "3.0", ""), CSVFileError);
+
+ // Close the file.
+ ASSERT_NO_THROW(csv->close());
+ // And check that now it is possible to add the column.
+ EXPECT_NO_THROW(csv->addColumn("zoo", "3.0", ""));
+}
+
+// Verifies that a current schema version file loads correctly.
+TEST_F(VersionedCSVFileTest, currentSchemaTest) {
+
+ // Create our versioned file, with three columns
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "2.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "grey"));
+ ASSERT_NO_THROW(csv->addColumn("age", "2.0", "0"));
+
+ // Write a file compliant with the current schema version.
+ writeFile("animal,color,age\n"
+ "cat,black,2\n"
+ "lion,yellow,17\n"
+ "dog,brown,5\n");
+
+ // Header should pass validation and allow the open to succeed.
+ ASSERT_NO_THROW(csv->open());
+
+ // For schema current file We should have:
+ // 3 defined columns
+ // 3 columns total found in the header
+ // 3 valid columns found in the header
+ // Minimum valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(3, csv->getColumnCount());
+ EXPECT_EQ(3, csv->getInputHeaderCount());
+ EXPECT_EQ(3, csv->getValidColumnCount());
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Input schema and current schema should both be 2.0
+ EXPECT_EQ("2.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("2.0", csv->getSchemaVersion());
+
+ // Input Schema State should be CURRENT
+ EXPECT_EQ(VersionedCSVFile::CURRENT, csv->getInputSchemaState());
+ EXPECT_FALSE(csv->needsConversion());
+
+ // First row is correct.
+ CSVRow row;
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("black", row.readAt(1));
+ EXPECT_EQ("2", row.readAt(2));
+
+ // Second row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("yellow", row.readAt(1));
+ EXPECT_EQ("17", row.readAt(2));
+
+ // Third row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("dog", row.readAt(0));
+ EXPECT_EQ("brown", row.readAt(1));
+ EXPECT_EQ("5", row.readAt(2));
+}
+
+
+// Verifies the basic ability to upgrade valid files.
+// It starts with a version 1.0 file and updates
+// it through two schema evolutions.
+TEST_F(VersionedCSVFileTest, upgradeOlderVersions) {
+
+ // Create version 1.0 schema CSV file
+ writeFile("animal\n"
+ "cat\n"
+ "lion\n"
+ "dog\n");
+
+ // Create our versioned file, with two columns, one for each
+ // schema version
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "1.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "blue"));
+
+ // Header should pass validation and allow the open to succeed.
+ ASSERT_NO_THROW(csv->open());
+
+ // We should have:
+ // 2 defined columns
+ // 1 column found in the header
+ // 1 valid column in the header
+ // Minimum valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(2, csv->getColumnCount());
+ EXPECT_EQ(1, csv->getInputHeaderCount());
+ EXPECT_EQ(1, csv->getValidColumnCount());
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Input schema should be 1.0, while our current schema should be 2.0
+ EXPECT_EQ("1.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("2.0", csv->getSchemaVersion());
+
+ // Input Schema State should be NEEDS_UPGRADE
+ EXPECT_EQ(VersionedCSVFile::NEEDS_UPGRADE, csv->getInputSchemaState());
+ EXPECT_TRUE(csv->needsConversion());
+
+ // First row is correct.
+ CSVRow row;
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+
+ // Second row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+
+ // Third row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("dog", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+
+ // Now, let's try to append something to this file.
+ CSVRow row_write(2);
+ row_write.writeAt(0, "bird");
+ row_write.writeAt(1, "yellow");
+ ASSERT_NO_THROW(csv->append(row_write));
+
+ // Close the file
+ ASSERT_NO_THROW(csv->flush());
+ ASSERT_NO_THROW(csv->close());
+
+
+ // Check the file contents are correct.
+ EXPECT_EQ("animal\n"
+ "cat\n"
+ "lion\n"
+ "dog\n"
+ "bird,yellow\n",
+ readFile());
+
+ // Create a third schema by adding a column
+ ASSERT_NO_THROW(csv->addColumn("age", "3.0", "21"));
+ ASSERT_EQ(3, csv->getColumnCount());
+
+ // Header should pass validation and allow the open to succeed
+ ASSERT_NO_THROW(csv->open());
+
+ // We should have:
+ // 3 defined columns
+ // 1 column found in the header
+ // 1 valid column in the header
+ // Minimum valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(3, csv->getColumnCount());
+ EXPECT_EQ(1, csv->getInputHeaderCount());
+ EXPECT_EQ(1, csv->getValidColumnCount());
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Make sure schema versions are accurate
+ EXPECT_EQ("1.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("3.0", csv->getSchemaVersion());
+
+ // Input Schema State should be NEEDS_UPGRADE
+ EXPECT_EQ(VersionedCSVFile::NEEDS_UPGRADE, csv->getInputSchemaState());
+ EXPECT_TRUE(csv->needsConversion());
+
+ // First row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+
+ // Second row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+
+ // Third row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("dog", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+
+ // Fourth row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("bird", row.readAt(0));
+ EXPECT_EQ("yellow", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+}
+
+TEST_F(VersionedCSVFileTest, minimumValidColumn) {
+ // Create version 1.0 schema CSV file
+ writeFile("animal\n"
+ "cat\n"
+ "lion\n"
+ "dog\n");
+
+ // Create our versioned file, with three columns, one for each
+ // schema version
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "1.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "blue"));
+ ASSERT_NO_THROW(csv->addColumn("age", "3.0", "21"));
+
+ // Verify we can't set minimum columns with a non-existent column
+ EXPECT_THROW(csv->setMinimumValidColumns("bogus"), VersionedCSVFileError);
+
+ // Set the minimum number of columns to "color"
+ csv->setMinimumValidColumns("color");
+ EXPECT_EQ(2, csv->getMinimumValidColumns());
+
+ // Header validation should fail, too few columns
+ ASSERT_THROW(csv->open(), CSVFileError);
+
+ // Set the minimum number of columns to 1. File should parse now.
+ csv->setMinimumValidColumns("animal");
+ EXPECT_EQ(1, csv->getMinimumValidColumns());
+ ASSERT_NO_THROW(csv->open());
+
+ // First row is correct.
+ CSVRow row;
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("dog", row.readAt(0));
+ EXPECT_EQ("blue", row.readAt(1));
+ EXPECT_EQ("21", row.readAt(2));
+}
+
+TEST_F(VersionedCSVFileTest, invalidHeaderColumn) {
+
+ // Create our version 2.0 schema file
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "1.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "blue"));
+
+ // Create a file with the correct number of columns but a wrong column name
+ writeFile("animal,colour\n"
+ "cat,red\n"
+ "lion,green\n");
+
+ // Header validation should fail, we have an invalid column
+ ASSERT_THROW(csv->open(), CSVFileError);
+}
+
+TEST_F(VersionedCSVFileTest, downGrading) {
+ // Create our version 2.0 schema file
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "1.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "blue"));
+
+ // Create schema 2.0 file PLUS an extra column
+ writeFile("animal,color,age\n"
+ "cat,red,5\n"
+ "lion,green,8\n");
+
+ // Header should validate and file should open.
+ ASSERT_NO_THROW(csv->open());
+
+ // We should have:
+ // 2 defined columns
+ // 3 columns found in the header
+ // 2 valid columns in the header
+ // Minimum valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(2, csv->getColumnCount());
+ EXPECT_EQ(3, csv->getInputHeaderCount());
+ EXPECT_EQ(2, csv->getValidColumnCount());
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Input schema and current schema should both be 2.0
+ EXPECT_EQ("2.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("2.0", csv->getSchemaVersion());
+
+ // Input Schema State should be NEEDS_DOWNGRADE
+ EXPECT_EQ(VersionedCSVFile::NEEDS_DOWNGRADE, csv->getInputSchemaState());
+ EXPECT_TRUE(csv->needsConversion());
+
+ // First row is correct.
+ CSVRow row;
+ EXPECT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("red", row.readAt(1));
+
+ // No data beyond the second column
+ EXPECT_THROW(row.readAt(2), CSVFileError);
+
+ // Second row is correct.
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("green", row.readAt(1));
+
+ // No data beyond the second column
+ EXPECT_THROW(row.readAt(2), CSVFileError);
+}
+
+
+TEST_F(VersionedCSVFileTest, rowChecking) {
+ // Create version 2.0 schema CSV file with a
+ // - valid header
+ // - row 0 has too many values
+ // - row 1 is valid
+ // - row 3 is too few values
+ writeFile("animal,color\n"
+ "cat,red,bogus_row_value\n"
+ "lion,green\n"
+ "too_few\n");
+
+ // Create our versioned file, with two columns, one for each
+ // schema version
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ csv->addColumn("animal", "1.0", "");
+ csv->addColumn("color", "2.0", "blue");
+
+ // Header validation should pass, so we can open
+ ASSERT_NO_THROW(csv->open());
+
+ CSVRow row;
+ // First row has too many
+ EXPECT_FALSE(csv->next(row));
+
+ // Second row is valid
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("lion", row.readAt(0));
+ EXPECT_EQ("green", row.readAt(1));
+
+ // Third row has too few
+ EXPECT_FALSE(csv->next(row));
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/watch_socket_unittests.cc b/src/lib/util/tests/watch_socket_unittests.cc
new file mode 100644
index 0000000..b503844
--- /dev/null
+++ b/src/lib/util/tests/watch_socket_unittests.cc
@@ -0,0 +1,263 @@
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <config.h>
+#include <util/watch_socket.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/select.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_SYS_FILIO_H
+// FIONREAD is here on Solaris
+#include <sys/filio.h>
+#endif
+
+using namespace std;
+using namespace isc;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Returns the result of select() given an fd to check for read status.
+///
+/// @param fd_to_check The file descriptor to test
+///
+/// @return Returns less than one on an error, 0 if the fd is not ready to
+/// read, > 0 if it is ready to read.
+int selectCheck(int fd_to_check) {
+ fd_set read_fds;
+ int maxfd = 0;
+
+ FD_ZERO(&read_fds);
+
+ // Add this socket to listening set
+ FD_SET(fd_to_check, &read_fds);
+ maxfd = fd_to_check;
+
+ struct timeval select_timeout;
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = 0;
+
+ return (select(maxfd + 1, &read_fds, NULL, NULL, &select_timeout));
+}
+
+/// @brief Tests the basic functionality of WatchSocket.
+TEST(WatchSocketTest, basics) {
+ WatchSocketPtr watch;
+
+ /// Verify that we can construct a WatchSocket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ /// Verify that post-construction the state the select-fd is valid.
+ int select_fd = watch->getSelectFd();
+ EXPECT_NE(select_fd, WatchSocket::SOCKET_NOT_VALID);
+
+ /// Verify that isReady() is false and that a call to select agrees.
+ EXPECT_FALSE(watch->isReady());
+ EXPECT_EQ(0, selectCheck(select_fd));
+
+ /// Verify that the socket can be marked ready.
+ ASSERT_NO_THROW(watch->markReady());
+
+ /// Verify that we have exactly one marker waiting to be read.
+ int count = 0;
+ EXPECT_FALSE(ioctl(select_fd, FIONREAD, &count));
+ EXPECT_EQ(sizeof(WatchSocket::MARKER), count);
+
+ /// Verify that we can call markReady again without error.
+ ASSERT_NO_THROW(watch->markReady());
+
+ /// Verify that we STILL have exactly one marker waiting to be read.
+ EXPECT_FALSE(ioctl(select_fd, FIONREAD, &count));
+ EXPECT_EQ(sizeof(WatchSocket::MARKER), count);
+
+ /// Verify that isReady() is true and that a call to select agrees.
+ EXPECT_TRUE(watch->isReady());
+ EXPECT_EQ(1, selectCheck(select_fd));
+
+ /// Verify that the socket can be cleared.
+ ASSERT_NO_THROW(watch->clearReady());
+
+ /// Verify that isReady() is false and that a call to select agrees.
+ EXPECT_FALSE(watch->isReady());
+ EXPECT_EQ(0, selectCheck(select_fd));
+}
+
+/// @brief Checks behavior when select_fd is closed externally while in the
+/// "cleared" state.
+TEST(WatchSocketTest, closedWhileClear) {
+ WatchSocketPtr watch;
+
+ /// Verify that we can construct a WatchSocket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ /// Verify that post-construction the state the select-fd is valid.
+ int select_fd = watch->getSelectFd();
+ ASSERT_NE(select_fd, WatchSocket::SOCKET_NOT_VALID);
+
+ // Verify that socket does not appear ready.
+ ASSERT_EQ(0, watch->isReady());
+
+ // Interfere by closing the fd.
+ ASSERT_EQ(0, close(select_fd));
+
+ // Verify that socket does not appear ready.
+ ASSERT_EQ(0, watch->isReady());
+
+ // Verify that clear does NOT throw.
+ ASSERT_NO_THROW(watch->clearReady());
+
+ // Verify that trying to mark it fails.
+ ASSERT_THROW(watch->markReady(), WatchSocketError);
+
+ // Verify that clear does NOT throw.
+ ASSERT_NO_THROW(watch->clearReady());
+
+ // Verify that getSelectFd() returns invalid socket.
+ ASSERT_EQ(WatchSocket::SOCKET_NOT_VALID, watch->getSelectFd());
+}
+
+/// @brief Checks behavior when select_fd has closed while in the "ready"
+/// state.
+TEST(WatchSocketTest, closedWhileReady) {
+ WatchSocketPtr watch;
+
+ /// Verify that we can construct a WatchSocket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ /// Verify that post-construction the state the select-fd is valid.
+ int select_fd = watch->getSelectFd();
+ ASSERT_NE(select_fd, WatchSocket::SOCKET_NOT_VALID);
+
+ /// Verify that the socket can be marked ready.
+ ASSERT_NO_THROW(watch->markReady());
+ EXPECT_EQ(1, selectCheck(select_fd));
+ EXPECT_TRUE(watch->isReady());
+
+ // Interfere by closing the fd.
+ ASSERT_EQ(0, close(select_fd));
+
+ // Verify that isReady() does not throw.
+ ASSERT_NO_THROW(watch->isReady());
+
+ // and return false.
+ EXPECT_FALSE(watch->isReady());
+
+ // Verify that trying to clear it does not throw.
+ ASSERT_NO_THROW(watch->clearReady());
+
+ // Verify the select_fd fails as socket is invalid/closed.
+ EXPECT_EQ(-1, selectCheck(select_fd));
+
+ // Verify that subsequent attempts to mark it will fail.
+ ASSERT_THROW(watch->markReady(), WatchSocketError);
+}
+
+/// @brief Checks behavior when select_fd has been marked ready but then
+/// emptied by an external read.
+TEST(WatchSocketTest, emptyReadySelectFd) {
+ WatchSocketPtr watch;
+
+ /// Verify that we can construct a WatchSocket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ /// Verify that post-construction the state the select-fd is valid.
+ int select_fd = watch->getSelectFd();
+ ASSERT_NE(select_fd, WatchSocket::SOCKET_NOT_VALID);
+
+ /// Verify that the socket can be marked ready.
+ ASSERT_NO_THROW(watch->markReady());
+ EXPECT_TRUE(watch->isReady());
+ EXPECT_EQ(1, selectCheck(select_fd));
+
+ // Interfere by reading the fd. This should empty the read pipe.
+ uint32_t buf = 0;
+ ASSERT_EQ((read (select_fd, &buf, sizeof(buf))), sizeof(buf));
+ ASSERT_EQ(WatchSocket::MARKER, buf);
+
+ // Really nothing that can be done to protect against this, but let's
+ // make sure we aren't in a weird state.
+ ASSERT_NO_THROW(watch->clearReady());
+
+ // Verify the select_fd does not fail.
+ EXPECT_FALSE(watch->isReady());
+ EXPECT_EQ(0, selectCheck(select_fd));
+
+ // Verify that getSelectFd() returns is still good.
+ ASSERT_EQ(select_fd, watch->getSelectFd());
+}
+
+/// @brief Checks behavior when select_fd has been marked ready but then
+/// contents have been "corrupted" by a partial read.
+TEST(WatchSocketTest, badReadOnClear) {
+ WatchSocketPtr watch;
+
+ /// Verify that we can construct a WatchSocket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ /// Verify that post-construction the state the select-fd is valid.
+ int select_fd = watch->getSelectFd();
+ ASSERT_NE(select_fd, WatchSocket::SOCKET_NOT_VALID);
+
+ /// Verify that the socket can be marked ready.
+ ASSERT_NO_THROW(watch->markReady());
+ EXPECT_TRUE(watch->isReady());
+ EXPECT_EQ(1, selectCheck(select_fd));
+
+ // Interfere by reading the fd. This should empty the read pipe.
+ uint32_t buf = 0;
+ ASSERT_EQ((read (select_fd, &buf, 1)), 1);
+ ASSERT_NE(WatchSocket::MARKER, buf);
+
+ // Really nothing that can be done to protect against this, but let's
+ // make sure we aren't in a weird state.
+ /// @todo maybe clear should never throw, log only
+ ASSERT_THROW(watch->clearReady(), WatchSocketError);
+
+ // Verify the select_fd does not evaluate to ready.
+ EXPECT_FALSE(watch->isReady());
+ EXPECT_NE(1, selectCheck(select_fd));
+
+ // Verify that getSelectFd() returns INVALID.
+ ASSERT_EQ(WatchSocket::SOCKET_NOT_VALID, watch->getSelectFd());
+
+ // Verify that subsequent attempt to mark it fails.
+ ASSERT_THROW(watch->markReady(), WatchSocketError);
+}
+
+/// @brief Checks if the socket can be explicitly closed.
+TEST(WatchSocketTest, explicitClose) {
+ WatchSocketPtr watch;
+
+ // Create new instance of the socket.
+ ASSERT_NO_THROW(watch.reset(new WatchSocket()));
+ ASSERT_TRUE(watch);
+
+ // Make sure it has been opened by checking that its descriptor
+ // is valid.
+ EXPECT_NE(watch->getSelectFd(), WatchSocket::SOCKET_NOT_VALID);
+
+ // Close the socket.
+ std::string error_string;
+ ASSERT_TRUE(watch->closeSocket(error_string));
+
+ // Make sure that the descriptor is now invalid which indicates
+ // that the socket has been closed.
+ EXPECT_EQ(WatchSocket::SOCKET_NOT_VALID, watch->getSelectFd());
+ // No errors should be reported.
+ EXPECT_TRUE(error_string.empty());
+ // Not ready too.
+ ASSERT_NO_THROW(watch->isReady());
+ EXPECT_FALSE(watch->isReady());
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/util/tests/watched_thread_unittest.cc b/src/lib/util/tests/watched_thread_unittest.cc
new file mode 100644
index 0000000..dd01550
--- /dev/null
+++ b/src/lib/util/tests/watched_thread_unittest.cc
@@ -0,0 +1,218 @@
+// Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/watched_thread.h>
+
+#include <gtest/gtest.h>
+
+#include <atomic>
+#include <functional>
+#include <signal.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::util;
+
+namespace {
+
+/// @brief Test Fixture for testing @c isc::util::WatchedThread
+class WatchedThreadTest : public ::testing::Test {
+public:
+ /// @brief Maximum number of passes allowed in worker event loop
+ static const int WORKER_MAX_PASSES;
+
+ /// @brief Constructor.
+ WatchedThreadTest() {}
+
+ /// @brief Destructor.
+ ~WatchedThreadTest() {
+ }
+
+ /// @brief Sleeps for a given number of event periods sleep
+ /// Each period is 50 ms.
+ void nap(int periods) {
+ usleep(periods * 50 * 1000);
+ };
+
+ /// @brief Worker function to be used by the WatchedThread's thread
+ ///
+ /// The function runs 10 passes through an "event" loop.
+ /// On each pass:
+ /// - check terminate command
+ /// - instigate the desired event (second pass only)
+ /// - naps for 1 period (50ms)
+ ///
+ /// @param watch_type type of event that should occur
+ void worker(WatchedThread::WatchType watch_type) {
+ sigset_t nsset;
+ pthread_sigmask(SIG_SETMASK, 0, &nsset);
+ EXPECT_EQ(1, sigismember(&nsset, SIGCHLD));
+ EXPECT_EQ(1, sigismember(&nsset, SIGINT));
+ EXPECT_EQ(1, sigismember(&nsset, SIGHUP));
+ EXPECT_EQ(1, sigismember(&nsset, SIGTERM));
+ for (passes_ = 1; passes_ < WORKER_MAX_PASSES; ++passes_) {
+
+ // Stop if we're told to do it.
+ if (wthread_->shouldTerminate()) {
+ return;
+ }
+
+ // On the second pass, set the event.
+ if (passes_ == 2) {
+ switch (watch_type) {
+ case WatchedThread::ERROR:
+ wthread_->setError("we have an error");
+ break;
+ case WatchedThread::READY:
+ wthread_->markReady(watch_type);
+ break;
+ case WatchedThread::TERMINATE:
+ default:
+ // Do nothing, we're waiting to be told to stop.
+ break;
+ }
+ }
+
+ // Take a nap.
+ nap(1);
+ }
+
+ // Indicate why we stopped.
+ wthread_->setError("thread expired");
+ }
+
+ /// @brief Current WatchedThread instance.
+ WatchedThreadPtr wthread_;
+
+ /// @brief Counter used to track the number of passes made
+ /// within the thread worker function.
+ std::atomic<int> passes_;
+};
+
+const int WatchedThreadTest::WORKER_MAX_PASSES = 10;
+
+/// Verifies the basic operation of the WatchedThread class.
+/// It checks that a WatchedThread can be created, can be stopped,
+/// and that in set and clear sockets.
+TEST_F(WatchedThreadTest, watchedThreadClassBasics) {
+
+ /// We'll create a WatchedThread and let it run until it expires. (Note this is more
+ /// of a test of WatchedThreadTest itself and ensures that the assumptions made in
+ /// our other tests as to why threads have finished are sound.
+ wthread_.reset(new WatchedThread());
+ ASSERT_FALSE(wthread_->isRunning());
+ wthread_->start(std::bind(&WatchedThreadTest::worker, this, WatchedThread::TERMINATE));
+ ASSERT_TRUE(wthread_->isRunning());
+
+ // Wait more long enough (we hope) for the thread to expire.
+ nap(WORKER_MAX_PASSES * 4);
+
+ // It should have done the maximum number of passes.
+ EXPECT_EQ(passes_, WORKER_MAX_PASSES);
+
+ // Error should be ready and error text should be "thread expired".
+ ASSERT_TRUE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+ EXPECT_EQ("thread expired", wthread_->getLastError());
+
+ // Thread is technically still running, so let's stop it.
+ EXPECT_TRUE(wthread_->isRunning());
+ ASSERT_NO_THROW(wthread_->stop());
+ ASSERT_FALSE(wthread_->isRunning());
+
+ /// Now we'll test stopping a thread.
+ /// Start the WatchedThread, let it run a little and then tell it to stop.
+ wthread_->start(std::bind(&WatchedThreadTest::worker, this, WatchedThread::TERMINATE));
+ ASSERT_TRUE(wthread_->isRunning());
+
+ // No watches should be ready.
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+
+ // Wait a little while.
+ nap(3);
+
+ // Tell it to stop.
+ wthread_->stop();
+ ASSERT_FALSE(wthread_->isRunning());
+
+ // It should have done less than the maximum number of passes.
+ EXPECT_LT(passes_, WORKER_MAX_PASSES);
+
+ // No watches should be ready. Error text should be "thread stopped".
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+ EXPECT_EQ("thread stopped", wthread_->getLastError());
+
+
+ // Next we'll test error notification.
+ // Start the WatchedThread with a thread that sets an error on the second pass.
+ wthread_->start(std::bind(&WatchedThreadTest::worker, this, WatchedThread::ERROR));
+ ASSERT_TRUE(wthread_->isRunning());
+
+ // No watches should be ready.
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+
+ // Wait a little while.
+ nap(6);
+
+ // It should now indicate an error.
+ ASSERT_TRUE(wthread_->isReady(WatchedThread::ERROR));
+ EXPECT_EQ("we have an error", wthread_->getLastError());
+
+ // Tell it to stop.
+ wthread_->stop();
+ ASSERT_FALSE(wthread_->isRunning());
+
+ // It should have done less than the maximum number of passes.
+ EXPECT_LT(passes_, WORKER_MAX_PASSES);
+
+ // No watches should be ready. Error text should be "thread stopped".
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+ EXPECT_EQ("thread stopped", wthread_->getLastError());
+
+
+ // Finally, we'll test data ready notification.
+ // We'll start the WatchedThread with a thread that indicates data ready on its second pass.
+ wthread_->start(std::bind(&WatchedThreadTest::worker, this, WatchedThread::READY));
+ ASSERT_TRUE(wthread_->isRunning());
+
+ // No watches should be ready.
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+
+ // Wait a little while.
+ nap(6);
+
+ // It should now indicate data ready.
+ ASSERT_TRUE(wthread_->isReady(WatchedThread::READY));
+
+ // Tell it to stop.
+ wthread_->stop();
+ ASSERT_FALSE(wthread_->isRunning());
+
+ // It should have done less than the maximum number of passes.
+ EXPECT_LT(passes_, WORKER_MAX_PASSES);
+
+ // No watches should be ready. Error text should be "thread stopped".
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::ERROR));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::READY));
+ ASSERT_FALSE(wthread_->isReady(WatchedThread::TERMINATE));
+ EXPECT_EQ("thread stopped", wthread_->getLastError());
+}
+
+}