| /* |
| * Copyright (C) 2020 Sony Interactive Entertainment Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include <WebCore/KeyedCoding.h> |
| #include <WebCore/SharedBuffer.h> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <wtf/text/WTFString.h> |
| |
| namespace TestWebKitAPI { |
| |
| static bool checkDecodedBytes(const uint8_t* original, size_t originalSize, const uint8_t* decoded, size_t decodedSize) |
| { |
| if (originalSize != decodedSize) |
| return false; |
| |
| return !std::memcmp(original, decoded, originalSize); |
| } |
| |
| TEST(KeyedCoding, SetAndGetBytes) |
| { |
| const uint8_t data[] = { 0x00, 0x01, 0x02, 0x03, 0xde, 0xad, 0xbe, 0xef }; |
| const size_t dataLength = WTF_ARRAY_LENGTH(data); |
| const size_t dataLengthOne = 1; |
| const size_t dataLengthZero = 0; |
| |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| encoder->encodeBytes("data"_s, data, dataLength); |
| encoder->encodeBytes("data-size0"_s, data, dataLengthZero); |
| encoder->encodeBytes("data-size1"_s, data, dataLengthOne); |
| auto encodedBuffer = encoder->finishEncoding(); |
| |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| |
| bool success; |
| const uint8_t* buffer; |
| size_t size; |
| |
| success = decoder->decodeBytes("data"_s, buffer, size); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(dataLength, size); |
| EXPECT_TRUE(checkDecodedBytes(data, dataLength, buffer, size)); |
| |
| success = decoder->decodeBytes("data-size0"_s, buffer, size); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(dataLengthZero, size); |
| |
| success = decoder->decodeBytes("data-size1"_s, buffer, size); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(dataLengthOne, size); |
| EXPECT_TRUE(checkDecodedBytes(data, dataLengthOne, buffer, size)); |
| } |
| |
| template <typename EncodeFunctionType, typename DecodeValueType, typename EncodeValueType> |
| bool testSimpleValue(EncodeFunctionType encode, bool (WebCore::KeyedDecoder::* decode)(const String&, DecodeValueType&), EncodeValueType value) |
| { |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| (encoder.get()->*encode)("key"_s, value); |
| |
| auto encodedBuffer = encoder->finishEncoding(); |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| |
| DecodeValueType decodedValue; |
| bool success = (decoder.get()->*decode)("key"_s, decodedValue); |
| |
| return success && decodedValue == value; |
| } |
| |
| TEST(KeyedCoding, SetAndGetBool) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeBool, &WebCore::KeyedDecoder::decodeBool, true)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeBool, &WebCore::KeyedDecoder::decodeBool, false)); |
| } |
| |
| TEST(KeyedCoding, SetAndGetInt32) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt32, &WebCore::KeyedDecoder::decodeInt32, 0)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt32, &WebCore::KeyedDecoder::decodeInt32, 1)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt32, &WebCore::KeyedDecoder::decodeInt32, -1)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt32, &WebCore::KeyedDecoder::decodeInt32, INT_MIN)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt32, &WebCore::KeyedDecoder::decodeInt32, INT_MAX)); |
| } |
| |
| TEST(KeyedCoding, SetAndGetUInt32) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt32, &WebCore::KeyedDecoder::decodeUInt32, uint32_t(0))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt32, &WebCore::KeyedDecoder::decodeUInt32, uint32_t(1))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt32, &WebCore::KeyedDecoder::decodeUInt32, UINT32_MAX)); |
| } |
| |
| TEST(KeyedCoding, SetAndGetInt64) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt64, &WebCore::KeyedDecoder::decodeInt64, int64_t(0))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt64, &WebCore::KeyedDecoder::decodeInt64, int64_t(-2))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt64, &WebCore::KeyedDecoder::decodeInt64, int64_t(2))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt64, &WebCore::KeyedDecoder::decodeInt64, INT64_MIN)); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeInt64, &WebCore::KeyedDecoder::decodeInt64, INT64_MAX)); |
| } |
| |
| TEST(KeyedCoding, SetAndGetUInt64) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt64, &WebCore::KeyedDecoder::decodeUInt64, uint64_t(0))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt64, &WebCore::KeyedDecoder::decodeUInt64, uint64_t(1))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeUInt64, &WebCore::KeyedDecoder::decodeUInt64, UINT64_MAX)); |
| } |
| |
| TEST(KeyedCoding, SetAndGetFloat) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, float(0))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, float(1.5))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, float(-1.5))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, std::numeric_limits<float>::lowest())); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, std::numeric_limits<float>::min())); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeFloat, &WebCore::KeyedDecoder::decodeFloat, std::numeric_limits<float>::max())); |
| } |
| |
| TEST(KeyedCoding, SetAndGetDouble) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, double(0))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, double(1.25))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, double(-1.25))); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, std::numeric_limits<double>::lowest())); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, std::numeric_limits<double>::min())); |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeDouble, &WebCore::KeyedDecoder::decodeDouble, std::numeric_limits<double>::max())); |
| } |
| |
| TEST(KeyedCoding, SetAndGetString) |
| { |
| EXPECT_TRUE(testSimpleValue(&WebCore::KeyedEncoder::encodeString, &WebCore::KeyedDecoder::decodeString, String("WebKit"_s))); |
| } |
| |
| TEST(KeyedCoding, GetNonExistingRecord) |
| { |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| encoder->encodeBool("bool-true"_s, true); |
| |
| auto encodedBuffer = encoder->finishEncoding(); |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| |
| bool success, boolValue; |
| success = decoder->decodeBool("bool-true"_s, boolValue); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(true, boolValue); |
| |
| success = decoder->decodeBool("no-exist-key"_s, boolValue); |
| EXPECT_FALSE(success); |
| |
| int32_t int32Value; |
| success = decoder->decodeInt32("no-exist-key"_s, int32Value); |
| EXPECT_FALSE(success); |
| |
| uint32_t uint32Value; |
| success = decoder->decodeUInt32("no-exist-key"_s, uint32Value); |
| EXPECT_FALSE(success); |
| |
| int64_t int64Value; |
| success = decoder->decodeInt64("no-exist-key"_s, int64Value); |
| EXPECT_FALSE(success); |
| |
| uint64_t uint64Value; |
| success = decoder->decodeUInt64("no-exist-key"_s, uint64Value); |
| EXPECT_FALSE(success); |
| |
| float floatValue; |
| success = decoder->decodeFloat("no-exist-key"_s, floatValue); |
| EXPECT_FALSE(success); |
| |
| double doubleValue; |
| success = decoder->decodeDouble("no-exist-key"_s, doubleValue); |
| EXPECT_FALSE(success); |
| |
| const uint8_t* buffer; |
| size_t size; |
| success = decoder->decodeBytes("no-exist-key"_s, buffer, size); |
| EXPECT_FALSE(success); |
| } |
| |
| struct KeyedCodingTestObject { |
| static void encode(WebCore::KeyedEncoder& encoder, const KeyedCodingTestObject& object) |
| { |
| encoder.encodeString("name"_s, object.m_name); |
| encoder.encodeInt32("age"_s, object.m_age); |
| } |
| |
| static bool decode(WebCore::KeyedDecoder& decoder, KeyedCodingTestObject& object) |
| { |
| if (!decoder.decodeString("name"_s, object.m_name)) |
| return false; |
| if (!decoder.decodeInt32("age"_s, object.m_age)) |
| return false; |
| return true; |
| } |
| |
| KeyedCodingTestObject() { }; |
| KeyedCodingTestObject(String name, int age) |
| : m_name(name) |
| , m_age(age) |
| { |
| } |
| |
| bool equals(const KeyedCodingTestObject& other) const |
| { |
| return (m_name == other.m_name) && (m_age == other.m_age); |
| } |
| |
| String m_name; |
| int32_t m_age; |
| }; |
| |
| static bool operator==(const KeyedCodingTestObject& lObject, const KeyedCodingTestObject& rObject) |
| { |
| return lObject.equals(rObject); |
| } |
| |
| TEST(KeyedCoding, SetAndGetObject) |
| { |
| const KeyedCodingTestObject user0("Noah"_s, 28); |
| const KeyedCodingTestObject user1("Emma"_s, 31); |
| |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| encoder->encodeObject("user0"_s, user0, KeyedCodingTestObject::encode); |
| encoder->encodeObject("user1"_s, user1, KeyedCodingTestObject::encode); |
| auto encodedBuffer = encoder->finishEncoding(); |
| |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| bool success; |
| KeyedCodingTestObject decodedUser0, decodedUser1; |
| |
| success = decoder->decodeObject("user0"_s, decodedUser0, KeyedCodingTestObject::decode); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(decodedUser0, user0); |
| |
| success = decoder->decodeObject("user1"_s, decodedUser1, KeyedCodingTestObject::decode); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(decodedUser1, user1); |
| } |
| |
| TEST(KeyedCoding, SetAndGetObjects) |
| { |
| Vector<KeyedCodingTestObject> users; |
| for (int i = 0; i < 10; i++) |
| users.append(KeyedCodingTestObject("username"_s, i)); |
| |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| encoder->encodeObjects("users"_s, users.begin(), users.end(), KeyedCodingTestObject::encode); |
| auto encodedBuffer = encoder->finishEncoding(); |
| |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| Vector<KeyedCodingTestObject> decodedUsers; |
| |
| bool success = decoder->decodeObjects("users"_s, decodedUsers, KeyedCodingTestObject::decode); |
| EXPECT_TRUE(success); |
| EXPECT_EQ(users, decodedUsers); |
| } |
| |
| TEST(KeyedCoding, SetAndGetWithEmptyKey) |
| { |
| auto encoder = WebCore::KeyedEncoder::encoder(); |
| encoder->encodeBool(emptyString(), false); |
| |
| auto encodedBuffer = encoder->finishEncoding(); |
| auto decoder = WebCore::KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(encodedBuffer->data()), encodedBuffer->size()); |
| |
| bool success, boolValue; |
| success = decoder->decodeBool(emptyString(), boolValue); |
| |
| EXPECT_TRUE(success); |
| EXPECT_EQ(false, boolValue); |
| } |
| |
| static Vector<uint8_t> generateRandomData() |
| { |
| Vector<uint8_t> data; |
| for (auto i = 0; i < 256; ++i) |
| data.append(std::rand() / (RAND_MAX + 1.0) * std::numeric_limits<uint8_t>::max()); |
| return data; |
| } |
| |
| TEST(KeyedCoding, DecodeRandomData) |
| { |
| std::srand(0); |
| for (auto i = 0; i < 10; ++i) { |
| auto data = generateRandomData(); |
| // Don't crash. |
| WebCore::KeyedDecoder::decoder(data.data(), data.size()); |
| } |
| } |
| |
| } |