aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Bayles <jophba@chromium.org>2021-06-04 11:42:08 -0700
committerOpenscreen LUCI CQ <openscreen-scoped@luci-project-accounts.iam.gserviceaccount.com>2021-06-04 19:38:37 +0000
commitaccf7fd700bff19266b17eb271e3c805a3230352 (patch)
treedbf63a464dad4321e8b4605e57a06c8dc6ef3ba4
parentdec3ae516ec228e649869988229b0e48ee8bc269 (diff)
downloadopenscreen-accf7fd700bff19266b17eb271e3c805a3230352.tar.gz
[Cast Streaming] Cleanup OFFER/ANSWER
This patch finishes handling a TODO around json deserialization for offer messages, and removes some of the duplicate code in the json_helpers.h header. One more followup patch after this: ParseAndValidate* methods be simply renamed to Parse* methods. Change-Id: I36db01f1841731793597e5f89e904edb36d027ef Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/2911769 Commit-Queue: Jordan Bayles <jophba@chromium.org> Reviewed-by: Ryan Keane <rwkeane@google.com>
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.cc16
-rw-r--r--cast/streaming/answer_messages.cc112
-rw-r--r--cast/streaming/answer_messages.h18
-rw-r--r--cast/streaming/answer_messages_unittest.cc48
-rw-r--r--cast/streaming/offer_messages.cc393
-rw-r--r--cast/streaming/offer_messages.h7
-rw-r--r--cast/streaming/offer_messages_unittest.cc55
-rw-r--r--cast/streaming/receiver_message.cc29
-rw-r--r--cast/streaming/resolution.cc15
-rw-r--r--cast/streaming/resolution.h4
-rw-r--r--cast/streaming/sender_message.cc13
-rw-r--r--cast/streaming/session_messager.cc4
-rw-r--r--util/json/json_helpers.h92
-rw-r--r--util/json/json_helpers_unittest.cc121
14 files changed, 427 insertions, 500 deletions
diff --git a/cast/standalone_sender/looping_file_cast_agent.cc b/cast/standalone_sender/looping_file_cast_agent.cc
index 5477c155..e26d4f5e 100644
--- a/cast/standalone_sender/looping_file_cast_agent.cc
+++ b/cast/standalone_sender/looping_file_cast_agent.cc
@@ -132,8 +132,7 @@ void LoopingFileCastAgent::OnMessage(VirtualConnectionRouter* router,
HandleReceiverStatus(payload.value());
} else if (HasType(payload.value(), CastMessageType::kLaunchError)) {
std::string reason;
- if (!json::ParseAndValidateString(payload.value()[kMessageKeyReason],
- &reason)) {
+ if (!json::TryParseString(payload.value()[kMessageKeyReason], &reason)) {
reason = "UNKNOWN";
}
OSP_LOG_ERROR
@@ -142,8 +141,7 @@ void LoopingFileCastAgent::OnMessage(VirtualConnectionRouter* router,
Shutdown();
} else if (HasType(payload.value(), CastMessageType::kInvalidRequest)) {
std::string reason;
- if (!json::ParseAndValidateString(payload.value()[kMessageKeyReason],
- &reason)) {
+ if (!json::TryParseString(payload.value()[kMessageKeyReason], &reason)) {
reason = "UNKNOWN";
}
OSP_LOG_ERROR << "Cast Receiver thinks our request is invalid: "
@@ -167,8 +165,7 @@ void LoopingFileCastAgent::HandleReceiverStatus(const Json::Value& status) {
: Json::Value();
std::string running_app_id;
- if (!json::ParseAndValidateString(details[kMessageKeyAppId],
- &running_app_id) ||
+ if (!json::TryParseString(details[kMessageKeyAppId], &running_app_id) ||
running_app_id != GetMirroringAppId()) {
// The mirroring app is not running. If it was just stopped, Shutdown() will
// tear everything down. If it has been stopped already, Shutdown() is a
@@ -178,8 +175,7 @@ void LoopingFileCastAgent::HandleReceiverStatus(const Json::Value& status) {
}
std::string session_id;
- if (!json::ParseAndValidateString(details[kMessageKeySessionId],
- &session_id) ||
+ if (!json::TryParseString(details[kMessageKeySessionId], &session_id) ||
session_id.empty()) {
OSP_LOG_ERROR
<< "Cannot continue: Cast Receiver did not provide a session ID for "
@@ -207,8 +203,8 @@ void LoopingFileCastAgent::HandleReceiverStatus(const Json::Value& status) {
}
std::string message_destination_id;
- if (!json::ParseAndValidateString(details[kMessageKeyTransportId],
- &message_destination_id) ||
+ if (!json::TryParseString(details[kMessageKeyTransportId],
+ &message_destination_id) ||
message_destination_id.empty()) {
OSP_LOG_ERROR
<< "Cannot continue: Cast Receiver did not provide a transport ID for "
diff --git a/cast/streaming/answer_messages.cc b/cast/streaming/answer_messages.cc
index c59aeff8..20af542f 100644
--- a/cast/streaming/answer_messages.cc
+++ b/cast/streaming/answer_messages.cc
@@ -9,9 +9,9 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "platform/base/error.h"
+#include "util/enum_name_table.h"
#include "util/json/json_helpers.h"
#include "util/osp_logging.h"
-
namespace openscreen {
namespace cast {
@@ -110,35 +110,29 @@ static constexpr char kReceiverRtcpDscp[] = "receiverRtcpDscp";
// RTP extensions (such as adaptive playout delay).
static constexpr char kRtpExtensions[] = "rtpExtensions";
+EnumNameTable<AspectRatioConstraint, 2> kAspectRatioConstraintNames{
+ {{kScalingReceiver, AspectRatioConstraint::kVariable},
+ {kScalingSender, AspectRatioConstraint::kFixed}}};
+
Json::Value AspectRatioConstraintToJson(AspectRatioConstraint aspect_ratio) {
- switch (aspect_ratio) {
- case AspectRatioConstraint::kVariable:
- return Json::Value(kScalingReceiver);
- case AspectRatioConstraint::kFixed:
- default:
- return Json::Value(kScalingSender);
- }
+ return Json::Value(GetEnumName(kAspectRatioConstraintNames, aspect_ratio)
+ .value(kScalingSender));
}
-bool AspectRatioConstraintParseAndValidate(const Json::Value& value,
- AspectRatioConstraint* out) {
- // the aspect ratio constraint is an optional field.
- if (!value) {
- return true;
- }
-
+bool TryParseAspectRatioConstraint(const Json::Value& value,
+ AspectRatioConstraint* out) {
std::string aspect_ratio;
- if (!json::ParseAndValidateString(value, &aspect_ratio)) {
+ if (!json::TryParseString(value, &aspect_ratio)) {
return false;
}
- if (aspect_ratio == kScalingReceiver) {
- *out = AspectRatioConstraint::kVariable;
- return true;
- } else if (aspect_ratio == kScalingSender) {
- *out = AspectRatioConstraint::kFixed;
- return true;
+
+ ErrorOr<AspectRatioConstraint> constraint =
+ GetEnum(kAspectRatioConstraintNames, aspect_ratio);
+ if (constraint.is_error()) {
+ return false;
}
- return false;
+ *out = constraint.value();
+ return true;
}
template <typename T>
@@ -160,7 +154,7 @@ bool ParseOptional(const Json::Value& value, absl::optional<T>* out) {
return true;
}
T tentative_out;
- if (!T::ParseAndValidate(value, &tentative_out)) {
+ if (!T::TryParse(value, &tentative_out)) {
return false;
}
*out = tentative_out;
@@ -170,9 +164,9 @@ bool ParseOptional(const Json::Value& value, absl::optional<T>* out) {
} // namespace
// static
-bool AspectRatio::ParseAndValidate(const Json::Value& value, AspectRatio* out) {
+bool AspectRatio::TryParse(const Json::Value& value, AspectRatio* out) {
std::string parsed_value;
- if (!json::ParseAndValidateString(value, &parsed_value)) {
+ if (!json::TryParseString(value, &parsed_value)) {
return false;
}
@@ -194,21 +188,20 @@ bool AspectRatio::IsValid() const {
}
// static
-bool AudioConstraints::ParseAndValidate(const Json::Value& root,
- AudioConstraints* out) {
- if (!json::ParseAndValidateInt(root[kMaxSampleRate],
- &(out->max_sample_rate)) ||
- !json::ParseAndValidateInt(root[kMaxChannels], &(out->max_channels)) ||
- !json::ParseAndValidateInt(root[kMaxBitRate], &(out->max_bit_rate))) {
+bool AudioConstraints::TryParse(const Json::Value& root,
+ AudioConstraints* out) {
+ if (!json::TryParseInt(root[kMaxSampleRate], &(out->max_sample_rate)) ||
+ !json::TryParseInt(root[kMaxChannels], &(out->max_channels)) ||
+ !json::TryParseInt(root[kMaxBitRate], &(out->max_bit_rate))) {
return false;
}
std::chrono::milliseconds max_delay;
- if (json::ParseAndValidateMilliseconds(root[kMaxDelay], &max_delay)) {
+ if (json::TryParseMilliseconds(root[kMaxDelay], &max_delay)) {
out->max_delay = max_delay;
}
- if (!json::ParseAndValidateInt(root[kMinBitRate], &(out->min_bit_rate))) {
+ if (!json::TryParseInt(root[kMinBitRate], &(out->min_bit_rate))) {
out->min_bit_rate = kDefaultAudioMinBitRate;
}
return out->IsValid();
@@ -233,28 +226,26 @@ bool AudioConstraints::IsValid() const {
}
// static
-bool VideoConstraints::ParseAndValidate(const Json::Value& root,
- VideoConstraints* out) {
- if (!Dimensions::ParseAndValidate(root[kMaxDimensions],
- &(out->max_dimensions)) ||
- !json::ParseAndValidateInt(root[kMaxBitRate], &(out->max_bit_rate)) ||
+bool VideoConstraints::TryParse(const Json::Value& root,
+ VideoConstraints* out) {
+ if (!Dimensions::TryParse(root[kMaxDimensions], &(out->max_dimensions)) ||
+ !json::TryParseInt(root[kMaxBitRate], &(out->max_bit_rate)) ||
!ParseOptional<Dimensions>(root[kMinResolution],
&(out->min_resolution))) {
return false;
}
std::chrono::milliseconds max_delay;
- if (json::ParseAndValidateMilliseconds(root[kMaxDelay], &max_delay)) {
+ if (json::TryParseMilliseconds(root[kMaxDelay], &max_delay)) {
out->max_delay = max_delay;
}
double max_pixels_per_second;
- if (json::ParseAndValidateDouble(root[kMaxPixelsPerSecond],
- &max_pixels_per_second)) {
+ if (json::TryParseDouble(root[kMaxPixelsPerSecond], &max_pixels_per_second)) {
out->max_pixels_per_second = max_pixels_per_second;
}
- if (!json::ParseAndValidateInt(root[kMinBitRate], &(out->min_bit_rate))) {
+ if (!json::TryParseInt(root[kMinBitRate], &(out->min_bit_rate))) {
out->min_bit_rate = kDefaultVideoMinBitRate;
}
return out->IsValid();
@@ -290,9 +281,9 @@ Json::Value VideoConstraints::ToJson() const {
}
// static
-bool Constraints::ParseAndValidate(const Json::Value& root, Constraints* out) {
- if (!AudioConstraints::ParseAndValidate(root[kAudio], &(out->audio)) ||
- !VideoConstraints::ParseAndValidate(root[kVideo], &(out->video))) {
+bool Constraints::TryParse(const Json::Value& root, Constraints* out) {
+ if (!AudioConstraints::TryParse(root[kAudio], &(out->audio)) ||
+ !VideoConstraints::TryParse(root[kVideo], &(out->video))) {
return false;
}
return out->IsValid();
@@ -311,15 +302,15 @@ Json::Value Constraints::ToJson() const {
}
// static
-bool DisplayDescription::ParseAndValidate(const Json::Value& root,
- DisplayDescription* out) {
+bool DisplayDescription::TryParse(const Json::Value& root,
+ DisplayDescription* out) {
if (!ParseOptional<Dimensions>(root[kDimensions], &(out->dimensions)) ||
!ParseOptional<AspectRatio>(root[kAspectRatio], &(out->aspect_ratio))) {
return false;
}
AspectRatioConstraint constraint;
- if (AspectRatioConstraintParseAndValidate(root[kScaling], &constraint)) {
+ if (TryParseAspectRatioConstraint(root[kScaling], &constraint)) {
out->aspect_ratio_constraint =
absl::optional<AspectRatioConstraint>(std::move(constraint));
} else {
@@ -368,11 +359,14 @@ Json::Value DisplayDescription::ToJson() const {
return root;
}
-bool Answer::ParseAndValidate(const Json::Value& root, Answer* out) {
- if (!json::ParseAndValidateInt(root[kUdpPort], &(out->udp_port)) ||
- !json::ParseAndValidateIntArray(root[kSendIndexes],
- &(out->send_indexes)) ||
- !json::ParseAndValidateUintArray(root[kSsrcs], &(out->ssrcs)) ||
+bool Answer::ParseAndValidate(const Json::Value& value, Answer* out) {
+ return TryParse(value, out);
+}
+
+bool Answer::TryParse(const Json::Value& root, Answer* out) {
+ if (!json::TryParseInt(root[kUdpPort], &(out->udp_port)) ||
+ !json::TryParseIntArray(root[kSendIndexes], &(out->send_indexes)) ||
+ !json::TryParseUintArray(root[kSsrcs], &(out->ssrcs)) ||
!ParseOptional<Constraints>(root[kConstraints], &(out->constraints)) ||
!ParseOptional<DisplayDescription>(root[kDisplay], &(out->display))) {
return false;
@@ -380,12 +374,10 @@ bool Answer::ParseAndValidate(const Json::Value& root, Answer* out) {
// These function set to empty array if not present, so we can ignore
// the return value for optional values.
- json::ParseAndValidateIntArray(root[kReceiverRtcpEventLog],
- &(out->receiver_rtcp_event_log));
- json::ParseAndValidateIntArray(root[kReceiverRtcpDscp],
- &(out->receiver_rtcp_dscp));
- json::ParseAndValidateStringArray(root[kRtpExtensions],
- &(out->rtp_extensions));
+ json::TryParseIntArray(root[kReceiverRtcpEventLog],
+ &(out->receiver_rtcp_event_log));
+ json::TryParseIntArray(root[kReceiverRtcpDscp], &(out->receiver_rtcp_dscp));
+ json::TryParseStringArray(root[kRtpExtensions], &(out->rtp_extensions));
return out->IsValid();
}
diff --git a/cast/streaming/answer_messages.h b/cast/streaming/answer_messages.h
index 3a811073..7095e455 100644
--- a/cast/streaming/answer_messages.h
+++ b/cast/streaming/answer_messages.h
@@ -29,14 +29,14 @@ namespace cast {
// readability of the structs provided in this file by cutting down on the
// amount of obscuring boilerplate code. For each of the following struct
// definitions, the following method definitions are shared:
-// (1) ParseAndValidate. Shall return a boolean indicating whether the out
+// (1) TryParse. Shall return a boolean indicating whether the out
// parameter is in a valid state after checking bounds and restrictions.
// (2) ToJson. Should return a proper JSON object. Assumes that IsValid()
// has been called already, OSP_DCHECKs if not IsValid().
-// (3) IsValid. Used by both ParseAndValidate and ToJson to ensure that the
+// (3) IsValid. Used by both TryParse and ToJson to ensure that the
// object is in a good state.
struct AudioConstraints {
- static bool ParseAndValidate(const Json::Value& value, AudioConstraints* out);
+ static bool TryParse(const Json::Value& value, AudioConstraints* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -48,7 +48,7 @@ struct AudioConstraints {
};
struct VideoConstraints {
- static bool ParseAndValidate(const Json::Value& value, VideoConstraints* out);
+ static bool TryParse(const Json::Value& value, VideoConstraints* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -61,7 +61,7 @@ struct VideoConstraints {
};
struct Constraints {
- static bool ParseAndValidate(const Json::Value& value, Constraints* out);
+ static bool TryParse(const Json::Value& value, Constraints* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -75,7 +75,7 @@ struct Constraints {
enum class AspectRatioConstraint : uint8_t { kVariable = 0, kFixed };
struct AspectRatio {
- static bool ParseAndValidate(const Json::Value& value, AspectRatio* out);
+ static bool TryParse(const Json::Value& value, AspectRatio* out);
bool IsValid() const;
bool operator==(const AspectRatio& other) const {
@@ -87,8 +87,7 @@ struct AspectRatio {
};
struct DisplayDescription {
- static bool ParseAndValidate(const Json::Value& value,
- DisplayDescription* out);
+ static bool TryParse(const Json::Value& value, DisplayDescription* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -100,7 +99,10 @@ struct DisplayDescription {
};
struct Answer {
+ // TODO(jophba): DEPRECATED, remove separately.
static bool ParseAndValidate(const Json::Value& value, Answer* out);
+
+ static bool TryParse(const Json::Value& value, Answer* out);
Json::Value ToJson() const;
bool IsValid() const;
diff --git a/cast/streaming/answer_messages_unittest.cc b/cast/streaming/answer_messages_unittest.cc
index eb354ba4..3d618828 100644
--- a/cast/streaming/answer_messages_unittest.cc
+++ b/cast/streaming/answer_messages_unittest.cc
@@ -156,7 +156,7 @@ void ExpectFailureOnParse(absl::string_view raw_json) {
ASSERT_TRUE(root.is_value());
Answer answer;
- EXPECT_FALSE(Answer::ParseAndValidate(std::move(root.value()), &answer));
+ EXPECT_FALSE(Answer::TryParse(std::move(root.value()), &answer));
EXPECT_FALSE(answer.IsValid());
}
@@ -168,7 +168,7 @@ void ExpectSuccessOnParse(absl::string_view raw_json, Answer* out = nullptr) {
ASSERT_TRUE(root.is_value());
Answer answer;
- ASSERT_TRUE(Answer::ParseAndValidate(std::move(root.value()), &answer));
+ ASSERT_TRUE(Answer::TryParse(std::move(root.value()), &answer));
EXPECT_TRUE(answer.IsValid());
if (out) {
*out = std::move(answer);
@@ -495,7 +495,7 @@ TEST(AnswerMessagesTest, AspectRatioIsValid) {
EXPECT_FALSE(kInvalidHeight.IsValid());
}
-TEST(AnswerMessagesTest, AspectRatioParseAndValidate) {
+TEST(AnswerMessagesTest, AspectRatioTryParse) {
const Json::Value kValid = "16:9";
const Json::Value kWrongDelimiter = "16-9";
const Json::Value kTooManyFields = "16:9:3";
@@ -510,24 +510,24 @@ TEST(AnswerMessagesTest, AspectRatioParseAndValidate) {
const Json::Value kZeroHeight = "16:0";
AspectRatio out;
- EXPECT_TRUE(AspectRatio::ParseAndValidate(kValid, &out));
+ EXPECT_TRUE(AspectRatio::TryParse(kValid, &out));
EXPECT_EQ(out.width, 16);
EXPECT_EQ(out.height, 9);
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kWrongDelimiter, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kTooManyFields, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kTooFewFields, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kWrongDelimiter, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNoDelimiter, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNegativeWidth, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNegativeHeight, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNegativeBoth, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNonNumberWidth, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kNonNumberHeight, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kZeroWidth, &out));
- EXPECT_FALSE(AspectRatio::ParseAndValidate(kZeroHeight, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kWrongDelimiter, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kTooManyFields, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kTooFewFields, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kWrongDelimiter, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNoDelimiter, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNegativeWidth, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNegativeHeight, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNegativeBoth, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNonNumberWidth, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kNonNumberHeight, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kZeroWidth, &out));
+ EXPECT_FALSE(AspectRatio::TryParse(kZeroHeight, &out));
}
-TEST(AnswerMessagesTest, DisplayDescriptionParseAndValidate) {
+TEST(AnswerMessagesTest, DisplayDescriptionTryParse) {
Json::Value valid_scaling;
valid_scaling["scaling"] = "receiver";
Json::Value invalid_scaling;
@@ -553,25 +553,23 @@ TEST(AnswerMessagesTest, DisplayDescriptionParseAndValidate) {
aspect_ratio_and_constraint["aspectRatio"] = "4:3";
DisplayDescription out;
- ASSERT_TRUE(DisplayDescription::ParseAndValidate(valid_scaling, &out));
+ ASSERT_TRUE(DisplayDescription::TryParse(valid_scaling, &out));
ASSERT_TRUE(out.aspect_ratio_constraint.has_value());
EXPECT_EQ(out.aspect_ratio_constraint.value(),
AspectRatioConstraint::kVariable);
- EXPECT_FALSE(DisplayDescription::ParseAndValidate(invalid_scaling, &out));
- EXPECT_TRUE(
- DisplayDescription::ParseAndValidate(invalid_scaling_valid_ratio, &out));
+ EXPECT_FALSE(DisplayDescription::TryParse(invalid_scaling, &out));
+ EXPECT_TRUE(DisplayDescription::TryParse(invalid_scaling_valid_ratio, &out));
- ASSERT_TRUE(DisplayDescription::ParseAndValidate(valid_dimensions, &out));
+ ASSERT_TRUE(DisplayDescription::TryParse(valid_dimensions, &out));
ASSERT_TRUE(out.dimensions.has_value());
EXPECT_EQ(1920, out.dimensions->width);
EXPECT_EQ(1080, out.dimensions->height);
EXPECT_EQ((SimpleFraction{30, 1}), out.dimensions->frame_rate);
- EXPECT_FALSE(DisplayDescription::ParseAndValidate(invalid_dimensions, &out));
+ EXPECT_FALSE(DisplayDescription::TryParse(invalid_dimensions, &out));
- ASSERT_TRUE(
- DisplayDescription::ParseAndValidate(aspect_ratio_and_constraint, &out));
+ ASSERT_TRUE(DisplayDescription::TryParse(aspect_ratio_and_constraint, &out));
EXPECT_EQ(AspectRatioConstraint::kFixed, out.aspect_ratio_constraint.value());
}
diff --git a/cast/streaming/offer_messages.cc b/cast/streaming/offer_messages.cc
index f21decb1..f438d9be 100644
--- a/cast/streaming/offer_messages.cc
+++ b/cast/streaming/offer_messages.cc
@@ -33,36 +33,39 @@ constexpr char kAudioSourceType[] = "audio_source";
constexpr char kVideoSourceType[] = "video_source";
constexpr char kStreamType[] = "type";
-ErrorOr<RtpPayloadType> ParseRtpPayloadType(const Json::Value& parent,
- const std::string& field) {
- auto t = json::ParseInt(parent, field);
- if (!t) {
- return t.error();
+EnumNameTable<CastMode, 2> kCastModeNames{
+ {{"mirroring", CastMode::kMirroring}, {"remoting", CastMode::kRemoting}}};
+
+bool TryParseRtpPayloadType(const Json::Value& value, RtpPayloadType* out) {
+ int t;
+ if (!json::TryParseInt(value, &t)) {
+ return false;
}
- uint8_t t_small = t.value();
- if (t_small != t.value() || !IsRtpPayloadType(t_small)) {
- return Error(Error::Code::kParameterInvalid,
- "Received invalid RTP Payload Type.");
+ uint8_t t_small = t;
+ if (t_small != t || !IsRtpPayloadType(t_small)) {
+ return false;
}
- return static_cast<RtpPayloadType>(t_small);
+ *out = static_cast<RtpPayloadType>(t_small);
+ return true;
}
-ErrorOr<int> ParseRtpTimebase(const Json::Value& parent,
- const std::string& field) {
- auto error_or_raw = json::ParseString(parent, field);
- if (!error_or_raw) {
- return error_or_raw.error();
+bool TryParseRtpTimebase(const Json::Value& value, int* out) {
+ std::string raw_timebase;
+ if (!json::TryParseString(value, &raw_timebase)) {
+ return false;
}
// The spec demands a leading 1, so this isn't really a fraction.
- const auto fraction = SimpleFraction::FromString(error_or_raw.value());
+ const auto fraction = SimpleFraction::FromString(raw_timebase);
if (fraction.is_error() || !fraction.value().is_positive() ||
fraction.value().numerator() != 1) {
- return json::CreateParseError("RTP timebase");
+ return false;
}
- return fraction.value().denominator();
+
+ *out = fraction.value().denominator();
+ return true;
}
// For a hex byte, the conversion is 4 bits to 1 character, e.g.
@@ -70,203 +73,119 @@ ErrorOr<int> ParseRtpTimebase(const Json::Value& parent,
constexpr int kHexDigitsPerByte = 2;
constexpr int kAesBytesSize = 16;
constexpr int kAesStringLength = kAesBytesSize * kHexDigitsPerByte;
-ErrorOr<std::array<uint8_t, kAesBytesSize>> ParseAesHexBytes(
- const Json::Value& parent,
- const std::string& field) {
- auto hex_string = json::ParseString(parent, field);
- if (!hex_string) {
- return hex_string.error();
+bool TryParseAesHexBytes(const Json::Value& value,
+ std::array<uint8_t, kAesBytesSize>* out) {
+ std::string hex_string;
+ if (!json::TryParseString(value, &hex_string)) {
+ return false;
}
constexpr int kHexDigitsPerScanField = 16;
constexpr int kNumScanFields = kAesStringLength / kHexDigitsPerScanField;
uint64_t quads[kNumScanFields];
int chars_scanned;
- if (hex_string.value().size() == kAesStringLength &&
- sscanf(hex_string.value().c_str(), "%16" SCNx64 "%16" SCNx64 "%n",
- &quads[0], &quads[1], &chars_scanned) == kNumScanFields &&
+ if (hex_string.size() == kAesStringLength &&
+ sscanf(hex_string.c_str(), "%16" SCNx64 "%16" SCNx64 "%n", &quads[0],
+ &quads[1], &chars_scanned) == kNumScanFields &&
chars_scanned == kAesStringLength &&
- std::none_of(hex_string.value().begin(), hex_string.value().end(),
+ std::none_of(hex_string.begin(), hex_string.end(),
[](char c) { return std::isspace(c); })) {
- std::array<uint8_t, kAesBytesSize> bytes;
- WriteBigEndian(quads[0], bytes.data());
- WriteBigEndian(quads[1], bytes.data() + 8);
- return bytes;
+ WriteBigEndian(quads[0], out->data());
+ WriteBigEndian(quads[1], out->data() + 8);
+ return true;
}
- return json::CreateParseError("AES hex string bytes");
-}
-ErrorOr<Stream> ParseStream(const Json::Value& value, Stream::Type type) {
- auto index = json::ParseInt(value, "index");
- if (!index) {
- return index.error();
- }
- // If channel is omitted, the default value is used later.
- auto channels = json::ParseInt(value, "channels");
- if (channels.is_value() && channels.value() <= 0) {
- return json::CreateParameterError("channel");
- }
- auto rtp_profile = json::ParseString(value, "rtpProfile");
- if (!rtp_profile) {
- return rtp_profile.error();
- }
- auto rtp_payload_type = ParseRtpPayloadType(value, "rtpPayloadType");
- if (!rtp_payload_type) {
- return rtp_payload_type.error();
- }
- auto ssrc = json::ParseUint(value, "ssrc");
- if (!ssrc) {
- return ssrc.error();
- }
- auto aes_key = ParseAesHexBytes(value, "aesKey");
- auto aes_iv_mask = ParseAesHexBytes(value, "aesIvMask");
- if (!aes_key || !aes_iv_mask) {
- return Error(Error::Code::kUnencryptedOffer,
- "Offer stream must have both a valid aesKey and aesIvMask");
- }
- auto rtp_timebase = ParseRtpTimebase(value, "timeBase");
- if (!rtp_timebase) {
- return rtp_timebase.error();
- }
- if (rtp_timebase.value() <
- std::min(kDefaultAudioMinSampleRate, kRtpVideoTimebase) ||
- rtp_timebase.value() > kRtpVideoTimebase) {
- return json::CreateParameterError("rtp_timebase (sample rate)");
- }
+ return false;
+}
- auto target_delay = json::ParseInt(value, "targetDelay");
- std::chrono::milliseconds target_delay_ms = kDefaultTargetPlayoutDelay;
- if (target_delay) {
- auto d = std::chrono::milliseconds(target_delay.value());
- if (kMinTargetPlayoutDelay <= d && d <= kMaxTargetPlayoutDelay) {
- target_delay_ms = d;
+absl::string_view ToString(Stream::Type type) {
+ switch (type) {
+ case Stream::Type::kAudioSource:
+ return kAudioSourceType;
+ case Stream::Type::kVideoSource:
+ return kVideoSourceType;
+ default: {
+ OSP_NOTREACHED();
}
}
-
- auto receiver_rtcp_event_log = json::ParseBool(value, "receiverRtcpEventLog");
- auto receiver_rtcp_dscp = json::ParseString(value, "receiverRtcpDscp");
- return Stream{index.value(),
- type,
- channels.value(type == Stream::Type::kAudioSource
- ? kDefaultNumAudioChannels
- : kDefaultNumVideoChannels),
- rtp_payload_type.value(),
- ssrc.value(),
- target_delay_ms,
- aes_key.value(),
- aes_iv_mask.value(),
- receiver_rtcp_event_log.value({}),
- receiver_rtcp_dscp.value({}),
- rtp_timebase.value()};
}
-ErrorOr<AudioStream> ParseAudioStream(const Json::Value& value) {
- auto stream = ParseStream(value, Stream::Type::kAudioSource);
- if (!stream) {
- return stream.error();
- }
- auto bit_rate = json::ParseInt(value, "bitRate");
- if (!bit_rate) {
- return bit_rate.error();
- }
-
- auto codec_name = json::ParseString(value, kCodecName);
- if (!codec_name) {
- return codec_name.error();
- }
- ErrorOr<AudioCodec> codec = StringToAudioCodec(codec_name.value());
- if (!codec) {
- return Error(Error::Code::kUnknownCodec,
- "Codec is not known, can't use stream");
- }
-
- // A bit rate of 0 is valid for some codec types, so we don't enforce here.
- if (bit_rate.value() < 0) {
- return json::CreateParameterError("bit rate");
- }
- return AudioStream{stream.value(), codec.value(), bit_rate.value()};
-}
+bool TryParseResolutions(const Json::Value& value,
+ std::vector<Resolution>* out) {
+ out->clear();
-ErrorOr<std::vector<Resolution>> ParseResolutions(const Json::Value& parent,
- const std::string& field) {
- std::vector<Resolution> resolutions;
// Some legacy senders don't provide resolutions, so just return empty.
- const Json::Value& value = parent[field];
if (!value.isArray() || value.empty()) {
- return resolutions;
+ return false;
}
for (Json::ArrayIndex i = 0; i < value.size(); ++i) {
Resolution resolution;
- if (!Resolution::ParseAndValidate(value[i], &resolution)) {
- return Error(Error::Code::kJsonParseError);
+ if (!Resolution::TryParse(value[i], &resolution)) {
+ out->clear();
+ return false;
}
- resolutions.push_back(std::move(resolution));
+ out->push_back(std::move(resolution));
}
- return resolutions;
+ return true;
}
-ErrorOr<VideoStream> ParseVideoStream(const Json::Value& value) {
- auto stream = ParseStream(value, Stream::Type::kVideoSource);
- if (!stream) {
- return stream.error();
+} // namespace
+
+Error Stream::TryParse(const Json::Value& value,
+ Stream::Type type,
+ Stream* out) {
+ out->type = type;
+
+ if (!json::TryParseInt(value["index"], &out->index) ||
+ !json::TryParseUint(value["ssrc"], &out->ssrc) ||
+ !TryParseRtpPayloadType(value["rtpPayloadType"],
+ &out->rtp_payload_type) ||
+ !TryParseRtpTimebase(value["timeBase"], &out->rtp_timebase)) {
+ return Error(Error::Code::kJsonParseError,
+ "Offer stream has missing or invalid mandatory field");
}
- auto codec_name = json::ParseString(value, kCodecName);
- if (!codec_name) {
- return codec_name.error();
+
+ if (!json::TryParseInt(value["channels"], &out->channels)) {
+ out->channels = out->type == Stream::Type::kAudioSource
+ ? kDefaultNumAudioChannels
+ : kDefaultNumVideoChannels;
+ } else if (out->channels <= 0) {
+ return Error(Error::Code::kJsonParseError, "Invalid channel count");
}
- ErrorOr<VideoCodec> codec = StringToVideoCodec(codec_name.value());
- if (!codec) {
- return Error(Error::Code::kUnknownCodec,
- "Codec is not known, can't use stream");
+
+ if (!TryParseAesHexBytes(value["aesKey"], &out->aes_key) ||
+ !TryParseAesHexBytes(value["aesIvMask"], &out->aes_iv_mask)) {
+ return Error(Error::Code::kUnencryptedOffer,
+ "Offer stream must have both a valid aesKey and aesIvMask");
}
- auto resolutions = ParseResolutions(value, "resolutions");
- if (!resolutions) {
- return resolutions.error();
+ if (out->rtp_timebase <
+ std::min(kDefaultAudioMinSampleRate, kRtpVideoTimebase) ||
+ out->rtp_timebase > kRtpVideoTimebase) {
+ return Error(Error::Code::kJsonParseError, "rtp_timebase (sample rate)");
}
- auto raw_max_frame_rate = json::ParseString(value, "maxFrameRate");
- SimpleFraction max_frame_rate{kDefaultMaxFrameRate, 1};
- if (raw_max_frame_rate.is_value()) {
- auto parsed = SimpleFraction::FromString(raw_max_frame_rate.value());
- if (parsed.is_value() && parsed.value().is_positive()) {
- max_frame_rate = parsed.value();
+ out->target_delay = kDefaultTargetPlayoutDelay;
+ int target_delay;
+ if (json::TryParseInt(value["targetDelay"], &target_delay)) {
+ auto d = std::chrono::milliseconds(target_delay);
+ if (kMinTargetPlayoutDelay <= d && d <= kMaxTargetPlayoutDelay) {
+ out->target_delay = d;
}
}
- auto profile = json::ParseString(value, "profile");
- auto protection = json::ParseString(value, "protection");
- auto max_bit_rate = json::ParseInt(value, "maxBitRate");
- auto level = json::ParseString(value, "level");
- auto error_recovery_mode = json::ParseString(value, "errorRecoveryMode");
- return VideoStream{stream.value(),
- codec.value(),
- max_frame_rate,
- max_bit_rate.value(4 << 20),
- protection.value({}),
- profile.value({}),
- level.value({}),
- resolutions.value(),
- error_recovery_mode.value({})};
-}
-
-absl::string_view ToString(Stream::Type type) {
- switch (type) {
- case Stream::Type::kAudioSource:
- return kAudioSourceType;
- case Stream::Type::kVideoSource:
- return kVideoSourceType;
- default: {
- OSP_NOTREACHED();
- }
+ if (!json::TryParseBool(value["receiverRtcpEventLog"],
+ &out->receiver_rtcp_event_log)) {
+ out->receiver_rtcp_event_log = false;
+ }
+ if (!json::TryParseString(value["receiverRtcpDscp"],
+ &out->receiver_rtcp_dscp)) {
+ out->receiver_rtcp_dscp = {};
}
-}
-
-EnumNameTable<CastMode, 2> kCastModeNames{
- {{"mirroring", CastMode::kMirroring}, {"remoting", CastMode::kRemoting}}};
-} // namespace
+ return Error::None();
+}
Json::Value Stream::ToJson() const {
OSP_DCHECK(IsValid());
@@ -297,6 +216,28 @@ bool Stream::IsValid() const {
rtp_timebase >= 1;
}
+Error AudioStream::TryParse(const Json::Value& value, AudioStream* out) {
+ Error error =
+ Stream::TryParse(value, Stream::Type::kAudioSource, &out->stream);
+ if (!error.ok()) {
+ return error;
+ }
+
+ std::string codec_name;
+ if (!json::TryParseInt(value["bitRate"], &out->bit_rate) ||
+ out->bit_rate < 0 ||
+ !json::TryParseString(value[kCodecName], &codec_name)) {
+ return Error(Error::Code::kJsonParseError, "Invalid audio stream field");
+ }
+ ErrorOr<AudioCodec> codec = StringToAudioCodec(codec_name);
+ if (!codec) {
+ return Error(Error::Code::kUnknownCodec,
+ "Codec is not known, can't use stream");
+ }
+ out->codec = codec.value();
+ return Error::None();
+}
+
Json::Value AudioStream::ToJson() const {
OSP_DCHECK(IsValid());
@@ -310,6 +251,45 @@ bool AudioStream::IsValid() const {
return bit_rate >= 0 && stream.IsValid();
}
+Error VideoStream::TryParse(const Json::Value& value, VideoStream* out) {
+ Error error =
+ Stream::TryParse(value, Stream::Type::kVideoSource, &out->stream);
+ if (!error.ok()) {
+ return error;
+ }
+
+ std::string codec_name;
+ if (!json::TryParseString(value[kCodecName], &codec_name)) {
+ return Error(Error::Code::kJsonParseError, "Video stream missing codec");
+ }
+ ErrorOr<VideoCodec> codec = StringToVideoCodec(codec_name);
+ if (!codec) {
+ return Error(Error::Code::kUnknownCodec,
+ "Codec is not known, can't use stream");
+ }
+ out->codec = codec.value();
+
+ out->max_frame_rate = SimpleFraction{kDefaultMaxFrameRate, 1};
+ std::string raw_max_frame_rate;
+ if (json::TryParseString(value["maxFrameRate"], &raw_max_frame_rate)) {
+ auto parsed = SimpleFraction::FromString(raw_max_frame_rate);
+ if (parsed.is_value() && parsed.value().is_positive()) {
+ out->max_frame_rate = parsed.value();
+ }
+ }
+
+ TryParseResolutions(value["resolutions"], &out->resolutions);
+ json::TryParseString(value["profile"], &out->profile);
+ json::TryParseString(value["protection"], &out->protection);
+ json::TryParseString(value["level"], &out->level);
+ json::TryParseString(value["errorRecoveryMode"], &out->error_recovery_mode);
+ if (!json::TryParseInt(value["maxBitRate"], &out->max_bit_rate)) {
+ out->max_bit_rate = 4 << 20;
+ }
+
+ return Error::None();
+}
+
Json::Value VideoStream::ToJson() const {
OSP_DCHECK(IsValid());
@@ -335,55 +315,54 @@ bool VideoStream::IsValid() const {
}
// static
-ErrorOr<Offer> Offer::Parse(const Json::Value& root) {
+Error Offer::TryParse(const Json::Value& root, Offer* out) {
if (!root.isObject()) {
- return json::CreateParseError("null offer");
+ return Error(Error::Code::kJsonParseError, "null offer");
}
const ErrorOr<CastMode> cast_mode =
GetEnum(kCastModeNames, root["castMode"].asString());
Json::Value supported_streams = root[kSupportedStreams];
if (!supported_streams.isArray()) {
- return json::CreateParseError("supported streams in offer");
+ return Error(Error::Code::kJsonParseError, "supported streams in offer");
}
std::vector<AudioStream> audio_streams;
std::vector<VideoStream> video_streams;
for (Json::ArrayIndex i = 0; i < supported_streams.size(); ++i) {
const Json::Value& fields = supported_streams[i];
- auto type = json::ParseString(fields, kStreamType);
- if (!type) {
- return type.error();
+ std::string type;
+ if (!json::TryParseString(fields[kStreamType], &type)) {
+ return Error(Error::Code::kJsonParseError, "Missing stream type");
}
- if (type.value() == kAudioSourceType) {
- auto stream = ParseAudioStream(fields);
- if (!stream) {
- if (stream.error().code() == Error::Code::kUnknownCodec) {
- OSP_DVLOG << "Dropping audio stream due to unknown codec: "
- << stream.error();
- continue;
- } else {
- return stream.error();
- }
+ Error error;
+ if (type == kAudioSourceType) {
+ AudioStream stream;
+ error = AudioStream::TryParse(fields, &stream);
+ if (error.ok()) {
+ audio_streams.push_back(std::move(stream));
}
- audio_streams.push_back(std::move(stream.value()));
- } else if (type.value() == kVideoSourceType) {
- auto stream = ParseVideoStream(fields);
- if (!stream) {
- if (stream.error().code() == Error::Code::kUnknownCodec) {
- OSP_DVLOG << "Dropping video stream due to unknown codec: "
- << stream.error();
- continue;
- } else {
- return stream.error();
- }
+ } else if (type == kVideoSourceType) {
+ VideoStream stream;
+ error = VideoStream::TryParse(fields, &stream);
+ if (error.ok()) {
+ video_streams.push_back(std::move(stream));
+ }
+ }
+
+ if (!error.ok()) {
+ if (error.code() == Error::Code::kUnknownCodec) {
+ OSP_DVLOG << "Dropping audio stream due to unknown codec: " << error;
+ continue;
+ } else {
+ return error;
}
- video_streams.push_back(std::move(stream.value()));
}
}
- return Offer{cast_mode.value(CastMode::kMirroring), std::move(audio_streams),
+ *out = Offer{cast_mode.value(CastMode::kMirroring), std::move(audio_streams),
std::move(video_streams)};
+ return Error::None();
}
Json::Value Offer::ToJson() const {
diff --git a/cast/streaming/offer_messages.h b/cast/streaming/offer_messages.h
index efb3a1f6..80458954 100644
--- a/cast/streaming/offer_messages.h
+++ b/cast/streaming/offer_messages.h
@@ -46,6 +46,9 @@ constexpr int kDefaultNumAudioChannels = 2;
struct Stream {
enum class Type : uint8_t { kAudioSource, kVideoSource };
+ static Error TryParse(const Json::Value& root,
+ Stream::Type type,
+ Stream* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -68,6 +71,7 @@ struct Stream {
};
struct AudioStream {
+ static Error TryParse(const Json::Value& root, AudioStream* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -78,6 +82,7 @@ struct AudioStream {
struct VideoStream {
+ static Error TryParse(const Json::Value& root, VideoStream* out);
Json::Value ToJson() const;
bool IsValid() const;
@@ -95,7 +100,7 @@ struct VideoStream {
enum class CastMode : uint8_t { kMirroring, kRemoting };
struct Offer {
- static ErrorOr<Offer> Parse(const Json::Value& root);
+ static Error TryParse(const Json::Value& root, Offer* out);
Json::Value ToJson() const;
bool IsValid() const;
diff --git a/cast/streaming/offer_messages_unittest.cc b/cast/streaming/offer_messages_unittest.cc
index e1e70550..038d2f80 100644
--- a/cast/streaming/offer_messages_unittest.cc
+++ b/cast/streaming/offer_messages_unittest.cc
@@ -90,10 +90,12 @@ void ExpectFailureOnParse(
absl::optional<Error::Code> expected = absl::nullopt) {
ErrorOr<Json::Value> root = json::Parse(body);
ASSERT_TRUE(root.is_value()) << root.error();
- ErrorOr<Offer> error_or_offer = Offer::Parse(std::move(root.value()));
- EXPECT_TRUE(error_or_offer.is_error());
+
+ Offer offer;
+ Error error = Offer::TryParse(std::move(root.value()), &offer);
+ EXPECT_FALSE(error.ok());
if (expected) {
- EXPECT_EQ(expected, error_or_offer.error().code());
+ EXPECT_EQ(expected, error.code());
}
}
@@ -200,7 +202,9 @@ TEST(OfferTest, CanParseValidButStreamlessOffer) {
"supportedStreams": []
})");
ASSERT_TRUE(root.is_value()) << root.error();
- EXPECT_TRUE(Offer::Parse(std::move(root.value())).is_value());
+
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
}
TEST(OfferTest, ErrorOnMissingAudioStreamMandatoryField) {
@@ -249,7 +253,8 @@ TEST(OfferTest, CanParseValidButMinimalAudioOffer) {
}]
})");
ASSERT_TRUE(root.is_value());
- EXPECT_TRUE(Offer::Parse(std::move(root.value())).is_value());
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
}
TEST(OfferTest, CanParseValidZeroBitRateAudioOffer) {
@@ -270,8 +275,8 @@ TEST(OfferTest, CanParseValidZeroBitRateAudioOffer) {
}]
})");
ASSERT_TRUE(root.is_value()) << root.error();
- const auto offer = Offer::Parse(std::move(root.value()));
- EXPECT_TRUE(offer.is_value()) << offer.error();
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
}
TEST(OfferTest, ErrorOnInvalidRtpTimebase) {
@@ -439,26 +444,29 @@ TEST(OfferTest, CanParseValidButMinimalVideoOffer) {
})");
ASSERT_TRUE(root.is_value());
- EXPECT_TRUE(Offer::Parse(std::move(root.value())).is_value());
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
}
TEST(OfferTest, CanParseValidOffer) {
ErrorOr<Json::Value> root = json::Parse(kValidOffer);
ASSERT_TRUE(root.is_value());
- ErrorOr<Offer> offer = Offer::Parse(std::move(root.value()));
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
- ExpectEqualsValidOffer(offer.value());
+ ExpectEqualsValidOffer(offer);
}
TEST(OfferTest, ParseAndToJsonResultsInSameOffer) {
ErrorOr<Json::Value> root = json::Parse(kValidOffer);
ASSERT_TRUE(root.is_value());
- ErrorOr<Offer> offer = Offer::Parse(std::move(root.value()));
- ExpectEqualsValidOffer(offer.value());
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
+ ExpectEqualsValidOffer(offer);
- ErrorOr<Offer> reparsed_offer =
- Offer::Parse(std::move(offer.value().ToJson()));
- ExpectEqualsValidOffer(reparsed_offer.value());
+ Offer reparsed_offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &reparsed_offer).ok());
+ ExpectEqualsValidOffer(reparsed_offer);
}
// We don't want to enforce that a given offer must have both audio and
@@ -466,9 +474,10 @@ TEST(OfferTest, ParseAndToJsonResultsInSameOffer) {
TEST(OfferTest, IsValidWithMissingStreams) {
ErrorOr<Json::Value> root = json::Parse(kValidOffer);
ASSERT_TRUE(root.is_value());
- ErrorOr<Offer> offer = Offer::Parse(std::move(root.value()));
- ExpectEqualsValidOffer(offer.value());
- const Offer valid_offer = std::move(offer.value());
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
+ ExpectEqualsValidOffer(offer);
+ const Offer valid_offer = std::move(offer);
Offer missing_audio_streams = valid_offer;
missing_audio_streams.audio_streams.clear();
@@ -482,15 +491,15 @@ TEST(OfferTest, IsValidWithMissingStreams) {
TEST(OfferTest, InvalidIfInvalidStreams) {
ErrorOr<Json::Value> root = json::Parse(kValidOffer);
ASSERT_TRUE(root.is_value());
- ErrorOr<Offer> offer = Offer::Parse(std::move(root.value()));
- ExpectEqualsValidOffer(offer.value());
- const Offer valid_offer = std::move(offer.value());
+ Offer offer;
+ EXPECT_TRUE(Offer::TryParse(std::move(root.value()), &offer).ok());
+ ExpectEqualsValidOffer(offer);
- Offer video_stream_invalid = valid_offer;
+ Offer video_stream_invalid = offer;
video_stream_invalid.video_streams[0].max_frame_rate = SimpleFraction{1, 0};
EXPECT_FALSE(video_stream_invalid.IsValid());
- Offer audio_stream_invalid = valid_offer;
+ Offer audio_stream_invalid = offer;
video_stream_invalid.audio_streams[0].bit_rate = 0;
EXPECT_FALSE(video_stream_invalid.IsValid());
}
diff --git a/cast/streaming/receiver_message.cc b/cast/streaming/receiver_message.cc
index ec8f9619..e1af610c 100644
--- a/cast/streaming/receiver_message.cc
+++ b/cast/streaming/receiver_message.cc
@@ -41,7 +41,7 @@ EnumNameTable<MediaCapability, 9> kMediaCapabilityNames{{
ReceiverMessage::Type GetMessageType(const Json::Value& root) {
std::string type;
- if (!json::ParseAndValidateString(root[kMessageType], &type)) {
+ if (!json::TryParseString(root[kMessageType], &type)) {
return ReceiverMessage::Type::kUnknown;
}
@@ -51,10 +51,9 @@ ReceiverMessage::Type GetMessageType(const Json::Value& root) {
return parsed.value(ReceiverMessage::Type::kUnknown);
}
-bool ParseAndValidateCapability(const Json::Value& value,
- MediaCapability* out) {
+bool TryParseCapability(const Json::Value& value, MediaCapability* out) {
std::string c;
- if (!json::ParseAndValidateString(value, &c)) {
+ if (!json::TryParseString(value, &c)) {
return false;
}
@@ -78,8 +77,8 @@ ErrorOr<ReceiverError> ReceiverError::Parse(const Json::Value& value) {
int code;
std::string description;
- if (!json::ParseAndValidateInt(value[kErrorCode], &code) ||
- !json::ParseAndValidateString(value[kErrorDescription], &description)) {
+ if (!json::TryParseInt(value[kErrorCode], &code) ||
+ !json::TryParseString(value[kErrorDescription], &description)) {
return Error::Code::kJsonParseError;
}
return ReceiverError{code, description};
@@ -101,13 +100,13 @@ ErrorOr<ReceiverCapability> ReceiverCapability::Parse(
}
int remoting_version;
- if (!json::ParseAndValidateInt(value["remoting"], &remoting_version)) {
+ if (!json::TryParseInt(value["remoting"], &remoting_version)) {
remoting_version = ReceiverCapability::kRemotingVersionUnknown;
}
std::vector<MediaCapability> capabilities;
- if (!json::ParseAndValidateArray<MediaCapability>(
- value["mediaCaps"], ParseAndValidateCapability, &capabilities)) {
+ if (!json::TryParseArray<MediaCapability>(
+ value["mediaCaps"], TryParseCapability, &capabilities)) {
return Error(Error::Code::kJsonParseError,
"Failed to parse media capabilities");
}
@@ -129,14 +128,14 @@ Json::Value ReceiverCapability::ToJson() const {
// static
ErrorOr<ReceiverMessage> ReceiverMessage::Parse(const Json::Value& value) {
ReceiverMessage message;
- if (!value || !json::ParseAndValidateInt(value[kSequenceNumber],
- &(message.sequence_number))) {
+ if (!value ||
+ !json::TryParseInt(value[kSequenceNumber], &(message.sequence_number))) {
return Error(Error::Code::kJsonParseError,
"Failed to parse sequence number");
}
std::string result;
- if (!json::ParseAndValidateString(value[kResult], &result)) {
+ if (!json::TryParseString(value[kResult], &result)) {
result = kResultError;
}
@@ -155,8 +154,8 @@ ErrorOr<ReceiverMessage> ReceiverMessage::Parse(const Json::Value& value) {
switch (message.type) {
case Type::kAnswer: {
Answer answer;
- if (openscreen::cast::Answer::ParseAndValidate(value[kAnswerMessageBody],
- &answer)) {
+ if (openscreen::cast::Answer::TryParse(value[kAnswerMessageBody],
+ &answer)) {
message.body = std::move(answer);
message.valid = true;
}
@@ -174,7 +173,7 @@ ErrorOr<ReceiverMessage> ReceiverMessage::Parse(const Json::Value& value) {
case Type::kRpc: {
std::string encoded_rpc;
std::vector<uint8_t> rpc;
- if (json::ParseAndValidateString(value[kRpcMessageBody], &encoded_rpc) &&
+ if (json::TryParseString(value[kRpcMessageBody], &encoded_rpc) &&
base64::Decode(encoded_rpc, &rpc)) {
message.body = std::move(rpc);
message.valid = true;
diff --git a/cast/streaming/resolution.cc b/cast/streaming/resolution.cc
index de6b9358..0bcf5067 100644
--- a/cast/streaming/resolution.cc
+++ b/cast/streaming/resolution.cc
@@ -41,9 +41,9 @@ bool FrameRateEquals(double a, double b) {
} // namespace
-bool Resolution::ParseAndValidate(const Json::Value& root, Resolution* out) {
- if (!json::ParseAndValidateInt(root[kWidth], &(out->width)) ||
- !json::ParseAndValidateInt(root[kHeight], &(out->height))) {
+bool Resolution::TryParse(const Json::Value& root, Resolution* out) {
+ if (!json::TryParseInt(root[kWidth], &(out->width)) ||
+ !json::TryParseInt(root[kHeight], &(out->height))) {
return false;
}
return out->IsValid();
@@ -70,12 +70,11 @@ bool Resolution::operator!=(const Resolution& other) const {
return !(*this == other);
}
-bool Dimensions::ParseAndValidate(const Json::Value& root, Dimensions* out) {
- if (!json::ParseAndValidateInt(root[kWidth], &(out->width)) ||
- !json::ParseAndValidateInt(root[kHeight], &(out->height)) ||
+bool Dimensions::TryParse(const Json::Value& root, Dimensions* out) {
+ if (!json::TryParseInt(root[kWidth], &(out->width)) ||
+ !json::TryParseInt(root[kHeight], &(out->height)) ||
!(root[kFrameRate].isNull() ||
- json::ParseAndValidateSimpleFraction(root[kFrameRate],
- &(out->frame_rate)))) {
+ json::TryParseSimpleFraction(root[kFrameRate], &(out->frame_rate)))) {
return false;
}
return out->IsValid();
diff --git a/cast/streaming/resolution.h b/cast/streaming/resolution.h
index d27c7d28..ba370820 100644
--- a/cast/streaming/resolution.h
+++ b/cast/streaming/resolution.h
@@ -19,7 +19,7 @@ namespace cast {
// A resolution in pixels.
struct Resolution {
- static bool ParseAndValidate(const Json::Value& value, Resolution* out);
+ static bool TryParse(const Json::Value& value, Resolution* out);
bool IsValid() const;
Json::Value ToJson() const;
@@ -33,7 +33,7 @@ struct Resolution {
// A resolution in pixels and a frame rate.
struct Dimensions {
- static bool ParseAndValidate(const Json::Value& value, Dimensions* out);
+ static bool TryParse(const Json::Value& value, Dimensions* out);
bool IsValid() const;
Json::Value ToJson() const;
diff --git a/cast/streaming/sender_message.cc b/cast/streaming/sender_message.cc
index d776c67e..2526f96a 100644
--- a/cast/streaming/sender_message.cc
+++ b/cast/streaming/sender_message.cc
@@ -25,7 +25,7 @@ EnumNameTable<SenderMessage::Type, 4> kMessageTypeNames{
SenderMessage::Type GetMessageType(const Json::Value& root) {
std::string type;
- if (!json::ParseAndValidateString(root[kMessageType], &type)) {
+ if (!json::TryParseString(root[kMessageType], &type)) {
return SenderMessage::Type::kUnknown;
}
@@ -44,17 +44,16 @@ ErrorOr<SenderMessage> SenderMessage::Parse(const Json::Value& value) {
}
SenderMessage message;
- if (!json::ParseAndValidateInt(value[kSequenceNumber],
- &(message.sequence_number))) {
+ if (!json::TryParseInt(value[kSequenceNumber], &(message.sequence_number))) {
message.sequence_number = -1;
}
message.type = GetMessageType(value);
switch (message.type) {
case Type::kOffer: {
- ErrorOr<Offer> offer = Offer::Parse(value[kOfferMessageBody]);
- if (offer.is_value()) {
- message.body = std::move(offer.value());
+ Offer offer;
+ if (Offer::TryParse(value[kOfferMessageBody], &offer).ok()) {
+ message.body = std::move(offer);
message.valid = true;
}
} break;
@@ -62,7 +61,7 @@ ErrorOr<SenderMessage> SenderMessage::Parse(const Json::Value& value) {
case Type::kRpc: {
std::string rpc_body;
std::vector<uint8_t> rpc;
- if (json::ParseAndValidateString(value[kRpcMessageBody], &rpc_body) &&
+ if (json::TryParseString(value[kRpcMessageBody], &rpc_body) &&
base64::Decode(rpc_body, &rpc)) {
message.body = rpc;
message.valid = true;
diff --git a/cast/streaming/session_messager.cc b/cast/streaming/session_messager.cc
index 184da30c..e66e984f 100644
--- a/cast/streaming/session_messager.cc
+++ b/cast/streaming/session_messager.cc
@@ -147,8 +147,8 @@ void SenderSessionMessager::OnMessage(const std::string& source_id,
}
int sequence_number;
- if (!json::ParseAndValidateInt(message_body.value()[kSequenceNumber],
- &sequence_number)) {
+ if (!json::TryParseInt(message_body.value()[kSequenceNumber],
+ &sequence_number)) {
OSP_DLOG_WARN << "Received a message without a sequence number";
return;
}
diff --git a/util/json/json_helpers.h b/util/json/json_helpers.h
index 499d6352..ebd25add 100644
--- a/util/json/json_helpers.h
+++ b/util/json/json_helpers.h
@@ -24,53 +24,7 @@
namespace openscreen {
namespace json {
-// TODO(jophba): remove these methods after refactoring offer messaging.
-inline Error CreateParseError(const std::string& type) {
- return Error(Error::Code::kJsonParseError, "Failed to parse " + type);
-}
-
-inline Error CreateParameterError(const std::string& type) {
- return Error(Error::Code::kParameterInvalid, "Invalid parameter: " + type);
-}
-
-inline ErrorOr<bool> ParseBool(const Json::Value& parent,
- const std::string& field) {
- const Json::Value& value = parent[field];
- if (!value.isBool()) {
- return CreateParseError("bool field " + field);
- }
- return value.asBool();
-}
-
-inline ErrorOr<int> ParseInt(const Json::Value& parent,
- const std::string& field) {
- const Json::Value& value = parent[field];
- if (!value.isInt()) {
- return CreateParseError("integer field: " + field);
- }
- return value.asInt();
-}
-
-inline ErrorOr<uint32_t> ParseUint(const Json::Value& parent,
- const std::string& field) {
- const Json::Value& value = parent[field];
- if (!value.isUInt()) {
- return CreateParseError("unsigned integer field: " + field);
- }
- return value.asUInt();
-}
-
-inline ErrorOr<std::string> ParseString(const Json::Value& parent,
- const std::string& field) {
- const Json::Value& value = parent[field];
- if (!value.isString()) {
- return CreateParseError("string field: " + field);
- }
- return value.asString();
-}
-
-// TODO(jophba): offer messaging should use these methods instead.
-inline bool ParseBool(const Json::Value& value, bool* out) {
+inline bool TryParseBool(const Json::Value& value, bool* out) {
if (!value.isBool()) {
return false;
}
@@ -81,9 +35,9 @@ inline bool ParseBool(const Json::Value& value, bool* out) {
// A general note about parsing primitives. "Validation" in this context
// generally means ensuring that the values are non-negative, excepting doubles
// which may be negative in some cases.
-inline bool ParseAndValidateDouble(const Json::Value& value,
- double* out,
- bool allow_negative = false) {
+inline bool TryParseDouble(const Json::Value& value,
+ double* out,
+ bool allow_negative = false) {
if (!value.isDouble()) {
return false;
}
@@ -98,7 +52,7 @@ inline bool ParseAndValidateDouble(const Json::Value& value,
return true;
}
-inline bool ParseAndValidateInt(const Json::Value& value, int* out) {
+inline bool TryParseInt(const Json::Value& value, int* out) {
if (!value.isInt()) {
return false;
}
@@ -110,7 +64,7 @@ inline bool ParseAndValidateInt(const Json::Value& value, int* out) {
return true;
}
-inline bool ParseAndValidateUint(const Json::Value& value, uint32_t* out) {
+inline bool TryParseUint(const Json::Value& value, uint32_t* out) {
if (!value.isUInt()) {
return false;
}
@@ -118,7 +72,7 @@ inline bool ParseAndValidateUint(const Json::Value& value, uint32_t* out) {
return true;
}
-inline bool ParseAndValidateString(const Json::Value& value, std::string* out) {
+inline bool TryParseString(const Json::Value& value, std::string* out) {
if (!value.isString()) {
return false;
}
@@ -129,8 +83,8 @@ inline bool ParseAndValidateString(const Json::Value& value, std::string* out) {
// We want to be more robust when we parse fractions then just
// allowing strings, this will parse numeral values such as
// value: 50 as well as value: "50" and value: "100/2".
-inline bool ParseAndValidateSimpleFraction(const Json::Value& value,
- SimpleFraction* out) {
+inline bool TryParseSimpleFraction(const Json::Value& value,
+ SimpleFraction* out) {
if (value.isInt()) {
int parsed = value.asInt();
if (parsed < 0) {
@@ -156,10 +110,9 @@ inline bool ParseAndValidateSimpleFraction(const Json::Value& value,
return false;
}
-inline bool ParseAndValidateMilliseconds(const Json::Value& value,
- milliseconds* out) {
+inline bool TryParseMilliseconds(const Json::Value& value, milliseconds* out) {
int out_ms;
- if (!ParseAndValidateInt(value, &out_ms) || out_ms < 0) {
+ if (!TryParseInt(value, &out_ms) || out_ms < 0) {
return false;
}
*out = milliseconds(out_ms);
@@ -172,9 +125,9 @@ using Parser = std::function<bool(const Json::Value&, T*)>;
// NOTE: array parsing methods reset the output vector to an empty vector in
// any error case. This is especially useful for optional arrays.
template <typename T>
-bool ParseAndValidateArray(const Json::Value& value,
- Parser<T> parser,
- std::vector<T>* out) {
+bool TryParseArray(const Json::Value& value,
+ Parser<T> parser,
+ std::vector<T>* out) {
out->clear();
if (!value.isArray() || value.empty()) {
return false;
@@ -193,19 +146,18 @@ bool ParseAndValidateArray(const Json::Value& value,
return true;
}
-inline bool ParseAndValidateIntArray(const Json::Value& value,
- std::vector<int>* out) {
- return ParseAndValidateArray<int>(value, ParseAndValidateInt, out);
+inline bool TryParseIntArray(const Json::Value& value, std::vector<int>* out) {
+ return TryParseArray<int>(value, TryParseInt, out);
}
-inline bool ParseAndValidateUintArray(const Json::Value& value,
- std::vector<uint32_t>* out) {
- return ParseAndValidateArray<uint32_t>(value, ParseAndValidateUint, out);
+inline bool TryParseUintArray(const Json::Value& value,
+ std::vector<uint32_t>* out) {
+ return TryParseArray<uint32_t>(value, TryParseUint, out);
}
-inline bool ParseAndValidateStringArray(const Json::Value& value,
- std::vector<std::string>* out) {
- return ParseAndValidateArray<std::string>(value, ParseAndValidateString, out);
+inline bool TryParseStringArray(const Json::Value& value,
+ std::vector<std::string>* out) {
+ return TryParseArray<std::string>(value, TryParseString, out);
}
} // namespace json
diff --git a/util/json/json_helpers_unittest.cc b/util/json/json_helpers_unittest.cc
index c461cf93..eb05d3f6 100644
--- a/util/json/json_helpers_unittest.cc
+++ b/util/json/json_helpers_unittest.cc
@@ -26,9 +26,9 @@ struct Dummy {
}
};
-bool ParseAndValidateDummy(const Json::Value& value, Dummy* out) {
+bool TryParseDummy(const Json::Value& value, Dummy* out) {
int value_out;
- if (!ParseAndValidateInt(value, &value_out)) {
+ if (!TryParseInt(value, &value_out)) {
return false;
}
*out = Dummy{value_out};
@@ -37,7 +37,7 @@ bool ParseAndValidateDummy(const Json::Value& value, Dummy* out) {
} // namespace
-TEST(ParsingHelpersTest, ParseAndValidateDouble) {
+TEST(ParsingHelpersTest, TryParseDouble) {
const Json::Value kValid = 13.37;
const Json::Value kNotDouble = "coffee beans";
const Json::Value kNegativeDouble = -4.2;
@@ -45,62 +45,62 @@ TEST(ParsingHelpersTest, ParseAndValidateDouble) {
const Json::Value kNanDouble = std::nan("");
double out;
- EXPECT_TRUE(ParseAndValidateDouble(kValid, &out));
+ EXPECT_TRUE(TryParseDouble(kValid, &out));
EXPECT_DOUBLE_EQ(13.37, out);
- EXPECT_TRUE(ParseAndValidateDouble(kZeroDouble, &out));
+ EXPECT_TRUE(TryParseDouble(kZeroDouble, &out));
EXPECT_DOUBLE_EQ(0.0, out);
- EXPECT_FALSE(ParseAndValidateDouble(kNotDouble, &out));
- EXPECT_FALSE(ParseAndValidateDouble(kNegativeDouble, &out));
- EXPECT_FALSE(ParseAndValidateDouble(kNone, &out));
- EXPECT_FALSE(ParseAndValidateDouble(kNanDouble, &out));
+ EXPECT_FALSE(TryParseDouble(kNotDouble, &out));
+ EXPECT_FALSE(TryParseDouble(kNegativeDouble, &out));
+ EXPECT_FALSE(TryParseDouble(kNone, &out));
+ EXPECT_FALSE(TryParseDouble(kNanDouble, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateInt) {
+TEST(ParsingHelpersTest, TryParseInt) {
const Json::Value kValid = 1337;
const Json::Value kNotInt = "cold brew";
const Json::Value kNegativeInt = -42;
const Json::Value kZeroInt = 0;
int out;
- EXPECT_TRUE(ParseAndValidateInt(kValid, &out));
+ EXPECT_TRUE(TryParseInt(kValid, &out));
EXPECT_EQ(1337, out);
- EXPECT_TRUE(ParseAndValidateInt(kZeroInt, &out));
+ EXPECT_TRUE(TryParseInt(kZeroInt, &out));
EXPECT_EQ(0, out);
- EXPECT_FALSE(ParseAndValidateInt(kNone, &out));
- EXPECT_FALSE(ParseAndValidateInt(kNotInt, &out));
- EXPECT_FALSE(ParseAndValidateInt(kNegativeInt, &out));
+ EXPECT_FALSE(TryParseInt(kNone, &out));
+ EXPECT_FALSE(TryParseInt(kNotInt, &out));
+ EXPECT_FALSE(TryParseInt(kNegativeInt, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateUint) {
+TEST(ParsingHelpersTest, TryParseUint) {
const Json::Value kValid = 1337u;
const Json::Value kNotUint = "espresso";
const Json::Value kZeroUint = 0u;
uint32_t out;
- EXPECT_TRUE(ParseAndValidateUint(kValid, &out));
+ EXPECT_TRUE(TryParseUint(kValid, &out));
EXPECT_EQ(1337u, out);
- EXPECT_TRUE(ParseAndValidateUint(kZeroUint, &out));
+ EXPECT_TRUE(TryParseUint(kZeroUint, &out));
EXPECT_EQ(0u, out);
- EXPECT_FALSE(ParseAndValidateUint(kNone, &out));
- EXPECT_FALSE(ParseAndValidateUint(kNotUint, &out));
+ EXPECT_FALSE(TryParseUint(kNone, &out));
+ EXPECT_FALSE(TryParseUint(kNotUint, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateString) {
+TEST(ParsingHelpersTest, TryParseString) {
const Json::Value kValid = "macchiato";
const Json::Value kNotString = 42;
std::string out;
- EXPECT_TRUE(ParseAndValidateString(kValid, &out));
+ EXPECT_TRUE(TryParseString(kValid, &out));
EXPECT_EQ("macchiato", out);
- EXPECT_TRUE(ParseAndValidateString(kEmptyString, &out));
+ EXPECT_TRUE(TryParseString(kEmptyString, &out));
EXPECT_EQ("", out);
- EXPECT_FALSE(ParseAndValidateString(kNone, &out));
- EXPECT_FALSE(ParseAndValidateString(kNotString, &out));
+ EXPECT_FALSE(TryParseString(kNone, &out));
+ EXPECT_FALSE(TryParseString(kNotString, &out));
}
// Simple fraction validity is tested extensively in its unit tests, so we
// just check the major cases here.
-TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) {
+TEST(ParsingHelpersTest, TryParseSimpleFraction) {
const Json::Value kValid = "42/30";
const Json::Value kValidNumber = "42";
const Json::Value kUndefined = "5/0";
@@ -111,22 +111,22 @@ TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) {
const Json::Value kNegativeInteger = -5000;
SimpleFraction out;
- EXPECT_TRUE(ParseAndValidateSimpleFraction(kValid, &out));
+ EXPECT_TRUE(TryParseSimpleFraction(kValid, &out));
EXPECT_EQ((SimpleFraction{42, 30}), out);
- EXPECT_TRUE(ParseAndValidateSimpleFraction(kValidNumber, &out));
+ EXPECT_TRUE(TryParseSimpleFraction(kValidNumber, &out));
EXPECT_EQ((SimpleFraction{42, 1}), out);
- EXPECT_TRUE(ParseAndValidateSimpleFraction(kInteger, &out));
+ EXPECT_TRUE(TryParseSimpleFraction(kInteger, &out));
EXPECT_EQ((SimpleFraction{123, 1}), out);
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kUndefined, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegative, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kInvalidNumber, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kNotSimpleFraction, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kNone, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kEmptyString, &out));
- EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegativeInteger, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kUndefined, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kNegative, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kInvalidNumber, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kNotSimpleFraction, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kNone, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kEmptyString, &out));
+ EXPECT_FALSE(TryParseSimpleFraction(kNegativeInteger, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) {
+TEST(ParsingHelpersTest, TryParseMilliseconds) {
const Json::Value kValid = 1000;
const Json::Value kValidFloat = 500.0;
const Json::Value kNegativeNumber = -120;
@@ -134,18 +134,18 @@ TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) {
const Json::Value kNotNumber = "affogato";
milliseconds out;
- EXPECT_TRUE(ParseAndValidateMilliseconds(kValid, &out));
+ EXPECT_TRUE(TryParseMilliseconds(kValid, &out));
EXPECT_EQ(milliseconds(1000), out);
- EXPECT_TRUE(ParseAndValidateMilliseconds(kValidFloat, &out));
+ EXPECT_TRUE(TryParseMilliseconds(kValidFloat, &out));
EXPECT_EQ(milliseconds(500), out);
- EXPECT_TRUE(ParseAndValidateMilliseconds(kZeroNumber, &out));
+ EXPECT_TRUE(TryParseMilliseconds(kZeroNumber, &out));
EXPECT_EQ(milliseconds(0), out);
- EXPECT_FALSE(ParseAndValidateMilliseconds(kNone, &out));
- EXPECT_FALSE(ParseAndValidateMilliseconds(kNegativeNumber, &out));
- EXPECT_FALSE(ParseAndValidateMilliseconds(kNotNumber, &out));
+ EXPECT_FALSE(TryParseMilliseconds(kNone, &out));
+ EXPECT_FALSE(TryParseMilliseconds(kNegativeNumber, &out));
+ EXPECT_FALSE(TryParseMilliseconds(kNotNumber, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateArray) {
+TEST(ParsingHelpersTest, TryParseArray) {
Json::Value valid_dummy_array;
valid_dummy_array[0] = 123;
valid_dummy_array[1] = 456;
@@ -155,16 +155,13 @@ TEST(ParsingHelpersTest, ParseAndValidateArray) {
invalid_dummy_array[1] = 456;
std::vector<Dummy> out;
- EXPECT_TRUE(ParseAndValidateArray<Dummy>(valid_dummy_array,
- ParseAndValidateDummy, &out));
+ EXPECT_TRUE(TryParseArray<Dummy>(valid_dummy_array, TryParseDummy, &out));
EXPECT_THAT(out, ElementsAre(Dummy{123}, Dummy{456}));
- EXPECT_FALSE(ParseAndValidateArray<Dummy>(invalid_dummy_array,
- ParseAndValidateDummy, &out));
- EXPECT_FALSE(
- ParseAndValidateArray<Dummy>(kEmptyArray, ParseAndValidateDummy, &out));
+ EXPECT_FALSE(TryParseArray<Dummy>(invalid_dummy_array, TryParseDummy, &out));
+ EXPECT_FALSE(TryParseArray<Dummy>(kEmptyArray, TryParseDummy, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateIntArray) {
+TEST(ParsingHelpersTest, TryParseIntArray) {
Json::Value valid_int_array;
valid_int_array[0] = 123;
valid_int_array[1] = 456;
@@ -174,13 +171,13 @@ TEST(ParsingHelpersTest, ParseAndValidateIntArray) {
invalid_int_array[1] = 456;
std::vector<int> out;
- EXPECT_TRUE(ParseAndValidateIntArray(valid_int_array, &out));
+ EXPECT_TRUE(TryParseIntArray(valid_int_array, &out));
EXPECT_THAT(out, ElementsAre(123, 456));
- EXPECT_FALSE(ParseAndValidateIntArray(invalid_int_array, &out));
- EXPECT_FALSE(ParseAndValidateIntArray(kEmptyArray, &out));
+ EXPECT_FALSE(TryParseIntArray(invalid_int_array, &out));
+ EXPECT_FALSE(TryParseIntArray(kEmptyArray, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateUintArray) {
+TEST(ParsingHelpersTest, TryParseUintArray) {
Json::Value valid_uint_array;
valid_uint_array[0] = 123u;
valid_uint_array[1] = 456u;
@@ -190,13 +187,13 @@ TEST(ParsingHelpersTest, ParseAndValidateUintArray) {
invalid_uint_array[1] = 456u;
std::vector<uint32_t> out;
- EXPECT_TRUE(ParseAndValidateUintArray(valid_uint_array, &out));
+ EXPECT_TRUE(TryParseUintArray(valid_uint_array, &out));
EXPECT_THAT(out, ElementsAre(123u, 456u));
- EXPECT_FALSE(ParseAndValidateUintArray(invalid_uint_array, &out));
- EXPECT_FALSE(ParseAndValidateUintArray(kEmptyArray, &out));
+ EXPECT_FALSE(TryParseUintArray(invalid_uint_array, &out));
+ EXPECT_FALSE(TryParseUintArray(kEmptyArray, &out));
}
-TEST(ParsingHelpersTest, ParseAndValidateStringArray) {
+TEST(ParsingHelpersTest, TryParseStringArray) {
Json::Value valid_string_array;
valid_string_array[0] = "nitro cold brew";
valid_string_array[1] = "doppio espresso";
@@ -206,10 +203,10 @@ TEST(ParsingHelpersTest, ParseAndValidateStringArray) {
invalid_string_array[1] = 456;
std::vector<std::string> out;
- EXPECT_TRUE(ParseAndValidateStringArray(valid_string_array, &out));
+ EXPECT_TRUE(TryParseStringArray(valid_string_array, &out));
EXPECT_THAT(out, ElementsAre("nitro cold brew", "doppio espresso"));
- EXPECT_FALSE(ParseAndValidateStringArray(invalid_string_array, &out));
- EXPECT_FALSE(ParseAndValidateStringArray(kEmptyArray, &out));
+ EXPECT_FALSE(TryParseStringArray(invalid_string_array, &out));
+ EXPECT_FALSE(TryParseStringArray(kEmptyArray, &out));
}
} // namespace json