Browse Source

added datasync and more qml tests

pull/2/head
Skycoder42 6 years ago
parent
commit
392a5fd64e
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 1
      .gitignore
  2. 2
      src/imports/mvvmdatasyncquick/ChangeRemoteView11.qml
  3. 8
      src/mvvmcore/binding.cpp
  4. 2
      src/mvvmcore/binding.h
  5. 3
      src/mvvmcore/binding_p.h
  6. 13
      src/mvvmdatasynccore/datasyncsettingsaccessor.cpp
  7. 3
      src/mvvmdatasynccore/datasyncsettingsaccessor.h
  8. 5
      src/mvvmdatasyncwidgets/changeremotedialog.ui
  9. 5
      tests/auto/auto.pro
  10. 14
      tests/auto/mvvmdatasynccore/datasyncsettingsaccessor/datasyncsettingsaccessor.pro
  11. 57
      tests/auto/mvvmdatasynccore/datasyncsettingsaccessor/tst_datasyncsettingsaccessor.cpp
  12. 4
      tests/auto/mvvmdatasynccore/mvvmdatasynccore.pro
  13. 3
      tests/auto/qml/qml.pro
  14. 16
      tests/auto/qml/qmlmvvmcore/qmlmvvmcore.pro
  15. 4
      tests/auto/qml/qmlmvvmcore/tst_qmlmvvmcore.cpp
  16. 61
      tests/auto/qml/qmlmvvmcore/tst_qmlmvvmcore.qml
  17. 59
      tests/auto/settings.xml
  18. 53
      tests/shared/tst_isettingsaccessor.h

1
.gitignore

@ -79,3 +79,4 @@ qpmx.user.json
.qpmx-dev-cache .qpmx-dev-cache
qpmx.json.user qpmx.json.user
*.pro.dummy *.pro.dummy
*.qmlc

2
src/imports/mvvmdatasyncquick/ChangeRemoteView11.qml

@ -69,6 +69,7 @@ Page {
id: _urlEdit id: _urlEdit
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "wss://example.org/qdsapp/"
validator: UrlValidator { validator: UrlValidator {
allowedSchemes: ["ws", "wss"] allowedSchemes: ["ws", "wss"]
} }
@ -92,6 +93,7 @@ Page {
id: _accessKeyEdit id: _accessKeyEdit
Layout.fillWidth: true Layout.fillWidth: true
echoMode: TextInput.Password echoMode: TextInput.Password
placeholderText: "Optional access secret"
MvvmBinding { MvvmBinding {
viewModel: _changeRemoteView.viewModel viewModel: _changeRemoteView.viewModel

8
src/mvvmcore/binding.cpp

@ -108,6 +108,10 @@ Binding::operator bool() const
void Binding::unbind() void Binding::unbind()
{ {
if(d) { if(d) {
if(d->modelToViewConnection)
QObject::disconnect(d->modelToViewConnection);
if(d->viewToModelConnection)
QObject::disconnect(d->viewToModelConnection);
d->deleteLater(); d->deleteLater();
d.clear(); d.clear();
} }
@ -165,7 +169,7 @@ void BindingPrivate::bindFrom(QMetaMethod changeSignal)
changeSignal = viewModelProperty.notifySignal(); changeSignal = viewModelProperty.notifySignal();
} }
auto trigger = metaObject()->method(metaObject()->indexOfSlot("viewModelTrigger()")); auto trigger = metaObject()->method(metaObject()->indexOfSlot("viewModelTrigger()"));
connect(viewModel, changeSignal, this, trigger); modelToViewConnection = connect(viewModel, changeSignal, this, trigger);
} }
void BindingPrivate::bindTo(QMetaMethod changeSignal) void BindingPrivate::bindTo(QMetaMethod changeSignal)
@ -177,7 +181,7 @@ void BindingPrivate::bindTo(QMetaMethod changeSignal)
changeSignal = viewProperty.notifySignal(); changeSignal = viewProperty.notifySignal();
} }
auto trigger = metaObject()->method(metaObject()->indexOfSlot("viewTrigger()")); auto trigger = metaObject()->method(metaObject()->indexOfSlot("viewTrigger()"));
connect(view, changeSignal, this, trigger); viewToModelConnection = connect(view, changeSignal, this, trigger);
} }
void BindingPrivate::testReadable(const QMetaProperty &property, bool asView) const void BindingPrivate::testReadable(const QMetaProperty &property, bool asView) const

2
src/mvvmcore/binding.h

