3
\$\begingroup\$

Part 1: JSON Test Harness: Part 1
Part 2: JSON Test Harness: Part 2
Part 4: JSON Test Harness: Part 4

Time to review some test harness code I have written.

https://github.com/Loki-Astari/JsonBenchmark

I wrote a C++ JSON parser/serializer and wanted to compare performance against other JSON parsers. This was originally written by somebody else (credit were credit is due (see README)) but has been highly modified to use better C++ idioms (I hope).

This questions covers the simpler tests. These are all part of the "Conformance" tests. Results found here: https://lokiastari.com/Json/Conformance.linux.html

PassChecker.h

#ifndef THORS_ANVIL_BENCHMARK_PASS_CHECKER_H
#define THORS_ANVIL_BENCHMARK_PASS_CHECKER_H

#include "CommonReader.h"
#include <memory>

namespace ThorsAnvil
{
    namespace Benchmark
    {

class PassChecker: public CommonReader
{
    public:
        using CommonReader::CommonReader;
        virtual std::string getDir() const override
        {
            return "jsonchecker_pass";
        }
        virtual State executeTest(TestBase const& parser, Test const& test) override
        {
            std::unique_ptr<ParseResultBase> result(parser.Parse(test.input.c_str(), test.input.size()));
            return result != nullptr ? Pass : Fail;
        }
        virtual void generateConPerData(TestBase const& parser, Test const& test, State state) override
        {
            std::size_t begin   = test.path.str().rfind('/') + 1;
            std::size_t end     = test.path.str().rfind('.');
            std::string fileName = test.path.str().substr(begin, (end - begin));
            options.conformance << "1. Parse Validation,"
                                << parser.GetName() << ","
                                << fileName << ","
                                << (state == Pass ? "true" : "false")
                                << "\n";
        }
};

    }
}

#endif

FailChecker.h

#ifndef THORS_ANVIL_BENCHMARK_FAIL_CHECKER_H
#define THORS_ANVIL_BENCHMARK_FAIL_CHECKER_H

#include "CommonReader.h"
#include <memory>

namespace ThorsAnvil
{
    namespace Benchmark
    {

class FailChecker: public CommonReader
{
    public:
        using CommonReader::CommonReader;
        virtual std::string getDir() const override
        {
            return "jsonchecker_fail";
        }
        virtual State executeTest(TestBase const& parser, Test const& test) override
        {
            std::unique_ptr<ParseResultBase> result(parser.Parse(test.input.c_str(), test.input.size()));
            return result == nullptr ? Pass : Fail;
        }
        virtual void generateConPerData(TestBase const& parser, Test const& test, State state) override
        {
            std::size_t begin   = test.path.str().rfind('/') + 1;
            std::size_t end     = test.path.str().rfind('.');
            std::string fileName = test.path.str().substr(begin, (end - begin));
            options.conformance << "1. Parse Validation,"
                                << parser.GetName() << ","
                                << fileName << ","
                                << (state == Pass ? "true" : "false")
                                << "\n";
        }
};

    }
}

#endif

RoundTripChecker.h

#ifndef THORS_ANVIL_BENCHMARK_ROUNDTRIP_CHECKER_H
#define THORS_ANVIL_BENCHMARK_ROUNDTRIP_CHECKER_H

#include "CommonReader.h"
#include <string>
#include <memory>
#include <cctype>

