/*
 *  $Id: testlibgwy.c 28076 2025-06-09 14:55:16Z yeti-dn $
 *  Copyright (C) 2025 David Nečas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program 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 General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

// The test case declarations are separated from testlibgwy.h to avoid recompilation of everything when a new test is
// added.
#include <stdarg.h>
#include <locale.h>
#include <unistd.h>
#include <fftw3.h>

#ifdef HAVE_VALGRIND
#include <valgrind/valgrind.h>
#else
#define RUNNING_ON_VALGRIND 0
#endif

#include "tests/testlibgwy.h"
#include "tests/test-list.h"

#define TEST_DATA_DIR "_testdata"

static gchar *test_data_dir = NULL;

static void remove_files_recursively(const gchar *dirname,
                                     gint max_recurse);

static void
remove_files_recursively(const gchar *dirname, gint max_recurse)
{
    GFile *gfile = g_file_new_for_path(dirname);
    GFileEnumerator *enumerator = g_file_enumerate_children(gfile,
                                                            G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                                                            G_FILE_ATTRIBUTE_STANDARD_NAME ",",
                                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                            NULL, NULL);
    if (enumerator) {
        GFileInfo *fileinfo;
        while ((fileinfo = g_file_enumerator_next_file(enumerator, NULL, NULL))) {
            gchar *path = g_build_filename(dirname, g_file_info_get_name(fileinfo), NULL);
            GFileType filetype = g_file_info_get_file_type(fileinfo);
            if (filetype == G_FILE_TYPE_REGULAR)
                g_unlink(path);
            else if (filetype == G_FILE_TYPE_DIRECTORY && max_recurse> 0)
                remove_files_recursively(path, max_recurse-1);
            else
                fprintf(stderr, "Cannot remove %s: not a regular file.\n", path);
            g_free(path);
            g_object_unref(fileinfo);
        }
        g_object_unref(enumerator);
    }
    g_object_unref(gfile);
    g_rmdir(dirname);
}

static void
remove_testdata(void)
{
    /* Nothing in the test should create subidirectory structure more than one level deep. So do not try to do full
     * rm -rf. Just don't. */
    if (test_data_dir && *test_data_dir)
        remove_files_recursively(test_data_dir, 1);
}

gchar*
ensure_test_data_dir(void)
{
    if (test_data_dir)
        return test_data_dir;

    test_data_dir = g_strdup_printf("%s%lu", TEST_DATA_DIR, (gulong)getpid());
    remove_testdata();
    g_mkdir(test_data_dir, 0700);

    return test_data_dir;
}

void
assert_subprocesses_critical_fail(const gchar *prefix,
                                  guint64 timeout,
                                  GTestSubprocessFlags test_flags,
                                  ...)
{
    GString *str = g_string_new(prefix);
    g_string_append(str, "/subprocess");
    guint len = str->len;

    va_list ap;
    va_start(ap, test_flags);

    const gchar *subpath;
    while ((subpath = va_arg(ap, const gchar*))) {
        g_string_truncate(str, len);
        g_string_append(str, subpath);
        g_test_trap_subprocess(str->str, timeout, test_flags);
        g_test_trap_assert_failed();
        g_test_trap_assert_stderr("*CRITICAL*");
    }
    va_end(ap);

    g_string_free(str, TRUE);
}

int
main(int argc, char *argv[])
{
    setenv("GWYDDION_HOMEDIR", ensure_test_data_dir(), TRUE);
    setenv("LC_NUMERIC", "C", TRUE);
    setlocale(LC_NUMERIC, "C");
    if (RUNNING_ON_VALGRIND) {
        /* GSlice is obsolete and we de not use it explicitly either. But older libraries might. */
        setenv("G_SLICE", "always-malloc", TRUE);
        g_mem_gc_friendly = TRUE;
    }

    g_test_init(&argc, &argv, NULL);

#include "test-list.c"

    gint status = g_test_run();

    if (!g_test_subprocess())
        remove_testdata();

    // Good on Valgrind, but do it consistently always.
    fftw_forget_wisdom();
    //gwy_resources_finalize();
    g_free(test_data_dir);

    return status;
}

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
