1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "IDBBindingUtilities.h"
28#include "IDBKey.h"
29#include "IDBKeyPath.h"
30#include "SerializedScriptValue.h"
31
32#include <gtest/gtest.h>
33#include <wtf/Vector.h>
34
35#if ENABLE(INDEXED_DATABASE)
36
37using namespace WebCore;
38
39namespace {
40
41class LocalContext {
42public:
43    LocalContext()
44        : m_context(v8::Context::New())
45    {
46        m_context->Enter();
47    }
48
49    virtual ~LocalContext()
50    {
51        m_context->Exit();
52        m_context.Dispose();
53    }
54
55private:
56    v8::HandleScope m_scope;
57    v8::Persistent<v8::Context> m_context;
58};
59
60PassRefPtr<IDBKey> checkKeyFromValueAndKeyPathInternal(SerializedScriptValue* value, const String& keyPath)
61{
62    Vector<IDBKeyPathElement> idbKeyPath;
63    IDBKeyPathParseError parseError;
64    IDBParseKeyPath(keyPath, idbKeyPath, parseError);
65    EXPECT_EQ(IDBKeyPathParseErrorNone, parseError);
66    return createIDBKeyFromSerializedValueAndKeyPath(value, idbKeyPath);
67}
68
69void checkKeyPathNullValue(SerializedScriptValue* value, const String& keyPath)
70{
71    RefPtr<IDBKey> idbKey = checkKeyFromValueAndKeyPathInternal(value, keyPath);
72    ASSERT_FALSE(idbKey.get());
73}
74
75PassRefPtr<SerializedScriptValue> injectKey(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
76{
77    Vector<IDBKeyPathElement> idbKeyPath;
78    IDBKeyPathParseError parseError;
79    IDBParseKeyPath(keyPath, idbKeyPath, parseError);
80    EXPECT_EQ(IDBKeyPathParseErrorNone, parseError);
81    return injectIDBKeyIntoSerializedValue(key, value, idbKeyPath);
82}
83
84void checkInjection(PassRefPtr<IDBKey> prpKey, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
85{
86    RefPtr<IDBKey> key = prpKey;
87    RefPtr<SerializedScriptValue> newValue = injectKey(key, value, keyPath);
88    ASSERT_TRUE(newValue);
89    RefPtr<IDBKey> extractedKey = checkKeyFromValueAndKeyPathInternal(newValue.get(), keyPath);
90    EXPECT_TRUE(key->isEqual(extractedKey.get()));
91}
92
93void checkInjectionFails(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
94{
95    EXPECT_FALSE(injectKey(key, value, keyPath));
96}
97
98void checkKeyPathStringValue(SerializedScriptValue* value, const String& keyPath, const String& expected)
99{
100    RefPtr<IDBKey> idbKey = checkKeyFromValueAndKeyPathInternal(value, keyPath);
101    ASSERT_TRUE(idbKey.get());
102    ASSERT_EQ(IDBKey::StringType, idbKey->type());
103    ASSERT_TRUE(expected == idbKey->string());
104}
105
106void checkKeyPathNumberValue(SerializedScriptValue* value, const String& keyPath, int expected)
107{
108    RefPtr<IDBKey> idbKey = checkKeyFromValueAndKeyPathInternal(value, keyPath);
109    ASSERT_TRUE(idbKey.get());
110    ASSERT_EQ(IDBKey::NumberType, idbKey->type());
111    ASSERT_TRUE(expected == idbKey->number());
112}
113
114TEST(IDBKeyFromValueAndKeyPathTest, TopLevelPropertyStringValue)
115{
116    LocalContext v8context;
117    v8::Local<v8::Object> object = v8::Object::New();
118    object->Set(v8::String::New("foo"), v8::String::New("zoo"));
119
120    RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(object);
121
122    checkKeyPathStringValue(serializedScriptValue.get(), "foo", "zoo");
123    checkKeyPathNullValue(serializedScriptValue.get(), "bar");
124    checkKeyPathNullValue(serializedScriptValue.get(), "[3]");
125}
126
127TEST(IDBKeyFromValueAndKeyPathTest, TopLevelPropertyNumberValue)
128{
129    LocalContext v8context;
130    v8::Local<v8::Object> object = v8::Object::New();
131    object->Set(v8::String::New("foo"), v8::Number::New(456));
132
133    RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(object);
134
135    checkKeyPathNumberValue(serializedScriptValue.get(), "foo", 456);
136    checkKeyPathNullValue(serializedScriptValue.get(), "bar");
137    checkKeyPathNullValue(serializedScriptValue.get(), "[3]");
138}
139
140TEST(IDBKeyFromValueAndKeyPathTest, TopLevelArrayElement)
141{
142    LocalContext v8context;
143    v8::Local<v8::Array> array = v8::Array::New();
144    array->Set(3, v8::String::New("zoo"));
145
146    RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(array);
147
148    checkKeyPathStringValue(serializedScriptValue.get(), "[3]", "zoo");
149    checkKeyPathNullValue(serializedScriptValue.get(), "foo");
150    checkKeyPathNullValue(serializedScriptValue.get(), "bar");
151}
152
153TEST(IDBKeyFromValueAndKeyPathTest, SubProperty)
154{
155    LocalContext v8context;
156    v8::Local<v8::Object> object = v8::Object::New();
157    v8::Local<v8::Object> subProperty = v8::Object::New();
158    subProperty->Set(v8::String::New("bar"), v8::String::New("zee"));
159    object->Set(v8::String::New("foo"), subProperty);
160
161    RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(object);
162
163    checkKeyPathStringValue(serializedScriptValue.get(), "foo.bar", "zee");
164    checkKeyPathNullValue(serializedScriptValue.get(), "bar");
165    checkKeyPathNullValue(serializedScriptValue.get(), "[3]");
166}
167
168TEST(IDBKeyFromValueAndKeyPathTest, Array2D)
169{
170    LocalContext v8context;
171    v8::Local<v8::Object> object = v8::Object::New();
172    v8::Local<v8::Array> array = v8::Array::New();
173    v8::Local<v8::Array> subArray = v8::Array::New();
174    subArray->Set(7, v8::String::New("zee"));
175    array->Set(3, subArray);
176    object->Set(v8::String::New("foo"), array);
177
178    RefPtr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::create(object);
179
180    checkKeyPathStringValue(serializedScriptValue.get(), "foo[3][7]", "zee");
181    checkKeyPathNullValue(serializedScriptValue.get(), "bar");
182    checkKeyPathNullValue(serializedScriptValue.get(), "[4]");
183}
184
185TEST(InjectIDBKeyTest, TopLevelPropertyStringValue)
186{
187    LocalContext v8context;
188    v8::Local<v8::Object> object = v8::Object::New();
189    object->Set(v8::String::New("foo"), v8::String::New("zoo"));
190
191    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(object), "bar");
192    checkInjection(IDBKey::createNumber(1234), SerializedScriptValue::create(object), "bar");
193
194    checkInjectionFails(IDBKey::createString("key"), SerializedScriptValue::create(object), "foo.bar");
195    checkInjectionFails(IDBKey::createString("key"), SerializedScriptValue::create(object), "[3]");
196}
197
198TEST(InjectIDBKeyTest, TopLevelArrayElement)
199{
200    LocalContext v8context;
201    v8::Local<v8::Array> array = v8::Array::New();
202    array->Set(3, v8::String::New("zoo"));
203
204    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(array), "[2]");
205    checkInjection(IDBKey::createNumber(789), SerializedScriptValue::create(array), "[4]");
206    checkInjection(IDBKey::createDate(4567), SerializedScriptValue::create(array), "[1]");
207
208    checkInjectionFails(IDBKey::createString("foo"), SerializedScriptValue::create(array), "[5].bar");
209}
210
211TEST(InjectIDBKeyTest, SubProperty)
212{
213    LocalContext v8context;
214    v8::Local<v8::Object> object = v8::Object::New();
215    v8::Local<v8::Object> subProperty = v8::Object::New();
216    subProperty->Set(v8::String::New("bar"), v8::String::New("zee"));
217    object->Set(v8::String::New("foo"), subProperty);
218
219    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(object), "foo.baz");
220    checkInjection(IDBKey::createNumber(789), SerializedScriptValue::create(object), "foo.baz");
221    checkInjection(IDBKey::createDate(4567), SerializedScriptValue::create(object), "foo.baz");
222    checkInjection(IDBKey::createDate(4567), SerializedScriptValue::create(object), "bar");
223
224    checkInjectionFails(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo.bar.baz");
225    checkInjectionFails(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo.xyz.foo");
226}
227
228TEST(InjectIDBKeyTest, Array2D)
229{
230    LocalContext v8context;
231    v8::Local<v8::Object> object = v8::Object::New();
232    v8::Local<v8::Array> array = v8::Array::New();
233    v8::Local<v8::Array> subArray = v8::Array::New();
234    subArray->Set(7, v8::String::New("zee"));
235    array->Set(3, subArray);
236    object->Set(v8::String::New("foo"), array);
237
238    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(object), "foo[3][8]");
239    checkInjection(IDBKey::createNumber(789), SerializedScriptValue::create(object), "foo[3][8]");
240    checkInjection(IDBKey::createDate(4567), SerializedScriptValue::create(object), "foo[3][8]");
241    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(object), "bar");
242    checkInjection(IDBKey::createString("myNewKey"), SerializedScriptValue::create(object), "foo[4]");
243
244    checkInjectionFails(IDBKey::createString("zoo"), SerializedScriptValue::create(object), "foo[3][7].foo");
245}
246} // namespace
247
248#endif // ENABLE(INDEXED_DATABASE)
249