From: Greg Hudson Date: Wed, 26 May 2021 05:30:14 +0000 (-0400) Subject: Add C profile test program to replace Tcl tests X-Git-Tag: krb5-1.20-beta1~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea99c4dda830c700f2fd81a89b90ea50d2591ee4;p=thirdparty%2Fkrb5.git Add C profile test program to replace Tcl tests --- diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in index 6ee264ad07..30f1695149 100644 --- a/src/util/profile/Makefile.in +++ b/src/util/profile/Makefile.in @@ -38,7 +38,7 @@ SRCS = $(srcdir)/prof_tree.c \ EXTRADEPSRCS=$(srcdir)/test_load.c $(srcdir)/test_parse.c \ $(srcdir)/test_profile.c $(srcdir)/test_vtable.c \ - $(srcdir)/profile_tcl.c + $(srcdir)/profile_tcl.c $(srcdir)/t_profile.c DEPLIBS = $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB) MLIBS = $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS) @@ -65,7 +65,7 @@ $(PROFILE_HDR): profile.h includes: $(PROFILE_HDR) clean-unix:: - $(RM) $(BUILDTOP)/include/profile.h test2.ini test3.ini test2.ini.bak + $(RM) $(BUILDTOP)/include/profile.h ##DOS##LIBOBJS = $(OBJS) @@ -89,6 +89,9 @@ test_vtable: test_vtable.$(OBJEXT) $(OBJS) $(DEPLIBS) test_load: test_load.$(OBJEXT) $(OBJS) $(DEPLIBS) $(CC_LINK) -o test_load test_load.$(OBJEXT) $(OBJS) $(MLIBS) +t_profile: t_profile.$(OBJEXT) $(OBJS) $(DEPLIBS) + $(CC_LINK) -o $@ t_profile.$(OBJEXT) $(OBJS) $(MLIBS) + modtest.conf: echo "module `pwd`/testmod/proftest$(DYNOBJEXT):teststring" > $@ @@ -129,15 +132,19 @@ profile_tcl: profile_tcl.o $(PROF_DEPLIB) $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB) clean-unix:: clean-libs clean-libobjs $(RM) $(PROGS) *.o *~ core prof_err.h profile.h prof_err.c $(RM) test_load test_parse test_profile test_vtable profile_tcl - $(RM) modtest.conf testinc.ini testinc2.ini final.out + $(RM) t_profile modtest.conf testinc.ini testinc2.ini final.out + $(RM) test2* test3* $(RM) -r test_include_dir clean-windows:: $(RM) $(PROFILE_HDR) -check-unix: test_parse test_profile test_vtable test_load modtest.conf +check-unix: test_parse test_profile modtest.conf +check-unix: test_vtable test_load t_profile $(RUN_TEST) ./test_vtable $(RUN_TEST) ./test_load + cp $(srcdir)/test.ini test2.ini + $(RUN_TEST) ./t_profile DO_TCL=@DO_TCL@ check-unix: check-unix-final check-unix-tcl-$(DO_TCL) diff --git a/src/util/profile/t_profile.c b/src/util/profile/t_profile.c new file mode 100644 index 0000000000..b0e715ba02 --- /dev/null +++ b/src/util/profile/t_profile.c @@ -0,0 +1,389 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* util/profile/t_profile.c - profile library regression tests */ +/* + * Copyright (C) 2021 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "profile.h" + +static void +check(long code) +{ + assert(code == 0); +} + +static void +check_fail(long code, long expected) +{ + assert(code == expected); +} + +static void +write_file(const char *name, int nlines, ...) +{ + FILE *f; + va_list ap; + int i; + + (void)unlink(name); + f = fopen(name, "w"); + assert(f != NULL); + va_start(ap, nlines); + for (i = 0; i < nlines; i++) + fprintf(f, "%s\n", va_arg(ap, char *)); + va_end(ap); + fclose(f); +} + +/* Regression test for #2685 (profile iterator breaks when modifications + * made) */ +static void +test_iterate() +{ + profile_t p; + void *iter; + const char *names[] = { "test section 1", "child_section", "child", NULL }; + const char *values[] = { "slick", "harry", "john", NULL }; + char *name, *value; + int i; + + check(profile_init_path("test2.ini", &p)); + + /* Iterate and check for the expected values. */ + check(profile_iterator_create(p, names, 0, &iter)); + for (i = 0;; i++) { + check(profile_iterator(&iter, &name, &value)); + if (name == NULL && value == NULL) + break; + assert(strcmp(name, names[2]) == 0); + assert(values[i] != NULL); + assert(strcmp(value, values[i]) == 0); + profile_release_string(name); + profile_release_string(value); + } + assert(values[i] == NULL); + profile_iterator_free(&iter); + + /* Iterate again, deleting each value as we go. Flush the result to a + * separate file. */ + check(profile_iterator_create(p, names, 0, &iter)); + for (;;) { + check(profile_iterator(&iter, NULL, &value)); + if (value == NULL) + break; + check(profile_update_relation(p, names, value, NULL)); + profile_release_string(value); + } + profile_iterator_free(&iter); + (void)unlink("test3.ini"); + profile_flush_to_file(p, "test3.ini"); + + profile_abandon(p); + + /* Check that no values for the section are found in the resulting file. */ + check(profile_init_path("test3.ini", &p)); + check(profile_iterator_create(p, names, 0, &iter)); + check(profile_iterator(&iter, &name, &value)); + assert(name == NULL && value == NULL); + profile_iterator_free(&iter); + profile_abandon(p); +} + +/* + * Regression test for a 1.4-era bug where updating the underlying file data of + * a profile object lost track of the flag indicating that it was part of the + * global shared profiles list. + */ +static void +test_shared() +{ + profile_t a, b; + struct utimbuf times; + + system("cp test2.ini test3.ini"); + + /* Create an entry in the shared table. */ + check(profile_init_path("test3.ini", &a)); + + /* + * Force an update of the underlying data. With the bug present, the + * shared flag is erroneously cleared. The easiest way to force an update + * is to reopen the file (since we don't enforce the one-stat-per-second + * limit during open) after changing the timestamp. + */ + times.actime = time(NULL) + 2; + times.modtime = times.actime; + utime("test3.ini", ×); + check(profile_init_path("test3.ini", &b)); + profile_release(b); + + /* Release the profile. With the bug present, a dangling reference is left + * behind in the shared table. */ + profile_release(a); + + /* Open the profile again to dereference the dangling pointer if one was + * created. */ + check(profile_init_path("test3.ini", &a)); + profile_release(a); +} + +/* Regression test for #2950 (profile_clear_relation not reflected within + * handle where deletion is performed) */ +static void +test_clear() +{ + profile_t p; + const char *names[] = { "test section 1", "quux", NULL }; + char **values, **dummy; + + check(profile_init_path("test2.ini", &p)); + check(profile_get_values(p, names, &values)); + check(profile_clear_relation(p, names)); + check_fail(profile_get_values(p, names, &dummy), PROF_NO_RELATION); + check(profile_add_relation(p, names, values[0])); + profile_free_list(values); + check(profile_get_values(p, names, &values)); + assert(values[0] != NULL && values[1] == NULL); + profile_free_list(values); + profile_abandon(p); +} + +static void +test_include() +{ + profile_t p; + const char *names[] = { "test section 1", "bar", NULL }; + char **values; + + /* Test expected error code when including nonexistent file. */ + write_file("testinc.ini", 1, "include does-not-exist"); + check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_FILE); + + /* Test expected error code when including nonexistent directory. */ + write_file("testinc.ini", 1, "includedir does-not-exist"); + check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_DIR); + + /* Test including a file. */ + write_file("testinc.ini", 1, "include test2.ini"); + check(profile_init_path("testinc.ini", &p)); + check(profile_get_values(p, names, &values)); + assert(strcmp(values[0], "foo") == 0 && values[1] == NULL); + profile_free_list(values); + profile_release(p); + + /* + * Test including a directory. Put four copies of test2.ini inside the + * directory, two with invalid names. Check that we get two values for one + * of the variables. + */ + system("rm -rf test_include_dir"); + system("mkdir test_include_dir"); + system("cp test2.ini test_include_dir/a"); + system("cp test2.ini test_include_dir/a~"); + system("cp test2.ini test_include_dir/b.conf"); + system("cp test2.ini test_include_dir/b.conf.rpmsave"); + write_file("testinc.ini", 1, "includedir test_include_dir"); + check(profile_init_path("testinc.ini", &p)); + check(profile_get_values(p, names, &values)); + assert(strcmp(values[0], "foo") == 0); + assert(strcmp(values[1], "foo") == 0); + assert(values[2] == NULL); + profile_free_list(values); + profile_release(p); + + /* Directly list the directory in the profile path and try again. */ + check(profile_init_path("test_include_dir", &p)); + check(profile_get_values(p, names, &values)); + assert(strcmp(values[0], "foo") == 0); + assert(strcmp(values[1], "foo") == 0); + assert(values[2] == NULL); + profile_free_list(values); + profile_release(p); +} + +/* Test syntactic independence of included profile files. */ +static void +test_independence() +{ + profile_t p; + const char *names1[] = { "sec1", "var", "a", NULL }; + const char *names2[] = { "sec2", "b", NULL }; + const char *names3[] = { "sec1", "var", "c", NULL }; + char **values; + + write_file("testinc.ini", 6, "[sec1]", "var = {", "a = 1", + "include testinc2.ini", "c = 3", "}"); + write_file("testinc2.ini", 2, "[sec2]", "b = 2"); + + check(profile_init_path("testinc.ini", &p)); + check(profile_get_values(p, names1, &values)); + assert(strcmp(values[0], "1") == 0 && values[1] == NULL); + profile_free_list(values); + check(profile_get_values(p, names2, &values)); + assert(strcmp(values[0], "2") == 0 && values[1] == NULL); + profile_free_list(values); + check(profile_get_values(p, names3, &values)); + assert(strcmp(values[0], "3") == 0 && values[1] == NULL); + profile_free_list(values); + profile_release(p); +} + +/* Regression test for #7971 (deleted sections should not be iterable) */ +static void +test_delete_section() +{ + profile_t p; + const char *sect[] = { "test section 1", NULL }; + const char *newrel[] = { "test section 1", "testkey", NULL }; + const char *oldrel[] = { "test section 1", "child", NULL }; + char **values; + + check(profile_init_path("test2.ini", &p)); + + /* Remove and replace a section. */ + check(profile_rename_section(p, sect, NULL)); + check(profile_add_relation(p, sect, NULL)); + check(profile_add_relation(p, newrel, "6")); + + /* Check that we can read the new relation but not the old one. */ + check(profile_get_values(p, newrel, &values)); + assert(strcmp(values[0], "6") == 0 && values[1] == NULL); + profile_free_list(values); + check_fail(profile_get_values(p, oldrel, &values), PROF_NO_RELATION); + profile_abandon(p); +} + +/* Regression test for #7971 (profile_clear_relation() error with deleted node + * at end of value set) */ +static void +test_delete_clear_relation() +{ + profile_t p; + const char *names[] = { "test section 1", "testkey", NULL }; + + check(profile_init_path("test2.ini", &p)); + check(profile_add_relation(p, names, "1")); + check(profile_add_relation(p, names, "2")); + check(profile_update_relation(p, names, "2", NULL)); + check(profile_clear_relation(p, names)); + profile_abandon(p); +} + +/* Test that order of relations is preserved if some relations are deleted. */ +static void +test_delete_ordering() +{ + profile_t p; + const char *names[] = { "test section 1", "testkey", NULL }; + char **values; + + check(profile_init_path("test2.ini", &p)); + check(profile_add_relation(p, names, "1")); + check(profile_add_relation(p, names, "2")); + check(profile_add_relation(p, names, "3")); + check(profile_update_relation(p, names, "2", NULL)); + check(profile_add_relation(p, names, "4")); + check(profile_get_values(p, names, &values)); + assert(strcmp(values[0], "1") == 0); + assert(strcmp(values[1], "3") == 0); + assert(strcmp(values[2], "4") == 0); + assert(values[3] == NULL); + profile_free_list(values); + profile_abandon(p); +} + +/* Regression test for #8431 (profile_flush_to_file erroneously changes flag + * state on source object) */ +static void +test_flush_to_file() +{ + profile_t p; + + /* Flush a profile object to a file without making any changes, so that the + * source object is still within g_shared_trees. */ + check(profile_init_path("test2.ini", &p)); + unlink("test3.ini"); + check(profile_flush_to_file(p, "test3.ini")); + profile_release(p); + + /* Check for a dangling reference in g_shared_trees by creating another + * profile object. */ + profile_init_path("test2.ini", &p); + profile_release(p); +} + +/* Regression test for #7863 (multiply-specified subsections should + * be merged) */ +static void +test_merge_subsections() +{ + profile_t p; + const char *n1[] = { "test section 2", "child_section2", "child", NULL }; + const char *n2[] = { "test section 2", "child_section2", "chores", NULL }; + char **values; + + check(profile_init_path("test2.ini", &p)); + + check(profile_get_values(p, n1, &values)); + assert(strcmp(values[0], "slick") == 0); + assert(strcmp(values[1], "harry") == 0); + assert(strcmp(values[2], "john\tb ") == 0); + assert(strcmp(values[3], "ron") == 0); + assert(values[4] == NULL); + profile_free_list(values); + + check(profile_get_values(p, n2, &values)); + assert(strcmp(values[0], "cleaning") == 0 && values[1] == NULL); + profile_free_list(values); + + profile_release(p); +} + +int +main() +{ + test_iterate(); + test_shared(); + test_clear(); + test_include(); + test_independence(); + test_delete_section(); + test_delete_clear_relation(); + test_delete_ordering(); + test_flush_to_file(); + test_merge_subsections(); +}