aboutsummaryrefslogtreecommitdiff
path: root/cast
diff options
context:
space:
mode:
authorYuri Wiitala <miu@chromium.org>2020-11-24 04:33:44 -0800
committerCommit Bot <commit-bot@chromium.org>2020-11-24 13:03:38 +0000
commit784170929fae06482dd9603d62697d57d5bde382 (patch)
tree2c26cee2698d434ad2c4d5cde7bc88cd5e79c94e /cast
parentb5ac6d34a14cc938258a938ebe3604a93776f7fa (diff)
downloadopenscreen-784170929fae06482dd9603d62697d57d5bde382.tar.gz
Bring openscreen::cast::ServiceInfo parsing/validation up-to-spec.
1. More-thorough validation-before-serialization (ServiceInfo::IsValid()), ensuring required fields are set, within valid ranges, and will fit within the TXT record field maximum size. 2. Make "model name" an optional field (was being treated as required). 3. Range-checks of untrusted input in DnsSdInstanceEndpointToServiceInfo(). 4. Rename kXYZId[] char constants to kXYZKey[], since they are key names in the record, not identifiers. 5. Removed DnsSdTxtRecord::SetValue() overload for uint8_t values, since it was being erroneously used to set values that were supposed to be decimal-formatted number strings (i.e., not a raw byte value!). 6. Add a regression test, to ensure a real-world TXT record from a Chromecast Ultra is successfully converted into a ServiceInfo. Bug: b/162542369 Change-Id: I06633c6c54dd2f6e6367033381b100949b08be8b Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/2552423 Commit-Queue: Yuri Wiitala <miu@chromium.org> Reviewed-by: Ryan Keane <rwkeane@google.com>
Diffstat (limited to 'cast')
-rw-r--r--cast/common/public/service_info.cc237
-rw-r--r--cast/common/public/service_info.h41
-rw-r--r--cast/common/public/service_info_unittest.cc67
-rw-r--r--cast/common/public/testing/discovery_utils.cc28
-rw-r--r--cast/common/public/testing/discovery_utils.h35
5 files changed, 211 insertions, 197 deletions
diff --git a/cast/common/public/service_info.cc b/cast/common/public/service_info.cc
index b6d6f623..732688f8 100644
--- a/cast/common/public/service_info.cc
+++ b/cast/common/public/service_info.cc
@@ -5,7 +5,7 @@
#include "cast/common/public/service_info.h"
#include <cctype>
-#include <memory>
+#include <cinttypes>
#include <string>
#include <vector>
@@ -17,9 +17,6 @@ namespace openscreen {
namespace cast {
namespace {
-// The mask for the set of supported capabilities in v2 of the Cast protocol.
-const uint16_t kCapabilitiesMask = 0x1F;
-
// Maximum size for registered MDNS service instance names.
const size_t kMaxDeviceNameSize = 63;
@@ -59,75 +56,17 @@ std::string CalculateInstanceId(const ServiceInfo& info) {
return std::string(instance_name, 0, kMaxDeviceNameSize);
}
-// NOTE: Eureka uses base::StringToUint64 which takes in a string and reads it
-// left to right, converts it to a number sequence, and uses the sequence to
-// calculate the resulting integer. This process assumes that the input is in
-// base 10. For example, ['1', '2', '3'] converts to 123.
-//
-// The below 2 functions re-create this logic for converting to and from this
-// encoding scheme.
-inline std::string EncodeIntegerString(uint64_t value) {
- return std::to_string(value);
-}
-
-ErrorOr<uint64_t> DecodeIntegerString(const std::string& value) {
- uint64_t result;
- if (!absl::SimpleAtoi(value, &result)) {
- return Error::Code::kParameterInvalid;
- }
-
- return result;
-}
-
-// Attempts to parse the string present at the provided |key| in the TXT record
-// |txt|, placing the result into |result| on success and error into |error| on
-// failure.
-bool TryParseString(const discovery::DnsSdTxtRecord& txt,
- const std::string& key,
- Error* error,
- std::string* result) {
- const ErrorOr<discovery::DnsSdTxtRecord::ValueRef> value = txt.GetValue(key);
- if (value.is_error()) {
- *error = value.error();
- return false;
- }
-
- const std::vector<uint8_t>& txt_value = value.value().get();
- *result = std::string(txt_value.begin(), txt_value.end());
- return true;
-}
-// Attempts to parse the uint8_t present at the provided |key| in the TXT record
-// |txt|, placing the result into |result| on success and error into |error| on
-// failure.
-bool TryParseInt(const discovery::DnsSdTxtRecord& txt,
- const std::string& key,
- Error* error,
- uint8_t* result) {
+// Returns the value for the provided |key| in the |txt| record if it exists;
+// otherwise, returns an empty string.
+std::string GetStringFromRecord(const discovery::DnsSdTxtRecord& txt,
+ const std::string& key) {
+ std::string result;
const ErrorOr<discovery::DnsSdTxtRecord::ValueRef> value = txt.GetValue(key);
- if (value.is_error()) {
- *error = value.error();
- return false;
- }
-
- const std::vector<uint8_t>& txt_value = value.value().get();
- if (txt_value.size() != 1) {
- *error = Error::Code::kParameterInvalid;
- return false;
- }
-
- *result = txt_value[0];
- return true;
-}
-
-// Simplifies logic below by changing error into an output parameter instead of
-// a return value.
-bool IsError(Error error, Error* result) {
- if (error.ok()) {
- return false;
- } else {
- *result = error;
- return true;
+ if (value.is_value()) {
+ const std::vector<uint8_t>& txt_value = value.value().get();
+ result.assign(txt_value.begin(), txt_value.end());
}
+ return result;
}
} // namespace
@@ -141,62 +80,54 @@ const std::string& ServiceInfo::GetInstanceId() const {
}
bool ServiceInfo::IsValid() const {
- std::string instance_id = GetInstanceId();
- if (!discovery::IsInstanceValid(instance_id)) {
- return false;
- }
-
- const std::string capabilities_str = EncodeIntegerString(capabilities);
- if (!discovery::DnsSdTxtRecord::IsValidTxtValue(kUniqueIdKey, unique_id) ||
- !discovery::DnsSdTxtRecord::IsValidTxtValue(kVersionId,
- protocol_version) ||
- !discovery::DnsSdTxtRecord::IsValidTxtValue(kCapabilitiesId,
- capabilities_str) ||
- !discovery::DnsSdTxtRecord::IsValidTxtValue(kStatusId, status) ||
- !discovery::DnsSdTxtRecord::IsValidTxtValue(kFriendlyNameId,
- friendly_name) ||
- !discovery::DnsSdTxtRecord::IsValidTxtValue(kModelNameId, model_name)) {
- return false;
- }
-
- return port;
+ return (
+ discovery::IsInstanceValid(GetInstanceId()) && port != 0 &&
+ !unique_id.empty() &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(kUniqueIdKey, unique_id) &&
+ protocol_version >= 2 &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(
+ kVersionKey, std::to_string(static_cast<int>(protocol_version))) &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(
+ kCapabilitiesKey, std::to_string(capabilities)) &&
+ (status == ReceiverStatus::kIdle || status == ReceiverStatus::kBusy) &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(
+ kStatusKey, std::to_string(static_cast<int>(status))) &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(kModelNameKey, model_name) &&
+ !friendly_name.empty() &&
+ discovery::DnsSdTxtRecord::IsValidTxtValue(kFriendlyNameKey,
+ friendly_name));
}
-discovery::DnsSdInstance ServiceInfoToDnsSdInstance(
- const ServiceInfo& service) {
+discovery::DnsSdInstance ServiceInfoToDnsSdInstance(const ServiceInfo& info) {
OSP_DCHECK(discovery::IsServiceValid(kCastV2ServiceId));
OSP_DCHECK(discovery::IsDomainValid(kCastV2DomainId));
- std::string instance_id = service.GetInstanceId();
- OSP_DCHECK(discovery::IsInstanceValid(instance_id));
-
- const std::string capabilities_str =
- EncodeIntegerString(service.capabilities);
+ OSP_DCHECK(info.IsValid());
discovery::DnsSdTxtRecord txt;
- Error error;
- const bool set_txt =
- !IsError(txt.SetValue(kUniqueIdKey, service.unique_id), &error) &&
- !IsError(txt.SetValue(kVersionId, service.protocol_version), &error) &&
- !IsError(txt.SetValue(kCapabilitiesId, capabilities_str), &error) &&
- !IsError(txt.SetValue(kStatusId, service.status), &error) &&
- !IsError(txt.SetValue(kFriendlyNameId, service.friendly_name), &error) &&
- !IsError(txt.SetValue(kModelNameId, service.model_name), &error);
- OSP_DCHECK(set_txt);
-
- return discovery::DnsSdInstance(instance_id, kCastV2ServiceId,
- kCastV2DomainId, std::move(txt),
- service.port);
+ const bool did_set_everything =
+ txt.SetValue(kUniqueIdKey, info.unique_id).ok() &&
+ txt.SetValue(kVersionKey,
+ std::to_string(static_cast<int>(info.protocol_version)))
+ .ok() &&
+ txt.SetValue(kCapabilitiesKey, std::to_string(info.capabilities)).ok() &&
+ txt.SetValue(kStatusKey, std::to_string(static_cast<int>(info.status)))
+ .ok() &&
+ txt.SetValue(kModelNameKey, info.model_name).ok() &&
+ txt.SetValue(kFriendlyNameKey, info.friendly_name).ok();
+ OSP_DCHECK(did_set_everything);
+
+ return discovery::DnsSdInstance(info.GetInstanceId(), kCastV2ServiceId,
+ kCastV2DomainId, std::move(txt), info.port);
}
ErrorOr<ServiceInfo> DnsSdInstanceEndpointToServiceInfo(
const discovery::DnsSdInstanceEndpoint& endpoint) {
if (endpoint.service_id() != kCastV2ServiceId) {
- return Error::Code::kParameterInvalid;
+ return {Error::Code::kParameterInvalid, "Not a Cast device."};
}
ServiceInfo record;
- record.port = endpoint.port();
for (const IPAddress& address : endpoint.addresses()) {
if (!record.v4_address && address.IsV4()) {
record.v4_address = address;
@@ -204,31 +135,71 @@ ErrorOr<ServiceInfo> DnsSdInstanceEndpointToServiceInfo(
record.v6_address = address;
}
}
- OSP_DCHECK(record.v4_address || record.v6_address);
-
- const auto& txt = endpoint.txt();
- std::string capabilities_base64;
- std::string unique_id;
- uint8_t status;
- Error error;
- if (!TryParseInt(txt, kVersionId, &error, &record.protocol_version) ||
- !TryParseInt(txt, kStatusId, &error, &status) ||
- !TryParseString(txt, kFriendlyNameId, &error, &record.friendly_name) ||
- !TryParseString(txt, kModelNameId, &error, &record.model_name) ||
- !TryParseString(txt, kCapabilitiesId, &error, &capabilities_base64) ||
- !TryParseString(txt, kUniqueIdKey, &error, &record.unique_id)) {
- return error;
+ if (!record.v4_address && !record.v6_address) {
+ return {Error::Code::kParameterInvalid,
+ "No IPv4 nor IPv6 address in record."};
+ }
+ record.port = endpoint.port();
+ if (record.port == 0) {
+ return {Error::Code::kParameterInvalid, "Invalid TCP port in record."};
+ }
+
+ // 128-bit integer in hexadecimal format.
+ record.unique_id = GetStringFromRecord(endpoint.txt(), kUniqueIdKey);
+ if (record.unique_id.empty()) {
+ return {Error::Code::kParameterInvalid,
+ "Missing device unique ID in record."};
+ }
+
+ // Cast protocol version supported. Begins at 2 and is incremented by 1 with
+ // each version.
+ std::string a_decimal_number =
+ GetStringFromRecord(endpoint.txt(), kVersionKey);
+ if (a_decimal_number.empty()) {
+ return {Error::Code::kParameterInvalid,
+ "Missing Cast protocol version in record."};
+ }
+ constexpr int kMinVersion = 2; // According to spec.
+ constexpr int kMaxVersion = 99; // Implied by spec (field is max of 2 bytes).
+ int version;
+ if (!absl::SimpleAtoi(a_decimal_number, &version) || version < kMinVersion ||
+ version > kMaxVersion) {
+ return {Error::Code::kParameterInvalid,
+ "Invalid Cast protocol version in record."};
+ }
+ record.protocol_version = static_cast<uint8_t>(version);
+
+ // A bitset of device capabilities.
+ a_decimal_number = GetStringFromRecord(endpoint.txt(), kCapabilitiesKey);
+ if (a_decimal_number.empty()) {
+ return {Error::Code::kParameterInvalid,
+ "Missing device capabilities in record."};
+ }
+ if (!absl::SimpleAtoi(a_decimal_number, &record.capabilities)) {
+ return {Error::Code::kParameterInvalid,
+ "Invalid device capabilities field in record."};
+ }
+
+ // Receiver status flag.
+ a_decimal_number = GetStringFromRecord(endpoint.txt(), kStatusKey);
+ if (a_decimal_number == "0") {
+ record.status = ReceiverStatus::kIdle;
+ } else if (a_decimal_number == "1") {
+ record.status = ReceiverStatus::kBusy;
+ } else {
+ return {Error::Code::kParameterInvalid,
+ "Missing/Invalid receiver status flag in record."};
}
- record.status = static_cast<ReceiverStatus>(status);
+ // [Optional] Receiver model name.
+ record.model_name = GetStringFromRecord(endpoint.txt(), kModelNameKey);
- const ErrorOr<uint64_t> capabilities_flags =
- DecodeIntegerString(capabilities_base64);
- if (capabilities_flags.is_error()) {
- return capabilities_flags.error();
+ // The friendly name of the device.
+ record.friendly_name = GetStringFromRecord(endpoint.txt(), kFriendlyNameKey);
+ if (record.friendly_name.empty()) {
+ return {Error::Code::kParameterInvalid,
+ "Missing device friendly name in record."};
}
- record.capabilities = static_cast<ReceiverCapabilities>(
- capabilities_flags.value() & kCapabilitiesMask);
return record;
}
diff --git a/cast/common/public/service_info.h b/cast/common/public/service_info.h
index 944a68ed..301ef99f 100644
--- a/cast/common/public/service_info.h
+++ b/cast/common/public/service_info.h
@@ -17,16 +17,16 @@ namespace openscreen {
namespace cast {
// Constants to identify a CastV2 instance with DNS-SD.
-static constexpr char kCastV2ServiceId[] = "_googlecast._tcp";
-static constexpr char kCastV2DomainId[] = "local";
+constexpr char kCastV2ServiceId[] = "_googlecast._tcp";
+constexpr char kCastV2DomainId[] = "local";
// Constants to be used as keys when storing data inside of a DNS-SD TXT record.
-static constexpr char kUniqueIdKey[] = "id";
-static constexpr char kVersionId[] = "ve";
-static constexpr char kCapabilitiesId[] = "ca";
-static constexpr char kStatusId[] = "st";
-static constexpr char kFriendlyNameId[] = "fn";
-static constexpr char kModelNameId[] = "mn";
+constexpr char kUniqueIdKey[] = "id";
+constexpr char kVersionKey[] = "ve";
+constexpr char kCapabilitiesKey[] = "ca";
+constexpr char kStatusKey[] = "st";
+constexpr char kFriendlyNameKey[] = "fn";
+constexpr char kModelNameKey[] = "md";
// This represents the ‘st’ flag in the CastV2 TXT record.
enum ReceiverStatus {
@@ -42,19 +42,16 @@ enum ReceiverStatus {
kJoin = kBusy
};
-// This represents the ‘ca’ field in the CastV2 spec.
-enum ReceiverCapabilities : uint64_t {
- kNone = 0x00,
- kHasVideoOutput = 0x01 << 0,
- kHasVideoInput = 0x01 << 1,
- kHasAudioOutput = 0x01 << 2,
- kHasAudioInput = 0x01 << 3,
- kIsDevModeEnabled = 0x01 << 4,
-};
+constexpr uint8_t kCurrentCastVersion = 2;
+
+// Bits in the ‘ca’ bitfield, per the CastV2 spec.
+constexpr uint64_t kHasVideoOutput = 1 << 0;
+constexpr uint64_t kHasVideoInput = 1 << 1;
+constexpr uint64_t kHasAudioOutput = 1 << 2;
+constexpr uint64_t kHasAudioIntput = 1 << 3;
+constexpr uint64_t kIsDevModeEnabled = 1 << 4;
-static constexpr uint8_t kCurrentCastVersion = 2;
-static constexpr ReceiverCapabilities kDefaultCapabilities =
- ReceiverCapabilities::kNone;
+constexpr uint64_t kNoCapabilities = 0;
// This is the top-level service info class for CastV2. It describes a specific
// service instance.
@@ -85,8 +82,8 @@ struct ServiceInfo {
// each version.
uint8_t protocol_version = kCurrentCastVersion;
- // Capabilities supported by this service instance.
- ReceiverCapabilities capabilities = kDefaultCapabilities;
+ // Bitfield of ReceiverCapabilities supported by this service instance.
+ uint64_t capabilities = kNoCapabilities;
// Status of the service instance.
ReceiverStatus status = ReceiverStatus::kIdle;
diff --git a/cast/common/public/service_info_unittest.cc b/cast/common/public/service_info_unittest.cc
index 2f53ef97..08401a45 100644
--- a/cast/common/public/service_info_unittest.cc
+++ b/cast/common/public/service_info_unittest.cc
@@ -4,6 +4,9 @@
#include "cast/common/public/service_info.h"
+#include <cstdio>
+#include <sstream>
+
#include "cast/common/public/testing/discovery_utils.h"
#include "discovery/dnssd/public/dns_sd_instance.h"
#include "gmock/gmock.h"
@@ -24,7 +27,7 @@ TEST(ServiceInfoTests, ConvertValidFromDnsSd) {
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
ErrorOr<ServiceInfo> info = DnsSdInstanceEndpointToServiceInfo(record);
- ASSERT_TRUE(info.is_value());
+ ASSERT_TRUE(info.is_value()) << info;
EXPECT_EQ(info.value().unique_id, kTestUniqueId);
EXPECT_TRUE(info.value().v4_address);
EXPECT_EQ(info.value().v4_address, kAddressV4);
@@ -81,39 +84,40 @@ TEST(ServiceInfoTests, ConvertInvalidFromDnsSd) {
EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
txt = CreateValidTxt();
- txt.ClearValue(kVersionId);
+ txt.ClearValue(kVersionKey);
record = discovery::DnsSdInstanceEndpoint(
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
txt = CreateValidTxt();
- txt.ClearValue(kCapabilitiesId);
+ txt.ClearValue(kCapabilitiesKey);
record = discovery::DnsSdInstanceEndpoint(
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
txt = CreateValidTxt();
- txt.ClearValue(kStatusId);
+ txt.ClearValue(kStatusKey);
record = discovery::DnsSdInstanceEndpoint(
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
txt = CreateValidTxt();
- txt.ClearValue(kFriendlyNameId);
+ txt.ClearValue(kFriendlyNameKey);
record = discovery::DnsSdInstanceEndpoint(
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
txt = CreateValidTxt();
- txt.ClearValue(kModelNameId);
+ txt.ClearValue(kModelNameKey);
record = discovery::DnsSdInstanceEndpoint(
instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface,
kEndpointV4, kEndpointV6);
- EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
+ // Note: Model name is an optional field.
+ EXPECT_FALSE(DnsSdInstanceEndpointToServiceInfo(record).is_error());
}
TEST(ServiceInfoTests, ConvertValidToDnsSd) {
@@ -129,11 +133,50 @@ TEST(ServiceInfoTests, ConvertValidToDnsSd) {
info.friendly_name = kFriendlyName;
discovery::DnsSdInstance instance = ServiceInfoToDnsSdInstance(info);
CompareTxtString(instance.txt(), kUniqueIdKey, kTestUniqueId);
- CompareTxtString(instance.txt(), kCapabilitiesId, kCapabilitiesString);
- CompareTxtString(instance.txt(), kModelNameId, kModelName);
- CompareTxtString(instance.txt(), kFriendlyNameId, kFriendlyName);
- CompareTxtInt(instance.txt(), kVersionId, kTestVersion);
- CompareTxtInt(instance.txt(), kStatusId, kStatus);
+ CompareTxtString(instance.txt(), kCapabilitiesKey, kCapabilitiesString);
+ CompareTxtString(instance.txt(), kModelNameKey, kModelName);
+ CompareTxtString(instance.txt(), kFriendlyNameKey, kFriendlyName);
+ CompareTxtInt(instance.txt(), kVersionKey, kTestVersion);
+ CompareTxtInt(instance.txt(), kStatusKey, kStatus);
+}
+
+TEST(ServiceInfoTests, ParseServiceInfoFromRealTXT) {
+ constexpr struct {
+ const char* key;
+ const char* value;
+ } kRealTXTForReceiverCastingYoutube[] = {
+ {"bs", "FA99CBBF17D0"},
+ // Note: Includes bits set that are not known:
+ {"ca", "208901"},
+ {"cd", "FED81089FA3FF851CF088AB33AB014C0"},
+ {"fn", u8"⚡ Yurovision® ULTRA™"},
+ {"ic", "/setup/icon.png"},
+ {"id", "4ef522244a5a877f35ddead7d98702e6"},
+ {"md", "Chromecast Ultra"},
+ {"nf", "2"},
+ {"rm", "6342FE65DD269999"},
+ {"rs", "YouTube"},
+ {"st", "1"},
+ {"ve", "05"},
+ };
+
+ discovery::DnsSdTxtRecord txt;
+ for (const auto e : kRealTXTForReceiverCastingYoutube) {
+ ASSERT_TRUE(txt.SetValue(e.key, e.value).ok());
+ }
+ const discovery::DnsSdInstanceEndpoint record(
+ "InstanceId", kCastV2ServiceId, kCastV2DomainId, std::move(txt),
+ kNetworkInterface, kEndpointV4, kEndpointV6);
+
+ const ErrorOr<ServiceInfo> result =
+ DnsSdInstanceEndpointToServiceInfo(record);
+ const ServiceInfo& info = result.value();
+ EXPECT_EQ(info.unique_id, "4ef522244a5a877f35ddead7d98702e6");
+ EXPECT_EQ(info.protocol_version, 5);
+ EXPECT_TRUE(info.capabilities & (kHasVideoOutput | kHasAudioOutput));
+ EXPECT_EQ(info.status, kBusy);
+ EXPECT_EQ(info.model_name, "Chromecast Ultra");
+ EXPECT_EQ(info.friendly_name, u8"⚡ Yurovision® ULTRA™");
}
} // namespace cast
diff --git a/cast/common/public/testing/discovery_utils.cc b/cast/common/public/testing/discovery_utils.cc
index e87f9bcc..66fdeb2d 100644
--- a/cast/common/public/testing/discovery_utils.cc
+++ b/cast/common/public/testing/discovery_utils.cc
@@ -5,20 +5,27 @@
#include "cast/common/public/testing/discovery_utils.h"
#include <sstream>
+#include <string>
+#include <vector>
#include "util/stringprintf.h"
namespace openscreen {
namespace cast {
+const IPAddress kAddressV4 = {192, 168, 0, 0};
+const IPAddress kAddressV6 = {1, 2, 3, 4, 5, 6, 7, 8};
+const IPEndpoint kEndpointV4 = {kAddressV4, kPort};
+const IPEndpoint kEndpointV6 = {kAddressV6, kPort};
+
discovery::DnsSdTxtRecord CreateValidTxt() {
discovery::DnsSdTxtRecord txt;
txt.SetValue(kUniqueIdKey, kTestUniqueId);
- txt.SetValue(kVersionId, kTestVersion);
- txt.SetValue(kCapabilitiesId, kCapabilitiesStringLong);
- txt.SetValue(kStatusId, kStatus);
- txt.SetValue(kFriendlyNameId, kFriendlyName);
- txt.SetValue(kModelNameId, kModelName);
+ txt.SetValue(kVersionKey, std::to_string(kTestVersion));
+ txt.SetValue(kCapabilitiesKey, kCapabilitiesStringLong);
+ txt.SetValue(kStatusKey, std::to_string(kStatus));
+ txt.SetValue(kFriendlyNameKey, kFriendlyName);
+ txt.SetValue(kModelNameKey, kModelName);
return txt;
}
@@ -37,18 +44,13 @@ void CompareTxtString(const discovery::DnsSdTxtRecord& txt,
void CompareTxtInt(const discovery::DnsSdTxtRecord& txt,
const std::string& key,
- uint8_t expected) {
+ int expected) {
ErrorOr<discovery::DnsSdTxtRecord::ValueRef> value = txt.GetValue(key);
ASSERT_FALSE(value.is_error())
<< "key: '" << key << "'' expected: '" << expected << "'";
const std::vector<uint8_t>& data = value.value().get();
- std::string parsed_value = HexEncode(data);
- ASSERT_EQ(data.size(), size_t{1})
- << "expected one byte value for key: '" << key << "' got size: '"
- << data.size() << "' bytes";
- EXPECT_EQ(data[0], expected)
- << "expected :" << std::hex << expected << "for key: '" << key
- << "', got value: '" << parsed_value << "'";
+ EXPECT_EQ(std::string(data.begin(), data.end()), std::to_string(expected))
+ << "for key: '" << key << "'";
}
} // namespace cast
diff --git a/cast/common/public/testing/discovery_utils.h b/cast/common/public/testing/discovery_utils.h
index bea23850..b0d7d03b 100644
--- a/cast/common/public/testing/discovery_utils.h
+++ b/cast/common/public/testing/discovery_utils.h
@@ -5,6 +5,8 @@
#ifndef CAST_COMMON_PUBLIC_TESTING_DISCOVERY_UTILS_H_
#define CAST_COMMON_PUBLIC_TESTING_DISCOVERY_UTILS_H_
+#include <string>
+
#include "cast/common/public/service_info.h"
#include "discovery/dnssd/public/dns_sd_txt_record.h"
#include "gmock/gmock.h"
@@ -15,22 +17,21 @@ namespace openscreen {
namespace cast {
// Constants used for testing.
-static const IPAddress kAddressV4(192, 168, 0, 0);
-static const IPAddress kAddressV6(1, 2, 3, 4, 5, 6, 7, 8);
-static constexpr uint16_t kPort = 80;
-static const IPEndpoint kEndpointV4{kAddressV4, kPort};
-static const IPEndpoint kEndpointV6{kAddressV6, kPort};
-static constexpr char kTestUniqueId[] = "1234";
-static constexpr char kFriendlyName[] = "Friendly Name 123";
-static constexpr char kModelName[] = "Openscreen";
-static constexpr char kInstanceId[] = "Openscreen-1234";
-static constexpr uint8_t kTestVersion = 0;
-static constexpr char kCapabilitiesString[] = "3";
-static constexpr char kCapabilitiesStringLong[] = "000003";
-static constexpr ReceiverCapabilities kCapabilitiesParsed =
- static_cast<ReceiverCapabilities>(0x03);
-static constexpr uint8_t kStatus = 0x01;
-static constexpr ReceiverStatus kStatusParsed = ReceiverStatus::kBusy;
+extern const IPAddress kAddressV4;
+extern const IPAddress kAddressV6;
+constexpr uint16_t kPort = 80;
+extern const IPEndpoint kEndpointV4;
+extern const IPEndpoint kEndpointV6;
+constexpr char kTestUniqueId[] = "1234";
+constexpr char kFriendlyName[] = "Friendly Name 123";
+constexpr char kModelName[] = "Openscreen";
+constexpr char kInstanceId[] = "Openscreen-1234";
+constexpr uint8_t kTestVersion = 5;
+constexpr char kCapabilitiesString[] = "3";
+constexpr char kCapabilitiesStringLong[] = "000003";
+constexpr uint64_t kCapabilitiesParsed = 0x03;
+constexpr uint8_t kStatus = 0x01;
+constexpr ReceiverStatus kStatusParsed = ReceiverStatus::kBusy;
discovery::DnsSdTxtRecord CreateValidTxt();
@@ -40,7 +41,7 @@ void CompareTxtString(const discovery::DnsSdTxtRecord& txt,
void CompareTxtInt(const discovery::DnsSdTxtRecord& txt,
const std::string& key,
- uint8_t expected);
+ int expected);
} // namespace cast
} // namespace openscreen