root/lib/libc/tests/gen/fts_test.h
/*-
 * Copyright (c) 2025 Klara, Inc.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifndef FTS_TEST_H_INCLUDED
#define FTS_TEST_H_INCLUDED

struct fts_expect {
        int fts_info;
        const char *fts_name;
        const char *fts_accpath;
};

struct fts_testcase {
        char **paths;
        int fts_options;
        struct fts_expect *fts_expect;
};

/* shorter name for dead links */
#define FTS_DL FTS_SLNONE

/* are we being debugged? */
static bool fts_test_debug;

/*
 * Set debug flag if appropriate.
 */
static void
fts_check_debug(void)
{
        fts_test_debug = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
            isatty(STDERR_FILENO);
}

/*
 * Lexical order for reproducability.
 */
static int
fts_lexical_compar(const FTSENT * const *a, const FTSENT * const *b)
{
        return (strcmp((*a)->fts_name, (*b)->fts_name));
}

/*
 * Run FTS with the specified paths and options and verify that it
 * produces the expected result in the correct order.
 */
static void
fts_test(const struct atf_tc *tc, const struct fts_testcase *fts_tc)
{
        FTS *fts;
        FTSENT *ftse;
        const struct fts_expect *expect = fts_tc->fts_expect;
        long level = 0;

        fts = fts_open(fts_tc->paths, fts_tc->fts_options, fts_lexical_compar);
        ATF_REQUIRE_MSG(fts != NULL, "fts_open(): %m");
        while ((ftse = fts_read(fts)) != NULL && expect->fts_name != NULL) {
                if (expect->fts_info == FTS_DP || expect->fts_info == FTS_DNR)
                        level--;
                if (fts_test_debug) {
                        fprintf(stderr, "%2ld %2d %s\n", level,
                            ftse->fts_info, ftse->fts_name);
                }
                ATF_CHECK_STREQ(expect->fts_name, ftse->fts_name);
                ATF_CHECK_STREQ(expect->fts_accpath, ftse->fts_accpath);
                ATF_CHECK_INTEQ(expect->fts_info, ftse->fts_info);
                ATF_CHECK_INTEQ(level, ftse->fts_level);
                if (expect->fts_info == FTS_D)
                        level++;
                expect++;
        }
        ATF_CHECK_EQ(NULL, ftse);
        ATF_CHECK_EQ(NULL, expect->fts_name);
        ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m");
}

#endif /* FTS_TEST_H_INCLUDED */