Skip to content

Commit d0fca0d

Browse files
committed
Add unit tests with matching/non-matching args
1 parent 87e00e0 commit d0fca0d

File tree

6 files changed

+144
-2
lines changed

6 files changed

+144
-2
lines changed

GraphQLResponse.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ bool Value::operator==(const Value& rhs) const noexcept
153153

154154
case Type::String:
155155
case Type::EnumValue:
156-
return _string == rhs._string;
156+
return *_string == *rhs._string;
157157

158158
case Type::Null:
159159
return true;

include/Today.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,11 @@ class Subscription : public object::Subscription
487487
{
488488
throw std::runtime_error("Unexpected call to getNextAppointmentChange");
489489
}
490+
491+
std::future<std::shared_ptr<service::Object>> getNodeChange(service::FieldParams&&, std::vector<uint8_t>&&) const override
492+
{
493+
throw std::runtime_error("Unexpected call to getNodeChange");
494+
}
490495
};
491496

492497
class NextAppointmentChange : public object::Subscription
@@ -508,10 +513,43 @@ class NextAppointmentChange : public object::Subscription
508513
return promise.get_future();
509514
}
510515

516+
std::future<std::shared_ptr<service::Object>> getNodeChange(service::FieldParams&&, std::vector<uint8_t>&&) const override
517+
{
518+
throw std::runtime_error("Unexpected call to getNodeChange");
519+
}
520+
511521
private:
512522
nextAppointmentChange _changeNextAppointment;
513523
};
514524

