108 lines
3.1 KiB
C
108 lines
3.1 KiB
C
|
/*
|
||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <folly/dynamic.h>
|
||
|
#include <folly/json.h>
|
||
|
#include <folly/json_pointer.h>
|
||
|
#include <gmock/gmock.h>
|
||
|
|
||
|
namespace facebook {
|
||
|
|
||
|
namespace folly_dynamic_matchers_utils {
|
||
|
|
||
|
std::string as_string(std::string value);
|
||
|
std::string as_string(folly::dynamic value);
|
||
|
std::string explain_error(
|
||
|
folly::dynamic::json_pointer_resolution_error<const folly::dynamic> error);
|
||
|
|
||
|
} // namespace folly_dynamic_matchers_utils
|
||
|
|
||
|
// GTest / GMock compatible matchers for `folly::dynamic` values.
|
||
|
|
||
|
/**
|
||
|
* Parses a JSON string into a folly::dynamic, then matches it against the
|
||
|
* given matcher.
|
||
|
*/
|
||
|
MATCHER_P(
|
||
|
JsonParsed,
|
||
|
innerMatcher,
|
||
|
std::string{"parsed as JSON "} +
|
||
|
testing::DescribeMatcher<folly::dynamic>(innerMatcher, negation)) {
|
||
|
using namespace ::testing;
|
||
|
using namespace folly_dynamic_matchers_utils;
|
||
|
const auto& json = arg;
|
||
|
folly::dynamic parsed = folly::parseJson(as_string(json));
|
||
|
return ExplainMatchResult(innerMatcher, parsed, result_listener);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Given a folly::dynamic argument, asserts that it is deeply equal to the
|
||
|
* result of parsing the given JSON string.
|
||
|
*/
|
||
|
MATCHER_P(
|
||
|
JsonEq,
|
||
|
expected,
|
||
|
std::string{"deeply equals "} +
|
||
|
folly::toPrettyJson(folly::parseJson(expected))) {
|
||
|
using namespace ::testing;
|
||
|
return ExplainMatchResult(
|
||
|
JsonParsed(Eq(folly::parseJson(expected))), arg, result_listener);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A higher-order matcher that applies an inner matcher to the value at a
|
||
|
* particular JSON Pointer location within a folly::dynamic.
|
||
|
*/
|
||
|
MATCHER_P2(
|
||
|
AtJsonPtr,
|
||
|
jsonPointer,
|
||
|
innerMatcher,
|
||
|
std::string{"value at "} + jsonPointer + " " +
|
||
|
testing::DescribeMatcher<folly::dynamic>(innerMatcher, negation)) {
|
||
|
using namespace ::testing;
|
||
|
using namespace folly_dynamic_matchers_utils;
|
||
|
auto resolved_ptr = arg.try_get_ptr(folly::json_pointer::parse(jsonPointer));
|
||
|
if (resolved_ptr.hasValue()) {
|
||
|
return ExplainMatchResult(
|
||
|
innerMatcher, *resolved_ptr.value().value, result_listener);
|
||
|
}
|
||
|
*result_listener << "has no value at " << jsonPointer << " because of error: "
|
||
|
<< explain_error(resolved_ptr.error());
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A higher-order matcher that applies an inner matcher to the string value of
|
||
|
* a folly::dynamic.
|
||
|
*/
|
||
|
MATCHER_P(
|
||
|
DynamicString,
|
||
|
innerMatcher,
|
||
|
std::string{"string value "} +
|
||
|
testing::DescribeMatcher<std::string>(innerMatcher, negation)) {
|
||
|
using namespace ::testing;
|
||
|
using namespace folly_dynamic_matchers_utils;
|
||
|
if (!arg.isString()) {
|
||
|
*result_listener << "is not a string";
|
||
|
return false;
|
||
|
}
|
||
|
return ExplainMatchResult(innerMatcher, arg.getString(), result_listener);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A user-defined literal for constructing a folly::dynamic from a JSON
|
||
|
* string. Not technically specific to GMock, but convenient to have in a test
|
||
|
* suite.
|
||
|
*/
|
||
|
inline folly::dynamic operator""_json(const char* s, size_t n) {
|
||
|
return folly::parseJson(std::string{s, n});
|
||
|
}
|
||
|
|
||
|
} // namespace facebook
|