Skip to content

Commit

Permalink
Migrate parse_id_list to Catch2
Browse files Browse the repository at this point in the history
  • Loading branch information
mmd-osm committed Nov 25, 2023
1 parent b9de251 commit e650dff
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 116 deletions.
4 changes: 3 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ ___test_test_core_SOURCES=\
../test/test_core.cpp \
../test/test_request.cpp

___test_test_parse_id_list_CPPFLAGS=$(AM_CPPFLAGS) $(CATCH2_CPPFLAGS)
___test_test_parse_id_list_SOURCES=\
../test/test_parse_id_list.cpp
../test/test_parse_id_list.cpp \
../test/test_request.cpp

___test_test_basicauth_CPPFLAGS=$(AM_CPPFLAGS) $(CATCH2_CPPFLAGS)
___test_test_basicauth_SOURCES=\
Expand Down
135 changes: 20 additions & 115 deletions test/test_parse_id_list.cpp
Original file line number Diff line number Diff line change
@@ -1,151 +1,56 @@
#include "cgimap/api06/handler_utils.hpp"
#include "cgimap/api06/id_version_io.hpp"
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include "test_request.hpp"

namespace {

struct test_request : public request {
test_request() = default;

/// implementation of request interface
virtual ~test_request() = default;
const char *get_param(const char *key) const override {
std::string key_str(key);
auto itr = m_params.find(key_str);
if (itr != m_params.end()) {
return itr->second.c_str();
} else {
return NULL;
}
}

const std::string get_payload() override {
return "";
}

void dispose() override {}

/// getters and setters for the input headers and output response
void set_header(const std::string &k, const std::string &v) {
m_params.insert(std::make_pair(k, v));
}
std::stringstream &buffer() { assert(false); }

std::chrono::system_clock::time_point get_current_time() const override {
return std::chrono::system_clock::time_point();
}

protected:
void write_header_info(int status, const http::headers_t &headers) override {}
output_buffer& get_buffer_internal() override {
throw std::runtime_error("test_request::get_buffer_internal unimplemented.");
}
void finish_internal() override {}

private:
std::map<std::string, std::string> m_params;
};
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

std::vector<api06::id_version> parse_query_str(std::string query_str) {
test_request req;
req.set_header("REQUEST_METHOD", "GET");
req.set_header("QUERY_STRING", query_str);
req.set_header("PATH_INFO", "/api/0.6/nodes");

return api06::parse_id_list_params(req, "nodes");
}

void test_parse_returns_no_duplicates() {
TEST_CASE("Id list returns no duplicates", "[idlist]") {
// the container returned from parse_id_list_params should not contain any duplicates.
std::string query_str = "nodes=1,1,1,1";

// the container returned from parse_id_list_params should not contain
// any duplicates.
std::vector<api06::id_version> ids = parse_query_str(query_str);

if (ids.size() != 1) {
std::ostringstream err;
err << "Parsing " << query_str << " as a list of nodes should "
<< "discard duplicates, but got: {";
for (api06::id_version id : ids) {
err << id << ", ";
}
err << "}\n";
throw std::runtime_error(err.str());
}
auto ids = parse_query_str(query_str);
CHECK(ids.size() == 1);
}

void test_parse_negative_nodes() {
TEST_CASE("Id list parse negative nodes", "[idlist]") {

std::string query_str =
"nodes=-1875196430,1970729486,-715595887,153329585,276538320,276538320,"
"276538320,276538320,557671215,268800768,268800768,272134694,416571249,"
"4118507737,639141976,-120408340,4118507737,4118507737,-176459559,"
"-176459559,-176459559,416571249,-176459559,-176459559,-176459559,"
"557671215";

std::vector<api06::id_version> ids = parse_query_str(query_str);
auto ids = parse_query_str(query_str);

// maximum ID that postgres can handle is 2^63-1, so that should never
// be returned by the parsing function.
const osm_nwr_id_t max_id = std::numeric_limits<int64_t>::max();
for (api06::id_version idv : ids) {
if (idv.id > max_id) {
throw std::runtime_error("Found ID > max allowed ID in parsed list.");
}
CHECK (idv.id < max_id);
}
}

void test_parse_garbage() {
std::string query_str =
"nodes=\xf5";

// may not crash
std::vector<api06::id_version> ids = parse_query_str(query_str);

TEST_CASE("Id list with garbage", "[idlist]") {
std::string query_str = "nodes=\xf5";
REQUIRE_NOTHROW(parse_query_str(query_str));
}

void test_parse_history() {
TEST_CASE("Id list with history", "[idlist]") {
std::string query_str = "nodes=1,1v1";
auto ids = parse_query_str(query_str);

std::vector<api06::id_version> ids = parse_query_str(query_str);

if (ids.size() != 2) {
throw std::runtime_error("Expected ID list of size 2.");
}

// NOTE: ID list is uniqued and sorted, which puts the "latest" version
// at the end.
if (ids[0] != api06::id_version(1, 1)) {
std::ostringstream out;
out << "Expected ID=1, version=1 to be the first element, but got "
<< ids[0] << ".";
throw std::runtime_error(out.str());
}

if (ids[1] != api06::id_version(1)) {
throw std::runtime_error("Expected ID=1, latest version to be the second element.");
}
}

} // anonymous namespace

int main(int argc, char *argv[]) {
try {
test_parse_returns_no_duplicates();
test_parse_negative_nodes();
test_parse_history();
test_parse_garbage();

} catch (const std::exception &e) {
std::cout << "Error: " << e.what() << std::endl;
return 1;

} catch (...) {
std::cout << "Unknown exception type." << std::endl;
return 99;
}
CHECK(ids.size() == 2);

return 0;
// NOTE: ID list is uniqued and sorted, which puts the "latest" version at the end.
CHECK(ids[0] == api06::id_version(1, 1));
CHECK(ids[1] == api06::id_version(1));
}

0 comments on commit e650dff

Please sign in to comment.