IDBLevelDBCodingTest.cpp [plain text]
#include "config.h"
#include "IDBLevelDBCoding.h"
#if ENABLE(INDEXED_DATABASE)
#if USE(LEVELDB)
#include "IDBKey.h"
#include "LevelDBSlice.h"
#include <gtest/gtest.h>
#include <wtf/Vector.h>
using namespace WebCore;
using namespace IDBLevelDBCoding;
namespace {
static PassRefPtr<IDBKey> createArrayIDBKey()
{
return IDBKey::createArray(IDBKey::KeyArray());
}
static PassRefPtr<IDBKey> createArrayIDBKey(PassRefPtr<IDBKey> prpKey1)
{
RefPtr<IDBKey> key1 = prpKey1;
IDBKey::KeyArray array;
array.append(key1);
return IDBKey::createArray(array);
}
static PassRefPtr<IDBKey> createArrayIDBKey(PassRefPtr<IDBKey> prpKey1, PassRefPtr<IDBKey> prpKey2)
{
RefPtr<IDBKey> key1 = prpKey1;
RefPtr<IDBKey> key2 = prpKey2;
IDBKey::KeyArray array;
array.append(key1);
array.append(key2);
return IDBKey::createArray(array);
}
TEST(IDBLevelDBCodingTest, EncodeByte)
{
Vector<char> expected;
expected.append(0);
unsigned char c;
c = 0;
expected[0] = c;
EXPECT_EQ(expected, encodeByte(c));
c = 1;
expected[0] = c;
EXPECT_EQ(expected, encodeByte(c));
c = 255;
expected[0] = c;
EXPECT_EQ(expected, encodeByte(c));
}
TEST(IDBLevelDBCodingTest, MaxIDBKey)
{
Vector<char> maxKey = maxIDBKey();
Vector<char> minKey = minIDBKey();
Vector<char> arrayKey = encodeIDBKey(*IDBKey::createArray(IDBKey::KeyArray()));
Vector<char> stringKey = encodeIDBKey(*IDBKey::createString("Hello world"));
Vector<char> numberKey = encodeIDBKey(*IDBKey::createNumber(3.14));
Vector<char> dateKey = encodeIDBKey(*IDBKey::createDate(1000000));
EXPECT_GT(compareEncodedIDBKeys(maxKey, minKey), 0);
EXPECT_GT(compareEncodedIDBKeys(maxKey, arrayKey), 0);
EXPECT_GT(compareEncodedIDBKeys(maxKey, stringKey), 0);
EXPECT_GT(compareEncodedIDBKeys(maxKey, numberKey), 0);
EXPECT_GT(compareEncodedIDBKeys(maxKey, dateKey), 0);
}
TEST(IDBLevelDBCodingTest, MinIDBKey)
{
Vector<char> minKey = minIDBKey();
Vector<char> maxKey = maxIDBKey();
Vector<char> arrayKey = encodeIDBKey(*IDBKey::createArray(IDBKey::KeyArray()));
Vector<char> stringKey = encodeIDBKey(*IDBKey::createString("Hello world"));
Vector<char> numberKey = encodeIDBKey(*IDBKey::createNumber(3.14));
Vector<char> dateKey = encodeIDBKey(*IDBKey::createDate(1000000));
EXPECT_LT(compareEncodedIDBKeys(minKey, maxKey), 0);
EXPECT_LT(compareEncodedIDBKeys(minKey, arrayKey), 0);
EXPECT_LT(compareEncodedIDBKeys(minKey, stringKey), 0);
EXPECT_LT(compareEncodedIDBKeys(minKey, numberKey), 0);
EXPECT_LT(compareEncodedIDBKeys(minKey, dateKey), 0);
}
TEST(IDBLevelDBCodingTest, EncodeInt)
{
EXPECT_EQ(static_cast<size_t>(1), encodeInt(0).size());
EXPECT_EQ(static_cast<size_t>(1), encodeInt(1).size());
EXPECT_EQ(static_cast<size_t>(1), encodeInt(255).size());
EXPECT_EQ(static_cast<size_t>(2), encodeInt(256).size());
EXPECT_EQ(static_cast<size_t>(4), encodeInt(0xffffffff).size());
}
TEST(IDBLevelDBCodingTest, DecodeInt)
{
Vector<int64_t> testCases;
testCases.append(0);
testCases.append(1);
testCases.append(255);
testCases.append(256);
testCases.append(65535);
testCases.append(655536);
testCases.append(7711192431755665792ll);
testCases.append(0x7fffffffffffffffll);
for (size_t i = 0; i < testCases.size(); ++i) {
int64_t n = testCases[i];
Vector<char> v = encodeInt(n);
EXPECT_EQ(n, decodeInt(v.data(), v.data() + v.size()));
}
}
TEST(IDBLevelDBCodingTest, EncodeVarInt)
{
EXPECT_EQ(static_cast<size_t>(1), encodeVarInt(0).size());
EXPECT_EQ(static_cast<size_t>(1), encodeVarInt(1).size());
EXPECT_EQ(static_cast<size_t>(2), encodeVarInt(255).size());
EXPECT_EQ(static_cast<size_t>(2), encodeVarInt(256).size());
EXPECT_EQ(static_cast<size_t>(5), encodeVarInt(0xffffffff).size());
}
TEST(IDBLevelDBCodingTest, DecodeVarInt)
{
Vector<int64_t> testCases;
testCases.append(0);
testCases.append(1);
testCases.append(255);
testCases.append(256);
testCases.append(65535);
testCases.append(655536);
testCases.append(7711192431755665792ll);
testCases.append(0x7fffffffffffffffll);
for (size_t i = 0; i < testCases.size(); ++i) {
int64_t n = testCases[i];
Vector<char> v = encodeVarInt(n);
int64_t res;
const char* p = decodeVarInt(v.data(), v.data() + v.size(), res);
EXPECT_EQ(n, res);
EXPECT_EQ(v.data() + v.size(), p);
p = decodeVarInt(v.data(), v.data() + v.size() - 1, res);
EXPECT_EQ(0, p);
p = decodeVarInt(v.data(), v.data(), res);
EXPECT_EQ(0, p);
}
}
TEST(IDBLevelDBCodingTest, EncodeString)
{
const UChar testStringA[] = {'f', 'o', 'o', '\0'};
const UChar testStringB[] = {0xdead, 0xbeef, '\0'};
EXPECT_EQ(static_cast<size_t>(0), encodeString(String("")).size());
EXPECT_EQ(static_cast<size_t>(2), encodeString(String("a")).size());
EXPECT_EQ(static_cast<size_t>(6), encodeString(String("foo")).size());
EXPECT_EQ(static_cast<size_t>(6), encodeString(String(testStringA)).size());
EXPECT_EQ(static_cast<size_t>(4), encodeString(String(testStringB)).size());
}
TEST(IDBLevelDBCodingTest, DecodeString)
{
const UChar testStringA[] = {'f', 'o', 'o', '\0'};
const UChar testStringB[] = {0xdead, 0xbeef, '\0'};
Vector<char> v;
v = encodeString(String(""));
EXPECT_EQ(String(""), decodeString(v.data(), v.data() + v.size()));
v = encodeString(String("a"));
EXPECT_EQ(String("a"), decodeString(v.data(), v.data() + v.size()));
v = encodeString(String("foo"));
EXPECT_EQ(String("foo"), decodeString(v.data(), v.data() + v.size()));
v = encodeString(String(testStringA));
EXPECT_EQ(String(testStringA), decodeString(v.data(), v.data() + v.size()));
v = encodeString(String(testStringB));
EXPECT_EQ(String(testStringB), decodeString(v.data(), v.data() + v.size()));
}
TEST(IDBLevelDBCodingTest, EncodeStringWithLength)
{
const UChar testStringA[] = {'f', 'o', 'o', '\0'};
const UChar testStringB[] = {0xdead, 0xbeef, '\0'};
EXPECT_EQ(static_cast<size_t>(1), encodeStringWithLength(String("")).size());
EXPECT_EQ(static_cast<size_t>(3), encodeStringWithLength(String("a")).size());
EXPECT_EQ(static_cast<size_t>(7), encodeStringWithLength(String(testStringA)).size());
EXPECT_EQ(static_cast<size_t>(5), encodeStringWithLength(String(testStringB)).size());
}
TEST(IDBLevelDBCodingTest, DecodeStringWithLength)
{
const UChar testStringA[] = {'f', 'o', 'o', '\0'};
const UChar testStringB[] = {0xdead, 0xbeef, '\0'};
const int kLongStringLen = 1234;
UChar longString[kLongStringLen + 1];
for (int i = 0; i < kLongStringLen; ++i)
longString[i] = i;
longString[kLongStringLen] = 0;
Vector<String> testCases;
testCases.append(String(""));
testCases.append(String("a"));
testCases.append(String("foo"));
testCases.append(String(testStringA));
testCases.append(String(testStringB));
testCases.append(String(longString));
for (size_t i = 0; i < testCases.size(); ++i) {
String s = testCases[i];
Vector<char> v = encodeStringWithLength(s);
String res;
const char* p = decodeStringWithLength(v.data(), v.data() + v.size(), res);
EXPECT_EQ(s, res);
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeStringWithLength(v.data(), v.data() + v.size() - 1, res));
EXPECT_EQ(0, decodeStringWithLength(v.data(), v.data(), res));
}
}
static int compareStrings(const char* p, const char* limitP, const char* q, const char* limitQ)
{
int result = compareEncodedStringsWithLength(p, limitP, q, limitQ);
EXPECT_EQ(p, limitP);
EXPECT_EQ(q, limitQ);
return result;
}
TEST(IDBLevelDBCodingTest, CompareEncodedStringsWithLength)
{
const UChar testStringA[] = {0x1000, 0x1000, '\0'};
const UChar testStringB[] = {0x1000, 0x1000, 0x1000, '\0'};
const UChar testStringC[] = {0x1000, 0x1000, 0x1001, '\0'};
const UChar testStringD[] = {0x1001, 0x1000, 0x1000, '\0'};
const UChar testStringE[] = {0xd834, 0xdd1e, '\0'};
const UChar testStringF[] = {0xfffd, '\0'};
Vector<String> testCases;
testCases.append(String(""));
testCases.append(String("a"));
testCases.append(String("b"));
testCases.append(String("baaa"));
testCases.append(String("baab"));
testCases.append(String("c"));
testCases.append(String(testStringA));
testCases.append(String(testStringB));
testCases.append(String(testStringC));
testCases.append(String(testStringD));
testCases.append(String(testStringE));
testCases.append(String(testStringF));
for (size_t i = 0; i < testCases.size() - 1; ++i) {
String a = testCases[i];
String b = testCases[i + 1];
EXPECT_LT(codePointCompare(a, b), 0);
EXPECT_GT(codePointCompare(b, a), 0);
EXPECT_EQ(codePointCompare(a, a), 0);
EXPECT_EQ(codePointCompare(b, b), 0);
Vector<char> encodedA = encodeStringWithLength(a);
EXPECT_TRUE(encodedA.size());
Vector<char> encodedB = encodeStringWithLength(b);
EXPECT_TRUE(encodedA.size());
const char* p = encodedA.data();
const char* limitP = p + encodedA.size();
const char* q = encodedB.data();
const char* limitQ = q + encodedB.size();
EXPECT_LT(compareStrings(p, limitP, q, limitQ), 0);
EXPECT_GT(compareStrings(q, limitQ, p, limitP), 0);
EXPECT_EQ(compareStrings(p, limitP, p, limitP), 0);
EXPECT_EQ(compareStrings(q, limitQ, q, limitQ), 0);
}
}
TEST(IDBLevelDBCodingTest, EncodeDouble)
{
EXPECT_EQ(static_cast<size_t>(8), encodeDouble(0).size());
EXPECT_EQ(static_cast<size_t>(8), encodeDouble(3.14).size());
}
TEST(IDBLevelDBCodingTest, DecodeDouble)
{
Vector<char> v;
const char* p;
double d;
v = encodeDouble(3.14);
p = decodeDouble(v.data(), v.data() + v.size(), &d);
EXPECT_EQ(3.14, d);
EXPECT_EQ(v.data() + v.size(), p);
v = encodeDouble(-3.14);
p = decodeDouble(v.data(), v.data() + v.size(), &d);
EXPECT_EQ(-3.14, d);
EXPECT_EQ(v.data() + v.size(), p);
v = encodeDouble(3.14);
p = decodeDouble(v.data(), v.data() + v.size() - 1, &d);
EXPECT_EQ(0, p);
}
TEST(IDBLevelDBCodingTest, EncodeDecodeIDBKey)
{
RefPtr<IDBKey> expectedKey;
RefPtr<IDBKey> decodedKey;
Vector<char> v;
const char* p;
expectedKey = IDBKey::createNumber(1234);
v = encodeIDBKey(*expectedKey);
p = decodeIDBKey(v.data(), v.data() + v.size(), decodedKey);
EXPECT_TRUE(decodedKey->isEqual(expectedKey.get()));
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey));
expectedKey = IDBKey::createString("Hello World!");
v = encodeIDBKey(*expectedKey);
p = decodeIDBKey(v.data(), v.data() + v.size(), decodedKey);
EXPECT_TRUE(decodedKey->isEqual(expectedKey.get()));
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey));
expectedKey = createArrayIDBKey();
v = encodeIDBKey(*expectedKey);
p = decodeIDBKey(v.data(), v.data() + v.size(), decodedKey);
EXPECT_TRUE(decodedKey->isEqual(expectedKey.get()));
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey));
expectedKey = IDBKey::createDate(7890);
v = encodeIDBKey(*expectedKey);
p = decodeIDBKey(v.data(), v.data() + v.size(), decodedKey);
EXPECT_TRUE(decodedKey->isEqual(expectedKey.get()));
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey));
IDBKey::KeyArray array;
array.append(IDBKey::createNumber(1234));
array.append(IDBKey::createString("Hello World!"));
array.append(IDBKey::createDate(7890));
expectedKey = IDBKey::createArray(array);
v = encodeIDBKey(*expectedKey);
p = decodeIDBKey(v.data(), v.data() + v.size(), decodedKey);
EXPECT_TRUE(decodedKey->isEqual(expectedKey.get()));
EXPECT_EQ(v.data() + v.size(), p);
EXPECT_EQ(0, decodeIDBKey(v.data(), v.data() + v.size() - 1, decodedKey));
}
TEST(IDBLevelDBCodingTest, ExtractAndCompareIDBKeys)
{
Vector<RefPtr<IDBKey> > keys;
keys.append(IDBKey::createNumber(-10));
keys.append(IDBKey::createNumber(0));
keys.append(IDBKey::createNumber(3.14));
keys.append(IDBKey::createDate(0));
keys.append(IDBKey::createDate(100));
keys.append(IDBKey::createDate(100000));
keys.append(IDBKey::createString(""));
keys.append(IDBKey::createString("a"));
keys.append(IDBKey::createString("b"));
keys.append(IDBKey::createString("baaa"));
keys.append(IDBKey::createString("baab"));
keys.append(IDBKey::createString("c"));
keys.append(createArrayIDBKey());
keys.append(createArrayIDBKey(IDBKey::createNumber(0)));
keys.append(createArrayIDBKey(IDBKey::createNumber(0), IDBKey::createNumber(3.14)));
keys.append(createArrayIDBKey(IDBKey::createDate(0)));
keys.append(createArrayIDBKey(IDBKey::createDate(0), IDBKey::createDate(0)));
keys.append(createArrayIDBKey(IDBKey::createString("")));
keys.append(createArrayIDBKey(IDBKey::createString(""), IDBKey::createString("a")));
keys.append(createArrayIDBKey(createArrayIDBKey()));
keys.append(createArrayIDBKey(createArrayIDBKey(), createArrayIDBKey()));
keys.append(createArrayIDBKey(createArrayIDBKey(createArrayIDBKey())));
keys.append(createArrayIDBKey(createArrayIDBKey(createArrayIDBKey(createArrayIDBKey()))));
for (size_t i = 0; i < keys.size() - 1; ++i) {
RefPtr<IDBKey> keyA = keys[i];
RefPtr<IDBKey> keyB = keys[i + 1];
EXPECT_TRUE(keyA->isLessThan(keyB.get()));
Vector<char> encodedA = encodeIDBKey(*keyA);
EXPECT_TRUE(encodedA.size());
Vector<char> encodedB = encodeIDBKey(*keyB);
EXPECT_TRUE(encodedB.size());
Vector<char> extractedA;
Vector<char> extractedB;
const char* p = extractEncodedIDBKey(encodedA.data(), encodedA.data() + encodedA.size(), &extractedA);
EXPECT_EQ(encodedA.data() + encodedA.size(), p);
EXPECT_EQ(encodedA, extractedA);
const char* q = extractEncodedIDBKey(encodedB.data(), encodedB.data() + encodedB.size(), &extractedB);
EXPECT_EQ(encodedB.data() + encodedB.size(), q);
EXPECT_EQ(encodedB, extractedB);
EXPECT_LT(compareEncodedIDBKeys(extractedA, extractedB), 0);
EXPECT_GT(compareEncodedIDBKeys(extractedB, extractedA), 0);
EXPECT_EQ(compareEncodedIDBKeys(extractedA, extractedA), 0);
EXPECT_EQ(compareEncodedIDBKeys(extractedB, extractedB), 0);
EXPECT_EQ(0, extractEncodedIDBKey(encodedA.data(), encodedA.data() + encodedA.size() - 1, &extractedA));
}
}
TEST(IDBLevelDBCodingTest, ComparisonTest)
{
Vector<Vector<char> > keys;
keys.append(SchemaVersionKey::encode());
keys.append(MaxDatabaseIdKey::encode());
keys.append(DatabaseFreeListKey::encode(0));
keys.append(DatabaseFreeListKey::encodeMaxKey());
keys.append(DatabaseNameKey::encode("", ""));
keys.append(DatabaseNameKey::encode("", "a"));
keys.append(DatabaseNameKey::encode("a", "a"));
keys.append(DatabaseMetaDataKey::encode(1, DatabaseMetaDataKey::kOriginName));
keys.append(ObjectStoreMetaDataKey::encode(1, 1, 0));
keys.append(ObjectStoreMetaDataKey::encodeMaxKey(1));
keys.append(IndexMetaDataKey::encode(1, 1, 30, 0));
keys.append(IndexMetaDataKey::encode(1, 1, 31, 0));
keys.append(IndexMetaDataKey::encode(1, 1, 31, 1));
keys.append(ObjectStoreFreeListKey::encode(1, 1));
keys.append(ObjectStoreFreeListKey::encodeMaxKey(1));
keys.append(IndexFreeListKey::encode(1, 1, kMinimumIndexId));
keys.append(IndexFreeListKey::encodeMaxKey(1, 1));
keys.append(IndexFreeListKey::encode(1, 2, kMinimumIndexId));
keys.append(IndexFreeListKey::encodeMaxKey(1, 2));
keys.append(ObjectStoreNamesKey::encode(1, ""));
keys.append(ObjectStoreNamesKey::encode(1, "a"));
keys.append(IndexNamesKey::encode(1, 1, ""));
keys.append(IndexNamesKey::encode(1, 1, "a"));
keys.append(IndexNamesKey::encode(1, 2, "a"));
keys.append(ObjectStoreDataKey::encode(1, 1, minIDBKey()));
keys.append(ObjectStoreDataKey::encode(1, 1, maxIDBKey()));
keys.append(ExistsEntryKey::encode(1, 1, minIDBKey()));
keys.append(ExistsEntryKey::encode(1, 1, maxIDBKey()));
keys.append(IndexDataKey::encode(1, 1, 30, minIDBKey(), minIDBKey(), 0));
keys.append(IndexDataKey::encode(1, 1, 30, minIDBKey(), minIDBKey(), 1));
keys.append(IndexDataKey::encode(1, 1, 30, minIDBKey(), maxIDBKey(), 0));
keys.append(IndexDataKey::encode(1, 1, 30, minIDBKey(), maxIDBKey(), 1));
keys.append(IndexDataKey::encode(1, 1, 30, maxIDBKey(), minIDBKey(), 0));
keys.append(IndexDataKey::encode(1, 1, 30, maxIDBKey(), minIDBKey(), 1));
keys.append(IndexDataKey::encode(1, 1, 30, maxIDBKey(), maxIDBKey(), 0));
keys.append(IndexDataKey::encode(1, 1, 30, maxIDBKey(), maxIDBKey(), 1));
keys.append(IndexDataKey::encode(1, 1, 31, minIDBKey(), minIDBKey(), 0));
keys.append(IndexDataKey::encode(1, 2, 30, minIDBKey(), minIDBKey(), 0));
keys.append(IndexDataKey::encodeMaxKey(1, 2, INT32_MAX));
for (size_t i = 0; i < keys.size(); ++i) {
const LevelDBSlice keyA(keys[i]);
EXPECT_EQ(compare(keyA, keyA), 0);
for (size_t j = i + 1; j < keys.size(); ++j) {
const LevelDBSlice keyB(keys[j]);
EXPECT_LT(compare(keyA, keyB), 0);
EXPECT_GT(compare(keyB, keyA), 0);
}
}
}
}
#endif // USE(LEVELDB)
#endif // ENABLE(INDEXED_DATABASE)