Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/rpcspec/RpcSpec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ struct RpcSpec
* @return An error on the first failing field; empty on success.
*/
template <typename V>
requires(not SomeObjectView<V>) and HasObjectView<V>
requires(not SomeObjectView<V>) and HasObjectView<V> and (not std::is_const_v<V>)
[[nodiscard]] MaybeError
process(V& value) const
{
Expand Down
3 changes: 2 additions & 1 deletion include/rpcspec/RpcSpecView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <rpcspec/Types.hpp>

#include <concepts>
#include <type_traits>

namespace rpc::spec {

Expand Down Expand Up @@ -136,7 +137,7 @@ class RpcSpecView
* @return An error on the first failing field; empty on success.
*/
template <typename V>
requires(not SomeObjectView<V>) and HasObjectView<V>
requires(not SomeObjectView<V>) and HasObjectView<V> and (not std::is_const_v<V>)
[[nodiscard]] MaybeError
process(V& value) const
{
Expand Down
2 changes: 1 addition & 1 deletion include/rpcspec/Typed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ struct TypedSpec
* @return The populated `InputT` on success, or an error on the first failing field.
*/
template <typename V>
requires(not SomeObjectView<V>) and HasObjectView<V>
requires(not SomeObjectView<V>) and HasObjectView<V> and (not std::is_const_v<V>)
[[nodiscard]] std::expected<InputT, rpc::Status>
parse(V& value) const
{
Expand Down
14 changes: 14 additions & 0 deletions tests/SpecCoreTests.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <boost/json/parse.hpp>
#include <boost/json/value.hpp>

#include <gtest/gtest.h>
#include <rpcspec/Aliases.hpp>
Expand All @@ -24,6 +25,9 @@ using namespace rpc::spec;

namespace {

template <typename Spec, typename V>
concept CanProcess = requires(Spec const& spec, V& value) { spec.process(value); };

TEST(RpcSpecDSL, ValidRequestPasses)
{
static constexpr auto kSpec = RpcSpec{
Expand Down Expand Up @@ -153,6 +157,16 @@ TEST(RpcSpecDSL, VersionedSpecViaRpcSpecView)
EXPECT_TRUE(spec(2).process(valid).has_value());
}

TEST(RpcSpecDSL, ProcessRejectsAConstDocument)
{
static constexpr auto kSpec = RpcSpec{field("account", required, account)};

static_assert(CanProcess<decltype(kSpec), boost::json::value>);
static_assert(not CanProcess<decltype(kSpec), boost::json::value const>);
static_assert(CanProcess<RpcSpecView<ObjectView>, boost::json::value>);
static_assert(not CanProcess<RpcSpecView<ObjectView>, boost::json::value const>);
}

TEST(RpcSpecDSL_Override, ExtendingASpecCanOverrideAnExistingField)
{
// V1 requires the field to be a bool; V2 overrides the same key to require a string.
Expand Down
10 changes: 10 additions & 0 deletions tests/SpecDefaultTests.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <boost/json/parse.hpp>
#include <boost/json/value.hpp>

#include <gtest/gtest.h>
#include <rpcspec/Aliases.hpp>
Expand Down Expand Up @@ -48,8 +49,17 @@ parse(char const* json)
return *result;
}

template <typename V>
concept CanParse = requires(V& value) { kSpec.parse(value); };

} // namespace

TEST(RpcSpecDSL_Default, ParseRejectsAConstDocument)
{
static_assert(CanParse<boost::json::value>);
static_assert(not CanParse<boost::json::value const>);
}

TEST(RpcSpecDSL_Default, AbsentFieldReceivesSpecDefault)
{
auto const in = parse(R"JSON({})JSON");
Expand Down
Loading