diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/strings')
11 files changed, 1370 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc new file mode 100644 index 0000000000..7e91c3b49d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2018 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 "rtc_base/strings/audio_format_to_string.h" + +#include <utility> + +#include "rtc_base/strings/string_builder.h" + +namespace rtc { +std::string ToString(const webrtc::SdpAudioFormat& saf) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{name: " << saf.name; + sb << ", clockrate_hz: " << saf.clockrate_hz; + sb << ", num_channels: " << saf.num_channels; + sb << ", parameters: {"; + const char* sep = ""; + for (const auto& kv : saf.parameters) { + sb << sep << kv.first << ": " << kv.second; + sep = ", "; + } + sb << "}}"; + return sb.str(); +} +std::string ToString(const webrtc::AudioCodecInfo& aci) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{sample_rate_hz: " << aci.sample_rate_hz; + sb << ", num_channels: " << aci.num_channels; + sb << ", default_bitrate_bps: " << aci.default_bitrate_bps; + sb << ", min_bitrate_bps: " << aci.min_bitrate_bps; + sb << ", max_bitrate_bps: " << aci.max_bitrate_bps; + sb << ", allow_comfort_noise: " << aci.allow_comfort_noise; + sb << ", supports_network_adaption: " << aci.supports_network_adaption; + sb << "}"; + return sb.str(); +} +std::string ToString(const webrtc::AudioCodecSpec& acs) { + char sb_buf[1024]; + rtc::SimpleStringBuilder sb(sb_buf); + sb << "{format: " << ToString(acs.format); + sb << ", info: " << ToString(acs.info); + sb << "}"; + return sb.str(); +} +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h new file mode 100644 index 0000000000..6a4535c939 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/audio_format_to_string.h @@ -0,0 +1,24 @@ +/* + * Copyright 2018 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 RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ +#define RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ + +#include <string> + +#include "api/audio_codecs/audio_format.h" + +namespace rtc { +std::string ToString(const webrtc::SdpAudioFormat& saf); +std::string ToString(const webrtc::AudioCodecInfo& saf); +std::string ToString(const webrtc::AudioCodecSpec& acs); +} // namespace rtc + +#endif // RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/json.cc b/third_party/libwebrtc/rtc_base/strings/json.cc new file mode 100644 index 0000000000..5cf153c926 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json.cc @@ -0,0 +1,296 @@ +/* + * Copyright 2004 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 "rtc_base/strings/json.h" + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include "absl/strings/string_view.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +bool GetStringFromJson(const Json::Value& in, std::string* out) { + if (!in.isString()) { + if (in.isBool()) { + *out = rtc::ToString(in.asBool()); + } else if (in.isInt()) { + *out = rtc::ToString(in.asInt()); + } else if (in.isUInt()) { + *out = rtc::ToString(in.asUInt()); + } else if (in.isDouble()) { + *out = rtc::ToString(in.asDouble()); + } else { + return false; + } + } else { + *out = in.asString(); + } + return true; +} + +bool GetIntFromJson(const Json::Value& in, int* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::intValue); + if (ret) { + *out = in.asInt(); + } + } else { + long val; // NOLINT + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtol(c_str, &end_ptr, 10); // NOLINT + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val >= INT_MIN && + val <= INT_MAX); + *out = val; + } + return ret; +} + +bool GetUIntFromJson(const Json::Value& in, unsigned int* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::uintValue); + if (ret) { + *out = in.asUInt(); + } + } else { + unsigned long val; // NOLINT + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtoul(c_str, &end_ptr, 10); // NOLINT + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val <= UINT_MAX); + *out = val; + } + return ret; +} + +bool GetBoolFromJson(const Json::Value& in, bool* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::booleanValue); + if (ret) { + *out = in.asBool(); + } + } else { + if (in.asString() == "true") { + *out = true; + ret = true; + } else if (in.asString() == "false") { + *out = false; + ret = true; + } else { + ret = false; + } + } + return ret; +} + +bool GetDoubleFromJson(const Json::Value& in, double* out) { + bool ret; + if (!in.isString()) { + ret = in.isConvertibleTo(Json::realValue); + if (ret) { + *out = in.asDouble(); + } + } else { + double val; + const char* c_str = in.asCString(); + char* end_ptr; + errno = 0; + val = strtod(c_str, &end_ptr); + ret = (end_ptr != c_str && *end_ptr == '\0' && !errno); + *out = val; + } + return ret; +} + +namespace { +template <typename T> +bool JsonArrayToVector(const Json::Value& value, + bool (*getter)(const Json::Value& in, T* out), + std::vector<T>* vec) { + vec->clear(); + if (!value.isArray()) { + return false; + } + + for (Json::Value::ArrayIndex i = 0; i < value.size(); ++i) { + T val; + if (!getter(value[i], &val)) { + return false; + } + vec->push_back(val); + } + + return true; +} +// Trivial getter helper +bool GetValueFromJson(const Json::Value& in, Json::Value* out) { + *out = in; + return true; +} +} // unnamed namespace + +bool JsonArrayToValueVector(const Json::Value& in, + std::vector<Json::Value>* out) { + return JsonArrayToVector(in, GetValueFromJson, out); +} + +bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out) { + return JsonArrayToVector(in, GetIntFromJson, out); +} + +bool JsonArrayToUIntVector(const Json::Value& in, + std::vector<unsigned int>* out) { + return JsonArrayToVector(in, GetUIntFromJson, out); +} + +bool JsonArrayToStringVector(const Json::Value& in, + std::vector<std::string>* out) { + return JsonArrayToVector(in, GetStringFromJson, out); +} + +bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out) { + return JsonArrayToVector(in, GetBoolFromJson, out); +} + +bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out) { + return JsonArrayToVector(in, GetDoubleFromJson, out); +} + +namespace { +template <typename T> +Json::Value VectorToJsonArray(const std::vector<T>& vec) { + Json::Value result(Json::arrayValue); + for (size_t i = 0; i < vec.size(); ++i) { + result.append(Json::Value(vec[i])); + } + return result; +} +} // unnamed namespace + +Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in) { + return VectorToJsonArray(in); +} + +Json::Value IntVectorToJsonArray(const std::vector<int>& in) { + return VectorToJsonArray(in); +} + +Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in) { + return VectorToJsonArray(in); +} + +Json::Value StringVectorToJsonArray(const std::vector<std::string>& in) { + return VectorToJsonArray(in); +} + +Json::Value BoolVectorToJsonArray(const std::vector<bool>& in) { + return VectorToJsonArray(in); +} + +Json::Value DoubleVectorToJsonArray(const std::vector<double>& in) { + return VectorToJsonArray(in); +} + +bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out) { + if (!in.isArray() || !in.isValidIndex(static_cast<int>(n))) { + return false; + } + + *out = in[static_cast<Json::Value::ArrayIndex>(n)]; + return true; +} + +bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetIntFromJson(x, out); +} + +bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetUIntFromJson(x, out); +} + +bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetStringFromJson(x, out); +} + +bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out); +} + +bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out) { + Json::Value x; + return GetValueFromJsonArray(in, n, &x) && GetDoubleFromJson(x, out); +} + +bool GetValueFromJsonObject(const Json::Value& in, + absl::string_view k, + Json::Value* out) { + std::string k_str(k); + if (!in.isObject() || !in.isMember(k_str)) { + return false; + } + + *out = in[k_str]; + return true; +} + +bool GetIntFromJsonObject(const Json::Value& in, + absl::string_view k, + int* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetIntFromJson(x, out); +} + +bool GetUIntFromJsonObject(const Json::Value& in, + absl::string_view k, + unsigned int* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetUIntFromJson(x, out); +} + +bool GetStringFromJsonObject(const Json::Value& in, + absl::string_view k, + std::string* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetStringFromJson(x, out); +} + +bool GetBoolFromJsonObject(const Json::Value& in, + absl::string_view k, + bool* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out); +} + +bool GetDoubleFromJsonObject(const Json::Value& in, + absl::string_view k, + double* out) { + Json::Value x; + return GetValueFromJsonObject(in, k, &x) && GetDoubleFromJson(x, out); +} + +std::string JsonValueToString(const Json::Value& json) { + Json::StreamWriterBuilder builder; + std::string output = Json::writeString(builder, json); + return output.substr(0, output.size() - 1); // trim trailing newline +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/json.h b/third_party/libwebrtc/rtc_base/strings/json.h new file mode 100644 index 0000000000..3e4bac6d89 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json.h @@ -0,0 +1,83 @@ +/* + * Copyright 2004 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 RTC_BASE_STRINGS_JSON_H_ +#define RTC_BASE_STRINGS_JSON_H_ + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "json/json.h" + +namespace rtc { + +/////////////////////////////////////////////////////////////////////////////// +// JSON Helpers +/////////////////////////////////////////////////////////////////////////////// + +// Robust conversion operators, better than the ones in JsonCpp. +bool GetIntFromJson(const Json::Value& in, int* out); +bool GetUIntFromJson(const Json::Value& in, unsigned int* out); +bool GetStringFromJson(const Json::Value& in, std::string* out); +bool GetBoolFromJson(const Json::Value& in, bool* out); +bool GetDoubleFromJson(const Json::Value& in, double* out); + +// Pull values out of a JSON array. +bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out); +bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out); +bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out); +bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out); +bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out); +bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out); + +// Convert json arrays to std::vector +bool JsonArrayToValueVector(const Json::Value& in, + std::vector<Json::Value>* out); +bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out); +bool JsonArrayToUIntVector(const Json::Value& in, + std::vector<unsigned int>* out); +bool JsonArrayToStringVector(const Json::Value& in, + std::vector<std::string>* out); +bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out); +bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out); + +// Convert std::vector to json array +Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in); +Json::Value IntVectorToJsonArray(const std::vector<int>& in); +Json::Value UIntVectorToJsonArray(const std::vector<unsigned int>& in); +Json::Value StringVectorToJsonArray(const std::vector<std::string>& in); +Json::Value BoolVectorToJsonArray(const std::vector<bool>& in); +Json::Value DoubleVectorToJsonArray(const std::vector<double>& in); + +// Pull values out of a JSON object. +bool GetValueFromJsonObject(const Json::Value& in, + absl::string_view k, + Json::Value* out); +bool GetIntFromJsonObject(const Json::Value& in, absl::string_view k, int* out); +bool GetUIntFromJsonObject(const Json::Value& in, + absl::string_view k, + unsigned int* out); +bool GetStringFromJsonObject(const Json::Value& in, + absl::string_view k, + std::string* out); +bool GetBoolFromJsonObject(const Json::Value& in, + absl::string_view k, + bool* out); +bool GetDoubleFromJsonObject(const Json::Value& in, + absl::string_view k, + double* out); + +// Writes out a Json value as a string. +std::string JsonValueToString(const Json::Value& json); + +} // namespace rtc + +#endif // RTC_BASE_STRINGS_JSON_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/json_unittest.cc b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc new file mode 100644 index 0000000000..82d26f179e --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/json_unittest.cc @@ -0,0 +1,283 @@ +/* + * Copyright 2009 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 "rtc_base/strings/json.h" + +#include <vector> + +#include "test/gtest.h" + +namespace rtc { + +static Json::Value in_s("foo"); +static Json::Value in_sn("99"); +static Json::Value in_si("-99"); +static Json::Value in_sb("true"); +static Json::Value in_sd("1.2"); +static Json::Value in_n(12); +static Json::Value in_i(-12); +static Json::Value in_u(34U); +static Json::Value in_b(true); +static Json::Value in_d(1.2); +static Json::Value big_sn("12345678901234567890"); +static Json::Value big_si("-12345678901234567890"); +static Json::Value big_u(0xFFFFFFFF); +static Json::Value bad_a(Json::arrayValue); +static Json::Value bad_o(Json::objectValue); + +TEST(JsonTest, GetString) { + std::string out; + EXPECT_TRUE(GetStringFromJson(in_s, &out)); + EXPECT_EQ("foo", out); + EXPECT_TRUE(GetStringFromJson(in_sn, &out)); + EXPECT_EQ("99", out); + EXPECT_TRUE(GetStringFromJson(in_si, &out)); + EXPECT_EQ("-99", out); + EXPECT_TRUE(GetStringFromJson(in_i, &out)); + EXPECT_EQ("-12", out); + EXPECT_TRUE(GetStringFromJson(in_n, &out)); + EXPECT_EQ("12", out); + EXPECT_TRUE(GetStringFromJson(in_u, &out)); + EXPECT_EQ("34", out); + EXPECT_TRUE(GetStringFromJson(in_b, &out)); + EXPECT_EQ("true", out); + // Not supported here yet. + EXPECT_FALSE(GetStringFromJson(bad_a, &out)); + EXPECT_FALSE(GetStringFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetInt) { + int out; + EXPECT_TRUE(GetIntFromJson(in_sn, &out)); + EXPECT_EQ(99, out); + EXPECT_TRUE(GetIntFromJson(in_si, &out)); + EXPECT_EQ(-99, out); + EXPECT_TRUE(GetIntFromJson(in_n, &out)); + EXPECT_EQ(12, out); + EXPECT_TRUE(GetIntFromJson(in_i, &out)); + EXPECT_EQ(-12, out); + EXPECT_TRUE(GetIntFromJson(in_u, &out)); + EXPECT_EQ(34, out); + EXPECT_TRUE(GetIntFromJson(in_b, &out)); + EXPECT_EQ(1, out); + EXPECT_FALSE(GetIntFromJson(in_s, &out)); + EXPECT_FALSE(GetIntFromJson(big_sn, &out)); + EXPECT_FALSE(GetIntFromJson(big_si, &out)); + EXPECT_FALSE(GetIntFromJson(big_u, &out)); + EXPECT_FALSE(GetIntFromJson(bad_a, &out)); + EXPECT_FALSE(GetIntFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetUInt) { + unsigned int out; + EXPECT_TRUE(GetUIntFromJson(in_sn, &out)); + EXPECT_EQ(99U, out); + EXPECT_TRUE(GetUIntFromJson(in_n, &out)); + EXPECT_EQ(12U, out); + EXPECT_TRUE(GetUIntFromJson(in_u, &out)); + EXPECT_EQ(34U, out); + EXPECT_TRUE(GetUIntFromJson(in_b, &out)); + EXPECT_EQ(1U, out); + EXPECT_TRUE(GetUIntFromJson(big_u, &out)); + EXPECT_EQ(0xFFFFFFFFU, out); + EXPECT_FALSE(GetUIntFromJson(in_s, &out)); + // TODO(bugs.webrtc.org/9804): Fail reading negative strings. + // EXPECT_FALSE(GetUIntFromJson(in_si, &out)); + EXPECT_FALSE(GetUIntFromJson(in_i, &out)); + EXPECT_FALSE(GetUIntFromJson(big_sn, &out)); + EXPECT_FALSE(GetUIntFromJson(big_si, &out)); + EXPECT_FALSE(GetUIntFromJson(bad_a, &out)); + EXPECT_FALSE(GetUIntFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetBool) { + bool out; + EXPECT_TRUE(GetBoolFromJson(in_sb, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_n, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_i, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_u, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(in_b, &out)); + EXPECT_EQ(true, out); + EXPECT_TRUE(GetBoolFromJson(big_u, &out)); + EXPECT_EQ(true, out); + EXPECT_FALSE(GetBoolFromJson(in_s, &out)); + EXPECT_FALSE(GetBoolFromJson(in_sn, &out)); + EXPECT_FALSE(GetBoolFromJson(in_si, &out)); + EXPECT_FALSE(GetBoolFromJson(big_sn, &out)); + EXPECT_FALSE(GetBoolFromJson(big_si, &out)); + EXPECT_FALSE(GetBoolFromJson(bad_a, &out)); + EXPECT_FALSE(GetBoolFromJson(bad_o, &out)); +} + +TEST(JsonTest, GetDouble) { + double out; + EXPECT_TRUE(GetDoubleFromJson(in_sn, &out)); + EXPECT_EQ(99, out); + EXPECT_TRUE(GetDoubleFromJson(in_si, &out)); + EXPECT_EQ(-99, out); + EXPECT_TRUE(GetDoubleFromJson(in_sd, &out)); + EXPECT_EQ(1.2, out); + EXPECT_TRUE(GetDoubleFromJson(in_n, &out)); + EXPECT_EQ(12, out); + EXPECT_TRUE(GetDoubleFromJson(in_i, &out)); + EXPECT_EQ(-12, out); + EXPECT_TRUE(GetDoubleFromJson(in_u, &out)); + EXPECT_EQ(34, out); + EXPECT_TRUE(GetDoubleFromJson(in_b, &out)); + EXPECT_EQ(1, out); + EXPECT_TRUE(GetDoubleFromJson(in_d, &out)); + EXPECT_EQ(1.2, out); + EXPECT_FALSE(GetDoubleFromJson(in_s, &out)); +} + +TEST(JsonTest, GetFromArray) { + Json::Value a, out; + a.append(in_s); + a.append(in_i); + a.append(in_u); + a.append(in_b); + EXPECT_TRUE(GetValueFromJsonArray(a, 0, &out)); + EXPECT_TRUE(GetValueFromJsonArray(a, 3, &out)); + EXPECT_FALSE(GetValueFromJsonArray(a, 99, &out)); + EXPECT_FALSE(GetValueFromJsonArray(a, 0xFFFFFFFF, &out)); +} + +TEST(JsonTest, GetFromObject) { + Json::Value o, out; + o["string"] = in_s; + o["int"] = in_i; + o["uint"] = in_u; + o["bool"] = in_b; + EXPECT_TRUE(GetValueFromJsonObject(o, "int", &out)); + EXPECT_TRUE(GetValueFromJsonObject(o, "bool", &out)); + EXPECT_FALSE(GetValueFromJsonObject(o, "foo", &out)); + EXPECT_FALSE(GetValueFromJsonObject(o, "", &out)); +} + +namespace { +template <typename T> +std::vector<T> VecOf3(const T& a, const T& b, const T& c) { + std::vector<T> in; + in.push_back(a); + in.push_back(b); + in.push_back(c); + return in; +} +template <typename T> +Json::Value JsonVecOf3(const T& a, const T& b, const T& c) { + Json::Value in(Json::arrayValue); + in.append(a); + in.append(b); + in.append(c); + return in; +} +} // unnamed namespace + +TEST(JsonTest, ValueVectorToFromArray) { + std::vector<Json::Value> in = VecOf3<Json::Value>("a", "b", "c"); + Json::Value out = ValueVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i].asString(), out[i].asString()); + } + Json::Value inj = JsonVecOf3<Json::Value>("a", "b", "c"); + EXPECT_EQ(inj, out); + std::vector<Json::Value> outj; + EXPECT_TRUE(JsonArrayToValueVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, IntVectorToFromArray) { + std::vector<int> in = VecOf3<int>(1, 2, 3); + Json::Value out = IntVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asInt()); + } + Json::Value inj = JsonVecOf3<int>(1, 2, 3); + EXPECT_EQ(inj, out); + std::vector<int> outj; + EXPECT_TRUE(JsonArrayToIntVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, UIntVectorToFromArray) { + std::vector<unsigned int> in = VecOf3<unsigned int>(1, 2, 3); + Json::Value out = UIntVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asUInt()); + } + Json::Value inj = JsonVecOf3<unsigned int>(1, 2, 3); + EXPECT_EQ(inj, out); + std::vector<unsigned int> outj; + EXPECT_TRUE(JsonArrayToUIntVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, StringVectorToFromArray) { + std::vector<std::string> in = VecOf3<std::string>("a", "b", "c"); + Json::Value out = StringVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asString()); + } + Json::Value inj = JsonVecOf3<std::string>("a", "b", "c"); + EXPECT_EQ(inj, out); + std::vector<std::string> outj; + EXPECT_TRUE(JsonArrayToStringVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, BoolVectorToFromArray) { + std::vector<bool> in = VecOf3<bool>(false, true, false); + Json::Value out = BoolVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asBool()); + } + Json::Value inj = JsonVecOf3<bool>(false, true, false); + EXPECT_EQ(inj, out); + std::vector<bool> outj; + EXPECT_TRUE(JsonArrayToBoolVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +TEST(JsonTest, DoubleVectorToFromArray) { + std::vector<double> in = VecOf3<double>(1.0, 2.0, 3.0); + Json::Value out = DoubleVectorToJsonArray(in); + EXPECT_EQ(in.size(), out.size()); + for (Json::Value::ArrayIndex i = 0; i < in.size(); ++i) { + EXPECT_EQ(in[i], out[i].asDouble()); + } + Json::Value inj = JsonVecOf3<double>(1.0, 2.0, 3.0); + EXPECT_EQ(inj, out); + std::vector<double> outj; + EXPECT_TRUE(JsonArrayToDoubleVector(inj, &outj)); + for (Json::Value::ArrayIndex i = 0; i < in.size(); i++) { + EXPECT_EQ(in[i], outj[i]); + } +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.cc b/third_party/libwebrtc/rtc_base/strings/string_builder.cc new file mode 100644 index 0000000000..a419b0b3cc --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder.cc @@ -0,0 +1,134 @@ +/* + * Copyright 2018 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 "rtc_base/strings/string_builder.h" + +#include <stdarg.h> + +#include <cstdio> +#include <cstring> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_minmax.h" + +namespace rtc { + +SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer) + : buffer_(buffer) { + buffer_[0] = '\0'; + RTC_DCHECK(IsConsistent()); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) { + return operator<<(absl::string_view(&ch, 1)); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(absl::string_view str) { + RTC_DCHECK_LT(size_ + str.length(), buffer_.size()) + << "Buffer size was insufficient"; + const size_t chars_added = + rtc::SafeMin(str.length(), buffer_.size() - size_ - 1); + memcpy(&buffer_[size_], str.data(), chars_added); + size_ += chars_added; + buffer_[size_] = '\0'; + RTC_DCHECK(IsConsistent()); + return *this; +} + +// Numeric conversion routines. +// +// We use std::[v]snprintf instead of std::to_string because: +// * std::to_string relies on the current locale for formatting purposes, +// and therefore concurrent calls to std::to_string from multiple threads +// may result in partial serialization of calls +// * snprintf allows us to print the number directly into our buffer. +// * avoid allocating a std::string (potential heap alloc). +// TODO(tommi): Switch to std::to_chars in C++17. + +SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) { + return AppendFormat("%d", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) { + return AppendFormat("%u", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT + return AppendFormat("%ld", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT + return AppendFormat("%lld", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<( + unsigned long i) { // NOLINT + return AppendFormat("%lu", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<( + unsigned long long i) { // NOLINT + return AppendFormat("%llu", i); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) { + return AppendFormat("%g", f); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) { + return AppendFormat("%g", f); +} + +SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) { + return AppendFormat("%Lg", f); +} + +SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + const int len = + std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args); + if (len >= 0) { + const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_); + size_ += chars_added; + RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient"; + } else { + // This should never happen, but we're paranoid, so re-write the + // terminator in case vsnprintf() overwrote it. + RTC_DCHECK_NOTREACHED(); + buffer_[size_] = '\0'; + } + va_end(args); + RTC_DCHECK(IsConsistent()); + return *this; +} + +StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) { + va_list args, copy; + va_start(args, fmt); + va_copy(copy, args); + const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + + RTC_DCHECK_GE(predicted_length, 0); + if (predicted_length > 0) { + const size_t size = str_.size(); + str_.resize(size + predicted_length); + // Pass "+ 1" to vsnprintf to include space for the '\0'. + const int actual_length = + std::vsnprintf(&str_[size], predicted_length + 1, fmt, args); + RTC_DCHECK_GE(actual_length, 0); + } + va_end(args); + return *this; +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder.h b/third_party/libwebrtc/rtc_base/strings/string_builder.h new file mode 100644 index 0000000000..00986371d3 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder.h @@ -0,0 +1,170 @@ +/* + * Copyright 2018 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 RTC_BASE_STRINGS_STRING_BUILDER_H_ +#define RTC_BASE_STRINGS_STRING_BUILDER_H_ + +#include <cstdio> +#include <string> +#include <utility> + +#include "absl/strings/string_view.h" +#include "api/array_view.h" +#include "rtc_base/string_encode.h" + +namespace rtc { + +// This is a minimalistic string builder class meant to cover the most cases of +// when you might otherwise be tempted to use a stringstream (discouraged for +// anything except logging). It uses a fixed-size buffer provided by the caller +// and concatenates strings and numbers into it, allowing the results to be +// read via `str()`. +class SimpleStringBuilder { + public: + explicit SimpleStringBuilder(rtc::ArrayView<char> buffer); + SimpleStringBuilder(const SimpleStringBuilder&) = delete; + SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete; + + SimpleStringBuilder& operator<<(char ch); + SimpleStringBuilder& operator<<(absl::string_view str); + SimpleStringBuilder& operator<<(int i); + SimpleStringBuilder& operator<<(unsigned i); + SimpleStringBuilder& operator<<(long i); // NOLINT + SimpleStringBuilder& operator<<(long long i); // NOLINT + SimpleStringBuilder& operator<<(unsigned long i); // NOLINT + SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT + SimpleStringBuilder& operator<<(float f); + SimpleStringBuilder& operator<<(double f); + SimpleStringBuilder& operator<<(long double f); + + // Returns a pointer to the built string. The name `str()` is borrowed for + // compatibility reasons as we replace usage of stringstream throughout the + // code base. + const char* str() const { return buffer_.data(); } + + // Returns the length of the string. The name `size()` is picked for STL + // compatibility reasons. + size_t size() const { return size_; } + +// Allows appending a printf style formatted string. +#if defined(__GNUC__) + __attribute__((__format__(__printf__, 2, 3))) +#endif + SimpleStringBuilder& + AppendFormat(const char* fmt, ...); + + private: + bool IsConsistent() const { + return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0'; + } + + // An always-zero-terminated fixed-size buffer that we write to. The fixed + // size allows the buffer to be stack allocated, which helps performance. + // Having a fixed size is furthermore useful to avoid unnecessary resizing + // while building it. + const rtc::ArrayView<char> buffer_; + + // Represents the number of characters written to the buffer. + // This does not include the terminating '\0'. + size_t size_ = 0; +}; + +// A string builder that supports dynamic resizing while building a string. +// The class is based around an instance of std::string and allows moving +// ownership out of the class once the string has been built. +// Note that this class uses the heap for allocations, so SimpleStringBuilder +// might be more efficient for some use cases. +class StringBuilder { + public: + StringBuilder() {} + explicit StringBuilder(absl::string_view s) : str_(s) {} + + // TODO(tommi): Support construction from StringBuilder? + StringBuilder(const StringBuilder&) = delete; + StringBuilder& operator=(const StringBuilder&) = delete; + + StringBuilder& operator<<(const absl::string_view str) { + str_.append(str.data(), str.length()); + return *this; + } + + StringBuilder& operator<<(char c) = delete; + + StringBuilder& operator<<(int i) { + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned i) { + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(long long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(unsigned long long i) { // NOLINT + str_ += rtc::ToString(i); + return *this; + } + + StringBuilder& operator<<(float f) { + str_ += rtc::ToString(f); + return *this; + } + + StringBuilder& operator<<(double f) { + str_ += rtc::ToString(f); + return *this; + } + + StringBuilder& operator<<(long double f) { + str_ += rtc::ToString(f); + return *this; + } + + const std::string& str() const { return str_; } + + void Clear() { str_.clear(); } + + size_t size() const { return str_.size(); } + + std::string Release() { + std::string ret = std::move(str_); + str_.clear(); + return ret; + } + + // Allows appending a printf style formatted string. + StringBuilder& AppendFormat(const char* fmt, ...) +#if defined(__GNUC__) + __attribute__((__format__(__printf__, 2, 3))) +#endif + ; + + private: + std::string str_; +}; + +} // namespace rtc + +#endif // RTC_BASE_STRINGS_STRING_BUILDER_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc new file mode 100644 index 0000000000..99dfd86292 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_builder_unittest.cc @@ -0,0 +1,202 @@ +/* + * Copyright 2018 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 "rtc_base/strings/string_builder.h" + +#include <string.h> + +#include "rtc_base/checks.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(SimpleStringBuilder, Limit) { + char sb_buf[10]; + SimpleStringBuilder sb(sb_buf); + EXPECT_EQ(0u, strlen(sb.str())); + + // Test that for a SSB with a buffer size of 10, that we can write 9 chars + // into it. + sb << "012345678"; // 9 characters + '\0'. + EXPECT_EQ(0, strcmp(sb.str(), "012345678")); +} + +TEST(SimpleStringBuilder, NumbersAndChars) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + sb << 1 << ':' << 2.1 << ":" << 2.2f << ':' << 78187493520ll << ':' + << 78187493520ul; + EXPECT_EQ(0, strcmp(sb.str(), "1:2.1:2.2:78187493520:78187493520")); +} + +TEST(SimpleStringBuilder, Format) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + sb << "Here we go - "; + sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL); + EXPECT_EQ(0, + strcmp(sb.str(), + "Here we go - This is a hex formatted value: 0xdeadbeef")); +} + +TEST(SimpleStringBuilder, StdString) { + char sb_buf[100]; + SimpleStringBuilder sb(sb_buf); + std::string str = "does this work?"; + sb << str; + EXPECT_EQ(str, sb.str()); +} + +// These tests are safe to run if we have death test support or if DCHECKs are +// off. +#if (GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)) || !RTC_DCHECK_IS_ON + +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharP) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + const char* const msg = "This is just too much"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("Thi")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunStdString) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << 12; + const std::string msg = "Aw, come on!"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("12A")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunInt) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + constexpr int num = -12345; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + // If we run into the end of the buffer, resonable results are either that + // the append has no effect or that it's truncated at the point where the + // buffer ends. + EXPECT_THAT(sb.str(), + ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("-12"))); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunDouble) { + char sb_buf[5]; + SimpleStringBuilder sb(sb_buf); + constexpr double num = 123.456; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + EXPECT_THAT(sb.str(), + ::testing::AnyOf(::testing::StrEq(""), ::testing::StrEq("123."))); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunConstCharPAlreadyFull) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << 123; + const char* const msg = "This is just too much"; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << msg, ""); +#else + sb << msg; + EXPECT_THAT(sb.str(), ::testing::StrEq("123")); +#endif +} + +TEST(SimpleStringBuilderDeathTest, BufferOverrunIntAlreadyFull) { + char sb_buf[4]; + SimpleStringBuilder sb(sb_buf); + sb << "xyz"; + constexpr int num = -12345; +#if RTC_DCHECK_IS_ON + EXPECT_DEATH(sb << num, ""); +#else + sb << num; + EXPECT_THAT(sb.str(), ::testing::StrEq("xyz")); +#endif +} + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// StringBuilder. + +TEST(StringBuilder, Limit) { + StringBuilder sb; + EXPECT_EQ(0u, sb.str().size()); + + sb << "012345678"; + EXPECT_EQ(sb.str(), "012345678"); +} + +TEST(StringBuilder, NumbersAndChars) { + StringBuilder sb; + sb << 1 << ":" << 2.1 << ":" << 2.2f << ":" << 78187493520ll << ":" + << 78187493520ul; + EXPECT_THAT(sb.str(), + ::testing::MatchesRegex("1:2.10*:2.20*:78187493520:78187493520")); +} + +TEST(StringBuilder, Format) { + StringBuilder sb; + sb << "Here we go - "; + sb.AppendFormat("This is a hex formatted value: 0x%08llx", 3735928559ULL); + EXPECT_EQ(sb.str(), "Here we go - This is a hex formatted value: 0xdeadbeef"); +} + +TEST(StringBuilder, StdString) { + StringBuilder sb; + std::string str = "does this work?"; + sb << str; + EXPECT_EQ(str, sb.str()); +} + +TEST(StringBuilder, Release) { + StringBuilder sb; + std::string str = + "This string has to be of a moderate length, or we might " + "run into problems with small object optimizations."; + EXPECT_LT(sizeof(str), str.size()); + sb << str; + EXPECT_EQ(str, sb.str()); + const char* original_buffer = sb.str().c_str(); + std::string moved = sb.Release(); + EXPECT_TRUE(sb.str().empty()); + EXPECT_EQ(str, moved); + EXPECT_EQ(original_buffer, moved.c_str()); +} + +TEST(StringBuilder, Reset) { + StringBuilder sb("abc"); + sb << "def"; + EXPECT_EQ("abcdef", sb.str()); + sb.Clear(); + EXPECT_TRUE(sb.str().empty()); + sb << 123 << "!"; + EXPECT_EQ("123!", sb.str()); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.cc b/third_party/libwebrtc/rtc_base/strings/string_format.cc new file mode 100644 index 0000000000..e69fb6193d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format.cc @@ -0,0 +1,41 @@ +/* + * Copyright 2020 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 "rtc_base/strings/string_format.h" + +#include <cstdarg> + +#include "rtc_base/checks.h" + +namespace rtc { + +namespace { + +// This is an arbitrary limitation that can be changed if necessary, or removed +// if someone has the time and inclination to replicate the fancy logic from +// Chromium's base::StringPrinf(). +constexpr int kMaxSize = 512; + +} // namespace + +std::string StringFormat(const char* fmt, ...) { + char buffer[kMaxSize]; + va_list args; + va_start(args, fmt); + int result = vsnprintf(buffer, kMaxSize, fmt, args); + va_end(args); + RTC_DCHECK_GE(result, 0) << "ERROR: vsnprintf() failed with error " << result; + RTC_DCHECK_LT(result, kMaxSize) + << "WARNING: string was truncated from " << result << " to " + << (kMaxSize - 1) << " characters"; + return std::string(buffer); +} + +} // namespace rtc diff --git a/third_party/libwebrtc/rtc_base/strings/string_format.h b/third_party/libwebrtc/rtc_base/strings/string_format.h new file mode 100644 index 0000000000..13124d2925 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 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 RTC_BASE_STRINGS_STRING_FORMAT_H_ +#define RTC_BASE_STRINGS_STRING_FORMAT_H_ + +#include <string> + +namespace rtc { + +#if defined(__GNUC__) +#define RTC_PRINTF_FORMAT(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#else +#define RTC_PRINTF_FORMAT(format_param, dots_param) +#endif + +// Return a C++ string given printf-like input. +// Based on base::StringPrintf() in Chrome but without its fancy dynamic memory +// allocation for any size of the input buffer. +std::string StringFormat(const char* fmt, ...) RTC_PRINTF_FORMAT(1, 2); +} // namespace rtc + +#endif // RTC_BASE_STRINGS_STRING_FORMAT_H_ diff --git a/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc new file mode 100644 index 0000000000..5531001979 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/strings/string_format_unittest.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2020 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 "rtc_base/strings/string_format.h" + +#include <vector> + +#include "absl/strings/string_view.h" +#include "rtc_base/checks.h" +#include "rtc_base/string_encode.h" +#include "test/gtest.h" + +namespace rtc { + +TEST(StringFormatTest, Empty) { + EXPECT_EQ("", StringFormat("%s", "")); +} + +TEST(StringFormatTest, Misc) { + EXPECT_EQ("123hello w", StringFormat("%3d%2s %1c", 123, "hello", 'w')); + EXPECT_EQ("3 = three", StringFormat("%d = %s", 1 + 2, "three")); +} + +TEST(StringFormatTest, MaxSizeShouldWork) { + const int kSrcLen = 512; + char str[kSrcLen]; + std::fill_n(str, kSrcLen, 'A'); + str[kSrcLen - 1] = 0; + EXPECT_EQ(str, StringFormat("%s", str)); +} + +// Test that formating a string using `absl::string_view` works as expected +// whe using `%.*s`. +TEST(StringFormatTest, FormatStringView) { + const std::string main_string("This is a substring test."); + std::vector<absl::string_view> string_views = rtc::split(main_string, ' '); + ASSERT_EQ(string_views.size(), 5u); + + const absl::string_view& sv = string_views[3]; + std::string formatted = + StringFormat("We have a %.*s.", static_cast<int>(sv.size()), sv.data()); + EXPECT_EQ(formatted.compare("We have a substring."), 0); +} + +} // namespace rtc |