libpurple/tests/sqlite3/test_sqlite3.c

Thu, 23 Mar 2023 22:03:45 -0500

author
Elliott Sales de Andrade <quantum.analyst@gmail.com>
date
Thu, 23 Mar 2023 22:03:45 -0500
changeset 42182
3fc2d2b7b7a8
parent 41804
36c3c3cd2402
permissions
-rw-r--r--

Fix leaked errors

And also simplify some cases with `g_clear_error`.

Testing Done:
Compiled and ran tests in valgrind, though it never noticed these anyway.

Reviewed at https://reviews.imfreedom.org/r/2384/

/*
 * Purple - Internet Messaging Library
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

#include <glib.h>

#include <sqlite3.h>

#include <purple.h>

/******************************************************************************
 * get schema version tests
 *****************************************************************************/
static void
test_sqlite3_get_schema_version_null(void) {
	if(g_test_subprocess()) {
		GError *error = NULL;
		int version = 0;

		version = purple_sqlite3_get_schema_version(NULL, &error);
		g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0);
		g_clear_error(&error);
		g_assert_cmpint(version, ==, -1);
	}

	g_test_trap_subprocess(NULL, 0, 0);
	g_test_trap_assert_failed();
	g_test_trap_assert_stderr("*assertion*!= NULL*");
}

static void
test_sqlite3_get_schema_version_new(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	int rc = 0;
	int version = 0;

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 0);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

/******************************************************************************
 * string migration tests
 *****************************************************************************/
static void
test_sqlite3_string_migrations_null(void) {
	if(g_test_subprocess()) {
		GError *error = NULL;
		sqlite3 *db = NULL;
		gboolean res = FALSE;
		int rc = 0;

		rc = sqlite3_open(":memory:", &db);
		g_assert_nonnull(db);
		g_assert_cmpint(rc, ==, SQLITE_OK);

		res = purple_sqlite3_run_migrations_from_strings(db, NULL, &error);
		g_assert_no_error(error);
		g_assert_false(res);
	}

	g_test_trap_subprocess(NULL, 0, 0);
	g_test_trap_assert_failed();
	g_test_trap_assert_stderr("*migrations != NULL*");
}