@ -39,7 +39,7 @@ public:
Q_INVOKABLE void unbind(); Q_INVOKABLE void unbind();
private: private:
QPointer<QObject> d; QPointer<BindingPrivate> d;
}; };
//! Create a multidirectional binding between properties //! Create a multidirectional binding between properties

3
src/mvvmcore/binding_p.h

@ -38,6 +38,9 @@ private:
QMetaProperty viewModelProperty; QMetaProperty viewModelProperty;
QMetaProperty viewProperty; QMetaProperty viewProperty;
QMetaObject::Connection modelToViewConnection;
QMetaObject::Connection viewToModelConnection;
void testReadable(const QMetaProperty &property, bool asView) const; void testReadable(const QMetaProperty &property, bool asView) const;
void testWritable(const QMetaProperty &property, bool asView) const; void testWritable(const QMetaProperty &property, bool asView) const;
void testNotifier(const QMetaProperty &property, bool asView) const; void testNotifier(const QMetaProperty &property, bool asView) const;

13
src/mvvmdatasynccore/datasyncsettingsaccessor.cpp

@ -29,7 +29,10 @@ DataSyncSettingsAccessor::DataSyncSettingsAccessor(QtDataSync::DataStore *store,
DataSyncSettingsAccessor::DataSyncSettingsAccessor(QtDataSync::DataTypeStore<DataSyncSettingsEntry> *store, QObject *parent) : DataSyncSettingsAccessor::DataSyncSettingsAccessor(QtDataSync::DataTypeStore<DataSyncSettingsEntry> *store, QObject *parent) :
ISettingsAccessor{parent}, ISettingsAccessor{parent},
d{new DataSyncSettingsAccessorPrivate{store}} d{new DataSyncSettingsAccessorPrivate{store}}
{} {
connect(d->store, &QtDataSync::DataTypeStoreBase::dataChanged,
this, &DataSyncSettingsAccessor::dataChanged);
}
DataSyncSettingsAccessor::~DataSyncSettingsAccessor() = default; DataSyncSettingsAccessor::~DataSyncSettingsAccessor() = default;
@ -89,6 +92,14 @@ void DataSyncSettingsAccessor::sync()
// nothing needs to be done // nothing needs to be done
} }
void DataSyncSettingsAccessor::dataChanged(const QString &key, const QVariant &value)
{
if(value.isValid())
emit entryChanged(key, value.value<DataSyncSettingsEntry>().value());
else
emit entryRemoved(key);
}
// ------------- Private Implementation ------------- // ------------- Private Implementation -------------
DataSyncSettingsAccessorPrivate::DataSyncSettingsAccessorPrivate(QtDataSync::DataTypeStore<DataSyncSettingsEntry> *store) : DataSyncSettingsAccessorPrivate::DataSyncSettingsAccessorPrivate(QtDataSync::DataTypeStore<DataSyncSettingsEntry> *store) :

3
src/mvvmdatasynccore/datasyncsettingsaccessor.h

@ -31,6 +31,9 @@ public:
public Q_SLOTS: public Q_SLOTS:
void sync() override; void sync() override;
private Q_SLOTS:
void dataChanged(const QString &key, const QVariant &value);
private: private:
QScopedPointer<DataSyncSettingsAccessorPrivate> d; QScopedPointer<DataSyncSettingsAccessorPrivate> d;
}; };

5
src/mvvmdatasyncwidgets/changeremotedialog.ui

@ -218,7 +218,10 @@
<normaloff>:/de/skycoder42/qtmvvm/widgets/icons/remove.ico</normaloff>:/de/skycoder42/qtmvvm/widgets/icons/remove.ico</iconset> <normaloff>:/de/skycoder42/qtmvvm/widgets/icons/remove.ico</normaloff>:/de/skycoder42/qtmvvm/widgets/icons/remove.ico</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Remove Selected Header</string> <string>&amp;Remove Header</string>
</property>
<property name="toolTip">
<string>Remove selected Header</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Del</string> <string>Del</string>

5
tests/auto/auto.pro

@ -3,3 +3,8 @@ TEMPLATE = subdirs
SUBDIRS += cmake \ SUBDIRS += cmake \
mvvmcore \ mvvmcore \
qml qml
qtHaveModule(datasync) {
SUBDIRS += \
mvvmdatasynccore
}

14
tests/auto/mvvmdatasynccore/datasyncsettingsaccessor/datasyncsettingsaccessor.pro

