diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/util/tests | |
parent | Initial commit. (diff) | |
download | isc-kea-upstream.tar.xz isc-kea-upstream.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
40 files changed, 10342 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..5f8b1e8 --- /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 += bigint_unittest.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..e2f6051 --- /dev/null +++ b/src/lib/util/tests/Makefile.in @@ -0,0 +1,1730 @@ +# 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_cpp20.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_netconf.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 bigint_unittest.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-bigint_unittest.$(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-bigint_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='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + 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_GSSAPI_CONFIGURE_FLAG = @DISTCHECK_GSSAPI_CONFIGURE_FLAG@ +DISTCHECK_GTEST_CONFIGURE_FLAG = @DISTCHECK_GTEST_CONFIGURE_FLAG@ +DISTCHECK_KEA_SHELL_CONFIGURE_FLAG = @DISTCHECK_KEA_SHELL_CONFIGURE_FLAG@ +DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG = @DISTCHECK_LIBYANGCPP_CONFIGURE_FLAG@ +DISTCHECK_LIBYANG_CONFIGURE_FLAG = @DISTCHECK_LIBYANG_CONFIGURE_FLAG@ +DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG = @DISTCHECK_LOG4CPLUS_CONFIGURE_FLAG@ +DISTCHECK_MYSQL_CONFIGURE_FLAG = @DISTCHECK_MYSQL_CONFIGURE_FLAG@ +DISTCHECK_PERFDHCP_CONFIGURE_FLAG = @DISTCHECK_PERFDHCP_CONFIGURE_FLAG@ +DISTCHECK_PGSQL_CONFIGURE_FLAG = @DISTCHECK_PGSQL_CONFIGURE_FLAG@ +DISTCHECK_PREMIUM_CONFIGURE_FLAG = @DISTCHECK_PREMIUM_CONFIGURE_FLAG@ +DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG = @DISTCHECK_SYSREPOCPP_CONFIGURE_FLAG@ +DISTCHECK_SYSREPO_CONFIGURE_FLAG = @DISTCHECK_SYSREPO_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_NETCONF = @HAVE_NETCONF@ +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@ +LIBYANGCPP_CPPFLAGS = @LIBYANGCPP_CPPFLAGS@ +LIBYANGCPP_INCLUDEDIR = @LIBYANGCPP_INCLUDEDIR@ +LIBYANGCPP_LIBS = @LIBYANGCPP_LIBS@ +LIBYANGCPP_PREFIX = @LIBYANGCPP_PREFIX@ +LIBYANGCPP_VERSION = @LIBYANGCPP_VERSION@ +LIBYANG_CPPFLAGS = @LIBYANG_CPPFLAGS@ +LIBYANG_INCLUDEDIR = @LIBYANG_INCLUDEDIR@ +LIBYANG_LIBS = @LIBYANG_LIBS@ +LIBYANG_PREFIX = @LIBYANG_PREFIX@ +LIBYANG_VERSION = @LIBYANG_VERSION@ +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_PLUGINS_PATH = @SR_PLUGINS_PATH@ +SR_REPO_PATH = @SR_REPO_PATH@ +STRIP = @STRIP@ +SYSREPOCPP_CPPFLAGS = @SYSREPOCPP_CPPFLAGS@ +SYSREPOCPP_INCLUDEDIR = @SYSREPOCPP_INCLUDEDIR@ +SYSREPOCPP_LIBS = @SYSREPOCPP_LIBS@ +SYSREPOCPP_PREFIX = @SYSREPOCPP_PREFIX@ +SYSREPOCPP_VERSION = @SYSREPOCPP_VERSION@ +SYSREPO_CPPFLAGS = @SYSREPO_CPPFLAGS@ +SYSREPO_INCLUDEDIR = @SYSREPO_INCLUDEDIR@ +SYSREPO_LIBS = @SYSREPO_LIBS@ +SYSREPO_PREFIX = @SYSREPO_PREFIX@ +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@ bigint_unittest.cc base32hex_unittest.cc \ +@HAVE_GTEST_TRUE@ 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-bigint_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-bigint_unittest.o: bigint_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-bigint_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-bigint_unittest.Tpo -c -o run_unittests-bigint_unittest.o `test -f 'bigint_unittest.cc' || echo '$(srcdir)/'`bigint_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-bigint_unittest.Tpo $(DEPDIR)/run_unittests-bigint_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='bigint_unittest.cc' object='run_unittests-bigint_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-bigint_unittest.o `test -f 'bigint_unittest.cc' || echo '$(srcdir)/'`bigint_unittest.cc + +run_unittests-bigint_unittest.obj: bigint_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-bigint_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-bigint_unittest.Tpo -c -o run_unittests-bigint_unittest.obj `if test -f 'bigint_unittest.cc'; then $(CYGPATH_W) 'bigint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/bigint_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-bigint_unittest.Tpo $(DEPDIR)/run_unittests-bigint_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='bigint_unittest.cc' object='run_unittests-bigint_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-bigint_unittest.obj `if test -f 'bigint_unittest.cc'; then $(CYGPATH_W) 'bigint_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/bigint_unittest.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-bigint_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-bigint_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/bigint_unittest.cc b/src/lib/util/tests/bigint_unittest.cc new file mode 100644 index 0000000..b811c07 --- /dev/null +++ b/src/lib/util/tests/bigint_unittest.cc @@ -0,0 +1,94 @@ +// Copyright (C) 2023 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 <testutils/gtest_utils.h> +#include <util/bigints.h> + +#include <gtest/gtest.h> + +using namespace isc::util; + +namespace { + +// C++ doesn't allow very big integer literals, so that's why some tests on big +// numbers might appear like they're unnecessarily circumventing a more obvious +// test choice. + +// Checks that int128_t behaves like a signed integer should. +TEST(BigintTest, int128) { + // Check addition with small numbers. + EXPECT_EQ(24, int128_t(16) + int128_t(8)); + + // Check subtraction with small numbers. + EXPECT_EQ(48, int128_t(64) - int128_t(16)); + + // Check multiplication with small numbers. + EXPECT_EQ(8, int128_t(2) * int128_t(4)); + + // Check division with small numbers. + EXPECT_EQ(16, int128_t(64) / int128_t(4)); + + // Check rounded division with small numbers. + EXPECT_EQ(16, int128_t(65) / int128_t(4)); + + // Check that dividing by zero throws. + EXPECT_THROW(int128_t(1) / 0, std::overflow_error); + + // Check that underflowing results in a negative number for int128_t. + EXPECT_EQ(-1, int128_t(0) - 1); + + // Check that UINT64_MAX < INT128_MAX. + EXPECT_LT(uint64_t(0) - 1, int128_t(uint128_t(0) - 1)); + + // Check that int128_t is default-initialized to zero. Not a strict + // requirement, but something that the current implementation ensures. + int128_t i128; + EXPECT_EQ(0, i128); + + // Check that overflowing on big numbers has the correct result. + i128 = int128_t(0) - 1; + EXPECT_EQ(i128 - 1, i128 + i128); +} + +// Checks that uint128_t behaves like an unsigned integer should. +TEST(BigintTest, uint128) { + // Check addition with small numbers. + EXPECT_EQ(24, uint128_t(16) + uint128_t(8)); + + // Check subtraction with small numbers. + EXPECT_EQ(48, uint128_t(64) - uint128_t(16)); + + // Check multiplication with small numbers. + EXPECT_EQ(8, uint128_t(2) * uint128_t(4)); + + // Check division with small numbers. + EXPECT_EQ(16, uint128_t(64) / uint128_t(4)); + + // Check rounded division with small numbers. + EXPECT_EQ(16, uint128_t(65) / uint128_t(4)); + + // Check that dividing by zero throws. + EXPECT_THROW(uint128_t(1) / 0, std::overflow_error); + + // Check that underflowing results in a positive number for uint128_t. + EXPECT_LT(0, uint128_t(0) - 1); + + // Check that UINT64_MAX < UINT128_MAX. + EXPECT_LT(uint64_t(0) - 1, uint128_t(0) - 1); + + // Check that uint128_t is default-initialized to zero. Not a strict + // requirement, but something that the current implementation ensures. + uint128_t u128; + EXPECT_EQ(0, u128); + + // Check that overflowing on big numbers has the correct result. + u128 = uint128_t(0) - 1; + EXPECT_EQ(u128 - 1, u128 + u128); +} + +} // namespace 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 ("ˏO^O\\ˋ?ˊR,", 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 = ("noscape"); + 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ˎscape"); + 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,-bar"); + ASSERT_EQ(2, row0.getValuesCount()); + EXPECT_EQ("bar", row0.readAt(0)); + // Read the second column as-is and escaped + EXPECT_EQ("foo,-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,one,two", 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..acaaf13 --- /dev/null +++ b/src/lib/util/tests/io_utilities_unittest.cc @@ -0,0 +1,160 @@ +// Copyright (C) 2011-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/. + +/// \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 = 0; + 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] = {0, 0, 0, 0, 0, 0, 0, 0}; + + // 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] = {0, 0, 0}; + 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..4d3ae33 --- /dev/null +++ b/src/lib/util/tests/multi_threading_mgr_unittest.cc @@ -0,0 +1,636 @@ +// Copyright (C) 2019-2023 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 Fixture used to reset multi-threading before and after each test. +struct MultiThreadingMgrTest : ::testing::Test { + MultiThreadingMgrTest() { + MultiThreadingMgr::instance().apply(false, 0, 0); + } + ~MultiThreadingMgrTest() { + MultiThreadingMgr::instance().apply(false, 0, 0); + } +}; + +/// @brief Verifies that the default mode is false (MT disabled). +TEST_F(MultiThreadingMgrTest, defaultMode) { + // MT should be disabled + EXPECT_FALSE(MultiThreadingMgr::instance().getMode()); +} + +/// @brief Verifies that the mode setter works. +TEST_F(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_F(MultiThreadingMgrTest, threadPool) { + // get the thread pool + EXPECT_NO_THROW(MultiThreadingMgr::instance().getThreadPool()); +} + +/// @brief Verifies that the thread pool size setter works. +TEST_F(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_F(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_F(MultiThreadingMgrTest, detectThreadCount) { + // detecting thread count should work + EXPECT_NE(MultiThreadingMgr::detectThreadCount(), 0); +} + +/// @brief Verifies that apply settings works. +TEST_F(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_F(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_F(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..a506b6b --- /dev/null +++ b/src/lib/util/tests/stopwatch_unittest.cc @@ -0,0 +1,307 @@ +// Copyright (C) 2015-2023 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)); + + duration = milliseconds(2100); + EXPECT_EQ("2.10 s", StopwatchImpl::logFormat(duration)); + + duration = milliseconds(3123); + EXPECT_EQ("3.12 s", 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..912b40f --- /dev/null +++ b/src/lib/util/tests/strutil_unittest.cc @@ -0,0 +1,642 @@ +// Copyright (C) 2011-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/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("0x01 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()); +} + +} |