[pacman-dev] [PATCH 10/10] wip: config parser unit test

Andrew Gregory andrew.gregory.8 at gmail.com
Sat Apr 26 19:57:03 EDT 2014


Just a quick-n-dirty test to demonstrate the reworked parser.  Obviously
not suitable to be committed.

Only modified conf.c to allow parsing the config without also
initializing alpm.

Can be run with `make check` in test/unit/pacman/.
---
 src/pacman/conf.c         |  81 +++++++++++----------
 test/unit/pacman/config.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++
 test/unit/pacman/tap.h    | 123 ++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+), 36 deletions(-)
 create mode 100644 test/unit/pacman/config.c
 create mode 100644 test/unit/pacman/tap.h

diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index 5449b92..09daeb4 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -679,6 +679,7 @@ static int register_repo(config_repo_t *repo)
  */
 static int setup_libalpm(void)
 {
+	setup_libalpm();
 	int ret = 0;
 	alpm_errno_t err;
 	alpm_handle_t *handle;
@@ -686,25 +687,6 @@ static int setup_libalpm(void)
 
 	pm_printf(ALPM_LOG_DEBUG, "setup_libalpm called\n");
 
-	/* Configure root path first. If it is set and dbpath/logfile were not
-	 * set, then set those as well to reside under the root. */
-	if(config->rootdir) {
-		char path[PATH_MAX];
-		if(!config->dbpath) {
-			snprintf(path, PATH_MAX, "%s/%s", config->rootdir, DBPATH + 1);
-			config->dbpath = strdup(path);
-		}
-		if(!config->logfile) {
-			snprintf(path, PATH_MAX, "%s/%s", config->rootdir, LOGFILE + 1);
-			config->logfile = strdup(path);
-		}
-	} else {
-		config->rootdir = strdup(ROOTDIR);
-		if(!config->dbpath) {
-			config->dbpath = strdup(DBPATH);
-		}
-	}
-
 	/* initialize library */
 	handle = alpm_initialize(config->rootdir, config->dbpath, &err);
 	if(!handle) {
@@ -722,7 +704,6 @@ static int setup_libalpm(void)
 	alpm_option_set_questioncb(handle, cb_question);
 	alpm_option_set_progresscb(handle, cb_progress);
 
-	config->logfile = config->logfile ? config->logfile : strdup(LOGFILE);
 	ret = alpm_option_set_logfile(handle, config->logfile);
 	if(ret != 0) {
 		pm_printf(ALPM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"),
@@ -730,9 +711,6 @@ static int setup_libalpm(void)
 		return ret;
 	}
 
-	/* Set GnuPG's home directory. This is not relative to rootdir, even if
-	 * rootdir is defined. Reasoning: gpgdir contains configuration data. */
-	config->gpgdir = config->gpgdir ? config->gpgdir : strdup(GPGDIR);
 	ret = alpm_option_set_gpgdir(handle, config->gpgdir);
 	if(ret != 0) {
 		pm_printf(ALPM_LOG_ERROR, _("problem setting gpgdir '%s' (%s)\n"),
@@ -749,18 +727,12 @@ static int setup_libalpm(void)
 
 	alpm_option_set_default_siglevel(handle, config->siglevel);
 
-#define SLMERGE(l, m) if(m) { l = (l & (m)) | (config->siglevel & ~(m)); }
-	SLMERGE(config->localfilesiglevel, config->localfilesiglevel_mask);
-	SLMERGE(config->remotefilesiglevel, config->remotefilesiglevel_mask);
 	alpm_option_set_local_file_siglevel(handle, config->localfilesiglevel);
 	alpm_option_set_remote_file_siglevel(handle, config->remotefilesiglevel);
 
 	for(i = config->repos; i; i = alpm_list_next(i)) {
-		config_repo_t *repo = i->data;
-		SLMERGE(repo->siglevel, repo->siglevel_mask);
-		register_repo(repo);
+		register_repo(i->data);
 	}
-#undef SLMERGE
 
 	if(config->xfercommand) {
 		alpm_option_set_fetchcb(handle, download_with_xfercommand);
@@ -980,6 +952,42 @@ static int _parse_directive(const char *file, int linenum, const char *name,
 	}
 }
 
+static void finalize_config(void)
+{
+	/* Configure root path first. If it is set and dbpath/logfile were not
+	 * set, then set those as well to reside under the root. */
+	if(config->rootdir) {
+		char path[PATH_MAX];
+		if(!config->dbpath) {
+			snprintf(path, PATH_MAX, "%s/%s", config->rootdir, DBPATH + 1);
+			config->dbpath = strdup(path);
+		}
+		if(!config->logfile) {
+			snprintf(path, PATH_MAX, "%s/%s", config->rootdir, LOGFILE + 1);
+			config->logfile = strdup(path);
+		}
+	} else {
+		config->rootdir = strdup(ROOTDIR);
+		if(!config->dbpath) {
+			config->dbpath = strdup(DBPATH);
+		}
+	}
+	config->logfile = config->logfile ? config->logfile : strdup(LOGFILE);
+	/* Set GnuPG's home directory. This is not relative to rootdir, even if
+	 * rootdir is defined. Reasoning: gpgdir contains configuration data. */
+	config->gpgdir = config->gpgdir ? config->gpgdir : strdup(GPGDIR);
+
+#define SLMERGE(l, m) if(m) { l = (l & (m)) | (config->siglevel & ~(m)); }
+	SLMERGE(config->localfilesiglevel, config->localfilesiglevel_mask);
+	SLMERGE(config->remotefilesiglevel, config->remotefilesiglevel_mask);
+	alpm_list_t *i;
+	for(i = config->repos; i; i = alpm_list_next(i)) {
+		config_repo_t *repo = i->data;
+		SLMERGE(repo->siglevel, repo->siglevel_mask);
+	}
+#undef SLMERGE
+}
+
 /** Parse a configuration file.
  * @param file path to the config file
  * @return 0 on success, non-zero on error
@@ -994,12 +1002,13 @@ int parseconfig(const char *file)
 		return ret;
 	}
 	pm_printf(ALPM_LOG_DEBUG, "config: finished parsing %s\n", file);
-	if((ret = setup_libalpm())) {
-		return ret;
-	}
-	alpm_list_free_inner(config->repos, (alpm_list_fn_free) config_repo_free);
-	alpm_list_free(config->repos);
-	config->repos = NULL;
+	finalize_config();
+	/*if((ret = setup_libalpm())) {*/
+		/*return ret;*/
+	/*}*/
+	/*alpm_list_free_inner(config->repos, (alpm_list_fn_free) config_repo_free);*/
+	/*alpm_list_free(config->repos);*/
+	/*config->repos = NULL;*/
 	return ret;
 }
 
diff --git a/test/unit/pacman/config.c b/test/unit/pacman/config.c
new file mode 100644
index 0000000..9f5aa54
--- /dev/null
+++ b/test/unit/pacman/config.c
@@ -0,0 +1,174 @@
+#include <string.h>
+#include <stdlib.h>
+
+#define CONFFILE "/etc/pacman.conf"
+#define DBPATH "/var/lib/pacman/"
+#define LOGFILE "/var/log/pacman.log"
+#define ROOTDIR "/"
+#define GPGDIR "/etc/pacman.d/gnupg/"
+#define CACHEDIR "/var/cache/pacman/pkg"
+
+#include "pacman/conf.c"
+#include "pacman/ini.c"
+#include "pacman/util.c"
+#include "pacman/callback.c"
+
+#include "tap.h"
+
+int main(int argc, char **argv) {
+    alpm_list_t *i;
+    char temp_path1[] = "pu_config_test_XXXXXX";
+    char temp_path2[] = "pu_config_test_XXXXXX";
+    int fd1 = mkstemp(temp_path1);
+    int fd2 = mkstemp(temp_path2);
+    FILE *stream1 = fdopen(fd1, "r+");
+    FILE *stream2 = fdopen(fd2, "r+");
+    fprintf(stream2,
+            "\n"
+            "SigLevel = DatabaseNever\n"
+            "");
+    fprintf(stream1,
+            "\n"
+            "[options]\n"
+            "#RootDir = /root1\n"
+            "RootDir = /root2\n"
+            "DBPath = /dbpath1/ \n"
+            "DBPath = /dbpath2/ \n"
+            "CacheDir=/cachedir\n"
+            "GPGDir =gpgdir\n"
+            "LogFile= /logfile #ignore me\n"
+            " HoldPkg = holdpkga holdpkgb \n"
+            "IgnorePkg = ignorepkga\n"
+            "IgnorePkg = ignorepkgb\n"
+            " IgnoreGroup = ignoregroupa ignoregroupb \n"
+            "Architecture = i686\n"
+            "NoUpgrade = /tmp/noupgrade*\n"
+            "NoExtract = /tmp/noextract*\n"
+            "CleanMethod = KeepInstalled KeepCurrent\n"
+            "UseSyslog\n"
+            "Color\n"
+            "UseDelta\n"
+            "TotalDownload\n"
+            "CheckSpace\n"
+            "VerbosePkgLists\n"
+            "XferCommand = xfercommand\n"
+
+            "LocalFileSigLevel = PackageNever\n"
+            "SigLevel = PackageOptional DatabaseRequired PackageTrustedOnly\n"
+            "RemoteFileSigLevel = PackageTrustAll\n"
+
+            "[core]\n"
+            "SigLevel = PackageRequired\n"
+            "Server = $repo:$arch\n"
+
+            "[extra]\n"
+            "Include = %s\n"
+            "",
+            temp_path2);
+
+    fclose(stream1);
+    fclose(stream2);
+
+	tap_plan(37);
+
+    if((config = config_new()) == NULL) {
+        tap_bail("config_new failed");
+    }
+    parseconfig(temp_path1);
+
+    tap_is_str(config->rootdir, "/root2", "RootDir");
+    tap_is_str(config->dbpath, "/dbpath1/", "DBPath");
+    tap_is_str(config->gpgdir, "gpgdir", "DPGDir");
+    tap_is_str(config->logfile, "/logfile", "LogFile");
+    tap_is_str(config->arch, "i686", "Arch");
+    tap_is_str(config->xfercommand, "xfercommand", "Include XferCommand");
+
+    tap_ok(config->usesyslog, "UseSyslog");
+    tap_ok(config->color, "Color");
+    tap_ok(config->totaldownload, "TotalDownload");
+    tap_ok(config->checkspace, "CheckSpace");
+    tap_ok(config->verbosepkglists, "VerbosePkgLists");
+
+#define is_list_exhausted(l, name) do { \
+        tap_ok(l == NULL, name " exhausted"); \
+        if(l) { \
+            tap_diag("remaining elements:"); \
+            while(l) { \
+                tap_diag(l->data); \
+                l = alpm_list_next(l); \
+            } \
+        } \
+    } while(0)
+
+
+#define is_str_list(l, str, desc) do { \
+        if(l) { \
+            tap_is_str(l->data, str, desc); \
+            l = alpm_list_next(l); \
+        } else { \
+            tap_ok(l != NULL, desc); \
+        } \
+    } while(0)
+
+    i = config->ignorepkg;
+    is_str_list(i, "ignorepkga", "IgnorePkg a");
+    is_str_list(i, "ignorepkgb", "IgnorePkg b");
+    is_list_exhausted(i, "ignorepkg");
+
+    i = config->ignoregrp;
+    is_str_list(i, "ignoregroupa", "IgnoreGroup a");
+    is_str_list(i, "ignoregroupb", "IgnoreGroup b");
+    is_list_exhausted(i, "ignoregroup");
+
+    i = config->noupgrade;
+    is_str_list(i, "/tmp/noupgrade*", "NoUpgrade");
+    is_list_exhausted(i, "noupgrade");
+
+    i = config->noextract;
+    is_str_list(i, "/tmp/noextract*", "NoExtract");
+    is_list_exhausted(i, "noextract");
+
+    i = config->cachedirs;
+    is_str_list(i, "/cachedir", "CacheDir");
+    is_list_exhausted(i, "cachedir");
+
+    i = config->holdpkg;
+    is_str_list(i, "holdpkga", "HoldPkg a");
+    is_str_list(i, "holdpkgb", "HoldPkg b");
+    is_list_exhausted(i, "holdpkgs");
+#undef tap_is_str_list
+
+    tap_is_float(config->deltaratio, 0.7, 0.0001, "UseDelta (default)");
+
+    alpm_siglevel_t base = ALPM_SIG_PACKAGE
+        | ALPM_SIG_PACKAGE_OPTIONAL
+        | ALPM_SIG_DATABASE;
+    alpm_siglevel_t local = base & ~(ALPM_SIG_PACKAGE);
+    alpm_siglevel_t remote = base
+        | ALPM_SIG_PACKAGE_MARGINAL_OK
+        | ALPM_SIG_PACKAGE_UNKNOWN_OK;
+    alpm_siglevel_t core = base & ~(ALPM_SIG_PACKAGE_OPTIONAL);
+    alpm_siglevel_t extra = base & ~(ALPM_SIG_DATABASE);
+
+    tap_is_int(config->siglevel, base, "SigLevel");
+    tap_is_int(config->localfilesiglevel, local, "LocalFileSigLevel");
+    tap_is_int(config->remotefilesiglevel, remote, "RemoteFileSigLevel");
+
+    i = config->repos;
+    config_repo_t *repo = i->data;
+    tap_is_str(repo->name, "core", "core name");
+    tap_is_int(repo->siglevel, core, "core siglevel");
+    tap_is_str(repo->servers->data, "$repo:$arch", "core server");
+    tap_ok(repo->servers->next == NULL, "core server count");
+
+    i = alpm_list_next(i);
+    repo = i->data;
+    tap_is_str(repo->name, "extra", "extra name");
+    tap_is_int(repo->siglevel, extra, "extra siglevel");
+    tap_ok(repo->servers == NULL, "extra server count");
+
+    unlink(temp_path1);
+    unlink(temp_path2);
+
+	return tap_tests_failed();
+}
diff --git a/test/unit/pacman/tap.h b/test/unit/pacman/tap.h
new file mode 100644
index 0000000..e670909
--- /dev/null
+++ b/test/unit/pacman/tap.h
@@ -0,0 +1,123 @@
+#include <math.h>
+#include <stdarg.h>
+
+int _tap_tests_run = 0;
+int _tap_tests_failed = 0;
+
+const char *_tap_todo = NULL;
+
+void tap_todo(const char *reason)
+{
+    _tap_todo = reason;
+}
+
+void tap_ok(int success, const char *description, ...)
+{
+	const char *result;
+	if(success) {
+		result = "ok";
+        if(_tap_todo) ++_tap_tests_failed;
+	} else {
+		result = "not ok";
+        if(!_tap_todo) ++_tap_tests_failed;
+	}
+
+    printf("%s %d", result, ++_tap_tests_run);
+
+	if(description) {
+        va_list args;
+        fputs(" - ", stdout);
+        va_start(args, description);
+        vprintf(description, args);
+        va_end(args);
+    }
+
+    if(_tap_todo) {
+        fputs(" # TODO", stdout);
+        if(*_tap_todo) {
+            fputc(' ', stdout);
+            fputs(_tap_todo, stdout);
+        }
+    }
+
+    fputc('\n', stdout);
+}
+
+void tap_bail(const char *format, ...)
+{
+	va_list args;
+    fputs("Bail out! ", stdout);
+	va_start(args, format);
+    vprintf(format, args);
+	va_end(args);
+    fputc('\n', stdout);
+}
+
+void tap_diag(const char *format, ...)
+{
+	va_list args;
+    fputs("    # ", stdout);
+	va_start(args, format);
+    vprintf(format, args);
+	va_end(args);
+    fputc('\n', stdout);
+}
+
+void tap_is_float(float got, float expected, float delta,
+        const char *description)
+{
+    float diff = fabs(expected - got);
+    int match = diff < delta;
+	tap_ok(match, description);
+	if(!match) {
+		tap_diag("expected '%f'", expected);
+		tap_diag("got      '%f'", got);
+        tap_diag("delta    '%f'", diff);
+        tap_diag("allowed  '%f'", delta);
+	}
+}
+
+void tap_is_int(int got, int expected, const char *description)
+{
+	int match = got == expected;
+	tap_ok(match, description);
+	if(!match) {
+		tap_diag("expected '%d'", expected);
+		tap_diag("got      '%d'", got);
+	}
+}
+
+void tap_is_str(const char *got, const char *expected, const char *description)
+{
+	int match;
+    if(got && expected) {
+        match = (strcmp(got, expected) == 0);
+    } else {
+        match = (got == expected);
+    }
+	tap_ok(match, description);
+	if(!match) {
+		tap_diag("expected '%s'", expected);
+		tap_diag("got      '%s'", got);
+	}
+}
+
+void tap_plan(int test_count)
+{
+	printf("1..%d\n", test_count);
+}
+
+void tap_done_testing(void)
+{
+	tap_plan(_tap_tests_run);
+}
+
+int tap_tests_run(void)
+{
+    return _tap_tests_run;
+}
+
+int tap_tests_failed(void)
+{
+    return _tap_tests_failed;
+}
-- 
1.9.2



More information about the pacman-dev mailing list