[Stats] Make RTCStatsMember<T> a type alias for absl::optional<T>. The moment we've all been waiting for. Step 1: Add type alias (this CL). Step 2: Migrate all uses of RTCStatsMember<T> to absl::optional<T>. Step 3: Delete type alias. Bug: webrtc:15164 Change-Id: I00a7202c0b684fb2c57fcad4f501bccc167f1fa3 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/334680 Commit-Queue: Henrik Boström <hbos@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Evan Shrubsole <eshr@google.com> Cr-Commit-Position: refs/heads/main@{#41593}
diff --git a/api/BUILD.gn b/api/BUILD.gn index 6af4fa5..2dba446 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn
@@ -774,7 +774,6 @@ "stats/attribute.h", "stats/rtc_stats.h", "stats/rtc_stats_collector_callback.h", - "stats/rtc_stats_member.h", "stats/rtc_stats_report.h", "stats/rtcstats_objects.h", ]
diff --git a/api/stats/attribute.h b/api/stats/attribute.h index 09211f4..d5fb290 100644 --- a/api/stats/attribute.h +++ b/api/stats/attribute.h
@@ -16,37 +16,41 @@ #include <string> #include <vector> +#include "absl/types/optional.h" #include "absl/types/variant.h" -#include "api/stats/rtc_stats_member.h" +#include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h" namespace webrtc { +// TODO(https://crbug.com/webrtc/15164): Migrate all uses of RTCStatsMember to +// absl::optional and delete this type alias. +template <typename T> +using RTCStatsMember = absl::optional<T>; + // A light-weight wrapper of an RTCStats attribute (an individual metric). class RTC_EXPORT Attribute { public: - // TODO(https://crbug.com/webrtc/15164): Replace uses of RTCStatsMember<T> - // with absl::optional<T> and update these pointer types. - typedef absl::variant<const RTCStatsMember<bool>*, - const RTCStatsMember<int32_t>*, - const RTCStatsMember<uint32_t>*, - const RTCStatsMember<int64_t>*, - const RTCStatsMember<uint64_t>*, - const RTCStatsMember<double>*, - const RTCStatsMember<std::string>*, - const RTCStatsMember<std::vector<bool>>*, - const RTCStatsMember<std::vector<int32_t>>*, - const RTCStatsMember<std::vector<uint32_t>>*, - const RTCStatsMember<std::vector<int64_t>>*, - const RTCStatsMember<std::vector<uint64_t>>*, - const RTCStatsMember<std::vector<double>>*, - const RTCStatsMember<std::vector<std::string>>*, - const RTCStatsMember<std::map<std::string, uint64_t>>*, - const RTCStatsMember<std::map<std::string, double>>*> + typedef absl::variant<const absl::optional<bool>*, + const absl::optional<int32_t>*, + const absl::optional<uint32_t>*, + const absl::optional<int64_t>*, + const absl::optional<uint64_t>*, + const absl::optional<double>*, + const absl::optional<std::string>*, + const absl::optional<std::vector<bool>>*, + const absl::optional<std::vector<int32_t>>*, + const absl::optional<std::vector<uint32_t>>*, + const absl::optional<std::vector<int64_t>>*, + const absl::optional<std::vector<uint64_t>>*, + const absl::optional<std::vector<double>>*, + const absl::optional<std::vector<std::string>>*, + const absl::optional<std::map<std::string, uint64_t>>*, + const absl::optional<std::map<std::string, double>>*> StatVariant; template <typename T> - explicit Attribute(const char* name, const RTCStatsMember<T>* attribute) + Attribute(const char* name, const absl::optional<T>* attribute) : name_(name), attribute_(attribute) {} const char* name() const; @@ -55,21 +59,18 @@ bool has_value() const; template <typename T> bool holds_alternative() const { - return absl::holds_alternative<const RTCStatsMember<T>*>(attribute_); + return absl::holds_alternative<const absl::optional<T>*>(attribute_); } template <typename T> - absl::optional<T> as_optional() const { + const absl::optional<T>& as_optional() const { RTC_CHECK(holds_alternative<T>()); - if (!has_value()) { - return absl::nullopt; - } - return absl::optional<T>(get<T>()); + return *absl::get<const absl::optional<T>*>(attribute_); } template <typename T> const T& get() const { RTC_CHECK(holds_alternative<T>()); RTC_CHECK(has_value()); - return absl::get<const RTCStatsMember<T>*>(attribute_)->value(); + return absl::get<const absl::optional<T>*>(attribute_)->value(); } bool is_sequence() const;
diff --git a/api/stats/rtc_stats.h b/api/stats/rtc_stats.h index edd293f..6781081 100644 --- a/api/stats/rtc_stats.h +++ b/api/stats/rtc_stats.h
@@ -21,7 +21,6 @@ #include <vector> #include "api/stats/attribute.h" -#include "api/stats/rtc_stats_member.h" #include "api/units/timestamp.h" #include "rtc_base/checks.h" #include "rtc_base/system/rtc_export.h"
diff --git a/api/stats/rtc_stats_member.h b/api/stats/rtc_stats_member.h deleted file mode 100644 index 9039569..0000000 --- a/api/stats/rtc_stats_member.h +++ /dev/null
@@ -1,185 +0,0 @@ -/* - * Copyright 2023 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef API_STATS_RTC_STATS_MEMBER_H_ -#define API_STATS_RTC_STATS_MEMBER_H_ - -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "absl/types/optional.h" -#include "rtc_base/checks.h" -#include "rtc_base/system/rtc_export.h" -#include "rtc_base/system/rtc_export_template.h" - -namespace webrtc { - -// Interface for `RTCStats` members, which have a name and a value of a type -// defined in a subclass. Only the types listed in `Type` are supported, these -// are implemented by `RTCStatsMember<T>`. The value of a member may be -// undefined, the value can only be read if `is_defined`. -class RTCStatsMemberInterface { - public: - // Member value types. - enum Type { - kBool, // bool - kInt32, // int32_t - kUint32, // uint32_t - kInt64, // int64_t - kUint64, // uint64_t - kDouble, // double - kString, // std::string - - kSequenceBool, // std::vector<bool> - kSequenceInt32, // std::vector<int32_t> - kSequenceUint32, // std::vector<uint32_t> - kSequenceInt64, // std::vector<int64_t> - kSequenceUint64, // std::vector<uint64_t> - kSequenceDouble, // std::vector<double> - kSequenceString, // std::vector<std::string> - - kMapStringUint64, // std::map<std::string, uint64_t> - kMapStringDouble, // std::map<std::string, double> - }; - - virtual ~RTCStatsMemberInterface() {} - - virtual Type type() const = 0; - virtual bool is_sequence() const = 0; - virtual bool is_string() const = 0; - virtual bool has_value() const = 0; - // Type and value comparator. The names are not compared. These operators are - // exposed for testing. - bool operator==(const RTCStatsMemberInterface& other) const { - return IsEqual(other); - } - bool operator!=(const RTCStatsMemberInterface& other) const { - return !(*this == other); - } - - virtual const RTCStatsMemberInterface* member_ptr() const { return this; } - template <typename T> - const T& cast_to() const { - RTC_DCHECK_EQ(type(), T::StaticType()); - return static_cast<const T&>(*member_ptr()); - } - - protected: - virtual bool IsEqual(const RTCStatsMemberInterface& other) const = 0; -}; - -// Template implementation of `RTCStatsMemberInterface`. -// The supported types are the ones described by -// `RTCStatsMemberInterface::Type`. -template <typename T> -class RTCStatsMember : public RTCStatsMemberInterface { - public: - RTCStatsMember() {} - explicit RTCStatsMember(const T& value) : value_(value) {} - - static Type StaticType(); - Type type() const override { return StaticType(); } - bool is_sequence() const override; - bool is_string() const override; - - template <typename U> - inline T value_or(U default_value) const { - return value_.value_or(default_value); - } - // TODO(https://crbug.com/webrtc/15164): Migrate to value_or() and delete. - template <typename U> - inline T ValueOrDefault(U default_value) const { - return value_or(default_value); - } - - // Assignment operators. - T& operator=(const T& value) { - value_ = value; - return value_.value(); - } - T& operator=(const T&& value) { - value_ = std::move(value); - return value_.value(); - } - - // Getter methods that look the same as absl::optional<T>. Please prefer these - // in order to unblock replacing RTCStatsMember<T> with absl::optional<T> in - // the future (https://crbug.com/webrtc/15164). - bool has_value() const override { return value_.has_value(); } - const T& value() const { return value_.value(); } - T& value() { return value_.value(); } - T& operator*() { - RTC_DCHECK(value_); - return *value_; - } - const T& operator*() const { - RTC_DCHECK(value_); - return *value_; - } - T* operator->() { - RTC_DCHECK(value_); - return &(*value_); - } - const T* operator->() const { - RTC_DCHECK(value_); - return &(*value_); - } - - bool IsEqual(const RTCStatsMemberInterface& other) const override { - if (type() != other.type()) - return false; - const RTCStatsMember<T>& other_t = - static_cast<const RTCStatsMember<T>&>(other); - return value_ == other_t.value_; - } - - private: - absl::optional<T> value_; -}; - -namespace rtc_stats_internal { - -typedef std::map<std::string, uint64_t> MapStringUint64; -typedef std::map<std::string, double> MapStringDouble; - -} // namespace rtc_stats_internal - -#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ - template <> \ - RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType(); \ - template <> \ - RTC_EXPORT bool RTCStatsMember<T>::is_sequence() const; \ - template <> \ - RTC_EXPORT bool RTCStatsMember<T>::is_string() const; \ - extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ - RTCStatsMember<T> - -WEBRTC_DECLARE_RTCSTATSMEMBER(bool); -WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); -WEBRTC_DECLARE_RTCSTATSMEMBER(double); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<bool>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int32_t>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint32_t>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int64_t>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint64_t>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<double>); -WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64); -WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble); - -} // namespace webrtc - -#endif // API_STATS_RTC_STATS_MEMBER_H_
diff --git a/stats/BUILD.gn b/stats/BUILD.gn index 8993272..76edc44 100644 --- a/stats/BUILD.gn +++ b/stats/BUILD.gn
@@ -18,7 +18,6 @@ sources = [ "attribute.cc", "rtc_stats.cc", - "rtc_stats_member.cc", "rtc_stats_report.cc", "rtcstats_objects.cc", ]
diff --git a/stats/attribute.cc b/stats/attribute.cc index fab948b..cf49cb2 100644 --- a/stats/attribute.cc +++ b/stats/attribute.cc
@@ -25,12 +25,12 @@ struct VisitIsSequence { // Any type of vector is a sequence. template <typename T> - bool operator()(const RTCStatsMember<std::vector<T>>* attribute) { + bool operator()(const absl::optional<std::vector<T>>* attribute) { return true; } // Any other type is not. template <typename T> - bool operator()(const RTCStatsMember<T>* attribute) { + bool operator()(const absl::optional<T>* attribute) { return false; } }; @@ -62,7 +62,7 @@ // Vector attributes. template <typename T> - std::string operator()(const RTCStatsMember<std::vector<T>>* attribute) { + std::string operator()(const absl::optional<std::vector<T>>* attribute) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; @@ -84,7 +84,7 @@ // Map attributes. template <typename T> std::string operator()( - const RTCStatsMember<std::map<std::string, T>>* attribute) { + const absl::optional<std::map<std::string, T>>* attribute) { rtc::StringBuilder sb; sb << "{"; const char* separator = ""; @@ -106,21 +106,18 @@ } // Simple attributes. template <typename T> - std::string operator()(const RTCStatsMember<T>* attribute) { + std::string operator()(const absl::optional<T>* attribute) { return ValueToString(attribute->value()); } }; struct VisitIsEqual { template <typename T> - bool operator()(const RTCStatsMember<T>* attribute) { + bool operator()(const absl::optional<T>* attribute) { if (!other.holds_alternative<T>()) { return false; } - absl::optional<T> attribute_as_optional = - attribute->has_value() ? absl::optional<T>(attribute->value()) - : absl::nullopt; - return attribute_as_optional == other.as_optional<T>(); + return *attribute == other.as_optional<T>(); } const Attribute& other; @@ -146,7 +143,7 @@ } bool Attribute::is_string() const { - return absl::holds_alternative<const RTCStatsMember<std::string>*>( + return absl::holds_alternative<const absl::optional<std::string>*>( attribute_); }
diff --git a/stats/rtc_stats_member.cc b/stats/rtc_stats_member.cc deleted file mode 100644 index 3f91988..0000000 --- a/stats/rtc_stats_member.cc +++ /dev/null
@@ -1,62 +0,0 @@ -/* - * Copyright 2023 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "api/stats/rtc_stats_member.h" - -namespace webrtc { - -#define WEBRTC_DEFINE_RTCSTATSMEMBER(T, type, is_seq, is_str) \ - template <> \ - RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType() { \ - return type; \ - } \ - template <> \ - bool RTCStatsMember<T>::is_sequence() const { \ - return is_seq; \ - } \ - template <> \ - bool RTCStatsMember<T>::is_string() const { \ - return is_str; \ - } \ - template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCStatsMember<T> - -WEBRTC_DEFINE_RTCSTATSMEMBER(bool, kBool, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(int32_t, kInt32, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(uint32_t, kUint32, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(int64_t, kInt64, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(uint64_t, kUint64, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(double, kDouble, false, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::string, kString, false, true); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<bool>, kSequenceBool, true, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<int32_t>, kSequenceInt32, true, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<uint32_t>, - kSequenceUint32, - true, - false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<int64_t>, kSequenceInt64, true, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<uint64_t>, - kSequenceUint64, - true, - false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<double>, kSequenceDouble, true, false); -WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector<std::string>, - kSequenceString, - true, - false); -WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64, - kMapStringUint64, - false, - false); -WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble, - kMapStringDouble, - false, - false); - -} // namespace webrtc
diff --git a/stats/rtc_stats_unittest.cc b/stats/rtc_stats_unittest.cc index fd90692..1098f04 100644 --- a/stats/rtc_stats_unittest.cc +++ b/stats/rtc_stats_unittest.cc
@@ -166,7 +166,8 @@ stats_with_all_values.m_map_string_double = std::map<std::string, double>(); EXPECT_NE(stats_with_all_values, empty_stats); EXPECT_EQ(stats_with_all_values, stats_with_all_values); - EXPECT_NE(stats_with_all_values.m_int32, stats_with_all_values.m_uint32); + EXPECT_NE(stats_with_all_values.GetAttribute(stats_with_all_values.m_int32), + stats_with_all_values.GetAttribute(stats_with_all_values.m_uint32)); RTCTestStats one_member_different[] = { stats_with_all_values, stats_with_all_values, stats_with_all_values, @@ -392,71 +393,42 @@ TEST(RTCStatsTest, IsSequence) { RTCTestStats stats("statsId", Timestamp::Micros(42)); - EXPECT_FALSE(stats.m_bool.is_sequence()); - EXPECT_FALSE(stats.m_int32.is_sequence()); - EXPECT_FALSE(stats.m_uint32.is_sequence()); - EXPECT_FALSE(stats.m_int64.is_sequence()); - EXPECT_FALSE(stats.m_uint64.is_sequence()); - EXPECT_FALSE(stats.m_double.is_sequence()); - EXPECT_FALSE(stats.m_string.is_sequence()); - EXPECT_TRUE(stats.m_sequence_bool.is_sequence()); - EXPECT_TRUE(stats.m_sequence_int32.is_sequence()); - EXPECT_TRUE(stats.m_sequence_uint32.is_sequence()); - EXPECT_TRUE(stats.m_sequence_int64.is_sequence()); - EXPECT_TRUE(stats.m_sequence_uint64.is_sequence()); - EXPECT_TRUE(stats.m_sequence_double.is_sequence()); - EXPECT_TRUE(stats.m_sequence_string.is_sequence()); - EXPECT_FALSE(stats.m_map_string_uint64.is_sequence()); - EXPECT_FALSE(stats.m_map_string_double.is_sequence()); -} - -TEST(RTCStatsTest, Type) { - RTCTestStats stats("statsId", Timestamp::Micros(42)); - EXPECT_EQ(RTCStatsMemberInterface::kBool, stats.m_bool.type()); - EXPECT_EQ(RTCStatsMemberInterface::kInt32, stats.m_int32.type()); - EXPECT_EQ(RTCStatsMemberInterface::kUint32, stats.m_uint32.type()); - EXPECT_EQ(RTCStatsMemberInterface::kInt64, stats.m_int64.type()); - EXPECT_EQ(RTCStatsMemberInterface::kUint64, stats.m_uint64.type()); - EXPECT_EQ(RTCStatsMemberInterface::kDouble, stats.m_double.type()); - EXPECT_EQ(RTCStatsMemberInterface::kString, stats.m_string.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceBool, - stats.m_sequence_bool.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceInt32, - stats.m_sequence_int32.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceUint32, - stats.m_sequence_uint32.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceInt64, - stats.m_sequence_int64.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceUint64, - stats.m_sequence_uint64.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceDouble, - stats.m_sequence_double.type()); - EXPECT_EQ(RTCStatsMemberInterface::kSequenceString, - stats.m_sequence_string.type()); - EXPECT_EQ(RTCStatsMemberInterface::kMapStringUint64, - stats.m_map_string_uint64.type()); - EXPECT_EQ(RTCStatsMemberInterface::kMapStringDouble, - stats.m_map_string_double.type()); + EXPECT_FALSE(stats.GetAttribute(stats.m_bool).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_int32).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_uint32).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_int64).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_uint64).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_double).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_string).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_bool).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_int32).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_uint32).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_int64).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_uint64).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_double).is_sequence()); + EXPECT_TRUE(stats.GetAttribute(stats.m_sequence_string).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_uint64).is_sequence()); + EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_double).is_sequence()); } TEST(RTCStatsTest, IsString) { RTCTestStats stats("statsId", Timestamp::Micros(42)); - EXPECT_TRUE(stats.m_string.is_string()); - EXPECT_FALSE(stats.m_bool.is_string()); - EXPECT_FALSE(stats.m_int32.is_string()); - EXPECT_FALSE(stats.m_uint32.is_string()); - EXPECT_FALSE(stats.m_int64.is_string()); - EXPECT_FALSE(stats.m_uint64.is_string()); - EXPECT_FALSE(stats.m_double.is_string()); - EXPECT_FALSE(stats.m_sequence_bool.is_string()); - EXPECT_FALSE(stats.m_sequence_int32.is_string()); - EXPECT_FALSE(stats.m_sequence_uint32.is_string()); - EXPECT_FALSE(stats.m_sequence_int64.is_string()); - EXPECT_FALSE(stats.m_sequence_uint64.is_string()); - EXPECT_FALSE(stats.m_sequence_double.is_string()); - EXPECT_FALSE(stats.m_sequence_string.is_string()); - EXPECT_FALSE(stats.m_map_string_uint64.is_string()); - EXPECT_FALSE(stats.m_map_string_double.is_string()); + EXPECT_TRUE(stats.GetAttribute(stats.m_string).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_bool).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_int32).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_uint32).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_int64).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_uint64).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_double).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_bool).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_int32).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_uint32).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_int64).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_uint64).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_double).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_sequence_string).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_uint64).is_string()); + EXPECT_FALSE(stats.GetAttribute(stats.m_map_string_double).is_string()); } TEST(RTCStatsTest, AttributeToString) {