Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/Progmasoft/Catch3/Strategy/Engine.hpp
blob: 3addf541510eb0e063866088ee384005c2b195ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright (c) 2026 Progmasoft.
// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-2.0
#pragma once

#include <Progmasoft/Catch3/Property.hpp>
#include <Progmasoft/Catch3/Strategy/ChoiceSource.hpp>
#include <Progmasoft/Catch3/Strategy/Context.hpp>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

namespace Progmasoft::Catch3::Detail
{

    enum class TrialVerdict : std::uint8_t
    {
        kPassed,
        kFailed,
        /// The body called CATCH3_PROPERTY_ASSUME with a false condition.
        kDiscarded,
        /// The strategies described no value, for example a filter that
        /// found nothing.
        kInvalid,
        /// A strategy threw; the property cannot be judged.
        kErrored,
    };

    struct TrialOutcome final
    {
        TrialVerdict Verdict = TrialVerdict::kPassed;
        std::string Reason;
        TrialRecord Record;
        /// The input, rendered; only filled when the engine asks for it.
        std::string Description;
    };

    /// Draws the input of one trial from the source and runs the body on
    /// it. describe asks for TrialOutcome::Description.
    using TrialRunner = std::function<TrialOutcome(ChoiceSource &, bool describe)>;

    /// Runs a strategy-based property: the regular trials, the targeted
    /// search, the coverage requirements, the example database and the
    /// shrinking of a failure. Independent of the value types, so that it
    /// is compiled once.
    [[nodiscard]] PropertyResult
    RunPropertyEngine(const PropertyOptions &options, const TrialRunner &runner);

    /// A replay token: the size of the trial and its choices.
    [[nodiscard]] std::string
    EncodeChoices(std::size_t size, const std::vector<std::uint64_t> &choices);

    struct DecodedChoices final
    {
        std::size_t Size = 0;
        std::vector<std::uint64_t> Choices;
    };

    [[nodiscard]] std::optional<DecodedChoices>
    DecodeChoices(std::string_view token);

    /// Minimizes a failing choice sequence: deletes and zeroes blocks of
    /// choices, lowers single choices by binary search, sorts neighbours
    /// and moves value between neighbours. stillFails replays a candidate
    /// and returns the choices the replay consumed when it fails too.
    /// Returns the simplest failing sequence found within budget replays;
    /// calls counts the replays made.
    [[nodiscard]] std::vector<std::uint64_t>
    ShrinkChoices(
        std::vector<std::uint64_t> failing,
        std::size_t budget,
        const std::function<std::optional<std::vector<std::uint64_t>>(
            const std::vector<std::uint64_t> &)> &stillFails,
        std::size_t &calls);

    /// Shortlex order: shorter first, then lexicographically smaller.
    [[nodiscard]] bool
    IsSimpler(const std::vector<std::uint64_t> &candidate,
              const std::vector<std::uint64_t> &current) noexcept;

} // namespace Progmasoft::Catch3::Detail