Repository: bitcoin/bitcoin
File: src/univalue/test/unitester.cpp (C++)

Code before:
        "fail12.json",
        "fail13.json",
        "fail14.json",
        "fail15.json",
        "fail16.json",
        "fail17.json",
        //"fail18.json",             // investigate
        "fail19.json",
        "fail1.json",
        "fail20.json",
        "fail21.json",
        "fail22.json",
        "fail23.json",
        "fail24.json",
        "fail25.json",
        "fail26.json",
        "fail27.json",
        "fail28.json",
        "fail29.json",
        "fail2.json",
        "fail30.json",
        "fail31.json",
        "fail32.json",
        "fail33.json",
        "fail34.json",
        "fail35.json",
        "fail36.json",
        "fail37.json",
        "fail38.json",               // invalid unicode: only first half of surrogate pair
        "fail39.json",               // invalid unicode: only second half of surrogate pair
        "fail40.json",               // invalid unicode: broken UTF-8
        "fail41.json",               // invalid unicode: unfinished UTF-8
        "fail42.json",               // valid json with garbage following a nul byte
        "fail44.json",               // unterminated string
        "fail45.json",               // nested beyond max depth
        "fail3.json",
        "fail4.json",                // extra comma
        "fail5.json",
        "fail6.json",
        "fail7.json",
        "fail8.json",
        "fail9.json",               // extra comma
        "pass1.json",
        "pass2.json",
        "pass3.json",
        "pass4.json",
        "round1.json",              // round-trip test
        "round2.json",              // unicode
        "round3.json",              // bare string
        "round4.json",              // bare number
        "round5.json",              // bare true

Review comment (bug):
I understand why a macro is the smallest change to make `runtest` happy, but I think we can avoid that weird string parsing and introduce enums instead:
```C++
enum class TestType { Fail, Pass, RoundTrip };
```
and define the test as:
```C++
inline constexpr std::map<std::string_view, TestType> tests{
    {json_tests::fail1, TestType::Fail},
    {json_tests::fail2, TestType::Fail},
    {json_tests::fail3, TestType::Fail},
...
```
which could simplify `runtest` to:
```C++
static void runtest(std::string_view data, TestType type) {
    UniValue val;
    bool testResult = val.read(std::string{data});

    if (type == TestType::Fail) {
        assert(!testResult);
        return;
    }
    ...
```

Code after:

static void runtest(std::string filename, const std::string& jdata)
{
    std::string prefix = filename.substr(0, 4);

    bool wantPass = (prefix == "pass") || (prefix == "roun");
    bool wantFail = (prefix == "fail");
    bool wantRoundTrip = (prefix == "roun");
    assert(wantPass || wantFail);

    UniValue val;
    bool testResult = val.read(jdata);

    if (wantPass) {
        assert(testResult == true);
    } else {
        assert(testResult == false);
    }

    if (wantRoundTrip) {
        std::string odata = val.write(0, 0);
        assert(odata == rtrim(jdata));
    }
}

#define TEST_FILE(name) {#name, json_tests::name}
inline constexpr std::array tests{std::to_array<std::tuple<std::string_view, std::string_view>>({
    TEST_FILE(fail1),
    TEST_FILE(fail10),
    TEST_FILE(fail11),
    TEST_FILE(fail12),
    TEST_FILE(fail13),
    TEST_FILE(fail14),
    TEST_FILE(fail15),
    TEST_FILE(fail16),
    TEST_FILE(fail17),
    TEST_FILE(fail18),
    TEST_FILE(fail19),
    TEST_FILE(fail2),
    TEST_FILE(fail20),
    TEST_FILE(fail21),
    TEST_FILE(fail22),
    TEST_FILE(fail23),
    TEST_FILE(fail24),
    TEST_FILE(fail25),
    TEST_FILE(fail26),
    TEST_FILE(fail27),
    TEST_FILE(fail28),
    TEST_FILE(fail29),
    TEST_FILE(fail3),
    TEST_FILE(fail30),