525+
class NodeChange : public object::Subscription
526+
{
527+
public:
528+
using nodeChange = std::function<std::shared_ptr<service::Object>(const std::shared_ptr<service::RequestState>&, std::vector<uint8_t>&&)>;
529+
530+
explicit NodeChange(nodeChange&& changeNode)
531+
: _changeNode(std::move(changeNode))
532+
{
533+
}
534+
535+
std::future<std::shared_ptr<object::Appointment>> getNextAppointmentChange(service::FieldParams&&) const override
536+
{
537+
throw std::runtime_error("Unexpected call to getNextAppointmentChange");
538+
}
539+
540+
std::future<std::shared_ptr<service::Object>> getNodeChange(service::FieldParams&& params, std::vector<uint8_t>&& idArg) const override
541+
{
542+
std::promise<std::shared_ptr<service::Object>> promise;
543+
544+
promise.set_value(std::static_pointer_cast<service::Object>(_changeNode(params.state, std::move(idArg))));
545+
546+
return promise.get_future();
547+
}
548+
549+
private:
550+
nodeChange _changeNode;
551+
};
552+
515553
struct CapturedParams
516554
{
517555
// Copied in the constructor

samples/TodaySchema.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ Subscription::Subscription()
540540
"Subscription"
541541
}, {
542542
{ "nextAppointmentChange", [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } },
543+
{ "nodeChange", [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } },
543544
{ "__typename", [this](service::ResolverParams&& params) { return resolve__typename(std::move(params)); } }
544545
})
545546
{
@@ -552,6 +553,14 @@ std::future<response::Value> Subscription::resolveNextAppointmentChange(service:
552553
return service::ModifiedResult<Appointment>::convert<service::TypeModifier::Nullable>(std::move(result), std::move(params));
553554
}
554555

556+
std::future<response::Value> Subscription::resolveNodeChange(service::ResolverParams&& params)
557+
{
558+
auto argId = service::ModifiedArgument<std::vector<uint8_t>>::require("id", params.arguments);
559+
auto result = getNodeChange(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argId));
560+
561+
return service::ModifiedResult<service::Object>::convert(std::move(result), std::move(params));
562+
}
563+
555564
std::future<response::Value> Subscription::resolve__typename(service::ResolverParams&&)
556565
{
557566
std::promise<response::Value> promise;
@@ -883,7 +892,10 @@ void AddTypesToSchema(std::shared_ptr<introspection::Schema> schema)
883892
}), schema->WrapType(introspection::__TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")))
884893
});
885894
typeSubscription->AddFields({
886-
std::make_shared<introspection::Field>("nextAppointmentChange", R"md()md", std::unique_ptr<std::string>(new std::string(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md")), std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Appointment"))
895+
std::make_shared<introspection::Field>("nextAppointmentChange", R"md()md", std::unique_ptr<std::string>(new std::string(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md")), std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Appointment")),
896+
std::make_shared<introspection::Field>("nodeChange", R"md()md", std::unique_ptr<std::string>(nullptr), std::vector<std::shared_ptr<introspection::InputValue>>({
897+
std::make_shared<introspection::InputValue>("id", R"md()md", schema->WrapType(introspection::__TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql")
898+
}), schema->WrapType(introspection::__TypeKind::NON_NULL, schema->LookupType("Node")))
887899
});
888900
typeAppointment->AddInterfaces({
889901
typeNode

samples/TodaySchema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,11 @@ class Subscription
253253

254254
public:
255255
virtual std::future<std::shared_ptr<Appointment>> getNextAppointmentChange(service::FieldParams&& params) const = 0;
256+
virtual std::future<std::shared_ptr<service::Object>> getNodeChange(service::FieldParams&& params, std::vector<uint8_t>&& idArg) const = 0;
256257

257258
private:
258259
std::future<response::Value> resolveNextAppointmentChange(service::ResolverParams&& params);
260+
std::future<response::Value> resolveNodeChange(service::ResolverParams&& params);
259261

260262
std::future<response::Value> resolve__typename(service::ResolverParams&& params);
261263
};

samples/schema.today.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type Mutation {
8585

8686
type Subscription {
8787
nextAppointmentChange : Appointment @deprecated(reason:"""Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation)""")
88+
nodeChange(id: ID!): Node!
8889
}
8990

9091
directive @subscriptionTag(field: String) on SUBSCRIPTION

tests.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,95 @@ TEST_F(TodayServiceCase, QueryAppointmentsById)
833833
}
834834
}
835835

836+
TEST_F(TodayServiceCase, SubscribeNodeChangeMatchingId)
837+
{
838+
auto ast = peg::parseString(R"(subscription TestSubscription {
839+
changedNode: nodeChange(id: "ZmFrZVRhc2tJZA==") {
840+
changedId: id
841+
...on Task {
842+
title
843+
isComplete
844+
}
845+
}
846+
})");
847+
response::Value variables(response::Type::Map);
848+
auto state = std::make_shared<today::RequestState>(13);
849+
auto subscriptionObject = std::make_shared<today::NodeChange>(
850+
[this](const std::shared_ptr<service::RequestState>& state, std::vector<uint8_t>&& idArg) -> std::shared_ptr<service::Object>
851+
{
852+
EXPECT_EQ(13, std::static_pointer_cast<today::RequestState>(state)->requestId) << "should pass the RequestState to the subscription resolvers";
853+
EXPECT_EQ(_fakeTaskId, idArg);
854+
return std::static_pointer_cast<service::Object>(std::make_shared<today::Task>(std::vector<uint8_t>(_fakeTaskId), "Don't forget", true));
855+
});
856+
response::Value result;
857+
auto key = _service->subscribe(service::SubscriptionParams { state, std::move(ast), "TestSubscription", std::move(std::move(variables)) },
858+
[&result](std::future<response::Value> response)
859+
{
860+
result = response.get();
861+
});
862+
_service->deliver("nodeChange", { {"id", response::Value(std::string("ZmFrZVRhc2tJZA==")) } }, std::static_pointer_cast<service::Object>(subscriptionObject));
863+
_service->unsubscribe(key);
864+
865+
try
866+
{
867+
ASSERT_TRUE(result.type() == response::Type::Map);
868+
auto errorsItr = result.find("errors");
869+
if (errorsItr != result.get<const response::MapType&>().cend())
870+
{
871+
FAIL() << response::toJSON(response::Value(errorsItr->second));
872+
}
873+
const auto data = service::ScalarArgument::require("data", result);
874+
875+
const auto taskNode = service::ScalarArgument::require("changedNode", data);
876+
EXPECT_EQ(_fakeTaskId, service::IdArgument::require("changedId", taskNode)) << "id should match in base64 encoding";
877+
EXPECT_EQ("Don't forget", service::StringArgument::require("title", taskNode)) << "title should match";
878+
EXPECT_TRUE(service::BooleanArgument::require("isComplete", taskNode)) << "isComplete should match";
879+
}
880+
catch (const service::schema_exception& ex)
881+
{
882+
FAIL() << response::toJSON(response::Value(ex.getErrors()));
883+
}
884+
}
885+
886+
TEST_F(TodayServiceCase, SubscribeNodeChangeMismatchedId)
887+
{
888+
auto ast = peg::parseString(R"(subscription TestSubscription {
889+
changedNode: nodeChange(id: "ZmFrZVRhc2tJZA==") {
890+
changedId: id
891+
...on Task {
892+
title
893+
isComplete
894+
}
895+
}
896+
})");
897+
response::Value variables(response::Type::Map);
898+
bool calledResolver = false;
899+
auto subscriptionObject = std::make_shared<today::NodeChange>(
900+
[this, &calledResolver](const std::shared_ptr<service::RequestState>& state, std::vector<uint8_t>&& idArg) -> std::shared_ptr<service::Object>
901+
{
902+
calledResolver = true;
903+
return nullptr;
904+
});
905+
bool calledGet = false;
906+
auto key = _service->subscribe(service::SubscriptionParams { nullptr, std::move(ast), "TestSubscription", std::move(std::move(variables)) },
907+
[&calledGet](std::future<response::Value>)
908+
{
909+
calledGet = true;
910+
});
911+
_service->deliver("nodeChange", { {"id", response::Value(std::string("ZmFrZUFwcG9pbnRtZW50SWQ=")) } }, std::static_pointer_cast<service::Object>(subscriptionObject));
912+
_service->unsubscribe(key);
913+
914+
try
915+
{
916+
ASSERT_FALSE(calledResolver);
917+
ASSERT_FALSE(calledGet);
918+
}
919+
catch (const service::schema_exception& ex)
920+
{
921+
FAIL() << response::toJSON(response::Value(ex.getErrors()));
922+
}
923+
}
924+
836925
TEST(ArgumentsCase, ListArgumentStrings)
837926
{
838927
auto parsed = response::parseJSON(R"js({"value":[

0 commit comments

Comments
 (0)