namespace ThorsAnvil
{
    namespace Benchmark
    {

class RoundTripChecker: public CommonReader
{
    public:
        using CommonReader::CommonReader;
        virtual void preloadData(Test& test) override
        {
            CommonReader::preloadData(test);
            test.output = stripSpace(test.input);
        }
        virtual State executeTest(TestBase const& parser, Test const& test) override
        {
            std::unique_ptr<ParseResultBase> result(parser.Parse(test.input.c_str(), test.input.size()));
            if (!result)
            {
                return NotImplemented;
            }
            std::unique_ptr<StringResultBase> stringify(parser.Stringify(result.get()));
            std::string                       output;
            if (stringify)
            {
                output = stringify->c_str();
            }
            return test.output == stripSpace(output) ? Pass : Fail;
        }
        virtual std::string getDir() const override
        {
            return "roundtrip";
        }
    private:
        std::string stripSpace(std::string const from)
        {
            std::string result;
            std::copy_if(std::begin(from), std::end(from),
                         std::back_inserter(result),
                         [inString = false, lastChar = ' '](char next) mutable
                         {
                            if (next == '"' && lastChar != '\\')
                            {
                                inString    = !inString;
                            }
                            lastChar = next;
                            return !inString && std::isspace(next);
                         }
                        );
            return result;
        }
        virtual void generateConPerData(TestBase const& parser, Test const& test, State state) override
        {
            std::size_t begin   = test.path.str().rfind('/') + 1;
            std::size_t end     = test.path.str().rfind('.');
            std::string fileName = test.path.str().substr(begin, (end - begin));
            options.conformance << "4. Roundtrip,"
                                << parser.GetName() << ","
                                << fileName << ","
                                << (state == Pass ? "true" : "false")
                                << "\n";
        }
};

    }
}

#endif

ValidFloatChecker.h

#ifndef THORS_ANVIL_BENCHMARK_VALIDATE_FLOAT_H
#define THORS_ANVIL_BENCHMARK_VALIDATE_FLOAT_H

#include "TestSuite.h"
#include <fstream>
#include <string>
#include <limits>
#include <cstdlib>

namespace ThorsAnvil
{
    namespace Benchmark
    {

class ValidateFloat: public TestSuite
{
    public:
        using TestSuite::TestSuite;
        virtual std::string setupName(Test const&) override
        {
            return "vector-double";
        }
        virtual std::string getDir() const override
        {
            return "validate_float";
        }
        virtual void preloadData(Test& test) override
        {
            std::ifstream   input(test.path.str());

            std::getline(input, test.input, '<');
            input.ignore(std::numeric_limits<std::streamsize>::max(), '>');
            std::getline(input, test.output, '<');
        }
        virtual State executeTest(TestBase const& parser, Test const& test) override
        {
            double output;
            char *end;
            double expected = std::strtod(test.output.c_str(), &end);
            bool result = parser.ParseDouble(test.input.c_str(), &output);
            return !result ? NotImplemented : output == expected ? Pass: Fail;
        }
        virtual void generateConPerData(TestBase const& parser, Test const& test, State state) override
        {
            std::size_t begin   = test.path.str().rfind('/') + 1;
            std::size_t end     = test.path.str().rfind('.');
            std::string fileName = test.path.str().substr(begin, (end - begin));
            options.conformance << "2. Parse Double,"
                                << parser.GetName() << ","
                                << fileName << ","
                                << (state == Pass ? "true" : "false")
                                << "\n";
        }
};

    }
}

#endif

ValidStringChecker.h

#ifndef THORS_ANVIL_BENCHMARK_VALIDATE_STRING_H
#define THORS_ANVIL_BENCHMARK_VALIDATE_STRING_H

#include "TestSuite.h"
#include <fstream>
#include <string>

namespace ThorsAnvil
{
    namespace Benchmark
    {

class ValidateString: public TestSuite
{
    public:
        using TestSuite::TestSuite;
        virtual std::string setupName(Test const&) override
        {
            return "vector-string";
        }
        virtual std::string getDir() const override
        {
            return "validate_string";
        }
        virtual void preloadData(Test& test) override
        {
            std::ifstream   input(test.path.str());

            std::getline(input, test.input, '<');
            input.ignore(std::numeric_limits<std::streamsize>::max(), '>');
            std::getline(input, test.output, '<');
        }
        virtual State executeTest(TestBase const& parser, Test const& test) override
        {
            std::string output;
            bool result = parser.ParseString(test.input.c_str(), output);
            return !result ? NotImplemented : output == test.output ? Pass: Fail;
        }
        virtual void generateConPerData(TestBase const& parser, Test const& test, State state) override
        {
            std::size_t begin   = test.path.str().rfind('/') + 1;
            std::size_t end     = test.path.str().rfind('.');
            std::string fileName = test.path.str().substr(begin, (end - begin));
            options.conformance << "3. Parse String,"
                                << parser.GetName() << ","
                                << fileName << ","
                                << (state == Pass ? "true" : "false")
                                << "\n";
        }
};

    }
}

#endif
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.