diff options
Diffstat (limited to 'chromium/third_party/openscreen/src/util')
13 files changed, 524 insertions, 41 deletions
diff --git a/chromium/third_party/openscreen/src/util/BUILD.gn b/chromium/third_party/openscreen/src/util/BUILD.gn index b21003462dc..000b3ea679c 100644 --- a/chromium/third_party/openscreen/src/util/BUILD.gn +++ b/chromium/third_party/openscreen/src/util/BUILD.gn @@ -23,6 +23,7 @@ source_set("util") { "alarm.h", "big_endian.cc", "big_endian.h", + "chrono_helpers.h", "crypto/certificate_utils.cc", "crypto/certificate_utils.h", "crypto/digest_sign.cc", @@ -37,6 +38,7 @@ source_set("util") { "crypto/sha2.h", "hashing.h", "integer_division.h", + "json/json_helpers.h", "json/json_serialization.cc", "json/json_serialization.h", "json/json_value.cc", @@ -86,6 +88,7 @@ source_set("unittests") { "crypto/secure_hash_unittest.cc", "crypto/sha2_unittest.cc", "integer_division_unittest.cc", + "json/json_helpers_unittest.cc", "json/json_serialization_unittest.cc", "json/json_value_unittest.cc", "operation_loop_unittest.cc", diff --git a/chromium/third_party/openscreen/src/util/alarm_unittest.cc b/chromium/third_party/openscreen/src/util/alarm_unittest.cc index 5fad74bf7f4..094afc9c42a 100644 --- a/chromium/third_party/openscreen/src/util/alarm_unittest.cc +++ b/chromium/third_party/openscreen/src/util/alarm_unittest.cc @@ -5,10 +5,12 @@ #include "util/alarm.h" #include <algorithm> +#include <chrono> #include "gtest/gtest.h" #include "platform/test/fake_clock.h" #include "platform/test/fake_task_runner.h" +#include "util/chrono_helpers.h" namespace openscreen { namespace { @@ -26,7 +28,7 @@ class AlarmTest : public testing::Test { }; TEST_F(AlarmTest, RunsTaskAsClockAdvances) { - constexpr Clock::duration kDelay = std::chrono::milliseconds(20); + constexpr Clock::duration kDelay = milliseconds(20); const Clock::time_point alarm_time = FakeClock::now() + kDelay; Clock::time_point actual_run_time{}; @@ -61,12 +63,12 @@ TEST_F(AlarmTest, RunsTaskImmediately) { ASSERT_EQ(expected_run_time, actual_run_time); // Confirm the lambda is only run once. - clock()->Advance(std::chrono::seconds(2)); + clock()->Advance(seconds(2)); ASSERT_EQ(expected_run_time, actual_run_time); } TEST_F(AlarmTest, CancelsTaskWhenGoingOutOfScope) { - constexpr Clock::duration kDelay = std::chrono::milliseconds(20); + constexpr Clock::duration kDelay = milliseconds(20); constexpr Clock::time_point kNever{}; Clock::time_point actual_run_time{}; @@ -85,7 +87,7 @@ TEST_F(AlarmTest, CancelsTaskWhenGoingOutOfScope) { } TEST_F(AlarmTest, Cancels) { - constexpr Clock::duration kDelay = std::chrono::milliseconds(20); + constexpr Clock::duration kDelay = milliseconds(20); const Clock::time_point alarm_time = FakeClock::now() + kDelay; Clock::time_point actual_run_time{}; @@ -104,8 +106,8 @@ TEST_F(AlarmTest, Cancels) { } TEST_F(AlarmTest, CancelsAndRearms) { - constexpr Clock::duration kShorterDelay = std::chrono::milliseconds(10); - constexpr Clock::duration kLongerDelay = std::chrono::milliseconds(100); + constexpr Clock::duration kShorterDelay = milliseconds(10); + constexpr Clock::duration kLongerDelay = milliseconds(100); // Run the test twice: Once when scheduling first with a long delay, then a // shorter delay; and once when scheduling first with a short delay, then a diff --git a/chromium/third_party/openscreen/src/util/big_endian.cc b/chromium/third_party/openscreen/src/util/big_endian.cc index d56589003ae..59992d605d4 100644 --- a/chromium/third_party/openscreen/src/util/big_endian.cc +++ b/chromium/third_party/openscreen/src/util/big_endian.cc @@ -30,4 +30,4 @@ bool BigEndianWriter::Write(const void* buffer, size_t length) { return false; } -} // namespace openscreen
\ No newline at end of file +} // namespace openscreen diff --git a/chromium/third_party/openscreen/src/util/big_endian.h b/chromium/third_party/openscreen/src/util/big_endian.h index b2067d7537e..0953ddf08a6 100644 --- a/chromium/third_party/openscreen/src/util/big_endian.h +++ b/chromium/third_party/openscreen/src/util/big_endian.h @@ -150,7 +150,7 @@ class BigEndianBuffer { public: class Cursor { public: - Cursor(BigEndianBuffer* buffer) + explicit Cursor(BigEndianBuffer* buffer) : buffer_(buffer), origin_(buffer_->current_) {} Cursor(const Cursor& other) = delete; Cursor(Cursor&& other) = delete; diff --git a/chromium/third_party/openscreen/src/util/chrono_helpers.h b/chromium/third_party/openscreen/src/util/chrono_helpers.h new file mode 100644 index 00000000000..a3711bbebb3 --- /dev/null +++ b/chromium/third_party/openscreen/src/util/chrono_helpers.h @@ -0,0 +1,50 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UTIL_CHRONO_HELPERS_H_ +#define UTIL_CHRONO_HELPERS_H_ + +#include <chrono> + +// This file is a collection of helpful utilities and using statement for +// working with std::chrono. In practice we previously defined these frequently, +// this header allows for a single set of convenience statements. +namespace openscreen { + +using hours = std::chrono::hours; +using microseconds = std::chrono::microseconds; +using milliseconds = std::chrono::milliseconds; +using nanoseconds = std::chrono::nanoseconds; +using seconds = std::chrono::seconds; + +// Casting statements. Note that duration_cast is not a type, it's a function, +// so its behavior is different than the using statements above. +template <typename D> +static constexpr hours to_hours(D d) { + return std::chrono::duration_cast<hours>(d); +} + +template <typename D> +static constexpr microseconds to_microseconds(D d) { + return std::chrono::duration_cast<microseconds>(d); +} + +template <typename D> +static constexpr milliseconds to_milliseconds(D d) { + return std::chrono::duration_cast<milliseconds>(d); +} + +template <typename D> +static constexpr nanoseconds to_nanoseconds(D d) { + return std::chrono::duration_cast<nanoseconds>(d); +} + +template <typename D> +static constexpr seconds to_seconds(D d) { + return std::chrono::duration_cast<seconds>(d); +} + +} // namespace openscreen + +#endif // UTIL_CHRONO_HELPERS_H_ diff --git a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc index ddedb533bb8..8f18b7ea9d8 100644 --- a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc +++ b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc @@ -146,19 +146,6 @@ ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509Certificate( absl::string_view name, std::chrono::seconds duration, const EVP_PKEY& key_pair, - std::chrono::seconds time_since_unix_epoch) { - bssl::UniquePtr<X509> certificate = CreateCertificateInternal( - name, duration, key_pair, time_since_unix_epoch, false, nullptr, nullptr); - if (!certificate) { - return Error::Code::kCertificateCreationError; - } - return certificate; -} - -ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509CertificateForTest( - absl::string_view name, - std::chrono::seconds duration, - const EVP_PKEY& key_pair, std::chrono::seconds time_since_unix_epoch, bool make_ca, X509* issuer, diff --git a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h index e60c28c3d26..22da0330a0b 100644 --- a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h +++ b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h @@ -23,22 +23,12 @@ namespace openscreen { // Generates a new RSA key pair with bit width |key_bits|. bssl::UniquePtr<EVP_PKEY> GenerateRsaKeyPair(int key_bits = 2048); -// Creates a new self-signed X509 certificate having the given |name| and -// |duration| until expiration, and based on the given |key_pair|, which is -// expected to contain a valid private key. -// |time_since_unix_epoch| is the current time. -ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509Certificate( - absl::string_view name, - std::chrono::seconds duration, - const EVP_PKEY& key_pair, - std::chrono::seconds time_since_unix_epoch = GetWallTimeSinceUnixEpoch()); - // Creates a new X509 certificate having the given |name| and |duration| until // expiration, and based on the given |key_pair|. If |issuer| and |issuer_key| // are provided, they are used to set the issuer information, otherwise it will // be self-signed. |make_ca| determines whether additional extensions are added // to make it a valid certificate authority cert. -ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509CertificateForTest( +ErrorOr<bssl::UniquePtr<X509>> CreateSelfSignedX509Certificate( absl::string_view name, std::chrono::seconds duration, const EVP_PKEY& key_pair, diff --git a/chromium/third_party/openscreen/src/util/crypto/secure_hash.h b/chromium/third_party/openscreen/src/util/crypto/secure_hash.h index 7c007f96350..f748cc458b5 100644 --- a/chromium/third_party/openscreen/src/util/crypto/secure_hash.h +++ b/chromium/third_party/openscreen/src/util/crypto/secure_hash.h @@ -21,7 +21,7 @@ namespace openscreen { // same as if we have the full input in advance. class SecureHash { public: - SecureHash(const EVP_MD* type); + explicit SecureHash(const EVP_MD* type); SecureHash(const SecureHash& other); SecureHash(SecureHash&& other); SecureHash& operator=(const SecureHash& other); diff --git a/chromium/third_party/openscreen/src/util/json/json_helpers.h b/chromium/third_party/openscreen/src/util/json/json_helpers.h new file mode 100644 index 00000000000..a4c43479edc --- /dev/null +++ b/chromium/third_party/openscreen/src/util/json/json_helpers.h @@ -0,0 +1,209 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UTIL_JSON_JSON_HELPERS_H_ +#define UTIL_JSON_JSON_HELPERS_H_ + +#include <chrono> +#include <functional> +#include <string> +#include <utility> +#include <vector> + +#include "absl/strings/string_view.h" +#include "json/value.h" +#include "platform/base/error.h" +#include "util/chrono_helpers.h" +#include "util/simple_fraction.h" + +// This file contains helper methods for parsing JSON, in an attempt to +// reduce boilerplate code when working with JsonCpp. +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) { + if (!value.isBool()) { + return false; + } + *out = value.asBool(); + return true; +} + +// A general note about parsing primitives. "Validation" in this context +// generally means ensuring that the values are non-negative. There are +// currently no cases in our usage of JSON strings where we accept negative +// values. If this changes in the future, care must be taken to ensure +// that we don't break anything in existing code. +inline bool ParseAndValidateDouble(const Json::Value& value, double* out) { + if (!value.isDouble()) { + return false; + } + const double d = value.asDouble(); + if (d < 0) { + return false; + } + *out = d; + return true; +} + +inline bool ParseAndValidateInt(const Json::Value& value, int* out) { + if (!value.isInt()) { + return false; + } + int i = value.asInt(); + if (i < 0) { + return false; + } + *out = i; + return true; +} + +inline bool ParseAndValidateUint(const Json::Value& value, uint32_t* out) { + if (!value.isUInt()) { + return false; + } + *out = value.asUInt(); + return true; +} + +inline bool ParseAndValidateString(const Json::Value& value, std::string* out) { + if (!value.isString()) { + return false; + } + *out = value.asString(); + return true; +} + +// 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) { + if (value.isInt()) { + int parsed = value.asInt(); + if (parsed < 0) { + return false; + } + *out = SimpleFraction{parsed, 1}; + return true; + } + + if (value.isString()) { + auto fraction_or_error = SimpleFraction::FromString(value.asString()); + if (!fraction_or_error) { + return false; + } + + if (!fraction_or_error.value().is_positive() || + !fraction_or_error.value().is_defined()) { + return false; + } + *out = std::move(fraction_or_error.value()); + return true; + } + return false; +} + +inline bool ParseAndValidateMilliseconds(const Json::Value& value, + milliseconds* out) { + int out_ms; + if (!ParseAndValidateInt(value, &out_ms) || out_ms < 0) { + return false; + } + *out = milliseconds(out_ms); + return true; +} + +template <typename T> +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) { + out->clear(); + if (!value.isArray() || value.empty()) { + return false; + } + + out->reserve(value.size()); + for (Json::ArrayIndex i = 0; i < value.size(); ++i) { + T v; + if (!parser(value[i], &v)) { + out->clear(); + return false; + } + out->push_back(v); + } + + return true; +} + +inline bool ParseAndValidateIntArray(const Json::Value& value, + std::vector<int>* out) { + return ParseAndValidateArray<int>(value, ParseAndValidateInt, out); +} + +inline bool ParseAndValidateUintArray(const Json::Value& value, + std::vector<uint32_t>* out) { + return ParseAndValidateArray<uint32_t>(value, ParseAndValidateUint, out); +} + +inline bool ParseAndValidateStringArray(const Json::Value& value, + std::vector<std::string>* out) { + return ParseAndValidateArray<std::string>(value, ParseAndValidateString, out); +} + +} // namespace json +} // namespace openscreen + +#endif // UTIL_JSON_JSON_HELPERS_H_ diff --git a/chromium/third_party/openscreen/src/util/json/json_helpers_unittest.cc b/chromium/third_party/openscreen/src/util/json/json_helpers_unittest.cc new file mode 100644 index 00000000000..fdac1897e4b --- /dev/null +++ b/chromium/third_party/openscreen/src/util/json/json_helpers_unittest.cc @@ -0,0 +1,209 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "util/json/json_helpers.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "util/chrono_helpers.h" + +namespace openscreen { +namespace json { +namespace { + +using ::testing::ElementsAre; + +const Json::Value kNone; +const Json::Value kEmptyString = ""; +const Json::Value kEmptyArray(Json::arrayValue); + +struct Dummy { + int value; + + constexpr bool operator==(const Dummy& other) const { + return other.value == value; + } +}; + +bool ParseAndValidateDummy(const Json::Value& value, Dummy* out) { + int value_out; + if (!ParseAndValidateInt(value, &value_out)) { + return false; + } + *out = Dummy{value_out}; + return true; +} + +} // namespace + +TEST(ParsingHelpersTest, ParseAndValidateDouble) { + const Json::Value kValid = 13.37; + const Json::Value kNotDouble = "coffee beans"; + const Json::Value kNegativeDouble = -4.2; + const Json::Value kZeroDouble = 0.0; + + double out; + EXPECT_TRUE(ParseAndValidateDouble(kValid, &out)); + EXPECT_DOUBLE_EQ(13.37, out); + EXPECT_TRUE(ParseAndValidateDouble(kZeroDouble, &out)); + EXPECT_DOUBLE_EQ(0.0, out); + EXPECT_FALSE(ParseAndValidateDouble(kNotDouble, &out)); + EXPECT_FALSE(ParseAndValidateDouble(kNegativeDouble, &out)); + EXPECT_FALSE(ParseAndValidateDouble(kNone, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateInt) { + 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_EQ(1337, out); + EXPECT_TRUE(ParseAndValidateInt(kZeroInt, &out)); + EXPECT_EQ(0, out); + EXPECT_FALSE(ParseAndValidateInt(kNone, &out)); + EXPECT_FALSE(ParseAndValidateInt(kNotInt, &out)); + EXPECT_FALSE(ParseAndValidateInt(kNegativeInt, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateUint) { + const Json::Value kValid = 1337u; + const Json::Value kNotUint = "espresso"; + const Json::Value kZeroUint = 0u; + + uint32_t out; + EXPECT_TRUE(ParseAndValidateUint(kValid, &out)); + EXPECT_EQ(1337u, out); + EXPECT_TRUE(ParseAndValidateUint(kZeroUint, &out)); + EXPECT_EQ(0u, out); + EXPECT_FALSE(ParseAndValidateUint(kNone, &out)); + EXPECT_FALSE(ParseAndValidateUint(kNotUint, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateString) { + const Json::Value kValid = "macchiato"; + const Json::Value kNotString = 42; + + std::string out; + EXPECT_TRUE(ParseAndValidateString(kValid, &out)); + EXPECT_EQ("macchiato", out); + EXPECT_TRUE(ParseAndValidateString(kEmptyString, &out)); + EXPECT_EQ("", out); + EXPECT_FALSE(ParseAndValidateString(kNone, &out)); + EXPECT_FALSE(ParseAndValidateString(kNotString, &out)); +} + +// Simple fraction validity is tested extensively in its unit tests, so we +// just check the major cases here. +TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) { + const Json::Value kValid = "42/30"; + const Json::Value kValidNumber = "42"; + const Json::Value kUndefined = "5/0"; + const Json::Value kNegative = "10/-2"; + const Json::Value kInvalidNumber = "-1"; + const Json::Value kNotSimpleFraction = "latte"; + + SimpleFraction out; + EXPECT_TRUE(ParseAndValidateSimpleFraction(kValid, &out)); + EXPECT_EQ((SimpleFraction{42, 30}), out); + EXPECT_TRUE(ParseAndValidateSimpleFraction(kValidNumber, &out)); + EXPECT_EQ((SimpleFraction{42, 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)); +} + +TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) { + const Json::Value kValid = 1000; + const Json::Value kValidFloat = 500.0; + const Json::Value kNegativeNumber = -120; + const Json::Value kZeroNumber = 0; + const Json::Value kNotNumber = "affogato"; + + milliseconds out; + EXPECT_TRUE(ParseAndValidateMilliseconds(kValid, &out)); + EXPECT_EQ(milliseconds(1000), out); + EXPECT_TRUE(ParseAndValidateMilliseconds(kValidFloat, &out)); + EXPECT_EQ(milliseconds(500), out); + EXPECT_TRUE(ParseAndValidateMilliseconds(kZeroNumber, &out)); + EXPECT_EQ(milliseconds(0), out); + EXPECT_FALSE(ParseAndValidateMilliseconds(kNone, &out)); + EXPECT_FALSE(ParseAndValidateMilliseconds(kNegativeNumber, &out)); + EXPECT_FALSE(ParseAndValidateMilliseconds(kNotNumber, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateArray) { + Json::Value valid_dummy_array; + valid_dummy_array[0] = 123; + valid_dummy_array[1] = 456; + + Json::Value invalid_dummy_array; + invalid_dummy_array[0] = "iced coffee"; + invalid_dummy_array[1] = 456; + + std::vector<Dummy> out; + EXPECT_TRUE(ParseAndValidateArray<Dummy>(valid_dummy_array, + ParseAndValidateDummy, &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)); +} + +TEST(ParsingHelpersTest, ParseAndValidateIntArray) { + Json::Value valid_int_array; + valid_int_array[0] = 123; + valid_int_array[1] = 456; + + Json::Value invalid_int_array; + invalid_int_array[0] = "iced coffee"; + invalid_int_array[1] = 456; + + std::vector<int> out; + EXPECT_TRUE(ParseAndValidateIntArray(valid_int_array, &out)); + EXPECT_THAT(out, ElementsAre(123, 456)); + EXPECT_FALSE(ParseAndValidateIntArray(invalid_int_array, &out)); + EXPECT_FALSE(ParseAndValidateIntArray(kEmptyArray, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateUintArray) { + Json::Value valid_uint_array; + valid_uint_array[0] = 123u; + valid_uint_array[1] = 456u; + + Json::Value invalid_uint_array; + invalid_uint_array[0] = "breve"; + invalid_uint_array[1] = 456u; + + std::vector<uint32_t> out; + EXPECT_TRUE(ParseAndValidateUintArray(valid_uint_array, &out)); + EXPECT_THAT(out, ElementsAre(123u, 456u)); + EXPECT_FALSE(ParseAndValidateUintArray(invalid_uint_array, &out)); + EXPECT_FALSE(ParseAndValidateUintArray(kEmptyArray, &out)); +} + +TEST(ParsingHelpersTest, ParseAndValidateStringArray) { + Json::Value valid_string_array; + valid_string_array[0] = "nitro cold brew"; + valid_string_array[1] = "doppio espresso"; + + Json::Value invalid_string_array; + invalid_string_array[0] = "mocha latte"; + invalid_string_array[1] = 456; + + std::vector<std::string> out; + EXPECT_TRUE(ParseAndValidateStringArray(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)); +} + +} // namespace json +} // namespace openscreen diff --git a/chromium/third_party/openscreen/src/util/simple_fraction_unittest.cc b/chromium/third_party/openscreen/src/util/simple_fraction_unittest.cc index 7cdbfeeccad..49bf3987df1 100644 --- a/chromium/third_party/openscreen/src/util/simple_fraction_unittest.cc +++ b/chromium/third_party/openscreen/src/util/simple_fraction_unittest.cc @@ -4,6 +4,7 @@ #include "util/simple_fraction.h" +#include <cmath> #include <limits> #include "gtest/gtest.h" @@ -15,16 +16,15 @@ namespace { constexpr int kMin = std::numeric_limits<int>::min(); constexpr int kMax = std::numeric_limits<int>::max(); -void ExpectFromStringEquals(absl::string_view s, - const SimpleFraction& expected) { - const ErrorOr<SimpleFraction> f = SimpleFraction::FromString(s); - EXPECT_TRUE(f.is_value()); +void ExpectFromStringEquals(const char* s, const SimpleFraction& expected) { + const ErrorOr<SimpleFraction> f = SimpleFraction::FromString(std::string(s)); + EXPECT_TRUE(f.is_value()) << "from string: '" << s << "'"; EXPECT_EQ(expected, f.value()); } -void ExpectFromStringError(absl::string_view s) { - const auto f = SimpleFraction::FromString(s); - EXPECT_TRUE(f.is_error()); +void ExpectFromStringError(const char* s) { + const auto f = SimpleFraction::FromString(std::string(s)); + EXPECT_TRUE(f.is_error()) << "from string: '" << s << "'"; } } // namespace @@ -46,6 +46,7 @@ TEST(SimpleFractionTest, FromStringErrorsOnInvalid) { ExpectFromStringError("1/"); ExpectFromStringError("/1"); ExpectFromStringError("888/"); + ExpectFromStringError("1/2/3"); ExpectFromStringError("not a fraction at all"); } @@ -91,6 +92,7 @@ TEST(SimpleFractionTest, Positivity) { TEST(SimpleFractionTest, CastToDouble) { EXPECT_DOUBLE_EQ(0.0, static_cast<double>(SimpleFraction{0, 1})); EXPECT_DOUBLE_EQ(1.0, static_cast<double>(SimpleFraction{1, 1})); + EXPECT_TRUE(std::isnan(static_cast<double>(SimpleFraction{1, 0}))); EXPECT_DOUBLE_EQ(1.0, static_cast<double>(SimpleFraction{kMax, kMax})); EXPECT_DOUBLE_EQ(1.0, static_cast<double>(SimpleFraction{kMin, kMin})); } diff --git a/chromium/third_party/openscreen/src/util/std_util.h b/chromium/third_party/openscreen/src/util/std_util.h index 5a77bb5513a..87726955f94 100644 --- a/chromium/third_party/openscreen/src/util/std_util.h +++ b/chromium/third_party/openscreen/src/util/std_util.h @@ -5,8 +5,10 @@ #ifndef UTIL_STD_UTIL_H_ #define UTIL_STD_UTIL_H_ +#include <algorithm> #include <map> #include <string> +#include <utility> #include <vector> #include "absl/algorithm/container.h" @@ -53,6 +55,34 @@ void SortAndDedupeElements(RandomAccessContainer* c) { c->erase(new_end, c->end()); } +// Append the provided elements together into a single vector. This can be +// useful when creating a vector of variadic templates in the ctor. +// +// This is the base case for the recursion +template <typename T> +std::vector<T>&& Append(std::vector<T>&& so_far) { + return std::move(so_far); +} + +// This is the recursive call. Depending on the number of remaining elements, it +// either calls into itself or into the above base case. +template <typename T, typename TFirst, typename... TOthers> +std::vector<T>&& Append(std::vector<T>&& so_far, + TFirst&& new_element, + TOthers&&... new_elements) { + so_far.push_back(std::move(new_element)); + return Append(std::move(so_far), std::move(new_elements)...); +} + +// Creates an empty vector with |size| elements reserved. Intended to be used as +// GetEmptyVectorOfSize<T>(sizeof...(variadic_input)) +template <typename T> +std::vector<T> GetVectorWithCapacity(size_t size) { + std::vector<T> results; + results.reserve(size); + return results; +} + } // namespace openscreen #endif // UTIL_STD_UTIL_H_ diff --git a/chromium/third_party/openscreen/src/util/weak_ptr.h b/chromium/third_party/openscreen/src/util/weak_ptr.h index cb6967a1d59..c941017d511 100644 --- a/chromium/third_party/openscreen/src/util/weak_ptr.h +++ b/chromium/third_party/openscreen/src/util/weak_ptr.h @@ -6,6 +6,7 @@ #define UTIL_WEAK_PTR_H_ #include <memory> +#include <utility> #include "util/osp_logging.h" @@ -92,7 +93,7 @@ class WeakPtr { } // Create/Assign from nullptr. - WeakPtr(std::nullptr_t) {} + WeakPtr(std::nullptr_t) {} // NOLINT WeakPtr& operator=(std::nullptr_t) { impl_.reset(); |