<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <stdlib.h>
#include <stdio.h>
#include <csptr/smalloc.h>
#include "criterion/criterion.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
#include "criterion/logging.h"
#include "stats.h"
#include "runner.h"
#include "report.h"
#include "event.h"
#include "process.h"
#include "timer.h"
#include "posix-compat.h"
#include "abort.h"
#include "config.h"
#include "i18n.h"
#include "common.h"

#ifdef HAVE_PCRE
#include "extmatch.h"
#endif

#ifdef _MSC_VER
struct criterion_test  SECTION_START_(cr_tst);
struct criterion_suite SECTION_START_(cr_sts);
struct criterion_test  SECTION_END_(cr_tst);
struct criterion_suite SECTION_END_(cr_sts);
#endif

IMPL_SECTION_LIMITS(struct criterion_test, cr_tst);
IMPL_SECTION_LIMITS(struct criterion_suite, cr_sts);

// This is here to make the test suite & test sections non-empty
TestSuite();
Test(,) {};

static INLINE void nothing() {}

int cmp_suite(void *a, void *b) {
    struct criterion_suite *s1 = a, *s2 = b;
    return strcmp(s1->name, s2->name);
}

int cmp_test(void *a, void *b) {
    struct criterion_test *s1 = a, *s2 = b;
    return strcmp(s1->name, s2->name);
}

static void dtor_suite_set(void *ptr, UNUSED void *meta) {
    struct criterion_suite_set *s = ptr;
    sfree(s->tests);
}

static void dtor_test_set(void *ptr, UNUSED void *meta) {
    struct criterion_test_set *t = ptr;
    sfree(t->suites);
}

struct criterion_test_set *criterion_init(void) {
    struct criterion_ordered_set *suites = new_ordered_set(cmp_suite, dtor_suite_set);

    FOREACH_SUITE_SEC(s) {
        if (!s->name)
            break;

        struct criterion_suite_set css = {
            .suite = *s,
        };
        insert_ordered_set(suites, &css, sizeof (css));
    }

    size_t nb_tests = 0;
    FOREACH_TEST_SEC(test) {
        if (!test->category)
            break;

        if (!*test->category)
            continue;

        struct criterion_suite_set css = {
            .suite = { .name = test->category },
        };
        struct criterion_suite_set *s = insert_ordered_set(suites, &css, sizeof (css));
        if (!s->tests)
            s->tests = new_ordered_set(cmp_test, NULL);

        insert_ordered_set(s->tests, test, sizeof(*test));
        ++nb_tests;
    }

    struct criterion_test_set *set = smalloc(
            .size = sizeof (struct criterion_test_set),
            .dtor = dtor_test_set
        );

    *set = (struct criterion_test_set) {
        suites,
        nb_tests,
    };

    return set;
}

typedef void (*f_test_run)(struct criterion_global_stats *,
        struct criterion_suite_stats *,
        struct criterion_test *,
        struct criterion_suite *);

static void map_tests(struct criterion_test_set *set,
                      struct criterion_global_stats *stats,
                      f_test_run fun) {

    FOREACH_SET(struct criterion_suite_set *s, set->suites) {
        if (!s->tests)
            continue;

        report(PRE_SUITE, s);
        log(pre_suite, s);

        struct criterion_suite_stats *suite_stats = suite_stats_init(&s->suite);

        struct event ev = { .kind = PRE_SUITE };
        stat_push_event(stats, suite_stats, NULL, &ev);

        FOREACH_SET(struct criterion_test *t, s->tests) {
            fun(stats, suite_stats, t, &s->suite);
            if (criterion_options.fail_fast && stats->tests_failed > 0)
                break;
            if (!is_runner()) {
                sfree(suite_stats);
                return;
            }
        }

        report(POST_SUITE, suite_stats);
        log(post_suite, suite_stats);

        sfree(suite_stats);
    }

}

static void run_test_child(struct criterion_test *test,
                           struct criterion_suite *suite) {

    send_event(PRE_INIT, NULL, 0);
    if (suite->data)
        suite->data->init ? suite->data->init() : nothing();
    test->data->init ? test->data->init() : nothing();
    send_event(PRE_TEST, NULL, 0);

    struct timespec_compat ts;
    if (setup_abort_test()) {
        timer_start(&ts);
        test->test ? test->test() : nothing();
    }

    double elapsed_time;
    if (!timer_end(&elapsed_time, &ts))
        elapsed_time = -1;

    send_event(POST_TEST, &elapsed_time, sizeof (double));
    test->data->fini ? test->data->fini() : nothing();
    if (suite->data)
        suite->data->fini ? suite->data->fini() : nothing();
    send_event(POST_FINI, NULL, 0);
}

static INLINE bool is_disabled(struct criterion_test *t,
                               struct criterion_suite *s) {

    return t->data->disabled || (s->data && s->data->disabled);
}

#define push_event(Kind, ...)                                       \
    do {                                                            \
        stat_push_event(stats,                                      \
                suite_stats,                                        \
                test_stats,                                         \
                &(struct event) { .kind = Kind, __VA_ARGS__ });     \
        report(Kind, test_stats);                                   \
    } while (0)<commit_msg>Fixed UB introduced by the previous commit<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <stdlib.h>
