Skip to content

Commit

Permalink
Use new picojson_util.h classes in remaining test code
Browse files Browse the repository at this point in the history
  • Loading branch information
rmisev committed Nov 10, 2023
1 parent a715cdf commit 58abe59
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 158 deletions.
64 changes: 9 additions & 55 deletions test/bench-url.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Copyright 2023 Rimas Misevičius
// Distributed under the BSD-style license that can be
// found in the LICENSE file.
//

#include "upa/url.h"
#include "picojson_util.h"

#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>

Expand Down Expand Up @@ -46,63 +52,11 @@ int benchmark_txt(const char* file_name, uint64_t min_iters) {
// -----------------------------------------------------------------------------
// Read samples from urltestdata.json and benchmark

template <class OnArrayItem>
class root_array_context : public picojson::deny_parse_context {
OnArrayItem on_array_item_;
public:
root_array_context(OnArrayItem on_array_item)
: on_array_item_(on_array_item)
{}

// array as root
bool parse_array_start() { return true; }
bool parse_array_stop(std::size_t) { return true; }

template <typename Iter> bool parse_array_item(picojson::input<Iter>& in, std::size_t) {
picojson::value item;

// parse the array item
picojson::default_parse_context ctx(&item);
if (!picojson::_parse(ctx, in))
return false;

// callback with array item
return on_array_item_(item);
}

// deny object as root
bool parse_object_start() { return false; }
bool parse_object_stop() { return false; }
};

template <typename Context>
bool load_tests(Context& ctx, const char* file_name) {
// Load URL samples
std::cout << "Load URL samples from: " << file_name << '\n';
std::ifstream file(file_name, std::ios_base::in | std::ios_base::binary);
if (!file.is_open()) {
std::cerr << "Can't open file: " << file_name << std::endl;
return false;
}

std::string err;

// for unformatted reading use std::istreambuf_iterator
// http://stackoverflow.com/a/17776228/3908097
picojson::_parse(ctx, std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), &err);

if (!err.empty()) {
std::cerr << err << std::endl;
return false;
}
return true;
}