@ -0,0 +1,14 @@
TEMPLATE = app
QT += testlib mvvmdatasynccore
QT -= gui
CONFIG += console
CONFIG -= app_bundle
TARGET = tst_datasyncsettingsaccessor
HEADERS += \
../../../shared/tst_isettingsaccessor.h
SOURCES += \
tst_datasyncsettingsaccessor.cpp

57
tests/auto/mvvmdatasynccore/datasyncsettingsaccessor/tst_datasyncsettingsaccessor.cpp

@ -0,0 +1,57 @@
#include <QtTest>
#include <QtMvvmDataSyncCore/DataSyncSettingsAccessor>
#include <QtDataSync/Setup>
#include "../../../shared/tst_isettingsaccessor.h"
using namespace QtDataSync;
using namespace QtMvvm;
class DataSyncSettingsAccessorTest : public ISettingsAccessorTest
{
Q_OBJECT
protected:
ISettingsAccessor *createFirst() override;
ISettingsAccessor *createSecond() override;
bool testSyncChangeSignals() override;
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private:
QTemporaryDir tDir;
};
ISettingsAccessor *DataSyncSettingsAccessorTest::createFirst()
{
return new DataSyncSettingsAccessor{this};
}
ISettingsAccessor *DataSyncSettingsAccessorTest::createSecond()
{
return new DataSyncSettingsAccessor{this};
}
bool DataSyncSettingsAccessorTest::testSyncChangeSignals()
{
return true;
}
void DataSyncSettingsAccessorTest::initTestCase()
{
Setup{}.setLocalDir(tDir.path())
.setKeyStoreProvider(QStringLiteral("plain"))
.create();
}
void DataSyncSettingsAccessorTest::cleanupTestCase()
{
delete first;
delete second;
Setup::removeSetup(DefaultSetup, true);
tDir.remove();
}
QTEST_MAIN(DataSyncSettingsAccessorTest)
#include "tst_datasyncsettingsaccessor.moc"

4
tests/auto/mvvmdatasynccore/mvvmdatasynccore.pro

@ -0,0 +1,4 @@
TEMPLATE = subdirs
SUBDIRS += \
datasyncsettingsaccessor

3
tests/auto/qml/qml.pro

@ -1,6 +1,7 @@
TEMPLATE = subdirs TEMPLATE = subdirs
SUBDIRS += \ SUBDIRS += \
qmlsettingsgenerator qmlsettingsgenerator \
qmlmvvmcore
equals(MSVC_VER, 14.0): SUBDIRS -= qmlsettingsgenerator equals(MSVC_VER, 14.0): SUBDIRS -= qmlsettingsgenerator

16
tests/auto/qml/qmlmvvmcore/qmlmvvmcore.pro

@ -0,0 +1,16 @@
TEMPLATE = app
QT += testlib mvvmcore qml
CONFIG += qmltestcase console
CONFIG -= app_bundle
TARGET = tst_qmlmvvmcore
SOURCES += \
tst_qmlmvvmcore.cpp
DISTFILES += \
tst_qmlmvvmcore.qml
importFiles.path = .
DEPLOYMENT += importFiles

4
tests/auto/qml/qmlmvvmcore/tst_qmlmvvmcore.cpp

@ -0,0 +1,4 @@
#include <QtCore>
#include <QtQuickTest/quicktest.h>
QUICK_TEST_MAIN(qmlmvvmcore)

61
tests/auto/qml/qmlmvvmcore/tst_qmlmvvmcore.qml

@ -0,0 +1,61 @@
import QtQuick 2.10
import de.skycoder42.QtMvvm.Core 1.1
import QtTest 1.1
Item {
id: root
TestCase {
name: "Binding"
QtObject {
id: obj
property int prop1: 42
property int prop2: 0
}
MvvmBinding {
id: bind
viewModel: obj
view: obj
viewModelProperty: "prop1"
viewProperty: "prop2"
type: MvvmBinding.SingleInit
}
function test_1_SingleInit() {
verify(bind.isValid());
compare(obj.prop1, 42);
compare(obj.prop2, 42);
obj.prop1 = 24;
compare(obj.prop2, 42);
obj.prop2 = 44;
compare(obj.prop1, 24);
}
function test_2_OneWayToView() {
bind.type = MvvmBinding.OneWayToView
obj.prop1 = 33;
compare(obj.prop2, 33);
obj.prop2 = 44;
compare(obj.prop1, 33);
}
function test_3_OneWayToViewModel() {
bind.type = MvvmBinding.OneWayToViewModel
obj.prop2 = 45;
compare(obj.prop1, 45);
obj.prop1 = 22;
compare(obj.prop2, 45);
}
function test_4_TwoWay() {
bind.type = MvvmBinding.TwoWay
obj.prop1 = 78;
compare(obj.prop2, 78);
obj.prop2 = 87;
compare(obj.prop1, 87);
}
}
}

