diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/BUILD.gn | 67 | ||||
-rw-r--r-- | util/base64.cc | 16 | ||||
-rw-r--r-- | util/base64.h | 3 | ||||
-rw-r--r-- | util/base64_unittest.cc | 20 | ||||
-rw-r--r-- | util/json/json_helpers.h | 93 | ||||
-rw-r--r-- | util/json/json_helpers_unittest.cc | 121 | ||||
-rw-r--r-- | util/simple_fraction.cc | 31 | ||||
-rw-r--r-- | util/simple_fraction.h | 54 | ||||
-rw-r--r-- | util/stringprintf.cc | 6 | ||||
-rw-r--r-- | util/stringprintf.h | 10 | ||||
-rw-r--r-- | util/stringprintf_unittest.cc | 4 |
11 files changed, 202 insertions, 223 deletions
diff --git a/util/BUILD.gn b/util/BUILD.gn index 3f97e09e..90a7fe39 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -17,31 +17,14 @@ config("trace_logging_config") { } } -source_set("util") { +# The set of util classes which have no dependency on platform:api. +source_set("base") { sources = [ - "alarm.cc", - "alarm.h", "base64.cc", "base64.h", "big_endian.cc", "big_endian.h", "chrono_helpers.h", - "crypto/certificate_utils.cc", - "crypto/certificate_utils.h", - "crypto/digest_sign.cc", - "crypto/digest_sign.h", - "crypto/openssl_util.cc", - "crypto/openssl_util.h", - "crypto/pem_helpers.cc", - "crypto/pem_helpers.h", - "crypto/random_bytes.cc", - "crypto/random_bytes.h", - "crypto/rsa_private_key.cc", - "crypto/rsa_private_key.h", - "crypto/secure_hash.cc", - "crypto/secure_hash.h", - "crypto/sha2.cc", - "crypto/sha2.h", "enum_name_table.h", "flat_map.h", "hashing.h", @@ -59,10 +42,6 @@ source_set("util") { "std_util.h", "stringprintf.cc", "stringprintf.h", - "trace_logging.h", - "trace_logging/macro_support.h", - "trace_logging/scoped_trace_operations.cc", - "trace_logging/scoped_trace_operations.h", "url.cc", "url.h", "weak_ptr.h", @@ -71,14 +50,13 @@ source_set("util") { ] public_deps = [ - "../platform:api", "../platform:base", + "../platform:logging", "../third_party/abseil", "../third_party/jsoncpp", ] deps = [ - "../third_party/boringssl", "../third_party/mozilla", # We do a clone of Chrome's modp_b64 in order to share their BUILD.gn @@ -86,6 +64,45 @@ source_set("util") { "//third_party/modp_b64", ] + public_configs = [ "../build:openscreen_include_dirs" ] +} + +source_set("util") { + sources = [ + "alarm.cc", + "alarm.h", + "crypto/certificate_utils.cc", + "crypto/certificate_utils.h", + "crypto/digest_sign.cc", + "crypto/digest_sign.h", + "crypto/openssl_util.cc", + "crypto/openssl_util.h", + "crypto/pem_helpers.cc", + "crypto/pem_helpers.h", + "crypto/random_bytes.cc", + "crypto/random_bytes.h", + "crypto/rsa_private_key.cc", + "crypto/rsa_private_key.h", + "crypto/secure_hash.cc", + "crypto/secure_hash.h", + "crypto/sha2.cc", + "crypto/sha2.h", + "trace_logging.h", + "trace_logging/macro_support.h", + "trace_logging/scoped_trace_operations.cc", + "trace_logging/scoped_trace_operations.h", + ] + + public_deps = [ + ":base", + "../platform:api", + "../platform:base", + "../third_party/abseil", + "../third_party/jsoncpp", + ] + + deps = [ "../third_party/boringssl" ] + public_configs = [ "../build:openscreen_include_dirs", ":trace_logging_config", diff --git a/util/base64.cc b/util/base64.cc index 06e120e0..64e34175 100644 --- a/util/base64.cc +++ b/util/base64.cc @@ -6,6 +6,10 @@ #include <stddef.h> +#include <string> +#include <utility> +#include <vector> + #include "third_party/modp_b64/modp_b64.h" #include "util/osp_logging.h" #include "util/std_util.h" @@ -33,20 +37,18 @@ std::string Encode(absl::string_view input) { return out; } -bool Decode(absl::string_view input, std::string* output) { - std::string out; - out.resize(modp_b64_decode_len(input.size())); +bool Decode(absl::string_view input, std::vector<uint8_t>* output) { + std::vector<uint8_t> out(modp_b64_decode_len(input.size())); - // We don't null terminate the result since it is binary data. - const size_t output_size = - modp_b64_decode(data(out), input.data(), input.size()); + const size_t output_size = modp_b64_decode( + reinterpret_cast<char*>(out.data()), input.data(), input.size()); if (output_size == MODP_B64_ERROR) { return false; } // The output size from decode_len is generally larger than needed. out.resize(output_size); - output->swap(out); + *output = std::move(out); return true; } diff --git a/util/base64.h b/util/base64.h index b24c3b3f..a7af9eca 100644 --- a/util/base64.h +++ b/util/base64.h @@ -6,6 +6,7 @@ #define UTIL_BASE64_H_ #include <string> +#include <vector> #include "absl/strings/string_view.h" #include "absl/types/span.h" @@ -23,7 +24,7 @@ std::string Encode(absl::string_view input); // Decodes the base64 input string. Returns true if successful and false // otherwise. The output string is only modified if successful. The decoding can // be done in-place. -bool Decode(absl::string_view input, std::string* output); +bool Decode(absl::string_view input, std::vector<uint8_t>* output); } // namespace base64 } // namespace openscreen diff --git a/util/base64_unittest.cc b/util/base64_unittest.cc index 28d4fb1d..873b5656 100644 --- a/util/base64_unittest.cc +++ b/util/base64_unittest.cc @@ -4,6 +4,9 @@ #include "util/base64.h" +#include <string> +#include <vector> + #include "gtest/gtest.h" namespace openscreen { @@ -14,13 +17,21 @@ namespace { constexpr char kText[] = "hello world"; constexpr char kBase64Text[] = "aGVsbG8gd29ybGQ="; +// More sophisticated comparisons here, such as EXPECT_STREQ, may +// cause memory failures on some platforms (e.g. ASAN) due to mismatched +// lengths. +void CheckEquals(const char* expected, const std::vector<uint8_t>& actual) { + EXPECT_EQ(0, std::memcmp(actual.data(), expected, actual.size())); +} + void CheckEncodeDecode(const char* to_encode, const char* encode_expected) { std::string encoded = Encode(to_encode); EXPECT_EQ(encode_expected, encoded); - std::string decoded; + std::vector<uint8_t> decoded; EXPECT_TRUE(Decode(encoded, &decoded)); - EXPECT_EQ(to_encode, decoded); + + CheckEquals(to_encode, decoded); } } // namespace @@ -52,8 +63,9 @@ TEST(Base64Test, InPlace) { text = Encode(text); EXPECT_EQ(kBase64Text, text); - EXPECT_TRUE(Decode(text, &text)); - EXPECT_EQ(text, kText); + std::vector<uint8_t> out; + EXPECT_TRUE(Decode(text, &out)); + CheckEquals(kText, out); } } // namespace base64 diff --git a/util/json/json_helpers.h b/util/json/json_helpers.h index 1943973d..ebd25add 100644 --- a/util/json/json_helpers.h +++ b/util/json/json_helpers.h @@ -16,6 +16,7 @@ #include "json/value.h" #include "platform/base/error.h" #include "util/chrono_helpers.h" +#include "util/json/json_serialization.h" #include "util/simple_fraction.h" // This file contains helper methods for parsing JSON, in an attempt to @@ -23,53 +24,7 @@ namespace openscreen { namespace json { -// TODO(jophba): remove these methods after refactoring offer messaging. -inline Error CreateParseError(const std::string& type) { - return Error(Error::Code::kJsonParseError, "Failed to parse " + type); -} - -inline Error CreateParameterError(const std::string& type) { - return Error(Error::Code::kParameterInvalid, "Invalid parameter: " + type); -} - -inline ErrorOr<bool> ParseBool(const Json::Value& parent, - const std::string& field) { - const Json::Value& value = parent[field]; - if (!value.isBool()) { - return CreateParseError("bool field " + field); - } - return value.asBool(); -} - -inline ErrorOr<int> ParseInt(const Json::Value& parent, - const std::string& field) { - const Json::Value& value = parent[field]; - if (!value.isInt()) { - return CreateParseError("integer field: " + field); - } - return value.asInt(); -} - -inline ErrorOr<uint32_t> ParseUint(const Json::Value& parent, - const std::string& field) { - const Json::Value& value = parent[field]; - if (!value.isUInt()) { - return CreateParseError("unsigned integer field: " + field); - } - return value.asUInt(); -} - -inline ErrorOr<std::string> ParseString(const Json::Value& parent, - const std::string& field) { - const Json::Value& value = parent[field]; - if (!value.isString()) { - return CreateParseError("string field: " + field); - } - return value.asString(); -} - -// TODO(jophba): offer messaging should use these methods instead. -inline bool ParseBool(const Json::Value& value, bool* out) { +inline bool TryParseBool(const Json::Value& value, bool* out) { if (!value.isBool()) { return false; } @@ -80,9 +35,9 @@ inline bool ParseBool(const Json::Value& value, bool* out) { // A general note about parsing primitives. "Validation" in this context // generally means ensuring that the values are non-negative, excepting doubles // which may be negative in some cases. -inline bool ParseAndValidateDouble(const Json::Value& value, - double* out, - bool allow_negative = false) { +inline bool TryParseDouble(const Json::Value& value, + double* out, + bool allow_negative = false) { if (!value.isDouble()) { return false; } @@ -97,7 +52,7 @@ inline bool ParseAndValidateDouble(const Json::Value& value, return true; } -inline bool ParseAndValidateInt(const Json::Value& value, int* out) { +inline bool TryParseInt(const Json::Value& value, int* out) { if (!value.isInt()) { return false; } @@ -109,7 +64,7 @@ inline bool ParseAndValidateInt(const Json::Value& value, int* out) { return true; } -inline bool ParseAndValidateUint(const Json::Value& value, uint32_t* out) { +inline bool TryParseUint(const Json::Value& value, uint32_t* out) { if (!value.isUInt()) { return false; } @@ -117,7 +72,7 @@ inline bool ParseAndValidateUint(const Json::Value& value, uint32_t* out) { return true; } -inline bool ParseAndValidateString(const Json::Value& value, std::string* out) { +inline bool TryParseString(const Json::Value& value, std::string* out) { if (!value.isString()) { return false; } @@ -128,8 +83,8 @@ inline bool ParseAndValidateString(const Json::Value& value, std::string* out) { // We want to be more robust when we parse fractions then just // allowing strings, this will parse numeral values such as // value: 50 as well as value: "50" and value: "100/2". -inline bool ParseAndValidateSimpleFraction(const Json::Value& value, - SimpleFraction* out) { +inline bool TryParseSimpleFraction(const Json::Value& value, + SimpleFraction* out) { if (value.isInt()) { int parsed = value.asInt(); if (parsed < 0) { @@ -155,10 +110,9 @@ inline bool ParseAndValidateSimpleFraction(const Json::Value& value, return false; } -inline bool ParseAndValidateMilliseconds(const Json::Value& value, - milliseconds* out) { +inline bool TryParseMilliseconds(const Json::Value& value, milliseconds* out) { int out_ms; - if (!ParseAndValidateInt(value, &out_ms) || out_ms < 0) { + if (!TryParseInt(value, &out_ms) || out_ms < 0) { return false; } *out = milliseconds(out_ms); @@ -171,9 +125,9 @@ using Parser = std::function<bool(const Json::Value&, T*)>; // NOTE: array parsing methods reset the output vector to an empty vector in // any error case. This is especially useful for optional arrays. template <typename T> -bool ParseAndValidateArray(const Json::Value& value, - Parser<T> parser, - std::vector<T>* out) { +bool TryParseArray(const Json::Value& value, + Parser<T> parser, + std::vector<T>* out) { out->clear(); if (!value.isArray() || value.empty()) { return false; @@ -192,19 +146,18 @@ bool ParseAndValidateArray(const Json::Value& value, return true; } -inline bool ParseAndValidateIntArray(const Json::Value& value, - std::vector<int>* out) { - return ParseAndValidateArray<int>(value, ParseAndValidateInt, out); +inline bool TryParseIntArray(const Json::Value& value, std::vector<int>* out) { + return TryParseArray<int>(value, TryParseInt, out); } -inline bool ParseAndValidateUintArray(const Json::Value& value, - std::vector<uint32_t>* out) { - return ParseAndValidateArray<uint32_t>(value, ParseAndValidateUint, out); +inline bool TryParseUintArray(const Json::Value& value, + std::vector<uint32_t>* out) { + return TryParseArray<uint32_t>(value, TryParseUint, out); } -inline bool ParseAndValidateStringArray(const Json::Value& value, - std::vector<std::string>* out) { - return ParseAndValidateArray<std::string>(value, ParseAndValidateString, out); +inline bool TryParseStringArray(const Json::Value& value, + std::vector<std::string>* out) { + return TryParseArray<std::string>(value, TryParseString, out); } } // namespace json diff --git a/util/json/json_helpers_unittest.cc b/util/json/json_helpers_unittest.cc index c461cf93..eb05d3f6 100644 --- a/util/json/json_helpers_unittest.cc +++ b/util/json/json_helpers_unittest.cc @@ -26,9 +26,9 @@ struct Dummy { } }; -bool ParseAndValidateDummy(const Json::Value& value, Dummy* out) { +bool TryParseDummy(const Json::Value& value, Dummy* out) { int value_out; - if (!ParseAndValidateInt(value, &value_out)) { + if (!TryParseInt(value, &value_out)) { return false; } *out = Dummy{value_out}; @@ -37,7 +37,7 @@ bool ParseAndValidateDummy(const Json::Value& value, Dummy* out) { } // namespace -TEST(ParsingHelpersTest, ParseAndValidateDouble) { +TEST(ParsingHelpersTest, TryParseDouble) { const Json::Value kValid = 13.37; const Json::Value kNotDouble = "coffee beans"; const Json::Value kNegativeDouble = -4.2; @@ -45,62 +45,62 @@ TEST(ParsingHelpersTest, ParseAndValidateDouble) { const Json::Value kNanDouble = std::nan(""); double out; - EXPECT_TRUE(ParseAndValidateDouble(kValid, &out)); + EXPECT_TRUE(TryParseDouble(kValid, &out)); EXPECT_DOUBLE_EQ(13.37, out); - EXPECT_TRUE(ParseAndValidateDouble(kZeroDouble, &out)); + EXPECT_TRUE(TryParseDouble(kZeroDouble, &out)); EXPECT_DOUBLE_EQ(0.0, out); - EXPECT_FALSE(ParseAndValidateDouble(kNotDouble, &out)); - EXPECT_FALSE(ParseAndValidateDouble(kNegativeDouble, &out)); - EXPECT_FALSE(ParseAndValidateDouble(kNone, &out)); - EXPECT_FALSE(ParseAndValidateDouble(kNanDouble, &out)); + EXPECT_FALSE(TryParseDouble(kNotDouble, &out)); + EXPECT_FALSE(TryParseDouble(kNegativeDouble, &out)); + EXPECT_FALSE(TryParseDouble(kNone, &out)); + EXPECT_FALSE(TryParseDouble(kNanDouble, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateInt) { +TEST(ParsingHelpersTest, TryParseInt) { const Json::Value kValid = 1337; const Json::Value kNotInt = "cold brew"; const Json::Value kNegativeInt = -42; const Json::Value kZeroInt = 0; int out; - EXPECT_TRUE(ParseAndValidateInt(kValid, &out)); + EXPECT_TRUE(TryParseInt(kValid, &out)); EXPECT_EQ(1337, out); - EXPECT_TRUE(ParseAndValidateInt(kZeroInt, &out)); + EXPECT_TRUE(TryParseInt(kZeroInt, &out)); EXPECT_EQ(0, out); - EXPECT_FALSE(ParseAndValidateInt(kNone, &out)); - EXPECT_FALSE(ParseAndValidateInt(kNotInt, &out)); - EXPECT_FALSE(ParseAndValidateInt(kNegativeInt, &out)); + EXPECT_FALSE(TryParseInt(kNone, &out)); + EXPECT_FALSE(TryParseInt(kNotInt, &out)); + EXPECT_FALSE(TryParseInt(kNegativeInt, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateUint) { +TEST(ParsingHelpersTest, TryParseUint) { const Json::Value kValid = 1337u; const Json::Value kNotUint = "espresso"; const Json::Value kZeroUint = 0u; uint32_t out; - EXPECT_TRUE(ParseAndValidateUint(kValid, &out)); + EXPECT_TRUE(TryParseUint(kValid, &out)); EXPECT_EQ(1337u, out); - EXPECT_TRUE(ParseAndValidateUint(kZeroUint, &out)); + EXPECT_TRUE(TryParseUint(kZeroUint, &out)); EXPECT_EQ(0u, out); - EXPECT_FALSE(ParseAndValidateUint(kNone, &out)); - EXPECT_FALSE(ParseAndValidateUint(kNotUint, &out)); + EXPECT_FALSE(TryParseUint(kNone, &out)); + EXPECT_FALSE(TryParseUint(kNotUint, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateString) { +TEST(ParsingHelpersTest, TryParseString) { const Json::Value kValid = "macchiato"; const Json::Value kNotString = 42; std::string out; - EXPECT_TRUE(ParseAndValidateString(kValid, &out)); + EXPECT_TRUE(TryParseString(kValid, &out)); EXPECT_EQ("macchiato", out); - EXPECT_TRUE(ParseAndValidateString(kEmptyString, &out)); + EXPECT_TRUE(TryParseString(kEmptyString, &out)); EXPECT_EQ("", out); - EXPECT_FALSE(ParseAndValidateString(kNone, &out)); - EXPECT_FALSE(ParseAndValidateString(kNotString, &out)); + EXPECT_FALSE(TryParseString(kNone, &out)); + EXPECT_FALSE(TryParseString(kNotString, &out)); } // Simple fraction validity is tested extensively in its unit tests, so we // just check the major cases here. -TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) { +TEST(ParsingHelpersTest, TryParseSimpleFraction) { const Json::Value kValid = "42/30"; const Json::Value kValidNumber = "42"; const Json::Value kUndefined = "5/0"; @@ -111,22 +111,22 @@ TEST(ParsingHelpersTest, ParseAndValidateSimpleFraction) { const Json::Value kNegativeInteger = -5000; SimpleFraction out; - EXPECT_TRUE(ParseAndValidateSimpleFraction(kValid, &out)); + EXPECT_TRUE(TryParseSimpleFraction(kValid, &out)); EXPECT_EQ((SimpleFraction{42, 30}), out); - EXPECT_TRUE(ParseAndValidateSimpleFraction(kValidNumber, &out)); + EXPECT_TRUE(TryParseSimpleFraction(kValidNumber, &out)); EXPECT_EQ((SimpleFraction{42, 1}), out); - EXPECT_TRUE(ParseAndValidateSimpleFraction(kInteger, &out)); + EXPECT_TRUE(TryParseSimpleFraction(kInteger, &out)); EXPECT_EQ((SimpleFraction{123, 1}), out); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kUndefined, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegative, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kInvalidNumber, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kNotSimpleFraction, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kNone, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kEmptyString, &out)); - EXPECT_FALSE(ParseAndValidateSimpleFraction(kNegativeInteger, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kUndefined, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kNegative, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kInvalidNumber, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kNotSimpleFraction, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kNone, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kEmptyString, &out)); + EXPECT_FALSE(TryParseSimpleFraction(kNegativeInteger, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) { +TEST(ParsingHelpersTest, TryParseMilliseconds) { const Json::Value kValid = 1000; const Json::Value kValidFloat = 500.0; const Json::Value kNegativeNumber = -120; @@ -134,18 +134,18 @@ TEST(ParsingHelpersTest, ParseAndValidateMilliseconds) { const Json::Value kNotNumber = "affogato"; milliseconds out; - EXPECT_TRUE(ParseAndValidateMilliseconds(kValid, &out)); + EXPECT_TRUE(TryParseMilliseconds(kValid, &out)); EXPECT_EQ(milliseconds(1000), out); - EXPECT_TRUE(ParseAndValidateMilliseconds(kValidFloat, &out)); + EXPECT_TRUE(TryParseMilliseconds(kValidFloat, &out)); EXPECT_EQ(milliseconds(500), out); - EXPECT_TRUE(ParseAndValidateMilliseconds(kZeroNumber, &out)); + EXPECT_TRUE(TryParseMilliseconds(kZeroNumber, &out)); EXPECT_EQ(milliseconds(0), out); - EXPECT_FALSE(ParseAndValidateMilliseconds(kNone, &out)); - EXPECT_FALSE(ParseAndValidateMilliseconds(kNegativeNumber, &out)); - EXPECT_FALSE(ParseAndValidateMilliseconds(kNotNumber, &out)); + EXPECT_FALSE(TryParseMilliseconds(kNone, &out)); + EXPECT_FALSE(TryParseMilliseconds(kNegativeNumber, &out)); + EXPECT_FALSE(TryParseMilliseconds(kNotNumber, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateArray) { +TEST(ParsingHelpersTest, TryParseArray) { Json::Value valid_dummy_array; valid_dummy_array[0] = 123; valid_dummy_array[1] = 456; @@ -155,16 +155,13 @@ TEST(ParsingHelpersTest, ParseAndValidateArray) { invalid_dummy_array[1] = 456; std::vector<Dummy> out; - EXPECT_TRUE(ParseAndValidateArray<Dummy>(valid_dummy_array, - ParseAndValidateDummy, &out)); + EXPECT_TRUE(TryParseArray<Dummy>(valid_dummy_array, TryParseDummy, &out)); EXPECT_THAT(out, ElementsAre(Dummy{123}, Dummy{456})); - EXPECT_FALSE(ParseAndValidateArray<Dummy>(invalid_dummy_array, - ParseAndValidateDummy, &out)); - EXPECT_FALSE( - ParseAndValidateArray<Dummy>(kEmptyArray, ParseAndValidateDummy, &out)); + EXPECT_FALSE(TryParseArray<Dummy>(invalid_dummy_array, TryParseDummy, &out)); + EXPECT_FALSE(TryParseArray<Dummy>(kEmptyArray, TryParseDummy, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateIntArray) { +TEST(ParsingHelpersTest, TryParseIntArray) { Json::Value valid_int_array; valid_int_array[0] = 123; valid_int_array[1] = 456; @@ -174,13 +171,13 @@ TEST(ParsingHelpersTest, ParseAndValidateIntArray) { invalid_int_array[1] = 456; std::vector<int> out; - EXPECT_TRUE(ParseAndValidateIntArray(valid_int_array, &out)); + EXPECT_TRUE(TryParseIntArray(valid_int_array, &out)); EXPECT_THAT(out, ElementsAre(123, 456)); - EXPECT_FALSE(ParseAndValidateIntArray(invalid_int_array, &out)); - EXPECT_FALSE(ParseAndValidateIntArray(kEmptyArray, &out)); + EXPECT_FALSE(TryParseIntArray(invalid_int_array, &out)); + EXPECT_FALSE(TryParseIntArray(kEmptyArray, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateUintArray) { +TEST(ParsingHelpersTest, TryParseUintArray) { Json::Value valid_uint_array; valid_uint_array[0] = 123u; valid_uint_array[1] = 456u; @@ -190,13 +187,13 @@ TEST(ParsingHelpersTest, ParseAndValidateUintArray) { invalid_uint_array[1] = 456u; std::vector<uint32_t> out; - EXPECT_TRUE(ParseAndValidateUintArray(valid_uint_array, &out)); + EXPECT_TRUE(TryParseUintArray(valid_uint_array, &out)); EXPECT_THAT(out, ElementsAre(123u, 456u)); - EXPECT_FALSE(ParseAndValidateUintArray(invalid_uint_array, &out)); - EXPECT_FALSE(ParseAndValidateUintArray(kEmptyArray, &out)); + EXPECT_FALSE(TryParseUintArray(invalid_uint_array, &out)); + EXPECT_FALSE(TryParseUintArray(kEmptyArray, &out)); } -TEST(ParsingHelpersTest, ParseAndValidateStringArray) { +TEST(ParsingHelpersTest, TryParseStringArray) { Json::Value valid_string_array; valid_string_array[0] = "nitro cold brew"; valid_string_array[1] = "doppio espresso"; @@ -206,10 +203,10 @@ TEST(ParsingHelpersTest, ParseAndValidateStringArray) { invalid_string_array[1] = 456; std::vector<std::string> out; - EXPECT_TRUE(ParseAndValidateStringArray(valid_string_array, &out)); + EXPECT_TRUE(TryParseStringArray(valid_string_array, &out)); EXPECT_THAT(out, ElementsAre("nitro cold brew", "doppio espresso")); - EXPECT_FALSE(ParseAndValidateStringArray(invalid_string_array, &out)); - EXPECT_FALSE(ParseAndValidateStringArray(kEmptyArray, &out)); + EXPECT_FALSE(TryParseStringArray(invalid_string_array, &out)); + EXPECT_FALSE(TryParseStringArray(kEmptyArray, &out)); } } // namespace json diff --git a/util/simple_fraction.cc b/util/simple_fraction.cc index a98d825c..46d2e585 100644 --- a/util/simple_fraction.cc +++ b/util/simple_fraction.cc @@ -33,37 +33,14 @@ ErrorOr<SimpleFraction> SimpleFraction::FromString(absl::string_view value) { } } - return SimpleFraction{numerator, denominator}; + return SimpleFraction(numerator, denominator); } std::string SimpleFraction::ToString() const { - if (denominator == 1) { - return std::to_string(numerator); + if (denominator_ == 1) { + return std::to_string(numerator_); } - return absl::StrCat(numerator, "/", denominator); -} - -bool SimpleFraction::operator==(const SimpleFraction& other) const { - return numerator == other.numerator && denominator == other.denominator; -} - -bool SimpleFraction::operator!=(const SimpleFraction& other) const { - return !(*this == other); -} - -bool SimpleFraction::is_defined() const { - return denominator != 0; -} - -bool SimpleFraction::is_positive() const { - return is_defined() && (numerator >= 0) && (denominator > 0); -} - -SimpleFraction::operator double() const { - if (denominator == 0) { - return nan(""); - } - return static_cast<double>(numerator) / static_cast<double>(denominator); + return absl::StrCat(numerator_, "/", denominator_); } } // namespace openscreen diff --git a/util/simple_fraction.h b/util/simple_fraction.h index f8ab5083..2df45e24 100644 --- a/util/simple_fraction.h +++ b/util/simple_fraction.h @@ -5,6 +5,8 @@ #ifndef UTIL_SIMPLE_FRACTION_H_ #define UTIL_SIMPLE_FRACTION_H_ +#include <cmath> +#include <limits> #include <string> #include "absl/strings/string_view.h" @@ -14,30 +16,56 @@ namespace openscreen { // SimpleFraction is used to represent simple (or "common") fractions, composed // of a rational number written a/b where a and b are both integers. - -// Note: Since SimpleFraction is a trivial type, it comes with a -// default constructor and is copyable, as well as allowing static -// initialization. - // Some helpful notes on SimpleFraction assumptions/limitations: // 1. SimpleFraction does not perform reductions. 2/4 != 1/2, and -1/-1 != 1/1. // 2. denominator = 0 is considered undefined. // 3. numerator = saturates range to int min or int max // 4. A SimpleFraction is "positive" if and only if it is defined and at least // equal to zero. Since reductions are not performed, -1/-1 is negative. -struct SimpleFraction { +class SimpleFraction { + public: static ErrorOr<SimpleFraction> FromString(absl::string_view value); std::string ToString() const; - bool operator==(const SimpleFraction& other) const; - bool operator!=(const SimpleFraction& other) const; + constexpr SimpleFraction() = default; + constexpr SimpleFraction(int numerator) // NOLINT + : numerator_(numerator) {} + constexpr SimpleFraction(int numerator, int denominator) + : numerator_(numerator), denominator_(denominator) {} + + constexpr SimpleFraction(const SimpleFraction&) = default; + constexpr SimpleFraction(SimpleFraction&&) noexcept = default; + constexpr SimpleFraction& operator=(const SimpleFraction&) = default; + constexpr SimpleFraction& operator=(SimpleFraction&&) = default; + ~SimpleFraction() = default; + + constexpr bool operator==(const SimpleFraction& other) const { + return numerator_ == other.numerator_ && denominator_ == other.denominator_; + } + + constexpr bool operator!=(const SimpleFraction& other) const { + return !(*this == other); + } + + constexpr bool is_defined() const { return denominator_ != 0; } + + constexpr bool is_positive() const { + return (numerator_ >= 0) && (denominator_ > 0); + } + + constexpr explicit operator double() const { + if (denominator_ == 0) { + return nan(""); + } + return static_cast<double>(numerator_) / static_cast<double>(denominator_); + } - bool is_defined() const; - bool is_positive() const; - explicit operator double() const; + constexpr int numerator() const { return numerator_; } + constexpr int denominator() const { return denominator_; } - int numerator = 0; - int denominator = 0; + private: + int numerator_ = 0; + int denominator_ = 1; }; } // namespace openscreen diff --git a/util/stringprintf.cc b/util/stringprintf.cc index 2d9bba22..49c29dc8 100644 --- a/util/stringprintf.cc +++ b/util/stringprintf.cc @@ -32,11 +32,11 @@ std::string StringPrintf(const char* format, ...) { return result; } -std::string HexEncode(absl::Span<const uint8_t> bytes) { +std::string HexEncode(const uint8_t* bytes, std::size_t len) { std::ostringstream hex_dump; hex_dump << std::setfill('0') << std::hex; - for (const uint8_t byte : bytes) { - hex_dump << std::setw(2) << static_cast<int>(byte); + for (std::size_t i = 0; i < len; i++) { + hex_dump << std::setw(2) << static_cast<int>(bytes[i]); } return hex_dump.str(); } diff --git a/util/stringprintf.h b/util/stringprintf.h index 0de394ea..23f07fea 100644 --- a/util/stringprintf.h +++ b/util/stringprintf.h @@ -10,12 +10,6 @@ #include <ostream> #include <string> -// TODO: This header is included in the openscreen discovery public headers (dns_sd_instance.h), -// which exposes this abseil header. Need to figure out a way to hide it. -#if 0 -#include "absl/types/span.h" -#endif - namespace openscreen { // Enable compile-time checking of the printf format argument, if available. @@ -58,10 +52,8 @@ void PrettyPrintAsciiHex(std::ostream& os, It first, It last) { } } -#if 0 // Returns a hex string representation of the given |bytes|. -std::string HexEncode(absl::Span<const uint8_t> bytes); -#endif +std::string HexEncode(const uint8_t* bytes, std::size_t len); } // namespace openscreen diff --git a/util/stringprintf_unittest.cc b/util/stringprintf_unittest.cc index e37e7cb6..bf882163 100644 --- a/util/stringprintf_unittest.cc +++ b/util/stringprintf_unittest.cc @@ -20,13 +20,13 @@ TEST(StringPrintf, ProducesFormattedStrings) { TEST(HexEncode, ProducesEmptyStringFromEmptyByteArray) { const uint8_t kSomeMemoryLocation = 0; - EXPECT_EQ("", HexEncode(absl::Span<const uint8_t>(&kSomeMemoryLocation, 0))); + EXPECT_EQ("", HexEncode(&kSomeMemoryLocation, 0)); } TEST(HexEncode, ProducesHexStringsFromBytes) { const uint8_t kMessage[] = "Hello world!"; const char kMessageInHex[] = "48656c6c6f20776f726c642100"; - EXPECT_EQ(kMessageInHex, HexEncode(kMessage)); + EXPECT_EQ(kMessageInHex, HexEncode(kMessage, sizeof(kMessage))); } } // namespace |