static void
test_sqlite3_string_migrations_null_terminator(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {NULL};

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 0);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_string_migrations_multiple(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {
		"CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);",
		"CREATE TABLE baz(c TEXT);",
		NULL
	};

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	/* Run the migrations again and make sure we remain at schema version 2. */
	res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_string_migrations_syntax_error(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {
		"CREATE TABLE broke(a TEXT",
		NULL
	};

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error);
	g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0);
	g_clear_error(&error);
	g_assert_false(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 0);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_string_migrations_older(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations1[] = {
		"CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);",
		"CREATE TABLE baz(c TEXT);",
		NULL
	};
	const char *migrations2[] = {
		"CREATE TABLE foo(a TEXT); CREATE TABLE bar(b TEXT);",
		NULL
	};

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_strings(db, migrations1, &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	/* Run the older migrations now and verify we get a failure. */
	res = purple_sqlite3_run_migrations_from_strings(db, migrations2, &error);
	g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0);
	g_clear_error(&error);
	g_assert_false(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

/******************************************************************************
 * resource migration tests
 *****************************************************************************/
static void
test_sqlite3_resource_migrations_null_path(void) {
	if(g_test_subprocess()) {
		GError *error = NULL;
		sqlite3 *db = NULL;
		gboolean res = FALSE;
		int rc = 0;

		rc = sqlite3_open(":memory:", &db);
		g_assert_nonnull(db);
		g_assert_cmpint(rc, ==, SQLITE_OK);

		res = purple_sqlite3_run_migrations_from_resources(db, NULL, NULL,
		                                                   &error);
		g_assert_no_error(error);
		g_assert_false(res);

		rc = sqlite3_close(db);
		g_assert_cmpint(rc, ==, SQLITE_OK);
	}

	g_test_trap_subprocess(NULL, 0, 0);
	g_test_trap_assert_failed();
	g_test_trap_assert_stderr("*path != NULL*");
}

static void
test_sqlite3_resource_migrations_null_migrations(void) {
	if(g_test_subprocess()) {
		GError *error = NULL;
		sqlite3 *db = NULL;
		gboolean res = FALSE;
		const char *path = "/im/libpidgin/purple/tests/sqlite3/";
		int rc = 0;

		rc = sqlite3_open(":memory:", &db);
		g_assert_nonnull(db);
		g_assert_cmpint(rc, ==, SQLITE_OK);

		res = purple_sqlite3_run_migrations_from_resources(db, path, NULL,
		                                                   &error);
		g_assert_no_error(error);
		g_assert_false(res);

		rc = sqlite3_close(db);
		g_assert_cmpint(rc, ==, SQLITE_OK);
	}

	g_test_trap_subprocess(NULL, 0, 0);
	g_test_trap_assert_failed();
	g_test_trap_assert_stderr("*migrations != NULL*");
}

static void
test_sqlite3_resource_migrations_null_terminator(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {NULL};
	const char *path = "/im/pidgin/libpurple/tests/sqlite3/";

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations,
	                                                   &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 0);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_resource_migrations_multiple(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {"initial.sql", "secondary.sql", NULL};
	const char *path = "/im/pidgin/libpurple/tests/sqlite3/";

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations,
	                                                   &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	/* Run the migrations again and make sure we remain at schema version 2. */
	res = purple_sqlite3_run_migrations_from_strings(db, migrations, &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_resource_migrations_missing(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {"initial.sql", "imaginary.sql", NULL};
	const char *path = "/im/pidgin/libpurple/tests/sqlite3/";

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations,
	                                                   &error);
	g_assert_error(error, G_RESOURCE_ERROR, 0);
	g_clear_error(&error);
	g_assert_false(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 1);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_resource_migrations_syntax_error(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations[] = {"malformed.sql", NULL};
	const char *path = "/im/pidgin/libpurple/tests/sqlite3/";

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations,
	                                                   &error);
	g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0);
	g_clear_error(&error);
	g_assert_false(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 0);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

static void
test_sqlite3_resource_migrations_older(void) {
	GError *error = NULL;
	sqlite3 *db = NULL;
	gboolean res = FALSE;
	int rc = 0;
	int version = -1;
	const char *migrations1[] = {"initial.sql", "secondary.sql", NULL};
	const char *migrations2[] = {"initial.sql", NULL};
	const char *path = "/im/pidgin/libpurple/tests/sqlite3/";

	rc = sqlite3_open(":memory:", &db);
	g_assert_nonnull(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);

	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations1,
	                                                   &error);
	g_assert_no_error(error);
	g_assert_true(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	/* Run the older migrations now and verify we get a failure. */
	res = purple_sqlite3_run_migrations_from_resources(db, path, migrations2,
	                                                   &error);
	g_assert_error(error, PURPLE_SQLITE3_DOMAIN, 0);
	g_clear_error(&error);
	g_assert_false(res);

	version = purple_sqlite3_get_schema_version(db, &error);
	g_assert_no_error(error);
	g_assert_cmpint(version, ==, 2);

	rc = sqlite3_close(db);
	g_assert_cmpint(rc, ==, SQLITE_OK);
}

/******************************************************************************
 * Main
 *****************************************************************************/
int
main(int argc, char *argv[]) {
	g_test_init(&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);

	g_test_add_func("/sqlite3/schema_version/null",
	                test_sqlite3_get_schema_version_null);
	g_test_add_func("/sqlite3/schema_version/new",
	                test_sqlite3_get_schema_version_new);

	g_test_add_func("/sqlite3/string_migrations/null",
	                test_sqlite3_string_migrations_null);
	g_test_add_func("/sqlite3/string_migrations/null-terminator",
	                test_sqlite3_string_migrations_null_terminator);
	g_test_add_func("/sqlite3/string_migrations/multiple",
	                test_sqlite3_string_migrations_multiple);
	g_test_add_func("/sqlite3/string_migrations/syntax-error",
	                test_sqlite3_string_migrations_syntax_error);
	g_test_add_func("/sqlite3/string_migrations/older",
	                test_sqlite3_string_migrations_older);

	g_test_add_func("/sqlite3/resource_migrations/null-path",
	                test_sqlite3_resource_migrations_null_path);
	g_test_add_func("/sqlite3/resource_migrations/null-migrations",
	                test_sqlite3_resource_migrations_null_migrations);
	g_test_add_func("/sqlite3/resource_migrations/null-terminator",
	                test_sqlite3_resource_migrations_null_terminator);
	g_test_add_func("/sqlite3/resource_migrations/multiple",
	                test_sqlite3_resource_migrations_multiple);
	g_test_add_func("/sqlite3/resource_migrations/missing",
	                test_sqlite3_resource_migrations_missing);
	g_test_add_func("/sqlite3/resource_migrations/syntax-error",
	                test_sqlite3_resource_migrations_syntax_error);
	g_test_add_func("/sqlite3/resource_migrations/older",
	                test_sqlite3_resource_migrations_older);

	return g_test_run();
}

mercurial