Refactor JSON Pointer test cases into generalised test runner and test cases

This commit is contained in:
Tristan Penman 2015-05-06 07:03:20 +10:00
parent feaea37aee
commit fb1f08181d

View File

@ -1,3 +1,6 @@
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
#include <valijson/internal/json_reference.hpp>
@ -7,57 +10,105 @@
using valijson::adapters::RapidJsonAdapter;
using valijson::internal::json_reference::resolveJsonPointer;
namespace {
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> allocator;
}
typedef rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>
RapidJsonCrtAllocator;
class TestJsonReference : public testing::Test
{
};
TEST_F(TestJsonReference, PointerWithoutLeadingSlashShouldThrow)
struct JsonPointerTestCase
{
// Given an Adapter for a JSON object
rapidjson::Value value;
value.SetObject();
const RapidJsonAdapter rootAdapter(value);
JsonPointerTestCase(const std::string &description)
: description(description) { }
// When a JSON Pointer that does not begin with a slash is resolved
// Then an exception should be thrown
EXPECT_THROW(resolveJsonPointer(rootAdapter, "#"), std::runtime_error);
/// Description of test case
std::string description;
/// Document to traverse when resolving the JSON Pointer
rapidjson::Value value;
/// JSON Pointer that should guide traversal of the document
std::string jsonPointer;
/// Optional reference to the expected result from the original document
rapidjson::Value *expectedValue;
};
std::vector<boost::shared_ptr<JsonPointerTestCase> >
testCasesForSingleLevelObjectPointers(
RapidJsonCrtAllocator &allocator)
{
typedef boost::shared_ptr<JsonPointerTestCase> TestCase;
std::vector<TestCase> testCases;
TestCase testCase = boost::make_shared<JsonPointerTestCase>(
"Resolving '#' should cause an exception to be thrown");
testCase->value.SetNull();
testCase->jsonPointer = "#";
testCase->expectedValue = NULL;
testCases.push_back(testCase);
testCase = boost::make_shared<JsonPointerTestCase>(
"Resolving an empty string should cause an exception to be thrown");
testCase->value.SetNull();
testCase->jsonPointer = "";
testCase->expectedValue = NULL;
testCases.push_back(testCase);
testCase = boost::make_shared<JsonPointerTestCase>(
"Resolve '/test' in object containing one member named 'test'");
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/test";
testCase->expectedValue = &testCase->value.FindMember("test")->value;
testCases.push_back(testCase);
testCase = boost::make_shared<JsonPointerTestCase>(
"Resolve '/test/' in object containing one member named 'test' "
"should cause an exception to be thrown");
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/test/";
testCase->expectedValue = NULL;
testCases.push_back(testCase);
testCase = boost::make_shared<JsonPointerTestCase>(
"Resolve '/missing' in object containing one member name 'test'");
testCase->value.SetObject();
testCase->value.AddMember("test", "test", allocator);
testCase->jsonPointer = "/missing";
testCase->expectedValue = NULL;
testCases.push_back(testCase);
return testCases;
}
TEST_F(TestJsonReference, RootPointer)
TEST_F(TestJsonReference, JsonPointerTestCases)
{
// Given an Adapter for a JSON object containing one attribute
rapidjson::Value value;
value.SetObject();
value.AddMember("test", "test", allocator);
const RapidJsonAdapter rootAdapter(value);
typedef std::vector<boost::shared_ptr<JsonPointerTestCase> > TestCases;
// When a JSON Pointer that points to the root node is resolved
const RapidJsonAdapter resultAdapter = resolveJsonPointer(rootAdapter, "/");
// Ensure memory used for test cases is freed when test function completes
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> allocator;
// Then the returned Adapter should also refer to the root node
EXPECT_TRUE(resultAdapter.isObject());
const RapidJsonAdapter::Object object = resultAdapter.asObject();
EXPECT_NE(object.end(), object.find("test"));
}
TEST_F(TestJsonReference, SingleLevelObjectPointer)
{
// Given an Adapter for a JSON object containing one attribute
rapidjson::Value value;
value.SetObject();
value.AddMember("test", "test", allocator);
const RapidJsonAdapter rootAdapter(value);
// When a JSON Pointer that points to the only member is resolved
const RapidJsonAdapter resultAdapter =
resolveJsonPointer(rootAdapter, "/test");
// Then the returned Adapter should refer to the value of that member
EXPECT_TRUE(resultAdapter.isString());
EXPECT_STREQ("test", resultAdapter.getString().c_str());
TestCases testCases = testCasesForSingleLevelObjectPointers(allocator);
for (TestCases::const_iterator itr = testCases.begin();
itr != testCases.end(); ++itr) {
const std::string &jsonPointer = (*itr)->jsonPointer;
const RapidJsonAdapter valueAdapter((*itr)->value);
if ((*itr)->expectedValue) {
const RapidJsonAdapter expectedAdapter(*((*itr)->expectedValue));
const RapidJsonAdapter actualAdapter =
resolveJsonPointer(valueAdapter, jsonPointer);
EXPECT_TRUE(actualAdapter.equalTo(expectedAdapter, true)) <<
(*itr)->description;
} else {
EXPECT_THROW(
resolveJsonPointer(valueAdapter, jsonPointer),
std::runtime_error);
}
}
}