59
tests/auto/settings.xml

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<SettingsConfig allowSearch="true" allowRestore="true">
<Include optional="true">/absolute/include/path.xml</Include>
<Include optional="false">../relative/include/path.xml</Include>
<Category title="title"
icon="file:///icon/path.svg"
tooltip="useful tip"
frontends="widgets|quick"
selectors="ios|android&amp;xhdpi">
<Include optional="true">/absolute/include/path.xml</Include>
<Include>../relative/include/path.xml</Include>
<Section title="another title"
icon="https://example.org/icon/path.svg"
tooltip="another tip"
frontends="widgets"
selectors="android&amp;xhdpi">
<Include optional="true">/absolute/include/path.xml</Include>
<Include>../relative/include/path.xml</Include>
<Group title="group title"
tooltip="hovering tool tip"
frontends="quick"
selectors="ios|android">
<Include optional="true">/absolute/include/path.xml</Include>
<Include>../relative/include/path.xml</Include>
<Entry key="property"
type="bool"
title="&amp;Check me"
tooltip="I am a checkbox!"
default="false"
frontends="widgets|quick"
selectors="ios|android&amp;xhdpi">
<SearchKey>prop</SearchKey>
<SearchKey>attrib</SearchKey>
<SearchKey>sample</SearchKey>
<Property key="text" type="string">Please do check me</Property>
<Property key="size" type="object">
<Property key="width" type="int">42</Property>
<Property key="height" type="int">42</Property>
</Property>
<Property key="things" type="list">
<Element type="int">42</Element>
<Element type="list">
<Element type="string">elem 1</Element>
<Element type="string">elem 2</Element>
</Element>
<Element type="object">
<Property key="name" type="string">baum</Property>
<Property key="number" type="int">42</Property>
</Element>
</Property>
</Entry>
<Entry key="req" type="req" title="req" />
</Group>
<Group/>
</Section>
<Section/>
</Category>
<Category/>
</SettingsConfig>

53
tests/shared/tst_isettingsaccessor.h

