1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/validation.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <numeric>
8*3f982cf4SFabien Sanglard #include <string>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "absl/strings/string_view.h"
11*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/receiver_examples/get_app_availability_data.h"
12*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/receiver_examples/get_app_availability_response_data.h"
13*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/receiver_examples/launch_data.h"
14*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/receiver_examples/stop_data.h"
15*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/receiver_schema_data.h"
16*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/answer_data.h"
17*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/capabilities_response_data.h"
18*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/get_capabilities_data.h"
19*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/get_status_data.h"
20*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/offer_data.h"
21*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/rpc_data.h"
22*3f982cf4SFabien Sanglard #include "cast/protocol/castv2/streaming_examples/status_response_data.h"
23*3f982cf4SFabien Sanglard #include "gmock/gmock.h"
24*3f982cf4SFabien Sanglard #include "gtest/gtest.h"
25*3f982cf4SFabien Sanglard #include "json/value.h"
26*3f982cf4SFabien Sanglard #include "platform/base/error.h"
27*3f982cf4SFabien Sanglard #include "util/json/json_serialization.h"
28*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
29*3f982cf4SFabien Sanglard #include "util/std_util.h"
30*3f982cf4SFabien Sanglard #include "util/stringprintf.h"
31*3f982cf4SFabien Sanglard
32*3f982cf4SFabien Sanglard namespace openscreen {
33*3f982cf4SFabien Sanglard namespace cast {
34*3f982cf4SFabien Sanglard
35*3f982cf4SFabien Sanglard namespace {
36*3f982cf4SFabien Sanglard
37*3f982cf4SFabien Sanglard constexpr char kEmptyJson[] = "{}";
38*3f982cf4SFabien Sanglard
39*3f982cf4SFabien Sanglard // Schema format string, that allows for specifying definitions,
40*3f982cf4SFabien Sanglard // properties, and required fields.
41*3f982cf4SFabien Sanglard constexpr char kSchemaFormat[] = R"({
42*3f982cf4SFabien Sanglard "$schema": "http://json-schema.org/draft-07/schema#",
43*3f982cf4SFabien Sanglard "$id": "https://something/app_schema_data.h",
44*3f982cf4SFabien Sanglard "definitions": {
45*3f982cf4SFabien Sanglard %s
46*3f982cf4SFabien Sanglard },
47*3f982cf4SFabien Sanglard "type": "object",
48*3f982cf4SFabien Sanglard "properties": {
49*3f982cf4SFabien Sanglard %s
50*3f982cf4SFabien Sanglard },
51*3f982cf4SFabien Sanglard "required": [%s]
52*3f982cf4SFabien Sanglard })";
53*3f982cf4SFabien Sanglard
54*3f982cf4SFabien Sanglard // Fields used for an appId containing schema
55*3f982cf4SFabien Sanglard constexpr char kAppIdDefinition[] = R"("app_id": {
56*3f982cf4SFabien Sanglard "type": "string",
57*3f982cf4SFabien Sanglard "enum": ["0F5096E8", "85CDB22F"]
58*3f982cf4SFabien Sanglard })";
59*3f982cf4SFabien Sanglard constexpr char kAppIdName[] = "\"appId\"";
60*3f982cf4SFabien Sanglard constexpr char kAppIdProperty[] =
61*3f982cf4SFabien Sanglard R"( "appId": {"$ref": "#/definitions/app_id"})";
62*3f982cf4SFabien Sanglard
63*3f982cf4SFabien Sanglard // Teest documents containing an appId.
64*3f982cf4SFabien Sanglard constexpr char kValidAppIdDocument[] = R"({ "appId": "0F5096E8" })";
65*3f982cf4SFabien Sanglard constexpr char kInvalidAppIdDocument[] = R"({ "appId": "FooBar" })";
66*3f982cf4SFabien Sanglard
BuildSchema(const char * definitions,const char * properties,const char * required)67*3f982cf4SFabien Sanglard std::string BuildSchema(const char* definitions,
68*3f982cf4SFabien Sanglard const char* properties,
69*3f982cf4SFabien Sanglard const char* required) {
70*3f982cf4SFabien Sanglard return StringPrintf(kSchemaFormat, definitions, properties, required);
71*3f982cf4SFabien Sanglard }
72*3f982cf4SFabien Sanglard
TestValidate(absl::string_view document,absl::string_view schema)73*3f982cf4SFabien Sanglard bool TestValidate(absl::string_view document, absl::string_view schema) {
74*3f982cf4SFabien Sanglard ErrorOr<Json::Value> document_root = json::Parse(document);
75*3f982cf4SFabien Sanglard EXPECT_TRUE(document_root.is_value());
76*3f982cf4SFabien Sanglard ErrorOr<Json::Value> schema_root = json::Parse(schema);
77*3f982cf4SFabien Sanglard EXPECT_TRUE(schema_root.is_value());
78*3f982cf4SFabien Sanglard
79*3f982cf4SFabien Sanglard std::vector<Error> errors =
80*3f982cf4SFabien Sanglard Validate(document_root.value(), schema_root.value());
81*3f982cf4SFabien Sanglard return errors.empty();
82*3f982cf4SFabien Sanglard }
83*3f982cf4SFabien Sanglard
GetEmptySchema()84*3f982cf4SFabien Sanglard const std::string& GetEmptySchema() {
85*3f982cf4SFabien Sanglard static const std::string kEmptySchema = BuildSchema("", "", "");
86*3f982cf4SFabien Sanglard return kEmptySchema;
87*3f982cf4SFabien Sanglard }
88*3f982cf4SFabien Sanglard
GetAppSchema()89*3f982cf4SFabien Sanglard const std::string& GetAppSchema() {
90*3f982cf4SFabien Sanglard static const std::string kAppIdSchema =
91*3f982cf4SFabien Sanglard BuildSchema(kAppIdDefinition, kAppIdProperty, kAppIdName);
92*3f982cf4SFabien Sanglard return kAppIdSchema;
93*3f982cf4SFabien Sanglard }
94*3f982cf4SFabien Sanglard
95*3f982cf4SFabien Sanglard class StreamingValidationTest : public testing::TestWithParam<const char*> {};
96*3f982cf4SFabien Sanglard class ReceiverValidationTest : public testing::TestWithParam<const char*> {};
97*3f982cf4SFabien Sanglard
98*3f982cf4SFabien Sanglard } // namespace
99*3f982cf4SFabien Sanglard
TEST(ValidationTest,EmptyPassesEmpty)100*3f982cf4SFabien Sanglard TEST(ValidationTest, EmptyPassesEmpty) {
101*3f982cf4SFabien Sanglard EXPECT_TRUE(TestValidate(kEmptyJson, kEmptyJson));
102*3f982cf4SFabien Sanglard }
103*3f982cf4SFabien Sanglard
TEST(ValidationTest,EmptyPassesBasicSchema)104*3f982cf4SFabien Sanglard TEST(ValidationTest, EmptyPassesBasicSchema) {
105*3f982cf4SFabien Sanglard EXPECT_TRUE(TestValidate(kEmptyJson, GetEmptySchema()));
106*3f982cf4SFabien Sanglard }
107*3f982cf4SFabien Sanglard
TEST(ValidationTest,EmptyFailsAppIdSchema)108*3f982cf4SFabien Sanglard TEST(ValidationTest, EmptyFailsAppIdSchema) {
109*3f982cf4SFabien Sanglard EXPECT_FALSE(TestValidate(kEmptyJson, GetAppSchema()));
110*3f982cf4SFabien Sanglard }
111*3f982cf4SFabien Sanglard
TEST(ValidationTest,InvalidAppIdFailsAppIdSchema)112*3f982cf4SFabien Sanglard TEST(ValidationTest, InvalidAppIdFailsAppIdSchema) {
113*3f982cf4SFabien Sanglard EXPECT_FALSE(TestValidate(kInvalidAppIdDocument, GetAppSchema()));
114*3f982cf4SFabien Sanglard }
115*3f982cf4SFabien Sanglard
TEST(ValidationTest,ValidAppIdPassesAppIdSchema)116*3f982cf4SFabien Sanglard TEST(ValidationTest, ValidAppIdPassesAppIdSchema) {
117*3f982cf4SFabien Sanglard EXPECT_TRUE(TestValidate(kValidAppIdDocument, GetAppSchema()));
118*3f982cf4SFabien Sanglard }
119*3f982cf4SFabien Sanglard
TEST(ValidationTest,InvalidAppIdPassesEmptySchema)120*3f982cf4SFabien Sanglard TEST(ValidationTest, InvalidAppIdPassesEmptySchema) {
121*3f982cf4SFabien Sanglard EXPECT_TRUE(TestValidate(kInvalidAppIdDocument, GetEmptySchema()));
122*3f982cf4SFabien Sanglard }
123*3f982cf4SFabien Sanglard
TEST(ValidationTest,ValidAppIdPassesEmptySchema)124*3f982cf4SFabien Sanglard TEST(ValidationTest, ValidAppIdPassesEmptySchema) {
125*3f982cf4SFabien Sanglard EXPECT_TRUE(TestValidate(kValidAppIdDocument, GetEmptySchema()));
126*3f982cf4SFabien Sanglard }
127*3f982cf4SFabien Sanglard
128*3f982cf4SFabien Sanglard INSTANTIATE_TEST_SUITE_P(StreamingValidations,
129*3f982cf4SFabien Sanglard StreamingValidationTest,
130*3f982cf4SFabien Sanglard testing::Values(kAnswer,
131*3f982cf4SFabien Sanglard kCapabilitiesResponse,
132*3f982cf4SFabien Sanglard kGetCapabilities,
133*3f982cf4SFabien Sanglard kGetStatus,
134*3f982cf4SFabien Sanglard kOffer,
135*3f982cf4SFabien Sanglard kRpc,
136*3f982cf4SFabien Sanglard kStatusResponse));
137*3f982cf4SFabien Sanglard
TEST_P(StreamingValidationTest,ExampleStreamingMessages)138*3f982cf4SFabien Sanglard TEST_P(StreamingValidationTest, ExampleStreamingMessages) {
139*3f982cf4SFabien Sanglard ErrorOr<Json::Value> message_root = json::Parse(GetParam());
140*3f982cf4SFabien Sanglard EXPECT_TRUE(message_root.is_value());
141*3f982cf4SFabien Sanglard EXPECT_TRUE(ValidateStreamingMessage(message_root.value()).empty());
142*3f982cf4SFabien Sanglard }
143*3f982cf4SFabien Sanglard
ExpectReceiverMessageValid(const char * message)144*3f982cf4SFabien Sanglard void ExpectReceiverMessageValid(const char* message) {}
145*3f982cf4SFabien Sanglard
146*3f982cf4SFabien Sanglard INSTANTIATE_TEST_SUITE_P(ReceiverValidations,
147*3f982cf4SFabien Sanglard ReceiverValidationTest,
148*3f982cf4SFabien Sanglard testing::Values(kGetAppAvailability,
149*3f982cf4SFabien Sanglard kGetAppAvailabilityResponse,
150*3f982cf4SFabien Sanglard kLaunch,
151*3f982cf4SFabien Sanglard kStop));
152*3f982cf4SFabien Sanglard
TEST_P(ReceiverValidationTest,ExampleReceiverMessages)153*3f982cf4SFabien Sanglard TEST_P(ReceiverValidationTest, ExampleReceiverMessages) {
154*3f982cf4SFabien Sanglard ErrorOr<Json::Value> message_root = json::Parse(GetParam());
155*3f982cf4SFabien Sanglard EXPECT_TRUE(message_root.is_value());
156*3f982cf4SFabien Sanglard EXPECT_TRUE(ValidateReceiverMessage(message_root.value()).empty());
157*3f982cf4SFabien Sanglard }
158*3f982cf4SFabien Sanglard } // namespace cast
159*3f982cf4SFabien Sanglard } // namespace openscreen
160