Add QJson support to QV8Engine
Make QV8Engine perform direct conversion between JavaScript values and QJson{Value,Object,Array}. This implementation always makes a deep clone of the QJson{Object,Array} when converting to JS; it might make sense to add a lazy conversion scheme for dealing with large objects. Change-Id: Id0b65891a19515ce22f1e51fa8a28d9f3e595271 Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com> Reviewed-by: Jamey Hicks <jamey.hicks@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
This commit is contained in:
parent
31c5b237c4
commit
e5f45d9b57
|
@ -58,6 +58,9 @@
|
|||
#include "qv8domerrors_p.h"
|
||||
#include "qv8sqlerrors_p.h"
|
||||
|
||||
#include <QtCore/qjsonarray.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qjsonvalue.h>
|
||||
|
||||
Q_DECLARE_METATYPE(QJSValue)
|
||||
Q_DECLARE_METATYPE(QList<int>)
|
||||
|
@ -155,6 +158,7 @@ QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership)
|
|||
m_variantWrapper.init(this);
|
||||
m_valueTypeWrapper.init(this);
|
||||
m_sequenceWrapper.init(this);
|
||||
m_jsonWrapper.init(this);
|
||||
|
||||
{
|
||||
v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
|
||||
|
@ -182,6 +186,7 @@ QV8Engine::~QV8Engine()
|
|||
|
||||
qPersistentDispose(m_strongReferencer);
|
||||
|
||||
m_jsonWrapper.destroy();
|
||||
m_sequenceWrapper.destroy();
|
||||
m_valueTypeWrapper.destroy();
|
||||
m_variantWrapper.destroy();
|
||||
|
@ -220,6 +225,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
|
|||
if (typeHint == QVariant::Bool)
|
||||
return QVariant(value->BooleanValue());
|
||||
|
||||
if (typeHint == QMetaType::QJsonValue)
|
||||
return QVariant::fromValue(jsonValueFromJS(value));
|
||||
|
||||
if (value->IsObject()) {
|
||||
QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
|
||||
if (r) {
|
||||
|
@ -251,6 +259,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
|
|||
case QV8ObjectResource::SequenceType:
|
||||
return m_sequenceWrapper.toVariant(r);
|
||||
}
|
||||
} else if (typeHint == QMetaType::QJsonObject
|
||||
&& !value->IsArray() && !value->IsFunction()) {
|
||||
return QVariant::fromValue(jsonObjectFromJS(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +280,8 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
|
|||
}
|
||||
|
||||
return qVariantFromValue<QList<QObject*> >(list);
|
||||
} else if (typeHint == QMetaType::QJsonArray) {
|
||||
return QVariant::fromValue(jsonArrayFromJS(value));
|
||||
}
|
||||
|
||||
bool succeeded = false;
|
||||
|
@ -368,6 +381,12 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
|
|||
return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
|
||||
case QMetaType::QVariantMap:
|
||||
return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
|
||||
case QMetaType::QJsonValue:
|
||||
return jsonValueToJS(*reinterpret_cast<const QJsonValue *>(ptr));
|
||||
case QMetaType::QJsonObject:
|
||||
return jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(ptr));
|
||||
case QMetaType::QJsonArray:
|
||||
return jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(ptr));
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -1152,6 +1171,15 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
|
|||
case QMetaType::QVariant:
|
||||
result = variantToJS(*reinterpret_cast<const QVariant*>(data));
|
||||
break;
|
||||
case QMetaType::QJsonValue:
|
||||
result = jsonValueToJS(*reinterpret_cast<const QJsonValue *>(data));
|
||||
break;
|
||||
case QMetaType::QJsonObject:
|
||||
result = jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(data));
|
||||
break;
|
||||
case QMetaType::QJsonArray:
|
||||
result = jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(data));
|
||||
break;
|
||||
default:
|
||||
if (type == qMetaTypeId<QJSValue>()) {
|
||||
return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this);
|
||||
|
@ -1267,6 +1295,15 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data
|
|||
case QMetaType::QVariant:
|
||||
*reinterpret_cast<QVariant*>(data) = variantFromJS(value);
|
||||
return true;
|
||||
case QMetaType::QJsonValue:
|
||||
*reinterpret_cast<QJsonValue *>(data) = jsonValueFromJS(value);
|
||||
return true;
|
||||
case QMetaType::QJsonObject:
|
||||
*reinterpret_cast<QJsonObject *>(data) = jsonObjectFromJS(value);
|
||||
return true;
|
||||
case QMetaType::QJsonArray:
|
||||
*reinterpret_cast<QJsonArray *>(data) = jsonArrayFromJS(value);
|
||||
return true;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -1383,6 +1420,36 @@ QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value)
|
|||
return variantMapFromJS(value->ToObject());
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> QV8Engine::jsonValueToJS(const QJsonValue &value)
|
||||
{
|
||||
return m_jsonWrapper.fromJsonValue(value);
|
||||
}
|
||||
|
||||
QJsonValue QV8Engine::jsonValueFromJS(v8::Handle<v8::Value> value)
|
||||
{
|
||||
return m_jsonWrapper.toJsonValue(value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> QV8Engine::jsonObjectToJS(const QJsonObject &object)
|
||||
{
|
||||
return m_jsonWrapper.fromJsonObject(object);
|
||||
}
|
||||
|
||||
QJsonObject QV8Engine::jsonObjectFromJS(v8::Handle<v8::Value> value)
|
||||
{
|
||||
return m_jsonWrapper.toJsonObject(value);
|
||||
}
|
||||
|
||||
v8::Local<v8::Array> QV8Engine::jsonArrayToJS(const QJsonArray &array)
|
||||
{
|
||||
return m_jsonWrapper.fromJsonArray(array);
|
||||
}
|
||||
|
||||
QJsonArray QV8Engine::jsonArrayFromJS(v8::Handle<v8::Value> value)
|
||||
{
|
||||
return m_jsonWrapper.toJsonArray(value);
|
||||
}
|
||||
|
||||
bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
|
||||
const QByteArray &targetType,
|
||||
void **result)
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include "qv8variantwrapper_p.h"
|
||||
#include "qv8valuetypewrapper_p.h"
|
||||
#include "qv8sequencewrapper_p.h"
|
||||
#include "qv8jsonwrapper_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -415,6 +416,13 @@ public:
|
|||
v8::Handle<v8::Value> variantToJS(const QVariant &value);
|
||||
QVariant variantFromJS(v8::Handle<v8::Value> value);
|
||||
|
||||
v8::Handle<v8::Value> jsonValueToJS(const QJsonValue &value);
|
||||
QJsonValue jsonValueFromJS(v8::Handle<v8::Value> value);
|
||||
v8::Local<v8::Object> jsonObjectToJS(const QJsonObject &object);
|
||||
QJsonObject jsonObjectFromJS(v8::Handle<v8::Value> value);
|
||||
v8::Local<v8::Array> jsonArrayToJS(const QJsonArray &array);
|
||||
QJsonArray jsonArrayFromJS(v8::Handle<v8::Value> value);
|
||||
|
||||
v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
|
||||
bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
|
||||
|
||||
|
@ -477,6 +485,7 @@ protected:
|
|||
QV8VariantWrapper m_variantWrapper;
|
||||
QV8ValueTypeWrapper m_valueTypeWrapper;
|
||||
QV8SequenceWrapper m_sequenceWrapper;
|
||||
QV8JsonWrapper m_jsonWrapper;
|
||||
|
||||
v8::Persistent<v8::Function> m_getOwnPropertyNames;
|
||||
v8::Persistent<v8::Function> m_freezeObject;
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtQml module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qv8jsonwrapper_p.h"
|
||||
#include "qv8engine_p.h"
|
||||
#include "qjsconverter_impl_p.h"
|
||||
|
||||
#include <QtCore/qjsonarray.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qjsonvalue.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QV8JsonWrapper::QV8JsonWrapper()
|
||||
: m_engine(0)
|
||||
{
|
||||
}
|
||||
|
||||
QV8JsonWrapper::~QV8JsonWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
void QV8JsonWrapper::init(QV8Engine *engine)
|
||||
{
|
||||
m_engine = engine;
|
||||
}
|
||||
|
||||
void QV8JsonWrapper::destroy()
|
||||
{
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> QV8JsonWrapper::fromJsonValue(const QJsonValue &value)
|
||||
{
|
||||
if (value.isString())
|
||||
return QJSConverter::toString(value.toString());
|
||||
else if (value.isDouble())
|
||||
return v8::Number::New(value.toDouble());
|
||||
else if (value.isBool())
|
||||
return value.toBool() ? v8::True() : v8::False();
|
||||
else if (value.isArray())
|
||||
return fromJsonArray(value.toArray());
|
||||
else if (value.isObject())
|
||||
return fromJsonObject(value.toObject());
|
||||
else if (value.isNull())
|
||||
return v8::Null();
|
||||
else
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
QJsonValue QV8JsonWrapper::toJsonValue(v8::Handle<v8::Value> value)
|
||||
{
|
||||
if (value->IsString())
|
||||
return QJsonValue(QJSConverter::toString(value.As<v8::String>()));
|
||||
else if (value->IsNumber())
|
||||
return QJsonValue(value->NumberValue());
|
||||
else if (value->IsBoolean())
|
||||
return QJsonValue(value->BooleanValue());
|
||||
else if (value->IsArray())
|
||||
return toJsonArray(value.As<v8::Array>());
|
||||
else if (value->IsObject())
|
||||
return toJsonObject(value.As<v8::Object>());
|
||||
else if (value->IsNull())
|
||||
return QJsonValue(QJsonValue::Null);
|
||||
else
|
||||
return QJsonValue(QJsonValue::Undefined);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> QV8JsonWrapper::fromJsonObject(const QJsonObject &object)
|
||||
{
|
||||
v8::Local<v8::Object> v8object = v8::Object::New();
|
||||
for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it)
|
||||
v8object->Set(QJSConverter::toString(it.key()), fromJsonValue(it.value()));
|
||||
return v8object;
|
||||
}
|
||||
|
||||
QJsonObject QV8JsonWrapper::toJsonObject(v8::Handle<v8::Value> value)
|
||||
{
|
||||
QJsonObject result;
|
||||
if (!value->IsObject() || value->IsArray() || value->IsFunction())
|
||||
return result;
|
||||
|
||||
v8::Handle<v8::Object> v8object(value.As<v8::Object>());
|
||||
int hash = v8object->GetIdentityHash();
|
||||
if (m_visitedConversionObjects.contains(hash)) {
|
||||
// Avoid recursion.
|
||||
// For compatibility with QVariant{List,Map} conversion, we return an
|
||||
// empty object (and no error is thrown).
|
||||
return result;
|
||||
}
|
||||
|
||||
m_visitedConversionObjects.insert(hash);
|
||||
|
||||
v8::Local<v8::Array> propertyNames = m_engine->getOwnPropertyNames(v8object);
|
||||
uint32_t length = propertyNames->Length();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
v8::Local<v8::Value> name = propertyNames->Get(i);
|
||||
v8::Local<v8::Value> propertyValue = v8object->Get(name);
|
||||
if (!propertyValue->IsFunction())
|
||||
result.insert(QJSConverter::toString(name->ToString()), toJsonValue(propertyValue));
|
||||
}
|
||||
|
||||
m_visitedConversionObjects.remove(hash);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
v8::Local<v8::Array> QV8JsonWrapper::fromJsonArray(const QJsonArray &array)
|
||||
{
|
||||
int size = array.size();
|
||||
v8::Local<v8::Array> v8array = v8::Array::New(size);
|
||||
for (int i = 0; i < size; i++)
|
||||
v8array->Set(i, fromJsonValue(array.at(i)));
|
||||
return v8array;
|
||||
}
|
||||
|
||||
QJsonArray QV8JsonWrapper::toJsonArray(v8::Handle<v8::Value> value)
|
||||
{
|
||||
QJsonArray result;
|
||||
if (!value->IsArray())
|
||||
return result;
|
||||
|
||||
v8::Handle<v8::Array> v8array(value.As<v8::Array>());
|
||||
int hash = v8array->GetIdentityHash();
|
||||
if (m_visitedConversionObjects.contains(hash)) {
|
||||
// Avoid recursion.
|
||||
// For compatibility with QVariant{List,Map} conversion, we return an
|
||||
// empty array (and no error is thrown).
|
||||
return result;
|
||||
}
|
||||
|
||||
m_visitedConversionObjects.insert(hash);
|
||||
|
||||
uint32_t length = v8array->Length();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
v8::Local<v8::Value> element = v8array->Get(i);
|
||||
if (!element->IsFunction())
|
||||
result.append(toJsonValue(element));
|
||||
}
|
||||
|
||||
m_visitedConversionObjects.remove(hash);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
|
@ -0,0 +1,93 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtQml module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QV8JSONWRAPPER_P_H
|
||||
#define QV8JSONWRAPPER_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qset.h>
|
||||
#include <private/qv8_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QJsonValue;
|
||||
class QJsonObject;
|
||||
class QJsonArray;
|
||||
|
||||
class QV8Engine;
|
||||
class QV8JsonWrapper
|
||||
{
|
||||
public:
|
||||
QV8JsonWrapper();
|
||||
~QV8JsonWrapper();
|
||||
|
||||
void init(QV8Engine *);
|
||||
void destroy();
|
||||
|
||||
v8::Handle<v8::Value> fromJsonValue(const QJsonValue &value);
|
||||
QJsonValue toJsonValue(v8::Handle<v8::Value> value);
|
||||
|
||||
v8::Local<v8::Object> fromJsonObject(const QJsonObject &object);
|
||||
QJsonObject toJsonObject(v8::Handle<v8::Value> value);
|
||||
|
||||
v8::Local<v8::Array> fromJsonArray(const QJsonArray &array);
|
||||
QJsonArray toJsonArray(v8::Handle<v8::Value> value);
|
||||
|
||||
private:
|
||||
QV8Engine *m_engine;
|
||||
QSet<int> m_visitedConversionObjects;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QV8JSONWRAPPER_P_H
|
||||
|
|
@ -54,6 +54,7 @@
|
|||
#include <private/qqmlexpression_p.h>
|
||||
|
||||
#include <QtQml/qjsvalue.h>
|
||||
#include <QtCore/qjsonvalue.h>
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qatomic.h>
|
||||
|
@ -659,6 +660,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
|
|||
QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
|
||||
} else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
|
||||
PROPERTY_STORE(QVariant, QVariant());
|
||||
} else if (value->IsUndefined() && property->propType == QMetaType::QJsonValue) {
|
||||
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
|
||||
} else if (value->IsUndefined()) {
|
||||
QString error = QLatin1String("Cannot assign [undefined] to ") +
|
||||
QLatin1String(QMetaType::typeName(property->propType));
|
||||
|
|
|
@ -15,6 +15,7 @@ HEADERS += \
|
|||
$$PWD/qv8variantwrapper_p.h \
|
||||
$$PWD/qv8variantresource_p.h \
|
||||
$$PWD/qv8valuetypewrapper_p.h \
|
||||
$$PWD/qv8jsonwrapper_p.h \
|
||||
$$PWD/qv8include_p.h \
|
||||
$$PWD/qv8worker_p.h \
|
||||
$$PWD/qv8bindings_p.h \
|
||||
|
@ -33,6 +34,7 @@ SOURCES += \
|
|||
$$PWD/qv8listwrapper.cpp \
|
||||
$$PWD/qv8variantwrapper.cpp \
|
||||
$$PWD/qv8valuetypewrapper.cpp \
|
||||
$$PWD/qv8jsonwrapper.cpp \
|
||||
$$PWD/qv8include.cpp \
|
||||
$$PWD/qv8worker.cpp \
|
||||
$$PWD/qv8bindings.cpp \
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1 @@
|
|||
[123]
|
|
@ -0,0 +1 @@
|
|||
[true,false,null,"hello"]
|
|
@ -0,0 +1 @@
|
|||
[{"a":42}]
|
|
@ -0,0 +1 @@
|
|||
[[[42]],[]]
|
|
@ -0,0 +1 @@
|
|||
false
|
|
@ -0,0 +1 @@
|
|||
null
|
|
@ -0,0 +1 @@
|
|||
123
|
|
@ -0,0 +1 @@
|
|||
42.35
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1 @@
|
|||
{"foo":123}
|
|
@ -0,0 +1 @@
|
|||
{"a":true,"b":false,"c":null,"d":"hello"}
|
|
@ -0,0 +1 @@
|
|||
{"a":{"b":{"c":42}}}
|
|
@ -0,0 +1 @@
|
|||
{"a":[],"b":[42],"c":{"d":null}}
|
|
@ -0,0 +1 @@
|
|||
"hello"
|
|
@ -0,0 +1 @@
|
|||
true
|
|
@ -0,0 +1,16 @@
|
|||
CONFIG += testcase
|
||||
TARGET = tst_qjsonbinding
|
||||
macx:CONFIG -= app_bundle
|
||||
|
||||
SOURCES += tst_qjsonbinding.cpp
|
||||
INCLUDEPATH += ../../shared
|
||||
|
||||
include (../../shared/util.pri)
|
||||
|
||||
# QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage
|
||||
# LIBS += -lgcov
|
||||
|
||||
TESTDATA = data/*
|
||||
|
||||
CONFIG += parallel_test
|
||||
QT += core qml testlib
|
|
@ -0,0 +1,535 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtQml/QtQml>
|
||||
#include "../../shared/util.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QJsonValue::Type)
|
||||
|
||||
class JsonPropertyObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QJsonValue value READ value WRITE setValue)
|
||||
Q_PROPERTY(QJsonObject object READ object WRITE setObject)
|
||||
Q_PROPERTY(QJsonArray array READ array WRITE setArray)
|
||||
public:
|
||||
QJsonValue value() const { return m_value; }
|
||||
void setValue(const QJsonValue &v) { m_value = v; }
|
||||
QJsonObject object() const { return m_object; }
|
||||
void setObject(const QJsonObject &o) { m_object = o; }
|
||||
QJsonArray array() const { return m_array; }
|
||||
void setArray(const QJsonArray &a) { m_array = a; }
|
||||
|
||||
private:
|
||||
QJsonValue m_value;
|
||||
QJsonObject m_object;
|
||||
QJsonArray m_array;
|
||||
};
|
||||
|
||||
class tst_qjsonbinding : public QQmlDataTest
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
tst_qjsonbinding() {}
|
||||
|
||||
private slots:
|
||||
void cppJsConversion_data();
|
||||
void cppJsConversion();
|
||||
|
||||
void readValueProperty_data();
|
||||
void readValueProperty();
|
||||
void readObjectOrArrayProperty_data();
|
||||
void readObjectOrArrayProperty();
|
||||
|
||||
void writeValueProperty_data();
|
||||
void writeValueProperty();
|
||||
void writeObjectOrArrayProperty_data();
|
||||
void writeObjectOrArrayProperty();
|
||||
|
||||
void writeProperty_incompatibleType_data();
|
||||
void writeProperty_incompatibleType();
|
||||
|
||||
void writeProperty_javascriptExpression_data();
|
||||
void writeProperty_javascriptExpression();
|
||||
|
||||
private:
|
||||
QByteArray readAsUtf8(const QString &fileName);
|
||||
static QJsonValue valueFromJson(const QByteArray &json);
|
||||
|
||||
void addPrimitiveDataTestFiles();
|
||||
void addObjectDataTestFiles();
|
||||
void addArrayDataTestFiles();
|
||||
};
|
||||
|
||||
QByteArray tst_qjsonbinding::readAsUtf8(const QString &fileName)
|
||||
{
|
||||
QFile file(testFile(fileName));
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QTextStream stream(&file);
|
||||
return stream.readAll().trimmed().toUtf8();
|
||||
}
|
||||
|
||||
QJsonValue tst_qjsonbinding::valueFromJson(const QByteArray &json)
|
||||
{
|
||||
if (json.isEmpty())
|
||||
return QJsonValue(QJsonValue::Undefined);
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json);
|
||||
if (!doc.isEmpty())
|
||||
return doc.isObject() ? QJsonValue(doc.object()) : QJsonValue(doc.array());
|
||||
|
||||
// QJsonDocument::fromJson() only handles objects and arrays...
|
||||
// Wrap the JSON inside a dummy object and extract the value.
|
||||
QByteArray wrappedJson = "{\"prop\":" + json + "}";
|
||||
doc = QJsonDocument::fromJson(wrappedJson);
|
||||
Q_ASSERT(doc.isObject());
|
||||
return doc.object().value("prop");
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::addPrimitiveDataTestFiles()
|
||||
{
|
||||
QTest::newRow("true") << "true.json";
|
||||
QTest::newRow("false") << "false.json";
|
||||
|
||||
QTest::newRow("null") << "null.json";
|
||||
|
||||
QTest::newRow("number.0") << "number.0.json";
|
||||
QTest::newRow("number.1") << "number.1.json";
|
||||
|
||||
QTest::newRow("string.0") << "string.0.json";
|
||||
|
||||
QTest::newRow("undefined") << "empty.json";
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::addObjectDataTestFiles()
|
||||
{
|
||||
QTest::newRow("object.0") << "object.0.json";
|
||||
QTest::newRow("object.1") << "object.1.json";
|
||||
QTest::newRow("object.2") << "object.2.json";
|
||||
QTest::newRow("object.3") << "object.3.json";
|
||||
QTest::newRow("object.4") << "object.4.json";
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::addArrayDataTestFiles()
|
||||
{
|
||||
QTest::newRow("array.0") << "array.0.json";
|
||||
QTest::newRow("array.1") << "array.1.json";
|
||||
QTest::newRow("array.2") << "array.2.json";
|
||||
QTest::newRow("array.3") << "array.3.json";
|
||||
QTest::newRow("array.4") << "array.4.json";
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::cppJsConversion_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
|
||||
addPrimitiveDataTestFiles();
|
||||
addObjectDataTestFiles();
|
||||
addArrayDataTestFiles();
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::cppJsConversion()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QByteArray json = readAsUtf8(fileName);
|
||||
QJsonValue jsonValue = valueFromJson(json);
|
||||
|
||||
QJSEngine eng;
|
||||
QJSValue stringify = eng.globalObject().property("JSON").property("stringify");
|
||||
QVERIFY(stringify.isCallable());
|
||||
|
||||
{
|
||||
QJSValue jsValue = eng.toScriptValue(jsonValue);
|
||||
QVERIFY(!jsValue.isVariant());
|
||||
switch (jsonValue.type()) {
|
||||
case QJsonValue::Null:
|
||||
QVERIFY(jsValue.isNull());
|
||||
break;
|
||||
case QJsonValue::Bool:
|
||||
QVERIFY(jsValue.isBool());
|
||||
QCOMPARE(jsValue.toBool(), jsonValue.toBool());
|
||||
break;
|
||||
case QJsonValue::Double:
|
||||
QVERIFY(jsValue.isNumber());
|
||||
QCOMPARE(jsValue.toNumber(), jsonValue.toDouble());
|
||||
break;
|
||||
case QJsonValue::String:
|
||||
QVERIFY(jsValue.isString());
|
||||
QCOMPARE(jsValue.toString(), jsonValue.toString());
|
||||
break;
|
||||
case QJsonValue::Array:
|
||||
QVERIFY(jsValue.isArray());
|
||||
break;
|
||||
case QJsonValue::Object:
|
||||
QVERIFY(jsValue.isObject());
|
||||
break;
|
||||
case QJsonValue::Undefined:
|
||||
QVERIFY(jsValue.isUndefined());
|
||||
break;
|
||||
}
|
||||
|
||||
if (jsValue.isUndefined()) {
|
||||
QVERIFY(json.isEmpty());
|
||||
} else {
|
||||
QJSValue stringified = stringify.call(QJSValueList() << jsValue);
|
||||
QVERIFY(!stringified.isError());
|
||||
QCOMPARE(stringified.toString().toUtf8(), json);
|
||||
}
|
||||
|
||||
QJsonValue roundtrip = qjsvalue_cast<QJsonValue>(jsValue);
|
||||
// Workarounds for QTBUG-25164
|
||||
if (jsonValue.isObject() && jsonValue.toObject().isEmpty())
|
||||
QVERIFY(roundtrip.isObject() && roundtrip.toObject().isEmpty());
|
||||
else if (jsonValue.isArray() && jsonValue.toArray().isEmpty())
|
||||
QVERIFY(roundtrip.isArray() && roundtrip.toArray().isEmpty());
|
||||
else
|
||||
QCOMPARE(roundtrip, jsonValue);
|
||||
}
|
||||
|
||||
if (jsonValue.isObject()) {
|
||||
QJsonObject jsonObject = jsonValue.toObject();
|
||||
QJSValue jsObject = eng.toScriptValue(jsonObject);
|
||||
QVERIFY(!jsObject.isVariant());
|
||||
QVERIFY(jsObject.isObject());
|
||||
|
||||
QJSValue stringified = stringify.call(QJSValueList() << jsObject);
|
||||
QVERIFY(!stringified.isError());
|
||||
QCOMPARE(stringified.toString().toUtf8(), json);
|
||||
|
||||
QJsonObject roundtrip = qjsvalue_cast<QJsonObject>(jsObject);
|
||||
QCOMPARE(roundtrip, jsonObject);
|
||||
} else if (jsonValue.isArray()) {
|
||||
QJsonArray jsonArray = jsonValue.toArray();
|
||||
QJSValue jsArray = eng.toScriptValue(jsonArray);
|
||||
QVERIFY(!jsArray.isVariant());
|
||||
QVERIFY(jsArray.isArray());
|
||||
|
||||
QJSValue stringified = stringify.call(QJSValueList() << jsArray);
|
||||
QVERIFY(!stringified.isError());
|
||||
QCOMPARE(stringified.toString().toUtf8(), json);
|
||||
|
||||
QJsonArray roundtrip = qjsvalue_cast<QJsonArray>(jsArray);
|
||||
QCOMPARE(roundtrip, jsonArray);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::readValueProperty_data()
|
||||
{
|
||||
cppJsConversion_data();
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::readValueProperty()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QByteArray json = readAsUtf8(fileName);
|
||||
QJsonValue jsonValue = valueFromJson(json);
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
obj.setValue(jsonValue);
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
QJSValue stringified = eng.evaluate(
|
||||
"var v = obj.value; (typeof v == 'undefined') ? '' : JSON.stringify(v)");
|
||||
QVERIFY(!stringified.isError());
|
||||
QCOMPARE(stringified.toString().toUtf8(), json);
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::readObjectOrArrayProperty_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
|
||||
addObjectDataTestFiles();
|
||||
addArrayDataTestFiles();
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::readObjectOrArrayProperty()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QByteArray json = readAsUtf8(fileName);
|
||||
QJsonValue jsonValue = valueFromJson(json);
|
||||
QVERIFY(jsonValue.isObject() || jsonValue.isArray());
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
if (jsonValue.isObject())
|
||||
obj.setObject(jsonValue.toObject());
|
||||
else
|
||||
obj.setArray(jsonValue.toArray());
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
|
||||
QJSValue stringified = eng.evaluate(
|
||||
QString::fromLatin1("JSON.stringify(obj.%0)").arg(
|
||||
jsonValue.isObject() ? "object" : "array"));
|
||||
QVERIFY(!stringified.isError());
|
||||
QCOMPARE(stringified.toString().toUtf8(), json);
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeValueProperty_data()
|
||||
{
|
||||
readValueProperty_data();
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeValueProperty()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QByteArray json = readAsUtf8(fileName);
|
||||
QJsonValue jsonValue = valueFromJson(json);
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
|
||||
QJSValue fun = eng.evaluate(
|
||||
"(function(json) {"
|
||||
" void(obj.value = (json == '') ? undefined : JSON.parse(json));"
|
||||
"})");
|
||||
QVERIFY(fun.isCallable());
|
||||
|
||||
QVERIFY(obj.value().isNull());
|
||||
QVERIFY(fun.call(QJSValueList() << QString::fromUtf8(json)).isUndefined());
|
||||
|
||||
// Workarounds for QTBUG-25164
|
||||
if (jsonValue.isObject() && jsonValue.toObject().isEmpty())
|
||||
QVERIFY(obj.value().isObject() && obj.value().toObject().isEmpty());
|
||||
else if (jsonValue.isArray() && jsonValue.toArray().isEmpty())
|
||||
QVERIFY(obj.value().isArray() && obj.value().toArray().isEmpty());
|
||||
else
|
||||
QCOMPARE(obj.value(), jsonValue);
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeObjectOrArrayProperty_data()
|
||||
{
|
||||
readObjectOrArrayProperty_data();
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeObjectOrArrayProperty()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QByteArray json = readAsUtf8(fileName);
|
||||
QJsonValue jsonValue = valueFromJson(json);
|
||||
QVERIFY(jsonValue.isObject() || jsonValue.isArray());
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
|
||||
QJSValue fun = eng.evaluate(
|
||||
QString::fromLatin1(
|
||||
"(function(json) {"
|
||||
" void(obj.%0 = JSON.parse(json));"
|
||||
"})").arg(jsonValue.isObject() ? "object" : "array")
|
||||
);
|
||||
QVERIFY(fun.isCallable());
|
||||
|
||||
QVERIFY(obj.object().isEmpty() && obj.array().isEmpty());
|
||||
QVERIFY(fun.call(QJSValueList() << QString::fromUtf8(json)).isUndefined());
|
||||
|
||||
if (jsonValue.isObject())
|
||||
QCOMPARE(obj.object(), jsonValue.toObject());
|
||||
else
|
||||
QCOMPARE(obj.array(), jsonValue.toArray());
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeProperty_incompatibleType_data()
|
||||
{
|
||||
QTest::addColumn<QString>("property");
|
||||
QTest::addColumn<QString>("expression");
|
||||
|
||||
QTest::newRow("value=function") << "value" << "(function(){})";
|
||||
|
||||
QTest::newRow("object=undefined") << "object" << "undefined";
|
||||
QTest::newRow("object=null") << "object" << "null";
|
||||
QTest::newRow("object=false") << "object" << "false";
|
||||
QTest::newRow("object=true") << "object" << "true";
|
||||
QTest::newRow("object=123") << "object" << "123";
|
||||
QTest::newRow("object=42.35") << "object" << "42.35";
|
||||
QTest::newRow("object='foo'") << "object" << "'foo'";
|
||||
QTest::newRow("object=[]") << "object" << "[]";
|
||||
QTest::newRow("object=function") << "object" << "(function(){})";
|
||||
|
||||
QTest::newRow("array=undefined") << "array" << "undefined";
|
||||
QTest::newRow("array=null") << "array" << "null";
|
||||
QTest::newRow("array=false") << "array" << "false";
|
||||
QTest::newRow("array=true") << "array" << "true";
|
||||
QTest::newRow("array=123") << "array" << "123";
|
||||
QTest::newRow("array=42.35") << "array" << "42.35";
|
||||
QTest::newRow("array='foo'") << "array" << "'foo'";
|
||||
QTest::newRow("array={}") << "array" << "{}";
|
||||
QTest::newRow("array=function") << "array" << "(function(){})";
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeProperty_incompatibleType()
|
||||
{
|
||||
QFETCH(QString, property);
|
||||
QFETCH(QString, expression);
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
|
||||
QJSValue ret = eng.evaluate(QString::fromLatin1("obj.%0 = %1")
|
||||
.arg(property).arg(expression));
|
||||
QEXPECT_FAIL("value=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort);
|
||||
QEXPECT_FAIL("object=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort);
|
||||
QEXPECT_FAIL("array=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort);
|
||||
QVERIFY(ret.isError());
|
||||
QVERIFY(ret.toString().contains("Cannot assign"));
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeProperty_javascriptExpression_data()
|
||||
{
|
||||
QTest::addColumn<QString>("property");
|
||||
QTest::addColumn<QString>("expression");
|
||||
QTest::addColumn<QString>("expectedJson");
|
||||
|
||||
// Function properties should be omitted.
|
||||
QTest::newRow("value = object with function property")
|
||||
<< "value" << "{ foo: function() {} }" << "{}";
|
||||
QTest::newRow("object = object with function property")
|
||||
<< "object" << "{ foo: function() {} }" << "{}";
|
||||
QTest::newRow("array = array with function property")
|
||||
<< "array" << "[function() {}]" << "[]";
|
||||
|
||||
// Inherited properties should not be included.
|
||||
QTest::newRow("value = object with inherited property")
|
||||
<< "value" << "{ __proto__: { proto_foo: 123 } }"
|
||||
<< "{}";
|
||||
QTest::newRow("value = object with inherited property 2")
|
||||
<< "value" << "{ foo: 123, __proto__: { proto_foo: 456 } }"
|
||||
<< "{\"foo\":123}";
|
||||
QTest::newRow("value = array with inherited property")
|
||||
<< "value" << "(function() { var a = []; a.__proto__ = { proto_foo: 123 }; return a; })()"
|
||||
<< "[]";
|
||||
QTest::newRow("value = array with inherited property 2")
|
||||
<< "value" << "(function() { var a = [10, 20]; a.__proto__ = { proto_foo: 123 }; return a; })()"
|
||||
<< "[10,20]";
|
||||
|
||||
QTest::newRow("object = object with inherited property")
|
||||
<< "object" << "{ __proto__: { proto_foo: 123 } }"
|
||||
<< "{}";
|
||||
QTest::newRow("object = object with inherited property 2")
|
||||
<< "object" << "{ foo: 123, __proto__: { proto_foo: 456 } }"
|
||||
<< "{\"foo\":123}";
|
||||
QTest::newRow("array = array with inherited property")
|
||||
<< "array" << "(function() { var a = []; a.__proto__ = { proto_foo: 123 }; return a; })()"
|
||||
<< "[]";
|
||||
QTest::newRow("array = array with inherited property 2")
|
||||
<< "array" << "(function() { var a = [10, 20]; a.__proto__ = { proto_foo: 123 }; return a; })()"
|
||||
<< "[10,20]";
|
||||
|
||||
// Non-enumerable properties should be included.
|
||||
QTest::newRow("value = object with non-enumerable property")
|
||||
<< "value" << "Object.defineProperty({}, 'foo', { value: 123, enumerable: false })"
|
||||
<< "{\"foo\":123}";
|
||||
QTest::newRow("object = object with non-enumerable property")
|
||||
<< "object" << "Object.defineProperty({}, 'foo', { value: 123, enumerable: false })"
|
||||
<< "{\"foo\":123}";
|
||||
|
||||
// Cyclic data structures are permitted, but the cyclic links become
|
||||
// empty objects.
|
||||
QTest::newRow("value = cyclic object")
|
||||
<< "value" << "(function() { var o = { foo: 123 }; o.o = o; return o; })()"
|
||||
<< "{\"foo\":123,\"o\":{}}";
|
||||
QTest::newRow("value = cyclic array")
|
||||
<< "value" << "(function() { var a = [10, 20]; a.push(a); return a; })()"
|
||||
<< "[10,20,[]]";
|
||||
QTest::newRow("object = cyclic object")
|
||||
<< "object" << "(function() { var o = { bar: true }; o.o = o; return o; })()"
|
||||
<< "{\"bar\":true,\"o\":{}}";
|
||||
QTest::newRow("array = cyclic array")
|
||||
<< "array" << "(function() { var a = [30, 40]; a.unshift(a); return a; })()"
|
||||
<< "[[],30,40]";
|
||||
|
||||
// Properties with undefined value are excluded.
|
||||
QTest::newRow("value = { foo: undefined }")
|
||||
<< "value" << "{ foo: undefined }" << "{}";
|
||||
QTest::newRow("value = { foo: undefined, bar: 123 }")
|
||||
<< "value" << "{ foo: undefined, bar: 123 }" << "{\"bar\":123}";
|
||||
QTest::newRow("value = { foo: 456, bar: undefined }")
|
||||
<< "value" << "{ foo: 456, bar: undefined }" << "{\"foo\":456}";
|
||||
|
||||
QTest::newRow("object = { foo: undefined }")
|
||||
<< "object" << "{ foo: undefined }" << "{}";
|
||||
QTest::newRow("object = { foo: undefined, bar: 123 }")
|
||||
<< "object" << "{ foo: undefined, bar: 123 }" << "{\"bar\":123}";
|
||||
QTest::newRow("object = { foo: 456, bar: undefined }")
|
||||
<< "object" << "{ foo: 456, bar: undefined }" << "{\"foo\":456}";
|
||||
|
||||
// QJsonArray::append() implicitly converts undefined values to null.
|
||||
QTest::newRow("value = [undefined]")
|
||||
<< "value" << "[undefined]" << "[null]";
|
||||
QTest::newRow("value = [undefined, 10]")
|
||||
<< "value" << "[undefined, 10]" << "[null,10]";
|
||||
QTest::newRow("value = [10, undefined, 20]")
|
||||
<< "value" << "[10, undefined, 20]" << "[10,null,20]";
|
||||
|
||||
QTest::newRow("array = [undefined]")
|
||||
<< "array" << "[undefined]" << "[null]";
|
||||
QTest::newRow("array = [undefined, 10]")
|
||||
<< "array" << "[undefined, 10]" << "[null,10]";
|
||||
QTest::newRow("array = [10, undefined, 20]")
|
||||
<< "array" << "[10, undefined, 20]" << "[10,null,20]";
|
||||
}
|
||||
|
||||
void tst_qjsonbinding::writeProperty_javascriptExpression()
|
||||
{
|
||||
QFETCH(QString, property);
|
||||
QFETCH(QString, expression);
|
||||
QFETCH(QString, expectedJson);
|
||||
|
||||
QJSEngine eng;
|
||||
JsonPropertyObject obj;
|
||||
eng.globalObject().setProperty("obj", eng.newQObject(&obj));
|
||||
|
||||
QJSValue ret = eng.evaluate(QString::fromLatin1("obj.%0 = %1; JSON.stringify(obj.%0)")
|
||||
.arg(property).arg(expression));
|
||||
QVERIFY(!ret.isError());
|
||||
QCOMPARE(ret.toString(), expectedJson);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qjsonbinding)
|
||||
|
||||
#include "tst_qjsonbinding.moc"
|
|
@ -8,6 +8,7 @@ PUBLICTESTS += \
|
|||
qjsengine \
|
||||
qjsvalue \
|
||||
qjsvalueiterator \
|
||||
qjsonbinding \
|
||||
qmlmin \
|
||||
qmlplugindump \
|
||||
qqmlcomponent \
|
||||
|
|
Loading…
Reference in New Issue