@ -10,7 +10,8 @@ class ISettingsAccessorTest : public QObject
Q_OBJECT Q_OBJECT
protected: protected:
QtMvvm::ISettingsAccessor *accessor = nullptr; QtMvvm::ISettingsAccessor *first = nullptr;
QtMvvm::ISettingsAccessor *second = nullptr;
virtual QtMvvm::ISettingsAccessor *createFirst() = 0; virtual QtMvvm::ISettingsAccessor *createFirst() = 0;
virtual QtMvvm::ISettingsAccessor *createSecond() = 0; virtual QtMvvm::ISettingsAccessor *createSecond() = 0;
@ -18,23 +19,23 @@ protected:
private Q_SLOTS: private Q_SLOTS:
void testAccessorValid() { void testAccessorValid() {
accessor = createFirst(); first = createFirst();
QVERIFY(accessor); QVERIFY(first);
} }
void testSimpleOperations() { void testSimpleOperations() {
QSignalSpy changedSpy{accessor, &QtMvvm::ISettingsAccessor::entryChanged}; QSignalSpy changedSpy{first, &QtMvvm::ISettingsAccessor::entryChanged};
QSignalSpy removedSpy{accessor, &QtMvvm::ISettingsAccessor::entryRemoved}; QSignalSpy removedSpy{first, &QtMvvm::ISettingsAccessor::entryRemoved};
auto key = QStringLiteral("test/key"); auto key = QStringLiteral("test/key");
QVERIFY(!accessor->contains(key)); QVERIFY(!first->contains(key));
QCOMPARE(accessor->load(key, 24).toInt(), 24); QCOMPARE(first->load(key, 24).toInt(), 24);
QVERIFY(changedSpy.isEmpty()); QVERIFY(changedSpy.isEmpty());
QVERIFY(removedSpy.isEmpty()); QVERIFY(removedSpy.isEmpty());
accessor->save(key, 42); first->save(key, 42);
QVERIFY(accessor->contains(key)); QVERIFY(first->contains(key));
QCOMPARE(accessor->load(key, 24).toInt(), 42); QCOMPARE(first->load(key, 24).toInt(), 42);
if(changedSpy.isEmpty()) if(changedSpy.isEmpty())
QVERIFY(changedSpy.wait()); QVERIFY(changedSpy.wait());
QCOMPARE(changedSpy.size(), 1); QCOMPARE(changedSpy.size(), 1);
@ -43,9 +44,9 @@ private Q_SLOTS:
QCOMPARE(changeEvent[1].toInt(), 42); QCOMPARE(changeEvent[1].toInt(), 42);
QVERIFY(removedSpy.isEmpty()); QVERIFY(removedSpy.isEmpty());
accessor->remove(key); first->remove(key);
QVERIFY(!accessor->contains(key)); QVERIFY(!first->contains(key));
QCOMPARE(accessor->load(key, 24).toInt(), 24); QCOMPARE(first->load(key, 24).toInt(), 24);
if(removedSpy.isEmpty()) if(removedSpy.isEmpty())
QVERIFY(removedSpy.wait()); QVERIFY(removedSpy.wait());
QCOMPARE(removedSpy.size(), 1); QCOMPARE(removedSpy.size(), 1);
@ -59,13 +60,13 @@ private Q_SLOTS:
auto key2 = QStringLiteral("group/key/subkey"); auto key2 = QStringLiteral("group/key/subkey");
auto key3 = QStringLiteral("group/key/subgroup/subkey"); auto key3 = QStringLiteral("group/key/subgroup/subkey");
accessor->save(key0, true); first->save(key0, true);
accessor->save(key1, true); first->save(key1, true);
accessor->save(key2, true); first->save(key2, true);
accessor->save(key3, true); first->save(key3, true);
QSignalSpy removedSpy{accessor, &QtMvvm::ISettingsAccessor::entryRemoved}; QSignalSpy removedSpy{first, &QtMvvm::ISettingsAccessor::entryRemoved};
accessor->remove(key1); first->remove(key1);
while(removedSpy.size() < 3) while(removedSpy.size() < 3)
QVERIFY(removedSpy.wait()); QVERIFY(removedSpy.wait());
@ -83,14 +84,14 @@ private Q_SLOTS:
} }
void testSync() { void testSync() {
auto second = createSecond(); second = createSecond();
QVERIFY(second); QVERIFY(second);
QSignalSpy changedSpy{second, &QtMvvm::ISettingsAccessor::entryChanged}; QSignalSpy changedSpy{second, &QtMvvm::ISettingsAccessor::entryChanged};
QSignalSpy removedSpy{accessor, &QtMvvm::ISettingsAccessor::entryRemoved}; QSignalSpy removedSpy{first, &QtMvvm::ISettingsAccessor::entryRemoved};
auto key = QStringLiteral("sync/key"); auto key = QStringLiteral("sync/key");
accessor->save(key, 13); first->save(key, 13);
accessor->sync(); first->sync();
second->sync(); second->sync();
if(!testSyncChangeSignals()) if(!testSyncChangeSignals())
QEXPECT_FAIL("", "The testes accessor does not support notifying changes over multiple instances", Continue); QEXPECT_FAIL("", "The testes accessor does not support notifying changes over multiple instances", Continue);
@ -100,13 +101,13 @@ private Q_SLOTS:
QCOMPARE(changedSpy.size(), 1); QCOMPARE(changedSpy.size(), 1);
auto changeEvent = changedSpy.takeFirst(); auto changeEvent = changedSpy.takeFirst();
QCOMPARE(changeEvent[0].toString(), key); QCOMPARE(changeEvent[0].toString(), key);
QCOMPARE(changeEvent[1].toInt(), 42); QCOMPARE(changeEvent[1].toInt(), 13);
} }
QCOMPARE(second->load(key, 24).toInt(), 13); QCOMPARE(second->load(key, 24).toInt(), 13);
second->remove(key); second->remove(key);
second->sync(); second->sync();
accessor->sync(); first->sync();
if(!testSyncChangeSignals()) if(!testSyncChangeSignals())
QEXPECT_FAIL("", "The testes accessor does not support notifying changes over multiple instances", Continue); QEXPECT_FAIL("", "The testes accessor does not support notifying changes over multiple instances", Continue);
if(removedSpy.isEmpty()) if(removedSpy.isEmpty())
@ -115,7 +116,7 @@ private Q_SLOTS:
QCOMPARE(removedSpy.size(), 1); QCOMPARE(removedSpy.size(), 1);
QCOMPARE(removedSpy.takeFirst()[0].toString(), key); QCOMPARE(removedSpy.takeFirst()[0].toString(), key);
} }
QCOMPARE(accessor->load(key, 24).toInt(), 24); QCOMPARE(first->load(key, 24).toInt(), 24);
} }
}; };

Loading…
Cancel
Save