diff options
Diffstat (limited to 'src/lib/cc/tests')
-rw-r--r-- | src/lib/cc/tests/Makefile.am | 40 | ||||
-rw-r--r-- | src/lib/cc/tests/Makefile.in | 1071 | ||||
-rw-r--r-- | src/lib/cc/tests/command_interpreter_unittests.cc | 249 | ||||
-rw-r--r-- | src/lib/cc/tests/data_file_unittests.cc | 98 | ||||
-rw-r--r-- | src/lib/cc/tests/data_unittests.cc | 2232 | ||||
-rw-r--r-- | src/lib/cc/tests/element_value_unittests.cc | 43 | ||||
-rw-r--r-- | src/lib/cc/tests/json_feed_unittests.cc | 453 | ||||
-rw-r--r-- | src/lib/cc/tests/run_unittests.cc | 20 | ||||
-rw-r--r-- | src/lib/cc/tests/server_tag_unittest.cc | 97 | ||||
-rw-r--r-- | src/lib/cc/tests/simple_parser_unittest.cc | 364 | ||||
-rw-r--r-- | src/lib/cc/tests/stamped_element_unittest.cc | 132 | ||||
-rw-r--r-- | src/lib/cc/tests/stamped_value_unittest.cc | 175 | ||||
-rw-r--r-- | src/lib/cc/tests/user_context_unittests.cc | 132 |
13 files changed, 5106 insertions, 0 deletions
diff --git a/src/lib/cc/tests/Makefile.am b/src/lib/cc/tests/Makefile.am new file mode 100644 index 0000000..38f6e7a --- /dev/null +++ b/src/lib/cc/tests/Makefile.am @@ -0,0 +1,40 @@ +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +if USE_STATIC_LINK +AM_LDFLAGS = -static +endif + +CLEANFILES = *.gcno *.gcda + +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) + +TESTS = +if HAVE_GTEST +TESTS += run_unittests +run_unittests_SOURCES = command_interpreter_unittests.cc +run_unittests_SOURCES += data_unittests.cc +run_unittests_SOURCES += data_file_unittests.cc +run_unittests_SOURCES += element_value_unittests.cc +run_unittests_SOURCES += json_feed_unittests.cc +run_unittests_SOURCES += server_tag_unittest.cc +run_unittests_SOURCES += simple_parser_unittest.cc +run_unittests_SOURCES += stamped_element_unittest.cc +run_unittests_SOURCES += stamped_value_unittest.cc +run_unittests_SOURCES += user_context_unittests.cc +run_unittests_SOURCES += run_unittests.cc +run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) + +run_unittests_LDADD = $(top_builddir)/src/lib/cc/libkea-cc.la +run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la +run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la +run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.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 += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) $(GTEST_LDADD) + +endif + +noinst_PROGRAMS = $(TESTS) diff --git a/src/lib/cc/tests/Makefile.in b/src/lib/cc/tests/Makefile.in new file mode 100644 index 0000000..5fb8c66 --- /dev/null +++ b/src/lib/cc/tests/Makefile.in @@ -0,0 +1,1071 @@ +# 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/cc/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 = command_interpreter_unittests.cc \ + data_unittests.cc data_file_unittests.cc \ + element_value_unittests.cc json_feed_unittests.cc \ + server_tag_unittest.cc simple_parser_unittest.cc \ + stamped_element_unittest.cc stamped_value_unittest.cc \ + user_context_unittests.cc run_unittests.cc +@HAVE_GTEST_TRUE@am_run_unittests_OBJECTS = run_unittests-command_interpreter_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-data_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-data_file_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-element_value_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-json_feed_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-server_tag_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-simple_parser_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-stamped_element_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-stamped_value_unittest.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-user_context_unittests.$(OBJEXT) \ +@HAVE_GTEST_TRUE@ run_unittests-run_unittests.$(OBJEXT) +run_unittests_OBJECTS = $(am_run_unittests_OBJECTS) +am__DEPENDENCIES_1 = +@HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.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__DEPENDENCIES_1) \ +@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-command_interpreter_unittests.Po \ + ./$(DEPDIR)/run_unittests-data_file_unittests.Po \ + ./$(DEPDIR)/run_unittests-data_unittests.Po \ + ./$(DEPDIR)/run_unittests-element_value_unittests.Po \ + ./$(DEPDIR)/run_unittests-json_feed_unittests.Po \ + ./$(DEPDIR)/run_unittests-run_unittests.Po \ + ./$(DEPDIR)/run_unittests-server_tag_unittest.Po \ + ./$(DEPDIR)/run_unittests-simple_parser_unittest.Po \ + ./$(DEPDIR)/run_unittests-stamped_element_unittest.Po \ + ./$(DEPDIR)/run_unittests-stamped_value_unittest.Po \ + ./$(DEPDIR)/run_unittests-user_context_unittests.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 = +SOURCES = $(run_unittests_SOURCES) +DIST_SOURCES = $(am__run_unittests_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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; \ +} +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +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@ +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib \ + $(BOOST_INCLUDES) +AM_CXXFLAGS = $(KEA_CXXFLAGS) +@USE_STATIC_LINK_TRUE@AM_LDFLAGS = -static +CLEANFILES = *.gcno *.gcda +TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND) +@HAVE_GTEST_TRUE@run_unittests_SOURCES = \ +@HAVE_GTEST_TRUE@ command_interpreter_unittests.cc \ +@HAVE_GTEST_TRUE@ data_unittests.cc data_file_unittests.cc \ +@HAVE_GTEST_TRUE@ element_value_unittests.cc \ +@HAVE_GTEST_TRUE@ json_feed_unittests.cc server_tag_unittest.cc \ +@HAVE_GTEST_TRUE@ simple_parser_unittest.cc \ +@HAVE_GTEST_TRUE@ stamped_element_unittest.cc \ +@HAVE_GTEST_TRUE@ stamped_value_unittest.cc \ +@HAVE_GTEST_TRUE@ user_context_unittests.cc run_unittests.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 = \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/cc/libkea-cc.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/asiolink/libkea-asiolink.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/log/libkea-log.la \ +@HAVE_GTEST_TRUE@ $(top_builddir)/src/lib/util/unittests/libutil_unittests.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@ $(LOG4CPLUS_LIBS) $(BOOST_LIBS) \ +@HAVE_GTEST_TRUE@ $(GTEST_LDADD) +all: all-am + +.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/cc/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib/cc/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-command_interpreter_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-data_file_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-data_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-element_value_unittests.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-json_feed_unittests.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-server_tag_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-simple_parser_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-stamped_element_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-stamped_value_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-user_context_unittests.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-command_interpreter_unittests.o: command_interpreter_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_interpreter_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-command_interpreter_unittests.Tpo -c -o run_unittests-command_interpreter_unittests.o `test -f 'command_interpreter_unittests.cc' || echo '$(srcdir)/'`command_interpreter_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_interpreter_unittests.Tpo $(DEPDIR)/run_unittests-command_interpreter_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_interpreter_unittests.cc' object='run_unittests-command_interpreter_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-command_interpreter_unittests.o `test -f 'command_interpreter_unittests.cc' || echo '$(srcdir)/'`command_interpreter_unittests.cc + +run_unittests-command_interpreter_unittests.obj: command_interpreter_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-command_interpreter_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-command_interpreter_unittests.Tpo -c -o run_unittests-command_interpreter_unittests.obj `if test -f 'command_interpreter_unittests.cc'; then $(CYGPATH_W) 'command_interpreter_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_interpreter_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-command_interpreter_unittests.Tpo $(DEPDIR)/run_unittests-command_interpreter_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='command_interpreter_unittests.cc' object='run_unittests-command_interpreter_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-command_interpreter_unittests.obj `if test -f 'command_interpreter_unittests.cc'; then $(CYGPATH_W) 'command_interpreter_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/command_interpreter_unittests.cc'; fi` + +run_unittests-data_unittests.o: data_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-data_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-data_unittests.Tpo -c -o run_unittests-data_unittests.o `test -f 'data_unittests.cc' || echo '$(srcdir)/'`data_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-data_unittests.Tpo $(DEPDIR)/run_unittests-data_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='data_unittests.cc' object='run_unittests-data_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-data_unittests.o `test -f 'data_unittests.cc' || echo '$(srcdir)/'`data_unittests.cc + +run_unittests-data_unittests.obj: data_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-data_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-data_unittests.Tpo -c -o run_unittests-data_unittests.obj `if test -f 'data_unittests.cc'; then $(CYGPATH_W) 'data_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/data_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-data_unittests.Tpo $(DEPDIR)/run_unittests-data_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='data_unittests.cc' object='run_unittests-data_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-data_unittests.obj `if test -f 'data_unittests.cc'; then $(CYGPATH_W) 'data_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/data_unittests.cc'; fi` + +run_unittests-data_file_unittests.o: data_file_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-data_file_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-data_file_unittests.Tpo -c -o run_unittests-data_file_unittests.o `test -f 'data_file_unittests.cc' || echo '$(srcdir)/'`data_file_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-data_file_unittests.Tpo $(DEPDIR)/run_unittests-data_file_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='data_file_unittests.cc' object='run_unittests-data_file_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-data_file_unittests.o `test -f 'data_file_unittests.cc' || echo '$(srcdir)/'`data_file_unittests.cc + +run_unittests-data_file_unittests.obj: data_file_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-data_file_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-data_file_unittests.Tpo -c -o run_unittests-data_file_unittests.obj `if test -f 'data_file_unittests.cc'; then $(CYGPATH_W) 'data_file_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/data_file_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-data_file_unittests.Tpo $(DEPDIR)/run_unittests-data_file_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='data_file_unittests.cc' object='run_unittests-data_file_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-data_file_unittests.obj `if test -f 'data_file_unittests.cc'; then $(CYGPATH_W) 'data_file_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/data_file_unittests.cc'; fi` + +run_unittests-element_value_unittests.o: element_value_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-element_value_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-element_value_unittests.Tpo -c -o run_unittests-element_value_unittests.o `test -f 'element_value_unittests.cc' || echo '$(srcdir)/'`element_value_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-element_value_unittests.Tpo $(DEPDIR)/run_unittests-element_value_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='element_value_unittests.cc' object='run_unittests-element_value_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-element_value_unittests.o `test -f 'element_value_unittests.cc' || echo '$(srcdir)/'`element_value_unittests.cc + +run_unittests-element_value_unittests.obj: element_value_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-element_value_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-element_value_unittests.Tpo -c -o run_unittests-element_value_unittests.obj `if test -f 'element_value_unittests.cc'; then $(CYGPATH_W) 'element_value_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/element_value_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-element_value_unittests.Tpo $(DEPDIR)/run_unittests-element_value_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='element_value_unittests.cc' object='run_unittests-element_value_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-element_value_unittests.obj `if test -f 'element_value_unittests.cc'; then $(CYGPATH_W) 'element_value_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/element_value_unittests.cc'; fi` + +run_unittests-json_feed_unittests.o: json_feed_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-json_feed_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-json_feed_unittests.Tpo -c -o run_unittests-json_feed_unittests.o `test -f 'json_feed_unittests.cc' || echo '$(srcdir)/'`json_feed_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-json_feed_unittests.Tpo $(DEPDIR)/run_unittests-json_feed_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_feed_unittests.cc' object='run_unittests-json_feed_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-json_feed_unittests.o `test -f 'json_feed_unittests.cc' || echo '$(srcdir)/'`json_feed_unittests.cc + +run_unittests-json_feed_unittests.obj: json_feed_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-json_feed_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-json_feed_unittests.Tpo -c -o run_unittests-json_feed_unittests.obj `if test -f 'json_feed_unittests.cc'; then $(CYGPATH_W) 'json_feed_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/json_feed_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-json_feed_unittests.Tpo $(DEPDIR)/run_unittests-json_feed_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_feed_unittests.cc' object='run_unittests-json_feed_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-json_feed_unittests.obj `if test -f 'json_feed_unittests.cc'; then $(CYGPATH_W) 'json_feed_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/json_feed_unittests.cc'; fi` + +run_unittests-server_tag_unittest.o: server_tag_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-server_tag_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-server_tag_unittest.Tpo -c -o run_unittests-server_tag_unittest.o `test -f 'server_tag_unittest.cc' || echo '$(srcdir)/'`server_tag_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-server_tag_unittest.Tpo $(DEPDIR)/run_unittests-server_tag_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='server_tag_unittest.cc' object='run_unittests-server_tag_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-server_tag_unittest.o `test -f 'server_tag_unittest.cc' || echo '$(srcdir)/'`server_tag_unittest.cc + +run_unittests-server_tag_unittest.obj: server_tag_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-server_tag_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-server_tag_unittest.Tpo -c -o run_unittests-server_tag_unittest.obj `if test -f 'server_tag_unittest.cc'; then $(CYGPATH_W) 'server_tag_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/server_tag_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-server_tag_unittest.Tpo $(DEPDIR)/run_unittests-server_tag_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='server_tag_unittest.cc' object='run_unittests-server_tag_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-server_tag_unittest.obj `if test -f 'server_tag_unittest.cc'; then $(CYGPATH_W) 'server_tag_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/server_tag_unittest.cc'; fi` + +run_unittests-simple_parser_unittest.o: simple_parser_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-simple_parser_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-simple_parser_unittest.Tpo -c -o run_unittests-simple_parser_unittest.o `test -f 'simple_parser_unittest.cc' || echo '$(srcdir)/'`simple_parser_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-simple_parser_unittest.Tpo $(DEPDIR)/run_unittests-simple_parser_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='simple_parser_unittest.cc' object='run_unittests-simple_parser_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-simple_parser_unittest.o `test -f 'simple_parser_unittest.cc' || echo '$(srcdir)/'`simple_parser_unittest.cc + +run_unittests-simple_parser_unittest.obj: simple_parser_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-simple_parser_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-simple_parser_unittest.Tpo -c -o run_unittests-simple_parser_unittest.obj `if test -f 'simple_parser_unittest.cc'; then $(CYGPATH_W) 'simple_parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/simple_parser_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-simple_parser_unittest.Tpo $(DEPDIR)/run_unittests-simple_parser_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='simple_parser_unittest.cc' object='run_unittests-simple_parser_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-simple_parser_unittest.obj `if test -f 'simple_parser_unittest.cc'; then $(CYGPATH_W) 'simple_parser_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/simple_parser_unittest.cc'; fi` + +run_unittests-stamped_element_unittest.o: stamped_element_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stamped_element_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-stamped_element_unittest.Tpo -c -o run_unittests-stamped_element_unittest.o `test -f 'stamped_element_unittest.cc' || echo '$(srcdir)/'`stamped_element_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stamped_element_unittest.Tpo $(DEPDIR)/run_unittests-stamped_element_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stamped_element_unittest.cc' object='run_unittests-stamped_element_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-stamped_element_unittest.o `test -f 'stamped_element_unittest.cc' || echo '$(srcdir)/'`stamped_element_unittest.cc + +run_unittests-stamped_element_unittest.obj: stamped_element_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stamped_element_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-stamped_element_unittest.Tpo -c -o run_unittests-stamped_element_unittest.obj `if test -f 'stamped_element_unittest.cc'; then $(CYGPATH_W) 'stamped_element_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stamped_element_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stamped_element_unittest.Tpo $(DEPDIR)/run_unittests-stamped_element_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stamped_element_unittest.cc' object='run_unittests-stamped_element_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-stamped_element_unittest.obj `if test -f 'stamped_element_unittest.cc'; then $(CYGPATH_W) 'stamped_element_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stamped_element_unittest.cc'; fi` + +run_unittests-stamped_value_unittest.o: stamped_value_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stamped_value_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-stamped_value_unittest.Tpo -c -o run_unittests-stamped_value_unittest.o `test -f 'stamped_value_unittest.cc' || echo '$(srcdir)/'`stamped_value_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stamped_value_unittest.Tpo $(DEPDIR)/run_unittests-stamped_value_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stamped_value_unittest.cc' object='run_unittests-stamped_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-stamped_value_unittest.o `test -f 'stamped_value_unittest.cc' || echo '$(srcdir)/'`stamped_value_unittest.cc + +run_unittests-stamped_value_unittest.obj: stamped_value_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-stamped_value_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-stamped_value_unittest.Tpo -c -o run_unittests-stamped_value_unittest.obj `if test -f 'stamped_value_unittest.cc'; then $(CYGPATH_W) 'stamped_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stamped_value_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-stamped_value_unittest.Tpo $(DEPDIR)/run_unittests-stamped_value_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stamped_value_unittest.cc' object='run_unittests-stamped_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-stamped_value_unittest.obj `if test -f 'stamped_value_unittest.cc'; then $(CYGPATH_W) 'stamped_value_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/stamped_value_unittest.cc'; fi` + +run_unittests-user_context_unittests.o: user_context_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-user_context_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-user_context_unittests.Tpo -c -o run_unittests-user_context_unittests.o `test -f 'user_context_unittests.cc' || echo '$(srcdir)/'`user_context_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-user_context_unittests.Tpo $(DEPDIR)/run_unittests-user_context_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='user_context_unittests.cc' object='run_unittests-user_context_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-user_context_unittests.o `test -f 'user_context_unittests.cc' || echo '$(srcdir)/'`user_context_unittests.cc + +run_unittests-user_context_unittests.obj: user_context_unittests.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-user_context_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-user_context_unittests.Tpo -c -o run_unittests-user_context_unittests.obj `if test -f 'user_context_unittests.cc'; then $(CYGPATH_W) 'user_context_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/user_context_unittests.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/run_unittests-user_context_unittests.Tpo $(DEPDIR)/run_unittests-user_context_unittests.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='user_context_unittests.cc' object='run_unittests-user_context_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-user_context_unittests.obj `if test -f 'user_context_unittests.cc'; then $(CYGPATH_W) 'user_context_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/user_context_unittests.cc'; fi` + +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` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(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-am + +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-am + +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 +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +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-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/run_unittests-command_interpreter_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-data_file_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-data_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-element_value_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-json_feed_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-server_tag_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-simple_parser_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-stamped_element_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-stamped_value_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-user_context_unittests.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/run_unittests-command_interpreter_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-data_file_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-data_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-element_value_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-json_feed_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-run_unittests.Po + -rm -f ./$(DEPDIR)/run_unittests-server_tag_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-simple_parser_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-stamped_element_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-stamped_value_unittest.Po + -rm -f ./$(DEPDIR)/run_unittests-user_context_unittests.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: 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 \ + 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/cc/tests/command_interpreter_unittests.cc b/src/lib/cc/tests/command_interpreter_unittests.cc new file mode 100644 index 0000000..8738b92 --- /dev/null +++ b/src/lib/cc/tests/command_interpreter_unittests.cc @@ -0,0 +1,249 @@ +// Copyright (C) 2009-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 <gtest/gtest.h> + +#include <cc/command_interpreter.h> +#include <config/tests/data_def_unittests_config.h> +#include <log/logger_name.h> + +#include <boost/scoped_ptr.hpp> + +#include <fstream> + +using namespace isc::data; +using namespace isc::config; +using namespace std; + +namespace { + + +/// @brief Convenience method for creating elements from JSON string +/// +/// @param str string to be converted +/// @return Element structure +ElementPtr +el(const std::string& str) { + return (Element::fromJSON(str)); +} + +// This test verifies that that createAnswer method is able to generate +// various answers. +TEST(CommandInterpreterTest, createAnswer) { + ConstElementPtr answer; + + // By default the answer is a successful one. + answer = createAnswer(); + EXPECT_EQ("{ \"result\": 0 }", answer->str()); + + // Let's check if we can generate an error. + answer = createAnswer(CONTROL_RESULT_ERROR, "error"); + EXPECT_EQ("{ \"result\": 1, \"text\": \"error\" }", answer->str()); + + // This is expected to throw. When status code is non-zero (indicating error), + // textual explanation is mandatory. + EXPECT_THROW(createAnswer(CONTROL_RESULT_ERROR, ElementPtr()), CtrlChannelError); + EXPECT_THROW(createAnswer(CONTROL_RESULT_ERROR, Element::create(1)), CtrlChannelError); + + // Let's check if answer can be generate with some data in it. + ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]"); + answer = createAnswer(CONTROL_RESULT_SUCCESS, arg); + EXPECT_EQ("{ \"arguments\": [ \"just\", \"some\", \"data\" ], \"result\": 0 }", + answer->str()); +} + +// This test checks whether parseAnswer is able to handle good and malformed +// answers. +TEST(CommandInterpreterTest, parseAnswer) { + ConstElementPtr answer; + ConstElementPtr arg; + int rcode; + + EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("1")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("[]")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("{ }")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 0 ] }")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CtrlChannelError); + EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CtrlChannelError); + + answer = el("{ \"result\": 0 }"); + arg = parseAnswer(rcode, answer); + EXPECT_EQ(0, rcode); + EXPECT_TRUE(isNull(arg)); + + answer = el("{ \"result\": 3, \"text\": \"error\", \"arguments\": [ \"some\", \"data\" ] }"); + arg = parseAnswer(rcode, answer); + ASSERT_TRUE(arg); + EXPECT_EQ(3, rcode); + EXPECT_EQ("[ \"some\", \"data\" ]", arg->str()); +} + +// Checks if parseAnswerText can return the text +TEST(CommandInterpreterTest, parseAnswerText) { + ConstElementPtr answer; + ConstElementPtr arg; + int rcode; + + answer = el("{ \"result\": 5, \"text\": \"error\", \"arguments\": [ \"some\", \"data\" ] }"); + arg = parseAnswerText(rcode, answer); + ASSERT_TRUE(arg); + EXPECT_EQ(5, rcode); + EXPECT_EQ("error", arg->stringValue()); +} + +// This checks whether we can convert an answer to easily printable form. +TEST(CommandInterpreterTest, answerToText) { + ConstElementPtr answer; + + // Doing jolly good here. + answer = el("{ \"result\": 0 }"); + EXPECT_EQ("success(0)", answerToText(answer)); + + // Sometimes things don't go according to plan. + answer = el("{ \"result\": 1, \"text\": \"ho lee fuk sum ting wong\" }"); + EXPECT_EQ("failure(1), text=ho lee fuk sum ting wong", answerToText(answer)); +} + +// This test checks whether createCommand function is able to create commands +// with and without parameters. +TEST(CommandInterpreterTest, createCommand) { + ConstElementPtr command; + ConstElementPtr arg; + string service; + + command = createCommand("my_command"); + ASSERT_EQ("{ \"command\": \"my_command\" }", command->str()); + + arg = el("1"); + command = createCommand("my_command", arg); + ASSERT_EQ("{ \"arguments\": 1, \"command\": \"my_command\" }", + command->str()); + + arg = el("[ \"a\", \"b\" ]"); + command = createCommand("my_cmd", arg); + ASSERT_EQ("{ \"arguments\": [ \"a\", \"b\" ], \"command\": \"my_cmd\" }", + command->str()); + + arg = el("{ \"a\": \"map\" }"); + command = createCommand("foo", arg); + ASSERT_EQ("{ \"arguments\": { \"a\": \"map\" }, \"command\": \"foo\" }", + command->str()); + + command = createCommand("my_command", "my_service"); + ASSERT_EQ("{ \"command\": \"my_command\", " + "\"service\": [ \"my_service\" ] }", + command->str()); + + arg = el("1"); + command = createCommand("my_command", arg, "my_service"); + ASSERT_EQ("{ \"arguments\": 1, \"command\": \"my_command\", " + "\"service\": [ \"my_service\" ] }", + command->str()); + + arg = el("[ \"a\", \"b\" ]"); + command = createCommand("my_cmd", arg, "my_server"); + ASSERT_EQ("{ \"arguments\": [ \"a\", \"b\" ], " + "\"command\": \"my_cmd\", " + "\"service\": [ \"my_server\" ] }", + command->str()); + + arg = el("{ \"a\": \"map\" }"); + command = createCommand("foo", arg, "bar"); + ASSERT_EQ("{ \"arguments\": { \"a\": \"map\" }, " + "\"command\": \"foo\", " + "\"service\": [ \"bar\" ] }", + command->str()); +} + +// This test checks whether parseCommand function is able to parse various valid +// and malformed commands. +TEST(CommandInterpreterTest, parseCommand) { + ConstElementPtr arg; + std::string cmd; + + // should throw + EXPECT_THROW(parseCommand(arg, ElementPtr()), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("1")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ }")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CtrlChannelError); + EXPECT_THROW(parseCommand(arg, el("{ \"command\": \"my_command\", " + "\"unknown\": \"xyz\" }")), CtrlChannelError); + + cmd = parseCommand(arg, el("{ \"command\": \"my_command\" }")); + EXPECT_EQ("my_command", cmd); + EXPECT_FALSE(arg); + + // Include "service" to verify that it is not rejected. + cmd = parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": 1, " + " \"service\": [ \"dhcp4\" ] }")); + ASSERT_TRUE(arg); + EXPECT_EQ("my_command", cmd); + EXPECT_EQ("1", arg->str()); + + parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": " + "[ \"some\", \"argument\", \"list\" ] }")); + EXPECT_EQ("my_command", cmd); + ASSERT_TRUE(arg); + EXPECT_EQ("[ \"some\", \"argument\", \"list\" ]", arg->str()); + +} + +// This test checks whether parseCommandWithArgs function is able to parse +// various valid and malformed commands. +TEST(CommandInterpreterTest, parseCommandWithArgs) { + ConstElementPtr arg; + std::string cmd; + + // Arguments are required. + EXPECT_THROW(parseCommandWithArgs(arg, el("{ \"command\": \"my_command\" }")), + CtrlChannelError); + + // Arguments must be a map. + EXPECT_THROW(parseCommandWithArgs(arg, el("{ \"command\": \"my_command\", " + "\"arguments\": [ 1, 2, 3 ] }")), + CtrlChannelError); + + // Arguments must not be empty. + EXPECT_THROW(parseCommandWithArgs(arg, el("{ \"command\": \"my_command\", " + "\"arguments\": { } }")), + CtrlChannelError); + + // Command with unsupported parameter is rejected. + EXPECT_THROW(parseCommandWithArgs(arg, el("{ \"command\": \"my_command\", " + " \"arguments\": { \"arg1\": \"value1\" }, " + " \"unsupported\": 1 }")), + CtrlChannelError); + + + // Specifying arguments in non empty map should be successful. + EXPECT_NO_THROW( + cmd = parseCommandWithArgs(arg, el("{ \"command\": \"my_command\", " + " \"arguments\": { \"arg1\": \"value1\" } }")) + ); + ASSERT_TRUE(arg); + ASSERT_EQ(Element::map, arg->getType()); + auto arg1 = arg->get("arg1"); + ASSERT_TRUE(arg1); + ASSERT_EQ(Element::string, arg1->getType()); + EXPECT_EQ("value1", arg1->stringValue()); + EXPECT_EQ("my_command", cmd); + + // The "service" parameter should be allowed. + EXPECT_NO_THROW(parseCommandWithArgs(arg, el("{ \"command\": \"my_command\", " + " \"service\": [ \"dhcp4\" ], " + " \"arguments\": { \"arg1\": \"value1\" } }")) + ); + +} + +} diff --git a/src/lib/cc/tests/data_file_unittests.cc b/src/lib/cc/tests/data_file_unittests.cc new file mode 100644 index 0000000..a7f1b8d --- /dev/null +++ b/src/lib/cc/tests/data_file_unittests.cc @@ -0,0 +1,98 @@ +// 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 <exceptions/exceptions.h> +#include <gtest/gtest.h> +#include <cc/data.h> +#include <fstream> + +using namespace isc; +using namespace isc::data; + +namespace { + +/// @brief Test class for testing Daemon class +class DataFileTest : public ::testing::Test { +public: + + /// @brief writes specified text to a file + /// + /// That is an auxiliary function used in fileRead() tests. + /// + /// @param content text to be written to disk + void writeFile(const std::string& content) { + // Write sample content to disk + static_cast<void>(remove(TEMP_FILE)); + std::ofstream write_me(TEMP_FILE); + EXPECT_TRUE(write_me.is_open()); + write_me << content; + write_me.close(); + } + + /// destructor + ~DataFileTest() { + static_cast<void>(remove(TEMP_FILE)); + } + + /// Name of the temporary file + static const char* TEMP_FILE; +}; + +/// Temporary file name used in some tests +const char* DataFileTest::TEMP_FILE="temp-file.json"; + +// Test checks whether a text file can be read from disk. +TEST_F(DataFileTest, readFileMultiline) { + + const char* no_endline = "{ \"abc\": 123 }"; + const char* with_endline = "{\n \"abc\":\n 123\n }\n"; + + // That's what we expect + ElementPtr exp = Element::fromJSON(no_endline); + + // Write sample content to disk + writeFile(no_endline); + + // Check that the read content is correct + EXPECT_TRUE(exp->equals(*Element::fromJSONFile(TEMP_FILE))); + + // Write sample content to disk + writeFile(with_endline); + + // Check that the read content is correct + EXPECT_TRUE(exp->equals(*Element::fromJSONFile(TEMP_FILE))); +} + +// Test checks whether comments in file are ignored as expected. +TEST_F(DataFileTest, readFileComments) { + const char* commented_content = "# This is a comment\n" + "{ \"abc\":\n" + "# a comment comment\n" + "1 }\n"; + + // That's what we expect + ElementPtr exp = Element::fromJSON("{ \"abc\": 1 }"); + + // Write sample content to disk + writeFile(commented_content); + + // Check that the read will fail (without comment elimination) + EXPECT_THROW(Element::fromJSONFile(TEMP_FILE), JSONError); + + // Check that the read content is correct (with comment elimination) + EXPECT_NO_THROW(Element::fromJSONFile(TEMP_FILE, true)); + EXPECT_TRUE(exp->equals(*Element::fromJSONFile(TEMP_FILE, true))); +} + +// This test checks that missing file will generate an exception. +TEST_F(DataFileTest, readFileError) { + + // Check that the read content is correct + EXPECT_THROW(Element::fromJSONFile("no-such-file.txt"), isc::InvalidOperation); +} + +}; diff --git a/src/lib/cc/tests/data_unittests.cc b/src/lib/cc/tests/data_unittests.cc new file mode 100644 index 0000000..ed23c45 --- /dev/null +++ b/src/lib/cc/tests/data_unittests.cc @@ -0,0 +1,2232 @@ +// Copyright (C) 2009-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 <gtest/gtest.h> +#include <boost/foreach.hpp> +#include <boost/pointer_cast.hpp> +#include <boost/assign/std/vector.hpp> +#include <climits> + +#include <cc/data.h> +#include <util/unittests/check_valgrind.h> + +using namespace isc::data; + +#include <sstream> +#include <iostream> +using std::oct; +#include <iomanip> +using std::setfill; +using std::setw; +using std::string; + +namespace { + +TEST(Position, str) { + Element::Position position("kea.conf", 30, 20); + EXPECT_EQ("kea.conf:30:20", position.str()); + + Element::Position position2("another.conf", 123, 24); + EXPECT_EQ("another.conf:123:24", position2.str()); +} + +TEST(Element, type) { + // this tests checks whether the getType() function returns the + // correct type + IntElement int_el = IntElement(1); + EXPECT_EQ(int_el.getType(), Element::integer); + DoubleElement double_el = DoubleElement(1.0); + EXPECT_EQ(double_el.getType(), Element::real); + BoolElement bool_el = BoolElement(true); + EXPECT_EQ(bool_el.getType(), Element::boolean); + StringElement str_el = StringElement("foo"); + EXPECT_EQ(str_el.getType(), Element::string); + ListElement list_el = ListElement(); + EXPECT_EQ(list_el.getType(), Element::list); + MapElement map_el = MapElement(); + EXPECT_EQ(map_el.getType(), Element::map); + +} + +TEST(Element, TypeNameConversion) { + EXPECT_EQ(Element::integer, Element::nameToType("integer")); + EXPECT_EQ(Element::bigint, Element::nameToType("bigint")); + EXPECT_EQ(Element::real, Element::nameToType("real")); + EXPECT_EQ(Element::boolean, Element::nameToType("boolean")); + EXPECT_EQ(Element::string, Element::nameToType("string")); + EXPECT_EQ(Element::list, Element::nameToType("list")); + EXPECT_EQ(Element::map, Element::nameToType("map")); + EXPECT_EQ(Element::null, Element::nameToType("null")); + EXPECT_EQ(Element::any, Element::nameToType("any")); + EXPECT_THROW(Element::nameToType("somethingunknown"), TypeError); + + EXPECT_EQ("integer", Element::typeToName(Element::integer)); + EXPECT_EQ("bigint", Element::typeToName(Element::bigint)); + EXPECT_EQ("real", Element::typeToName(Element::real)); + EXPECT_EQ("boolean", Element::typeToName(Element::boolean)); + EXPECT_EQ("string", Element::typeToName(Element::string)); + EXPECT_EQ("list", Element::typeToName(Element::list)); + EXPECT_EQ("map", Element::typeToName(Element::map)); + EXPECT_EQ("null", Element::typeToName(Element::null)); + EXPECT_EQ("any", Element::typeToName(Element::any)); + EXPECT_EQ("unknown", Element::typeToName(static_cast<Element::types>(123))); +} + +TEST(Element, from_and_to_json) { + // a set of inputs that are the same when converted to json and + // back to a string (tests for inputs that have equivalent, but + // different string representations when converted back are below) + ConstElementPtr el; + std::vector<std::string> sv; + + sv.push_back("12"); + sv.push_back("1.1"); + sv.push_back("true"); + sv.push_back("false"); + sv.push_back("\"asdf\""); + sv.push_back("null"); + sv.push_back("[ 1, 2, 3, 4 ]"); + sv.push_back("{ \"name\": \"foo\", \"value\": 56176 }"); + sv.push_back("[ { \"a\": 1, \"b\": \"c\" }, { \"a\": 2, \"b\": \"d\" } ]"); + sv.push_back("8.23"); + sv.push_back("123.456"); + sv.push_back("null"); + sv.push_back("-1"); + sv.push_back("-1.234"); + sv.push_back("-123.456"); + // We should confirm that our string handling is 8-bit clean. + // At one point we were using char-length data and comparing to EOF, + // which means that character '\xFF' would not parse properly. + sv.push_back("\"\\u00ff\""); + + BOOST_FOREACH(const std::string& s, sv) { + // Test two types of fromJSON(): with string and istream. + for (unsigned i = 0; i < 2; ++i) { + // test << operator, which uses Element::str() + if (i == 0) { + el = Element::fromJSON(s); + } else { + std::istringstream iss(s); + el = Element::fromJSON(iss); + } + std::ostringstream stream; + stream << *el; + EXPECT_EQ(s, stream.str()); + + // test toWire(ostream), which should also be the same now + std::ostringstream wire_stream; + el->toWire(wire_stream); + EXPECT_EQ(s, wire_stream.str()); + } + } + + // some parse errors + try { + Element::fromJSON("{1}"); + } catch (const isc::data::JSONError& pe) { + std::string s = std::string(pe.what()); + EXPECT_EQ("String expected in <string>:1:3", s); + } + + sv.clear(); + sv.push_back("{1}"); + //ElementPtr ep = Element::fromJSON("\"aaa\nbbb\"err"); + //std::cout << ep << std::endl; + sv.push_back("\n\nTrue"); + sv.push_back("\n\ntru"); + sv.push_back("{ \n \"aaa\nbbb\"err:"); + sv.push_back("{ \t\n \"aaa\nbbb\"\t\n\n:\n true, \"\\\""); + sv.push_back("{ \"a\": None}"); + sv.push_back(""); + sv.push_back("NULL"); + sv.push_back("nul"); + sv.push_back("hello\"foobar\""); + sv.push_back("\"foobar\"hello"); + sv.push_back("[]hello"); + sv.push_back("{}hello"); + // String not delimited correctly + sv.push_back("\"hello"); + sv.push_back("hello\""); + // Bad unicode + sv.push_back("\"\\u123\""); + sv.push_back("\"\\u1234\""); + sv.push_back("\"\\u0123\""); + sv.push_back("\"\\u00ag\""); + sv.push_back("\"\\u00BH\""); + + BOOST_FOREACH(std::string s, sv) { + EXPECT_THROW(el = Element::fromJSON(s), isc::data::JSONError); + } + + // some json specific format tests, here the str() output is + // different from the string input + // +100 is incorrect according to the ECMA 404 JSON standard. + // Keeping it as it will be reversed. + // EXPECT_EQ("100", Element::fromJSON("+100")->str()); + EXPECT_EQ("100.0", Element::fromJSON("1e2")->str()); + EXPECT_EQ("100.0", Element::fromJSON("+1e2")->str()); + EXPECT_EQ("-100.0", Element::fromJSON("-1e2")->str()); + + EXPECT_NO_THROW({ + EXPECT_EQ("9223372036854775807", Element::fromJSON("9223372036854775807")->str()); + }); + EXPECT_NO_THROW({ + EXPECT_EQ("-9223372036854775808", Element::fromJSON("-9223372036854775808")->str()); + }); + EXPECT_THROW({ + EXPECT_NE("9223372036854775808", Element::fromJSON("9223372036854775808")->str()); + }, JSONError); + + EXPECT_EQ("0.01", Element::fromJSON("1e-2")->str()); + EXPECT_EQ("0.01", Element::fromJSON(".01")->str()); + EXPECT_EQ("-0.01", Element::fromJSON("-1e-2")->str()); + EXPECT_EQ("1.2", Element::fromJSON("1.2")->str()); + EXPECT_EQ("1.0", Element::fromJSON("1.0")->str()); + EXPECT_EQ("120.0", Element::fromJSON("1.2e2")->str()); + EXPECT_EQ("100.0", Element::fromJSON("1.0e2")->str()); + EXPECT_EQ("100.0", Element::fromJSON("1.0E2")->str()); + EXPECT_EQ("0.01", Element::fromJSON("1.0e-2")->str()); + EXPECT_EQ("0.012", Element::fromJSON("1.2e-2")->str()); + EXPECT_EQ("0.012", Element::fromJSON("1.2E-2")->str()); + EXPECT_EQ("\"\"", Element::fromJSON(" \n \t \r \f \b \"\" \n \f \t \r \b")->str()); + EXPECT_EQ("{ }", Element::fromJSON("{ \n \r \t \b \f }")->str()); + EXPECT_EQ("[ ]", Element::fromJSON("[ \n \r \f \t \b ]")->str()); + + // number overflows + EXPECT_THROW(Element::fromJSON("12345678901234567890")->str(), JSONError); + EXPECT_THROW(Element::fromJSON("1.1e12345678901234567890")->str(), JSONError); + EXPECT_THROW(Element::fromJSON("-1.1e12345678901234567890")->str(), JSONError); + EXPECT_THROW(Element::fromJSON("1e12345678901234567890")->str(), JSONError); + EXPECT_THROW(Element::fromJSON("1e50000")->str(), JSONError); + // number underflow + // EXPECT_THROW(Element::fromJSON("1.1e-12345678901234567890")->str(), JSONError); + +} + +template <typename T> +void +testGetValueInt() { + T el; + int64_t i; + int32_t i32; + uint32_t ui32; + long l; + long long ll; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::create(1); + EXPECT_NO_THROW({ + EXPECT_EQ(1, el->intValue()); + }); + EXPECT_THROW(el->doubleValue(), TypeError); + EXPECT_THROW(el->boolValue(), TypeError); + EXPECT_THROW(el->stringValue(), TypeError); + EXPECT_THROW(el->listValue(), TypeError); + EXPECT_THROW(el->mapValue(), TypeError); + EXPECT_TRUE(el->getValue(i)); + EXPECT_FALSE(el->getValue(d)); + EXPECT_FALSE(el->getValue(b)); + EXPECT_FALSE(el->getValue(s)); + EXPECT_FALSE(el->getValue(v)); + EXPECT_FALSE(el->getValue(m)); + EXPECT_EQ(1, i); + + el = Element::create(9223372036854775807LL); + EXPECT_NO_THROW({ + EXPECT_EQ(9223372036854775807LL, el->intValue()); + }); + EXPECT_TRUE(el->getValue(i)); + EXPECT_EQ(9223372036854775807LL, i); + + ll = 9223372036854775807LL; + el = Element::create(ll); + EXPECT_NO_THROW({ + EXPECT_EQ(ll, el->intValue()); + }); + EXPECT_TRUE(el->getValue(i)); + EXPECT_EQ(ll, i); + + i32 = 2147483647L; + el = Element::create(i32); + EXPECT_NO_THROW({ + EXPECT_EQ(i32, el->intValue()); + }); + EXPECT_TRUE(el->getValue(i)); + EXPECT_EQ(i32, i); + + ui32 = 4294967295L; + el = Element::create(ui32); + EXPECT_NO_THROW({ + EXPECT_EQ(ui32, el->intValue()); + }); + EXPECT_TRUE(el->getValue(i)); + EXPECT_EQ(ui32, i); + + l = 2147483647L; + el = Element::create(l); + EXPECT_NO_THROW({ + EXPECT_EQ(l, el->intValue()); + }); + EXPECT_TRUE(el->getValue(i)); + EXPECT_EQ(l, i); +} + +template <typename T> +void +testGetValueDouble() { + T el; + int64_t i; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::create(1.1); + EXPECT_THROW(el->intValue(), TypeError); + EXPECT_NO_THROW(el->doubleValue()); + EXPECT_THROW(el->boolValue(), TypeError); + EXPECT_THROW(el->stringValue(), TypeError); + EXPECT_THROW(el->listValue(), TypeError); + EXPECT_THROW(el->mapValue(), TypeError); + EXPECT_FALSE(el->getValue(i)); + EXPECT_TRUE(el->getValue(d)); + EXPECT_FALSE(el->getValue(b)); + EXPECT_FALSE(el->getValue(s)); + EXPECT_FALSE(el->getValue(v)); + EXPECT_FALSE(el->getValue(m)); + EXPECT_EQ(1.1, d); +} + +template <typename T> +void +testGetValueBool() { + T el; + int64_t i; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::create(true); + EXPECT_THROW(el->intValue(), TypeError); + EXPECT_THROW(el->doubleValue(), TypeError); + EXPECT_NO_THROW(el->boolValue()); + EXPECT_THROW(el->stringValue(), TypeError); + EXPECT_THROW(el->listValue(), TypeError); + EXPECT_THROW(el->mapValue(), TypeError); + EXPECT_FALSE(el->getValue(i)); + EXPECT_FALSE(el->getValue(d)); + EXPECT_TRUE(el->getValue(b)); + EXPECT_FALSE(el->getValue(s)); + EXPECT_FALSE(el->getValue(v)); + EXPECT_FALSE(el->getValue(m)); + EXPECT_EQ(true, b); +} + +template <typename T> +void +testGetValueString() { + T el; + int64_t i; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::create("foo"); + EXPECT_THROW(el->intValue(), TypeError); + EXPECT_THROW(el->doubleValue(), TypeError); + EXPECT_THROW(el->boolValue(), TypeError); + EXPECT_NO_THROW(el->stringValue()); + EXPECT_THROW(el->listValue(), TypeError); + EXPECT_THROW(el->mapValue(), TypeError); + EXPECT_FALSE(el->getValue(i)); + EXPECT_FALSE(el->getValue(d)); + EXPECT_FALSE(el->getValue(b)); + EXPECT_TRUE(el->getValue(s)); + EXPECT_FALSE(el->getValue(v)); + EXPECT_FALSE(el->getValue(m)); + EXPECT_EQ("foo", s); +} + +template <typename T> +void +testGetValueList() { + T el; + int64_t i; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::createList(); + EXPECT_THROW(el->intValue(), TypeError); + EXPECT_THROW(el->doubleValue(), TypeError); + EXPECT_THROW(el->boolValue(), TypeError); + EXPECT_THROW(el->stringValue(), TypeError); + EXPECT_NO_THROW(el->listValue()); + EXPECT_THROW(el->mapValue(), TypeError); + EXPECT_FALSE(el->getValue(i)); + EXPECT_FALSE(el->getValue(d)); + EXPECT_FALSE(el->getValue(b)); + EXPECT_FALSE(el->getValue(s)); + EXPECT_TRUE(el->getValue(v)); + EXPECT_FALSE(el->getValue(m)); + EXPECT_EQ("[ ]", el->str()); +} + +template <typename T> +void +testGetValueMap() { + T el; + int64_t i; + double d; + bool b; + std::string s; + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + + el = Element::createMap(); + EXPECT_THROW(el->intValue(), TypeError); + EXPECT_THROW(el->doubleValue(), TypeError); + EXPECT_THROW(el->boolValue(), TypeError); + EXPECT_THROW(el->stringValue(), TypeError); + EXPECT_THROW(el->listValue(), TypeError); + EXPECT_NO_THROW(el->mapValue()); + EXPECT_FALSE(el->getValue(i)); + EXPECT_FALSE(el->getValue(d)); + EXPECT_FALSE(el->getValue(b)); + EXPECT_FALSE(el->getValue(s)); + EXPECT_FALSE(el->getValue(v)); + EXPECT_TRUE(el->getValue(m)); + EXPECT_EQ("{ }", el->str()); +} + +TEST(Element, create_and_value_throws) { + // this test checks whether elements throw exceptions if the + // incorrect type is requested + ElementPtr el; + ConstElementPtr cel; + int64_t i = 0; + double d = 0.0; + bool b = false; + std::string s("asdf"); + std::vector<ElementPtr> v; + std::map<std::string, ConstElementPtr> m; + ConstElementPtr tmp; + + testGetValueInt<ElementPtr>(); + testGetValueInt<ConstElementPtr>(); + + el = Element::create(1); + i = 2; + EXPECT_TRUE(el->setValue(i)); + EXPECT_EQ(2, el->intValue()); + EXPECT_FALSE(el->setValue(d)); + EXPECT_FALSE(el->setValue(b)); + EXPECT_FALSE(el->setValue(s)); + EXPECT_FALSE(el->setValue(v)); + EXPECT_FALSE(el->setValue(m)); + EXPECT_THROW(el->get(1), TypeError); + EXPECT_THROW(el->set(1, el), TypeError); + EXPECT_THROW(el->add(el), TypeError); + EXPECT_THROW(el->remove(1), TypeError); + EXPECT_THROW(el->size(), TypeError); + EXPECT_THROW(el->empty(), TypeError); + EXPECT_THROW(el->get("foo"), TypeError); + EXPECT_THROW(el->set("foo", el), TypeError); + EXPECT_THROW(el->remove("foo"), TypeError); + EXPECT_THROW(el->contains("foo"), TypeError); + EXPECT_FALSE(el->find("foo", tmp)); + + testGetValueDouble<ElementPtr>(); + testGetValueDouble<ConstElementPtr>(); + + el = Element::create(1.1); + d = 2.2; + EXPECT_TRUE(el->setValue(d)); + EXPECT_EQ(2.2, el->doubleValue()); + EXPECT_FALSE(el->setValue(i)); + EXPECT_FALSE(el->setValue(b)); + EXPECT_FALSE(el->setValue(s)); + EXPECT_FALSE(el->setValue(v)); + EXPECT_FALSE(el->setValue(m)); + EXPECT_THROW(el->get(1), TypeError); + EXPECT_THROW(el->set(1, el), TypeError); + EXPECT_THROW(el->add(el), TypeError); + EXPECT_THROW(el->remove(1), TypeError); + EXPECT_THROW(el->size(), TypeError); + EXPECT_THROW(el->empty(), TypeError); + EXPECT_THROW(el->get("foo"), TypeError); + EXPECT_THROW(el->set("foo", el), TypeError); + EXPECT_THROW(el->remove("foo"), TypeError); + EXPECT_THROW(el->contains("foo"), TypeError); + EXPECT_FALSE(el->find("foo", tmp)); + + testGetValueBool<ElementPtr>(); + testGetValueBool<ConstElementPtr>(); + + el = Element::create(true); + b = false; + EXPECT_TRUE(el->setValue(b)); + EXPECT_FALSE(el->boolValue()); + EXPECT_FALSE(el->setValue(i)); + EXPECT_FALSE(el->setValue(d)); + EXPECT_FALSE(el->setValue(s)); + EXPECT_FALSE(el->setValue(v)); + EXPECT_FALSE(el->setValue(m)); + EXPECT_THROW(el->get(1), TypeError); + EXPECT_THROW(el->set(1, el), TypeError); + EXPECT_THROW(el->add(el), TypeError); + EXPECT_THROW(el->remove(1), TypeError); + EXPECT_THROW(el->size(), TypeError); + EXPECT_THROW(el->empty(), TypeError); + EXPECT_THROW(el->get("foo"), TypeError); + EXPECT_THROW(el->set("foo", el), TypeError); + EXPECT_THROW(el->remove("foo"), TypeError); + EXPECT_THROW(el->contains("foo"), TypeError); + EXPECT_FALSE(el->find("foo", tmp)); + + testGetValueString<ElementPtr>(); + testGetValueString<ConstElementPtr>(); + + el = Element::create("foo"); + s = "bar"; + EXPECT_TRUE(el->setValue(s)); + EXPECT_EQ("bar", el->stringValue()); + EXPECT_FALSE(el->setValue(i)); + EXPECT_FALSE(el->setValue(b)); + EXPECT_FALSE(el->setValue(d)); + EXPECT_FALSE(el->setValue(v)); + EXPECT_FALSE(el->setValue(m)); + EXPECT_THROW(el->get(1), TypeError); + EXPECT_THROW(el->set(1, el), TypeError); + EXPECT_THROW(el->add(el), TypeError); + EXPECT_THROW(el->remove(1), TypeError); + EXPECT_THROW(el->size(), TypeError); + EXPECT_THROW(el->empty(), TypeError); + EXPECT_THROW(el->get("foo"), TypeError); + EXPECT_THROW(el->set("foo", el), TypeError); + EXPECT_THROW(el->remove("foo"), TypeError); + EXPECT_THROW(el->contains("foo"), TypeError); + EXPECT_FALSE(el->find("foo", tmp)); + + testGetValueList<ElementPtr>(); + testGetValueList<ConstElementPtr>(); + + el = Element::createList(); + EXPECT_TRUE(el->empty()); + v.push_back(Element::create(1)); + EXPECT_TRUE(el->setValue(v)); + EXPECT_FALSE(el->empty()); + EXPECT_EQ("[ 1 ]", el->str()); + + testGetValueMap<ElementPtr>(); + testGetValueMap<ConstElementPtr>(); + + el = Element::createMap(); + EXPECT_NO_THROW(el->set("foo", Element::create("bar"))); + EXPECT_EQ("{ \"foo\": \"bar\" }", el->str()); +} + +// Helper for escape check; it puts the given string in a StringElement, +// then checks for the following conditions: +// stringValue() must be same as input +// toJSON() output must be escaped +// fromJSON() on the previous output must result in original input +void +escapeHelper(const std::string& input, const std::string& expected) { + StringElement str_element = StringElement(input); + EXPECT_EQ(input, str_element.stringValue()); + std::stringstream os; + str_element.toJSON(os); + EXPECT_EQ(expected, os.str()); + ElementPtr str_element2 = Element::fromJSON(os.str()); + EXPECT_EQ(str_element.stringValue(), str_element2->stringValue()); +} + +TEST(Element, escape) { + // Test whether quotes are escaped correctly when creating direct + // String elements. + escapeHelper("foo\"bar", "\"foo\\\"bar\""); + escapeHelper("foo\\bar", "\"foo\\\\bar\""); + escapeHelper("foo\bbar", "\"foo\\bbar\""); + escapeHelper("foo\fbar", "\"foo\\fbar\""); + escapeHelper("foo\nbar", "\"foo\\nbar\""); + escapeHelper("foo\rbar", "\"foo\\rbar\""); + escapeHelper("foo\tbar", "\"foo\\tbar\""); + escapeHelper("foo\u001fbar", "\"foo\\u001fbar\""); + // Bad escapes + EXPECT_THROW(Element::fromJSON("\\a"), JSONError); + EXPECT_THROW(Element::fromJSON("\\"), JSONError); + // Can't have escaped quotes outside strings + EXPECT_THROW(Element::fromJSON("\\\"\\\""), JSONError); + // Unicode use lower u and 4 hexa, only 00 prefix is supported + EXPECT_THROW(Element::fromJSON("\\U0020"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u002"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u0123"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u1023"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u00ag"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u00ga"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u00BH"), JSONError); + EXPECT_THROW(Element::fromJSON("\\u00HB"), JSONError); + // Inside strings is OK + EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\"")); + // A whitespace test + EXPECT_NO_THROW(Element::fromJSON("\" \n \r \t \f \n \n \t\"")); + // Escape for forward slash is optional + ASSERT_NO_THROW(Element::fromJSON("\"foo\\/bar\"")); + EXPECT_EQ("foo/bar", Element::fromJSON("\"foo\\/bar\"")->stringValue()); + // Control characters + StringElement bell("foo\abar"); + EXPECT_EQ("\"foo\\u0007bar\"", bell.str()); + // 8 bit escape + StringElement ab("foo\253bar"); + EXPECT_EQ("\"foo\\u00abbar\"", ab.str()); + ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00abbar\"")); + EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00abbar\""))); + ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00ABbar\"")); + EXPECT_TRUE(ab.equals(*Element::fromJSON("\"foo\\u00ABbar\""))); + StringElement f1("foo\361bar"); + EXPECT_EQ("\"foo\\u00f1bar\"", f1.str()); + ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00f1bar\"")); + EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00f1bar\""))); + ASSERT_NO_THROW(Element::fromJSON("\"foo\\u00F1bar\"")); + EXPECT_TRUE(f1.equals(*Element::fromJSON("\"foo\\u00F1bar\""))); +} + +// This test verifies that strings are copied. +TEST(Element, stringCopy) { + // StringElement constructor copies its string argument. + std::string foo = "foo"; + ElementPtr elem = ElementPtr(new StringElement(foo)); + EXPECT_EQ(foo, elem->stringValue()); + foo[1] = 'O'; + EXPECT_EQ("fOo", foo); + EXPECT_NE(foo, elem->stringValue()); + + // Map keys are copied too. + ElementPtr map = ElementPtr(new MapElement()); + std::string bar = "bar"; + map->set(bar, ElementPtr(new IntElement(1))); + ConstElementPtr item = map->get("bar"); + ASSERT_TRUE(item); + EXPECT_EQ(1, item->intValue()); + bar[0] = 'B'; + EXPECT_EQ("Bar", bar); + EXPECT_TRUE(map->get("bar")); + EXPECT_FALSE(map->get(bar)); +} + +// This test verifies that a backslash can be used in element content +// when the element is created using constructor. +TEST(Element, backslash1) { + string input = "SMSBoot\\x64";// One slash passed to elem constructor... + string exp = "SMSBoot\\x64"; // ... should result in one slash in the actual option. + + StringElement elem(input); + EXPECT_EQ(exp, elem.stringValue()); +} + +// This test verifies that a backslash can be used in element content +// when the element is created using fromJSON. +TEST(Element, backslash2) { + string input = "\"SMSBoot\\\\x64\""; // Two slashes put in the config file... + string exp = "SMSBoot\\x64"; // ... should result in one slash in the actual option. + + ElementPtr elem = Element::fromJSON(input); + EXPECT_EQ(exp, elem->stringValue()); +} + +TEST(Element, ListElement) { + // this function checks the specific functions for ListElements + ElementPtr el = Element::fromJSON("[ 1, \"bar\", 3 ]"); + EXPECT_EQ(el->get(0)->intValue(), 1); + EXPECT_EQ(el->get(1)->stringValue(), "bar"); + EXPECT_EQ(el->get(2)->intValue(), 3); + + el->set(0, Element::fromJSON("\"foo\"")); + EXPECT_EQ(el->get(0)->stringValue(), "foo"); + + el->add(Element::create(56176)); + EXPECT_EQ(el->get(3)->intValue(), 56176); + + el->remove(1); + el->remove(1); + EXPECT_EQ(el->str(), "[ \"foo\", 56176 ]"); + + // hmm, it errors on EXPECT_THROW(el->get(3), std::out_of_range) + EXPECT_ANY_THROW(el->get(3)); + + el->add(Element::create(32)); + EXPECT_EQ(32, el->get(2)->intValue()); + + // boundary condition tests for set() + el->set(2, Element::create(0)); // update the last entry of the list + EXPECT_EQ(0, el->get(2)->intValue()); + // attempt of set beyond the range of list should trigger an exception. + EXPECT_ANY_THROW(el->set(3, Element::create(0))); +} + +TEST(Element, MapElement) { + // this function checks the specific functions for ListElements + ElementPtr el = Element::fromJSON("{ \"name\": \"foo\", \"value1\": \"bar\", \"value2\": { \"number\": 42 } }"); + ConstElementPtr el2; + + EXPECT_EQ(el->get("name")->stringValue(), "foo"); + EXPECT_EQ(el->get("value2")->getType(), Element::map); + + EXPECT_TRUE(isNull(el->get("value3"))); + + EXPECT_FALSE(el->empty()); + + el->set("value3", Element::create(56176)); + EXPECT_EQ(el->get("value3")->intValue(), 56176); + + el->remove("value3"); + EXPECT_TRUE(isNull(el->get("value3"))); + + EXPECT_EQ(el->find("value2/number")->intValue(), 42); + EXPECT_TRUE(isNull(el->find("value2/nothing/"))); + + EXPECT_EQ(el->find("value1")->stringValue(), "bar"); + EXPECT_EQ(el->find("value1/")->stringValue(), "bar"); + + EXPECT_TRUE(el->find("value1", el2)); + EXPECT_EQ("bar", el2->stringValue()); + EXPECT_FALSE(el->find("name/error", el2)); + + // A map element whose (only) element has the maximum length of tag. + string long_maptag("0123456789abcdef1123456789abcdef2123456789abcdef" + "3123456789abcdef4123456789abcdef5123456789abcdef" + "6123456789abcdef7123456789abcdef8123456789abcdef" + "9123456789abcdefa123456789abcdefb123456789abcdef" + "c123456789abcdefd123456789abcdefe123456789abcdef" + "f123456789abcde"); + + EXPECT_EQ(255, long_maptag.length()); // check prerequisite + el = Element::fromJSON("{ \"" + long_maptag + "\": \"bar\"}"); + EXPECT_EQ("bar", el->find(long_maptag)->stringValue()); + + el = Element::createMap(); + el->set(long_maptag, Element::create("bar")); + EXPECT_EQ("bar", el->find(long_maptag)->stringValue()); + + // A one-byte longer tag should still be allowed + long_maptag.push_back('f'); + el = Element::fromJSON("{ \"" + long_maptag + "\": \"bar\"}"); + el->set(long_maptag, Element::create("bar")); + EXPECT_EQ("bar", el->find(long_maptag)->stringValue()); + + // Null pointer value + el.reset(new MapElement()); + ConstElementPtr null_ptr; + el->set("value", null_ptr); + EXPECT_FALSE(el->get("value")); + EXPECT_EQ("{ \"value\": None }", el->str()); +} + +TEST(Element, to_and_from_wire) { + // Wire format is now plain JSON. + EXPECT_EQ("1", Element::create(1)->toWire()); + EXPECT_EQ("1.1", Element::create(1.1)->toWire()); + EXPECT_EQ("true", Element::create(true)->toWire()); + EXPECT_EQ("false", Element::create(false)->toWire()); + EXPECT_EQ("null", Element::create()->toWire()); + EXPECT_EQ("\"a string\"", Element::create("a string")->toWire()); + EXPECT_EQ("[ \"a\", \"list\" ]", Element::fromJSON("[ \"a\", \"list\" ]")->toWire()); + EXPECT_EQ("{ \"a\": \"map\" }", Element::fromJSON("{ \"a\": \"map\" }")->toWire()); + + EXPECT_EQ("1", Element::fromWire("1")->str()); + + std::stringstream ss; + ss << "1"; + EXPECT_EQ("1", Element::fromWire(ss, 1)->str()); + + // Some malformed JSON input + EXPECT_THROW(Element::fromJSON("{ "), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\" "), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": "), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": \"b\""), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": {"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": {}"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": []"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\": [ }"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{\":"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("]"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("[ 1, 2, }"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("[ 1, 2, {}"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("[ 1, 2, { ]"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("[ "), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{{}}"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{[]}"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("{ \"a\", \"b\" }"), isc::data::JSONError); + EXPECT_THROW(Element::fromJSON("[ \"a\": \"b\" ]"), isc::data::JSONError); +} + +ConstElementPtr +efs(const std::string& str) { + return (Element::fromJSON(str)); +} + +TEST(Element, equals) { + EXPECT_EQ(*efs("1"), *efs("1")); + EXPECT_NE(*efs("1"), *efs("2")); + EXPECT_NE(*efs("1"), *efs("\"1\"")); + EXPECT_NE(*efs("1"), *efs("[]")); + EXPECT_NE(*efs("1"), *efs("true")); + EXPECT_NE(*efs("1"), *efs("{}")); + EXPECT_EQ(*efs("1.1"), *efs("1.1")); + EXPECT_NE(*efs("1.0"), *efs("1")); + EXPECT_NE(*efs("1.1"), *efs("\"1\"")); + EXPECT_NE(*efs("1.1"), *efs("[]")); + EXPECT_NE(*efs("1.1"), *efs("true")); + EXPECT_NE(*efs("1.1"), *efs("{}")); + + EXPECT_EQ(*efs("true"), *efs("true")); + EXPECT_NE(*efs("true"), *efs("false")); + EXPECT_NE(*efs("true"), *efs("1")); + EXPECT_NE(*efs("true"), *efs("\"1\"")); + EXPECT_NE(*efs("true"), *efs("[]")); + EXPECT_NE(*efs("true"), *efs("{}")); + + EXPECT_EQ(*efs("\"foo\""), *efs("\"foo\"")); + EXPECT_NE(*efs("\"foo\""), *efs("\"bar\"")); + EXPECT_NE(*efs("\"foo\""), *efs("1")); + EXPECT_NE(*efs("\"foo\""), *efs("\"1\"")); + EXPECT_NE(*efs("\"foo\""), *efs("true")); + EXPECT_NE(*efs("\"foo\""), *efs("[]")); + EXPECT_NE(*efs("\"foo\""), *efs("{}")); + + EXPECT_EQ(*efs("[]"), *efs("[]")); + EXPECT_EQ(*efs("[ 1, 2, 3 ]"), *efs("[ 1, 2, 3 ]")); + EXPECT_EQ(*efs("[ \"a\", [ true, 1], 2.2 ]"), *efs("[ \"a\", [ true, 1], 2.2 ]")); + EXPECT_NE(*efs("[ \"a\", [ true, 1], 2.2 ]"), *efs("[ \"a\", [ true, 2], 2.2 ]")); + EXPECT_NE(*efs("[]"), *efs("[1]")); + EXPECT_NE(*efs("[]"), *efs("1")); + EXPECT_NE(*efs("[]"), *efs("\"1\"")); + EXPECT_NE(*efs("[]"), *efs("{}")); + + EXPECT_EQ(*efs("{}"), *efs("{}")); + EXPECT_EQ(*efs("{ \"foo\": \"bar\" }"), *efs("{ \"foo\": \"bar\" }")); + EXPECT_EQ(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }")); + EXPECT_NE(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar2\" } }")); + EXPECT_NE(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\", 1 ], \"item3\": { \"foo\": \"bar\" } }")); + EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("1")); + EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("\"1\"")); + EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("[]")); + EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("{}")); + EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("{ \"something\": \"different\" }")); + + EXPECT_EQ(*efs("null"), *Element::create()); +} + +TEST(Element, removeIdentical) { + ElementPtr a = Element::createMap(); + ConstElementPtr b = Element::createMap(); + ConstElementPtr c = Element::createMap(); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1 }"); + b = Element::fromJSON("{ \"a\": 1 }"); + c = Element::createMap(); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::createMap(); + c = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + c = Element::createMap(); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 3 ] }"); + c = Element::fromJSON("{ \"b\": [ 1, 2 ] }"); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::createMap(); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + c = Element::createMap(); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }"); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }"); + b = Element::fromJSON("{ \"c\": 3, \"b\": 2 }"); + c = Element::fromJSON("{ \"a\": 1 }"); + removeIdentical(a, b); + EXPECT_EQ(*a, *c); + + EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)), TypeError); +} + +TEST(Element, constRemoveIdentical) { + ConstElementPtr a = Element::createMap(); + ConstElementPtr b = Element::createMap(); + ConstElementPtr c = Element::createMap(); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": 1 }"); + b = Element::fromJSON("{ \"a\": 1 }"); + c = Element::createMap(); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::createMap(); + c = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + c = Element::createMap(); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 3 ] }"); + c = Element::fromJSON("{ \"b\": [ 1, 2 ] }"); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::createMap(); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + c = Element::createMap(); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }"); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + EXPECT_EQ(*removeIdentical(a, b), *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }"); + b = Element::fromJSON("{ \"c\": 3, \"b\": 2 }"); + c = Element::fromJSON("{ \"a\": 1 }"); + EXPECT_EQ(*removeIdentical(a, b), *c); + + // removeIdentical() is overloaded so force the first argument to const + ConstElementPtr bad = Element::create(1); + EXPECT_THROW(removeIdentical(bad, Element::create(2)), TypeError); +} + +TEST(Element, merge) { + ElementPtr a = Element::createMap(); + ElementPtr b = Element::createMap(); + ConstElementPtr c = Element::createMap(); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("1"); + b = Element::createMap(); + EXPECT_THROW(merge(a, b), TypeError); + + a = Element::createMap(); + b = Element::fromJSON("{ \"a\": 1 }"); + c = Element::fromJSON("{ \"a\": 1 }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::createMap(); + b = Element::fromJSON("{ \"a\": 1 }"); + c = Element::fromJSON("{ \"a\": 1 }"); + merge(b, a); + EXPECT_EQ(*b, *c); + + a = Element::fromJSON("{ \"a\": 1 }"); + b = Element::fromJSON("{ \"a\": 2 }"); + c = Element::fromJSON("{ \"a\": 2 }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1 }"); + b = Element::fromJSON("{ \"a\": 2 }"); + c = Element::fromJSON("{ \"a\": 1 }"); + merge(b, a); + EXPECT_EQ(*b, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }"); + c = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }"); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + merge(b, a); + EXPECT_EQ(*b, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": null }"); + c = Element::fromJSON("{ }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + b = Element::fromJSON("{ \"a\": null }"); + c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }"); + merge(b, a); + EXPECT_EQ(*b, *c); + + // And some tests with multiple values + a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }"); + c = Element::fromJSON("{ \"a\": 1, \"c\": \"a string\" }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }"); + b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }"); + c = Element::fromJSON("{ \"a\": 1, \"b\": true }"); + merge(b, a); + EXPECT_EQ(*b, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }"); + b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }"); + c = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }"); + merge(a, b); + EXPECT_EQ(*a, *c); + + a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }"); + b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }"); + c = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }"); + merge(b, a); + EXPECT_EQ(*b, *c); + +} + +// This test checks copy. +TEST(Element, copy) { + // Null pointer + ElementPtr elem; + EXPECT_THROW(copy(elem, 0), isc::BadValue); + EXPECT_THROW(copy(elem), isc::BadValue); + EXPECT_THROW(copy(elem, -1), isc::BadValue); + + // Basic types + elem.reset(new IntElement(1)); + EXPECT_TRUE(elem->equals(*Element::fromJSON("1"))); + EXPECT_EQ("1", elem->str()); + ElementPtr copied; + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + + elem.reset(new DoubleElement(1.0)); + EXPECT_TRUE(elem->equals(*Element::fromJSON("1.0"))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + + elem.reset(new BoolElement(true)); + EXPECT_TRUE(elem->equals(*Element::fromJSON("true"))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + + elem.reset(new NullElement()); + EXPECT_TRUE(elem->equals(*Element::fromJSON("null"))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + + elem.reset(new StringElement("foo")); + EXPECT_TRUE(elem->equals(*Element::fromJSON("\"foo\""))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + ASSERT_NO_THROW(elem->setValue(std::string("bar"))); + EXPECT_TRUE(elem->equals(*Element::fromJSON("\"bar\""))); + EXPECT_FALSE(elem->equals(*copied)); + + elem.reset(new ListElement()); + ElementPtr item = ElementPtr(new IntElement(1)); + elem->add(item); + EXPECT_TRUE(elem->equals(*Element::fromJSON("[ 1 ]"))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + ElementPtr deep; + ASSERT_NO_THROW(deep = copy(elem)); + EXPECT_TRUE(elem->equals(*deep)); + ASSERT_NO_THROW(item = elem->getNonConst(0)); + ASSERT_NO_THROW(item->setValue(2)); + EXPECT_TRUE(elem->equals(*Element::fromJSON("[ 2 ]"))); + EXPECT_TRUE(elem->equals(*copied)); + EXPECT_FALSE(elem->equals(*deep)); + + elem.reset(new MapElement()); + item.reset(new StringElement("bar")); + elem->set("foo", item); + EXPECT_TRUE(elem->equals(*Element::fromJSON("{ \"foo\": \"bar\" }"))); + ASSERT_NO_THROW(copied = copy(elem, 0)); + EXPECT_TRUE(elem->equals(*copied)); + ASSERT_NO_THROW(deep = copy(elem)); + EXPECT_TRUE(elem->equals(*deep)); + ASSERT_NO_THROW(item->setValue(std::string("Bar"))); + EXPECT_TRUE(elem->equals(*Element::fromJSON("{ \"foo\": \"Bar\" }"))); + EXPECT_TRUE(elem->equals(*copied)); + EXPECT_FALSE(elem->equals(*deep)); + + // Complex example + std::string input = "{ \n" + "\"integer\": 1,\n" + "\"double\": 1.0,\n" + "\"boolean\": true,\n" + "\"null\": null,\n" + "\"string\": \"foobar\",\n" + "\"list\": [ 1, 2 ],\n" + "\"map\": { \"foo\": \"bar\" } }\n"; + ConstElementPtr complex; + ASSERT_NO_THROW(complex = Element::fromJSON(input)); + ASSERT_NO_THROW(copied = copy(complex, 0)); + EXPECT_TRUE(copied->equals(*complex)); + ASSERT_NO_THROW(deep = copy(complex)); + EXPECT_TRUE(deep->equals(*complex)); + ElementPtr shallow; + ASSERT_NO_THROW(shallow = copy(complex, 1)); + EXPECT_TRUE(shallow->equals(*complex)); + // Try to modify copies + ASSERT_NO_THROW(item = deep->get("list")->getNonConst(1)); + ASSERT_NO_THROW(item->setValue(3)); + EXPECT_FALSE(deep->equals(*complex)); + EXPECT_TRUE(shallow->equals(*complex)); + ASSERT_NO_THROW(item = boost::const_pointer_cast<Element>(shallow->get("string"))); + ASSERT_NO_THROW(item->setValue(std::string("FooBar"))); + EXPECT_FALSE(shallow->equals(*complex)); + EXPECT_TRUE(copied->equals(*complex)); +} + +// This test checks the isEquivalent function. +TEST(Element, isEquivalent) { + // All are different but a is equivalent to b + string texta = "{ \"a\": 1, \"b\": [ ], \"c\": [ 1, 1, 2 ] }"; + string textb = "{ \"b\": [ ], \"a\": 1, \"c\": [ 1, 2, 1 ] }"; + string textc = "{ \"a\": 2, \"b\": [ ], \"c\": [ 1, 1, 2 ] }"; + string textd = "{ \"a\": 1, \"c\": [ ], \"b\": [ 1, 1, 2 ] }"; + string texte = "{ \"a\": 1, \"b\": [ ], \"c\": [ 1, 2, 2 ] }"; + + ElementPtr a = Element::fromJSON(texta); + ElementPtr b = Element::fromJSON(textb); + ElementPtr c = Element::fromJSON(textc); + ElementPtr d = Element::fromJSON(textd); + ElementPtr e = Element::fromJSON(texte); + + EXPECT_TRUE(isEquivalent(a, b)); + EXPECT_NE(a, b); + EXPECT_FALSE(isEquivalent(a, c)); + EXPECT_FALSE(isEquivalent(a, d)); + EXPECT_FALSE(isEquivalent(a, e)); + + // Verifies isEquivalent handles cycles + if (isc::util::unittests::runningOnValgrind()) { + ElementPtr l = Element::createList(); + l->add(l); + EXPECT_THROW(isEquivalent(l, l), isc::BadValue); + } +} + +// This test checks the pretty print function. +TEST(Element, prettyPrint) { + + // default step is 2, order is alphabetic, no \n at the end + string text = "{\n" + " \"boolean\": true,\n" + " \"comment\": \"this is an exception\",\n" + " \"empty-list\": [ ],\n" + " \"empty-map\": { },\n" + " \"integer\": 1,\n" + " \"list\": [ 1, 2, 3 ],\n" + " \"map\": {\n" + " \"item\": null\n" + " },\n" + " \"string\": \"foobar\"\n" + "}"; + ElementPtr json = Element::fromJSON(text); + string pprinted = prettyPrint(json); + EXPECT_EQ(text, pprinted); +} + +// This test checks whether it is possible to ignore comments. It also checks +// that the comments are ignored only when told to. +TEST(Element, preprocessor) { + + string no_comment = "{ \"a\": 1,\n" + " \"b\": 2}"; + + string head_comment = "# this is a comment, ignore me\n" + "{ \"a\": 1,\n" + " \"b\": 2}"; + + string mid_comment = "{ \"a\": 1,\n" + "# this is a comment, ignore me\n" + " \"b\": 2}"; + + string tail_comment = "{ \"a\": 1,\n" + " \"b\": 2}" + "# this is a comment, ignore me\n"; + + string dbl_head_comment = "# this is a comment, ignore me\n" + "# second line, still ignored\n" + "{ \"a\": 1,\n" + " \"b\": 2}"; + + string dbl_mid_comment = "{ \"a\": 1,\n" + "# this is a comment, ignore me\n" + "# second line, still ignored\n" + " \"b\": 2}"; + + string dbl_tail_comment = "{ \"a\": 1,\n" + " \"b\": 2}" + "# this is a comment, ignore me\n" + "# second line, still ignored\n"; + + // This is what we expect in all cases. + ElementPtr exp = Element::fromJSON(no_comment); + + // Let's convert them all and see that the result it the same every time + EXPECT_TRUE(exp->equals(*Element::fromJSON(head_comment, true))); + EXPECT_TRUE(exp->equals(*Element::fromJSON(mid_comment, true))); + EXPECT_TRUE(exp->equals(*Element::fromJSON(tail_comment, true))); + EXPECT_TRUE(exp->equals(*Element::fromJSON(dbl_head_comment, true))); + EXPECT_TRUE(exp->equals(*Element::fromJSON(dbl_mid_comment, true))); + EXPECT_TRUE(exp->equals(*Element::fromJSON(dbl_tail_comment, true))); + + // With preprocessing disabled, it should fail all around + EXPECT_THROW(Element::fromJSON(head_comment), JSONError); + EXPECT_THROW(Element::fromJSON(mid_comment), JSONError); + EXPECT_THROW(Element::fromJSON(tail_comment), JSONError); + EXPECT_THROW(Element::fromJSON(dbl_head_comment), JSONError); + EXPECT_THROW(Element::fromJSON(dbl_mid_comment), JSONError); + EXPECT_THROW(Element::fromJSON(dbl_tail_comment), JSONError); + + // For coverage + std::istringstream iss(no_comment); + EXPECT_TRUE(exp->equals(*Element::fromJSON(iss, true))); +} + +TEST(Element, getPosition) { + std::istringstream ss("{\n" + " \"a\": 2,\n" + " \"b\":true,\n" + " \"cy\": \"a string\",\n" + " \"dyz\": {\n" + "\n" + " \"e\": 3,\n" + " \"f\": null\n" + "\n" + " },\n" + " \"g\": [ 5, 6,\n" + " 7 ]\n" + "}\n"); + + // Create a JSON string holding different type of values. Some of the + // values in the config string are not aligned, so as we can check that + // the position is set correctly for the elements. + ElementPtr top = Element::fromJSON(ss, string("kea.conf")); + ASSERT_TRUE(top); + + // Element "a" + ConstElementPtr level1_el = top->get("a"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(2, level1_el->getPosition().line_); + EXPECT_EQ(11, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "b" + level1_el = top->get("b"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(3, level1_el->getPosition().line_); + EXPECT_EQ(9, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "cy" + level1_el = top->get("cy"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(4, level1_el->getPosition().line_); + EXPECT_EQ(11, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "dyz" + level1_el = top->get("dyz"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(5, level1_el->getPosition().line_); + EXPECT_EQ(13, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "e" is a sub element of "dyz". + ConstElementPtr level2_el = level1_el->get("e"); + ASSERT_TRUE(level2_el); + EXPECT_EQ(7, level2_el->getPosition().line_); + EXPECT_EQ(12, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + + // Element "f" is also a sub element of "dyz" + level2_el = level1_el->get("f"); + ASSERT_TRUE(level2_el); + EXPECT_EQ(8, level2_el->getPosition().line_); + EXPECT_EQ(14, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + + // Element "g" is a list. + level1_el = top->get("g"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(11, level1_el->getPosition().line_); + // Position indicates where the values start (excluding the "[" character)" + EXPECT_EQ(11, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // First element from the list. + level2_el = level1_el->get(0); + ASSERT_TRUE(level2_el); + EXPECT_EQ(11, level2_el->getPosition().line_); + EXPECT_EQ(12, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + + // Second element from the list. + level2_el = level1_el->get(1); + ASSERT_TRUE(level2_el); + EXPECT_EQ(11, level2_el->getPosition().line_); + EXPECT_EQ(15, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + + // Third element from the list. + level2_el = level1_el->get(2); + ASSERT_TRUE(level2_el); + EXPECT_EQ(12, level2_el->getPosition().line_); + EXPECT_EQ(14, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + +} + +// Tests whether position is returned properly for a commented input JSON text. +TEST(Element, getPositionCommented) { + std::istringstream ss("{\n" + " \"a\": 2,\n" + "# comment\n" + " \"cy\": \"a string\",\n" + " \"dyz\": {\n" + "# another comment\n" + " \"e\": 3,\n" + " \"f\": null\n" + "\n" + " } }\n"); + + // Create a JSON string holding different type of values. Some of the + // values in the config string are not aligned, so as we can check that + // the position is set correctly for the elements. + ElementPtr top = Element::fromJSON(ss, string("kea.conf"), true); + ASSERT_TRUE(top); + + // Element "a" + ConstElementPtr level1_el = top->get("a"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(2, level1_el->getPosition().line_); + EXPECT_EQ(11, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "cy" + level1_el = top->get("cy"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(4, level1_el->getPosition().line_); + EXPECT_EQ(11, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "dyz" + level1_el = top->get("dyz"); + ASSERT_TRUE(level1_el); + EXPECT_EQ(5, level1_el->getPosition().line_); + EXPECT_EQ(13, level1_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level1_el->getPosition().file_); + + // Element "e" is a sub element of "dyz". + ConstElementPtr level2_el = level1_el->get("e"); + ASSERT_TRUE(level2_el); + EXPECT_EQ(7, level2_el->getPosition().line_); + EXPECT_EQ(12, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); + + // Element "f" is also a sub element of "dyz" + level2_el = level1_el->get("f"); + ASSERT_TRUE(level2_el); + EXPECT_EQ(8, level2_el->getPosition().line_); + EXPECT_EQ(14, level2_el->getPosition().pos_); + EXPECT_EQ("kea.conf", level2_el->getPosition().file_); +} + +TEST(Element, empty) { + + // Let's try Map first + ElementPtr m = Element::createMap(); + EXPECT_TRUE(m->empty()); + m->set("something", Element::create(123)); + EXPECT_FALSE(m->empty()); + m->remove("something"); + EXPECT_TRUE(m->empty()); + + // Now do the same with list + ElementPtr l = Element::createList(); + EXPECT_TRUE(l->empty()); + l->add(Element::create(123)); + EXPECT_FALSE(l->empty()); + l->remove(0); + EXPECT_TRUE(l->empty()); +} + +TEST(Element, sortIntegers) { + ElementPtr l(Element::fromJSON("[5, 7, 4, 2, 8, 6, 1, 9, 0, 3]")); + ElementPtr expected(Element::fromJSON("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]")); + boost::dynamic_pointer_cast<ListElement>(l)->sort(); + EXPECT_EQ(*l, *expected); +} + +TEST(Element, sortFloatingPoint) { + ElementPtr l(Element::fromJSON("[2.1, 3.2, 2.1, 2.2, 4.1, 3.2, 1.1, 4.2, 0.1, 1.2]")); + ElementPtr expected(Element::fromJSON("[0.1, 1.1, 1.2, 2.1, 2.1, 2.2, 3.2, 3.2, 4.1, 4.2]")); + boost::dynamic_pointer_cast<ListElement>(l)->sort(); + EXPECT_EQ(*l, *expected); +} + +TEST(Element, sortBooleans) { + ElementPtr l(Element::fromJSON("[false, true, false, true]")); + ElementPtr expected(Element::fromJSON("[false, false, true, true]")); + boost::dynamic_pointer_cast<ListElement>(l)->sort(); + EXPECT_EQ(*l, *expected); +} + +TEST(Element, sortStrings) { + ElementPtr l(Element::fromJSON(R"(["hello", "world", "lorem", "ipsum", "dolor", "sit", "amet"])")); + ElementPtr expected(Element::fromJSON(R"(["amet", "dolor", "hello", "ipsum", "lorem", "sit", "world"])")); + boost::dynamic_pointer_cast<ListElement>(l)->sort(); + EXPECT_EQ(*l, *expected); +} + +TEST(Element, sortMaps) { + ElementPtr e1(Element::fromJSON(R"({"id": 1, "subnet": "10.0.2.0/24"})")); + ElementPtr e2(Element::fromJSON(R"({"id": 2, "subnet": "10.0.1.0/24"})")); + ElementPtr l; + + // Test sorting by "id". Order shouldn't change. + l = Element::createList(); + l->add(e1); + l->add(e2); + boost::dynamic_pointer_cast<ListElement>(l)->sort("id"); + ASSERT_EQ(l->size(), 2); + EXPECT_EQ(*l->get(0), *e1); + EXPECT_EQ(*l->get(1), *e2); + + // Test sorting by "id". Order should change. + l = Element::createList(); + l->add(e2); + l->add(e1); + boost::dynamic_pointer_cast<ListElement>(l)->sort("id"); + ASSERT_EQ(l->size(), 2); + EXPECT_EQ(*l->get(0), *e1); + EXPECT_EQ(*l->get(1), *e2); + + // Test sorting by "subnet". Order should change. + l = Element::createList(); + l->add(e1); + l->add(e2); + boost::dynamic_pointer_cast<ListElement>(l)->sort("subnet"); + ASSERT_EQ(l->size(), 2); + EXPECT_EQ(*l->get(0), *e2); + EXPECT_EQ(*l->get(1), *e1); + + // Test sorting by "subnet". Order shouldn't change. + l = Element::createList(); + l->add(e2); + l->add(e1); + boost::dynamic_pointer_cast<ListElement>(l)->sort("subnet"); + ASSERT_EQ(l->size(), 2); + EXPECT_EQ(*l->get(0), *e2); + EXPECT_EQ(*l->get(1), *e1); +} + +TEST(Element, removeEmptyContainersRecursively) { + ElementPtr e(Element::fromJSON(R"( +{ + "list": [ + { + "nested-list": [ + { + "nestedx2-list": [ + {} + ] + } + ] + } + ], + "map": { + "nested-map": { + "nestedx2-map": {} + } + }, + "simple-list": {}, + "simple-map": {} +} +)")); + e->removeEmptyContainersRecursively(); + EXPECT_EQ(*e, *Element::fromJSON("{}")); + + e = Element::fromJSON(R"( +{ + "list": [ + { + "value": "not empty anymore", + "nested-list": [ + { + "nestedx2-list": [ + {} + ] + } + ] + } + ], + "map": { + "value": "not empty anymore", + "nested-map": { + "nestedx2-map": {} + } + }, + "simple-list": {}, + "simple-map": {} +} +)"); + e->removeEmptyContainersRecursively(); + EXPECT_EQ(*e, *Element::fromJSON(R"( +{ + "list": [ + { + "value": "not empty anymore" + } + ], + "map": { + "value": "not empty anymore" + } +} +)")); +} + +/// @brief Function which creates an imaginary configuration hierarchy used to +/// test mergeDiffAdd, mergeDiffDel and extend. +/// +/// @param any Flag which indicates if traversing the hierarchy should use exact +/// element match or not. +isc::data::HierarchyDescriptor createHierarchy(bool any = false) { + auto const& element_empty = [](ElementPtr& element) { + for (auto const& kv : element->mapValue()) { + auto const& key = kv.first; + if (key != "id") { + return (false); + } + } + return (true); + }; + auto const& element_match = [](ElementPtr& left, ElementPtr& right) -> bool { + return (left->get("id")->intValue() == right->get("id")->intValue()); + }; + auto const& element_any_match = [](ElementPtr&, ElementPtr&) -> bool { + return (true); + }; + auto const& element_is_key = [](const std::string& key) -> bool { + return (key == "id"); + }; + isc::data::HierarchyDescriptor hierarchy = { + { { "root", { element_match, element_empty, element_is_key } } }, + { { "elements", { element_match, element_empty, element_is_key } }, + { "elements-other", { element_match, element_empty, element_is_key } } } + }; + if (any) { + hierarchy = { + { { "root", { element_any_match, element_empty, element_is_key } } }, + { { "elements", { element_any_match, element_empty, element_is_key } }, + { "elements-other", { element_any_match, element_empty, element_is_key } } } + }; + } + return (hierarchy); +} + +/// @brief Test which checks that mergeDiffAdd throws if called with wrong +/// element types. +TEST(Element, mergeDiffAddBadParams) { + { + SCOPED_TRACE("root bad scalars"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(true); + ElementPtr right = Element::create("false"); + ASSERT_THROW(mergeDiffAdd(left, right, hierarchy, ""), TypeError); + } + { + SCOPED_TRACE("map bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::createList()); + right->set("elements", Element::createMap()); + ASSERT_THROW(mergeDiffAdd(left, right, hierarchy, "root"), TypeError); + } + { + SCOPED_TRACE("list bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::createMap()); + right_right->set("id", Element::create(0)); + right_right->set("elements", Element::createList()); + left->add(left_left); + right->add(right_right); + ASSERT_THROW(mergeDiffAdd(left, right, hierarchy, "root"), TypeError); + } +} + +/// @brief Test which checks that mergeDiffAdd works as expected. +TEST(Element, mergeDiffAdd) { + { + SCOPED_TRACE("scalar bool"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(true); + ElementPtr right = Element::create(false); + EXPECT_NE(left->boolValue(), right->boolValue()); + mergeDiffAdd(left, right, hierarchy, ""); + EXPECT_EQ(left->boolValue(), right->boolValue()); + std::string expected_str("false"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar int"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(1); + ElementPtr right = Element::create(2); + EXPECT_NE(left->intValue(), right->intValue()); + mergeDiffAdd(left, right, hierarchy, ""); + EXPECT_EQ(left->intValue(), right->intValue()); + std::string expected_str("2"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar double"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(0.1); + ElementPtr right = Element::create(0.2); + EXPECT_NE(left->doubleValue(), right->doubleValue()); + mergeDiffAdd(left, right, hierarchy, ""); + EXPECT_EQ(left->doubleValue(), right->doubleValue()); + std::string expected_str("0.2"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar string"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create("left"); + ElementPtr right = Element::create("right"); + EXPECT_NE(left->stringValue(), right->stringValue()); + mergeDiffAdd(left, right, hierarchy, ""); + EXPECT_EQ(left->stringValue(), right->stringValue()); + std::string expected_str("\"right\""); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::create("left")); + left->set("other-elements", Element::create("other")); + // scalar element which is updated + right->set("elements", Element::create("right")); + // scalar element which is added + right->set("new-elements", Element::create("new")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffAdd(left, right, hierarchy, ""); + std::string expected_str("{ \"elements\": \"right\", \"new-elements\": \"new\", \"other-elements\": \"other\" }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in list"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + left->add(Element::create("left")); + left->add(Element::create("other")); + left->add(Element::create("test")); + // scalar element which is added + right->add(Element::create("right")); + // scalar element which is added + right->add(Element::create("new")); + // scalar element which already exists but is still added + right->add(Element::create("test")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffAdd(left, right, hierarchy, ""); + std::string expected_str("[ \"left\", \"other\", \"test\", \"right\", \"new\", \"test\" ]"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar and list and map in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(0)); + // scalar element which is updated + right_right->set("elements", Element::create("right")); + // scalar element which is added + right_right->set("new-elements", Element::create("new")); + ElementPtr left_other_left = Element::createMap(); + ElementPtr right_other_right = Element::createMap(); + left_other_left->set("id", Element::create(1)); + left_other_left->set("elements", Element::create("other-left")); + // scalar element used as key + right_other_right->set("id", Element::create(2)); + // scalar element which is added + right_other_right->set("elements", Element::create("other-right")); + left->set("elements", left_left); + left->set("left-other-elements", left_other_left); + // map element which is added + right->set("right-other-elements", right_other_right); + // map element which is updated + right->set("elements", right_right); + left_other_left = Element::createList(); + right_other_right = Element::createList(); + left_other_left->add(Element::create("left-other-left")); + left_other_left->add(Element::create("left-other-left-other")); + left_other_left->add(Element::create("other-other")); + // scalar element which is added + right_other_right->add(Element::create("right-other-right")); + // scalar element which is added + right_other_right->add(Element::create("right-other-right-other")); + // scalar element which already exists but is still added + right_other_right->add(Element::create("other-other")); + left->set("other", left_other_left); + // list element which is updated + right->set("other", right_other_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffAdd(left, right, hierarchy, "root"); + std::string expected_str("{ \"elements\": { \"elements\": \"right\", \"id\": 0, \"new-elements\": \"new\", \"other-elements\": \"other\" }, " + "\"left-other-elements\": { \"elements\": \"other-left\", \"id\": 1 }, " + "\"other\": [ \"left-other-left\", \"left-other-left-other\", \"other-other\", \"right-other-right\", \"right-other-right-other\", \"other-other\" ], " + "\"right-other-elements\": { \"elements\": \"other-right\", \"id\": 2 } }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar and list and map in list"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(0)); + // scalar element which is updated + right_right->set("elements", Element::create("right")); + // scalar element which is added + right_right->set("new-elements", Element::create("new")); + ElementPtr left_other_left = Element::createMap(); + ElementPtr right_other_right = Element::createMap(); + left_other_left->set("id", Element::create(1)); + left_other_left->set("elements", Element::create("other-left")); + // scalar element used as key + right_other_right->set("id", Element::create(2)); + // scalar element which is added + right_other_right->set("elements", Element::create("other-right")); + left->add(left_left); + left->add(left_other_left); + // map element which is added + right->add(right_other_right); + // map element which is updated + right->add(right_right); + left_other_left = Element::createList(); + right_other_right = Element::createList(); + left_other_left->add(Element::create("left-other-left")); + left_other_left->add(Element::create("left-other-left-other")); + left_other_left->add(Element::create("other-other")); + // scalar element which is added + right_other_right->add(Element::create("right-other-right")); + // scalar element which is added + right_other_right->add(Element::create("right-other-right-other")); + // scalar element which already exists but is still added + right_other_right->add(Element::create("other-other")); + left_left->set("other", left_other_left); + // list element which is updated + right_right->set("other", right_other_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffAdd(left, right, hierarchy, "root"); + std::string expected_str("[ { \"elements\": \"right\", \"id\": 0, \"new-elements\": \"new\", " + "\"other\": [ \"left-other-left\", \"left-other-left-other\", \"other-other\", \"right-other-right\", \"right-other-right-other\", \"other-other\" ], " + "\"other-elements\": \"other\" }, " + "{ \"elements\": \"other-left\", \"id\": 1 }, " + "{ \"elements\": \"other-right\", \"id\": 2 } ]"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } +} + +/// @brief Test which checks that mergeDiffDel throws if called with wrong +/// element types. +TEST(Element, mergeDiffDelBadParams) { + { + SCOPED_TRACE("root bad scalars"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(true); + ElementPtr right = Element::create("false"); + ASSERT_THROW(mergeDiffDel(left, right, hierarchy, ""), TypeError); + } + { + SCOPED_TRACE("map bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::createList()); + right->set("elements", Element::createMap()); + ASSERT_THROW(mergeDiffDel(left, right, hierarchy, "root"), TypeError); + } + { + SCOPED_TRACE("list bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::createMap()); + right_right->set("id", Element::create(0)); + right_right->set("elements", Element::createList()); + left->add(left_left); + right->add(right_right); + ASSERT_THROW(mergeDiffDel(left, right, hierarchy, "root"), TypeError); + } +} + +/// @brief Test which checks that mergeDiffDel works as expected. +TEST(Element, mergeDiffDel) { + { + SCOPED_TRACE("scalar bool"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(true); + ElementPtr right = Element::create(false); + EXPECT_NE(left->boolValue(), right->boolValue()); + mergeDiffDel(left, right, hierarchy, ""); + EXPECT_EQ(left->getType(), Element::null); + } + { + SCOPED_TRACE("scalar int"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(1); + ElementPtr right = Element::create(2); + EXPECT_NE(left->intValue(), right->intValue()); + mergeDiffDel(left, right, hierarchy, ""); + EXPECT_EQ(left->getType(), Element::null); + } + { + SCOPED_TRACE("scalar double"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(0.1); + ElementPtr right = Element::create(0.2); + EXPECT_NE(left->doubleValue(), right->doubleValue()); + mergeDiffDel(left, right, hierarchy, ""); + EXPECT_EQ(left->getType(), Element::null); + } + { + SCOPED_TRACE("scalar string"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create("left"); + ElementPtr right = Element::create("right"); + EXPECT_NE(left->stringValue(), right->stringValue()); + mergeDiffDel(left, right, hierarchy, ""); + EXPECT_EQ(left->getType(), Element::null); + } + { + SCOPED_TRACE("scalar in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::create("left")); + left->set("other-elements", Element::create("other")); + // scalar element which is removed + right->set("elements", Element::create("right")); + // scalar element which does not exist and does nothing + right->set("new-elements", Element::create("new")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffDel(left, right, hierarchy, "root"); + std::string expected_str("{ \"other-elements\": \"other\" }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in list"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + left->add(Element::create("left")); + left->add(Element::create("other")); + left->add(Element::create("other-left")); + left->add(Element::create("new")); + // scalar element which does not exist and does nothing + right->add(Element::create("right")); + // scalar element which is removed + right->add(Element::create("other")); + // scalar element which does not exist and does nothing + right->add(Element::create("other-right")); + // scalar element which is removed + right->add(Element::create("new")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffDel(left, right, hierarchy, ""); + std::string expected_str("[ \"left\", \"other-left\" ]"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar and list and map in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(0)); + // scalar element which is removed + right_right->set("elements", Element::create("right")); + // scalar element which does not exist and does nothing + right_right->set("new-elements", Element::create("new")); + ElementPtr left_other_left = Element::createMap(); + ElementPtr right_other_right = Element::createMap(); + left_other_left->set("id", Element::create(1)); + left_other_left->set("elements", Element::create("other-left")); + // scalar element used as key + right_other_right->set("id", Element::create(2)); + // scalar element which does not exist and does nothing + right_other_right->set("elements", Element::create("other-right")); + left->set("elements", left_left); + left->set("left-other-elements", left_other_left); + // map element which does not exist and does nothing + right->set("right-other-elements", right_other_right); + // map element which is updated + right->set("elements", right_right); + left_other_left = Element::createList(); + right_other_right = Element::createList(); + left_other_left->add(Element::create("left-other-left")); + left_other_left->add(Element::create("other")); + left_other_left->add(Element::create("left-other-left-other")); + left_other_left->add(Element::create("new")); + // scalar element which does not exist and does nothing + right_other_right->add(Element::create("right-other-right")); + // scalar element which is removed + right_other_right->add(Element::create("other")); + // scalar element which does not exist and does nothing + right_other_right->add(Element::create("right-other-right-other")); + // scalar element which is removed + right_other_right->add(Element::create("new")); + left->set("other", left_other_left); + // list element which is updated + right->set("other", right_other_right); + left_left = Element::createMap(); + right_right = Element::createMap(); + left_left->set("id", Element::create(3)); + left_left->set("elements", Element::create("new-left")); + left_left->set("other-elements", Element::create("new-other")); + left->set("elements-other", left_left); + // scalar element used as key + right_right->set("id", Element::create(3)); + // map element which is not removed because it is contained in a map and + // the key can not be removed + right->set("elements-other", right_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffDel(left, right, hierarchy, "root"); + std::string expected_str("{ \"elements\": { \"id\": 0, \"other-elements\": \"other\" }, " + "\"elements-other\": { \"elements\": \"new-left\", \"id\": 3, \"other-elements\": \"new-other\" }, " + "\"left-other-elements\": { \"elements\": \"other-left\", \"id\": 1 }, " + "\"other\": [ \"left-other-left\", \"left-other-left-other\" ] }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar and list and map in list"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(0)); + // scalar element which is removed + right_right->set("elements", Element::create("right")); + // scalar element which does not exist and does nothing + right_right->set("new-elements", Element::create("new")); + ElementPtr left_other_left = Element::createMap(); + ElementPtr right_other_right = Element::createMap(); + left_other_left->set("id", Element::create(1)); + left_other_left->set("elements", Element::create("other-left")); + // scalar element used as key + right_other_right->set("id", Element::create(2)); + // scalar element which does not exist and does nothing + right_other_right->set("elements", Element::create("other-right")); + left->add(left_left); + left->add(left_other_left); + // map element which does not exist and does nothing + right->add(right_other_right); + // map element which is updated + right->add(right_right); + left_other_left = Element::createList(); + right_other_right = Element::createList(); + left_other_left->add(Element::create("left-other-left")); + left_other_left->add(Element::create("other")); + left_other_left->add(Element::create("left-other-left-other")); + left_other_left->add(Element::create("new")); + // scalar element which does not exist and does nothing + right_other_right->add(Element::create("right-other-right")); + // scalar element which is removed + right_other_right->add(Element::create("other")); + // scalar element which does not exist and does nothing + right_other_right->add(Element::create("right-other-right-other")); + // scalar element which is removed + right_other_right->add(Element::create("new")); + left_left->set("other", left_other_left); + // list element which is updated + right_right->set("other", right_other_right); + left_left = Element::createMap(); + right_right = Element::createMap(); + left_left->set("id", Element::create(3)); + left_left->set("elements", Element::create("new-left")); + left_left->set("other-elements", Element::create("new-other")); + left->add(left_left); + // scalar element used as key + right_right->set("id", Element::create(3)); + // map element which is removed by key + // the key can not be removed + right->add(right_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + mergeDiffDel(left, right, hierarchy, "root"); + std::string expected_str("[ { \"id\": 0, \"other\": [ \"left-other-left\", \"left-other-left-other\" ], \"other-elements\": \"other\" }, " + "{ \"elements\": \"other-left\", \"id\": 1 } ]"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } +} + +/// @brief Test which checks that extend throws if called with wrong element +/// types. +TEST(Element, extendBadParam) { + { + SCOPED_TRACE("root bad scalars"); + isc::data::HierarchyDescriptor hierarchy; + ElementPtr left = Element::create(true); + ElementPtr right = Element::create("false"); + ASSERT_THROW(extend("elements", "", left, right, hierarchy, ""), TypeError); + } + { + SCOPED_TRACE("map bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::createList()); + right->set("elements", Element::createMap()); + ASSERT_THROW(extend("elements", "", left, right, hierarchy, "root"), TypeError); + } + { + SCOPED_TRACE("list bad elements"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::createMap()); + right_right->set("id", Element::create(0)); + right_right->set("elements", Element::createList()); + left->add(left_left); + right->add(right_right); + ASSERT_THROW(extend("elements", "", left, right, hierarchy, "root"), TypeError); + } +} + +/// @brief Test which checks that extend works as expected. +TEST(Element, extend) { + { + SCOPED_TRACE("scalar in map but alter flag is not set"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(true); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::create("left")); + left->set("other-elements", Element::create("other")); + // scalar element which is not updated + right->set("elements", Element::create("right")); + // scalar element which is extended + right->set("new-elements", Element::create("new")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + extend("root", "new-elements", left, right, hierarchy, "root", 0, false); + std::string expected_str("{ \"elements\": \"left\", \"other-elements\": \"other\" }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(true); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + left->set("elements", Element::create("left")); + left->set("other-elements", Element::create("other")); + // scalar element which is not updated + right->set("elements", Element::create("right")); + // scalar element which is extended + right->set("new-elements", Element::create("new")); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + extend("root", "new-elements", left, right, hierarchy, "root", 0, true); + std::string expected_str("{ \"elements\": \"left\", \"new-elements\": \"new\", \"other-elements\": \"other\" }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in map in map"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(true); + ElementPtr left = Element::createMap(); + ElementPtr right = Element::createMap(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(1)); + // scalar element which is not updated + right_right->set("elements", Element::create("right")); + // scalar element which is extended + right_right->set("new-elements", Element::create("new")); + left->set("elements", left_left); + // map element which is used for extension + right->set("elements", right_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + extend("root", "new-elements", left, right, hierarchy, "root"); + std::string expected_str("{ \"elements\": { \"elements\": \"left\", \"id\": 0, \"new-elements\": \"new\", \"other-elements\": \"other\" } }"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } + { + SCOPED_TRACE("scalar in map in list"); + isc::data::HierarchyDescriptor hierarchy; + hierarchy = createHierarchy(true); + ElementPtr left = Element::createList(); + ElementPtr right = Element::createList(); + ElementPtr left_left = Element::createMap(); + ElementPtr right_right = Element::createMap(); + left_left->set("id", Element::create(0)); + left_left->set("elements", Element::create("left")); + left_left->set("other-elements", Element::create("other")); + // scalar element used as key + right_right->set("id", Element::create(1)); + // scalar element which is not updated + right_right->set("elements", Element::create("right")); + // scalar element which is extended + right_right->set("new-elements", Element::create("new")); + left->add(left_left); + // map element which is used for extension + right->add(right_right); + ASSERT_FALSE(isc::data::isEquivalent(left, right)); + extend("root", "new-elements", left, right, hierarchy, "root"); + std::string expected_str("[ { \"elements\": \"left\", \"id\": 0, \"new-elements\": \"new\", \"other-elements\": \"other\" } ]"); + ElementPtr expected = Element::fromJSON(expected_str); + EXPECT_TRUE(isc::data::isEquivalent(left, expected)) + << "Actual: " << left->str() + << "\nExpected: " << expected->str(); + } +} + +} // namespace diff --git a/src/lib/cc/tests/element_value_unittests.cc b/src/lib/cc/tests/element_value_unittests.cc new file mode 100644 index 0000000..e284440 --- /dev/null +++ b/src/lib/cc/tests/element_value_unittests.cc @@ -0,0 +1,43 @@ +// Copyright (C) 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 <cc/element_value.h> +#include <gtest/gtest.h> + +using namespace isc::data; + +namespace { + +// This test verifies that integer value can be extracted. +TEST(ElementValue, intValue) { + EXPECT_EQ(5, ElementValue<int>()(Element::create(5))); + EXPECT_THROW(ElementValue<int>()(Element::create("hola!")), + TypeError); +} + +// This test verifies that double value can be extracted. +TEST(ElementValue, doubleValue) { + EXPECT_EQ(1.4, ElementValue<double>()(Element::create(1.4))); + EXPECT_THROW(ElementValue<double>()(Element::create("hola!")), + TypeError); +} + +// This test verifies that boolean value can be extracted. +TEST(ElementValue, boolValue) { + EXPECT_TRUE(ElementValue<bool>()(Element::create(true))); + EXPECT_THROW(ElementValue<bool>()(Element::create("hola!")), + TypeError); +} + +// This test verifies that string value can be extracted. +TEST(ElementValue, stringValue) { + EXPECT_EQ("hola!", ElementValue<std::string>()(Element::create("hola!"))); + EXPECT_THROW(ElementValue<std::string>()(Element::create(false)), + TypeError); +} + +} diff --git a/src/lib/cc/tests/json_feed_unittests.cc b/src/lib/cc/tests/json_feed_unittests.cc new file mode 100644 index 0000000..747d142 --- /dev/null +++ b/src/lib/cc/tests/json_feed_unittests.cc @@ -0,0 +1,453 @@ +// Copyright (C) 2017-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 <cc/data.h> +#include <cc/json_feed.h> +#include <gtest/gtest.h> +#include <sstream> +#include <string> + +using namespace isc::config; +using namespace isc::data; + +namespace { + +/// @brief Test fixture class for @ref JSONFeed class. +class JSONFeedTest : public ::testing::Test { +public: + + /// @brief Constructor. + /// + /// Initializes @ref json_map_ and @ref json_list_ which hold reference + /// JSON structures. + JSONFeedTest() + : json_map_(), json_list_() { + ElementPtr m = Element::fromJSON(createJSON()); + ElementPtr l = Element::createList(); + l->add(m); + json_map_ = m; + json_list_ = l; + } + + /// @brief Creates a JSON map holding 20 elements. + /// + /// Each map value is a list of 20 elements. + std::string createJSON() const { + // Create a list of 20 elements. + ElementPtr list_element = Element::createList(); + for (unsigned i = 0; i < 20; ++i) { + std::ostringstream s; + s << "list_element" << i; + list_element->add(Element::create(s.str())); + } + + // Create a map of 20 elements. Each map element holds a list + // of 20 elements. + ElementPtr map_element = Element::createMap(); + for (unsigned i = 0; i < 20; ++i) { + std::ostringstream s; + s << "map_element" << i; + map_element->set(s.str(), list_element); + } + + return (prettyPrint(map_element)); + } + + /// @brief Test that the JSONFeed correctly recognizes the beginning + /// and the end of the JSON structure. + /// + /// @param input_json A string holding an input JSON structure. + /// @param expected_output A structure holding expected output from the + /// @ref JSONFeed::toElement. + void testRead(const std::string& input_json, + const ConstElementPtr& expected_output) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + + // Post the data into the feed in 10 bytes long chunks. + size_t chunk = 10; + + for (size_t i = 0; i < input_json.size(); i += chunk) { + bool done = false; + // When we're near the end of the data stream, the chunk length may + // vary. + if (i + chunk >= input_json.size()) { + chunk = input_json.size() - i; + done = true; + } + // Feed the parser with a data chunk and parse it. + feed.postBuffer(&input_json[i], chunk); + feed.poll(); + if (!done) { + ASSERT_TRUE(feed.needData()); + } + } + + // Convert parsed/collected data in the feed into the structure of + // elements. + ConstElementPtr element_from_feed = feed.toElement(); + EXPECT_TRUE(element_from_feed->equals(*expected_output)); + } + + /// @brief Test that the JSONFeed correctly recognizes the beginning + /// and the end of the JSON structure. + /// + /// @param input_json A string holding an input JSON structure. + /// @param expected_output A string holding expected output from the + /// @ref JSONFeed::getProcessedText. + void testRead(const std::string& input_json, + const std::string& expected_output) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + + // Post the data into the feed in 10 bytes long chunks. + size_t chunk = 10; + + for (size_t i = 0; i < input_json.size(); i += chunk) { + bool done = false; + // When we're near the end of the data stream, the chunk length may + // vary. + if (i + chunk >= input_json.size()) { + chunk = input_json.size() - i; + done = true; + } + // Feed the parser with a data chunk and parse it. + feed.postBuffer(&input_json[i], chunk); + feed.poll(); + if (!done) { + ASSERT_TRUE(feed.needData()); + } + } + + EXPECT_EQ(expected_output, feed.getProcessedText()); + } + + /// @brief Test that the @ref JSONFeed signals an error when the input + /// string holds invalid data. + /// + /// @param input_json A string holding an input JSON structure. + /// @param err_msg A string holding an expected error message. + void testInvalidRead(const std::string& input_json, + const std::string& err_msg) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + + ASSERT_NO_THROW(feed.postBuffer(&input_json[0], input_json.size())); + ASSERT_NO_THROW(feed.poll()); + + EXPECT_FALSE(feed.needData()); + EXPECT_FALSE(feed.feedOk()); + + EXPECT_EQ(err_msg, feed.getErrorMessage()); + } + + /// @brief JSON map holding a number of lists. + ConstElementPtr json_map_; + + /// @brief JSON list holding a map of lists. + ConstElementPtr json_list_; + +}; + +// This test verifies that toElement should not be called before +// the feed detects the end of the data stream. +TEST_F(JSONFeedTest, toElementTooSoon) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{\n"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_TRUE(feed.needData()); + EXPECT_THROW(feed.toElement(), JSONFeedError); +} + +// This test verifies that toElement checks JSON syntax as a side effect. +TEST_F(JSONFeedTest, badJSON) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{\n]\n"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_THROW(feed.toElement(), JSONFeedError); +} + +// This test verifies that a JSON structure starting with '{' is accepted +// and parsed. +TEST_F(JSONFeedTest, startWithBrace) { + std::string json = createJSON(); + testRead(json, json_map_); +} + +// This test verifies that a JSON structure starting with '[' is accepted +// and parsed. +TEST_F(JSONFeedTest, startWithSquareBracket) { + std::string json = createJSON(); + json = std::string("[") + json + std::string("]"); + testRead(json, json_list_); +} + +// This test verifies that input JSON can be preceded with whitespaces. +TEST_F(JSONFeedTest, startWithWhitespace) { + std::string json = createJSON(); + json = std::string(" \r\r\t ") + json; + testRead(json, json_map_); +} + +// This test verifies that an empty map is accepted and parsed. +TEST_F(JSONFeedTest, emptyMap) { + std::string json = "{}"; + testRead(json, Element::createMap()); +} + +// This test verifies that an empty list is accepted and parsed. +TEST_F(JSONFeedTest, emptyList) { + std::string json = "[ ]"; + testRead(json, Element::createList()); +} + +// This test verifies that an error is signalled when a JSON structure +// is preceded by invalid character. +TEST_F(JSONFeedTest, unexpectedFirstCharacter) { + std::string json = "a {}"; + std::string err_msg = "invalid first character a"; + testInvalidRead(json, err_msg); +} + +// This test verifies that an error is signalled when a JSON structure +// is preceded by white spaces and an invalid character. +TEST_F(JSONFeedTest, unexpectedCharacter) { + std::string json = " a {}"; + std::string err_msg = "invalid character a"; + testInvalidRead(json, err_msg); +} + +// This test verifies that an error is signalled when the JSON structure +// begins by a string. +TEST_F(JSONFeedTest, stringFirst) { + std::string json = "\"foo\""; + std::string err_msg = "invalid first character \""; + testInvalidRead(json, err_msg); +} + +// This test verifies that an error is signalled when the JSON structure +// begins by white spaces followed by a string. +TEST_F(JSONFeedTest, stringBefore) { + std::string json = " \"foo\""; + std::string err_msg = "invalid character \""; + testInvalidRead(json, err_msg); +} + +// This test verifies that an error is signalled when a JSON structure +// lacks an opening brace character. +TEST_F(JSONFeedTest, noOpeningBrace) { + std::string json = "\"x\": \"y\" }"; + std::string err_msg = "invalid first character \""; + testInvalidRead(json, err_msg); +} + +// This test verifies that an error is signalled when a JSON structure +// lacks an opening square bracket. +TEST_F(JSONFeedTest, noOpeningSquareBracket) { + std::string json = "1, 2 ]"; + std::string err_msg = "invalid first character 1"; + testInvalidRead(json, err_msg); +} + +// This test verifies that a string is correctly handled +TEST_F(JSONFeedTest, string) { + std::string json = "{ \"braces\": \"}}}}\" }"; + ElementPtr expected = Element::createMap(); + expected->set("braces", Element::create("}}}}")); + testRead(json, expected); +} + +// This test verifies that a string with escapes is correctly handled +TEST_F(JSONFeedTest, escape) { + std::string json = "{ \"escapes\": \"\\n\\t\\\"\\\\\" }"; + ElementPtr expected = Element::createMap(); + expected->set("escapes", Element::create("\n\t\"\\")); + testRead(json, expected); +} + +// This test verifies that white spaces before JSON are ignored. +TEST_F(JSONFeedTest, whiteSpaceBefore) { + std::string json = " \n [ ]\n"; + std::string expected = "[ ]"; + testRead(json, expected); +} + +// This test verifies that bash style comments before JSON are ignored. +TEST_F(JSONFeedTest, bashCommentBefore) { + std::string json = "# ahah\n # foo\"bar\n{ }\n"; + std::string expected = "{ }"; + testRead(json, expected); +} + +// This test verifies that C++ style comments before JSON are ignored. +TEST_F(JSONFeedTest, cppCommentBefore) { + std::string json = "// ahah\n // foo\"bar\n[ 12 ]\n"; + std::string expected = "[ 12 ]"; + testRead(json, expected); +} + +// This test verifies that multi-line comments before JSON are ignored. +TEST_F(JSONFeedTest, multiLineCommentBefore) { + std::string json = "/* ahah\n \"// foo*bar**/\n { \"foo\": \"bar\" }\n"; + std::string expected = "{ \"foo\": \"bar\" }"; + testRead(json, expected); +} + +// This test verifies that an error is signalled when a slash does not +// begin a C++ or C style comment before JSON. +TEST_F(JSONFeedTest, badCommentBefore) { + std::string json = "/# foo\n [ ]\n"; + std::string err_msg = "invalid characters /#"; + testInvalidRead(json, err_msg); +} + +// This test verifies that bash style comments are ignored. +TEST_F(JSONFeedTest, bashComments) { + std::string json = "{ # ahah\n \"foo\": # value?\n \"bar\" }"; + std::string expected = "{ \n \"foo\": \n \"bar\" }"; + testRead(json, expected); +} + +// This test verifies that C++ style comments are ignored. +TEST_F(JSONFeedTest, cppComments) { + std::string json = "[ // ahah\n \"foo\", /// value?\n \"bar\" ]"; + std::string expected = "[ \n \"foo\", \n \"bar\" ]"; + testRead(json, expected); +} + +// This test verifies that multi-line comments are ignored. +TEST_F(JSONFeedTest, multiLineComments) { + std::string json = "{ /* ahah\n \"// foo*bar**/\n \"foo\": \"bar\" }\n"; + std::string expected = "{ \n\n \"foo\": \"bar\" }"; + testRead(json, expected); +} + +// This test verifies that an error is signalled a slash does not begin +// a C++ or C style comment. +TEST_F(JSONFeedTest, badComment) { + std::string json = "[ /# foo\n ]\n"; + std::string err_msg = "invalid characters /#"; + testInvalidRead(json, err_msg); +} + +// This test verifies that trailing garbage is ignored. +TEST_F(JSONFeedTest, trailing) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "[ 1, 2] 3, 4]"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_TRUE(feed.feedOk()); + std::string expected = "[ 1, 2]"; + EXPECT_EQ(expected, feed.getProcessedText()); +} + +// Example from DHCPv4 unit tests. +TEST_F(JSONFeedTest, bashComment4) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "},\n" + "# this is a comment\n" + "\"rebind-timer\": 2000, \n" + "# lots of comments here\n" + "# and here\n" + "\"renew-timer\": 1000, \n" + "\"subnet4\": [ { " + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"subnet\": \"192.0.2.0/24\", " + " \"id\": 1, " + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 } }"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_TRUE(feed.feedOk()); + EXPECT_NO_THROW(feed.toElement()); +} + +// Example from DHCPv4 unit tests. +TEST_F(JSONFeedTest, bashCommentsInline4) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{ \"Dhcp4\": { \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "},\n" + "\"rebind-timer\": 2000, # everything after # is ignored\n" + "\"renew-timer\": 1000, # this will be ignored, too\n" + "\"subnet4\": [ { " + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ]," + " \"subnet\": \"192.0.2.0/24\", " + " \"id\": 1, " + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 } }"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_TRUE(feed.feedOk()); + EXPECT_NO_THROW(feed.toElement()); +} + +// Example from DHCPv6 unit tests. +TEST_F(JSONFeedTest, cppComments6) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "},\n" + "\"preferred-lifetime\": 3000, // this is a comment \n" + "\"rebind-timer\": 2000, // everything after // is ignored\n" + "\"renew-timer\": 1000, // this will be ignored, too\n" + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"id\": 1, " + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 } }"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_TRUE(feed.feedOk()); + EXPECT_NO_THROW(feed.toElement()); +} + +// Example from DHCPv6 unit tests. +TEST_F(JSONFeedTest, multilineComments6) { + JSONFeed feed; + ASSERT_NO_THROW(feed.initModel()); + std::string json = "{ \"Dhcp6\": { \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "},\n" + "\"preferred-lifetime\": 3000, /* this is a C style comment\n" + "that\n can \n span \n multiple \n lines */ \n" + "\"rebind-timer\": 2000,\n" + "\"renew-timer\": 1000, \n" + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"id\": 1, " + " \"interface\": \"eth0\"" + " } ]," + "\"valid-lifetime\": 4000 } }"; + feed.postBuffer(&json[0], json.size()); + feed.poll(); + EXPECT_FALSE(feed.needData()); + EXPECT_TRUE(feed.feedOk()); + EXPECT_NO_THROW(feed.toElement()); +} + +} // end of anonymous namespace. diff --git a/src/lib/cc/tests/run_unittests.cc b/src/lib/cc/tests/run_unittests.cc new file mode 100644 index 0000000..40c051f --- /dev/null +++ b/src/lib/cc/tests/run_unittests.cc @@ -0,0 +1,20 @@ +// Copyright (C) 2009-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 <log/logger_support.h> + +int +main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + isc::log::initLogger(); + + return (isc::util::unittests::run_all()); +} diff --git a/src/lib/cc/tests/server_tag_unittest.cc b/src/lib/cc/tests/server_tag_unittest.cc new file mode 100644 index 0000000..523be74 --- /dev/null +++ b/src/lib/cc/tests/server_tag_unittest.cc @@ -0,0 +1,97 @@ +// Copyright (C) 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 <cc/server_tag.h> +#include <exceptions/exceptions.h> +#include <boost/scoped_ptr.hpp> +#include <gtest/gtest.h> +#include <string> + +using namespace isc; +using namespace isc::data; + +namespace { + +// This test verifies that the constructors of the ServerTag class +// work properly. +TEST(ServerTagTest, constructors) { + boost::scoped_ptr<ServerTag> tag; + + { + SCOPED_TRACE("default constructor for all servers"); + ASSERT_NO_THROW(tag.reset(new ServerTag())); + EXPECT_EQ(ServerTag::ALL, tag->get()); + EXPECT_TRUE(tag->amAll()); + } + + { + SCOPED_TRACE("all servers"); + ASSERT_NO_THROW(tag.reset(new ServerTag(ServerTag::ALL))); + EXPECT_EQ(ServerTag::ALL, tag->get()); + EXPECT_TRUE(tag->amAll()); + } + + { + SCOPED_TRACE("no whitespace"); + ASSERT_NO_THROW(tag.reset(new ServerTag("xyz"))); + EXPECT_EQ("xyz", tag->get()); + EXPECT_FALSE(tag->amAll()); + } + + { + SCOPED_TRACE("leading whitespace"); + ASSERT_NO_THROW(tag.reset(new ServerTag(" left"))); + EXPECT_EQ("left", tag->get()); + EXPECT_FALSE(tag->amAll()); + } + + { + SCOPED_TRACE("terminating whitespace"); + ASSERT_NO_THROW(tag.reset(new ServerTag("right "))); + EXPECT_EQ("right", tag->get()); + EXPECT_FALSE(tag->amAll()); + } + + { + SCOPED_TRACE("leading and terminating whitespace"); + ASSERT_NO_THROW(tag.reset(new ServerTag(" both left-right "))); + EXPECT_EQ("both left-right", tag->get()); + EXPECT_FALSE(tag->amAll()); + } + + { + SCOPED_TRACE("upper to lower case"); + ASSERT_NO_THROW(tag.reset(new ServerTag("UPPER CASE TAG"))); + EXPECT_EQ("upper case tag", tag->get()); + EXPECT_FALSE(tag->amAll()); + } +} + +// This test verifies that malformed server tags are rejected. +TEST(ServerTagTest, malformed) { + { + SCOPED_TRACE("empty tag"); + EXPECT_THROW(ServerTag(""), BadValue); + } + + { + SCOPED_TRACE("only whitespaces"); + EXPECT_THROW(ServerTag(" "), BadValue); + } + + { + SCOPED_TRACE("too long tag, max is 256"); + EXPECT_THROW(ServerTag(std::string(257, 'c')), BadValue); + } + + { + SCOPED_TRACE("use reserved keyword any as a tag"); + EXPECT_THROW(ServerTag("any"), BadValue); + } +} + +} diff --git a/src/lib/cc/tests/simple_parser_unittest.cc b/src/lib/cc/tests/simple_parser_unittest.cc new file mode 100644 index 0000000..76e5ffc --- /dev/null +++ b/src/lib/cc/tests/simple_parser_unittest.cc @@ -0,0 +1,364 @@ +// Copyright (C) 2016-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 <stdint.h> +#include <cc/simple_parser.h> +#include <gtest/gtest.h> + +using namespace isc; +using namespace isc::data; +using namespace isc::asiolink; +using isc::dhcp::DhcpConfigError; + +/// This list defines required keywords. +const SimpleRequiredKeywords REQUIRED_KEYWORDS = { "foobar" }; + +/// This table defines keywords and types. +const SimpleKeywords KEYWORDS = { + { "id", Element::integer }, + { "prefix", Element::string }, + { "map", Element::map }, + { "any", Element::any } +}; + +/// This table defines sample default values. Although these are DHCPv6 +/// specific, the mechanism is generic and can be used by any other component. +const SimpleDefaults SAMPLE_DEFAULTS = { + { "renew-timer", Element::integer, "900" }, + { "rebind-timer", Element::integer, "1800" }, + { "preferred-lifetime", Element::integer, "3600" }, + { "valid-lifetime", Element::integer, "7200" } +}; + +/// This list defines parameters that can be inherited from one scope +/// to another. Although these are DHCPv6 specific, the mechanism is generic and +/// can be used by any other component. +const ParamsList SAMPLE_INHERITS = { + "renew-timer", + "rebind-timer", + "preferred-lifetime", + "valid-lifetime" +}; + +/// @brief Simple Parser test fixture class +class SimpleParserTest : public ::testing::Test { +public: + /// @brief Checks if specified map has an integer parameter with expected value + /// + /// @param map map to be checked + /// @param param_name name of the parameter to be checked + /// @param exp_value expected value of the parameter. + void checkIntegerValue(const ConstElementPtr& map, const std::string& param_name, + int64_t exp_value) { + + // First check if the passed element is a map. + ASSERT_EQ(Element::map, map->getType()); + + // Now try to get the element being checked + ConstElementPtr elem = map->get(param_name); + ASSERT_TRUE(elem); + + // Now check if it's indeed integer + ASSERT_EQ(Element::integer, elem->getType()); + + // Finally, check if its value meets expectation. + EXPECT_EQ(exp_value, elem->intValue()); + } +}; + +class SimpleParserClassTest : public SimpleParser { +public: + /// @brief Instantiation of getAndConvert + /// + /// @param scope specified parameter will be extracted from this scope + /// @param name name of the parameter for error report + /// @return a bool value + bool getAsBool(ConstElementPtr scope, const std::string& name) { + return (getAndConvert<bool, toBool>(scope, name, "boolean")); + } + + /// @brief Convert to boolean + /// + /// @param str the string "false" or "true" + /// @return false for "false" and true for "true" + /// @thrown isc::OutOfRange if not "false" or "true' + static bool toBool(const std::string& str) { + if (str == "false") { + return (false); + } else if (str == "true") { + return (true); + } else { + isc_throw(TypeError, "not a boolean: " << str); + } + } +}; + +// This test checks if the checkRequired method works as expected. +TEST_F(SimpleParserTest, checkRequired) { + ConstElementPtr empty = Element::fromJSON("{ }"); + EXPECT_THROW(SimpleParser::checkRequired(REQUIRED_KEYWORDS, empty), + DhcpConfigError); + ConstElementPtr other = Element::fromJSON("{ \"foo\": 1, \"bar\": 2 }"); + EXPECT_THROW(SimpleParser::checkRequired(REQUIRED_KEYWORDS, other), + DhcpConfigError); + ConstElementPtr good = Element::fromJSON("{ \"foobar\": 2 }"); + EXPECT_NO_THROW(SimpleParser::checkRequired(REQUIRED_KEYWORDS, good)); +} + +// This test checks if the checkKeywords method works as expected. +TEST_F(SimpleParserTest, checkKeywords) { + ConstElementPtr empty = Element::fromJSON("{ }"); + EXPECT_NO_THROW(SimpleParser::checkKeywords(KEYWORDS, empty)); + ConstElementPtr id = Element::fromJSON("{ \"id\": 1 }"); + EXPECT_NO_THROW(SimpleParser::checkKeywords(KEYWORDS, id)); + ConstElementPtr any = Element::fromJSON("{ \"any\": 1 }"); + EXPECT_NO_THROW(SimpleParser::checkKeywords(KEYWORDS, any)); + ConstElementPtr bad_id = Element::fromJSON("{ \"id\": true }"); + EXPECT_THROW(SimpleParser::checkKeywords(KEYWORDS, bad_id), + DhcpConfigError); + ConstElementPtr bad_prefix = Element::fromJSON("{ \"prefix\": 12 }"); + EXPECT_THROW(SimpleParser::checkKeywords(KEYWORDS, bad_prefix), + DhcpConfigError); + ConstElementPtr bad_map = Element::fromJSON("{ \"map\": [ ] }"); + EXPECT_THROW(SimpleParser::checkKeywords(KEYWORDS, bad_map), + DhcpConfigError); + ConstElementPtr spurious = Element::fromJSON("{ \"spurious\": 1 }"); + EXPECT_THROW(SimpleParser::checkKeywords(KEYWORDS, spurious), + DhcpConfigError); + + // Bad type has precedence. + ConstElementPtr bad = Element::fromJSON("{ \"spurious\": 1, \"id\": true }"); + try { + SimpleParser::checkKeywords(KEYWORDS, bad); + ADD_FAILURE() << "expect exception"; + } catch (const DhcpConfigError& ex) { + EXPECT_EQ("'id' parameter is not an integer", std::string(ex.what())); + } catch (...) { + ADD_FAILURE() << "expect DhcpConfigError"; + } +} + +// This test checks if the parameters can be inherited from the global +// scope to the subnet scope. +TEST_F(SimpleParserTest, deriveParams) { + ElementPtr global = Element::fromJSON("{ \"renew-timer\": 1," + " \"rebind-timer\": 2," + " \"preferred-lifetime\": 3," + " \"valid-lifetime\": 4" + "}"); + ElementPtr subnet = Element::fromJSON("{ \"renew-timer\": 100 }"); + + // we should inherit 3 parameters. Renew-timer should remain intact, + // as it was already defined in the subnet scope. + size_t num; + EXPECT_NO_THROW(num = SimpleParser::deriveParams(global, subnet, + SAMPLE_INHERITS)); + EXPECT_EQ(3, num); + + // Check the values. 3 of them are inherited, while the fourth one + // was already defined in the subnet, so should not be inherited. + checkIntegerValue(subnet, "renew-timer", 100); + checkIntegerValue(subnet, "rebind-timer", 2); + checkIntegerValue(subnet, "preferred-lifetime", 3); + checkIntegerValue(subnet, "valid-lifetime", 4); +} + +// This test checks if global defaults are properly set for DHCPv6. +TEST_F(SimpleParserTest, setDefaults) { + + ElementPtr empty = Element::fromJSON("{ }"); + size_t num = 0; + + EXPECT_NO_THROW(num = SimpleParser::setDefaults(empty, SAMPLE_DEFAULTS)); + + // We expect at least 4 parameters to be inserted. + EXPECT_GE(num, 3); + + checkIntegerValue(empty, "valid-lifetime", 7200); + checkIntegerValue(empty, "preferred-lifetime", 3600); + checkIntegerValue(empty, "rebind-timer", 1800); + checkIntegerValue(empty, "renew-timer", 900); +} + +// This test checks if global defaults are properly set for DHCPv6. +TEST_F(SimpleParserTest, setListDefaults) { + + ElementPtr empty = Element::fromJSON("[{}, {}, {}]"); + size_t num; + + EXPECT_NO_THROW(num = SimpleParser::setListDefaults(empty, SAMPLE_DEFAULTS)); + + // We expect at least 12 parameters to be inserted (3 entries, with + // 4 parameters inserted in each) + EXPECT_EQ(12, num); + + ASSERT_EQ(Element::list, empty->getType()); + ASSERT_EQ(3, empty->size()); + + ConstElementPtr first = empty->get(0); + ConstElementPtr second = empty->get(1); + ConstElementPtr third = empty->get(2); + + checkIntegerValue(first, "valid-lifetime", 7200); + checkIntegerValue(first, "preferred-lifetime", 3600); + checkIntegerValue(first, "rebind-timer", 1800); + checkIntegerValue(first, "renew-timer", 900); + + checkIntegerValue(second, "valid-lifetime", 7200); + checkIntegerValue(second, "preferred-lifetime", 3600); + checkIntegerValue(second, "rebind-timer", 1800); + checkIntegerValue(second, "renew-timer", 900); + + checkIntegerValue(third, "valid-lifetime", 7200); + checkIntegerValue(third, "preferred-lifetime", 3600); + checkIntegerValue(third, "rebind-timer", 1800); + checkIntegerValue(third, "renew-timer", 900); +} + +// This test exercises the getIntType template +TEST_F(SimpleParserTest, getIntType) { + + SimpleParserClassTest parser; + + // getIntType checks it can be found + ElementPtr not_found = Element::fromJSON("{ \"bar\": 1 }"); + EXPECT_THROW(parser.getUint8(not_found, "foo"), DhcpConfigError); + + // getIntType checks if it is an integer + ElementPtr not_int = Element::fromJSON("{ \"foo\": \"xyz\" }"); + EXPECT_THROW(parser.getUint8(not_int, "foo"), DhcpConfigError); + + // getIntType checks bounds + ElementPtr negative = Element::fromJSON("{ \"foo\": -1 }"); + EXPECT_THROW(parser.getUint8(negative, "foo"), DhcpConfigError); + ElementPtr too_large = Element::fromJSON("{ \"foo\": 1024 }"); + EXPECT_THROW(parser.getUint8(too_large, "foo"), DhcpConfigError); + + // checks if getIntType can return the expected value + ElementPtr hundred = Element::fromJSON("{ \"foo\": 100 }"); + uint8_t val = 0; + EXPECT_NO_THROW(val = parser.getUint8(hundred, "foo")); + EXPECT_EQ(100, val); +} + +// This test exercises the getInteger with range checking +TEST_F(SimpleParserTest, getInteger) { + + // The value specified is 100. + ElementPtr json = Element::fromJSON("{ \"bar\": 100 }"); + int64_t x = -1; + + // Positive case: we expect value in range 0..200. All ok. + EXPECT_NO_THROW(x = SimpleParser::getInteger(json, "bar", 0, 200)); + EXPECT_EQ(100, x); + + // Border checks: 100 for 100..200 range is still ok. + EXPECT_NO_THROW(x = SimpleParser::getInteger(json, "bar", 100, 200)); + // Border checks: 100 for 1..100 range is still ok. + EXPECT_NO_THROW(x = SimpleParser::getInteger(json, "bar", 1, 100)); + + // Out of expected range. Should throw. + EXPECT_THROW(x = SimpleParser::getInteger(json, "bar", 101, 200), OutOfRange); + EXPECT_THROW(x = SimpleParser::getInteger(json, "bar", 1, 99), OutOfRange); +} + +// This test exercises the getAndConvert template +TEST_F(SimpleParserTest, getAndConvert) { + + SimpleParserClassTest parser; + + // getAndConvert checks it can be found + ElementPtr not_found = Element::fromJSON("{ \"bar\": \"true\" }"); + EXPECT_THROW(parser.getAsBool(not_found, "foo"), DhcpConfigError); + + // getAndConvert checks if it is a string + ElementPtr not_bool = Element::fromJSON("{ \"foo\": 1 }"); + EXPECT_THROW(parser.getAsBool(not_bool, "foo"), DhcpConfigError); + + // checks if getAndConvert can return the expected value + ElementPtr a_bool = Element::fromJSON("{ \"foo\": \"false\" }"); + bool val = true; + EXPECT_NO_THROW(val = parser.getAsBool(a_bool, "foo")); + EXPECT_FALSE(val); + + // getAndConvert checks conversion + ElementPtr bad_bool = Element::fromJSON("{ \"foo\": \"bar\" }"); + EXPECT_THROW(parser.getAsBool(bad_bool, "bar"), DhcpConfigError); +} + +// This test exercises the getIOAddress +TEST_F(SimpleParserTest, getIOAddress) { + + SimpleParserClassTest parser; + + // getAddress checks it can be found + ElementPtr not_found = Element::fromJSON("{ \"bar\": 1 }"); + EXPECT_THROW(parser.getAddress(not_found, "foo"), DhcpConfigError); + + // getAddress checks if it is a string + ElementPtr not_addr = Element::fromJSON("{ \"foo\": 1234 }"); + EXPECT_THROW(parser.getAddress(not_addr, "foo"), DhcpConfigError); + + // checks if getAddress can return the expected value of v4 address + ElementPtr v4 = Element::fromJSON("{ \"foo\": \"192.0.2.1\" }"); + IOAddress val("::"); + EXPECT_NO_THROW(val = parser.getAddress(v4, "foo")); + EXPECT_EQ("192.0.2.1" , val.toText()); + + // checks if getAddress can return the expected value of v4 address + ElementPtr v6 = Element::fromJSON("{ \"foo\": \"2001:db8::1\" }"); + EXPECT_NO_THROW(val = parser.getAddress(v6, "foo")); + EXPECT_EQ("2001:db8::1" , val.toText()); +} + +// This test exercises getDouble() +TEST_F(SimpleParserTest, getDouble) { + + SimpleParserClassTest parser; + std::string json = + "{\n" + " \"string\" : \"12.3\",\n" + " \"bool\" : true, \n" + " \"int\" : 777, \n" + " \"map\" : {}, \n" + " \"list\" : [], \n" + " \"zero\" : 0.0, \n" + " \"fraction\" : .75, \n" + " \"negative\" : -1.45, \n" + " \"positive\" : 346.7 \n" + "}\n"; + + // Create our test set of parameters. + ElementPtr elems; + ASSERT_NO_THROW(elems = Element::fromJSON(json)) << " invalid JSON, test is broken"; + + // Verify that a non-existant element is caught. + EXPECT_THROW(parser.getDouble(elems, "not-there"), DhcpConfigError); + + // Verify that wrong element types are caught. + EXPECT_THROW(parser.getDouble(elems, "string"), DhcpConfigError); + EXPECT_THROW(parser.getDouble(elems, "int"), DhcpConfigError); + EXPECT_THROW(parser.getDouble(elems, "bool"), DhcpConfigError); + EXPECT_THROW(parser.getDouble(elems, "map"), DhcpConfigError); + EXPECT_THROW(parser.getDouble(elems, "list"), DhcpConfigError); + + // Verify valid values are correct. + double value; + + EXPECT_NO_THROW(value = parser.getDouble(elems, "zero")); + EXPECT_EQ(0.0, value); + + EXPECT_NO_THROW(value = parser.getDouble(elems, "fraction")); + EXPECT_EQ(.75, value); + + EXPECT_NO_THROW(value = parser.getDouble(elems, "negative")); + EXPECT_EQ(-1.45, value); + + EXPECT_NO_THROW(value = parser.getDouble(elems, "positive")); + EXPECT_EQ(346.7, value); +} diff --git a/src/lib/cc/tests/stamped_element_unittest.cc b/src/lib/cc/tests/stamped_element_unittest.cc new file mode 100644 index 0000000..1ffcd84 --- /dev/null +++ b/src/lib/cc/tests/stamped_element_unittest.cc @@ -0,0 +1,132 @@ +// Copyright (C) 2018-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 <cc/stamped_element.h> +#include <boost/date_time/gregorian/gregorian.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <gtest/gtest.h> + +using namespace isc::data; + +namespace { + +// Tests that the modification timestamp is by default set to current +// time and the identifier is set to 0. +TEST(StampedElementTest, create) { + StampedElement element; + + // Default identifier is 0. + EXPECT_EQ(0, element.getId()); + + // By default there is no server tag. + EXPECT_TRUE(element.getServerTags().empty()); + + // Checking that the delta between now and the timestamp is within + // 5s range should be sufficient. + boost::posix_time::time_duration delta = + boost::posix_time::second_clock::local_time() - + element.getModificationTime(); + EXPECT_LT(delta.seconds(), 5); +} + +// Tests that default id can be overridden by a new value. +TEST(StampedElementTest, setId) { + StampedElement element; + element.setId(123); + EXPECT_EQ(123, element.getId()); +} + +// Tests that the modification timestamp can be set to an arbitrary +// value. +TEST(StampedElementTest, setModificationTime) { + boost::posix_time::ptime + modification_time(boost::gregorian::date(2002, boost::date_time::Jan, 10), + boost::posix_time::time_duration(1,2,3)); + StampedElement element; + element.setModificationTime(modification_time); + EXPECT_TRUE(element.getModificationTime() == modification_time); +} + +// Tests that updating modification timestamp sets it to the current +// time. +TEST(StampedElementTest, update) { + boost::posix_time::ptime + modification_time(boost::gregorian::date(2002, boost::date_time::Jan, 10), + boost::posix_time::time_duration(1,2,3)); + StampedElement element; + element.setModificationTime(modification_time); + element.updateModificationTime(); + + // Checking that the delta between now and the timestamp is within + // 5s range should be sufficient. + boost::posix_time::time_duration delta = + boost::posix_time::second_clock::local_time() - + element.getModificationTime(); + EXPECT_LT(delta.seconds(), 5); +} + +// Tests that one or more server tag can be specified. +TEST(StampedElementTest, setServerTag) { + StampedElement element; + element.setServerTag("foo"); + EXPECT_EQ(1, element.getServerTags().size()); + EXPECT_EQ("foo", element.getServerTags().begin()->get()); + + element.setServerTag("bar"); + EXPECT_EQ(2, element.getServerTags().size()); + + EXPECT_TRUE(element.hasServerTag(ServerTag("foo"))); + EXPECT_TRUE(element.hasServerTag(ServerTag("bar"))); + EXPECT_FALSE(element.hasServerTag(ServerTag("xyz"))); + EXPECT_FALSE(element.hasAllServerTag()); + + element.setServerTag(ServerTag::ALL); + EXPECT_TRUE(element.hasAllServerTag()); +} + +// Tests that a server tag can be deleted. +TEST(StampedElementTest, delServerTag) { + StampedElement element; + EXPECT_THROW(element.delServerTag("foo"), isc::NotFound); + element.setServerTag("foo"); + element.setServerTag("bar"); + + ASSERT_EQ(2, element.getServerTags().size()); + EXPECT_TRUE(element.hasServerTag(ServerTag("foo"))); + EXPECT_TRUE(element.hasServerTag(ServerTag("bar"))); + + EXPECT_NO_THROW(element.delServerTag("foo")); + ASSERT_EQ(1, element.getServerTags().size()); + EXPECT_TRUE(element.hasServerTag(ServerTag("bar"))); + + EXPECT_NO_THROW(element.delServerTag("bar")); + EXPECT_EQ(0, element.getServerTags().size()); + EXPECT_THROW(element.delServerTag("bar"), isc::NotFound); +} + + +// Test that metadata can be created from the StampedElement. +TEST(StampedElementTest, getMetadata) { + StampedElement element; + element.setServerTag("world"); + auto metadata = element.getMetadata(); + ASSERT_TRUE(metadata); + ASSERT_EQ(Element::map, metadata->getType()); + + auto server_tags_element = metadata->get("server-tags"); + ASSERT_TRUE(server_tags_element); + EXPECT_EQ(Element::list, server_tags_element->getType()); + EXPECT_EQ(1, server_tags_element->size()); + + auto server_tag_element = server_tags_element->get(0); + ASSERT_TRUE(server_tag_element); + EXPECT_EQ(Element::string, server_tag_element->getType()); + EXPECT_EQ("world", server_tag_element->stringValue()); +} + +} diff --git a/src/lib/cc/tests/stamped_value_unittest.cc b/src/lib/cc/tests/stamped_value_unittest.cc new file mode 100644 index 0000000..d305a34 --- /dev/null +++ b/src/lib/cc/tests/stamped_value_unittest.cc @@ -0,0 +1,175 @@ +// Copyright (C) 2018-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 <cc/stamped_value.h> +#include <exceptions/exceptions.h> +#include <boost/scoped_ptr.hpp> +#include <gtest/gtest.h> + +using namespace isc; +using namespace isc::data; + +namespace { + +// Tests that the stamped value can be created with a NULL value. +TEST(StampedValueTest, createNull) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar")); + + EXPECT_TRUE(value->amNull()); + + EXPECT_THROW(value->getType(), InvalidOperation); + EXPECT_THROW(value->getValue(), InvalidOperation); + EXPECT_THROW(value->getIntegerValue(), InvalidOperation); + EXPECT_THROW(value->getBoolValue(), InvalidOperation); + EXPECT_THROW(value->getDoubleValue(), InvalidOperation); +} + +// Tests that stamped value from string can be created. +TEST(StampedValueTest, createFromString) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", Element::create("foo"))); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::string, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("foo", value->getValue()); + + EXPECT_THROW(value->getIntegerValue(), TypeError); + EXPECT_THROW(value->getBoolValue(), TypeError); + EXPECT_THROW(value->getDoubleValue(), TypeError); +} + +// Tests that the stamped value can be created from string using the +// factory function variant that takes parameter type as an argument. +TEST(StampedValueTest, convertStringToString) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", "foo", Element::string)); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::string, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("foo", value->getValue()); +} + +// Tests that stamped value from integer can be created. +TEST(StampedValueTest, createFromInteger) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", Element::create(static_cast<int64_t>(5)))); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::integer, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("5", value->getValue()); + int64_t signed_integer = 0; + ASSERT_NO_THROW(signed_integer = value->getIntegerValue()); + EXPECT_EQ(5, signed_integer); + + EXPECT_THROW(value->getBoolValue(), TypeError); + EXPECT_THROW(value->getDoubleValue(), TypeError); +} + +// Tests that stamped value can be converted from string to integer. +TEST(StampedValueTest, convertStringToInteger) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", "123", Element::integer)); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::integer, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ(123, value->getIntegerValue()); + + EXPECT_THROW(StampedValue::create("bar", "hoho", Element::integer), BadValue); +} + +// Tests that stamped value from bool can be created. +TEST(StampedValueTest, createFromBool) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", Element::create(static_cast<bool>(true)))); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::boolean, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("1", value->getValue()); + bool bool_value = false; + ASSERT_NO_THROW(bool_value = value->getBoolValue()); + EXPECT_TRUE(bool_value); + + EXPECT_THROW(value->getIntegerValue(), TypeError); + EXPECT_THROW(value->getDoubleValue(), TypeError); +} + +// Tests that stamped value can be converted from string to boolean. +TEST(StampedValueTest, convertStringToBoolean) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", "1", Element::boolean)); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::boolean, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_TRUE(value->getBoolValue()); + + ASSERT_NO_THROW(value = StampedValue::create("foo", "0", Element::boolean)); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::boolean, value->getType()); + EXPECT_EQ("foo", value->getName()); + EXPECT_FALSE(value->getBoolValue()); + + EXPECT_THROW(StampedValue::create("bar", "888", Element::boolean), BadValue); +} + +// Tests that stamped value from real can be created. +TEST(StampedValueTest, createFromDouble) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", Element::create(static_cast<double>(1.45)))); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::real, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("1.45", value->getValue()); + double double_value = 0; + ASSERT_NO_THROW(double_value = value->getDoubleValue()); + EXPECT_EQ(1.45, double_value); + + EXPECT_THROW(value->getIntegerValue(), TypeError); + EXPECT_THROW(value->getBoolValue(), TypeError); +} + +// Tests that stamped value from real can handle a round value. +TEST(StampedValueTest, createFromDoubleRound) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", Element::create(static_cast<double>(7.0)))); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::real, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ("7.0", value->getValue()); + double double_value = 0; + ASSERT_NO_THROW(double_value = value->getDoubleValue()); + EXPECT_EQ(7.0, double_value); + + EXPECT_THROW(value->getIntegerValue(), TypeError); + EXPECT_THROW(value->getBoolValue(), TypeError); +} + +// Tests that stamped value can be converted from string to real. +TEST(StampedValueTest, convertStringToDouble) { + StampedValuePtr value; + ASSERT_NO_THROW(value = StampedValue::create("bar", "1.67", Element::real)); + EXPECT_FALSE(value->amNull()); + EXPECT_EQ(Element::real, value->getType()); + EXPECT_EQ("bar", value->getName()); + EXPECT_EQ(1.67, value->getDoubleValue()); + + EXPECT_THROW(StampedValue::create("bar", "hoho", Element::real), BadValue); +} + +// Tests that the value must have an allowed type. +TEST(StampedValueTest, createFailures) { + EXPECT_THROW(StampedValue::create("bar", ElementPtr()), BadValue); + EXPECT_THROW(StampedValue::create("bar", Element::createMap()), TypeError); + EXPECT_THROW(StampedValue::create("bar", Element::createList()), TypeError); + + EXPECT_THROW(StampedValue::create("bar", "1", Element::map), TypeError); + EXPECT_THROW(StampedValue::create("bar", "1", Element::list), TypeError); + EXPECT_THROW(StampedValue::create("bar", "1", Element::null), TypeError); +} + +} diff --git a/src/lib/cc/tests/user_context_unittests.cc b/src/lib/cc/tests/user_context_unittests.cc new file mode 100644 index 0000000..e88b421 --- /dev/null +++ b/src/lib/cc/tests/user_context_unittests.cc @@ -0,0 +1,132 @@ +// Copyright (C) 2018-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 <cc/user_context.h> +#include <gtest/gtest.h> + +using namespace isc::data; + +namespace { + +ElementPtr gen() { + std::string content = "{ \"foo\": 1, \"bar\": \"xyz\" }"; + return (Element::fromJSON(content)); +} + +TEST(UserContext, setget) { + UserContext parent; + EXPECT_FALSE(parent.getContext()); + ConstElementPtr map = gen(); + parent.setContext(map); + ConstElementPtr ctx = parent.getContext(); + EXPECT_EQ(*ctx, *map); +} + +TEST(UserContext, null) { + UserContext parent; + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + EXPECT_EQ(*expected, *map); +} + +TEST(UserContext, notMap) { + UserContext parent; + ConstElementPtr ctx = Element::create("foo"); + parent.setContext(ctx); + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + expected->set("user-context", ctx); + EXPECT_EQ(*expected, *map); +} + +TEST(UserContext, empty) { + UserContext parent; + ConstElementPtr ctx = Element::createMap(); + parent.setContext(ctx); + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + expected->set("user-context", ctx); + EXPECT_EQ(*expected, *map); +} + +TEST(UserContext, noComment) { + UserContext parent; + ConstElementPtr ctx = Element::fromJSON("{ \"version\": 1 }"); + parent.setContext(ctx); + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + expected->set("user-context", ctx); + EXPECT_EQ(*expected, *map); +}; + +TEST(UserContext, onlyComment) { + UserContext parent; + ConstElementPtr ctx = Element::fromJSON("{ \"comment\": \"foobar\" }"); + parent.setContext(ctx); + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + expected->set("user-context", ctx); + EXPECT_EQ(*expected, *map); +} + +TEST(UserContext, both) { + UserContext parent; + ConstElementPtr ctx = + Element::fromJSON("{ \"comment\": \"foobar\", \"version\": 1 }"); + parent.setContext(ctx); + ElementPtr map = gen(); + parent.contextToElement(map); + ElementPtr expected = gen(); + expected->set("user-context", ctx); + EXPECT_EQ(*expected, *map); +} + +TEST(toElement, notMap) { + ConstElementPtr arg = Element::create("foo"); + ConstElementPtr result = UserContext::toElement(arg); + EXPECT_EQ(*result, *arg); +} + +TEST(toElement, empty) { + ElementPtr map = gen(); + ConstElementPtr ctx = Element::createMap(); + map->set("user-context", ctx); + ConstElementPtr result = UserContext::toElement(map); + EXPECT_EQ(*result, *map); +} + +TEST(toElement, noComment) { + ElementPtr map = gen(); + ConstElementPtr ctx = Element::fromJSON("{ \"version\": 1 }"); + map->set("user-context", ctx); + ConstElementPtr result = UserContext::toElement(map); + EXPECT_EQ(*result, *map); +} + +TEST(toElement, onlyComment) { + ElementPtr map = gen(); + ConstElementPtr ctx = Element::fromJSON("{ \"comment\": \"foobar\" }"); + map->set("user-context", ctx); + ConstElementPtr result = UserContext::toElement(map); + EXPECT_EQ(*result, *map); +} + +TEST(toElement, both) { + ElementPtr map = gen(); + ConstElementPtr ctx = + Element::fromJSON("{ \"comment\": \"foobar\", \"version\": 1 }"); + map->set("user-context", ctx); + ConstElementPtr result = UserContext::toElement(map); + EXPECT_EQ(*result, *map); +} + +} |