From efe4329f9fe448eb17784d7a9b9e6e519ec4fa57 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 21 Dec 2022 16:07:14 +0000 Subject: [PATCH] AK: Add JsonValue::{is,as}_integer() methods The existing `is_i32()` and friends only check if `i32` is their internal type, but a value such as `0` could be literally any integer type internally. `is_integer()` instead determines whether the contained value is an integer and can fit inside T. --- AK/JsonValue.h | 36 ++++++++++++++++++++++++++ Tests/AK/TestJSON.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/AK/JsonValue.h b/AK/JsonValue.h index 905483ee23..f01e38d595 100644 --- a/AK/JsonValue.h +++ b/AK/JsonValue.h @@ -261,6 +261,42 @@ public: return default_value; } + template + bool is_integer() const + { + switch (m_type) { + case Type::Int32: + return is_within_range(m_value.as_i32); + case Type::UnsignedInt32: + return is_within_range(m_value.as_u32); + case Type::Int64: + return is_within_range(m_value.as_i64); + case Type::UnsignedInt64: + return is_within_range(m_value.as_u64); + default: + return false; + } + } + + template + T as_integer() const + { + VERIFY(is_integer()); + + switch (m_type) { + case Type::Int32: + return static_cast(m_value.as_i32); + case Type::UnsignedInt32: + return static_cast(m_value.as_u32); + case Type::Int64: + return static_cast(m_value.as_i64); + case Type::UnsignedInt64: + return static_cast(m_value.as_u64); + default: + VERIFY_NOT_REACHED(); + } + } + bool equals(JsonValue const& other) const; private: diff --git a/Tests/AK/TestJSON.cpp b/Tests/AK/TestJSON.cpp index a04c3bcf92..92453ead2f 100644 --- a/Tests/AK/TestJSON.cpp +++ b/Tests/AK/TestJSON.cpp @@ -371,3 +371,62 @@ TEST_CASE(fallible_json_array_for_each) EXPECT(result4.is_error()); EXPECT((IsSame)); } + +TEST_CASE(json_value_as_integer) +{ + // is_integer() should validate based on the value, not the underlying type. + JsonValue value_int { static_cast(42) }; + JsonValue value_unsigned { static_cast(42) }; + JsonValue value_long { static_cast(42) }; + JsonValue value_long_unsigned { static_cast(42) }; + JsonValue value_long_long { static_cast(42) }; + JsonValue value_long_long_unsigned { static_cast(42) }; + + auto check_is_valid_for_all_types = [](JsonValue& value) { + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + EXPECT(value.is_integer()); + EXPECT_EQ(value.as_integer(), static_cast(42)); + }; + + check_is_valid_for_all_types(value_int); + check_is_valid_for_all_types(value_unsigned); + check_is_valid_for_all_types(value_long); + check_is_valid_for_all_types(value_long_unsigned); + check_is_valid_for_all_types(value_long_long); + check_is_valid_for_all_types(value_long_long_unsigned); + + // Negative values should only fit in signed types. + JsonValue negative_value { -42 }; + EXPECT(!negative_value.is_integer()); + EXPECT(!negative_value.is_integer()); + EXPECT(!negative_value.is_integer()); + EXPECT(!negative_value.is_integer()); + EXPECT(negative_value.is_integer()); + EXPECT(negative_value.is_integer()); + EXPECT(negative_value.is_integer()); + EXPECT(negative_value.is_integer()); + + // 64-bit only + JsonValue very_large_value { INT64_MAX }; + EXPECT(!very_large_value.is_integer()); + EXPECT(!very_large_value.is_integer()); + EXPECT(!very_large_value.is_integer()); + EXPECT(very_large_value.is_integer()); + EXPECT(!very_large_value.is_integer()); + EXPECT(!very_large_value.is_integer()); + EXPECT(!very_large_value.is_integer()); + EXPECT(very_large_value.is_integer()); +}