void benchmark_wpt(const char* file_name, uint64_t min_iters) {
// Load URL strings
std::vector<std::pair<std::string, std::string>> url_samples;

root_array_context context{ [&](const picojson::value& item) {
// Load URL samples
json_util::root_array_context context{ [&](const picojson::value& item) {
if (item.is<picojson::object>()) {
try {
const picojson::object& obj = item.get<picojson::object>();
Expand All @@ -121,7 +75,7 @@ void benchmark_wpt(const char* file_name, uint64_t min_iters) {
return true;
} };

if (!load_tests(context, file_name))
if (!json_util::load_file(context, file_name, "Load URL samples from"))
return;

// Run benchmark
Expand Down
55 changes: 15 additions & 40 deletions test/wpt-url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,7 @@ void test_percent_encoding(DataDrivenTest& ddt, EncodingObj& obj)
});
}


// Read tests in JSON format
// Read samples from JSON files and run tests

namespace {
enum class TestType {
Expand All @@ -362,34 +361,14 @@ namespace {
IdnaTestV2
};

// parses urltestdata.json, toascii.json
class root_context : public picojson::deny_parse_context {
DataDrivenTest& m_ddt;
TestType m_ttype;
public:
root_context(DataDrivenTest& ddt, TestType ttype)
: m_ddt(ddt)
, m_ttype(ttype)
{}

// array only as root
bool parse_array_start() { return true; }
bool parse_array_stop(std::size_t) { return true; }

template <typename Iter> bool parse_array_item(picojson::input<Iter>& in, std::size_t) {
picojson::value item;

// parse the array item
picojson::default_parse_context ctx(&item);
if (!picojson::_parse(ctx, in))
return false;

int load_and_run_tests(DataDrivenTest& ddt, TestType test_type, const char* file_name) {
const auto test_item = [&](const picojson::value& item) {
// analyze array item
if (item.is<picojson::object>()) {
ParserObj obj;

for (const auto& p : item.get<picojson::object>()) {
switch (m_ttype) {
switch (test_type) {
case TestType::UrlParser:
// boolean fields
if (p.first == "failure") {
Expand Down Expand Up @@ -429,15 +408,15 @@ namespace {
obj[p.first] = p.second.get<std::string>();
}
// run item test
switch (m_ttype) {
switch (test_type) {
case TestType::UrlParser:
test_parser(m_ddt, obj);
test_parser(ddt, obj);
break;
case TestType::HostParser:
test_host_parser(m_ddt, obj);
test_host_parser(ddt, obj);
break;
case TestType::IdnaTestV2:
test_idna_v2(m_ddt, obj);
test_idna_v2(ddt, obj);
break;
}
} else if (item.is<std::string>()) {
Expand All @@ -448,28 +427,24 @@ namespace {
return false;
}
return true;
}
};
json_util::root_array_context<decltype(test_item)> context{ test_item };

// deny object as root
bool parse_object_start() { return false; }
bool parse_object_stop() { return false; }
};
return json_util::load_file(context, file_name);
}

} // namespace

int run_parser_tests(DataDrivenTest& ddt, const char* file_name) {
root_context ctx(ddt, TestType::UrlParser);
return json_util::load_file(ctx, file_name);
return load_and_run_tests(ddt, TestType::UrlParser, file_name);
}

int run_host_parser_tests(DataDrivenTest& ddt, const char* file_name) {
root_context ctx(ddt, TestType::HostParser);
return json_util::load_file(ctx, file_name);
return load_and_run_tests(ddt, TestType::HostParser, file_name);
}

int run_idna_v2_tests(DataDrivenTest& ddt, const char* file_name) {
root_context ctx(ddt, TestType::IdnaTestV2);
return json_util::load_file(ctx, file_name);
return load_and_run_tests(ddt, TestType::IdnaTestV2, file_name);
}

// parses setters_tests.json
Expand Down
78 changes: 15 additions & 63 deletions test/wpt-urlencoded-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
#include "url_cleanup.h"

// https://github.com/kazuho/picojson
#include "picojson/picojson.h"
#include "picojson_util.h"

#include <fstream>
#include <iostream>
#include <string>

Expand Down Expand Up @@ -111,29 +110,15 @@ void test_urlsearchparams_sort(DataDrivenTest& ddt, const TestObj& obj) {
});
}

// Read data file and run tests from it

class root_context : public picojson::deny_parse_context {
protected:
DataDrivenTest& m_ddt;
bool m_sort;
public:
root_context(DataDrivenTest& ddt, bool sort)
: m_ddt(ddt)
, m_sort(sort)
{}

// array only as root
bool parse_array_start() { return true; }
bool parse_array_stop(std::size_t) { return true; }

template <typename Iter> bool parse_array_item(picojson::input<Iter>& in, std::size_t) {
picojson::value item;

// parse the array item
picojson::default_parse_context ctx(&item);
if (!picojson::_parse(ctx, in))
return false;
int test_from_file(const char* file_name, bool sort)
{
DataDrivenTest ddt;
ddt.config_show_passed(false);
ddt.config_debug_break(false);

const auto test_item = [&](const picojson::value& item) {
// analyze array item
if (item.is<picojson::object>()) {
const picojson::object& o = item.get<picojson::object>();
Expand All @@ -146,10 +131,10 @@ class root_context : public picojson::deny_parse_context {
obj.m_output.emplace_back(pair[0].get<std::string>(), pair[1].get<std::string>());
}

if (m_sort)
test_urlsearchparams_sort(m_ddt, obj);
if (sort)
test_urlsearchparams_sort(ddt, obj);
else
test_urlencoded_parser(m_ddt, obj);
test_urlencoded_parser(ddt, obj);
} else if (item.is<std::string>()) {
// comment
// std::cout << value.as_string() << std::endl;
Expand All @@ -158,43 +143,10 @@ class root_context : public picojson::deny_parse_context {
return false;
}
return true;
}

// deny object as root
bool parse_object_start() { return false; }
bool parse_object_stop() { return false; }
};
};
json_util::root_array_context<decltype(test_item)> context{ test_item };

// Read data file and run tests from it

int test_from_file(const char* file_name, bool sort)
{
DataDrivenTest ddt;
ddt.config_show_passed(false);
ddt.config_debug_break(false);

try {
std::cout << "========== " << file_name << " ==========\n";
std::ifstream file(file_name, std::ios_base::in | std::ios_base::binary);
if (!file.is_open()) {
std::cerr << "Can't open tests file: " << file_name << std::endl;
return 4;
}

std::string err;
// for unformatted reading use std::istreambuf_iterator
// http://stackoverflow.com/a/17776228/3908097
root_context ctx(ddt, sort);
picojson::_parse(ctx, std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), &err);
if (!err.empty()) {
std::cerr << err << std::endl;
return 2; // JSON error
}
}
catch (std::exception& ex) {
std::cerr << "ERROR: " << ex.what() << std::endl;
return 3;
}
const int res = json_util::load_file(context, file_name);

return ddt.result();
return res | ddt.result();
}

0 comments on commit 58abe59

Please sign in to comment.