#include <stdio.h>
#include <csptr/smalloc.h>
#include "criterion/criterion.h"
#include "criterion/options.h"
#include "criterion/ordered-set.h"
#include "criterion/logging.h"
#include "stats.h"
#include "runner.h"
#include "report.h"
#include "event.h"
#include "process.h"
#include "timer.h"
#include "posix-compat.h"
#include "abort.h"
#include "config.h"
#include "i18n.h"
#include "common.h"

#ifdef HAVE_PCRE
#include "extmatch.h"
#endif

#ifdef _MSC_VER
struct criterion_test  SECTION_START_(cr_tst);
struct criterion_suite SECTION_START_(cr_sts);
struct criterion_test  SECTION_END_(cr_tst);
struct criterion_suite SECTION_END_(cr_sts);
#endif

IMPL_SECTION_LIMITS(struct criterion_test, cr_tst);
IMPL_SECTION_LIMITS(struct criterion_suite, cr_sts);

// This is here to make the test suite & test sections non-empty
TestSuite();
Test(,) {};

static INLINE void nothing(void) {}

int cmp_suite(void *a, void *b) {
    struct criterion_suite *s1 = a, *s2 = b;
    return strcmp(s1->name, s2->name);
}

int cmp_test(void *a, void *b) {
    struct criterion_test *s1 = a, *s2 = b;
    return strcmp(s1->name, s2->name);
}

static void dtor_suite_set(void *ptr, UNUSED void *meta) {
    struct criterion_suite_set *s = ptr;
    sfree(s->tests);
}

static void dtor_test_set(void *ptr, UNUSED void *meta) {
    struct criterion_test_set *t = ptr;
    sfree(t->suites);
}

struct criterion_test_set *criterion_init(void) {
    struct criterion_ordered_set *suites = new_ordered_set(cmp_suite, dtor_suite_set);

    FOREACH_SUITE_SEC(s) {
        if (!s->name)
            break;

        struct criterion_suite_set css = {
            .suite = *s,
        };
        insert_ordered_set(suites, &css, sizeof (css));
    }

    size_t nb_tests = 0;
    FOREACH_TEST_SEC(test) {
        if (!test->category)
            break;

        if (!*test->category)
            continue;

        struct criterion_suite_set css = {
            .suite = { .name = test->category },
        };
        struct criterion_suite_set *s = insert_ordered_set(suites, &css, sizeof (css));
        if (!s->tests)
            s->tests = new_ordered_set(cmp_test, NULL);

        insert_ordered_set(s->tests, test, sizeof(*test));
        ++nb_tests;
    }

    struct criterion_test_set *set = smalloc(
            .size = sizeof (struct criterion_test_set),
            .dtor = dtor_test_set
        );

    *set = (struct criterion_test_set) {
        suites,
        nb_tests,
    };

    return set;
}

typedef void (*f_test_run)(struct criterion_global_stats *,
        struct criterion_suite_stats *,
        struct criterion_test *,
        struct criterion_suite *);

static void map_tests(struct criterion_test_set *set,
                      struct criterion_global_stats *stats,
                      f_test_run fun) {

    FOREACH_SET(struct criterion_suite_set *s, set->suites) {
        if (!s->tests)
            continue;

        report(PRE_SUITE, s);
        log(pre_suite, s);

        struct criterion_suite_stats *suite_stats = suite_stats_init(&s->suite);

        struct event ev = { .kind = PRE_SUITE };
        stat_push_event(stats, suite_stats, NULL, &ev);

        FOREACH_SET(struct criterion_test *t, s->tests) {
            fun(stats, suite_stats, t, &s->suite);
            if (criterion_options.fail_fast && stats->tests_failed > 0)
                break;
            if (!is_runner()) {
                sfree(suite_stats);
                return;
            }
        }

        report(POST_SUITE, suite_stats);
        log(post_suite, suite_stats);

        sfree(suite_stats);
    }

}

static void run_test_child(struct criterion_test *test,
                           struct criterion_suite *suite) {

    send_event(PRE_INIT, NULL, 0);
    if (suite->data)
        (suite->data->init ? suite->data->init : nothing)();
    (test->data->init ? test->data->init : nothing)();
    send_event(PRE_TEST, NULL, 0);

    struct timespec_compat ts;
    if (setup_abort_test()) {
        timer_start(&ts);
        (test->test ? test->test : nothing)();
    }

    double elapsed_time;
    if (!timer_end(&elapsed_time, &ts))
        elapsed_time = -1;

    send_event(POST_TEST, &elapsed_time, sizeof (double));
    (test->data->fini ? test->data->fini : nothing)();
    if (suite->data)
        (suite->data->fini ? suite->data->fini : nothing)();
    send_event(POST_FINI, NULL, 0);
}

static INLINE bool is_disabled(struct criterion_test *t,
                               struct criterion_suite *s) {

    return t->data->disabled || (s->data && s->data->disabled);
}

#define push_event(Kind, ...)                                       \
    do {                                                            \
        stat_push_event(stats,                                      \
                suite_stats,                                        \
                test_stats,                                         \
                &(struct event) { .kind = Kind, __VA_ARGS__ });     \
        report(Kind, test_stats);                                   \
    } while (0)
{'fraction_non_alphanumeric': 0.1105925164148406, 'fraction_numerical': 0.0033225219523771855, 'mean_word_length': 2.4288039056143207, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2300565', 'n_tokens_mistral': 4043, 'n_tokens_neox': 3769, 'n_words': 1049}