diff options
Diffstat (limited to 'tests/auto')
224 files changed, 16643 insertions, 159 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index f8f15a3..869f1c4 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -5,9 +5,11 @@ TEMPLATE = subdirs headers SUBDIRS += bic \ + dynamicobject \ collections \ compile \ compilerwarnings \ + dynamicobject \ exceptionsafety \ macgui \ macplist \ @@ -437,3 +439,6 @@ contains(QT_CONFIG, webkit): SUBDIRS += \ qwebframe \ qwebpage +SUBDIRS += math3d + +contains(QT_CONFIG, declarative): SUBDIRS += declarative diff --git a/tests/auto/declarative/.gitignore b/tests/auto/declarative/.gitignore new file mode 100644 index 0000000..c8bbd2f --- /dev/null +++ b/tests/auto/declarative/.gitignore @@ -0,0 +1,3 @@ +tst_* +!tst_*.* +tst_*~ diff --git a/tests/auto/declarative/datetimeformatter/datetimeformatter.pro b/tests/auto/declarative/datetimeformatter/datetimeformatter.pro new file mode 100644 index 0000000..e3d6cd0 --- /dev/null +++ b/tests/auto/declarative/datetimeformatter/datetimeformatter.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_datetimeformatter.cpp diff --git a/tests/auto/declarative/datetimeformatter/tst_datetimeformatter.cpp b/tests/auto/declarative/datetimeformatter/tst_datetimeformatter.cpp new file mode 100644 index 0000000..4593033 --- /dev/null +++ b/tests/auto/declarative/datetimeformatter/tst_datetimeformatter.cpp @@ -0,0 +1,83 @@ +#include <qtest.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qmldatetimeformatter.h> + +class tst_datetimeformatter : public QObject +{ + Q_OBJECT +public: + tst_datetimeformatter() {} + +private slots: + void date(); + void time(); + void dateTime(); +}; + +void tst_datetimeformatter::date() +{ + QmlEngine engine; + QmlComponent formatterComponent(&engine, "<DateTimeFormatter date=\"2008-12-24\"/>"); + QmlDateTimeFormatter *formatter = qobject_cast<QmlDateTimeFormatter*>(formatterComponent.create()); + QVERIFY(formatter != 0); + + QDate date(2008,12,24); + QCOMPARE(formatter->dateText(),date.toString(Qt::SystemLocaleShortDate)); + + formatter->setLongStyle(true); + QCOMPARE(formatter->dateText(),date.toString(Qt::SystemLocaleLongDate)); + + formatter->setDateFormat("ddd MMMM d yy"); + QCOMPARE(formatter->dateText(),date.toString("ddd MMMM d yy")); + + QVERIFY(formatter->timeText().isEmpty()); + QVERIFY(formatter->dateTimeText().isEmpty()); +} + +void tst_datetimeformatter::time() +{ + QmlEngine engine; + QmlComponent formatterComponent(&engine, "<DateTimeFormatter time=\"14:15:38.200\"/>"); + QmlDateTimeFormatter *formatter = qobject_cast<QmlDateTimeFormatter*>(formatterComponent.create()); + QVERIFY(formatter != 0); + + QTime time(14,15,38,200); + + QCOMPARE(formatter->time(),time); + + QCOMPARE(formatter->timeText(),time.toString(Qt::SystemLocaleShortDate)); + + formatter->setLongStyle(true); + QCOMPARE(formatter->timeText(),time.toString(Qt::SystemLocaleLongDate)); + + formatter->setTimeFormat("H:m:s a"); + QCOMPARE(formatter->timeText(),time.toString("H:m:s a")); + + formatter->setTimeFormat("hh:mm:ss.zzz"); + QCOMPARE(formatter->timeText(),time.toString("hh:mm:ss.zzz")); + + QVERIFY(formatter->dateText().isEmpty()); + QVERIFY(formatter->dateTimeText().isEmpty()); +} + +void tst_datetimeformatter::dateTime() +{ + QmlEngine engine; + QmlComponent formatterComponent(&engine, "<DateTimeFormatter dateTime=\"1978-03-04T09:13:54\"/>"); + QmlDateTimeFormatter *formatter = qobject_cast<QmlDateTimeFormatter*>(formatterComponent.create()); + QVERIFY(formatter != 0); + + QDateTime dateTime(QDate(1978,03,04),QTime(9,13,54)); + QCOMPARE(formatter->dateTimeText(),dateTime.toString(Qt::SystemLocaleShortDate)); + + formatter->setLongStyle(true); + QCOMPARE(formatter->dateTimeText(),dateTime.toString(Qt::SystemLocaleLongDate)); + + formatter->setDateTimeFormat("M/d/yy H:m:s a"); + QCOMPARE(formatter->dateTimeText(),dateTime.toString("M/d/yy H:m:s a")); +} + +QTEST_MAIN(tst_datetimeformatter) + +#include "tst_datetimeformatter.moc" diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro new file mode 100644 index 0000000..b6e3584 --- /dev/null +++ b/tests/auto/declarative/declarative.pro @@ -0,0 +1,22 @@ +TEMPLATE = subdirs +SUBDIRS += datetimeformatter \ + numberformatter \ + qbindablemap \ + layouts \ + listview \ + pathview \ + qfxtext \ + qfxtextedit \ + simplecanvasitem \ + repeater \ + qmlparser \ + qmlbindengine \ + qmlmetaproperty \ + qmllist \ + qmllistaccessor \ + visual + +# Tests which should run in Pulse +PULSE_TESTS = $$SUBDIRS +PULSE_TESTS -= visual # All except 'visual' tests, allegedly too flaky + diff --git a/tests/auto/declarative/layouts/data/grid-margin.xml b/tests/auto/declarative/layouts/data/grid-margin.xml new file mode 100644 index 0000000..fe58eef --- /dev/null +++ b/tests/auto/declarative/layouts/data/grid-margin.xml @@ -0,0 +1,9 @@ +<Item width="640" height="480"> + <GridLayout columns="3" margin="8"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="green" width="20" height="50"/> + <Rect id="three" color="blue" width="50" height="20"/> + <Rect id="four" color="cyan" width="50" height="50"/> + <Rect id="five" color="magenta" width="10" height="10"/> + </GridLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/grid-spacing-margin.xml b/tests/auto/declarative/layouts/data/grid-spacing-margin.xml new file mode 100644 index 0000000..807b653 --- /dev/null +++ b/tests/auto/declarative/layouts/data/grid-spacing-margin.xml @@ -0,0 +1,9 @@ +<Item width="640" height="480"> + <GridLayout columns="3" spacing="4" margin="8"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="green" width="20" height="50"/> + <Rect id="three" color="blue" width="50" height="20"/> + <Rect id="four" color="cyan" width="50" height="50"/> + <Rect id="five" color="magenta" width="10" height="10"/> + </GridLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/grid-spacing.xml b/tests/auto/declarative/layouts/data/grid-spacing.xml new file mode 100644 index 0000000..55ef5a5 --- /dev/null +++ b/tests/auto/declarative/layouts/data/grid-spacing.xml @@ -0,0 +1,9 @@ +<Item width="640" height="480"> + <GridLayout columns="3" spacing="4"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="green" width="20" height="50"/> + <Rect id="three" color="blue" width="50" height="20"/> + <Rect id="four" color="cyan" width="50" height="50"/> + <Rect id="five" color="magenta" width="10" height="10"/> + </GridLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/grid.xml b/tests/auto/declarative/layouts/data/grid.xml new file mode 100644 index 0000000..abef813 --- /dev/null +++ b/tests/auto/declarative/layouts/data/grid.xml @@ -0,0 +1,9 @@ +<Item width="640" height="480"> + <GridLayout columns="3"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="green" width="20" height="50"/> + <Rect id="three" color="blue" width="50" height="20"/> + <Rect id="four" color="cyan" width="50" height="50"/> + <Rect id="five" color="magenta" width="10" height="10"/> + </GridLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/horizontal-margin.xml b/tests/auto/declarative/layouts/data/horizontal-margin.xml new file mode 100644 index 0000000..7ee9706 --- /dev/null +++ b/tests/auto/declarative/layouts/data/horizontal-margin.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <HorizontalLayout margin="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </HorizontalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/horizontal-spacing-margin.xml b/tests/auto/declarative/layouts/data/horizontal-spacing-margin.xml new file mode 100644 index 0000000..8767818 --- /dev/null +++ b/tests/auto/declarative/layouts/data/horizontal-spacing-margin.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <HorizontalLayout spacing="5" margin="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </HorizontalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/horizontal-spacing.xml b/tests/auto/declarative/layouts/data/horizontal-spacing.xml new file mode 100644 index 0000000..cb58711 --- /dev/null +++ b/tests/auto/declarative/layouts/data/horizontal-spacing.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <HorizontalLayout spacing="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </HorizontalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/horizontal.xml b/tests/auto/declarative/layouts/data/horizontal.xml new file mode 100644 index 0000000..f9deaf1 --- /dev/null +++ b/tests/auto/declarative/layouts/data/horizontal.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <HorizontalLayout> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </HorizontalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/vertical-margin.xml b/tests/auto/declarative/layouts/data/vertical-margin.xml new file mode 100644 index 0000000..abd7635 --- /dev/null +++ b/tests/auto/declarative/layouts/data/vertical-margin.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <VerticalLayout margin="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </VerticalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/vertical-spacing-margin.xml b/tests/auto/declarative/layouts/data/vertical-spacing-margin.xml new file mode 100644 index 0000000..3d41ca0 --- /dev/null +++ b/tests/auto/declarative/layouts/data/vertical-spacing-margin.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <VerticalLayout spacing="5" margin="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </VerticalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/vertical-spacing.xml b/tests/auto/declarative/layouts/data/vertical-spacing.xml new file mode 100644 index 0000000..e25f981 --- /dev/null +++ b/tests/auto/declarative/layouts/data/vertical-spacing.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <VerticalLayout spacing="10"> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </VerticalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/data/vertical.xml b/tests/auto/declarative/layouts/data/vertical.xml new file mode 100644 index 0000000..198d99f --- /dev/null +++ b/tests/auto/declarative/layouts/data/vertical.xml @@ -0,0 +1,7 @@ +<Item width="640" height="480"> + <VerticalLayout> + <Rect id="one" color="red" width="50" height="50"/> + <Rect id="two" color="red" width="20" height="10"/> + <Rect id="three" color="red" width="40" height="20"/> + </VerticalLayout> +</Item> diff --git a/tests/auto/declarative/layouts/layouts.pro b/tests/auto/declarative/layouts/layouts.pro new file mode 100644 index 0000000..f7e7622 --- /dev/null +++ b/tests/auto/declarative/layouts/layouts.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_layouts.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/layouts/tst_layouts.cpp b/tests/auto/declarative/layouts/tst_layouts.cpp new file mode 100644 index 0000000..ad6a0b2 --- /dev/null +++ b/tests/auto/declarative/layouts/tst_layouts.cpp @@ -0,0 +1,392 @@ +#include <QtTest/QtTest> +#include <qlistmodelinterface.h> +#include <qfxview.h> +#include <qfxrect.h> +#include <qmlexpression.h> + +class tst_QFxLayouts : public QObject +{ + Q_OBJECT +public: + tst_QFxLayouts(); + +private slots: + void test_horizontal(); + void test_horizontal_spacing(); + void test_horizontal_margin(); + void test_horizontal_spacing_margin(); + void test_vertical(); + void test_vertical_spacing(); + void test_vertical_margin(); + void test_vertical_spacing_margin(); + void test_grid(); + void test_grid_spacing(); + void test_grid_margin(); + void test_grid_spacing_margin(); + +private: + QFxView *createView(const QString &filename); + template<typename T> + T *findItem(QFxItem *parent, const QString &id, int index=0); +}; + +tst_QFxLayouts::tst_QFxLayouts() +{ +} + +void tst_QFxLayouts::test_horizontal() +{ + QFxView *canvas = createView(SRCDIR "/data/horizontal.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); +} + +void tst_QFxLayouts::test_horizontal_spacing() +{ + QFxView *canvas = createView(SRCDIR "/data/horizontal-spacing.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 60.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 90.0); + QCOMPARE(three->y(), 0.0); +} + +void tst_QFxLayouts::test_horizontal_margin() +{ + QFxView *canvas = createView(SRCDIR "/data/horizontal-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 10.0); + QCOMPARE(one->y(), 10.0); + QCOMPARE(two->x(), 60.0); + QCOMPARE(two->y(), 10.0); + QCOMPARE(three->x(), 80.0); + QCOMPARE(three->y(), 10.0); +} + +void tst_QFxLayouts::test_horizontal_spacing_margin() +{ + QFxView *canvas = createView(SRCDIR "/data/horizontal-spacing-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 10.0); + QCOMPARE(one->y(), 10.0); + QCOMPARE(two->x(), 65.0); + QCOMPARE(two->y(), 10.0); + QCOMPARE(three->x(), 90.0); + QCOMPARE(three->y(), 10.0); +} + +void tst_QFxLayouts::test_vertical() +{ + QFxView *canvas = createView(SRCDIR "/data/vertical.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 0.0); + QCOMPARE(two->y(), 50.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 60.0); +} + +void tst_QFxLayouts::test_vertical_spacing() +{ + QFxView *canvas = createView(SRCDIR "/data/vertical-spacing.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 0.0); + QCOMPARE(two->y(), 60.0); + QCOMPARE(three->x(), 0.0); + QCOMPARE(three->y(), 80.0); +} + +void tst_QFxLayouts::test_vertical_margin() +{ + QFxView *canvas = createView(SRCDIR "/data/vertical-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 10.0); + QCOMPARE(one->y(), 10.0); + QCOMPARE(two->x(), 10.0); + QCOMPARE(two->y(), 60.0); + QCOMPARE(three->x(), 10.0); + QCOMPARE(three->y(), 70.0); +} + +void tst_QFxLayouts::test_vertical_spacing_margin() +{ + QFxView *canvas = createView(SRCDIR "/data/vertical-spacing-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + + QCOMPARE(one->x(), 10.0); + QCOMPARE(one->y(), 10.0); + QCOMPARE(two->x(), 10.0); + QCOMPARE(two->y(), 65.0); + QCOMPARE(three->x(), 10.0); + QCOMPARE(three->y(), 80.0); +} + +void tst_QFxLayouts::test_grid() +{ + QFxView *canvas = createView("data/grid.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + QFxRect *four = findItem<QFxRect>(canvas->root(), "four"); + QVERIFY(four != 0); + QFxRect *five = findItem<QFxRect>(canvas->root(), "five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 50.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 70.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 50.0); + QCOMPARE(five->x(), 50.0); + QCOMPARE(five->y(), 50.0); +} + +void tst_QFxLayouts::test_grid_spacing() +{ + QFxView *canvas = createView("data/grid-spacing.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + QFxRect *four = findItem<QFxRect>(canvas->root(), "four"); + QVERIFY(four != 0); + QFxRect *five = findItem<QFxRect>(canvas->root(), "five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 0.0); + QCOMPARE(one->y(), 0.0); + QCOMPARE(two->x(), 54.0); + QCOMPARE(two->y(), 0.0); + QCOMPARE(three->x(), 78.0); + QCOMPARE(three->y(), 0.0); + QCOMPARE(four->x(), 0.0); + QCOMPARE(four->y(), 54.0); + QCOMPARE(five->x(), 54.0); + QCOMPARE(five->y(), 54.0); +} + +void tst_QFxLayouts::test_grid_margin() +{ + QFxView *canvas = createView("data/grid-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + QFxRect *four = findItem<QFxRect>(canvas->root(), "four"); + QVERIFY(four != 0); + QFxRect *five = findItem<QFxRect>(canvas->root(), "five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 8.0); + QCOMPARE(one->y(), 8.0); + QCOMPARE(two->x(), 58.0); + QCOMPARE(two->y(), 8.0); + QCOMPARE(three->x(), 78.0); + QCOMPARE(three->y(), 8.0); + QCOMPARE(four->x(), 8.0); + QCOMPARE(four->y(), 58.0); + QCOMPARE(five->x(), 58.0); + QCOMPARE(five->y(), 58.0); +} + + +void tst_QFxLayouts::test_grid_spacing_margin() +{ + QFxView *canvas = createView("data/grid-spacing-margin.xml"); + + canvas->execute(); + qApp->processEvents(); + + QFxRect *one = findItem<QFxRect>(canvas->root(), "one"); + QVERIFY(one != 0); + QFxRect *two = findItem<QFxRect>(canvas->root(), "two"); + QVERIFY(two != 0); + QFxRect *three = findItem<QFxRect>(canvas->root(), "three"); + QVERIFY(three != 0); + QFxRect *four = findItem<QFxRect>(canvas->root(), "four"); + QVERIFY(four != 0); + QFxRect *five = findItem<QFxRect>(canvas->root(), "five"); + QVERIFY(five != 0); + + QCOMPARE(one->x(), 8.0); + QCOMPARE(one->y(), 8.0); + QCOMPARE(two->x(), 62.0); + QCOMPARE(two->y(), 8.0); + QCOMPARE(three->x(), 86.0); + QCOMPARE(three->y(), 8.0); + QCOMPARE(four->x(), 8.0); + QCOMPARE(four->y(), 62.0); + QCOMPARE(five->x(), 62.0); + QCOMPARE(five->y(), 62.0); +} + +QFxView *tst_QFxLayouts::createView(const QString &filename) +{ + QFxView *canvas = new QFxView(0); + + QFile file(filename); + file.open(QFile::ReadOnly); + QString xml = file.readAll(); + canvas->setXml(xml, filename); + + return canvas; +} + +/* + Find an item with the specified id. If index is supplied then the + item must also evaluate the {index} expression equal to index +*/ +template<typename T> +T *tst_QFxLayouts::findItem(QFxItem *parent, const QString &id, int index) +{ + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->children()->count(); ++i) { + QFxItem *item = parent->children()->at(i); + if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { + if (index != -1) { + QmlExpression e(item->itemContext(), "index", item); + e.setTrackChange(false); + if (e.value().toInt() == index) + return static_cast<T*>(item); + } else { + return static_cast<T*>(item); + } + } + item = findItem<T>(item, id, index); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +QTEST_MAIN(tst_QFxLayouts) + +#include "tst_layouts.moc" diff --git a/tests/auto/declarative/listview/data/listview.xml b/tests/auto/declarative/listview/data/listview.xml new file mode 100644 index 0000000..7fda2b5 --- /dev/null +++ b/tests/auto/declarative/listview/data/listview.xml @@ -0,0 +1,14 @@ +<Rect width="240" height="320" color="#ffffff"> + <resources> + <Component id="Delegate"> + <Item id="wrapper" height="20" width="240"> + <Text text="{index}"/> + <Text x="30" id="textName" text="{name}"/> + <Text x="120" id="textNumber" text="{number}"/> + <Text x="200" text="{wrapper.y}"/> + </Item> + </Component> + </resources> + <ListView id="list" width="240" height="320" model="{testModel}" delegate="{Delegate}"> + </ListView> +</Rect> diff --git a/tests/auto/declarative/listview/listview.pro b/tests/auto/declarative/listview/listview.pro new file mode 100644 index 0000000..bf68268 --- /dev/null +++ b/tests/auto/declarative/listview/listview.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_listview.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/listview/tst_listview.cpp b/tests/auto/declarative/listview/tst_listview.cpp new file mode 100644 index 0000000..681af57 --- /dev/null +++ b/tests/auto/declarative/listview/tst_listview.cpp @@ -0,0 +1,484 @@ +#include <QtTest/QtTest> +#include <qlistmodelinterface.h> +#include <qfxview.h> +#include <qfxlistview.h> +#include <qfxtext.h> +#include <qmlcontext.h> +#include <qmlexpression.h> + +class tst_QFxListView : public QObject +{ + Q_OBJECT +public: + tst_QFxListView(); + +private slots: + // Test both QListModelInterface and QAbstractItemModel model types + void qListModelInterface_items(); + void qAbstractItemModel_items(); + + void qListModelInterface_changed(); + void qAbstractItemModel_changed(); + + void qListModelInterface_inserted(); + void qAbstractItemModel_inserted(); + + void qListModelInterface_removed(); + void qAbstractItemModel_removed(); + +private: + template <class T> void items(); + template <class T> void changed(); + template <class T> void inserted(); + template <class T> void removed(); + QFxView *createView(const QString &filename); + template<typename T> + T *findItem(QFxItem *parent, const QString &id, int index=0); +}; + +class TestModel : public QListModelInterface +{ + Q_OBJECT +public: + TestModel(QObject *parent = 0) : QListModelInterface(parent) {} + ~TestModel() {} + + enum Roles { Name, Number }; + + QString name(int index) const { return list.at(index).first; } + QString number(int index) const { return list.at(index).second; } + + int count() const { return list.count(); } + + QList<int> roles() const { return QList<int>() << Name << Number; } + QString toString(int role) const { + switch(role) { + case Name: + return "name"; + case Number: + return "number"; + default: + return ""; + } + } + + QHash<int, QVariant> data(int index, const QList<int> &roles) const { + QHash<int,QVariant> returnHash; + + for (int i = 0; i < roles.size(); ++i) { + int role = roles.at(i); + QVariant info; + switch(role) { + case Name: + info = list.at(index).first; + break; + case Number: + info = list.at(index).second; + break; + default: + break; + } + returnHash.insert(role, info); + } + return returnHash; + } + + void addItem(const QString &name, const QString &number) { + list.append(QPair<QString,QString>(name, number)); + emit itemsInserted(list.count()-1, 1); + } + + void insertItem(int index, const QString &name, const QString &number) { + list.insert(index, QPair<QString,QString>(name, number)); + emit itemsInserted(index, 1); + } + + void removeItem(int index) { + list.removeAt(index); + emit itemsRemoved(index, 1); + } + + void modifyItem(int index, const QString &name, const QString &number) { + list[index] = QPair<QString,QString>(name, number); + emit itemsChanged(index, 1, roles()); + } + +private: + QList<QPair<QString,QString> > list; +}; + + +class TestModel2 : public QAbstractListModel +{ +public: + enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 }; + + TestModel2(QObject *parent=0) : QAbstractListModel(parent) { + QHash<int, QByteArray> roles; + roles[Name] = "name"; + roles[Number] = "number"; + setRoleNames(roles); + } + + int rowCount(const QModelIndex &parent=QModelIndex()) const { return list.count(); } + QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const { + QVariant rv; + if (role == Name) + rv = list.at(index.row()).first; + else if (role == Number) + rv = list.at(index.row()).second; + + return rv; + } + + int count() const { return rowCount(); } + QString name(int index) const { return list.at(index).first; } + QString number(int index) const { return list.at(index).second; } + + void addItem(const QString &name, const QString &number) { + emit beginInsertRows(QModelIndex(), list.count(), list.count()); + list.append(QPair<QString,QString>(name, number)); + emit endInsertRows(); + } + + void insertItem(int index, const QString &name, const QString &number) { + emit beginInsertRows(QModelIndex(), index, index); + list.insert(index, QPair<QString,QString>(name, number)); + emit endInsertRows(); + } + + void removeItem(int index) { + emit beginRemoveRows(QModelIndex(), index, index); + list.removeAt(index); + emit endRemoveRows(); + } + + void modifyItem(int idx, const QString &name, const QString &number) { + list[idx] = QPair<QString,QString>(name, number); + emit dataChanged(index(idx,0), index(idx,0)); + } + +private: + QList<QPair<QString,QString> > list; +}; + +tst_QFxListView::tst_QFxListView() +{ +} + +template <class T> +void tst_QFxListView::items() +{ + QFxView *canvas = createView(SRCDIR "/data/listview.xml"); + + T model; + model.addItem("Fred", "12345"); + model.addItem("John", "2345"); + model.addItem("Bob", "54321"); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxFlickable *listview = findItem<QFxFlickable>(canvas->root(), "list"); + QVERIFY(listview != 0); + + QFxItem *viewport = listview->viewport(); + QVERIFY(viewport != 0); + + QCOMPARE(viewport->children()->count(), model.count()); // assumes all are visible + + for (int i = 0; i < model.count(); ++i) { + QFxText *name = findItem<QFxText>(viewport, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + QFxText *number = findItem<QFxText>(viewport, "textNumber", i); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(i)); + } + + delete canvas; +} + +template <class T> +void tst_QFxListView::changed() +{ + QFxView *canvas = createView(SRCDIR "/data/listview.xml"); + + T model; + model.addItem("Fred", "12345"); + model.addItem("John", "2345"); + model.addItem("Bob", "54321"); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxFlickable *listview = findItem<QFxFlickable>(canvas->root(), "list"); + QVERIFY(listview != 0); + + QFxItem *viewport = listview->viewport(); + QVERIFY(viewport != 0); + + model.modifyItem(1, "Will", "9876"); + QFxText *name = findItem<QFxText>(viewport, "textName", 1); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(1)); + QFxText *number = findItem<QFxText>(viewport, "textNumber", 1); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(1)); + + delete canvas; +} + +template <class T> +void tst_QFxListView::inserted() +{ + QFxView *canvas = createView(SRCDIR "/data/listview.xml"); + + T model; + model.addItem("Fred", "12345"); + model.addItem("John", "2345"); + model.addItem("Bob", "54321"); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxListView *listview = findItem<QFxListView>(canvas->root(), "list"); + QVERIFY(listview != 0); + + QFxItem *viewport = listview->viewport(); + QVERIFY(viewport != 0); + + model.insertItem(1, "Will", "9876"); + + // let transitions settle. + QTest::qWait(1000); + + QCOMPARE(viewport->children()->count(), model.count()); // assumes all are visible + + QFxText *name = findItem<QFxText>(viewport, "textName", 1); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(1)); + QFxText *number = findItem<QFxText>(viewport, "textNumber", 1); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(1)); + + // Confirm items positioned correctly + for (int i = 0; i < model.count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QVERIFY(item->y() == i*20); + } + + model.insertItem(0, "Foo", "1111"); // zero index, and current item + + // let transitions settle. + QTest::qWait(1000); + + QCOMPARE(viewport->children()->count(), model.count()); // assumes all are visible + + name = findItem<QFxText>(viewport, "textName", 0); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(0)); + number = findItem<QFxText>(viewport, "textNumber", 0); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(0)); + + QCOMPARE(listview->currentIndex(), 1); + + // Confirm items positioned correctly + for (int i = 0; i < model.count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QVERIFY(item->y() == i*20); + } + + delete canvas; +} + +template <class T> +void tst_QFxListView::removed() +{ + QFxView *canvas = createView(SRCDIR "/data/listview.xml"); + + T model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxListView *listview = findItem<QFxListView>(canvas->root(), "list"); + QVERIFY(listview != 0); + + QFxItem *viewport = listview->viewport(); + QVERIFY(viewport != 0); + + model.removeItem(1); + + // let transitions settle. + QTest::qWait(1000); + + QFxText *name = findItem<QFxText>(viewport, "textName", 1); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(1)); + QFxText *number = findItem<QFxText>(viewport, "textNumber", 1); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(1)); + + // Confirm items positioned correctly + for (int i = 0; i < model.count() && i < viewport->children()->count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QVERIFY(item->y() == i*20); + } + + // Remove first item (which is the current item); + model.removeItem(0); // post: top item starts at 20 + + // let transitions settle. + QTest::qWait(1000); + + name = findItem<QFxText>(viewport, "textName", 0); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(0)); + number = findItem<QFxText>(viewport, "textNumber", 0); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(0)); + + // Confirm items positioned correctly + for (int i = 0; i < model.count() && i < viewport->children()->count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QCOMPARE(item->y(),i*20.0 + 20.0); + } + + // Remove items not visible + model.removeItem(18); + // let transitions settle. + QTest::qWait(1000); + + // Confirm items positioned correctly + for (int i = 0; i < model.count() && i < viewport->children()->count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QCOMPARE(item->y(),i*20.0+20.0); + } + + // Remove items before visible + listview->setYPosition(80); + listview->setCurrentIndex(10); + + model.removeItem(1); // post: top item will be at 40 + // let transitions settle. + QTest::qWait(1000); + + // Confirm items positioned correctly + for (int i = 2; i < 18; ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QCOMPARE(item->y(),40+i*20.0); + } + + listview->setYPosition(40); // That's the top now + // let transitions settle. + QTest::qWait(1000); + + // Confirm items positioned correctly + for (int i = 0; i < model.count() && i < viewport->children()->count(); ++i) { + QFxItem *item = findItem<QFxItem>(viewport, "wrapper", i); + QCOMPARE(item->y(),40+i*20.0); + } + + delete canvas; +} + +void tst_QFxListView::qListModelInterface_items() +{ + items<TestModel>(); +} + +void tst_QFxListView::qAbstractItemModel_items() +{ + items<TestModel2>(); +} + +void tst_QFxListView::qListModelInterface_changed() +{ + changed<TestModel>(); +} + +void tst_QFxListView::qAbstractItemModel_changed() +{ + changed<TestModel2>(); +} + +void tst_QFxListView::qListModelInterface_inserted() +{ + inserted<TestModel>(); +} + +void tst_QFxListView::qAbstractItemModel_inserted() +{ + inserted<TestModel2>(); +} + +void tst_QFxListView::qListModelInterface_removed() +{ + removed<TestModel>(); +} + +void tst_QFxListView::qAbstractItemModel_removed() +{ + removed<TestModel2>(); +} + +QFxView *tst_QFxListView::createView(const QString &filename) +{ + QFxView *canvas = new QFxView(0); + canvas->setFixedSize(240,320); + + QFile file(filename); + file.open(QFile::ReadOnly); + QString xml = file.readAll(); + canvas->setXml(xml, filename); + + return canvas; +} + +/* + Find an item with the specified id. If index is supplied then the + item must also evaluate the {index} expression equal to index +*/ +template<typename T> +T *tst_QFxListView::findItem(QFxItem *parent, const QString &id, int index) +{ + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->children()->count(); ++i) { + QFxItem *item = parent->children()->at(i); + if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { + if (index != -1) { + QmlExpression e(item->itemContext(), "index", item); + e.setTrackChange(false); + if (e.value().toInt() == index) + return static_cast<T*>(item); + } else { + return static_cast<T*>(item); + } + } + item = findItem<T>(item, id, index); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +QTEST_MAIN(tst_QFxListView) + +#include "tst_listview.moc" diff --git a/tests/auto/declarative/namespaces/data/Red/Rect.qml b/tests/auto/declarative/namespaces/data/Red/Rect.qml new file mode 100644 index 0000000..c7b3d8c --- /dev/null +++ b/tests/auto/declarative/namespaces/data/Red/Rect.qml @@ -0,0 +1,2 @@ +<Text objectName="x" text="Pretending to be a Rect" color="red"> +</Text> diff --git a/tests/auto/declarative/namespaces/namespaces.pro b/tests/auto/declarative/namespaces/namespaces.pro new file mode 100644 index 0000000..f232770 --- /dev/null +++ b/tests/auto/declarative/namespaces/namespaces.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_namespaces.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/namespaces/tst_namespaces.cpp b/tests/auto/declarative/namespaces/tst_namespaces.cpp new file mode 100644 index 0000000..665651d --- /dev/null +++ b/tests/auto/declarative/namespaces/tst_namespaces.cpp @@ -0,0 +1,94 @@ +#include <qtest.h> +#include <QtDeclarative/qfxview.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qfxrect.h> +#include <QtDeclarative/qfxtext.h> +#include <QDir> + +class tst_namespaces : public QObject + +{ + Q_OBJECT +public: + tst_namespaces(); + +private slots: + void simple(); + void simple_data(); +}; + +tst_namespaces::tst_namespaces() +{ +} + +void tst_namespaces::simple_data() +{ + QTest::addColumn<QString>("qml"); + QTest::addColumn<bool>("valid"); + QTest::addColumn<QString>("texts"); + QTest::addColumn<QString>("rects"); + + QTest::newRow("Control") << + "<Rect objectName=\"a\">" + "<Rect objectName=\"b\"/>" + "</Rect>" + << true << "" << "ab"; + + QTest::newRow("Control2") << + "<Rect objectName=\"a\">" + "<Text objectName=\"b\"/>" + "</Rect>" + << true << "b" << "a"; + + QTest::newRow("Replace builtin") << + "<Rect objectName=\"a\" xmlns:rs=\"http://nokia.com/qml/Red\">" + "<rs:Rect objectName=\"b\"/>" + "</Rect>" + << true << "b" << "a"; +} + +void tst_namespaces::simple() +{ + QFETCH(QString, qml); + QFETCH(bool, valid); + QFETCH(QString, texts); + QFETCH(QString, rects); + + QFxView canvas(0); + canvas.rootContext()->engine()->addNameSpacePath("http://nokia.com/qml", SRCDIR "/data"); + canvas.setXml(qml); + canvas.execute(); + qApp->processEvents(); + + QFxItem *testObject = qobject_cast<QFxItem*>(canvas.root()); + + QCOMPARE((testObject != 0),valid); + + if (valid && testObject != 0) { + QString textids; + QList<QFxText*> textobjects = testObject->findChildren<QFxText*>(); + if (qobject_cast<QFxText*>(testObject)) + textids += testObject->objectName(); + foreach (QFxText *obj, textobjects) { + textids += obj->objectName(); + } + if (textids != texts) + testObject->dump(); + QCOMPARE(textids,texts); + + QString rectids; + QList<QFxRect*> rectobjects = testObject->findChildren<QFxRect*>(); + if (qobject_cast<QFxRect*>(testObject)) + rectids += testObject->objectName(); + foreach (QFxRect *obj, rectobjects) + rectids += obj->objectName(); + if (rectids != rects) + testObject->dump(); + QCOMPARE(rectids,rects); + } +} + +QTEST_MAIN(tst_namespaces) + +#include "tst_namespaces.moc" diff --git a/tests/auto/declarative/numberformatter/numberformatter.pro b/tests/auto/declarative/numberformatter/numberformatter.pro new file mode 100644 index 0000000..ba391ed --- /dev/null +++ b/tests/auto/declarative/numberformatter/numberformatter.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_numberformatter.cpp diff --git a/tests/auto/declarative/numberformatter/tst_numberformatter.cpp b/tests/auto/declarative/numberformatter/tst_numberformatter.cpp new file mode 100644 index 0000000..eaeab51 --- /dev/null +++ b/tests/auto/declarative/numberformatter/tst_numberformatter.cpp @@ -0,0 +1,216 @@ +#include <qtest.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qnumberformat.h> +#include <QtDeclarative/qmlnumberformatter.h> + +class tst_numberformat : public QObject +{ + Q_OBJECT +public: + tst_numberformat(); + + void init() {} + void initTestCase() {} + + void cleanup() {} + void cleanupTestCase() {} + +private slots: + void number_data(); + void number(); + + void text_data(); + void text(); + +private: + QStringList strings; + QList<float> numbers; + QStringList formats; + QStringList texts; +}; + +tst_numberformat::tst_numberformat() +{ + strings << "100.0" + << "12345" + << "1234567" + << "0.123" + << "0.9999" + << "0.989" + << "1" + << "1.0" + << "1.01"; + + numbers << 100 + << 12345 + << 1234567 + << 0.123 + << 0.9999 + << 0.989 + << 1 + << 1.0 + << 1.01; + + formats << "" + << "0000" + << "0000.00" + << "##" + << "##.##" + << "#0.00#" + << "##,##0.##" + << "(000) 000 - 000" + << "00000,000.0000"; + + //US locale only. + texts << "100.000000" + << "12345.000000" + << "1234567.000000" + << "0.123000" + << "0.999900" + << "0.989000" + << "1.000000" + << "1.000000" + << "1.010000" //end "" + << "0100" + << "12345" + << "1234567" + << "0000" + << "0001" + << "0001" + << "0001" + << "0001" + << "0001" // end "0000" + << "0100.00" + << "12345.00" + << "1234567.00" + << "0000.12" + << "0001.00" + << "0000.99" + << "0001.00" + << "0001.00" + << "0001.01" // end "0000.00" + << "100" + << "12345" + << "1234567" + << "0" + << "1" + << "1" + << "1" + << "1" + << "1" // end "##" + << "100"//start "##.##" + << "12345" + << "1234567" + << "0.12" + << "1" + << "0.99" + << "1" + << "1" + << "1.01" // end "##.##" -- ### EXPECT FAIL ### QNumberFormat::formatDecimal() bug + << "100.00" //start "#0.00#" + << "12345.00" + << "1234567.00" + << "0.123" + << "1.00" + << "0.989" + << "1.00" + << "1.00" + << "1.01" //end "#0.00#" + << "100" //start "##,##0.##" + << "12,345" + << "1,234,567" + << "0.12" + << "1" + << "0.99" + << "1" + << "1" + << "1.01" //end "##,##0.##" -- ### EXPECT FAIL ### QNumberFormat::formatDecimal() bug + << "(000) 000 - 100" //start "(000) 000 - 000" + << "(000) 012 - 345" + << "(001) 234 - 567" + << "(000) 000 - 000" + << "(000) 000 - 001" + << "(000) 000 - 001" + << "(000) 000 - 001" + << "(000) 000 - 001" + << "(000) 000 - 001" // end "(000) 000 - 000" + << "00,000,100.0000" // start "00000,000.0000" + << "00,012,345.0000" + << "01,234,567.0000" + << "00,000,000.1230" + << "00,000,000.9999" + << "00,000,000.9890" + << "00,000,001.0000" + << "00,000,001.0000" + << "00,000,001.0100"; // end + + qDebug() << "strings.size()" << strings.size() + << "\nformats.size()" << formats.size() + << "texts.size()" << texts.size(); +} + +void tst_numberformat::number_data() +{ + QTest::addColumn<QString>("string"); + QTest::addColumn<float>("number"); + + for (int i = 0; i < strings.size(); i++) + QTest::newRow(QString::number(i).toAscii()) << strings.at(i) << numbers.at(i); +} + +void tst_numberformat::number() +{ + // ### tests the conversion from string to float + QFETCH(QString, string); + QFETCH(float, number); + + QString componentStr = QString("<NumberFormatter number=\"") + string + QString("\"/>"); + + QmlEngine engine; + QmlComponent formatterComponent(&engine, componentStr.toAscii()); + QmlNumberFormatter *formatter = qobject_cast<QmlNumberFormatter*>(formatterComponent.create()); + QVERIFY(formatter != 0); + QCOMPARE((float)formatter->number(), number); + //qDebug() << formatter->format() << formatter->text(); + QVERIFY(formatter->format().isEmpty()); + QVERIFY(formatter->text() == QString("%1").arg(number, -1, 'f', -1)); +} + +void tst_numberformat::text_data() +{ + QTest::addColumn<QString>("string"); + QTest::addColumn<QString>("format"); + QTest::addColumn<QString>("text"); + + for (int j=0; j < formats.size(); j++) + { + for (int i=0; i < strings.size(); i++) + { + QTest::newRow(QString("%1, %2").arg(strings.at(i)).arg(formats.at(j)).toAscii()) + << strings.at(i) << formats.at(j) << texts.at(j*formats.size()+i); + } + } + +} + +void tst_numberformat::text() +{ + QFETCH(QString, string); + QFETCH(QString, format); + QFETCH(QString, text); + + QString componentStr = QString("<NumberFormatter number=\"") + string + QString("\" format=\"") + format + QString("\" />"); + + QmlEngine engine; + QmlComponent formatterComponent(&engine, componentStr.toAscii()); + QmlNumberFormatter *formatter = qobject_cast<QmlNumberFormatter*>(formatterComponent.create()); + QVERIFY(formatter != 0); + + QCOMPARE(formatter->format(), format); + QCOMPARE(formatter->text(), text); +} + +QTEST_MAIN(tst_numberformat) + +#include "tst_numberformatter.moc" diff --git a/tests/auto/declarative/pathview/data/pathview.xml b/tests/auto/declarative/pathview/data/pathview.xml new file mode 100644 index 0000000..26b426c --- /dev/null +++ b/tests/auto/declarative/pathview/data/pathview.xml @@ -0,0 +1,20 @@ +<Rect width="240" height="320" color="#ffffff"> + <resources> + <Component id="Delegate"> + <Rect id="wrapper" height="20" width="60" color="white" pen.color="black"> + <Text text="{index}"/> + <Text x="20" id="textName" text="{name}"/> + <Text x="40" id="textNumber" text="{number}"/> + </Rect> + </Component> + </resources> + <PathView id="view" width="240" height="320" model="{testModel}" delegate="{Delegate}" snapPos="0.01"> + <path> + <Path startY="120" startX="160"> + <PathQuad y="120" x="80" controlY="330" controlX="100"/> + <PathLine y="160" x="20"/> + <PathCubic y="120" x="160" control1Y="0" control1X="100" control2Y="000" control2X="200"/> + </Path> + </path> + </PathView> +</Rect> diff --git a/tests/auto/declarative/pathview/pathview.pro b/tests/auto/declarative/pathview/pathview.pro new file mode 100644 index 0000000..28bbe49 --- /dev/null +++ b/tests/auto/declarative/pathview/pathview.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_pathview.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/pathview/tst_pathview.cpp b/tests/auto/declarative/pathview/tst_pathview.cpp new file mode 100644 index 0000000..110d129 --- /dev/null +++ b/tests/auto/declarative/pathview/tst_pathview.cpp @@ -0,0 +1,259 @@ +#include <QtTest/QtTest> +#include <qlistmodelinterface.h> +#include <qfxview.h> +#include <qfxpathview.h> +#include <qfxtext.h> +#include <qfxrect.h> +#include <qmlcontext.h> +#include <qmlexpression.h> + +class tst_QFxPathView : public QObject +{ + Q_OBJECT +public: + tst_QFxPathView(); + +private slots: + void items(); + void pathMoved(); + void limitedItems(); + +private: + QFxView *createView(const QString &filename); + template<typename T> + T *findItem(QFxItem *parent, const QString &id, int index=0); +}; + +class TestModel : public QListModelInterface +{ + Q_OBJECT +public: + TestModel(QObject *parent = 0) : QListModelInterface(parent) {} + ~TestModel() {} + + enum Roles { Name, Number }; + + QString name(int index) const { return list.at(index).first; } + QString number(int index) const { return list.at(index).second; } + + int count() const { return list.count(); } + + QList<int> roles() const { return QList<int>() << Name << Number; } + QString toString(int role) const { + switch(role) { + case Name: + return "name"; + case Number: + return "number"; + default: + return ""; + } + } + + QHash<int, QVariant> data(int index, const QList<int> &roles) const { + QHash<int,QVariant> returnHash; + + for (int i = 0; i < roles.size(); ++i) { + int role = roles.at(i); + QVariant info; + switch(role) { + case Name: + info = list.at(index).first; + break; + case Number: + info = list.at(index).second; + break; + default: + break; + } + returnHash.insert(role, info); + } + return returnHash; + } + + void addItem(const QString &name, const QString &number) { + list.append(QPair<QString,QString>(name, number)); + emit itemsInserted(list.count()-1, 1); + } + + void insertItem(int index, const QString &name, const QString &number) { + list.insert(index, QPair<QString,QString>(name, number)); + emit itemsInserted(index, 1); + } + + void removeItem(int index) { + list.removeAt(index); + emit itemsRemoved(index, 1); + } + + void modifyItem(int index, const QString &name, const QString &number) { + list[index] = QPair<QString,QString>(name, number); + emit itemsChanged(index, 1, roles()); + } + +private: + QList<QPair<QString,QString> > list; +}; + +tst_QFxPathView::tst_QFxPathView() +{ +} + +void tst_QFxPathView::items() +{ + QFxView *canvas = createView(SRCDIR "/data/pathview.xml"); + + TestModel model; + model.addItem("Fred", "12345"); + model.addItem("John", "2345"); + model.addItem("Bob", "54321"); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxPathView *pathview = findItem<QFxPathView>(canvas->root(), "view"); + QVERIFY(pathview != 0); + + QCOMPARE(pathview->children()->count(), model.count()); // assumes all are visible + + for (int i = 0; i < model.count(); ++i) { + QFxText *name = findItem<QFxText>(pathview, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + QFxText *number = findItem<QFxText>(pathview, "textNumber", i); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(i)); + } + + delete canvas; +} + +void tst_QFxPathView::pathMoved() +{ + QFxView *canvas = createView(SRCDIR "/data/pathview.xml"); + + TestModel model; + model.addItem("Ben", "12345"); + model.addItem("Bohn", "2345"); + model.addItem("Bob", "54321"); + model.addItem("Bill", "4321"); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxPathView *pathview = findItem<QFxPathView>(canvas->root(), "view"); + QVERIFY(pathview != 0); + + QFxRect *firstItem = findItem<QFxRect>(pathview, "wrapper", 0); + QVERIFY(firstItem); + QFxPath *path = qobject_cast<QFxPath*>(pathview->path()); + QVERIFY(path); + QPointF start = path->pointAt(0.0); + QPointF offset;//Center of item is at point, but pos is from corner + offset.setX(firstItem->width()/2); + offset.setY(firstItem->height()/2); + QCOMPARE(firstItem->pos() + offset, start); + pathview->setOffset(10); + QTest::qWait(1000);//Moving is animated? + + for(int i=0; i<model.count(); i++){ + QFxRect *curItem = findItem<QFxRect>(pathview, "wrapper", i); + QCOMPARE(curItem->pos() + offset, path->pointAt(0.1 + i*0.25)); + } + + pathview->setOffset(100); + QTest::qWait(1000);//Moving is animated? + QCOMPARE(firstItem->pos() + offset, start); + + delete canvas; +} + +void tst_QFxPathView::limitedItems() +{ + QFxView *canvas = createView(SRCDIR "/data/pathview.xml"); + + TestModel model; + for(int i=0; i<100; i++) + model.addItem("Bob", QString::number(i)); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QFxPathView *pathview = findItem<QFxPathView>(canvas->root(), "view"); + QVERIFY(pathview != 0); + + pathview->setPathItemCount(10); + QCOMPARE(pathview->pathItemCount(), 10); + + QFxRect *testItem = findItem<QFxRect>(pathview, "wrapper", 0); + QVERIFY(testItem != 0); + testItem = findItem<QFxRect>(pathview, "wrapper", 9); + QVERIFY(testItem != 0); + testItem = findItem<QFxRect>(pathview, "wrapper", 10); + QVERIFY(testItem == 0); + + pathview->setCurrentIndex(50); + QTest::qWait(5100);//Moving is animated and it's travelling far - should be reconsidered. + testItem = findItem<QFxRect>(pathview, "wrapper", 0); + QVERIFY(testItem == 0); + testItem = findItem<QFxRect>(pathview, "wrapper", 1); + QVERIFY(testItem == 0); + testItem = findItem<QFxRect>(pathview, "wrapper", 9); + QVERIFY(testItem == 0); + testItem = findItem<QFxRect>(pathview, "wrapper", 50); + QVERIFY(testItem != 0); +} + +QFxView *tst_QFxPathView::createView(const QString &filename) +{ + QFxView *canvas = new QFxView(0); + canvas->setFixedSize(240,320); + + QFile file(filename); + file.open(QFile::ReadOnly); + QString xml = file.readAll(); + canvas->setXml(xml, filename); + + return canvas; +} + +/* + Find an item with the specified id. If index is supplied then the + item must also evaluate the {index} expression equal to index +*/ +template<typename T> +T *tst_QFxPathView::findItem(QFxItem *parent, const QString &id, int index) +{ + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->children()->count(); ++i) { + QFxItem *item = parent->children()->at(i); + if (mo.cast(item) && (id.isEmpty() || item->id() == id)) { + if (index != -1) { + QmlExpression e(item->itemContext(), "index", item); + e.setTrackChange(false); + if (e.value().toInt() == index) + return static_cast<T*>(item); + } else { + return static_cast<T*>(item); + } + } + item = findItem<T>(item, id, index); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +QTEST_MAIN(tst_QFxPathView) + +#include "tst_pathview.moc" diff --git a/tests/auto/declarative/qbindablemap/qbindablemap.pro b/tests/auto/declarative/qbindablemap/qbindablemap.pro new file mode 100644 index 0000000..b042405 --- /dev/null +++ b/tests/auto/declarative/qbindablemap/qbindablemap.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qbindablemap.cpp diff --git a/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp b/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp new file mode 100644 index 0000000..da58857 --- /dev/null +++ b/tests/auto/declarative/qbindablemap/tst_qbindablemap.cpp @@ -0,0 +1,72 @@ +#include <qtest.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qbindablemap.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QSignalSpy> + +class tst_QBindableMap : public QObject +{ + Q_OBJECT +public: + tst_QBindableMap() {} + +private slots: + void insert(); + void clear(); + void changed(); +}; + +void tst_QBindableMap::insert() +{ + QBindableMap map; + map.setValue(QLatin1String("key1"),100); + map.setValue(QLatin1String("key2"),200); + QVERIFY(map.keys().count() == 2); + + QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); + QCOMPARE(map.value(QLatin1String("key2")), QVariant(200)); + + map.setValue(QLatin1String("key1"),"Hello World"); + QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); +} + +void tst_QBindableMap::clear() +{ + QBindableMap map; + map.setValue(QLatin1String("key1"),100); + QVERIFY(map.keys().count() == 1); + + QCOMPARE(map.value(QLatin1String("key1")), QVariant(100)); + + map.clearValue(QLatin1String("key1")); + QVERIFY(map.keys().count() == 1); + QCOMPARE(map.value(QLatin1String("key1")), QVariant()); +} + +void tst_QBindableMap::changed() +{ + QBindableMap map; + QSignalSpy spy(&map, SIGNAL(changed(const QString&))); + map.setValue(QLatin1String("key1"),100); + map.setValue(QLatin1String("key2"),200); + QCOMPARE(spy.count(), 0); + + map.clearValue(QLatin1String("key1")); + QCOMPARE(spy.count(), 0); + + //make changes in QML + QmlEngine engine; + QmlContext *ctxt = engine.rootContext(); + ctxt->setContextProperty(QLatin1String("data"), &map); + QmlComponent component(&engine, "<Script script=\"data.key1 = 'Hello World';\"/>"); + component.create(); + QCOMPARE(spy.count(), 1); + QList<QVariant> arguments = spy.takeFirst(); + QCOMPARE(arguments.at(0).toString(),QLatin1String("key1")); + QCOMPARE(map.value(QLatin1String("key1")), QVariant("Hello World")); +} + +QTEST_MAIN(tst_QBindableMap) + +#include "tst_qbindablemap.moc" diff --git a/tests/auto/declarative/qfxtext/qfxtext.pro b/tests/auto/declarative/qfxtext/qfxtext.pro new file mode 100644 index 0000000..f705334 --- /dev/null +++ b/tests/auto/declarative/qfxtext/qfxtext.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +SOURCES += tst_qfxtext.cpp diff --git a/tests/auto/declarative/qfxtext/tst_qfxtext.cpp b/tests/auto/declarative/qfxtext/tst_qfxtext.cpp new file mode 100644 index 0000000..ee74040 --- /dev/null +++ b/tests/auto/declarative/qfxtext/tst_qfxtext.cpp @@ -0,0 +1,412 @@ +#include <qtest.h> +#include <QTextDocument> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qfxtext.h> +#include <QFontMetrics> + +class tst_qfxtext : public QObject + +{ + Q_OBJECT +public: + tst_qfxtext(); + +private slots: + void text(); + void width(); + void wrap(); + void elide(); + + // ### these tests may be trivial + void hAlign(); + void vAlign(); + void font(); + void style(); + void color(); + +private: + QStringList standard; + QStringList richText; + + QStringList hAlignmentStrings; + QStringList vAlignmentStrings; + + QList<Qt::Alignment> vAlignments; + QList<Qt::Alignment> hAlignments; + + QStringList styleStrings; + QList<QFxText::TextStyle> styles; + + QStringList colorStrings; + + QmlEngine engine; +}; + +tst_qfxtext::tst_qfxtext() +{ + standard << "the quick brown fox jumped over the lazy dog" + << "the quick brown fox\n jumped over the lazy dog"; + + richText << "<i>the <b>quick</b> brown <a href=\"http://www.google.com\">fox</a> jumped over the <b>lazy</b> dog</i>" + << "<i>the <b>quick</b> brown <a href=\"http://www.google.com\">fox</a><br>jumped over the <b>lazy</b> dog</i>"; + + hAlignmentStrings << "AlignLeft" + << "AlignRight" + << "AlignHCenter"; + + vAlignmentStrings << "AlignTop" + << "AlignBottom" + << "AlignVCenter"; + + hAlignments << Qt::AlignLeft + << Qt::AlignRight + << Qt::AlignHCenter; + + vAlignments << Qt::AlignTop + << Qt::AlignBottom + << Qt::AlignVCenter; + + styleStrings << "Normal" + << "Outline" + << "Raised" + << "Sunken"; + + styles << QFxText::Normal + << QFxText::Outline + << QFxText::Raised + << QFxText::Sunken; + + colorStrings << "aliceblue" + << "antiquewhite" + << "aqua" + << "darkkhaki" + << "darkolivegreen" + << "dimgray" + << "palevioletred" + << "lightsteelblue" + << "#000000" + << "#AAAAAA" + << "#FFFFFF" + << "#2AC05F"; + // + // need a different test to do alpha channel test + // << "#AA0011DD" + // << "#00F16B11"; + // +} + +void tst_qfxtext::text() +{ + { + QmlComponent textComponent(&engine, "<Text text=\"\" />"); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QVERIFY(textObject != 0); + QCOMPARE(textObject->text(), QString("")); + } + + for (int i = 0; i < standard.size(); i++) + { + QString componentStr = "<Text>" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QVERIFY(textObject != 0); + QCOMPARE(textObject->text(), standard.at(i)); + } + + for (int i = 0; i < richText.size(); i++) + { + QString componentStr = "<Text><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QVERIFY(textObject != 0); + QCOMPARE(textObject->text(), richText.at(i)); + } +} + +void tst_qfxtext::width() +{ + // uses Font metrics to find the width for standard and document to find the width for rich + { + QmlComponent textComponent(&engine, "<Text text=\"\"/>"); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 0.); + } + + for (int i = 0; i < standard.size(); i++) + { + QFont f; + QFontMetrics fm(f); + int metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width(); + + QString componentStr = "<Text>" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), qreal(metricWidth)); + } + + for (int i = 0; i < richText.size(); i++) + { + QTextDocument document; + document.setHtml(richText.at(i)); + document.setDocumentMargin(0); + + int documentWidth = document.idealWidth(); + + QString componentStr = "<Text><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), qreal(documentWidth)); + } +} + +void tst_qfxtext::wrap() +{ + // XXX Poor coverage - should at least be testing an expected height. + + // for specified width and wrap set true + { + QmlComponent textComponent(&engine, "<Text text=\"\" wrap=\"true\" width=\"300\"/>"); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + + for (int i = 0; i < standard.size(); i++) + { + QString componentStr = "<Text wrap=\"true\" width=\"300\">" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + + for (int i = 0; i < richText.size(); i++) + { + QString componentStr = "<Text wrap=\"true\" width=\"300\"><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + +} + +void tst_qfxtext::elide() +{ + for (Qt::TextElideMode m = Qt::ElideLeft; m<=Qt::ElideNone; m=Qt::TextElideMode(int(m)+1)) { + const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"}; + QString elide = "elide=\""+QString(elidename[int(m)])+"\""; + + // XXX Poor coverage. + + { + QmlComponent textComponent(&engine, ("<Text text=\"\" "+elide+" width=\"300\"/>").toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + + for (int i = 0; i < standard.size(); i++) + { + QString componentStr = "<Text "+elide+" width=\"300\">" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + + // richtext - does nothing + for (int i = 0; i < richText.size(); i++) + { + QString componentStr = "<Text "+elide+" width=\"300\"><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->width(), 300.); + } + } +} + +//the alignment tests may be trivial o.oa +void tst_qfxtext::hAlign() +{ + //test one align each, and then test if two align fails. + + for (int i = 0; i < standard.size(); i++) + { + for (int j=0; j < hAlignmentStrings.size(); j++) + { + QString componentStr = "<Text hAlign=\"" + hAlignmentStrings.at(j) + "\">" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE((int)textObject->hAlign(), (int)hAlignments.at(j)); + } + } + + for (int i = 0; i < richText.size(); i++) + { + for (int j=0; j < hAlignmentStrings.size(); j++) + { + QString componentStr = "<Text hAlign=\"" + hAlignmentStrings.at(j) + "\"><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE((int)textObject->hAlign(), (int)hAlignments.at(j)); + } + } + +} + +void tst_qfxtext::vAlign() +{ + //test one align each, and then test if two align fails. + + for (int i = 0; i < standard.size(); i++) + { + for (int j=0; j < vAlignmentStrings.size(); j++) + { + QString componentStr = "<Text vAlign=\"" + vAlignmentStrings.at(j) + "\">" + standard.at(i) + "</Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE((int)textObject->vAlign(), (int)vAlignments.at(j)); + } + } + + for (int i = 0; i < richText.size(); i++) + { + for (int j=0; j < vAlignmentStrings.size(); j++) + { + QString componentStr = "<Text vAlign=\"" + vAlignmentStrings.at(j) + "\"><![CDATA[" + richText.at(i) + "]]></Text>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE((int)textObject->vAlign(), (int)vAlignments.at(j)); + } + } + +} + +void tst_qfxtext::font() +{ + //test size, then bold, then italic, then family + { + QString componentStr = "<Text font.size=\"40\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->font()->size(), qreal(40)); + QCOMPARE(textObject->font()->bold(), false); + QCOMPARE(textObject->font()->italic(), false); + } + + { + QString componentStr = "<Text font.bold=\"true\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->font()->bold(), true); + QCOMPARE(textObject->font()->italic(), false); + } + + { + QString componentStr = "<Text font.italic=\"true\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->font()->italic(), true); + QCOMPARE(textObject->font()->bold(), false); + } + + { + QString componentStr = "<Text font.family=\"Helvetica\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->font()->family(), QString("Helvetica")); + QCOMPARE(textObject->font()->bold(), false); + QCOMPARE(textObject->font()->italic(), false); + } + + { + QString componentStr = "<Text font.family=\"\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->font()->family(), QString("")); + } +} + +void tst_qfxtext::style() +{ + //test style + for (int i = 0; i < styles.size(); i++) + { + QString componentStr = "<Text style=\"" + styleStrings.at(i) + "\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE((int)textObject->style(), (int)styles.at(i)); + QCOMPARE(textObject->styleColor(), QColor()); + } +} + +void tst_qfxtext::color() +{ + //test style + for (int i = 0; i < colorStrings.size(); i++) + { + QString componentStr = "<Text color=\"" + colorStrings.at(i) + "\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->color(), QColor(colorStrings.at(i))); + QCOMPARE(textObject->styleColor(), QColor()); + } + + for (int i = 0; i < colorStrings.size(); i++) + { + QString componentStr = "<Text styleColor=\"" + colorStrings.at(i) + "\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i))); + // default color to black? + QCOMPARE(textObject->color(), QColor("black")); + } + + for (int i = 0; i < colorStrings.size(); i++) + { + for (int j = 0; j < colorStrings.size(); j++) + { + QString componentStr = "<Text color=\"" + colorStrings.at(i) + "\" styleColor=\"" + colorStrings.at(j) + "\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->color(), QColor(colorStrings.at(i))); + QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j))); + } + } + { + QString colorStr = "#AA001234"; + QColor testColor("#001234"); + testColor.setAlpha(170); + + QString componentStr = "<Text color=\"" + colorStr + "\" text=\"Hello World\"/>"; + QmlComponent textComponent(&engine, componentStr.toLatin1()); + QFxText *textObject = qobject_cast<QFxText*>(textComponent.create()); + + QCOMPARE(textObject->color(), testColor); + } +} +QTEST_MAIN(tst_qfxtext) + +#include "tst_qfxtext.moc" diff --git a/tests/auto/declarative/qfxtextedit/qfxtextedit.pro b/tests/auto/declarative/qfxtextedit/qfxtextedit.pro new file mode 100644 index 0000000..59ab6e5 --- /dev/null +++ b/tests/auto/declarative/qfxtextedit/qfxtextedit.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +SOURCES += tst_qfxtextedit.cpp diff --git a/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp new file mode 100644 index 0000000..8baef3d --- /dev/null +++ b/tests/auto/declarative/qfxtextedit/tst_qfxtextedit.cpp @@ -0,0 +1,326 @@ +#include <qtest.h> +#include <QTextDocument> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qfxtextedit.h> +#include <QFontMetrics> + +class tst_qfxtextedit : public QObject + +{ + Q_OBJECT +public: + tst_qfxtextedit(); + +private slots: + void text(); + void width(); + void wrap(); + + // ### these tests may be trivial + void hAlign(); + void vAlign(); + void font(); + void color(); + +private: + QStringList standard; + QStringList richText; + + QStringList hAlignmentStrings; + QStringList vAlignmentStrings; + + QList<Qt::Alignment> vAlignments; + QList<Qt::Alignment> hAlignments; + + QStringList colorStrings; + + QmlEngine engine; +}; + +tst_qfxtextedit::tst_qfxtextedit() +{ + standard << "the quick brown fox jumped over the lazy dog" + << "the quick brown fox\n jumped over the lazy dog"; + + richText << "<i>the <b>quick</b> brown <a href=\"http://www.google.com\">fox</a> jumped over the <b>lazy</b> dog</i>" + << "<i>the <b>quick</b> brown <a href=\"http://www.google.com\">fox</a><br>jumped over the <b>lazy</b> dog</i>"; + + hAlignmentStrings << "AlignLeft" + << "AlignRight" + << "AlignHCenter"; + + vAlignmentStrings << "AlignTop" + << "AlignBottom" + << "AlignVCenter"; + + hAlignments << Qt::AlignLeft + << Qt::AlignRight + << Qt::AlignHCenter; + + vAlignments << Qt::AlignTop + << Qt::AlignBottom + << Qt::AlignVCenter; + + colorStrings << "aliceblue" + << "antiquewhite" + << "aqua" + << "darkkhaki" + << "darkolivegreen" + << "dimgray" + << "palevioletred" + << "lightsteelblue" + << "#000000" + << "#AAAAAA" + << "#FFFFFF" + << "#2AC05F"; + // + // need a different test to do alpha channel test + // << "#AA0011DD" + // << "#00F16B11"; + // +} + +void tst_qfxtextedit::text() +{ + { + QmlComponent texteditComponent(&engine, "<TextEdit text=\"\" />"); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QVERIFY(textEditObject != 0); + QCOMPARE(textEditObject->text(), QString("")); + } + + for (int i = 0; i < standard.size(); i++) + { + QString componentStr = "<TextEdit>" + standard.at(i) + "</TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QVERIFY(textEditObject != 0); + QCOMPARE(textEditObject->text(), standard.at(i)); + } + + for (int i = 0; i < richText.size(); i++) + { + QString componentStr = "<TextEdit><![CDATA[" + richText.at(i) + "]]></TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QVERIFY(textEditObject != 0); + QString actual = textEditObject->text(); + QString expected = richText.at(i); + actual.replace(QRegExp(".*<body[^>]*>"),""); + actual.replace(QRegExp("(<[^>]*>)+"),"<>"); + expected.replace(QRegExp("(<[^>]*>)+"),"<>"); + QCOMPARE(actual.simplified(),expected.simplified()); + } +} + +void tst_qfxtextedit::width() +{ + // uses Font metrics to find the width for standard and document to find the width for rich + { + QmlComponent texteditComponent(&engine, "<TextEdit text=\"\"/>"); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), 0.); + } + + for (int i = 0; i < standard.size(); i++) + { + QFont f; + QFontMetrics fm(f); + int metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width(); + + QString componentStr = "<TextEdit>" + standard.at(i) + "</TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), qreal(metricWidth)); + } + + for (int i = 0; i < richText.size(); i++) + { + QTextDocument document; + document.setHtml(richText.at(i)); + document.setDocumentMargin(0); + + int documentWidth = document.idealWidth(); + + QString componentStr = "<TextEdit><![CDATA[" + richText.at(i) + "]]></TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), qreal(documentWidth)); + } +} + +void tst_qfxtextedit::wrap() +{ + // for specified width and wrap set true + { + QmlComponent texteditComponent(&engine, "<TextEdit text=\"\" wrap=\"true\" width=\"300\"/>"); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), 300.); + } + + for (int i = 0; i < standard.size(); i++) + { + QString componentStr = "<TextEdit wrap=\"true\" width=\"300\">" + standard.at(i) + "</TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), 300.); + } + + for (int i = 0; i < richText.size(); i++) + { + QString componentStr = "<TextEdit wrap=\"true\" width=\"300\"><![CDATA[" + richText.at(i) + "]]></TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->width(), 300.); + } + +} + +//the alignment tests may be trivial o.oa +void tst_qfxtextedit::hAlign() +{ + //test one align each, and then test if two align fails. + + for (int i = 0; i < standard.size(); i++) + { + for (int j=0; j < hAlignmentStrings.size(); j++) + { + QString componentStr = "<TextEdit hAlign=\"" + hAlignmentStrings.at(j) + "\">" + standard.at(i) + "</TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); + } + } + + for (int i = 0; i < richText.size(); i++) + { + for (int j=0; j < hAlignmentStrings.size(); j++) + { + QString componentStr = "<TextEdit hAlign=\"" + hAlignmentStrings.at(j) + "\"><![CDATA[" + richText.at(i) + "]]></TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); + } + } + +} + +void tst_qfxtextedit::vAlign() +{ + //test one align each, and then test if two align fails. + + for (int i = 0; i < standard.size(); i++) + { + for (int j=0; j < vAlignmentStrings.size(); j++) + { + QString componentStr = "<TextEdit vAlign=\"" + vAlignmentStrings.at(j) + "\">" + standard.at(i) + "</TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); + } + } + + for (int i = 0; i < richText.size(); i++) + { + for (int j=0; j < vAlignmentStrings.size(); j++) + { + QString componentStr = "<TextEdit vAlign=\"" + vAlignmentStrings.at(j) + "\"><![CDATA[" + richText.at(i) + "]]></TextEdit>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); + } + } + +} + +void tst_qfxtextedit::font() +{ + //test size, then bold, then italic, then family + { + QString componentStr = "<TextEdit font.size=\"40\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->font()->size(), qreal(40)); + QCOMPARE(textEditObject->font()->bold(), false); + QCOMPARE(textEditObject->font()->italic(), false); + } + + { + QString componentStr = "<TextEdit font.bold=\"true\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->font()->bold(), true); + QCOMPARE(textEditObject->font()->italic(), false); + } + + { + QString componentStr = "<TextEdit font.italic=\"true\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->font()->italic(), true); + QCOMPARE(textEditObject->font()->bold(), false); + } + + { + QString componentStr = "<TextEdit font.family=\"Helvetica\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->font()->family(), QString("Helvetica")); + QCOMPARE(textEditObject->font()->bold(), false); + QCOMPARE(textEditObject->font()->italic(), false); + } + + { + QString componentStr = "<TextEdit font.family=\"\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->font()->family(), QString("")); + } +} + +void tst_qfxtextedit::color() +{ + //test style + for (int i = 0; i < colorStrings.size(); i++) + { + QString componentStr = "<TextEdit color=\"" + colorStrings.at(i) + "\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i)); + QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i))); + } + + { + QString colorStr = "#AA001234"; + QColor testColor("#001234"); + testColor.setAlpha(170); + + QString componentStr = "<TextEdit color=\"" + colorStr + "\" text=\"Hello World\"/>"; + QmlComponent texteditComponent(&engine, componentStr.toLatin1()); + QFxTextEdit *textEditObject = qobject_cast<QFxTextEdit*>(texteditComponent.create()); + + QCOMPARE(textEditObject->color(), testColor); + } +} +QTEST_MAIN(tst_qfxtextedit) + +#include "tst_qfxtextedit.moc" diff --git a/tests/auto/declarative/qmlbindengine/qmlbindengine.pro b/tests/auto/declarative/qmlbindengine/qmlbindengine.pro new file mode 100644 index 0000000..6d84931 --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/qmlbindengine.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmlbindengine.cpp diff --git a/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp new file mode 100644 index 0000000..f5b32e8 --- /dev/null +++ b/tests/auto/declarative/qmlbindengine/tst_qmlbindengine.cpp @@ -0,0 +1,123 @@ +#include <qtest.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qmlengine.h> + +class MyQmlObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool trueProperty READ trueProperty) + Q_PROPERTY(bool falseProperty READ falseProperty) + Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) +public: + MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false) {} + + bool trueProperty() const { return true; } + bool falseProperty() const { return false; } + + QString stringProperty() const { return m_string; } + void setStringProperty(const QString &s) { m_string = s; } + + bool methodCalled() const { return m_methodCalled; } + bool methodIntCalled() const { return m_methodIntCalled; } + + QString string() const { return m_string; } +signals: + void basicSignal(); + void argumentSignal(int a, QString b, qreal c); + +public slots: + void method() { m_methodCalled = true; } + void method(int a) { if(a == 163) m_methodIntCalled = true; } + void setString(const QString &s) { m_string = s; } + +private: + friend class tst_qmlbindengine; + bool m_methodCalled; + bool m_methodIntCalled; + + QString m_string; +}; + +QML_DECLARE_TYPE(MyQmlObject); +QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); + +class tst_qmlbindengine : public QObject +{ + Q_OBJECT +public: + tst_qmlbindengine() {} + +private slots: + void boolPropertiesEvaluateAsBool(); + void methods(); + void signalAssignment(); + +private: + QmlEngine engine; +}; + +void tst_qmlbindengine::boolPropertiesEvaluateAsBool() +{ + { + QmlComponent component(&engine, "<MyQmlObject stringProperty=\"{trueProperty?'pass':'fail'}\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->stringProperty(), QLatin1String("pass")); + } + { + QmlComponent component(&engine, "<MyQmlObject stringProperty=\"{falseProperty?'fail':'pass'}\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->stringProperty(), QLatin1String("pass")); + } +} + +void tst_qmlbindengine::signalAssignment() +{ + { + QmlComponent component(&engine, "<MyQmlObject onBasicSignal=\"setString('pass')\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->string(), QString()); + emit object->basicSignal(); + QCOMPARE(object->string(), QString("pass")); + } + + { + QmlComponent component(&engine, "<MyQmlObject onArgumentSignal=\"setString('pass ' + a + ' ' + b + ' ' + c)\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->string(), QString()); + emit object->argumentSignal(19, "Hello world!", 10.3); + QCOMPARE(object->string(), QString("pass 19 Hello world! 10.3")); + } +} + +void tst_qmlbindengine::methods() +{ + { + QmlComponent component(&engine, "<MyQmlObject id=\"MyObject\" onBasicSignal=\"MyObject.method()\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->methodCalled(), false); + QCOMPARE(object->methodIntCalled(), false); + emit object->basicSignal(); + QCOMPARE(object->methodCalled(), true); + QCOMPARE(object->methodIntCalled(), false); + } + + { + QmlComponent component(&engine, "<MyQmlObject id=\"MyObject\" onBasicSignal=\"MyObject.method(163)\" />"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->methodCalled(), false); + QCOMPARE(object->methodIntCalled(), false); + emit object->basicSignal(); + QCOMPARE(object->methodCalled(), false); + QCOMPARE(object->methodIntCalled(), true); + } +} + +QTEST_MAIN(tst_qmlbindengine) + +#include "tst_qmlbindengine.moc" diff --git a/tests/auto/declarative/qmllist/qmllist.pro b/tests/auto/declarative/qmllist/qmllist.pro new file mode 100644 index 0000000..e5558f1 --- /dev/null +++ b/tests/auto/declarative/qmllist/qmllist.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmllist.cpp diff --git a/tests/auto/declarative/qmllist/tst_qmllist.cpp b/tests/auto/declarative/qmllist/tst_qmllist.cpp new file mode 100644 index 0000000..541ca64 --- /dev/null +++ b/tests/auto/declarative/qmllist/tst_qmllist.cpp @@ -0,0 +1,38 @@ +#include <qtest.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmlprivate.h> + +class tst_QmlList : public QObject +{ + Q_OBJECT +public: + tst_QmlList() {} + +private slots: + void interface(); +}; + +void tst_QmlList::interface() +{ + QmlConcreteList<QObject*> list; + QObject *obj = new QObject; + obj->setObjectName("foo"); + list.append(obj); + QVERIFY(list.count() == 1); + QCOMPARE(list.at(0), obj); + + QmlPrivate::ListInterface *li = (QmlPrivate::ListInterface*)&list; + + void *ptr[1]; + li->at(0, ptr); + QVERIFY(li->count() == 1); + QCOMPARE(ptr[0], obj); + + li->removeAt(0); + QVERIFY(li->count() == 0); + QVERIFY(list.count() == 0); +} + +QTEST_MAIN(tst_QmlList) + +#include "tst_qmllist.moc" diff --git a/tests/auto/declarative/qmllistaccessor/qmllistaccessor.pro b/tests/auto/declarative/qmllistaccessor/qmllistaccessor.pro new file mode 100644 index 0000000..4aa0450 --- /dev/null +++ b/tests/auto/declarative/qmllistaccessor/qmllistaccessor.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmllistaccessor.cpp diff --git a/tests/auto/declarative/qmllistaccessor/tst_qmllistaccessor.cpp b/tests/auto/declarative/qmllistaccessor/tst_qmllistaccessor.cpp new file mode 100644 index 0000000..f5b57ea --- /dev/null +++ b/tests/auto/declarative/qmllistaccessor/tst_qmllistaccessor.cpp @@ -0,0 +1,61 @@ +#include <qtest.h> +#include <QtDeclarative/qml.h> +#include <QtDeclarative/qmllistaccessor.h> + +class tst_QmlListAccessor : public QObject +{ + Q_OBJECT +public: + tst_QmlListAccessor() {} + +private slots: + void qmllist(); + //void qlist(); + //void qstringlist(); +}; + +void tst_QmlListAccessor::qmllist() +{ + QmlConcreteList<QObject*> list; + QObject *obj = new QObject; + list.append(obj); + QVERIFY(list.count() == 1); + QCOMPARE(list.at(0), obj); + + QmlListAccessor accessor; + accessor.setList(qVariantFromValue((QmlList<QObject*>*)&list)); + + QVERIFY(accessor.isValid()); + QVERIFY(accessor.count() == 1); + + QVariant v = accessor.at(0); + QCOMPARE(qvariant_cast<QObject*>(v), obj); + + accessor.removeAt(3); + QVERIFY(accessor.count() == 1); + + accessor.removeAt(0); + QVERIFY(accessor.count() == 0); + + accessor.insert(4, qVariantFromValue(obj)); + QVERIFY(accessor.count() == 1); + + v = accessor.at(0); + QCOMPARE(qvariant_cast<QObject*>(v), obj); + + QObject *obj2 = new QObject; + accessor.append(qVariantFromValue(obj2)); + QVERIFY(accessor.count() == 2); + + v = accessor.at(1); + QCOMPARE(qvariant_cast<QObject*>(v), obj2); + + accessor.clear(); + QVERIFY(accessor.count() == 0); + + QVERIFY(accessor.isValid()); +} + +QTEST_MAIN(tst_QmlListAccessor) + +#include "tst_qmllistaccessor.moc" diff --git a/tests/auto/declarative/qmlmetaproperty/qmlmetaproperty.pro b/tests/auto/declarative/qmlmetaproperty/qmlmetaproperty.pro new file mode 100644 index 0000000..af67373 --- /dev/null +++ b/tests/auto/declarative/qmlmetaproperty/qmlmetaproperty.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmlmetaproperty.cpp diff --git a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp new file mode 100644 index 0000000..3a87070 --- /dev/null +++ b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp @@ -0,0 +1,104 @@ +#include <qtest.h> +#include <QtDeclarative/QmlEngine.h> +#include <QtDeclarative/qmlcomponent.h> +#include <QtDeclarative/qmlmetaproperty.h> +#include <QtGui/QLineEdit> + +class MyQmlObject : public QObject +{ + Q_OBJECT +public: + MyQmlObject() {} +}; + +QML_DECLARE_TYPE(MyQmlObject); +QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); + +class MyContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList<MyQmlObject*>* children READ children) + Q_PROPERTY(QmlList<MyQmlObject*>* qmlChildren READ qmlChildren) +public: + MyContainer() {} + + QList<MyQmlObject*> *children() { return &m_children; } + QmlConcreteList<MyQmlObject *> *qmlChildren() { return &m_qmlChildren; } + +private: + QList<MyQmlObject*> m_children; + QmlConcreteList<MyQmlObject *> m_qmlChildren; +}; + +QML_DECLARE_TYPE(MyContainer); +QML_DEFINE_TYPE(MyContainer,MyContainer); + +class tst_QmlMetaProperty : public QObject +{ + Q_OBJECT +public: + tst_QmlMetaProperty() {} + +private slots: + void writeObjectToList(); + void writeListToList(); + void writeObjectToQmlList(); + + //writeToReadOnly(); + +private: + QmlEngine engine; +}; + +void tst_QmlMetaProperty::writeObjectToList() +{ + QmlComponent containerComponent(&engine, "<MyContainer><children><MyQmlObject/></children></MyContainer>"); + MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create()); + QVERIFY(container != 0); + QVERIFY(container->children()->size() == 1); + + MyQmlObject *object = new MyQmlObject; + QmlMetaProperty prop(container, "children"); + prop.write(qVariantFromValue(object)); + QCOMPARE(container->children()->size(), 2); + QCOMPARE(container->children()->at(1), object); +} + +Q_DECLARE_METATYPE(QList<QObject *>); +void tst_QmlMetaProperty::writeListToList() +{ + QmlComponent containerComponent(&engine, "<MyContainer><children><MyQmlObject/></children></MyContainer>"); + MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create()); + QVERIFY(container != 0); + QVERIFY(container->children()->size() == 1); + + QList<QObject*> objList; + objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject(); + QmlMetaProperty prop(container, "children"); + prop.write(qVariantFromValue(objList)); + QCOMPARE(container->children()->size(), 4); + + //XXX need to try this with read/write prop (for read-only it correctly doesn't write) + /*QList<MyQmlObject*> typedObjList; + typedObjList << new MyQmlObject(); + prop.write(qVariantFromValue(&typedObjList)); + QCOMPARE(container->children()->size(), 1);*/ +} + +void tst_QmlMetaProperty::writeObjectToQmlList() +{ + QmlComponent containerComponent(&engine, "<MyContainer><qmlChildren><MyQmlObject/></qmlChildren></MyContainer>"); + MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create()); + QVERIFY(container != 0); + QVERIFY(container->qmlChildren()->size() == 1); + + MyQmlObject *object = new MyQmlObject; + QmlMetaProperty prop(container, "qmlChildren"); + prop.write(qVariantFromValue(object)); + QCOMPARE(container->qmlChildren()->size(), 2); + QCOMPARE(container->qmlChildren()->at(1), object); +} + +QTEST_MAIN(tst_QmlMetaProperty) + +#include "tst_qmlmetaproperty.moc" diff --git a/tests/auto/declarative/qmlparser/qmlparser.pro b/tests/auto/declarative/qmlparser/qmlparser.pro new file mode 100644 index 0000000..3e0b6ea --- /dev/null +++ b/tests/auto/declarative/qmlparser/qmlparser.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qmlparser.cpp diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp new file mode 100644 index 0000000..24d3c22 --- /dev/null +++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp @@ -0,0 +1,444 @@ +#include <qtest.h> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qmlcomponent.h> + +class MyInterface +{ +public: + MyInterface() : id(913) {} + int id; +}; + +Q_DECLARE_INTERFACE(MyInterface, "com.trolltech.Qt.Test.MyInterface"); +QML_DECLARE_INTERFACE(MyInterface); +QML_DEFINE_INTERFACE(MyInterface); + +class MyQmlObject : public QObject, public MyInterface +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + Q_PROPERTY(QString readOnlyString READ readOnlyString) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) + Q_PROPERTY(QRect rect READ rect WRITE setRect) + Q_PROPERTY(QMatrix matrix READ matrix WRITE setMatrix) //assumed to be unsupported by QML + Q_PROPERTY(MyInterface *interface READ interface WRITE setInterface) + Q_INTERFACES(MyInterface) +public: + MyQmlObject() : m_value(-1), m_interface(0) {} + + int value() const { return m_value; } + void setValue(int v) { m_value = v; } + + QString readOnlyString() const { return QLatin1String(""); } + + bool enabled() const { return false; } + void setEnabled(bool) {} + + QRect rect() const { return QRect(); } + void setRect(const QRect&) {} + + QMatrix matrix() const { return QMatrix(); } + void setMatrix(const QMatrix&) {} + + MyInterface *interface() const { return m_interface; } + void setInterface(MyInterface *iface) { m_interface = iface; } + + Q_CLASSINFO("defaultMethod", "basicSlot()"); + +public slots: + void basicSlot() { qWarning("MyQmlObject::basicSlot"); } + +signals: + void basicSignal(); + +private: + friend class tst_qmlparser; + int m_value; + MyInterface *m_interface; +}; + +QML_DECLARE_TYPE(MyQmlObject); +QML_DEFINE_TYPE(MyQmlObject,MyQmlObject); + +class MyContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QList<QObject*>* children READ children) + Q_PROPERTY(QList<MyInterface*>* qlistInterfaces READ qlistInterfaces) + Q_PROPERTY(QmlList<MyInterface*>* qmllistInterfaces READ qmllistInterfaces) + Q_CLASSINFO("DefaultProperty", "children"); +public: + MyContainer() {} + + QList<QObject*> *children() { return &m_children; } + QList<MyInterface *> *qlistInterfaces() { return &m_interfaces; } + QmlList<MyInterface *> *qmllistInterfaces() { return &m_qmlinterfaces; } + const QmlConcreteList<MyInterface *> &qmllistAccessor() const { return m_qmlinterfaces; } + +private: + QList<QObject*> m_children; + QList<MyInterface *> m_interfaces; + QmlConcreteList<MyInterface *> m_qmlinterfaces; +}; + +QML_DECLARE_TYPE(MyContainer); +QML_DEFINE_TYPE(MyContainer,MyContainer); + +class MyDotPropertyObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(MyQmlObject *obj READ obj) + Q_PROPERTY(MyQmlObject *readWriteObj READ readWriteObj WRITE setReadWriteObj) +public: + MyDotPropertyObject() : m_rwobj(0), m_ownRWObj(false) {} + ~MyDotPropertyObject() + { + if (m_ownRWObj) + delete m_rwobj; + } + + MyQmlObject *obj() { return 0; } + + MyQmlObject *readWriteObj() + { + if (!m_rwobj) { + m_rwobj = new MyQmlObject; + m_ownRWObj = true; + } + return m_rwobj; + } + + void setReadWriteObj(MyQmlObject *obj) + { + if (m_ownRWObj) { + delete m_rwobj; + m_ownRWObj = false; + } + + m_rwobj = obj; + } + +private: + MyQmlObject *m_rwobj; + bool m_ownRWObj; +}; + +QML_DECLARE_TYPE(MyDotPropertyObject); +QML_DEFINE_TYPE(MyDotPropertyObject,MyDotPropertyObject); + +class tst_qmlparser : public QObject +{ + Q_OBJECT +public: + tst_qmlparser() {} + +private slots: + void simpleObject(); + void simpleContainer(); + void unregisteredObject(); + void nonexistantProperty(); + void unsupportedProperty(); + //void setProperties(); + void wrongType(); + void readOnly(); + //void dotProperties(); + void nullDotProperty(); + void fakeDotProperty(); + //void readWriteDotProperty(); + void emptyInput(); + void missingObject(); + void invalidXML(); + void duplicateIDs(); + void invalidID(); + void interfaceProperty(); + void interfaceQmlList(); + void interfaceQList(); + void cannotAssignBindingToSignal(); + void assignObjectToSignal(); + +private: + QmlEngine engine; +}; + +void tst_qmlparser::simpleObject() +{ + QmlComponent component(&engine, "<MyQmlObject/>"); + QObject *object = component.create(); + QVERIFY(object != 0); +} + +void tst_qmlparser::simpleContainer() +{ + QmlComponent component(&engine, "<MyContainer>\n<MyQmlObject/>\n<MyQmlObject/>\n</MyContainer>"); + MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QVERIFY(container != 0); + QCOMPARE(container->children()->count(),2); +} + +void tst_qmlparser::unregisteredObject() +{ + QmlComponent component(&engine, "<UnRegisteredObject/>", QUrl("myprogram.qml")); + QTest::ignoreMessage(QtWarningMsg, "Unable to create object of type 'UnRegisteredObject' @myprogram.qml:1"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +void tst_qmlparser::nonexistantProperty() +{ + //NOTE: these first 3 should all have the same error message + { + QmlComponent component(&engine, "<MyQmlObject something=\"24\"/>"); + QTest::ignoreMessage(QtWarningMsg, "Unknown property 'something' @<unspecified file>:1"); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + { + QmlComponent component(&engine, "<MyQmlObject>\n<something>24</something>\n</MyQmlObject>"); + QTest::ignoreMessage(QtWarningMsg, "Unknown property 'something' @<unspecified file>:2"); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + //non-existant using binding + { + QmlComponent component(&engine, "<MyQmlObject something=\"{1}\"/>"); + QTest::ignoreMessage(QtWarningMsg, "Unknown property 'something' @<unspecified file>:1"); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + { + QmlComponent component(&engine, "<MyQmlObject><something></something></MyQmlObject>"); + QObject *object = component.create(); + QVERIFY(object != 0); + } + + //non-existant value-type default property + { + QmlComponent component(&engine, "<MyQmlObject>\n24\n</MyQmlObject>"); + QTest::ignoreMessage(QtWarningMsg, "Unable to resolve default property @<unspecified file>:3"); + // XXX would 2 be a better line number in this case? Message should also be improved. + QObject *object = component.create(); + QVERIFY(object == 0); + } + + //non-existant object-type default property + { + QmlComponent component(&engine, "<MyQmlObject>\n<MyQmlObject/>\n</MyQmlObject>"); + QTest::ignoreMessage(QtWarningMsg, "Unable to assign to non-existant property @<unspecified file>:2"); + // XXX Message needs to be improved (and should be closer to value-type message). + QObject *object = component.create(); + QVERIFY(object == 0); + } +} + +void tst_qmlparser::unsupportedProperty() +{ + QTest::ignoreMessage(QtWarningMsg, "Property 'matrix' is of an unknown type @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject matrix=\"1,0,0,0,1,0,0,0,1\"/>"); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object == 0); +} + +void tst_qmlparser::wrongType() +{ + //string for int + { + QTest::ignoreMessage(QtWarningMsg, "Can't assign value 'hello' to property 'value' @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject value=\"hello\"/>"); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object == 0); + } + + //int for bool + { + QTest::ignoreMessage(QtWarningMsg, "Can't assign value '5' to property 'enabled' @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject enabled=\"5\"/>"); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object == 0); + } + + //bad format for rect + { + QTest::ignoreMessage(QtWarningMsg, "Can't assign value '5,5x10' to property 'rect' @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject rect=\"5,5x10\"/>"); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object == 0); + } + + //TODO: more types (including float-to-int, complex types, etc) +} + +void tst_qmlparser::readOnly() +{ + { + QTest::ignoreMessage(QtWarningMsg, "Can't assign value 'hello' to property 'readOnlyString' because 'readOnlyString' is read-only @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject readOnlyString=\"hello\"/>"); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + { + QTest::ignoreMessage(QtWarningMsg, "Can't assign a binding to property 'readOnlyString' because 'readOnlyString' is read-only @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject readOnlyString=\"{'hello'}\"/>"); + QObject *object = component.create(); + QVERIFY(object == 0); + } +} + +void tst_qmlparser::nullDotProperty() +{ + QTest::ignoreMessage(QtWarningMsg, "Can't set properties on 'obj' because it is null @<unspecified file>:1"); + QmlComponent component(&engine, "<MyDotPropertyObject obj.value=\"1\"/>"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +void tst_qmlparser::fakeDotProperty() +{ + QTest::ignoreMessage(QtWarningMsg, "Can't set properties on 'value' because it isn't a known object type @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject value.something=\"hello\"/>"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +//XXX need to define correct behavior first +/*void tst_qmlparser::readWriteDotProperty() +{ + QmlComponent component(&engine, "<MyDotPropertyObject readWriteObj.value=\"1\"/>"); + MyDotPropertyObject *object = qobject_cast<MyDotPropertyObject*>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->readWriteObj()->value(),1); + + { + QmlComponent component(&engine, "<MyContainer><MyQmlObject id=\"Obj\" value=\"1\"/><MyDotPropertyObject readWriteObj=\"{Obj}\"/></MyContainer>"); + MyContainer *object = qobject_cast<MyContainer*>(component.create()); + QVERIFY(object != 0); + MyDotPropertyObject *dpo = qobject_cast<MyDotPropertyObject *>(object->children()->at(1)); + QCOMPARE(dpo->readWriteObj()->value(),1); + } +}*/ + +void tst_qmlparser::emptyInput() +{ + QTest::ignoreMessage(QtCriticalMsg, "No Qml was specified for parsing."); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @<unspecified file>:-1"); + QmlComponent component(&engine, ""); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +void tst_qmlparser::missingObject() +{ + QTest::ignoreMessage(QtCriticalMsg, "Can't have a property with no object @<unspecified file>:1"); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @<unspecified file>:-1"); + QmlComponent component(&engine, "<something/>"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + + +void tst_qmlparser::invalidXML() +{ + //extra stuff on end + { + QTest::ignoreMessage(QtCriticalMsg, "Extra content at end of document. @myprogram.qml:1"); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @myprogram.qml:-1"); + QmlComponent component(&engine, "<MyQmlObject/><something/>", QUrl("myprogram.qml")); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + //mismatched tags + { + QTest::ignoreMessage(QtCriticalMsg, "Opening and ending tag mismatch. @myprogram.qml:2"); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @myprogram.qml:-1"); + QmlComponent component(&engine, "<MyQmlObject>\n</MyContainer>", QUrl("myprogram.qml")); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + { + QTest::ignoreMessage(QtCriticalMsg, "Expected '>' or '/', but got '<'. @myprogram.qml:1"); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @myprogram.qml:-1"); + QmlComponent component(&engine, "<MyQmlObject < />", QUrl("myprogram.qml")); + QObject *object = component.create(); + QVERIFY(object == 0); + } + + { + QTest::ignoreMessage(QtCriticalMsg, "Premature end of document. @myprogram.qml:1"); + QTest::ignoreMessage(QtWarningMsg, "Can't compile because of earlier errors @myprogram.qml:-1"); + QmlComponent component(&engine, "<MyQmlObject something=\" />", QUrl("myprogram.qml")); + QObject *object = component.create(); + QVERIFY(object == 0); + } + +} + +void tst_qmlparser::duplicateIDs() +{ + QTest::ignoreMessage(QtWarningMsg, "An id (\"MyID\") is not unique within its scope. @<unspecified file>:3"); + QmlComponent component(&engine, "<MyContainer>\n<MyQmlObject id=\"MyID\"/>\n<MyQmlObject id=\"MyID\"/>\n</MyContainer>"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +void tst_qmlparser::invalidID() +{ + QTest::ignoreMessage(QtWarningMsg, "'1' is not a valid id @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject id=\"1\"/>"); + QObject *object = component.create(); + QVERIFY(object == 0); +} + +void tst_qmlparser::interfaceProperty() +{ + QmlComponent component(&engine, "<MyQmlObject><interface>\n<MyQmlObject/></interface>\n</MyQmlObject>"); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object != 0); + QVERIFY(object->interface()); + QVERIFY(object->interface()->id == 913); +} + +void tst_qmlparser::interfaceQmlList() +{ + QmlComponent component(&engine, "<MyContainer><qmllistInterfaces>\n<MyQmlObject/>\n<MyQmlObject/>\n</qmllistInterfaces>\n</MyContainer>"); + MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QVERIFY(container != 0); + QVERIFY(container->qmllistAccessor().count() == 2); + for(int ii = 0; ii < 2; ++ii) + QVERIFY(container->qmllistAccessor().at(ii)->id == 913); +} + +void tst_qmlparser::interfaceQList() +{ + QmlComponent component(&engine, "<MyContainer><qlistInterfaces>\n<MyQmlObject/>\n<MyQmlObject/>\n</qlistInterfaces>\n</MyContainer>"); + MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QVERIFY(container != 0); + QVERIFY(container->qlistInterfaces()->count() == 2); + for(int ii = 0; ii < 2; ++ii) + QVERIFY(container->qlistInterfaces()->at(ii)->id == 913); +} + +void tst_qmlparser::cannotAssignBindingToSignal() +{ + QTest::ignoreMessage(QtWarningMsg, "Cannot assign binding to signal property @<unspecified file>:1"); + QmlComponent component(&engine, "<MyQmlObject onBasicSignal=\"{print(1921)}\" />"); + MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QVERIFY(container == 0); +} + +void tst_qmlparser::assignObjectToSignal() +{ + QmlComponent component(&engine, "<MyQmlObject><onBasicSignal><MyQmlObject /></onBasicSignal></MyQmlObject>"); + MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(object != 0); + QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); + emit object->basicSignal(); +} + +QTEST_MAIN(tst_qmlparser) + +#include "tst_qmlparser.moc" diff --git a/tests/auto/declarative/repeater/data/repeater.xml b/tests/auto/declarative/repeater/data/repeater.xml new file mode 100644 index 0000000..f863716 --- /dev/null +++ b/tests/auto/declarative/repeater/data/repeater.xml @@ -0,0 +1,7 @@ +<Rect id="container" width="240" height="320" color="white"> + <Repeater id="repeater" width="240" height="320" dataSource="{testData}"> + <Component> + <Text y="{index*20}" text="{modelData}"/> + </Component> + </Repeater> +</Rect> diff --git a/tests/auto/declarative/repeater/repeater.pro b/tests/auto/declarative/repeater/repeater.pro new file mode 100644 index 0000000..0ecd7ee --- /dev/null +++ b/tests/auto/declarative/repeater/repeater.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_repeater.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/repeater/tst_repeater.cpp b/tests/auto/declarative/repeater/tst_repeater.cpp new file mode 100644 index 0000000..cdf1716 --- /dev/null +++ b/tests/auto/declarative/repeater/tst_repeater.cpp @@ -0,0 +1,91 @@ +#include <QtTest/QtTest> +#include <qlistmodelinterface.h> +#include <qfxview.h> +#include <qfxrepeater.h> +#include <qfxtext.h> +#include <qmlcontext.h> + +class tst_QFxRepeater : public QObject +{ + Q_OBJECT +public: + tst_QFxRepeater(); + +private slots: + void stringList(); + +private: + QFxView *createView(const QString &filename); + template<typename T> + T *findItem(QFxItem *parent, const QString &id); +}; + +tst_QFxRepeater::tst_QFxRepeater() +{ +} + +void tst_QFxRepeater::stringList() +{ + QFxView *canvas = createView(SRCDIR "/data/repeater.xml"); + + QStringList data; + data << "One"; + data << "Two"; + data << "Three"; + data << "Four"; + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setProperty("testData", data); + + canvas->execute(); + qApp->processEvents(); + + QFxRepeater *repeater = findItem<QFxRepeater>(canvas->root(), "repeater"); + QVERIFY(repeater != 0); + + QFxItem *container = findItem<QFxItem>(canvas->root(), "container"); + QVERIFY(container != 0); + + QCOMPARE(container->children()->count(), data.count() + 1); + + for (int i = 1; i < container->children()->count(); ++i) { + QFxText *name = qobject_cast<QFxText*>(container->children()->at(i)); + QVERIFY(name != 0); + QCOMPARE(name->text(), data.at(i-1)); + } + + delete canvas; +} + + +QFxView *tst_QFxRepeater::createView(const QString &filename) +{ + QFxView *canvas = new QFxView(0); + canvas->setFixedSize(240,320); + + QFile file(filename); + file.open(QFile::ReadOnly); + QString xml = file.readAll(); + canvas->setXml(xml, filename); + + return canvas; +} + +template<typename T> +T *tst_QFxRepeater::findItem(QFxItem *parent, const QString &id) +{ + const QMetaObject &mo = T::staticMetaObject; + if (mo.cast(parent) && (id.isEmpty() || parent->id() == id)) + return static_cast<T*>(parent); + for (int i = 0; i < parent->children()->count(); ++i) { + QFxItem *item = findItem<T>(parent->children()->at(i), id); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +QTEST_MAIN(tst_QFxRepeater) + +#include "tst_repeater.moc" diff --git a/tests/auto/declarative/simplecanvasitem/data/test.xml b/tests/auto/declarative/simplecanvasitem/data/test.xml new file mode 100644 index 0000000..9b8f10a --- /dev/null +++ b/tests/auto/declarative/simplecanvasitem/data/test.xml @@ -0,0 +1,12 @@ +<Item width="320" height="480"> + <Rect color="blue" x="20" y="20" width="20" height="20"> + <Rect color="black" x="20" y="20" width="10" height="10"/> + </Rect> + <Rect color="red" x="40" y="20" width="20" height="20"/> + <Rect color="green" x="60" y="20" width="20" height="20"/> + <Rect color="yellow" x="20" y="40" width="20" height="20"/> + <Rect color="purple" x="20" y="60" width="20" height="20"/> + <Rect color="white" x="40" y="40" width="20" height="20"/> + <Rect anchors.fill="{parent}" color="gray" z="-1"/> +</Item> + diff --git a/tests/auto/declarative/simplecanvasitem/simplecanvasitem.pro b/tests/auto/declarative/simplecanvasitem/simplecanvasitem.pro new file mode 100644 index 0000000..114be8e --- /dev/null +++ b/tests/auto/declarative/simplecanvasitem/simplecanvasitem.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_simplecanvasitem.cpp + +# Define SRCDIR equal to test's source directory +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/declarative/simplecanvasitem/tst_simplecanvasitem.cpp b/tests/auto/declarative/simplecanvasitem/tst_simplecanvasitem.cpp new file mode 100644 index 0000000..47608a0 --- /dev/null +++ b/tests/auto/declarative/simplecanvasitem/tst_simplecanvasitem.cpp @@ -0,0 +1,79 @@ +#include <QtTest/QtTest> +#include <qfxview.h> +#include <qfxitem.h> +#include <qsimplecanvasitem.h> + +/* + Note: this autotest is specifically to test SimpleCanvasItem as a component of + Qt Declarative, and therefore will have all items created in XML. +*/ +class tst_SimpleCanvasItem : public QObject +{ + Q_OBJECT +public: + tst_SimpleCanvasItem(); + +private slots: + void test_pos(); + void test_scenePos(); +private: + QFxView *createView(const QString &filename); +}; + +tst_SimpleCanvasItem::tst_SimpleCanvasItem() +{ +} + +void tst_SimpleCanvasItem::test_pos() +{ + QFxView *canvas = createView(SRCDIR "/data/test.xml"); + canvas->execute(); + qApp->processEvents(); + QSimpleCanvasItem* root = qobject_cast<QSimpleCanvasItem*>(canvas->root()); + QVERIFY(root); + + QCOMPARE(root->pos(), QPointF(0,0)); + QCOMPARE(root->children().at(0)->pos(), QPointF(20,20)); + QCOMPARE(root->children().at(0)->children().at(0)->pos(), QPointF(20,20)); + QCOMPARE(root->children().at(2)->pos(), QPointF(60,20)); + QCOMPARE(root->children().at(3)->pos(), QPointF(20,40)); + QCOMPARE(root->children().at(5)->pos(), QPointF(40,40)); +} + +void tst_SimpleCanvasItem::test_scenePos() +{ + QFxView *canvas = createView(SRCDIR "/data/test.xml"); + canvas->execute(); + qApp->processEvents(); + QSimpleCanvasItem* root = qobject_cast<QSimpleCanvasItem*>(canvas->root()); + QVERIFY(root); + +#ifdef CANVAS_GL + QCOMPARE(root->transform(), QMatrix4x4()); +#else + QCOMPARE(root->transform(), QTransform()); +#endif + QCOMPARE(root->scenePos(), QPointF(0,0)); + QCOMPARE(root->children().at(0)->scenePos(), QPointF(20,20)); + QCOMPARE(root->children().at(0)->children().at(0)->scenePos(), QPointF(40,40)); + QCOMPARE(root->children().at(2)->scenePos(), QPointF(60,20)); + QCOMPARE(root->children().at(3)->scenePos(), QPointF(20,40)); + QCOMPARE(root->children().at(5)->scenePos(), QPointF(40,40)); +} + +QFxView *tst_SimpleCanvasItem::createView(const QString &filename) +{ + QFxView *canvas = new QFxView(0); + canvas->setFixedSize(240,320); + + QFile file(filename); + file.open(QFile::ReadOnly); + QString xml = file.readAll(); + canvas->setXml(xml, filename); + + return canvas; +} + +QTEST_MAIN(tst_SimpleCanvasItem) + +#include "tst_simplecanvasitem.moc" diff --git a/tests/auto/declarative/visual/ListView/basic1/basic1.xml b/tests/auto/declarative/visual/ListView/basic1/basic1.xml new file mode 100644 index 0000000..5038c0a --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic1/basic1.xml @@ -0,0 +1,19 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <ListView anchors.fill="{parent}"> + <delegate> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </delegate> + <model> + <ListModel> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + </model> + </ListView> +</Rect> diff --git a/tests/auto/declarative/visual/ListView/basic1/data/opengl/image0.png b/tests/auto/declarative/visual/ListView/basic1/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..403b407 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic1/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/ListView/basic1/data/opengl/manifest.xml b/tests/auto/declarative/visual/ListView/basic1/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic1/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/ListView/basic1/test b/tests/auto/declarative/visual/ListView/basic1/test new file mode 100644 index 0000000..62f0665 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic1/test @@ -0,0 +1 @@ +basic1.xml diff --git a/tests/auto/declarative/visual/ListView/basic2/basic2.xml b/tests/auto/declarative/visual/ListView/basic2/basic2.xml new file mode 100644 index 0000000..5e139fe --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic2/basic2.xml @@ -0,0 +1,20 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <Component id="Delegate"> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </Component> + + <ListView anchors.fill="{parent}" delegate="{Delegate}"> + <model> + <ListModel> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + </model> + </ListView> +</Rect> diff --git a/tests/auto/declarative/visual/ListView/basic2/data/opengl/image0.png b/tests/auto/declarative/visual/ListView/basic2/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..403b407 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic2/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/ListView/basic2/data/opengl/manifest.xml b/tests/auto/declarative/visual/ListView/basic2/data/opengl/manifest.xml new file mode 100644 index 0000000..f3fa6c9 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic2/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="31" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/ListView/basic2/test b/tests/auto/declarative/visual/ListView/basic2/test new file mode 100644 index 0000000..ae974fe --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic2/test @@ -0,0 +1 @@ +basic2.xml diff --git a/tests/auto/declarative/visual/ListView/basic3/basic3.xml b/tests/auto/declarative/visual/ListView/basic3/basic3.xml new file mode 100644 index 0000000..a587b82 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic3/basic3.xml @@ -0,0 +1,18 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <ListModel id="Model"> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + + <ListView anchors.fill="{parent}" model="{Model}"> + <delegate> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </delegate> + </ListView> +</Rect> diff --git a/tests/auto/declarative/visual/ListView/basic3/data/opengl/image0.png b/tests/auto/declarative/visual/ListView/basic3/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..403b407 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic3/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/ListView/basic3/data/opengl/manifest.xml b/tests/auto/declarative/visual/ListView/basic3/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic3/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/ListView/basic3/test b/tests/auto/declarative/visual/ListView/basic3/test new file mode 100644 index 0000000..ea3154e --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic3/test @@ -0,0 +1 @@ +basic3.xml diff --git a/tests/auto/declarative/visual/ListView/basic4/basic4.xml b/tests/auto/declarative/visual/ListView/basic4/basic4.xml new file mode 100644 index 0000000..4b9201c --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic4/basic4.xml @@ -0,0 +1,19 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <ListModel id="Model"> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + + <Component id="Delegate"> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </Component> + + <ListView anchors.fill="{parent}" model="{Model}" delegate="{Delegate}"> + </ListView> +</Rect> diff --git a/tests/auto/declarative/visual/ListView/basic4/data/opengl/image0.png b/tests/auto/declarative/visual/ListView/basic4/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..403b407 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic4/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/ListView/basic4/data/opengl/manifest.xml b/tests/auto/declarative/visual/ListView/basic4/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic4/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/ListView/basic4/test b/tests/auto/declarative/visual/ListView/basic4/test new file mode 100644 index 0000000..891e0be --- /dev/null +++ b/tests/auto/declarative/visual/ListView/basic4/test @@ -0,0 +1 @@ +basic4.xml diff --git a/tests/auto/declarative/visual/bindinganimation/bindinganimation.xml b/tests/auto/declarative/visual/bindinganimation/bindinganimation.xml new file mode 100644 index 0000000..30b0b6a --- /dev/null +++ b/tests/auto/declarative/visual/bindinganimation/bindinganimation.xml @@ -0,0 +1,19 @@ +<Rect color="blue" width="320" height="240" id="Page"> + <Rect id="MyRect" width="100" height="100" color="red" x="{10}" /> + + <states> + <State name="hello"> + <SetProperty target="{MyRect}" property="x" binding="100" /> + <SetProperty target="{MyMouseRegion}" property="onClick" value="Page.currentState = ''" /> + </State> + </states> + + <transitions> + <Transition> + <NumericAnimation properties="x" /> + </Transition> + </transitions> + + <MouseRegion id="MyMouseRegion" anchors.fill="{parent}" onClick="Page.currentState= 'hello'" /> + +</Rect> diff --git a/tests/auto/declarative/visual/bindinganimation/data/opengl/image0.png b/tests/auto/declarative/visual/bindinganimation/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..2cda3fa --- /dev/null +++ b/tests/auto/declarative/visual/bindinganimation/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest-play.xml b/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest-play.xml new file mode 100644 index 0000000..6c5856f --- /dev/null +++ b/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest-play.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="1770" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="1860" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="1860" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="1920" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="1950" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="1980" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="2010" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="2040" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="2070" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="2100" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="2130" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="2160" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="2190" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="2220" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="2250" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="2280" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="2310" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="2340" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="2370" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="2400" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestMouse time="2820" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="2910" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="2910" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestFrame time="2970" hash="ADC501A3A2B8AAF72F58BA985B57424E"/> + <TestFrame time="3000" hash="BFA51B7C19753EF7B16D78AFFFC7B9DD"/> + <TestFrame time="3030" hash="A93F930EC8528F954CD4A770C9A8171B"/> + <TestFrame time="3060" hash="0B0C6419E1E5B016D9C22BD98FD452B1"/> + <TestFrame time="3090" hash="1D5CD86AB732DA3705A7BB1DEAB77923"/> + <TestFrame time="3120" hash="69058485CED6BC992A1A7C5EE34ADD4C"/> + <TestFrame time="3150" hash="72731478D80F024076EA639B55152360"/> + <TestFrame time="3180" hash="37739777A5979F3EBF85E47E63341660"/> + <TestFrame time="3210" hash="FCAE0317F81A3DDD713F4DB1349A9DA0"/> + <TestFrame time="3240" hash="82363265ED2B611A54F8D48B2AF22F11"/> + <TestFrame time="3270" hash="5FAE0BDC65C609CB766CE585B8C649DB"/> + <TestFrame time="3300" hash="2D21B4AF3780EF2BBCCFCEC957CE49C8"/> + <TestFrame time="3330" hash="4AB21E266919FB8D340F87091D8E1F62"/> + <TestFrame time="3360" hash="5F5DA43901938FA244F536336FFD2DFC"/> + <TestFrame time="3390" hash="9B7685F5933C5E06883EE4D1BB2BD2C6"/> + <TestFrame time="3420" hash="96C077E3A572EDFF04FA9B2F7020FFD0"/> + <TestFrame time="3450" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestMouse time="3840" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="3930" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="3930" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="3990" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="4020" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="4050" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="4080" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="4110" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="4140" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="4170" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="4200" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="4230" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="4260" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="4290" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="4320" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="4350" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="4380" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="4410" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="4440" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="4470" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestMouse time="4920" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="5010" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="5010" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestFrame time="5070" hash="ADC501A3A2B8AAF72F58BA985B57424E"/> + <TestFrame time="5100" hash="BFA51B7C19753EF7B16D78AFFFC7B9DD"/> + <TestFrame time="5130" hash="A93F930EC8528F954CD4A770C9A8171B"/> + <TestFrame time="5160" hash="0B0C6419E1E5B016D9C22BD98FD452B1"/> + <TestFrame time="5190" hash="1D5CD86AB732DA3705A7BB1DEAB77923"/> + <TestFrame time="5220" hash="69058485CED6BC992A1A7C5EE34ADD4C"/> + <TestFrame time="5250" hash="72731478D80F024076EA639B55152360"/> + <TestFrame time="5280" hash="37739777A5979F3EBF85E47E63341660"/> + <TestFrame time="5310" hash="FCAE0317F81A3DDD713F4DB1349A9DA0"/> + <TestFrame time="5340" hash="82363265ED2B611A54F8D48B2AF22F11"/> + <TestFrame time="5370" hash="5FAE0BDC65C609CB766CE585B8C649DB"/> + <TestFrame time="5400" hash="2D21B4AF3780EF2BBCCFCEC957CE49C8"/> + <TestFrame time="5430" hash="4AB21E266919FB8D340F87091D8E1F62"/> + <TestFrame time="5460" hash="5F5DA43901938FA244F536336FFD2DFC"/> + <TestFrame time="5490" hash="9B7685F5933C5E06883EE4D1BB2BD2C6"/> + <TestFrame time="5520" hash="96C077E3A572EDFF04FA9B2F7020FFD0"/> + <TestFrame time="5550" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestMouse time="5910" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="6030" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="6030" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="6090" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="6120" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="6150" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="6180" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="6210" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="6240" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="6270" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="6300" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="6330" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="6360" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="6390" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="6420" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="6450" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="6480" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="6510" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="6540" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="6570" hash="383BA6B9EFCC58FCA512982A207631F6"/> +</TestLog> diff --git a/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest.xml b/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest.xml new file mode 100644 index 0000000..6c5856f --- /dev/null +++ b/tests/auto/declarative/visual/bindinganimation/data/opengl/manifest.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="1770" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="1860" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="1860" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="1920" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="1950" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="1980" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="2010" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="2040" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="2070" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="2100" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="2130" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="2160" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="2190" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="2220" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="2250" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="2280" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="2310" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="2340" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="2370" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="2400" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestMouse time="2820" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="2910" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="2910" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestFrame time="2970" hash="ADC501A3A2B8AAF72F58BA985B57424E"/> + <TestFrame time="3000" hash="BFA51B7C19753EF7B16D78AFFFC7B9DD"/> + <TestFrame time="3030" hash="A93F930EC8528F954CD4A770C9A8171B"/> + <TestFrame time="3060" hash="0B0C6419E1E5B016D9C22BD98FD452B1"/> + <TestFrame time="3090" hash="1D5CD86AB732DA3705A7BB1DEAB77923"/> + <TestFrame time="3120" hash="69058485CED6BC992A1A7C5EE34ADD4C"/> + <TestFrame time="3150" hash="72731478D80F024076EA639B55152360"/> + <TestFrame time="3180" hash="37739777A5979F3EBF85E47E63341660"/> + <TestFrame time="3210" hash="FCAE0317F81A3DDD713F4DB1349A9DA0"/> + <TestFrame time="3240" hash="82363265ED2B611A54F8D48B2AF22F11"/> + <TestFrame time="3270" hash="5FAE0BDC65C609CB766CE585B8C649DB"/> + <TestFrame time="3300" hash="2D21B4AF3780EF2BBCCFCEC957CE49C8"/> + <TestFrame time="3330" hash="4AB21E266919FB8D340F87091D8E1F62"/> + <TestFrame time="3360" hash="5F5DA43901938FA244F536336FFD2DFC"/> + <TestFrame time="3390" hash="9B7685F5933C5E06883EE4D1BB2BD2C6"/> + <TestFrame time="3420" hash="96C077E3A572EDFF04FA9B2F7020FFD0"/> + <TestFrame time="3450" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestMouse time="3840" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="3930" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="3930" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="3990" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="4020" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="4050" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="4080" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="4110" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="4140" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="4170" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="4200" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="4230" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="4260" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="4290" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="4320" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="4350" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="4380" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="4410" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="4440" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="4470" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestMouse time="4920" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="5010" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="5010" hash="383BA6B9EFCC58FCA512982A207631F6"/> + <TestFrame time="5070" hash="ADC501A3A2B8AAF72F58BA985B57424E"/> + <TestFrame time="5100" hash="BFA51B7C19753EF7B16D78AFFFC7B9DD"/> + <TestFrame time="5130" hash="A93F930EC8528F954CD4A770C9A8171B"/> + <TestFrame time="5160" hash="0B0C6419E1E5B016D9C22BD98FD452B1"/> + <TestFrame time="5190" hash="1D5CD86AB732DA3705A7BB1DEAB77923"/> + <TestFrame time="5220" hash="69058485CED6BC992A1A7C5EE34ADD4C"/> + <TestFrame time="5250" hash="72731478D80F024076EA639B55152360"/> + <TestFrame time="5280" hash="37739777A5979F3EBF85E47E63341660"/> + <TestFrame time="5310" hash="FCAE0317F81A3DDD713F4DB1349A9DA0"/> + <TestFrame time="5340" hash="82363265ED2B611A54F8D48B2AF22F11"/> + <TestFrame time="5370" hash="5FAE0BDC65C609CB766CE585B8C649DB"/> + <TestFrame time="5400" hash="2D21B4AF3780EF2BBCCFCEC957CE49C8"/> + <TestFrame time="5430" hash="4AB21E266919FB8D340F87091D8E1F62"/> + <TestFrame time="5460" hash="5F5DA43901938FA244F536336FFD2DFC"/> + <TestFrame time="5490" hash="9B7685F5933C5E06883EE4D1BB2BD2C6"/> + <TestFrame time="5520" hash="96C077E3A572EDFF04FA9B2F7020FFD0"/> + <TestFrame time="5550" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestMouse time="5910" type="2" button="1" buttons="1" globalPos="614,528" pos="175,131"/> + <TestMouse time="6030" type="3" button="1" buttons="0" globalPos="614,528" pos="175,131"/> + <TestFrame time="6030" hash="7CB5FC371040E587DE9F06CE14A4B29A"/> + <TestFrame time="6090" hash="8F88EE8780C32F038C9ACDC7172DE04E"/> + <TestFrame time="6120" hash="BE859D598C5DB953A8FC506DED4940EB"/> + <TestFrame time="6150" hash="16FE17B15900FF0464AB20EA921E5B1F"/> + <TestFrame time="6180" hash="FCB17070EF24575C61046928A8BBE440"/> + <TestFrame time="6210" hash="4F58226BDBDA7339D972ECA065F75766"/> + <TestFrame time="6240" hash="D9AF30557F99B086BB1A185A946B580D"/> + <TestFrame time="6270" hash="082E0E7650D187A54EF0948CCCA98E5A"/> + <TestFrame time="6300" hash="4F41101378A104E72228EEB4BA395CA8"/> + <TestFrame time="6330" hash="3223ED179C828FADB3ECA9C6373176C1"/> + <TestFrame time="6360" hash="DAFCCE427161A70C3513841AC22AEA00"/> + <TestFrame time="6390" hash="7F465A99FCA50503736E470A0B4E1C7A"/> + <TestFrame time="6420" hash="97542160B249135B1F3957DBBB329C2E"/> + <TestFrame time="6450" hash="F9F74A2E38B52C9266F33E428B6ACD9D"/> + <TestFrame time="6480" hash="65AD7E0189C096792331BD1BB0DAF0DB"/> + <TestFrame time="6510" hash="BA403842BA3128B1CDF6A9CB28C90751"/> + <TestFrame time="6540" hash="1BCDCD0E8166D69F4349E05D5E92FD9D"/> + <TestFrame time="6570" hash="383BA6B9EFCC58FCA512982A207631F6"/> +</TestLog> diff --git a/tests/auto/declarative/visual/bindinganimation/test b/tests/auto/declarative/visual/bindinganimation/test new file mode 100644 index 0000000..964c489 --- /dev/null +++ b/tests/auto/declarative/visual/bindinganimation/test @@ -0,0 +1 @@ +bindinganimation.xml diff --git a/tests/auto/declarative/visual/colorAnimation/colorAnimation.xml b/tests/auto/declarative/visual/colorAnimation/colorAnimation.xml new file mode 100644 index 0000000..39d08be --- /dev/null +++ b/tests/auto/declarative/visual/colorAnimation/colorAnimation.xml @@ -0,0 +1,18 @@ +<Rect id="mainrect" currentState="first"> +<states> + <State name="first"> + <SetProperty target="{mainrect}" property="color" value="red"/> + </State> + <State name="second" > + <SetProperty target="{mainrect}" property="color" value="blue"/> + </State> +</states> +<transitions> + <Transition fromState="first" toState="second" reversible="true" > + <SerialAnimation> + <ColorAnimation duration="2000" target="{mainrect}" property="color" /> + </SerialAnimation> + </Transition> +</transitions> +<MouseRegion anchors.fill="{parent}" onClick="mainrect.currentState = 'second'" /> +</Rect> diff --git a/tests/auto/declarative/visual/colorAnimation/image0.png b/tests/auto/declarative/visual/colorAnimation/image0.png Binary files differnew file mode 100644 index 0000000..9e1caf7 --- /dev/null +++ b/tests/auto/declarative/visual/colorAnimation/image0.png diff --git a/tests/auto/declarative/visual/colorAnimation/manifest-play.xml b/tests/auto/declarative/visual/colorAnimation/manifest-play.xml new file mode 100644 index 0000000..8e3de2e --- /dev/null +++ b/tests/auto/declarative/visual/colorAnimation/manifest-play.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="480" type="2" button="1" buttons="1" globalPos="93,129" pos="89,102"/> + <TestMouse time="570" type="3" button="1" buttons="0" globalPos="93,129" pos="89,102"/> + <TestFrame time="630" hash="D42762ECD293C6922C5F9593126DE636"/> + <TestFrame time="660" hash="8962505FCCB2E7559A99A8EDD325A82B"/> + <TestFrame time="690" hash="6812EFDA80607D4FA05CD3A5077F8EF7"/> + <TestFrame time="720" hash="A116DF73809679C1C5F9261F49B989F0"/> + <TestFrame time="750" hash="DC1B9D40AEE306171AD6625DDCA4EB45"/> + <TestFrame time="780" hash="B2DAF0E4C32080229664A8B0A155DE3B"/> + <TestFrame time="810" hash="496677B0D8707B91566D1244C46D50DB"/> + <TestFrame time="840" hash="A6558D8B0D1FB1D11BEBE36C078386CE"/> + <TestFrame time="870" hash="601436BB436D391B0BD5FCC289666208"/> + <TestFrame time="900" hash="8CF3CF9EAD875497870CC7C1035802DC"/> + <TestFrame time="930" hash="FF6BA6BAC30DADD3DBBFD96F127EB1FE"/> + <TestFrame time="960" hash="1D97A2A6890078DCF4CE9E508E5F9F08"/> + <TestFrame time="990" hash="58C9116FDDD03DD036820EFCD0DCD392"/> + <TestFrame time="1020" hash="E51287B911C140B41D350FCB2091AB80"/> + <TestFrame time="1050" hash="7B107411B436FABE469A069E6E5B0C3C"/> + <TestFrame time="1080" hash="9D1CB0E58F2BD00DDA0FB463F6BFF526"/> + <TestFrame time="1110" hash="35AB7788489B79E5A5C6F2BE11AFC9E1"/> + <TestFrame time="1140" hash="C82177AC4A7A497469292C5F0F8C4913"/> + <TestFrame time="1170" hash="18763D1B911FDC524DB9E7B2569FE984"/> + <TestFrame time="1200" hash="27F63572AAEF6D835272D5D65FCF608B"/> + <TestFrame time="1230" hash="585727CAEC1F83ADB9E422BAF058A622"/> + <TestFrame time="1260" hash="2C3BBFEFBE6E5FDA1905E9F50985E1B4"/> + <TestFrame time="1290" hash="81675C4ABB2696D960BC5F204F05F16B"/> + <TestFrame time="1320" hash="6D0F3CCC06EF1E3A895ECC9A8DE90039"/> + <TestFrame time="1350" hash="0BF36093CCAEA8BDAE96D4939A8DDE20"/> + <TestFrame time="1380" hash="5A1CBC68AB59977B65492B0F8A664418"/> + <TestFrame time="1410" hash="C35831A8C59D56193CED2C4AADB4DFCE"/> + <TestFrame time="1440" hash="ED15973425A8B8528896B344A61393AA"/> + <TestFrame time="1470" hash="EA8FC02A8606680C089F0C0CE454ABE3"/> + <TestFrame time="1500" hash="CFB5CFBA0A0BC62C0D03908FB9599A8E"/> + <TestFrame time="1530" hash="09FAA04AFB50B48BD6A83F9E25F9DDDB"/> + <TestFrame time="1560" hash="0FDD0B8CDCCEB78C7C67AB0F5EA74D6A"/> + <TestFrame time="1590" hash="058D26146879900B5E5CCE05AE38BA0E"/> + <TestFrame time="1620" hash="80F9074C50F967C99D4C3A3FF9EC3E71"/> + <TestFrame time="1650" hash="AD9BDCEEC1C058D6B658C5BA0D0BC1F0"/> + <TestFrame time="1680" hash="AC14DF5458F91001181154F8C68BCE2B"/> + <TestFrame time="1710" hash="AE9225263E4C8E75E4D0F1D7192B4260"/> + <TestFrame time="1740" hash="D3D50F1B7F476E79E5B99E0E6D4CF827"/> + <TestFrame time="1770" hash="A1367445C5232ACCBF4904A415416EA4"/> + <TestFrame time="1800" hash="A21C0F1DA9B64A5B000558BA1F2E495D"/> + <TestFrame time="1830" hash="61AF477B6FB22E38E698375EA5793D22"/> + <TestFrame time="1860" hash="B3AD3501D527939CEAA4F124AB10B2DF"/> + <TestFrame time="1890" hash="0C2BF65A43AE87AFB0068F9FA4A74707"/> + <TestFrame time="1920" hash="5B7F96C797BEE4FD1B04538DE5549C1B"/> + <TestFrame time="1950" hash="4C861E936A3F1AFE323395E30174F8CC"/> + <TestFrame time="1980" hash="87F1966E5B0E924EB7CEED5520D120BF"/> + <TestFrame time="2010" hash="1980755E0D80469D4DC0B9B0309F2DEB"/> + <TestFrame time="2040" hash="38A7ACC2E5607FC0965B7B376A0D3524"/> + <TestFrame time="2070" hash="4434746833EFF5A3A76491024763990A"/> + <TestFrame time="2100" hash="A8BAD928F92E851B45723068B7FEF739"/> + <TestFrame time="2130" hash="A96F5C522C0ECA5C78E982E4235218CB"/> + <TestFrame time="2160" hash="135F0EFEDE2832B76F49966EBD629879"/> + <TestFrame time="2190" hash="A51C6E443413F184CAAE8A7F98A369C8"/> + <TestFrame time="2220" hash="62A7521EE62E6A2543B3141C1EFCE72A"/> + <TestFrame time="2250" hash="D416A41125659167B3E6AD68F66F6E64"/> + <TestFrame time="2280" hash="0F653B5E965665A43F50437724DC704C"/> + <TestFrame time="2310" hash="13A6E2485179501FF3AA8BA91A5050B4"/> + <TestFrame time="2340" hash="9423475D3832FBABEC56B80FA9161020"/> + <TestFrame time="2370" hash="497B21108A6CB127DB066B32D06D992A"/> + <TestFrame time="2400" hash="22F01CB9B4F8FF01410566A61E281373"/> + <TestFrame time="2430" hash="A099640BC088E14E20585CB87FC5C6F1"/> + <TestFrame time="2460" hash="AC2954553C333EA1D524CE51CD35958A"/> + <TestFrame time="2490" hash="771E882CC788BECAA82E71E6FBAB150D"/> + <TestFrame time="2520" hash="42CEDA45D88A8D2B3DA5B749F4C3C1BF"/> + <TestFrame time="2550" hash="C6E1F91B917E47246E012D1B203E0DC2"/> + <TestFrame time="2580" hash="EFB3E57CF265B6E36AA4DF72771D119C"/> + <TestFrame time="2610" hash="657FC7FD496E5A2FC84F63930E0D1DE3"/> +</TestLog> diff --git a/tests/auto/declarative/visual/colorAnimation/manifest.xml b/tests/auto/declarative/visual/colorAnimation/manifest.xml new file mode 100644 index 0000000..8e3de2e --- /dev/null +++ b/tests/auto/declarative/visual/colorAnimation/manifest.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="480" type="2" button="1" buttons="1" globalPos="93,129" pos="89,102"/> + <TestMouse time="570" type="3" button="1" buttons="0" globalPos="93,129" pos="89,102"/> + <TestFrame time="630" hash="D42762ECD293C6922C5F9593126DE636"/> + <TestFrame time="660" hash="8962505FCCB2E7559A99A8EDD325A82B"/> + <TestFrame time="690" hash="6812EFDA80607D4FA05CD3A5077F8EF7"/> + <TestFrame time="720" hash="A116DF73809679C1C5F9261F49B989F0"/> + <TestFrame time="750" hash="DC1B9D40AEE306171AD6625DDCA4EB45"/> + <TestFrame time="780" hash="B2DAF0E4C32080229664A8B0A155DE3B"/> + <TestFrame time="810" hash="496677B0D8707B91566D1244C46D50DB"/> + <TestFrame time="840" hash="A6558D8B0D1FB1D11BEBE36C078386CE"/> + <TestFrame time="870" hash="601436BB436D391B0BD5FCC289666208"/> + <TestFrame time="900" hash="8CF3CF9EAD875497870CC7C1035802DC"/> + <TestFrame time="930" hash="FF6BA6BAC30DADD3DBBFD96F127EB1FE"/> + <TestFrame time="960" hash="1D97A2A6890078DCF4CE9E508E5F9F08"/> + <TestFrame time="990" hash="58C9116FDDD03DD036820EFCD0DCD392"/> + <TestFrame time="1020" hash="E51287B911C140B41D350FCB2091AB80"/> + <TestFrame time="1050" hash="7B107411B436FABE469A069E6E5B0C3C"/> + <TestFrame time="1080" hash="9D1CB0E58F2BD00DDA0FB463F6BFF526"/> + <TestFrame time="1110" hash="35AB7788489B79E5A5C6F2BE11AFC9E1"/> + <TestFrame time="1140" hash="C82177AC4A7A497469292C5F0F8C4913"/> + <TestFrame time="1170" hash="18763D1B911FDC524DB9E7B2569FE984"/> + <TestFrame time="1200" hash="27F63572AAEF6D835272D5D65FCF608B"/> + <TestFrame time="1230" hash="585727CAEC1F83ADB9E422BAF058A622"/> + <TestFrame time="1260" hash="2C3BBFEFBE6E5FDA1905E9F50985E1B4"/> + <TestFrame time="1290" hash="81675C4ABB2696D960BC5F204F05F16B"/> + <TestFrame time="1320" hash="6D0F3CCC06EF1E3A895ECC9A8DE90039"/> + <TestFrame time="1350" hash="0BF36093CCAEA8BDAE96D4939A8DDE20"/> + <TestFrame time="1380" hash="5A1CBC68AB59977B65492B0F8A664418"/> + <TestFrame time="1410" hash="C35831A8C59D56193CED2C4AADB4DFCE"/> + <TestFrame time="1440" hash="ED15973425A8B8528896B344A61393AA"/> + <TestFrame time="1470" hash="EA8FC02A8606680C089F0C0CE454ABE3"/> + <TestFrame time="1500" hash="CFB5CFBA0A0BC62C0D03908FB9599A8E"/> + <TestFrame time="1530" hash="09FAA04AFB50B48BD6A83F9E25F9DDDB"/> + <TestFrame time="1560" hash="0FDD0B8CDCCEB78C7C67AB0F5EA74D6A"/> + <TestFrame time="1590" hash="058D26146879900B5E5CCE05AE38BA0E"/> + <TestFrame time="1620" hash="80F9074C50F967C99D4C3A3FF9EC3E71"/> + <TestFrame time="1650" hash="AD9BDCEEC1C058D6B658C5BA0D0BC1F0"/> + <TestFrame time="1680" hash="AC14DF5458F91001181154F8C68BCE2B"/> + <TestFrame time="1710" hash="AE9225263E4C8E75E4D0F1D7192B4260"/> + <TestFrame time="1740" hash="D3D50F1B7F476E79E5B99E0E6D4CF827"/> + <TestFrame time="1770" hash="A1367445C5232ACCBF4904A415416EA4"/> + <TestFrame time="1800" hash="A21C0F1DA9B64A5B000558BA1F2E495D"/> + <TestFrame time="1830" hash="61AF477B6FB22E38E698375EA5793D22"/> + <TestFrame time="1860" hash="B3AD3501D527939CEAA4F124AB10B2DF"/> + <TestFrame time="1890" hash="0C2BF65A43AE87AFB0068F9FA4A74707"/> + <TestFrame time="1920" hash="5B7F96C797BEE4FD1B04538DE5549C1B"/> + <TestFrame time="1950" hash="4C861E936A3F1AFE323395E30174F8CC"/> + <TestFrame time="1980" hash="87F1966E5B0E924EB7CEED5520D120BF"/> + <TestFrame time="2010" hash="1980755E0D80469D4DC0B9B0309F2DEB"/> + <TestFrame time="2040" hash="38A7ACC2E5607FC0965B7B376A0D3524"/> + <TestFrame time="2070" hash="4434746833EFF5A3A76491024763990A"/> + <TestFrame time="2100" hash="A8BAD928F92E851B45723068B7FEF739"/> + <TestFrame time="2130" hash="A96F5C522C0ECA5C78E982E4235218CB"/> + <TestFrame time="2160" hash="135F0EFEDE2832B76F49966EBD629879"/> + <TestFrame time="2190" hash="A51C6E443413F184CAAE8A7F98A369C8"/> + <TestFrame time="2220" hash="62A7521EE62E6A2543B3141C1EFCE72A"/> + <TestFrame time="2250" hash="D416A41125659167B3E6AD68F66F6E64"/> + <TestFrame time="2280" hash="0F653B5E965665A43F50437724DC704C"/> + <TestFrame time="2310" hash="13A6E2485179501FF3AA8BA91A5050B4"/> + <TestFrame time="2340" hash="9423475D3832FBABEC56B80FA9161020"/> + <TestFrame time="2370" hash="497B21108A6CB127DB066B32D06D992A"/> + <TestFrame time="2400" hash="22F01CB9B4F8FF01410566A61E281373"/> + <TestFrame time="2430" hash="A099640BC088E14E20585CB87FC5C6F1"/> + <TestFrame time="2460" hash="AC2954553C333EA1D524CE51CD35958A"/> + <TestFrame time="2490" hash="771E882CC788BECAA82E71E6FBAB150D"/> + <TestFrame time="2520" hash="42CEDA45D88A8D2B3DA5B749F4C3C1BF"/> + <TestFrame time="2550" hash="C6E1F91B917E47246E012D1B203E0DC2"/> + <TestFrame time="2580" hash="EFB3E57CF265B6E36AA4DF72771D119C"/> + <TestFrame time="2610" hash="657FC7FD496E5A2FC84F63930E0D1DE3"/> +</TestLog> diff --git a/tests/auto/declarative/visual/easing/easing.xml b/tests/auto/declarative/visual/easing/easing.xml new file mode 100644 index 0000000..01a7d6c --- /dev/null +++ b/tests/auto/declarative/visual/easing/easing.xml @@ -0,0 +1,70 @@ +<Rect id="item" width="600" height="{layout.height}" color="white"> + <resources> + <ListModel id="easingtypes"> + <ListItem><type>easeNone</type></ListItem> + <ListItem><type>easeInQuad</type></ListItem> + <ListItem><type>easeOutQuad</type></ListItem> + <ListItem><type>easeInOutQuad</type></ListItem> + <ListItem><type>easeOutInQuad</type></ListItem> + <ListItem><type>easeInCubic</type></ListItem> + <ListItem><type>easeOutCubic</type></ListItem> + <ListItem><type>easeInOutCubic</type></ListItem> + <ListItem><type>easeOutInCubic</type></ListItem> + <ListItem><type>easeInQuart</type></ListItem> + <ListItem><type>easeOutQuart</type></ListItem> + <ListItem><type>easeInOutQuart</type></ListItem> + <ListItem><type>easeOutInQuart</type></ListItem> + <ListItem><type>easeInQuint</type></ListItem> + <ListItem><type>easeOutQuint</type></ListItem> + <ListItem><type>easeInOutQuint</type></ListItem> + <ListItem><type>easeOutInQuint</type></ListItem> + <ListItem><type>easeInSine</type></ListItem> + <ListItem><type>easeOutSine</type></ListItem> + <ListItem><type>easeInOutSine</type></ListItem> + <ListItem><type>easeOutInSine</type></ListItem> + <ListItem><type>easeInExpo</type></ListItem> + <ListItem><type>easeOutExpo</type></ListItem> + <ListItem><type>easeInOutExpo</type></ListItem> + <ListItem><type>easeOutInExpo</type></ListItem> + <ListItem><type>easeInCirc</type></ListItem> + <ListItem><type>easeOutCirc</type></ListItem> + <ListItem><type>easeInOutCirc</type></ListItem> + <ListItem><type>easeOutInCirc</type></ListItem> + <ListItem><type>easeInElastic</type></ListItem> + <ListItem><type>easeOutElastic</type></ListItem> + <ListItem><type>easeInOutElastic</type></ListItem> + <ListItem><type>easeOutInElastic</type></ListItem> + <ListItem><type>easeInBack</type></ListItem> + <ListItem><type>easeOutBack</type></ListItem> + <ListItem><type>easeInOutBack</type></ListItem> + <ListItem><type>easeOutInBack</type></ListItem> + <ListItem><type>easeOutBounce</type></ListItem> + <ListItem><type>easeInBounce</type></ListItem> + <ListItem><type>easeInOutBounce</type></ListItem> + <ListItem><type>easeOutInBounce</type></ListItem> + </ListModel> + </resources> + + <VerticalLayout id="layout" anchors.left="{item.left}" anchors.right="{item.right}"> + <Repeater dataSource="{easingtypes}" > + <Component> + <Text id="text" text="{type}" height="18" font.italic="true" color="black"> + <states> + <State name="from" when="{!mouse.pressed}"> + <SetProperty target="{text}" property="x" value="0"/> + </State> + <State name="to" when="{mouse.pressed}"> + <SetProperty target="{text}" property="x" value="{item.width-100}"/> + </State> + </states> + <transitions> + <Transition fromState="*" toState="to" reversible="true"> + <NumericAnimation properties="x" easing="{type}" /> + </Transition> + </transitions> + </Text> + </Component> + </Repeater> + </VerticalLayout> + <MouseRegion id="mouse" anchors.fill="{layout}"/> +</Rect> diff --git a/tests/auto/declarative/visual/easing/image0.png b/tests/auto/declarative/visual/easing/image0.png Binary files differnew file mode 100644 index 0000000..dbe03aa --- /dev/null +++ b/tests/auto/declarative/visual/easing/image0.png diff --git a/tests/auto/declarative/visual/easing/manifest-play.xml b/tests/auto/declarative/visual/easing/manifest-play.xml new file mode 100644 index 0000000..3c84452 --- /dev/null +++ b/tests/auto/declarative/visual/easing/manifest-play.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="480" type="2" button="1" buttons="1" globalPos="487,444" pos="483,417"/> + <TestFrame time="510" hash="83FB660D6CABAAFCB27C6EC001B14110"/> + <TestFrame time="540" hash="27FCD68F610024000CA6D3A8D9F0CF09"/> + <TestFrame time="570" hash="14728A6160AF51FCA8562D6A020BBA79"/> + <TestFrame time="600" hash="BDDB81682B30A6918927ACB59608D14E"/> + <TestFrame time="630" hash="03F16A41DCD31E41935E54763757C6D5"/> + <TestFrame time="660" hash="2D04EA1EBEDC77CF5D42A1B491A57EA6"/> + <TestFrame time="690" hash="762C36B33B75F24427CA45F4AD06B64E"/> + <TestFrame time="720" hash="AA02624CC889C95A99BBE58365F4FAAD"/> + <TestFrame time="750" hash="0529200188188708A18CE0F931780DBD"/> + <TestFrame time="780" hash="56036B63822AF34F26B149069CD189C6"/> + <TestFrame time="810" hash="CFFC6583E2BA1E47E1439BED6FE69665"/> + <TestFrame time="840" hash="25A1AFDC945D5264FF0337A421143A3C"/> + <TestFrame time="870" hash="601FA34B5E15E7B87E6490580C2E1858"/> + <TestFrame time="900" hash="1CA085F6CB8509957A51F6182F7F5443"/> + <TestFrame time="930" hash="09B5849DF18F6817F7450230DFEC0E95"/> + <TestFrame time="960" hash="15D212C1291DF97E3DEA5AA8793AD5CB"/> + <TestFrame time="990" hash="D6E42E8F4D06BDDBAE998079AC2C79AD"/> + <TestFrame time="1020" hash="7016B5C435006D859AB087A73299B6D5"/> +</TestLog> diff --git a/tests/auto/declarative/visual/easing/manifest.xml b/tests/auto/declarative/visual/easing/manifest.xml new file mode 100644 index 0000000..3c84452 --- /dev/null +++ b/tests/auto/declarative/visual/easing/manifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="480" type="2" button="1" buttons="1" globalPos="487,444" pos="483,417"/> + <TestFrame time="510" hash="83FB660D6CABAAFCB27C6EC001B14110"/> + <TestFrame time="540" hash="27FCD68F610024000CA6D3A8D9F0CF09"/> + <TestFrame time="570" hash="14728A6160AF51FCA8562D6A020BBA79"/> + <TestFrame time="600" hash="BDDB81682B30A6918927ACB59608D14E"/> + <TestFrame time="630" hash="03F16A41DCD31E41935E54763757C6D5"/> + <TestFrame time="660" hash="2D04EA1EBEDC77CF5D42A1B491A57EA6"/> + <TestFrame time="690" hash="762C36B33B75F24427CA45F4AD06B64E"/> + <TestFrame time="720" hash="AA02624CC889C95A99BBE58365F4FAAD"/> + <TestFrame time="750" hash="0529200188188708A18CE0F931780DBD"/> + <TestFrame time="780" hash="56036B63822AF34F26B149069CD189C6"/> + <TestFrame time="810" hash="CFFC6583E2BA1E47E1439BED6FE69665"/> + <TestFrame time="840" hash="25A1AFDC945D5264FF0337A421143A3C"/> + <TestFrame time="870" hash="601FA34B5E15E7B87E6490580C2E1858"/> + <TestFrame time="900" hash="1CA085F6CB8509957A51F6182F7F5443"/> + <TestFrame time="930" hash="09B5849DF18F6817F7450230DFEC0E95"/> + <TestFrame time="960" hash="15D212C1291DF97E3DEA5AA8793AD5CB"/> + <TestFrame time="990" hash="D6E42E8F4D06BDDBAE998079AC2C79AD"/> + <TestFrame time="1020" hash="7016B5C435006D859AB087A73299B6D5"/> +</TestLog> diff --git a/tests/auto/declarative/visual/easing/pics/qtlogo.png b/tests/auto/declarative/visual/easing/pics/qtlogo.png Binary files differnew file mode 100644 index 0000000..399bd0b --- /dev/null +++ b/tests/auto/declarative/visual/easing/pics/qtlogo.png diff --git a/tests/auto/declarative/visual/flickable/Day.qml b/tests/auto/declarative/visual/flickable/Day.qml new file mode 100644 index 0000000..0765e2f --- /dev/null +++ b/tests/auto/declarative/visual/flickable/Day.qml @@ -0,0 +1,8 @@ +<Rect width="400" height="500" radius="7" pen.color="black" id="Page"> + <properties> + <Property name="day" type="string" /> + </properties> + + <Image x="10" y="10" file="cork.jpg" opaque="true"/> + <Text x="20" y="20" height="40" font.size="14" font.bold="true" width="370" text="{day}" style="Outline" styleColor="#dedede"/> +</Rect> diff --git a/tests/auto/declarative/visual/flickable/cork.jpg b/tests/auto/declarative/visual/flickable/cork.jpg Binary files differnew file mode 100644 index 0000000..d4d706c --- /dev/null +++ b/tests/auto/declarative/visual/flickable/cork.jpg diff --git a/tests/auto/declarative/visual/flickable/flickable.xml b/tests/auto/declarative/visual/flickable/flickable.xml new file mode 100644 index 0000000..78bf42f --- /dev/null +++ b/tests/auto/declarative/visual/flickable/flickable.xml @@ -0,0 +1,43 @@ +<Rect color="lightSteelBlue" width="800" height="500"> + <ListModel id="List"> + <Day> + <name>Sunday</name> + <dayColor>#808080</dayColor> + </Day> + <Day> + <name>Monday</name> + <dayColor>blue</dayColor> + </Day> + <Day> + <name>Tuesday</name> + <dayColor>yellow</dayColor> + </Day> + <Day> + <name>Wednesday</name> + <dayColor>purple</dayColor> + </Day> + <Day> + <name>Thursday</name> + <dayColor>blue</dayColor> + </Day> + <Day> + <name>Friday</name> + <dayColor>green</dayColor> + </Day> + <Day> + <name>Saturday</name> + <dayColor>orange</dayColor> + </Day> + </ListModel> + + <Flickable id="Flick" anchors.fill="{parent}" viewportWidth="{Lay.width}"> + <HorizontalLayout id="Lay"> + <Repeater dataSource="{List}"> + <Component> + <Day day="{name}" color="{dayColor}" /> + </Component> + </Repeater> + </HorizontalLayout> + </Flickable> + +</Rect> diff --git a/tests/auto/declarative/visual/flickable/image0.png b/tests/auto/declarative/visual/flickable/image0.png Binary files differnew file mode 100644 index 0000000..a70ec71 --- /dev/null +++ b/tests/auto/declarative/visual/flickable/image0.png diff --git a/tests/auto/declarative/visual/flickable/manifest-fail.xml b/tests/auto/declarative/visual/flickable/manifest-fail.xml new file mode 100644 index 0000000..0701fa1 --- /dev/null +++ b/tests/auto/declarative/visual/flickable/manifest-fail.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="930" type="2" button="1" buttons="1" globalPos="1459,490" pos="712,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1457,490" pos="710,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1454,490" pos="707,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1446,488" pos="699,461"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1438,488" pos="691,461"/> + <TestFrame time="1020" hash="3A44CE7B924456B70E9ACAA4D6211036"/> + <TestMouse time="1050" type="5" button="0" buttons="1" globalPos="1402,484" pos="655,457"/> + <TestMouse time="1050" type="5" button="0" buttons="1" globalPos="1386,484" pos="639,457"/> + <TestFrame time="1050" hash="CC4B8F76C3758329C4792CC2499588B9"/> + <TestMouse time="1080" type="5" button="0" buttons="1" globalPos="1328,478" pos="581,451"/> + <TestFrame time="1080" hash="A314FC89F9915A0F62E77C649052F30B"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1306,476" pos="559,449"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1258,472" pos="511,445"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1234,468" pos="487,441"/> + <TestFrame time="1110" hash="496BEE45FD87ACA4335EB656DAB38E7C"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1206,466" pos="459,439"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1140,460" pos="393,433"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1106,454" pos="359,427"/> + <TestFrame time="1140" hash="9052B7F038D1BE19B5C603F2B376D95C"/> + <TestMouse time="1170" type="5" button="0" buttons="1" globalPos="980,438" pos="233,411"/> + <TestFrame time="1170" hash="75EBD16D2210983178EC267DD5C7E3DC"/> + <TestMouse time="1200" type="5" button="0" buttons="1" globalPos="930,432" pos="183,405"/> + <TestMouse time="1200" type="3" button="1" buttons="0" globalPos="930,432" pos="183,405"/> + <TestFrame time="1200" hash="A016C7981ACC7C26D0CDE0CF7D71E929"/> + <TestFrame time="1260" hash="A2EA153F54B2D98DEC895FC72D3279F0"/> + <TestFrame time="1290" hash="2702B6D7429FC955B2061C368910309F"/> +</TestLog> diff --git a/tests/auto/declarative/visual/flickable/manifest.xml b/tests/auto/declarative/visual/flickable/manifest.xml new file mode 100644 index 0000000..84d6890 --- /dev/null +++ b/tests/auto/declarative/visual/flickable/manifest.xml @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="930" type="2" button="1" buttons="1" globalPos="1459,490" pos="712,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1457,490" pos="710,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1454,490" pos="707,463"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1446,488" pos="699,461"/> + <TestMouse time="1020" type="5" button="0" buttons="1" globalPos="1438,488" pos="691,461"/> + <TestFrame time="1020" hash="3A44CE7B924456B70E9ACAA4D6211036"/> + <TestMouse time="1050" type="5" button="0" buttons="1" globalPos="1402,484" pos="655,457"/> + <TestMouse time="1050" type="5" button="0" buttons="1" globalPos="1386,484" pos="639,457"/> + <TestFrame time="1050" hash="CC4B8F76C3758329C4792CC2499588B9"/> + <TestMouse time="1080" type="5" button="0" buttons="1" globalPos="1328,478" pos="581,451"/> + <TestFrame time="1080" hash="A314FC89F9915A0F62E77C649052F30B"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1306,476" pos="559,449"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1258,472" pos="511,445"/> + <TestMouse time="1110" type="5" button="0" buttons="1" globalPos="1234,468" pos="487,441"/> + <TestFrame time="1110" hash="496BEE45FD87ACA4335EB656DAB38E7C"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1206,466" pos="459,439"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1140,460" pos="393,433"/> + <TestMouse time="1140" type="5" button="0" buttons="1" globalPos="1106,454" pos="359,427"/> + <TestFrame time="1140" hash="9052B7F038D1BE19B5C603F2B376D95C"/> + <TestMouse time="1170" type="5" button="0" buttons="1" globalPos="980,438" pos="233,411"/> + <TestFrame time="1170" hash="75EBD16D2210983178EC267DD5C7E3DC"/> + <TestMouse time="1200" type="5" button="0" buttons="1" globalPos="930,432" pos="183,405"/> + <TestMouse time="1200" type="3" button="1" buttons="0" globalPos="930,432" pos="183,405"/> + <TestFrame time="1200" hash="A016C7981ACC7C26D0CDE0CF7D71E929"/> + <TestFrame time="1260" hash="203B3D2224AA0B9CB9DB64C837402047"/> + <TestFrame time="1290" hash="E9974E5662F22716C9BC2CF8D1FF12FE"/> + <TestFrame time="1320" hash="1218CCCC399AE53D5D99D3E7AFD73A16"/> + <TestFrame time="1350" hash="FA5D19578629F56972955E9FE530BE59"/> + <TestFrame time="1380" hash="B5B23BBDF1FEB6E6B55AE3909F607D96"/> + <TestFrame time="1410" hash="17EDC257AF24F178455CDEE7B9D73A9F"/> + <TestFrame time="1440" hash="F62E75656DC8AEF20426535DC25FC9F7"/> + <TestFrame time="1470" hash="973D39071B13FBBC700964CA1E4995DA"/> + <TestFrame time="1500" hash="391C67A59AC71B498381FC4D3DA1E8BB"/> + <TestFrame time="1530" hash="C1D86256E4BE487CB61AB1CC8D277FF2"/> + <TestFrame time="1560" hash="D5324FF0B16AA4B532007236222FEEAA"/> + <TestFrame time="1590" hash="4B14446DE1B9DE22D3DFF86A7CC46A05"/> + <TestFrame time="1620" hash="49E6FF8DEB537ECE9BDF56135FCB8BE3"/> + <TestFrame time="1650" hash="25D8D454CD32513F2E711D1B09DF87AF"/> + <TestFrame time="1680" hash="AB511F44DD761AC1070733CB81731451"/> + <TestFrame time="1710" hash="3441D361DB85B2522C8CCB8C21D95E70"/> + <TestFrame time="1740" hash="DB333DF49E6DB519F1F5436F6EEEF18E"/> + <TestFrame time="1770" hash="97044C41A8C27B534707352334CB100E"/> + <TestFrame time="1800" hash="C9EE4321669BB45A574D2CD3448553FE"/> + <TestFrame time="1830" hash="6E1067FB547479F8AC0214B1DE4F1ABD"/> + <TestFrame time="1860" hash="9AC3067759043EF1C8138C6E3D3B26D1"/> + <TestFrame time="1890" hash="F90BB455E7D0266C631BFD6657AC673F"/> + <TestFrame time="1920" hash="064CA0BCE5BCE1E5409F7E95F501843A"/> + <TestFrame time="1950" hash="AC5489FE171E537E5AF6EC9F8B5241DA"/> + <TestFrame time="1980" hash="BBF5D953DCF7FF64D99BF10E244FACE0"/> + <TestFrame time="2010" hash="309FC8E37A3EC93C41BC5E2F8F2962DB"/> + <TestFrame time="2040" hash="192B13ADD78B36E54E3D39E998641F82"/> + <TestFrame time="2070" hash="10F9D012CD1ECD9C8A872AA28191599E"/> + <TestFrame time="2100" hash="E3C9CE476A02915B7EEAA5D16747BD74"/> + <TestFrame time="2130" hash="24AD4F88A8BE8E4059517DA5AB9EC3F9"/> + <TestFrame time="2160" hash="74CE8AFFE7BAC8380E9EE27E482107E8"/> + <TestFrame time="2190" hash="C3377013131C3D1EEFFAEC37C0359E7B"/> + <TestFrame time="2220" hash="1850C61F261E6E148E12C9D9508411E4"/> + <TestFrame time="2250" hash="30EEAD3AC4C869FEB9A2E2F18BB5F335"/> + <TestFrame time="2280" hash="EB0F744274AF8FF27CAFC73053B63C87"/> + <TestFrame time="2310" hash="ADF16B9E820CF7F77E17E2383E0BF345"/> + <TestFrame time="2340" hash="8623C727CB6605607679B7C973E5CE61"/> + <TestFrame time="2370" hash="DE795BC19AD3B24FF091D6EB500C0C9A"/> + <TestFrame time="2400" hash="E85F53F766BE13A62272442916217181"/> + <TestFrame time="2430" hash="B5B05BF6D74AC22BC0DC5ECF8AFFD571"/> + <TestFrame time="2460" hash="C9DB0041AEA560EA3569FA6A37A8E226"/> + <TestFrame time="2490" hash="96B6E45404C4CB7C65A7113294679C96"/> + <TestFrame time="2520" hash="780599814A9AEEB63B6604F8627966FC"/> + <TestFrame time="2550" hash="40D7E36CD63DC9B6F5E0340F8E61DE4F"/> + <TestFrame time="2580" hash="127E4A92CC2AF9B6C7B5686ECED260E3"/> + <TestFrame time="2610" hash="10FEB4963AAD931587BAC2101367CB92"/> + <TestFrame time="2640" hash="2926893CD68516281E47EAD04720E4DB"/> + <TestFrame time="2670" hash="23F790EF701E37C3959465BF5298C9C2"/> + <TestFrame time="2700" hash="461224D0A6662450BA361FAF90CA3087"/> + <TestFrame time="2730" hash="3779C1CC5CD18633C70CE5614C2FCA33"/> + <TestFrame time="2760" hash="D93F3000F95110464793C9BAEF58D694"/> + <TestFrame time="2790" hash="0BFCCED8AE73FBCAC251442F002D603C"/> + <TestFrame time="2820" hash="AC1D13A5508255DCA994CC4685FB0AE3"/> + <TestFrame time="2850" hash="A6709853B44AB203FC8806D3F4159639"/> + <TestFrame time="2880" hash="171589A0F67D72F1685836F5EFF2DD10"/> + <TestFrame time="2910" hash="D4984C2B663CFA0CDE95F9AD5BC9937B"/> + <TestFrame time="2940" hash="1BB6D261C9E800004B180FB8EC0B45AD"/> + <TestFrame time="2970" hash="46CD4E37C989FACF2B7CD71A16DB495A"/> + <TestFrame time="3000" hash="8ED436FF855C96A8CEB795AE175A7C54"/> + <TestFrame time="3030" hash="8ED436FF855C96A8CEB795AE175A7C54"/> + <TestFrame time="3060" hash="138D8CC351C847F266C63F323BABD7FE"/> + <TestFrame time="3090" hash="8D90560CCF5EEB1475F3AA46295E4DD0"/> + <TestFrame time="3120" hash="DD893A953B945365B0F9287A79826A6D"/> + <TestFrame time="3150" hash="386A768FD485BB66C9DC1465399B58C8"/> + <TestFrame time="3180" hash="21340437F1A05C216005157A8E8A9EEF"/> + <TestFrame time="3210" hash="6E2DA9DA5964F59715B08FD59D8BC3EF"/> + <TestFrame time="3240" hash="DC7108F44E225D70349889D9E3F62E74"/> + <TestMouse time="4110" type="2" button="1" buttons="1" globalPos="853,492" pos="106,465"/> + <TestMouse time="4170" type="5" button="0" buttons="1" globalPos="854,493" pos="107,466"/> + <TestMouse time="4170" type="5" button="0" buttons="1" globalPos="855,493" pos="108,466"/> + <TestMouse time="4170" type="5" button="0" buttons="1" globalPos="856,494" pos="109,467"/> + <TestMouse time="4170" type="5" button="0" buttons="1" globalPos="857,494" pos="110,467"/> + <TestMouse time="4200" type="5" button="0" buttons="1" globalPos="859,494" pos="112,467"/> + <TestMouse time="4200" type="5" button="0" buttons="1" globalPos="860,495" pos="113,468"/> + <TestMouse time="4200" type="5" button="0" buttons="1" globalPos="862,495" pos="115,468"/> + <TestFrame time="4200" hash="3946A595E81E4388AFDDDB2539B21BF3"/> + <TestMouse time="4230" type="5" button="0" buttons="1" globalPos="864,495" pos="117,468"/> + <TestMouse time="4230" type="5" button="0" buttons="1" globalPos="869,495" pos="122,468"/> + <TestMouse time="4230" type="5" button="0" buttons="1" globalPos="872,495" pos="125,468"/> + <TestFrame time="4230" hash="D9F7C86886CC5309846694F5DA98A123"/> + <TestMouse time="4260" type="5" button="0" buttons="1" globalPos="875,495" pos="128,468"/> + <TestMouse time="4260" type="5" button="0" buttons="1" globalPos="892,497" pos="145,470"/> + <TestFrame time="4260" hash="0B923428F4EAF40CB032FE8880B10943"/> + <TestMouse time="4290" type="5" button="0" buttons="1" globalPos="911,499" pos="164,472"/> + <TestMouse time="4290" type="5" button="0" buttons="1" globalPos="919,499" pos="172,472"/> + <TestFrame time="4290" hash="F1FCED7910188DBEDC62E289EC98D14A"/> + <TestMouse time="4320" type="5" button="0" buttons="1" globalPos="938,499" pos="191,472"/> + <TestFrame time="4320" hash="71A01976611816A5D42BBB6BC6DE5336"/> + <TestMouse time="4350" type="5" button="0" buttons="1" globalPos="957,501" pos="210,474"/> + <TestMouse time="4350" type="5" button="0" buttons="1" globalPos="960,501" pos="213,474"/> + <TestFrame time="4350" hash="204D5511DFAA28AF3E499FD5E503592A"/> + <TestMouse time="4380" type="5" button="0" buttons="1" globalPos="968,501" pos="221,474"/> + <TestMouse time="4380" type="5" button="0" buttons="1" globalPos="986,503" pos="239,476"/> + <TestMouse time="4380" type="5" button="0" buttons="1" globalPos="989,503" pos="242,476"/> + <TestFrame time="4380" hash="E7F2934FB80FD155AAE4E558B1D31AF9"/> + <TestMouse time="4410" type="5" button="0" buttons="1" globalPos="1015,501" pos="268,474"/> + <TestMouse time="4410" type="5" button="0" buttons="1" globalPos="1025,499" pos="278,472"/> + <TestFrame time="4410" hash="DE795BC19AD3B24FF091D6EB500C0C9A"/> + <TestMouse time="4440" type="5" button="0" buttons="1" globalPos="1065,497" pos="318,470"/> + <TestFrame time="4440" hash="3A2D5734CCC3E5690EF24D412B5ADE32"/> + <TestMouse time="4470" type="5" button="0" buttons="1" globalPos="1083,495" pos="336,468"/> + <TestMouse time="4470" type="5" button="0" buttons="1" globalPos="1135,493" pos="388,466"/> + <TestMouse time="4470" type="5" button="0" buttons="1" globalPos="1171,489" pos="424,462"/> + <TestFrame time="4470" hash="A5F66816E008610C1DA44270F837C9DF"/> + <TestMouse time="4500" type="5" button="0" buttons="1" globalPos="1215,489" pos="468,462"/> + <TestMouse time="4500" type="5" button="0" buttons="1" globalPos="1319,483" pos="572,456"/> + <TestMouse time="4500" type="5" button="0" buttons="1" globalPos="1379,479" pos="632,452"/> + <TestFrame time="4500" hash="6AE11928E7948AD5F9CE5EE07B5E7390"/> + <TestMouse time="4530" type="5" button="0" buttons="1" globalPos="1441,475" pos="694,448"/> + <TestMouse time="4530" type="3" button="1" buttons="0" globalPos="1441,475" pos="694,448"/> + <TestFrame time="4530" hash="47B438BC833CFF7984D3E158B54F0EA5"/> + <TestFrame time="4590" hash="DA134DD6826A87BC08F3BE59F3D2866D"/> + <TestFrame time="4620" hash="D1E87BD1C6264CE83979D34500EEB85B"/> + <TestFrame time="4650" hash="37C13A368649152DD1D43BDD17BEEE97"/> + <TestFrame time="4680" hash="C461AE2C388F4B06E958C12B543E53C0"/> + <TestFrame time="4710" hash="6070DD498E15C27243F09FD8CF8C0D2F"/> + <TestFrame time="4740" hash="FB74E95CF41BDA785991BA01369E9320"/> + <TestFrame time="4770" hash="F52AE455BBA3BAD36ABB4DB2480549D6"/> + <TestFrame time="4800" hash="9BC4E043F6595493ED32BBAAB949CC15"/> + <TestFrame time="4830" hash="4C87F70F6A46B2066021A68435BB285D"/> + <TestFrame time="4860" hash="282A523039F702F22C5D7F2B00BCA1F4"/> + <TestFrame time="4890" hash="D1623E75F20C00F6F357346F57E5C343"/> + <TestFrame time="4920" hash="F96CC72E3671C64D87719E5DF8303FA9"/> + <TestFrame time="4950" hash="44D4E09F9AB5C20E7A7F1AEF920B3599"/> + <TestFrame time="4980" hash="BBAD1BD87E29C1F0834B16DA9C1317A4"/> + <TestFrame time="5010" hash="66DF69AD2EA4823E59F6FC296910822F"/> + <TestFrame time="5040" hash="A0DCE22CFADFE091C5474C231EAD191E"/> + <TestFrame time="5070" hash="AE67DD3CD8B77D001288558E3C67E675"/> + <TestFrame time="5100" hash="B028CC11B70C5288436E49DD439F9F46"/> + <TestFrame time="5130" hash="2FBEFA9C751317D668A1074E8BCB8B10"/> + <TestFrame time="5160" hash="2DB3A59F7CB89B89CD45B86008CC0541"/> + <TestFrame time="5190" hash="AFE0FD3CB16F9DDD3E8DAD46656BE099"/> + <TestFrame time="5220" hash="90C04F980A0C008D4B919D9A4B663762"/> + <TestFrame time="5250" hash="215CB75F6359548B7A4A408E83049A25"/> + <TestFrame time="5280" hash="8EC68EA3F6B54415EC9B860B0207351E"/> + <TestFrame time="5310" hash="8FC14C2EB103B4FDC5B17E6E0F2386D1"/> + <TestFrame time="5340" hash="938DA507656430E1758CB8B5E9D874B1"/> + <TestFrame time="5370" hash="30A3166F0169715DA9FECD48DA257625"/> + <TestFrame time="5400" hash="0C24CD68AFE9C24380178417FE835494"/> + <TestFrame time="5430" hash="C8A18880023CB12BA98EBDFF65875874"/> + <TestFrame time="5460" hash="FE3BCA8DC715A19161FCD48C728366A0"/> + <TestFrame time="5490" hash="4771F9D8AA2A177A190879EB543FA138"/> + <TestFrame time="5520" hash="971D611BC939AB20B998D659DF2235FE"/> + <TestFrame time="5550" hash="7AF899892AE28C61B71A5682F9540DB5"/> + <TestFrame time="5580" hash="CCF349DCA802D5D68B6C9CB368104EF8"/> + <TestFrame time="5610" hash="3DC13F8B693648ABBE8FD6935832BEC7"/> + <TestFrame time="5640" hash="ED2AD5E716D69FD1A87133209695E911"/> + <TestFrame time="5670" hash="037B45A66950DF70D8BD7BC0E000ECC7"/> + <TestFrame time="5700" hash="43B59CF46A829CAFF7D9C0A6D1175581"/> + <TestFrame time="5730" hash="6FF016CE82BFD220418C0A9A644F2F81"/> + <TestFrame time="5760" hash="96D37AFF283210D59287526798E9376D"/> + <TestFrame time="5790" hash="7289570ABB671359AC2F2DF1898748CA"/> + <TestFrame time="5820" hash="2B3AF6424765512B8949BBB9BF6571DC"/> + <TestFrame time="5850" hash="23054E1F931342B8A6C5F6D30A9FF158"/> + <TestFrame time="5880" hash="E3D6EBB07FC90AD2483E95C09CB9E074"/> + <TestFrame time="5910" hash="08EE4C4D9F161AB4118EAD4F4AA8D5B3"/> + <TestFrame time="5940" hash="96D37AFF283210D59287526798E9376D"/> + <TestFrame time="5970" hash="40FB8747AACD078576573CF346E2C418"/> + <TestFrame time="6000" hash="4095D9B46D265D28C88DE0D0E02AC840"/> + <TestFrame time="6030" hash="E370C2A5451DC73AE4F742D52E3DAD4D"/> + <TestFrame time="6060" hash="AC4DC18BEFE0895C1ADF8EE2E3094A09"/> + <TestFrame time="6090" hash="AC4DC18BEFE0895C1ADF8EE2E3094A09"/> +</TestLog> diff --git a/tests/auto/declarative/visual/flipable/flipable.xml b/tests/auto/declarative/visual/flipable/flipable.xml new file mode 100644 index 0000000..d769e55 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/flipable.xml @@ -0,0 +1,138 @@ +<Rect color="lightsteelblue" height="400" width="500"> + <VisualModel id="MyVisualModel"> + <model> + <ListModel id="ListModel"> + <Person> + <name>Jessica</name> + <picture>face.png</picture> + </Person> + <Person> + <name>John</name> + <picture>photo0.png</picture> + </Person> + <Person> + <name>Susan</name> + <picture>photo10.png</picture> + </Person> + <Person> + <name>Samantha</name> + <picture>photo1.png</picture> + </Person> + <Person> + <name>Mark</name> + <picture>photo2.png</picture> + </Person> + <Person> + <name>Sarah</name> + <picture>photo3.png</picture> + </Person> + <Person> + <name>Pam</name> + <picture>photo4.png</picture> + </Person> + <Person> + <name>April</name> + <picture>photo5.png</picture> + </Person> + <Person> + <name>Tarryn</name> + <picture>photo6.png</picture> + </Person> + <Person> + <name>Geoff</name> + <picture>photo7.png</picture> + </Person> + <Person> + <name>Bill</name> + <picture>photo8.png</picture> + </Person> + <Person> + <name>Stuart</name> + <picture>photo9.png</picture> + </Person> + </ListModel> + </model> + <delegate> + <Package> + <Flipable id="MeRect" width="100" height="100"> + <properties> + <Property name="r" type="Real" /> + </properties> + <transform> + <Perspective angle="90" x="50" y="50" aspect="1" scale="256"/> + <Axis xStart="50" xEnd="50" yStart="0" yEnd="1" rotation="{MeRect.r}" /> + </transform> + + <front> + <Rect radius="5" color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </front> + + <back> + <Rect radius="5" color="red" width="100" height="100"> + <Image anchors.horizontalCenter="{parent.horizontalCenter}" anchors.verticalCenter="{parent.verticalCenter}" file="{picture}" /> + </Rect> + </back> + </Flipable> + + <Item Package.name="leftBox" id="LeftBox" + width="100" height="100"> + <Rect opacity="0.1" width="80" height="80" radius="4" + color="grey" x="10" y="10"> + <Text text="{name}" /> + <MouseRegion anchors.fill="{parent}" onClick="if(MyItem.currentState=='left') MyItem.currentState='right'; else MyItem.currentState='left';" /> + </Rect> + </Item> + <Item Package.name="rightBox" id="RightBox" + width="100" height="100"> + <Rect opacity="0.1" width="80" height="80" radius="4" + color="grey" x="10" y="10"> + <Text text="{name}" /> + <MouseRegion anchors.fill="{parent}" onClick="if(MyItem.currentState=='left') MyItem.currentState='right'; else MyItem.currentState='left';" /> + </Rect> + </Item> + <Item id="MyItem"> + <states> + <State name="left"> + <SetProperty target="{MeRect}" property="moveToParent" value="{LeftBox}" /> + </State> + <State name="right"> + <SetProperty target="{MeRect}" property="moveToParent" value="{RightBox}" /> + <SetProperty target="{MeRect}" property="r" value="180" /> + </State> + </states> + <transitions> + <Transition fromState="*" toState="*"> + <NumericAnimation property="r" duration="500" /> + <SerialAnimation> + <SetPropertyAction target="{MeRect}" property="moveToParent" value="{Bounce}" /> + <ParallelAnimation> + <NumericAnimation target="{MeRect}" properties="x" to="0" duration="250" /> + <NumericAnimation target="{MeRect}" properties="y" to="0" easing="easeInQuad" duration="250"/> + </ParallelAnimation> + <SetPropertyAction target="{MeRect}" property="moveToParent" /> + <ParallelAnimation> + <NumericAnimation target="{MeRect}" properties="x" to="0" duration="250"/> + <NumericAnimation target="{MeRect}" properties="y" to="0" easing="easeOutQuad" duration="250"/> + </ParallelAnimation> + </SerialAnimation> + </Transition> + </transitions> + <currentState>left</currentState> + </Item> + + </Package> + </delegate> + </VisualModel> + + <Item width="800" height="400" clip="true"> + <Item z="100" id="Bounce" x="200" y="300" /> + <ListView id="MyListView" width="400" height="400" x="400" + model="{MyVisualModel.parts.rightBox}" /> + + <ListView id="MyListView2" width="400" height="400" + model="{MyVisualModel.parts.leftBox}" /> + </Item> + +</Rect> diff --git a/tests/auto/declarative/visual/flipable/image0.png b/tests/auto/declarative/visual/flipable/image0.png Binary files differnew file mode 100644 index 0000000..affb8a5 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/image0.png diff --git a/tests/auto/declarative/visual/flipable/manifest-play.xml b/tests/auto/declarative/visual/flipable/manifest-play.xml new file mode 100644 index 0000000..81c08e4 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/manifest-play.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="2040" type="2" button="1" buttons="1" globalPos="812,72" pos="65,45"/> + <TestMouse time="2100" type="3" button="1" buttons="0" globalPos="812,72" pos="65,45"/> + <TestFrame time="2130" hash="210454ECF70EEA9CA43DD391BC23178B"/> + <TestFrame time="2160" hash="F6612DAD879208F4AF100337271C445C"/> + <TestFrame time="2190" hash="C77FC41100D0B066F8F0BF4ABCF2F0BF"/> + <TestFrame time="2220" hash="1AB3A42E6FC271E049E6071A88AB8EE4"/> + <TestFrame time="2250" hash="DB3D5BC6882699DCC0208E4F5294B609"/> + <TestFrame time="2280" hash="DC5A8B44283DA4A81D3994B873FC5695"/> + <TestFrame time="2310" hash="5149027ECF7813BA64D3AB8FFE0265F5"/> + <TestFrame time="2340" hash="B7E801DF476C012AC3E9E48A9D4AA321"/> + <TestFrame time="2370" hash="F31A647A6A3EC86D7F16EB3147E5FC29"/> + <TestFrame time="2400" hash="FBB068C39D5188A175075667B584F1BE"/> + <TestFrame time="2430" hash="EC487AB66384A4A3A718D03555EBFD41"/> + <TestFrame time="2460" hash="C7AD11EB051B11ACBA38027013215A05"/> + <TestFrame time="2490" hash="AA38FD8E97EC394488274127630E7946"/> + <TestFrame time="2520" hash="1CA2B617AC966B54FFA1A61914F68A9D"/> + <TestFrame time="2550" hash="1726C0BAA930CAF282154F14AC2FD120"/> + <TestFrame time="2580" hash="58F8196148C8B64191AF7B897A811CFB"/> + <TestFrame time="2610" hash="D56D3FA137AA63A0215611450B40F3E0"/> + <TestFrame time="2640" hash="5E1BCDF996B2903D1EAEAC65E17783C2"/> +</TestLog> diff --git a/tests/auto/declarative/visual/flipable/manifest.xml b/tests/auto/declarative/visual/flipable/manifest.xml new file mode 100644 index 0000000..81c08e4 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/manifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestMouse time="2040" type="2" button="1" buttons="1" globalPos="812,72" pos="65,45"/> + <TestMouse time="2100" type="3" button="1" buttons="0" globalPos="812,72" pos="65,45"/> + <TestFrame time="2130" hash="210454ECF70EEA9CA43DD391BC23178B"/> + <TestFrame time="2160" hash="F6612DAD879208F4AF100337271C445C"/> + <TestFrame time="2190" hash="C77FC41100D0B066F8F0BF4ABCF2F0BF"/> + <TestFrame time="2220" hash="1AB3A42E6FC271E049E6071A88AB8EE4"/> + <TestFrame time="2250" hash="DB3D5BC6882699DCC0208E4F5294B609"/> + <TestFrame time="2280" hash="DC5A8B44283DA4A81D3994B873FC5695"/> + <TestFrame time="2310" hash="5149027ECF7813BA64D3AB8FFE0265F5"/> + <TestFrame time="2340" hash="B7E801DF476C012AC3E9E48A9D4AA321"/> + <TestFrame time="2370" hash="F31A647A6A3EC86D7F16EB3147E5FC29"/> + <TestFrame time="2400" hash="FBB068C39D5188A175075667B584F1BE"/> + <TestFrame time="2430" hash="EC487AB66384A4A3A718D03555EBFD41"/> + <TestFrame time="2460" hash="C7AD11EB051B11ACBA38027013215A05"/> + <TestFrame time="2490" hash="AA38FD8E97EC394488274127630E7946"/> + <TestFrame time="2520" hash="1CA2B617AC966B54FFA1A61914F68A9D"/> + <TestFrame time="2550" hash="1726C0BAA930CAF282154F14AC2FD120"/> + <TestFrame time="2580" hash="58F8196148C8B64191AF7B897A811CFB"/> + <TestFrame time="2610" hash="D56D3FA137AA63A0215611450B40F3E0"/> + <TestFrame time="2640" hash="5E1BCDF996B2903D1EAEAC65E17783C2"/> +</TestLog> diff --git a/tests/auto/declarative/visual/flipable/pics/arrow.png b/tests/auto/declarative/visual/flipable/pics/arrow.png Binary files differnew file mode 100644 index 0000000..997190d --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/arrow.png diff --git a/tests/auto/declarative/visual/flipable/pics/face.png b/tests/auto/declarative/visual/flipable/pics/face.png Binary files differnew file mode 100644 index 0000000..e9529ac --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/face.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo0.png b/tests/auto/declarative/visual/flipable/pics/photo0.png Binary files differnew file mode 100644 index 0000000..26bbf5b --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo0.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo1.png b/tests/auto/declarative/visual/flipable/pics/photo1.png Binary files differnew file mode 100644 index 0000000..2230f71 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo1.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo10.png b/tests/auto/declarative/visual/flipable/pics/photo10.png Binary files differnew file mode 100644 index 0000000..119f142 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo10.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo2.png b/tests/auto/declarative/visual/flipable/pics/photo2.png Binary files differnew file mode 100644 index 0000000..e3d58c1 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo2.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo3.png b/tests/auto/declarative/visual/flipable/pics/photo3.png Binary files differnew file mode 100644 index 0000000..4b58df4 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo3.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo4.png b/tests/auto/declarative/visual/flipable/pics/photo4.png Binary files differnew file mode 100644 index 0000000..4ed4bd2 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo4.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo5.png b/tests/auto/declarative/visual/flipable/pics/photo5.png Binary files differnew file mode 100644 index 0000000..eb26704 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo5.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo6.png b/tests/auto/declarative/visual/flipable/pics/photo6.png Binary files differnew file mode 100644 index 0000000..69875ce --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo6.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo7.png b/tests/auto/declarative/visual/flipable/pics/photo7.png Binary files differnew file mode 100644 index 0000000..0b117c9 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo7.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo8.png b/tests/auto/declarative/visual/flipable/pics/photo8.png Binary files differnew file mode 100644 index 0000000..b77b997 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo8.png diff --git a/tests/auto/declarative/visual/flipable/pics/photo9.png b/tests/auto/declarative/visual/flipable/pics/photo9.png Binary files differnew file mode 100644 index 0000000..8a974d6 --- /dev/null +++ b/tests/auto/declarative/visual/flipable/pics/photo9.png diff --git a/tests/auto/declarative/visual/pauseAnimation/image0.png b/tests/auto/declarative/visual/pauseAnimation/image0.png Binary files differnew file mode 100644 index 0000000..80fd4d1 --- /dev/null +++ b/tests/auto/declarative/visual/pauseAnimation/image0.png diff --git a/tests/auto/declarative/visual/pauseAnimation/manifest-play.xml b/tests/auto/declarative/visual/pauseAnimation/manifest-play.xml new file mode 100644 index 0000000..6b15341 --- /dev/null +++ b/tests/auto/declarative/visual/pauseAnimation/manifest-play.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestFrame time="60" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="90" hash="6579681C59DD571DF0EE4429D74FB5C7"/> + <TestFrame time="120" hash="7DA50C2984E012F217DC44F79AD86D55"/> + <TestFrame time="150" hash="D5E2A4ABDCA59FA26FCE968AB11F0719"/> + <TestFrame time="180" hash="005ACBEF952A8EE536E6308A48223E65"/> + <TestFrame time="210" hash="C4F844EE71F23635BB3EC7375F6A134F"/> + <TestFrame time="240" hash="D9604BE23A91327E6AB454609A9D4A13"/> + <TestFrame time="270" hash="DA60100DC55023C3BAB367D97C8F6A85"/> + <TestFrame time="300" hash="79EC710576427DF73DD03F39FBA6E2EB"/> + <TestFrame time="330" hash="FFD39C1122FE2F7877EF30591B539B40"/> + <TestFrame time="360" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="390" hash="29ECE1BCA4D21FB5862091317D430A13"/> + <TestFrame time="420" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="450" hash="4AC43A03CC6F2020AB5F894D704092AC"/> + <TestFrame time="480" hash="6CC9DE62A0C8FA5E42EAC1B01E99AC32"/> + <TestFrame time="510" hash="D754D35D0793F9F7D4F6249A874E4C45"/> + <TestFrame time="540" hash="B2C778A5EFF5F01EDC54F03D8B4DE8C7"/> + <TestFrame time="570" hash="A4D9DFDBF32C0AD31794B04A2E23A0DB"/> + <TestFrame time="600" hash="5025EB75C88F0760F637E0342B7F88A2"/> + <TestFrame time="630" hash="F4732FF2DF93FE67CB850DEC34184924"/> + <TestFrame time="660" hash="97566CE9558D13EA0780BCE233097B27"/> + <TestFrame time="690" hash="2AD64CB01C9D50E0118D5ECE0A644DF2"/> + <TestFrame time="720" hash="721D7061811B5439C2E8E395917494BC"/> + <TestFrame time="750" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="780" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="810" hash="336D31586171F22D541B989D24B95CBB"/> + <TestFrame time="840" hash="6D63FB5C8A80F0280E88B2CDF8641BB9"/> + <TestFrame time="870" hash="EF8941674CB61F54853DC33652BB854E"/> + <TestFrame time="900" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="930" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="960" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="990" hash="A88A8129259F86DF5A73ADDC3649AD37"/> + <TestFrame time="1020" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="1050" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="1080" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1110" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1140" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1170" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1200" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="1230" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="1260" hash="A8B624EBFC9AB713D1CE55F318A6E90D"/> + <TestFrame time="1290" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="1320" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="1350" hash="BC426FB7C31751665B0D3F16E2CB0173"/> + <TestFrame time="1380" hash="DD60CBAFF6F34027474E92315DBC0EBC"/> + <TestFrame time="1410" hash="F0D8132489C2F2EF760E905B3C093726"/> + <TestFrame time="1440" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1470" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="1500" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1530" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="1560" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="1590" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="1620" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1650" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1680" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1710" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1740" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="1770" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="1800" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="1830" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1860" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="1890" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1920" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1950" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="1980" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="2010" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="2040" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="3060" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="3090" hash="6579681C59DD571DF0EE4429D74FB5C7"/> + <TestFrame time="3120" hash="7DA50C2984E012F217DC44F79AD86D55"/> + <TestFrame time="3150" hash="D5E2A4ABDCA59FA26FCE968AB11F0719"/> + <TestFrame time="3180" hash="005ACBEF952A8EE536E6308A48223E65"/> + <TestFrame time="3210" hash="C4F844EE71F23635BB3EC7375F6A134F"/> + <TestFrame time="3240" hash="D9604BE23A91327E6AB454609A9D4A13"/> + <TestFrame time="3270" hash="DA60100DC55023C3BAB367D97C8F6A85"/> + <TestFrame time="3300" hash="79EC710576427DF73DD03F39FBA6E2EB"/> + <TestFrame time="3330" hash="FFD39C1122FE2F7877EF30591B539B40"/> + <TestFrame time="3360" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="3390" hash="29ECE1BCA4D21FB5862091317D430A13"/> + <TestFrame time="3420" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="3450" hash="4AC43A03CC6F2020AB5F894D704092AC"/> + <TestFrame time="3480" hash="6CC9DE62A0C8FA5E42EAC1B01E99AC32"/> + <TestFrame time="3510" hash="D754D35D0793F9F7D4F6249A874E4C45"/> + <TestFrame time="3540" hash="B2C778A5EFF5F01EDC54F03D8B4DE8C7"/> + <TestFrame time="3570" hash="A4D9DFDBF32C0AD31794B04A2E23A0DB"/> + <TestFrame time="3600" hash="5025EB75C88F0760F637E0342B7F88A2"/> + <TestFrame time="3630" hash="F4732FF2DF93FE67CB850DEC34184924"/> + <TestFrame time="3660" hash="97566CE9558D13EA0780BCE233097B27"/> + <TestFrame time="3690" hash="2AD64CB01C9D50E0118D5ECE0A644DF2"/> + <TestFrame time="3720" hash="721D7061811B5439C2E8E395917494BC"/> + <TestFrame time="3750" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="3780" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="3810" hash="336D31586171F22D541B989D24B95CBB"/> + <TestFrame time="3840" hash="6D63FB5C8A80F0280E88B2CDF8641BB9"/> + <TestFrame time="3870" hash="EF8941674CB61F54853DC33652BB854E"/> + <TestFrame time="3900" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="3930" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="3960" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="3990" hash="A88A8129259F86DF5A73ADDC3649AD37"/> + <TestFrame time="4020" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="4050" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="4080" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4110" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4140" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4170" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4200" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="4230" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="4260" hash="A8B624EBFC9AB713D1CE55F318A6E90D"/> + <TestFrame time="4290" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="4320" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="4350" hash="BC426FB7C31751665B0D3F16E2CB0173"/> + <TestFrame time="4380" hash="DD60CBAFF6F34027474E92315DBC0EBC"/> + <TestFrame time="4410" hash="F0D8132489C2F2EF760E905B3C093726"/> + <TestFrame time="4440" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4470" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="4500" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4530" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="4560" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="4590" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="4620" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4650" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4680" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4710" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4740" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="4770" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="4800" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="4830" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4860" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="4890" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4920" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4950" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="4980" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="5010" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="5040" hash="A350B70C5238A340E85FD4A3EC0390A3"/> +</TestLog> diff --git a/tests/auto/declarative/visual/pauseAnimation/manifest.xml b/tests/auto/declarative/visual/pauseAnimation/manifest.xml new file mode 100644 index 0000000..6b15341 --- /dev/null +++ b/tests/auto/declarative/visual/pauseAnimation/manifest.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> + <TestFrame time="60" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="90" hash="6579681C59DD571DF0EE4429D74FB5C7"/> + <TestFrame time="120" hash="7DA50C2984E012F217DC44F79AD86D55"/> + <TestFrame time="150" hash="D5E2A4ABDCA59FA26FCE968AB11F0719"/> + <TestFrame time="180" hash="005ACBEF952A8EE536E6308A48223E65"/> + <TestFrame time="210" hash="C4F844EE71F23635BB3EC7375F6A134F"/> + <TestFrame time="240" hash="D9604BE23A91327E6AB454609A9D4A13"/> + <TestFrame time="270" hash="DA60100DC55023C3BAB367D97C8F6A85"/> + <TestFrame time="300" hash="79EC710576427DF73DD03F39FBA6E2EB"/> + <TestFrame time="330" hash="FFD39C1122FE2F7877EF30591B539B40"/> + <TestFrame time="360" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="390" hash="29ECE1BCA4D21FB5862091317D430A13"/> + <TestFrame time="420" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="450" hash="4AC43A03CC6F2020AB5F894D704092AC"/> + <TestFrame time="480" hash="6CC9DE62A0C8FA5E42EAC1B01E99AC32"/> + <TestFrame time="510" hash="D754D35D0793F9F7D4F6249A874E4C45"/> + <TestFrame time="540" hash="B2C778A5EFF5F01EDC54F03D8B4DE8C7"/> + <TestFrame time="570" hash="A4D9DFDBF32C0AD31794B04A2E23A0DB"/> + <TestFrame time="600" hash="5025EB75C88F0760F637E0342B7F88A2"/> + <TestFrame time="630" hash="F4732FF2DF93FE67CB850DEC34184924"/> + <TestFrame time="660" hash="97566CE9558D13EA0780BCE233097B27"/> + <TestFrame time="690" hash="2AD64CB01C9D50E0118D5ECE0A644DF2"/> + <TestFrame time="720" hash="721D7061811B5439C2E8E395917494BC"/> + <TestFrame time="750" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="780" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="810" hash="336D31586171F22D541B989D24B95CBB"/> + <TestFrame time="840" hash="6D63FB5C8A80F0280E88B2CDF8641BB9"/> + <TestFrame time="870" hash="EF8941674CB61F54853DC33652BB854E"/> + <TestFrame time="900" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="930" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="960" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="990" hash="A88A8129259F86DF5A73ADDC3649AD37"/> + <TestFrame time="1020" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="1050" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="1080" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1110" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1140" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1170" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="1200" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="1230" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="1260" hash="A8B624EBFC9AB713D1CE55F318A6E90D"/> + <TestFrame time="1290" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="1320" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="1350" hash="BC426FB7C31751665B0D3F16E2CB0173"/> + <TestFrame time="1380" hash="DD60CBAFF6F34027474E92315DBC0EBC"/> + <TestFrame time="1410" hash="F0D8132489C2F2EF760E905B3C093726"/> + <TestFrame time="1440" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1470" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="1500" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1530" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="1560" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="1590" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="1620" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1650" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1680" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1710" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="1740" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="1770" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="1800" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="1830" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1860" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="1890" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1920" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="1950" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="1980" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="2010" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="2040" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="3060" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="3090" hash="6579681C59DD571DF0EE4429D74FB5C7"/> + <TestFrame time="3120" hash="7DA50C2984E012F217DC44F79AD86D55"/> + <TestFrame time="3150" hash="D5E2A4ABDCA59FA26FCE968AB11F0719"/> + <TestFrame time="3180" hash="005ACBEF952A8EE536E6308A48223E65"/> + <TestFrame time="3210" hash="C4F844EE71F23635BB3EC7375F6A134F"/> + <TestFrame time="3240" hash="D9604BE23A91327E6AB454609A9D4A13"/> + <TestFrame time="3270" hash="DA60100DC55023C3BAB367D97C8F6A85"/> + <TestFrame time="3300" hash="79EC710576427DF73DD03F39FBA6E2EB"/> + <TestFrame time="3330" hash="FFD39C1122FE2F7877EF30591B539B40"/> + <TestFrame time="3360" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="3390" hash="29ECE1BCA4D21FB5862091317D430A13"/> + <TestFrame time="3420" hash="C1A7B7D6D64AC5584C073C2881290696"/> + <TestFrame time="3450" hash="4AC43A03CC6F2020AB5F894D704092AC"/> + <TestFrame time="3480" hash="6CC9DE62A0C8FA5E42EAC1B01E99AC32"/> + <TestFrame time="3510" hash="D754D35D0793F9F7D4F6249A874E4C45"/> + <TestFrame time="3540" hash="B2C778A5EFF5F01EDC54F03D8B4DE8C7"/> + <TestFrame time="3570" hash="A4D9DFDBF32C0AD31794B04A2E23A0DB"/> + <TestFrame time="3600" hash="5025EB75C88F0760F637E0342B7F88A2"/> + <TestFrame time="3630" hash="F4732FF2DF93FE67CB850DEC34184924"/> + <TestFrame time="3660" hash="97566CE9558D13EA0780BCE233097B27"/> + <TestFrame time="3690" hash="2AD64CB01C9D50E0118D5ECE0A644DF2"/> + <TestFrame time="3720" hash="721D7061811B5439C2E8E395917494BC"/> + <TestFrame time="3750" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="3780" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="3810" hash="336D31586171F22D541B989D24B95CBB"/> + <TestFrame time="3840" hash="6D63FB5C8A80F0280E88B2CDF8641BB9"/> + <TestFrame time="3870" hash="EF8941674CB61F54853DC33652BB854E"/> + <TestFrame time="3900" hash="0C20D12464ABBDC45041EA5D9F2719B1"/> + <TestFrame time="3930" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="3960" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="3990" hash="A88A8129259F86DF5A73ADDC3649AD37"/> + <TestFrame time="4020" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="4050" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="4080" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4110" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4140" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4170" hash="1373545E43FFF7251CEC9E8375EA267F"/> + <TestFrame time="4200" hash="E553F365912586C6408C8C53B1B7D118"/> + <TestFrame time="4230" hash="3DB5E30EF19EA693C21CCF72892C4390"/> + <TestFrame time="4260" hash="A8B624EBFC9AB713D1CE55F318A6E90D"/> + <TestFrame time="4290" hash="AF3120FE262D2489C0ED33FBBEE1549F"/> + <TestFrame time="4320" hash="53AE93140252373EAA4D9DA73756BD8E"/> + <TestFrame time="4350" hash="BC426FB7C31751665B0D3F16E2CB0173"/> + <TestFrame time="4380" hash="DD60CBAFF6F34027474E92315DBC0EBC"/> + <TestFrame time="4410" hash="F0D8132489C2F2EF760E905B3C093726"/> + <TestFrame time="4440" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4470" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="4500" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4530" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="4560" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="4590" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="4620" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4650" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4680" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4710" hash="3042003C067B257DE2CB32F650DDE693"/> + <TestFrame time="4740" hash="A725B59B4947357546BBFC7DF3D830AF"/> + <TestFrame time="4770" hash="CE57E27AF329EBA4FAC3AB891F0407CE"/> + <TestFrame time="4800" hash="41BA853C3403F68A23E708DF82E21C53"/> + <TestFrame time="4830" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4860" hash="A350B70C5238A340E85FD4A3EC0390A3"/> + <TestFrame time="4890" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4920" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="4950" hash="DCF2867C127E041970047EC8F3EDC04F"/> + <TestFrame time="4980" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="5010" hash="675EBBDD22DD22CE45993DF4AF1ACFE9"/> + <TestFrame time="5040" hash="A350B70C5238A340E85FD4A3EC0390A3"/> +</TestLog> diff --git a/tests/auto/declarative/visual/pauseAnimation/pauseAnimation.xml b/tests/auto/declarative/visual/pauseAnimation/pauseAnimation.xml new file mode 100644 index 0000000..bb411e2 --- /dev/null +++ b/tests/auto/declarative/visual/pauseAnimation/pauseAnimation.xml @@ -0,0 +1,13 @@ +<Rect id="rect" width="120" height="200" color="white"> + <Image id="img" file="pics/qtlogo.png" + x="{60-img.width/2}" y="{200-img.height}"> + <y> + <SerialAnimation running="true" repeat="true"> + <NumericAnimation to="{200-img.height}" + easing="easeOutBounce(amplitude:100)" + duration="2000" /> + <PauseAnimation duration="1000" /> + </SerialAnimation> + </y> + </Image> +</Rect> diff --git a/tests/auto/declarative/visual/pauseAnimation/pics/qtlogo.png b/tests/auto/declarative/visual/pauseAnimation/pics/qtlogo.png Binary files differnew file mode 100644 index 0000000..399bd0b --- /dev/null +++ b/tests/auto/declarative/visual/pauseAnimation/pics/qtlogo.png diff --git a/tests/auto/declarative/visual/qfxtext/elide/data/opengl/image0.png b/tests/auto/declarative/visual/qfxtext/elide/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..7d45407 --- /dev/null +++ b/tests/auto/declarative/visual/qfxtext/elide/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/qfxtext/elide/data/opengl/manifest.xml b/tests/auto/declarative/visual/qfxtext/elide/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/qfxtext/elide/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/qfxtext/elide/elide.xml b/tests/auto/declarative/visual/qfxtext/elide/elide.xml new file mode 100644 index 0000000..398da82 --- /dev/null +++ b/tests/auto/declarative/visual/qfxtext/elide/elide.xml @@ -0,0 +1,6 @@ +<VerticalLayout width="80" height="{Text.height*4}"> + <Text elide="ElideLeft" text="aaa bbb ccc ddd eee fff" width="80" color="white" id="Text"/> + <Text elide="ElideMiddle" text="aaa bbb ccc ddd eee fff" width="80" color="white"/> + <Text elide="ElideRight" text="aaa bbb ccc ddd eee fff" width="80" color="white"/> + <Text elide="ElideNone" text="aaa bbb ccc ddd eee fff" width="80" color="white"/> +</VerticalLayout> diff --git a/tests/auto/declarative/visual/qfxtext/elide/test b/tests/auto/declarative/visual/qfxtext/elide/test new file mode 100644 index 0000000..d35cbc9 --- /dev/null +++ b/tests/auto/declarative/visual/qfxtext/elide/test @@ -0,0 +1 @@ +elide.xml diff --git a/tests/auto/declarative/visual/repeater/basic1/basic1.xml b/tests/auto/declarative/visual/repeater/basic1/basic1.xml new file mode 100644 index 0000000..def809f --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic1/basic1.xml @@ -0,0 +1,21 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <HorizontalLayout> + <Repeater > + <component> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </component> + <dataSource> + <ListModel> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + </dataSource> + </Repeater> + </HorizontalLayout> +</Rect> diff --git a/tests/auto/declarative/visual/repeater/basic1/data/opengl/image0.png b/tests/auto/declarative/visual/repeater/basic1/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..f0be97f --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic1/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/repeater/basic1/data/opengl/manifest.xml b/tests/auto/declarative/visual/repeater/basic1/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic1/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/repeater/basic1/test b/tests/auto/declarative/visual/repeater/basic1/test new file mode 100644 index 0000000..62f0665 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic1/test @@ -0,0 +1 @@ +basic1.xml diff --git a/tests/auto/declarative/visual/repeater/basic2/basic2.xml b/tests/auto/declarative/visual/repeater/basic2/basic2.xml new file mode 100644 index 0000000..b16fbfe --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic2/basic2.xml @@ -0,0 +1,22 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <Component id="Delegate"> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </Component> + + <HorizontalLayout> + <Repeater component="{Delegate}"> + <dataSource> + <ListModel> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + </dataSource> + </Repeater> + </HorizontalLayout> +</Rect> diff --git a/tests/auto/declarative/visual/repeater/basic2/data/opengl/image0.png b/tests/auto/declarative/visual/repeater/basic2/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..f0be97f --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic2/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/repeater/basic2/data/opengl/manifest.xml b/tests/auto/declarative/visual/repeater/basic2/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic2/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/repeater/basic2/test b/tests/auto/declarative/visual/repeater/basic2/test new file mode 100644 index 0000000..ae974fe --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic2/test @@ -0,0 +1 @@ +basic2.xml diff --git a/tests/auto/declarative/visual/repeater/basic3/basic3.xml b/tests/auto/declarative/visual/repeater/basic3/basic3.xml new file mode 100644 index 0000000..1135f16 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic3/basic3.xml @@ -0,0 +1,19 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <ListModel id="DataSource"> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + <HorizontalLayout> + <Repeater dataSource="{DataSource}"> + <component> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </component> + </Repeater> + </HorizontalLayout> +</Rect> diff --git a/tests/auto/declarative/visual/repeater/basic3/data/opengl/image0.png b/tests/auto/declarative/visual/repeater/basic3/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..f0be97f --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic3/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/repeater/basic3/data/opengl/manifest.xml b/tests/auto/declarative/visual/repeater/basic3/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic3/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/repeater/basic3/test b/tests/auto/declarative/visual/repeater/basic3/test new file mode 100644 index 0000000..ea3154e --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic3/test @@ -0,0 +1 @@ +basic3.xml diff --git a/tests/auto/declarative/visual/repeater/basic4/basic4.xml b/tests/auto/declarative/visual/repeater/basic4/basic4.xml new file mode 100644 index 0000000..53b8ff9 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic4/basic4.xml @@ -0,0 +1,18 @@ +<Rect color="blue" width="800" height="600" id="Page"> + <ListModel id="DataSource"> + <Month> + <name>January</name> + </Month> + <Month> + <name>February</name> + </Month> + </ListModel> + <Component id="Delegate"> + <Rect color="red" width="100" height="100"> + <Text text="{name}" /> + </Rect> + </Component> + <HorizontalLayout> + <Repeater dataSource="{DataSource}" component="{Delegate}" /> + </HorizontalLayout> +</Rect> diff --git a/tests/auto/declarative/visual/repeater/basic4/data/opengl/image0.png b/tests/auto/declarative/visual/repeater/basic4/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..f0be97f --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic4/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/repeater/basic4/data/opengl/manifest.xml b/tests/auto/declarative/visual/repeater/basic4/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic4/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/repeater/basic4/test b/tests/auto/declarative/visual/repeater/basic4/test new file mode 100644 index 0000000..891e0be --- /dev/null +++ b/tests/auto/declarative/visual/repeater/basic4/test @@ -0,0 +1 @@ +basic4.xml diff --git a/tests/auto/declarative/visual/runtests.sh b/tests/auto/declarative/visual/runtests.sh new file mode 100755 index 0000000..f690381 --- /dev/null +++ b/tests/auto/declarative/visual/runtests.sh @@ -0,0 +1,2 @@ +#!/bin/sh +for a in `cat tests`; do ./tst_visual -testdir $a; done diff --git a/tests/auto/declarative/visual/tests b/tests/auto/declarative/visual/tests new file mode 100644 index 0000000..ca72e9e --- /dev/null +++ b/tests/auto/declarative/visual/tests @@ -0,0 +1,11 @@ +ListView/basic1 +ListView/basic2 +ListView/basic3 +ListView/basic4 +bindinganimation +repeater/basic1 +repeater/basic2 +repeater/basic3 +repeater/basic4 +webview/autosize +qfxtext/elide diff --git a/tests/auto/declarative/visual/tst_visual.cpp b/tests/auto/declarative/visual/tst_visual.cpp new file mode 100644 index 0000000..f077994 --- /dev/null +++ b/tests/auto/declarative/visual/tst_visual.cpp @@ -0,0 +1,72 @@ +#include <qtest.h> +#include <QFxView> +#include <QApplication> +#include <QFxTestView> +#include <QFile> + +static QString testdir; +class tst_visual : public QObject +{ + Q_OBJECT +public: + tst_visual() {} + +private slots: + void visual(); +}; + +#ifdef QT_OPENGL_ES +#define RASTER_TESTDIR "/data/opengl" +#else +#define RASTER_TESTDIR "/data/raster" +#endif + +void tst_visual::visual() +{ + QVERIFY(!testdir.isEmpty()); + + QFile configFile(QLatin1String(QT_TEST_SOURCE_DIR) + "/" + testdir + "/test"); + QVERIFY(configFile.open(QIODevice::ReadOnly)); + + QString testfile = configFile.readLine().trimmed(); + QVERIFY(!testfile.isEmpty()); + + if(testfile.startsWith("QTDIR/")) { + testfile.remove(0, 6); + testfile.prepend(QLatin1String(QT_TEST_SOURCE_DIR) + "/../../../../"); + } else { + testfile.prepend(QLatin1String(QT_TEST_SOURCE_DIR) + "/" + testdir + "/"); + } + + QFxTestView *view = new QFxTestView(testfile, QLatin1String(QT_TEST_SOURCE_DIR) + "/" + testdir + RASTER_TESTDIR); + QVERIFY(view->runTest()); +} + +#include <QtTest/qtest_gui.h> + +int main(int argc, char *argv[]) +{ + int newArgc = 1; + char **newArgv = new char*[argc]; + + newArgv[0] = argv[0]; + + QApplication app(newArgc, newArgv); + + for(int ii = 1; ii < argc; ii++) { + if(QLatin1String(argv[ii]) == "-testdir" && (ii + 1) < argc) { + testdir = QLatin1String(argv[ii + 1]); + ii++; + } else { + newArgv[newArgc++] = argv[ii]; + } + } + + tst_visual tc; + int rv = QTest::qExec(&tc, newArgc, newArgv); + + delete [] newArgv; + return rv; +} + +#include "tst_visual.moc" diff --git a/tests/auto/declarative/visual/visual.pro b/tests/auto/declarative/visual/visual.pro new file mode 100644 index 0000000..203b691 --- /dev/null +++ b/tests/auto/declarative/visual/visual.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_visual.cpp + +DEFINES += QT_TEST_SOURCE_DIR=\"\\\"$$PWD\\\"\" diff --git a/tests/auto/declarative/visual/webview/autosize/data/opengl/image0.png b/tests/auto/declarative/visual/webview/autosize/data/opengl/image0.png Binary files differnew file mode 100644 index 0000000..351a7b7 --- /dev/null +++ b/tests/auto/declarative/visual/webview/autosize/data/opengl/image0.png diff --git a/tests/auto/declarative/visual/webview/autosize/data/opengl/manifest.xml b/tests/auto/declarative/visual/webview/autosize/data/opengl/manifest.xml new file mode 100644 index 0000000..b784f42 --- /dev/null +++ b/tests/auto/declarative/visual/webview/autosize/data/opengl/manifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<TestLog> + <TestFullFrame time="30" frameId="0"/> +</TestLog> diff --git a/tests/auto/declarative/visual/webview/autosize/test b/tests/auto/declarative/visual/webview/autosize/test new file mode 100644 index 0000000..446d3f9 --- /dev/null +++ b/tests/auto/declarative/visual/webview/autosize/test @@ -0,0 +1 @@ +QTDIR/examples/declarative/webview/autosize.qml diff --git a/tests/auto/dynamicobject/dynamicobject.pro b/tests/auto/dynamicobject/dynamicobject.pro new file mode 100644 index 0000000..1b2a075 --- /dev/null +++ b/tests/auto/dynamicobject/dynamicobject.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qobject.cpp qmetaobjectbuilder.cpp qdynamicmetaobject.cpp +HEADERS += qmetaobjectbuilder.h qdynamicmetaobject.h + +QT = core + diff --git a/tests/auto/dynamicobject/qdynamicmetaobject.cpp b/tests/auto/dynamicobject/qdynamicmetaobject.cpp new file mode 100644 index 0000000..b44555f --- /dev/null +++ b/tests/auto/dynamicobject/qdynamicmetaobject.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +****************************************************************************/ + +#include <qcoreapplication.h> + +#include <qmetaobject.h> + +#include "qobject.h" +#include "private/qobject_p.h" +#include "qmetaobjectbuilder.h" +#include "qdynamicmetaobject.h" + +class QDynamicMetaObjectData +{ +public: + QDynamicMetaObjectData() : ref(1), baseMeta(0), meta(0) {} + ~QDynamicMetaObjectData() { qFree(meta); } + + QAtomicInt ref; + QMetaObjectBuilder builder; + const QMetaObject *baseMeta; + QMetaObject *meta; +}; + +/*! + \class QDynamicMetaObject + \brief The QDynamicMetaObject class allows adding signals, slots and properties to + QObjects at runtime. + + Any QObject derived class can be extended by creating a QDynamicMetaObject + based on the QObject's QMetaObject. + + QObject::setDynamicMetaObject() is called to set the dynamic meta-object for + the QObject. + + \sa QMetaObject +*/ + +/*! + Constructs a dynamic meta-object based on \a baseMetaObject. + + QObject::setDynamicMetaObject() should be called to install it. +*/ +QDynamicMetaObject::QDynamicMetaObject(const QMetaObject *baseMetaObject) +{ + data_ptr = new QDynamicMetaObjectData; + data_ptr->baseMeta = baseMetaObject; + data_ptr->builder.setSuperClass(data_ptr->baseMeta); + data_ptr->builder.setClassName(data_ptr->baseMeta->className()); + updateMetaData(); +} + +/*! + Constructs a dynamic meta-object that is a copy of \a other. +*/ +QDynamicMetaObject::QDynamicMetaObject(const QDynamicMetaObject &other) +{ + data_ptr = other.data_ptr; + data_ptr->ref.ref(); +} + +/*! + Destroys the dynamic meta-ovject. +*/ +QDynamicMetaObject::~QDynamicMetaObject() +{ + if (!data_ptr->ref.deref()) + delete data_ptr; +} + +/*! + Copies the dynamic metadata from \a that. The static metadata must be identical, + i.e. the dynamic metadata is constructed for the same class. +*/ +QDynamicMetaObject &QDynamicMetaObject::operator=(const QDynamicMetaObject &that) +{ + Q_ASSERT(data_ptr->baseMeta == that.data_ptr->baseMeta); + qAtomicAssign(data_ptr, that.data_ptr); + return *this; +} + +/*! + \internal +*/ +QDynamicMetaObject &QDynamicMetaObject::operator=(const QMetaObject &that) +{ + static_cast<QMetaObject*>(this)->d = that.d; + return *this; +} + +/*! + \internal +*/ +void QDynamicMetaObject::detach() +{ + if (data_ptr->ref == 1) + return; + + //XXX copy builder faster. + QByteArray buf; + QDataStream ds(&buf, QIODevice::ReadWrite); + data_ptr->builder.serialize(ds); + if (!data_ptr->ref.deref()) + delete data_ptr; + data_ptr = new QDynamicMetaObjectData; + QMap<QByteArray, const QMetaObject *> refs; + data_ptr->builder.deserialize(ds, refs); + updateMetaData(); +} + +/*! + Adds the signal with \a signature. +*/ +void QDynamicMetaObject::addSignal(const char *signature) +{ + detach(); + data_ptr->builder.addSignal(signature); + updateMetaData(); +} + +/*! + Adds the signal with \a signature and sets the \a parameterNames. +*/ +void QDynamicMetaObject::addSignal(const char *signature, const QList<QByteArray> ¶meterNames) +{ + detach(); + QMetaMethodBuilder method = data_ptr->builder.addSignal(signature); + method.setParameterNames(parameterNames); + updateMetaData(); +} + +/*! + Adds the slot with \a signature. +*/ +void QDynamicMetaObject::addSlot(const char *signature) +{ + detach(); + data_ptr->builder.addSlot(signature); + updateMetaData(); +} + + +/*! + Adds the slot with \a signature and sets the \a parameterNames. +*/ +void QDynamicMetaObject::addSlot(const char *signature, const QList<QByteArray> ¶meterNames) +{ + detach(); + QMetaMethodBuilder method = data_ptr->builder.addSlot(signature); + method.setParameterNames(parameterNames); + updateMetaData(); +} + +/*! + Adds the property with \a name of \a type. If \a notifier specified it is + set as the change notifier for the property. +*/ +void QDynamicMetaObject::addProperty(const char *name, const char *type, const char *notifier) +{ + int notifierId = -1; + if (notifier) + notifierId = data_ptr->builder.indexOfSignal(notifier); + data_ptr->builder.addProperty(name, type, notifierId); + updateMetaData(); +} + +/*! + Adds the property with \a name of \a type. If \a notifierId is specified it is + set as the change notifier for the property. +*/ +void QDynamicMetaObject::addProperty(const char *name, const char *type, int notifierId) +{ + data_ptr->builder.addProperty(name, type, notifierId); + updateMetaData(); +} + +/*! + \reimp +*/ +int QDynamicMetaObject::metaCall(QObject *object, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod && _id >= data_ptr->baseMeta->methodCount()) { + QMetaMethod metaMethod = method(_id); + if (metaMethod.methodType() == QMetaMethod::Slot) { + if (metaMethod.parameterTypes().count() == 0) { + static QList<QVariant> noArgs; + callSlot(object, _id, noArgs); + } else { + QList<QVariant> args; + for (int i = 0; i < metaMethod.parameterTypes().count(); ++i) { + int typeId = QVariant::nameToType(metaMethod.parameterTypes().at(i)); + args.append(QVariant(typeId, _a[i+1])); + } + callSlot(object, _id, args); + } + } else if (metaMethod.methodType() == QMetaMethod::Signal) + activate(object, _id, _a); + _id = -1; + } else if (_c == QMetaObject::ReadProperty && _id >= data_ptr->baseMeta->propertyCount()) { + *(reinterpret_cast<QVariant*>(_a[1])) = readProperty(object, _id); + _id = -1; + } else if (_c == QMetaObject::WriteProperty && _id >= data_ptr->baseMeta->propertyCount()) { + writeProperty(object, _id, *(reinterpret_cast<QVariant*>(_a[1]))); + if (property(_id).hasNotifySignal()) + activate(object, property(_id).notifySignalIndex(), 0); + _id = -1; + } else { + _id = object->qt_metacall(_c, _id, _a); + } + + return _id; +} + +/*! + The slot with \a id has been called for \a object. The parameters are available via \a args. +*/ +void QDynamicMetaObject::callSlot(QObject *object, int id, const QList<QVariant> &args) +{ + Q_UNUSED(object); + Q_UNUSED(id); + Q_UNUSED(args); +} + +/*! + The \a value of property with \a id has changed for \a object. +*/ +void QDynamicMetaObject::writeProperty(QObject *object, int id, const QVariant &value) +{ + Q_UNUSED(object); + Q_UNUSED(id); + Q_UNUSED(value); +} + +/*! + Return the value of the property with \a id belonging to \a object. +*/ +QVariant QDynamicMetaObject::readProperty(QObject *object, int id) const +{ + Q_UNUSED(object); + Q_UNUSED(id); + return QVariant(); +} + +void QDynamicMetaObject::updateMetaData() +{ + qFree(data_ptr->meta); + data_ptr->meta = data_ptr->builder.toMetaObject(); + *this = *data_ptr->meta; +} + diff --git a/tests/auto/dynamicobject/qdynamicmetaobject.h b/tests/auto/dynamicobject/qdynamicmetaobject.h new file mode 100644 index 0000000..747d118 --- /dev/null +++ b/tests/auto/dynamicobject/qdynamicmetaobject.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +****************************************************************************/ + +#ifndef _QDYNAMICMETAOBJECT_H_ +#define _QDYNAMICMETAOBJECT_H_ + +#include <qmetaobject.h> +#include <qobject.h> + +class QDynamicMetaObjectData; + +class QDynamicMetaObject : public QAbstractDynamicMetaObject +{ +public: + QDynamicMetaObject(const QMetaObject *baseMetaObject); + QDynamicMetaObject(const QDynamicMetaObject &other); + virtual ~QDynamicMetaObject(); + + QDynamicMetaObject &operator=(const QDynamicMetaObject &that); + + void addSignal(const char *sigName); + void addSignal(const char *sigName, const QList<QByteArray> ¶meterNames); + void addSlot(const char *slotName); + void addSlot(const char *slotName, const QList<QByteArray> ¶meterNames); + void addProperty(const char *name, const char *type, const char *notifier); + void addProperty(const char *name, const char *type, int notifierId=-1); + +protected: + virtual int metaCall(QObject *object, QMetaObject::Call _c, int _id, void **_a); + virtual void callSlot(QObject *object, int id, const QList<QVariant> &args); + virtual void writeProperty(QObject *object, int id, const QVariant &value); + virtual QVariant readProperty(QObject *object, int id) const; + +private: + void detach(); + void updateMetaData(); + QDynamicMetaObject &operator=(const QMetaObject &that); + +private: + QDynamicMetaObjectData *data_ptr; +}; + +#endif diff --git a/tests/auto/dynamicobject/qmetaobjectbuilder.cpp b/tests/auto/dynamicobject/qmetaobjectbuilder.cpp new file mode 100644 index 0000000..3927f6a --- /dev/null +++ b/tests/auto/dynamicobject/qmetaobjectbuilder.cpp @@ -0,0 +1,2347 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmetaobjectbuilder.h" +#include <QDebug> + +/*! + \class QMetaObjectBuilder + \brief The QMetaObjectBuilder class supports the building of QMetaObject objects at runtime. + + See the QDynamicMetaObject class documentation for an example + of using this class. + + \sa QDynamicMetaObject, QDynamicObject +*/ + +/*! + \enum QMetaObjectBuilder::AddMember + This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject() + + \value ClassName Add the class name. + \value SuperClass Add the super class. + \value Methods Add methods that aren't signals or slots. + \value Signals Add signals. + \value Slots Add slots. + \value Constructors Add constructors. + \value Properties Add properties. + \value Enumerators Add enumerators. + \value ClassInfos Add items of class information. + \value RelatedMetaObjects Add related meta objects. + \value StaticMetacall Add the static metacall function. + \value PublicMethods Add public methods (ignored for signals). + \value ProtectedMethods Add protected methods (ignored for signals). + \value PrivateMethods All private methods (ignored for signals). + \value AllMembers Add all members. + \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function. +*/ + +// copied from qmetaobject.cpp +// do not touch without touching the moc as well +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; +}; + +static inline const QMetaObjectPrivate *priv(const uint* data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } +// end of copied lines from qmetaobject.cpp + +class QMetaMethodBuilderPrivate +{ +public: + QMetaMethodBuilderPrivate + (QMetaMethod::MethodType _methodType, + const QByteArray& _signature, + const QByteArray& _returnType = QByteArray(), + QMetaMethod::Access _access = QMetaMethod::Public) + : signature(QMetaObject::normalizedSignature(_signature.constData())), + returnType(QMetaObject::normalizedType(_returnType)), + attributes(((int)_access) | (((int)_methodType) << 2)) + { + } + + QByteArray signature; + QByteArray returnType; + QList<QByteArray> parameterNames; + QByteArray tag; + int attributes; + + QMetaMethod::MethodType methodType() const + { + return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2); + } + + QMetaMethod::Access access() const + { + return (QMetaMethod::Access)(attributes & AccessMask); + } + + void setAccess(QMetaMethod::Access value) + { + attributes = ((attributes & ~AccessMask) | (int)value); + } +}; + +class QMetaPropertyBuilderPrivate +{ +public: + QMetaPropertyBuilderPrivate + (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1) + : name(_name), + type(QMetaObject::normalizedType(_type.constData())), + flags(Readable | Writable), notifySignal(-1) + { + if (notifierIdx >= 0) { + flags |= Notify; + notifySignal = notifierIdx; + } + } + + QByteArray name; + QByteArray type; + int flags; + int notifySignal; + + bool flag(int f) const + { + return ((flags & f) != 0); + } + + void setFlag(int f, bool value) + { + if (value) + flags |= f; + else + flags &= ~f; + } +}; + +class QMetaEnumBuilderPrivate +{ +public: + QMetaEnumBuilderPrivate(const QByteArray& _name) + : name(_name), isFlag(false) + { + } + + QByteArray name; + bool isFlag; + QList<QByteArray> keys; + QList<int> values; +}; + +class QMetaObjectBuilderPrivate +{ +public: + QMetaObjectBuilderPrivate() + { + superClass = &QObject::staticMetaObject; + staticMetacallFunction = 0; + } + + QByteArray className; + const QMetaObject *superClass; + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction; + QList<QMetaMethodBuilderPrivate> methods; + QList<QMetaMethodBuilderPrivate> constructors; + QList<QMetaPropertyBuilderPrivate> properties; + QList<QByteArray> classInfoNames; + QList<QByteArray> classInfoValues; + QList<QMetaEnumBuilderPrivate> enumerators; + QList<const QMetaObject *> relatedMetaObjects; +}; + +/*! + Constructs a new QMetaObjectBuilder. +*/ +QMetaObjectBuilder::QMetaObjectBuilder() +{ + d = new QMetaObjectBuilderPrivate(); +} + +/*! + Constructs a new QMetaObjectBuilder which is a copy of the + meta object information in \a prototype. Note: the super class + contents for \a prototype are not copied, only the immediate + class that is defined by \a prototype. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. + + \sa addMetaObject() +*/ +QMetaObjectBuilder::QMetaObjectBuilder + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + d = new QMetaObjectBuilderPrivate(); + addMetaObject(prototype, members); +} + +/*! + Destroys this meta object builder. +*/ +QMetaObjectBuilder::~QMetaObjectBuilder() +{ + delete d; +} + +/*! + Returns the name of the class being constructed by this + meta object builder. The default value is an empty QByteArray. + + \sa setClassName(), superClass() +*/ +QByteArray QMetaObjectBuilder::className() const +{ + return d->className; +} + +/*! + Sets the \a name of the class being constructed by this + meta object builder. + + \sa className(), setSuperClass() +*/ +void QMetaObjectBuilder::setClassName(const QByteArray& name) +{ + d->className = name; +} + +/*! + Returns the superclass meta object of the class being constructed + by this meta object builder. The default value is the meta object + for QObject. + + \sa setSuperClass(), className() +*/ +const QMetaObject *QMetaObjectBuilder::superClass() const +{ + return d->superClass; +} + +/*! + Sets the superclass meta object of the class being constructed + by this meta object builder to \a meta. The \a meta parameter + must not be null. + + \sa superClass(), setClassName() +*/ +void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta) +{ + Q_ASSERT(meta); + d->superClass = meta; +} + +/*! + Returns the number of methods in this class, excluding the number + of methods in the base class. These include signals and slots + as well as normal member functions. + + \sa addMethod(), method(), removeMethod(), indexOfMethod() +*/ +int QMetaObjectBuilder::methodCount() const +{ + return d->methods.size(); +} + +/*! + Returns the number of constructors in this class. + + \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor() +*/ +int QMetaObjectBuilder::constructorCount() const +{ + return d->constructors.size(); +} + +/*! + Returns the number of properties in this class, excluding the number + of properties in the base class. + + \sa addProperty(), property(), removeProperty(), indexOfProperty() +*/ +int QMetaObjectBuilder::propertyCount() const +{ + return d->properties.size(); +} + +/*! + Returns the number of enumerators in this class, excluding the + number of enumerators in the base class. + + \sa addEnumerator(), enumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +int QMetaObjectBuilder::enumeratorCount() const +{ + return d->enumerators.size(); +} + +/*! + Returns the number of items of class information in this class, + exclusing the number of items of class information in the base class. + + \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::classInfoCount() const +{ + return d->classInfoNames.size(); +} + +/*! + Returns the number of related meta objects that are associated + with this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa addRelatedMetaObject(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +int QMetaObjectBuilder::relatedMetaObjectCount() const +{ + return d->relatedMetaObjects.size(); +} + +/*! + Adds a new public method to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the method. The \a signature will be normalized before it is + added to the class. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class with the specified + \a signature and \a returnType. Returns an object that can be + used to adjust the other attributes of the method. The \a signature + and \a returnType will be normalized before they are added to + the class. If \a returnType is empty, then it indicates that + the method has \c{void} as its return type. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod + (const QByteArray& signature, const QByteArray& returnType) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Method, signature, returnType)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class that has the same information as + \a prototype. This is used to clone the methods of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the method. + + This function will detect if \a prototype is an ordinary method, + signal, slot, or constructor and act accordingly. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype) +{ + QMetaMethodBuilder method; + if (prototype.methodType() == QMetaMethod::Method) + method = addMethod(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Signal) + method = addSignal(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Slot) + method = addSlot(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Constructor) + method = addConstructor(prototype.signature()); + method.setReturnType(prototype.typeName()); + method.setParameterNames(prototype.parameterNames()); + method.setTag(prototype.tag()); + method.setAccess(prototype.access()); + method.setAttributes(prototype.attributes()); + return method; +} + +/*! + Adds a new public slot to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the slot. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSignal(), indexOfSlot() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new signal to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the signal. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSlot(), indexOfSignal() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new constructor to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the constructor. The \a signature will be normalized before it is + added to the class. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature) +{ + int index = d->constructors.size(); + d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature)); + return QMetaMethodBuilder(this, -(index + 1)); +} + +/*! + Adds a new constructor to this class that has the same information as + \a prototype. This is used to clone the constructors of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the constructor. + + This function requires that \a prototype be a constructor. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype) +{ + Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor); + QMetaMethodBuilder ctor = addConstructor(prototype.signature()); + ctor.setReturnType(prototype.typeName()); + ctor.setParameterNames(prototype.parameterNames()); + ctor.setTag(prototype.tag()); + ctor.setAccess(prototype.access()); + ctor.setAttributes(prototype.attributes()); + return ctor; +} + +/*! + Adds a new readable/writable property to this class with the specified + \a name and \a type. Returns an object that can be used to adjust + the other attributes of the property. The \a type will be + normalized before it is added to the class. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty + (const QByteArray& name, const QByteArray& type, int notifierId) +{ + int index = d->properties.size(); + d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId)); + return QMetaPropertyBuilder(this, index); +} + +/*! + Adds a new property to this class that has the same information as + \a prototype. This is used to clone the properties of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the property. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype) +{ + QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName()); + property.setReadable(prototype.isReadable()); + property.setWritable(prototype.isWritable()); + property.setResettable(prototype.isResettable()); + property.setDesignable(prototype.isDesignable()); + property.setScriptable(prototype.isScriptable()); + property.setStored(prototype.isStored()); + property.setEditable(prototype.isEditable()); + property.setUser(prototype.isUser()); + property.setStdCppSet(prototype.hasStdCppSet()); + property.setEnumOrFlag(prototype.isEnumType()); + if (prototype.hasNotifySignal()) { + // Find an existing method for the notify signal, or add a new one. + QMetaMethod method = prototype.notifySignal(); + int index = indexOfMethod(method.signature()); + if (index == -1) + index = addMethod(method).index(); + d->properties[property._index].notifySignal = index; + d->properties[property._index].setFlag(Notify, true); + } + return property; +} + +/*! + Adds a new enumerator to this class with the specified + \a name. Returns an object that can be used to adjust + the other attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name) +{ + int index = d->enumerators.size(); + d->enumerators.append(QMetaEnumBuilderPrivate(name)); + return QMetaEnumBuilder(this, index); +} + +/*! + Adds a new enumerator to this class that has the same information as + \a prototype. This is used to clone the enumerators of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype) +{ + QMetaEnumBuilder en = addEnumerator(prototype.name()); + en.setIsFlag(prototype.isFlag()); + int count = prototype.keyCount(); + for (int index = 0; index < count; ++index) + en.addKey(prototype.key(index), prototype.value(index)); + return en; +} + +/*! + Adds \a name and \a value as an item of class information to this class. + Returns the index of the new item of class information. + + \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value) +{ + int index = d->classInfoNames.size(); + d->classInfoNames += name; + d->classInfoValues += value; + return index; +} + +/*! + Adds \a meta to this class as a related meta object. Returns + the index of the new related meta object entry. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta) +{ + Q_ASSERT(meta); + int index = d->relatedMetaObjects.size(); + d->relatedMetaObjects.append(meta); + return index; +} + +/*! + Adds the contents of \a prototype to this meta object builder. + This function is useful for cloning the contents of an existing QMetaObject. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. +*/ +void QMetaObjectBuilder::addMetaObject + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + Q_ASSERT(prototype); + int index; + + if ((members & ClassName) != 0) + d->className = prototype->className(); + + if ((members & SuperClass) != 0) + d->superClass = prototype->superClass(); + + if ((members & (Methods | Signals | Slots)) != 0) { + for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) { + QMetaMethod method = prototype->method(index); + if (method.methodType() != QMetaMethod::Signal) { + if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0) + continue; + if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0) + continue; + if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0) + continue; + } + if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Signal && + (members & Signals) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Slot && + (members & Slots) != 0) { + addMethod(method); + } + } + } + + if ((members & Constructors) != 0) { + for (index = 0; index < prototype->constructorCount(); ++index) + addConstructor(prototype->constructor(index)); + } + + if ((members & Properties) != 0) { + for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index) + addProperty(prototype->property(index)); + } + + if ((members & Enumerators) != 0) { + for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index) + addEnumerator(prototype->enumerator(index)); + } + + if ((members & ClassInfos) != 0) { + for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) { + QMetaClassInfo ci = prototype->classInfo(index); + addClassInfo(ci.name(), ci.value()); + } + } + + if ((members & RelatedMetaObjects) != 0) { + const QMetaObject **objects; + if (priv(prototype->d.data)->revision < 2) { + objects = (const QMetaObject **)(prototype->d.extradata); + } else { + const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra) + objects = extra->objects; + else + objects = 0; + } + if (objects) { + while (*objects != 0) { + addRelatedMetaObject(*objects); + ++objects; + } + } + } + + if ((members & StaticMetacall) != 0) { + if (priv(prototype->d.data)->revision >= 2) { + const QMetaObjectExtraData *extra = + (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra && extra->static_metacall) + setStaticMetacallFunction(extra->static_metacall); + } + } +} + +/*! + Returns the method at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::method(int index) const +{ + if (index >= 0 && index < d->methods.size()) + return QMetaMethodBuilder(this, index); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the constructor at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const +{ + if (index >= 0 && index < d->constructors.size()) + return QMetaMethodBuilder(this, -(index + 1)); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the property at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const +{ + if (index >= 0 && index < d->properties.size()) + return QMetaPropertyBuilder(this, index); + else + return QMetaPropertyBuilder(); +} + +/*! + Returns the enumerator at \a index in this class. + + \sa enumeratorCount(), addEnumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const +{ + if (index >= 0 && index < d->enumerators.size()) + return QMetaEnumBuilder(this, index); + else + return QMetaEnumBuilder(); +} + +/*! + Returns the related meta object at \a index in this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa removeRelatedMetaObject() +*/ +const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) + return d->relatedMetaObjects[index]; + else + return 0; +} + +/*! + Returns the name of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoName(int index) const +{ + if (index >= 0 && index < d->classInfoNames.size()) + return d->classInfoNames[index]; + else + return QByteArray(); +} + +/*! + Returns the value of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoValue(int index) const +{ + if (index >= 0 && index < d->classInfoValues.size()) + return d->classInfoValues[index]; + else + return QByteArray(); +} + +/*! + Removes the method at \a index from this class. The indices of + all following methods will be adjusted downwards by 1. If the + method is registered as a notify signal on a property, then the + notify signal will be removed from the property. + + \sa methodCount(), addMethod(), method(), indexOfMethod() +*/ +void QMetaObjectBuilder::removeMethod(int index) +{ + if (index >= 0 && index < d->methods.size()) { + d->methods.removeAt(index); + for (int prop = 0; prop < d->properties.size(); ++prop) { + // Adjust the indices of property notify signal references. + if (d->properties[prop].notifySignal == index) + d->properties[prop].notifySignal = -1; + else if (d->properties[prop].notifySignal > index) + (d->properties[prop].notifySignal)--; + } + } +} + +/*! + Removes the constructor at \a index from this class. The indices of + all following constructors will be adjusted downwards by 1. + + \sa constructorCount(), addConstructor(), constructor() + \sa indexOfConstructor() +*/ +void QMetaObjectBuilder::removeConstructor(int index) +{ + if (index >= 0 && index < d->constructors.size()) + d->constructors.removeAt(index); +} + +/*! + Removes the property at \a index from this class. The indices of + all following properties will be adjusted downwards by 1. + + \sa propertyCount(), addProperty(), property(), indexOfProperty() +*/ +void QMetaObjectBuilder::removeProperty(int index) +{ + if (index >= 0 && index < d->properties.size()) + d->properties.removeAt(index); +} + +/*! + Removes the enumerator at \a index from this class. The indices of + all following enumerators will be adjusted downwards by 1. + + \sa enumertorCount(), addEnumerator(), enumerator() + \sa indexOfEnumerator() +*/ +void QMetaObjectBuilder::removeEnumerator(int index) +{ + if (index >= 0 && index < d->enumerators.size()) + d->enumerators.removeAt(index); +} + +/*! + Removes the item of class information at \a index from this class. + The indices of all following items will be adjusted downwards by 1. + + \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue() + \sa indexOfClassInfo() +*/ +void QMetaObjectBuilder::removeClassInfo(int index) +{ + if (index >= 0 && index < d->classInfoNames.size()) { + d->classInfoNames.removeAt(index); + d->classInfoValues.removeAt(index); + } +} + +/*! + Removes the related meta object at \a index from this class. + The indices of all following related meta objects will be adjusted + downwards by 1. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa relatedMetaObject() +*/ +void QMetaObjectBuilder::removeRelatedMetaObject(int index) +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) + d->relatedMetaObjects.removeAt(index); +} + +/*! + Finds a method with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa method(), methodCount(), addMethod(), removeMethod() +*/ +int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature) + return index; + } + return -1; +} + +/*! + Finds a signal with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSlot() +*/ +int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Signal) + return index; + } + return -1; +} + +/*! + Finds a slot with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSignal() +*/ +int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Slot) + return index; + } + return -1; +} + +/*! + Finds a constructor with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa constructor(), constructorCount(), addConstructor(), removeConstructor() +*/ +int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->constructors.size(); ++index) { + if (sig == d->constructors[index].signature) + return index; + } + return -1; +} + +/*! + Finds a property with the specified \a name and returns its index; + otherwise returns -1. + + \sa property(), propertyCount(), addProperty(), removeProperty() +*/ +int QMetaObjectBuilder::indexOfProperty(const QByteArray& name) +{ + for (int index = 0; index < d->properties.size(); ++index) { + if (name == d->properties[index].name) + return index; + } + return -1; +} + +/*! + Finds an enumerator with the specified \a name and returns its index; + otherwise returns -1. + + \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator() +*/ +int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name) +{ + for (int index = 0; index < d->enumerators.size(); ++index) { + if (name == d->enumerators[index].name) + return index; + } + return -1; +} + +/*! + Finds an item of class information with the specified \a name and + returns its index; otherwise returns -1. + + \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo() + \sa removeClassInfo() +*/ +int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name) +{ + for (int index = 0; index < d->classInfoNames.size(); ++index) { + if (name == d->classInfoNames[index]) + return index; + } + return -1; +} + +// Align on a specific type boundary. +#define ALIGN(size,type) \ + (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1) + +// Build a string into a QMetaObject representation. Returns the +// position in the string table where the string was placed. +static int buildString + (char *buf, char *str, int *offset, const QByteArray& value, int empty) +{ + if (value.size() == 0 && empty >= 0) + return empty; + if (buf) { + memcpy(str + *offset, value.constData(), value.size()); + str[*offset + value.size()] = '\0'; + } + int posn = *offset; + *offset += value.size() + 1; + return posn; +} + +// Build the parameter array string for a method. +static QByteArray buildParameterNames + (const QByteArray& signature, const QList<QByteArray>& parameterNames) +{ + // If the parameter name list is specified, then concatenate them. + if (!parameterNames.isEmpty()) { + QByteArray names; + bool first = true; + foreach (QByteArray name, parameterNames) { + if (first) + first = false; + else + names += (char)','; + names += name; + } + return names; + } + + // Count commas in the signature, excluding those inside template arguments. + int index = signature.indexOf('('); + if (index < 0) + return QByteArray(); + ++index; + if (index >= signature.size()) + return QByteArray(); + if (signature[index] == ')') + return QByteArray(); + int count = 1; + int brackets = 0; + while (index < signature.size() && signature[index] != ',') { + char ch = signature[index++]; + if (ch == '<') + ++brackets; + else if (ch == '>') + --brackets; + else if (ch == ',' && brackets <= 0) + ++count; + } + return QByteArray(count - 1, ','); +} + +// Build a QMetaObject in "buf" based on the information in "d". +// If "buf" is null, then return the number of bytes needed to +// build the QMetaObject. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) +{ + int size = 0; + int dataIndex; + int enumIndex; + int index; + bool hasNotifySignals = false; + + // Create the main QMetaObject structure at the start of the buffer. + QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf); + size += sizeof(QMetaObject); + ALIGN(size, int); + if (buf) { + meta->d.superdata = d->superClass; + meta->d.extradata = 0; + } + + // Populate the QMetaObjectPrivate structure. + QMetaObjectPrivate *pmeta + = reinterpret_cast<QMetaObjectPrivate *>(buf + size); + dataIndex = 12; // Number of fields in the QMetaObjectPrivate. + for (index = 0; index < d->properties.size(); ++index) { + if (d->properties[index].notifySignal != -1) { + hasNotifySignals = true; + break; + } + } + if (buf) { + pmeta->revision = 2; + pmeta->className = 0; // Class name is always the first string. + + pmeta->classInfoCount = d->classInfoNames.size(); + pmeta->classInfoData = dataIndex; + dataIndex += 2 * d->classInfoNames.size(); + + pmeta->methodCount = d->methods.size(); + pmeta->methodData = dataIndex; + dataIndex += 5 * d->methods.size(); + + pmeta->propertyCount = d->properties.size(); + pmeta->propertyData = dataIndex; + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + + pmeta->enumeratorCount = d->enumerators.size(); + pmeta->enumeratorData = dataIndex; + dataIndex += 4 * d->enumerators.size(); + + pmeta->constructorCount = d->constructors.size(); + pmeta->constructorData = dataIndex; + dataIndex += 5 * d->constructors.size(); + } else { + dataIndex += 2 * d->classInfoNames.size(); + dataIndex += 5 * d->methods.size(); + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + dataIndex += 4 * d->enumerators.size(); + dataIndex += 5 * d->constructors.size(); + } + + // Allocate space for the enumerator key names and values. + enumIndex = dataIndex; + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + dataIndex += 2 * enumerator->keys.size(); + } + + // Zero terminator at the end of the data offset table. + ++dataIndex; + + // Find the start of the data and string tables. + int *data = reinterpret_cast<int *>(pmeta); + size += dataIndex * sizeof(int); + char *str = reinterpret_cast<char *>(buf + size); + if (buf) { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast<uint *>(data); + } + + // Reset the current data position to just past the QMetaObjectPrivate. + dataIndex = 12; + + // Add the class name to the string table. + int offset = 0; + buildString(buf, str, &offset, d->className, -1); + + // Add a common empty string, which is used to indicate "void" + // method returns, empty tag strings, etc. + int empty = buildString(buf, str, &offset, QByteArray(), -1); + + // Output the class infos, + for (index = 0; index < d->classInfoNames.size(); ++index) { + int name = buildString(buf, str, &offset, d->classInfoNames[index], empty); + int value = buildString(buf, str, &offset, d->classInfoValues[index], empty); + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = value; + } + dataIndex += 2; + } + + // Output the methods in the class. + for (index = 0; index < d->methods.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // Output the properties in the class. + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + int name = buildString(buf, str, &offset, prop->name, empty); + int type = buildString(buf, str, &offset, prop->type, empty); + int flags = prop->flags; + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = type; + data[dataIndex + 2] = flags; + } + dataIndex += 3; + } + if (hasNotifySignals) { + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + if (buf) { + if (prop->notifySignal != -1) + data[dataIndex] = prop->notifySignal; + else + data[dataIndex] = 0; + } + ++dataIndex; + } + } + + // Output the enumerators in the class. + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + int name = buildString(buf, str, &offset, enumerator->name, empty); + int isFlag = (int)(enumerator->isFlag); + int count = enumerator->keys.size(); + int enumOffset = enumIndex; + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = isFlag; + data[dataIndex + 2] = count; + data[dataIndex + 3] = enumOffset; + } + for (int key = 0; key < count; ++key) { + int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty); + if (buf) { + data[enumOffset++] = keyIndex; + data[enumOffset++] = enumerator->values[key]; + } + } + dataIndex += 4; + enumIndex += 2 * count; + } + + // Output the constructors in the class. + for (index = 0; index < d->constructors.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // One more empty string to act as a terminator. + buildString(buf, str, &offset, QByteArray(), -1); + size += offset; + + // Output the zero terminator in the data array. + if (buf) + data[enumIndex] = 0; + + // Create the extradata block if we need one. + if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) { + ALIGN(size, QMetaObject **); + ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction); + QMetaObjectExtraData *extra = + reinterpret_cast<QMetaObjectExtraData *>(buf + size); + size += sizeof(QMetaObjectExtraData); + ALIGN(size, QMetaObject *); + const QMetaObject **objects = + reinterpret_cast<const QMetaObject **>(buf + size); + if (buf) { + if (d->relatedMetaObjects.size() > 0) { + extra->objects = objects; + for (index = 0; index < d->relatedMetaObjects.size(); ++index) + objects[index] = d->relatedMetaObjects[index]; + objects[index] = 0; + } else { + extra->objects = 0; + } + extra->static_metacall = d->staticMetacallFunction; + meta->d.extradata = reinterpret_cast<void *>(extra); + } + if (d->relatedMetaObjects.size() > 0) + size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1); + } + + // Align the final size and return it. + ALIGN(size, void *); + return size; +} + +/*! + Converts this meta object builder into a concrete QMetaObject. + The return value should be deallocated using qFree() once it + is no longer needed. + + The returned meta object is a snapshot of the state of the + QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder + will not be reflected in previous meta objects returned by + this method. +*/ +QMetaObject *QMetaObjectBuilder::toMetaObject() const +{ + int size = buildMetaObject(d, 0); + char *buf = reinterpret_cast<char *>(qMalloc(size)); + buildMetaObject(d, buf); + return reinterpret_cast<QMetaObject *>(buf); +} + +/*! + \typedef QMetaObjectBuilder::StaticMetacallFunction + + Typedef for static metacall functions. The three parameters are + the call type value, the constructor index, and the + array of parameters. +*/ + +/*! + Returns the static metacall function to use to construct objects + of this class. The default value is null. + + \sa setStaticMetacallFunction() +*/ +QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const +{ + return d->staticMetacallFunction; +} + +/*! + Sets the static metacall function to use to construct objects + of this class to \a value. The default value is null. + + \sa staticMetacallFunction() +*/ +void QMetaObjectBuilder::setStaticMetacallFunction + (QMetaObjectBuilder::StaticMetacallFunction value) +{ + d->staticMetacallFunction = value; +} + +#ifndef QT_NO_DATASTREAM + +/*! + Serializes the contents of the meta object builder onto \a stream. + + \sa deserialize() +*/ +void QMetaObjectBuilder::serialize(QDataStream& stream) const +{ + int index; + + // Write the class and super class names. + stream << d->className; + if (d->superClass) + stream << QByteArray(d->superClass->className()); + else + stream << QByteArray(); + + // Write the counts for each type of class member. + stream << d->classInfoNames.size(); + stream << d->methods.size(); + stream << d->properties.size(); + stream << d->enumerators.size(); + stream << d->constructors.size(); + stream << d->relatedMetaObjects.size(); + + // Write the items of class information. + for (index = 0; index < d->classInfoNames.size(); ++index) { + stream << d->classInfoNames[index]; + stream << d->classInfoValues[index]; + } + + // Write the methods. + for (index = 0; index < d->methods.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the properties. + for (index = 0; index < d->properties.size(); ++index) { + const QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream << property->name; + stream << property->type; + stream << property->flags; + stream << property->notifySignal; + } + + // Write the enumerators. + for (index = 0; index < d->enumerators.size(); ++index) { + const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream << enumerator->name; + stream << enumerator->isFlag; + stream << enumerator->keys; + stream << enumerator->values; + } + + // Write the constructors. + for (index = 0; index < d->constructors.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the related meta objects. + for (index = 0; index < d->relatedMetaObjects.size(); ++index) { + const QMetaObject *meta = d->relatedMetaObjects[index]; + stream << QByteArray(meta->className()); + } + + // Add an extra empty QByteArray for additional data in future versions. + // This should help maintain backwards compatibility, allowing older + // versions to read newer data. + stream << QByteArray(); +} + +// Resolve a class name using the name reference map. +static const QMetaObject *resolveClassName + (const QMap<QByteArray, const QMetaObject *>& references, + const QByteArray& name) +{ + if (name == QByteArray("QObject")) + return &QObject::staticMetaObject; + else + return references.value(name, 0); +} + +/*! + Deserializes a meta object builder from \a stream into + this meta object builder. + + The \a references parameter specifies a mapping from class names + to QMetaObject instances for resolving the super class name and + related meta objects in the object that is deserialized. + The meta object for QObject is implicitly added to \a references + and does not need to be supplied. + + The QDataStream::status() value on \a stream will be set to + QDataStream::ReadCorruptData if the input data is corrupt. + The status will be set to QDataStream::ReadPastEnd if the + input was exhausted before the full meta object was read. + + \sa serialize() +*/ +void QMetaObjectBuilder::deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references) +{ + QByteArray name; + const QMetaObject *cl; + int index; + + // Clear all members in the builder to their default states. + d->className.clear(); + d->superClass = &QObject::staticMetaObject; + d->classInfoNames.clear(); + d->classInfoValues.clear(); + d->methods.clear(); + d->properties.clear(); + d->enumerators.clear(); + d->constructors.clear(); + d->relatedMetaObjects.clear(); + d->staticMetacallFunction = 0; + + // Read the class and super class names. + stream >> d->className; + stream >> name; + if (name.isEmpty()) { + d->superClass = 0; + } else if ((cl = resolveClassName(references, name)) != 0) { + d->superClass = cl; + } else { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the counts for each type of class member. + int classInfoCount, methodCount, propertyCount; + int enumeratorCount, constructorCount, relatedMetaObjectCount; + stream >> classInfoCount; + stream >> methodCount; + stream >> propertyCount; + stream >> enumeratorCount; + stream >> constructorCount; + stream >> relatedMetaObjectCount; + if (classInfoCount < 0 || methodCount < 0 || + propertyCount < 0 || enumeratorCount < 0 || + constructorCount < 0 || relatedMetaObjectCount < 0) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the items of class information. + for (index = 0; index < classInfoCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray value; + stream >> name; + stream >> value; + addClassInfo(name, value); + } + + // Read the member methods. + for (index = 0; index < methodCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addMethod(name); + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() == QMetaMethod::Constructor) { + // Cannot add a constructor in this set of methods. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the properties. + for (index = 0; index < propertyCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray type; + stream >> name; + stream >> type; + addProperty(name, type); + QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream >> property->flags; + stream >> property->notifySignal; + if (property->notifySignal < -1 || + property->notifySignal >= d->methods.size()) { + // Notify signal method index is out of range. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + if (property->notifySignal >= 0 && + d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) { + // Notify signal method index does not refer to a signal. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the enumerators. + for (index = 0; index < enumeratorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addEnumerator(name); + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream >> enumerator->isFlag; + stream >> enumerator->keys; + stream >> enumerator->values; + if (enumerator->keys.size() != enumerator->values.size()) { + // Mismatch between number of keys and number of values. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the constructor methods. + for (index = 0; index < constructorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addConstructor(name); + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() != QMetaMethod::Constructor) { + // The type must be Constructor. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the related meta objects. + for (index = 0; index < relatedMetaObjectCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + cl = resolveClassName(references, name); + if (!cl) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + addRelatedMetaObject(cl); + } + + // Read the extra data block, which is reserved for future use. + stream >> name; +} + +#endif // !QT_NO_DATASTREAM + +/*! + \class QMetaMethodBuilder + \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder. +*/ + +QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const +{ + // Positive indices indicate methods, negative indices indicate constructors. + if (_mobj && _index >= 0 && _index < _mobj->d->methods.size()) + return &(_mobj->d->methods[_index]); + else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size()) + return &(_mobj->d->constructors[(-_index) - 1]); + else + return 0; +} + +/*! + \fn QMetaMethodBuilder::QMetaMethodBuilder() + \internal +*/ + +/*! + Returns the index of this method within its QMetaObjectBuilder. +*/ +int QMetaMethodBuilder::index() const +{ + if (_index >= 0) + return _index; // Method, signal, or slot + else + return (-_index) - 1; // Constructor +} + +/*! + Returns the type of this method (signal, slot, method, or constructor). +*/ +QMetaMethod::MethodType QMetaMethodBuilder::methodType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->methodType(); + else + return QMetaMethod::Method; +} + +/*! + Returns the signature of this method. + + \sa parameterNames(), returnType() +*/ +QByteArray QMetaMethodBuilder::signature() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->signature; + else + return QByteArray(); +} + +/*! + Returns the return type for this method; empty if the method's + return type is \c{void}. + + \sa setReturnType(), signature() +*/ +QByteArray QMetaMethodBuilder::returnType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->returnType; + else + return QByteArray(); +} + +/*! + Sets the return type for this method to \a value. If \a value + is empty, then the method's return type is \c{void}. The \a value + will be normalized before it is added to the method. + + \sa returnType(), signature() +*/ +void QMetaMethodBuilder::setReturnType(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->returnType = QMetaObject::normalizedType(value); +} + +/*! + Returns the list of parameter names for this method. + + \sa setParameterNames() +*/ +QList<QByteArray> QMetaMethodBuilder::parameterNames() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->parameterNames; + else + return QList<QByteArray>(); +} + +/*! + Sets the list of parameter names for this method to \a value. + + \sa parameterNames() +*/ +void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->parameterNames = value; +} + +/*! + Returns the tag associated with this method. + + \sa setTag() +*/ +QByteArray QMetaMethodBuilder::tag() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->tag; + else + return QByteArray(); +} + +/*! + Sets the tag associated with this method to \a value. + + \sa setTag() +*/ +void QMetaMethodBuilder::setTag(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->tag = value; +} + +/*! + Returns the access specification of this method (private, protected, + or public). The default value is QMetaMethod::Public for methods, + slots, and constructors. The default value is QMetaMethod::Protected + for signals. + + \sa setAccess() +*/ +QMetaMethod::Access QMetaMethodBuilder::access() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->access(); + else + return QMetaMethod::Public; +} + +/*! + Sets the access specification of this method (private, protected, + or public) to \a value. If the method is a signal, this function + will be ignored. + + \sa access() +*/ +void QMetaMethodBuilder::setAccess(QMetaMethod::Access value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d && d->methodType() != QMetaMethod::Signal) + d->setAccess(value); +} + +/*! + Returns the additional attributes for this method. + + \sa setAttributes() +*/ +int QMetaMethodBuilder::attributes() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return (d->attributes >> 4); + else + return 0; +} + +/*! + Sets the additional attributes for this method to \a value. + + \sa attributes() +*/ +void QMetaMethodBuilder::setAttributes(int value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->attributes = ((d->attributes & 0x0f) | (value << 4)); +} + +/*! + \class QMetaPropertyBuilder + \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder. +*/ + +QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->properties.size()) + return &(_mobj->d->properties[_index]); + else + return 0; +} + +/*! + \fn QMetaPropertyBuilder::QMetaPropertyBuilder() + \internal +*/ + +/*! + \fn int QMetaPropertyBuilder::index() const + + Returns the index of this property within its QMetaObjectBuilder. +*/ + +/*! + Returns the name associated with this property. + + \sa type() +*/ +QByteArray QMetaPropertyBuilder::name() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns the type associated with this property. + + \sa name() +*/ +QByteArray QMetaPropertyBuilder::type() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->type; + else + return QByteArray(); +} + +/*! + Returns true if this property has a notify signal; false otherwise. + + \sa notifySignal(), setNotifySignal(), removeNotifySignal() +*/ +bool QMetaPropertyBuilder::hasNotifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Notify); + else + return false; +} + +/*! + Returns the notify signal associated with this property. + + \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal() +*/ +QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d && d->notifySignal >= 0) + return QMetaMethodBuilder(_mobj, d->notifySignal); + else + return QMetaMethodBuilder(); +} + +/*! + Sets the notify signal associated with this property to \a value. + + \sa hasNotifySignal(), notifySignal(), removeNotifySignal() +*/ +void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + if (value._mobj) { + d->notifySignal = value._index; + d->setFlag(Notify, true); + } else { + d->notifySignal = -1; + d->setFlag(Notify, false); + } + } +} + +/*! + Removes the notify signal from this property. + + \sa hasNotifySignal(), notifySignal(), setNotifySignal() +*/ +void QMetaPropertyBuilder::removeNotifySignal() +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + d->notifySignal = -1; + d->setFlag(Notify, false); + } +} + +/*! + Returns true if this property is readable; otherwise returns false. + The default value is true. + + \sa setReadable(), isWritable() +*/ +bool QMetaPropertyBuilder::isReadable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Readable); + else + return false; +} + +/*! + Returns true if this property is writable; otherwise returns false. + The default value is true. + + \sa setWritable(), isReadable() +*/ +bool QMetaPropertyBuilder::isWritable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Writable); + else + return false; +} + +/*! + Returns true if this property can be reset to a default value; otherwise + returns false. The default value is false. + + \sa setResettable() +*/ +bool QMetaPropertyBuilder::isResettable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Resettable); + else + return false; +} + +/*! + Returns true if this property is designable; otherwise returns false. + This default value is false. + + \sa setDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isDesignable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Designable); + else + return false; +} + +/*! + Returns true if the property is scriptable; otherwise returns false. + This default value is false. + + \sa setScriptable(), isDesignable(), isStored() +*/ +bool QMetaPropertyBuilder::isScriptable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Scriptable); + else + return false; +} + +/*! + Returns true if the property is stored; otherwise returns false. + This default value is false. + + \sa setStored(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isStored() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Stored); + else + return false; +} + +/*! + Returns true if the property is editable; otherwise returns false. + This default value is false. + + \sa setEditable(), isDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isEditable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Editable); + else + return false; +} + +/*! + Returns true if this property is designated as the \c USER + property, i.e., the one that the user can edit or that is + significant in some other way. Otherwise it returns + false. This default value is false. + + \sa setUser(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isUser() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(User); + else + return false; +} + +/*! + Returns true if the property has a C++ setter function that + follows Qt's standard "name" / "setName" pattern. Designer and uic + query hasStdCppSet() in order to avoid expensive + QObject::setProperty() calls. All properties in Qt [should] follow + this pattern. The default value is false. + + \sa setStdCppSet() +*/ +bool QMetaPropertyBuilder::hasStdCppSet() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(StdCppSet); + else + return false; +} + +/*! + Returns true if the property is an enumerator or flag type; + otherwise returns false. This default value is false. + + \sa setEnumOrFlag() +*/ +bool QMetaPropertyBuilder::isEnumOrFlag() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(EnumOrFlag); + else + return false; +} + +/*! + Sets this property to readable if \a value is true. + + \sa isReadable(), setWritable() +*/ +void QMetaPropertyBuilder::setReadable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Readable, value); +} + +/*! + Sets this property to writable if \a value is true. + + \sa isWritable(), setReadable() +*/ +void QMetaPropertyBuilder::setWritable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Writable, value); +} + +/*! + Sets this property to resettable if \a value is true. + + \sa isResettable() +*/ +void QMetaPropertyBuilder::setResettable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Resettable, value); +} + +/*! + Sets this property to designable if \a value is true. + + \sa isDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setDesignable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Designable, value); +} + +/*! + Sets this property to scriptable if \a value is true. + + \sa isScriptable(), setDesignable(), setStored() +*/ +void QMetaPropertyBuilder::setScriptable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Scriptable, value); +} + +/*! + Sets this property to storable if \a value is true. + + \sa isStored(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setStored(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Stored, value); +} + +/*! + Sets this property to editable if \a value is true. + + \sa isEditable(), setDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setEditable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Editable, value); +} + +/*! + Sets the \c USER flag on this property to \a value. + + \sa isUser(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setUser(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(User, value); +} + +/*! + Sets the C++ setter flag on this property to \a value, which is + true if the property has a C++ setter function that follows Qt's + standard "name" / "setName" pattern. + + \sa hasStdCppSet() +*/ +void QMetaPropertyBuilder::setStdCppSet(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(StdCppSet, value); +} + +/*! + Sets this property to be of an enumerator or flag type if + \a value is true. + + \sa isEnumOrFlag() +*/ +void QMetaPropertyBuilder::setEnumOrFlag(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(EnumOrFlag, value); +} + +/*! + \class QMetaEnumBuilder + \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder. +*/ + +QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size()) + return &(_mobj->d->enumerators[_index]); + else + return 0; +} + +/*! + \fn QMetaEnumBuilder::QMetaEnumBuilder() + \internal +*/ + +/*! + \fn int QMetaEnumBuilder::index() const + + Returns the index of this enumerator within its QMetaObjectBuilder. +*/ + +/*! + Returns the name of the enumerator (without the scope). +*/ +QByteArray QMetaEnumBuilder::name() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns true if this enumerator is used as a flag; otherwise returns + false. + + \sa setIsFlag() +*/ +bool QMetaEnumBuilder::isFlag() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->isFlag; + else + return false; +} + +/*! + Sets this enumerator to be used as a flag if \a value is true. + + \sa isFlag() +*/ +void QMetaEnumBuilder::setIsFlag(bool value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + d->isFlag = value; +} + +/*! + Returns the number of keys. + + \sa key(), addKey() +*/ +int QMetaEnumBuilder::keyCount() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->keys.size(); + else + return 0; +} + +/*! + Returns the key with the given \a index, or an empty QByteArray + if no such key exists. + + \sa keyCount(), addKey(), value() +*/ +QByteArray QMetaEnumBuilder::key(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->keys[index]; + else + return QByteArray(); +} + +/*! + Returns the value with the given \a index; or returns -1 if there + is no such value. + + \sa keyCount(), addKey(), key() +*/ +int QMetaEnumBuilder::value(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->values[index]; + else + return -1; +} + +/*! + Adds a new key called \a name to this enumerator, associated + with \a value. Returns the index of the new key. + + \sa keyCount(), key(), value(), removeKey() +*/ +int QMetaEnumBuilder::addKey(const QByteArray& name, int value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) { + int index = d->keys.size(); + d->keys += name; + d->values += value; + return index; + } else { + return -1; + } +} + +/*! + Removes the key at \a index from this enumerator. + + \sa addKey() +*/ +void QMetaEnumBuilder::removeKey(int index) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) { + d->keys.removeAt(index); + d->values.removeAt(index); + } +} diff --git a/tests/auto/dynamicobject/qmetaobjectbuilder.h b/tests/auto/dynamicobject/qmetaobjectbuilder.h new file mode 100644 index 0000000..d820860 --- /dev/null +++ b/tests/auto/dynamicobject/qmetaobjectbuilder.h @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETAOBJECTBUILDER_H +#define QMETAOBJECTBUILDER_H + +#include <QtCore/qobject.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qmap.h> + +class QMetaObjectBuilderPrivate; +class QMetaMethodBuilder; +class QMetaMethodBuilderPrivate; +class QMetaPropertyBuilder; +class QMetaPropertyBuilderPrivate; +class QMetaEnumBuilder; +class QMetaEnumBuilderPrivate; + +class QMetaObjectBuilder +{ +public: + enum AddMember + { + ClassName = 0x00000001, + SuperClass = 0x00000002, + Methods = 0x00000004, + Signals = 0x00000008, + Slots = 0x00000010, + Constructors = 0x00000020, + Properties = 0x00000040, + Enumerators = 0x00000080, + ClassInfos = 0x00000100, + RelatedMetaObjects = 0x00000200, + StaticMetacall = 0x00000400, + PublicMethods = 0x00000800, + ProtectedMethods = 0x00001000, + PrivateMethods = 0x00002000, + AllMembers = 0x7FFFFFFF, + AllPrimaryMembers = 0x7FFFFBFC + }; + Q_DECLARE_FLAGS(AddMembers, AddMember) + + QMetaObjectBuilder(); + explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + virtual ~QMetaObjectBuilder(); + + QByteArray className() const; + void setClassName(const QByteArray& name); + + const QMetaObject *superClass() const; + void setSuperClass(const QMetaObject *meta); + + int methodCount() const; + int constructorCount() const; + int propertyCount() const; + int enumeratorCount() const; + int classInfoCount() const; + int relatedMetaObjectCount() const; + + QMetaMethodBuilder addMethod(const QByteArray& signature); + QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType); + QMetaMethodBuilder addMethod(const QMetaMethod& prototype); + + QMetaMethodBuilder addSlot(const QByteArray& signature); + QMetaMethodBuilder addSignal(const QByteArray& signature); + + QMetaMethodBuilder addConstructor(const QByteArray& signature); + QMetaMethodBuilder addConstructor(const QMetaMethod& prototype); + + QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1); + QMetaPropertyBuilder addProperty(const QMetaProperty& prototype); + + QMetaEnumBuilder addEnumerator(const QByteArray& name); + QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype); + + int addClassInfo(const QByteArray& name, const QByteArray& value); + + int addRelatedMetaObject(const QMetaObject *meta); + + void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + + QMetaMethodBuilder method(int index) const; + QMetaMethodBuilder constructor(int index) const; + QMetaPropertyBuilder property(int index) const; + QMetaEnumBuilder enumerator(int index) const; + const QMetaObject *relatedMetaObject(int index) const; + + QByteArray classInfoName(int index) const; + QByteArray classInfoValue(int index) const; + + void removeMethod(int index); + void removeConstructor(int index); + void removeProperty(int index); + void removeEnumerator(int index); + void removeClassInfo(int index); + void removeRelatedMetaObject(int index); + + int indexOfMethod(const QByteArray& signature); + int indexOfSignal(const QByteArray& signature); + int indexOfSlot(const QByteArray& signature); + int indexOfConstructor(const QByteArray& signature); + int indexOfProperty(const QByteArray& name); + int indexOfEnumerator(const QByteArray& name); + int indexOfClassInfo(const QByteArray& name); + + typedef int (*StaticMetacallFunction)(QMetaObject::Call, int, void **); + + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const; + void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); + + QMetaObject *toMetaObject() const; + +#ifndef QT_NO_DATASTREAM + void serialize(QDataStream& stream) const; + void deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references); +#endif + +private: + Q_DISABLE_COPY(QMetaObjectBuilder); + + QMetaObjectBuilderPrivate *d; + + friend class QMetaMethodBuilder; + friend class QMetaPropertyBuilder; + friend class QMetaEnumBuilder; +}; + +class QMetaMethodBuilder +{ +public: + QMetaMethodBuilder() : _mobj(0), _index(0) {} + + int index() const; + + QMetaMethod::MethodType methodType() const; + QByteArray signature() const; + + QByteArray returnType() const; + void setReturnType(const QByteArray& value); + + QList<QByteArray> parameterNames() const; + void setParameterNames(const QList<QByteArray>& value); + + QByteArray tag() const; + void setTag(const QByteArray& value); + + QMetaMethod::Access access() const; + void setAccess(QMetaMethod::Access value); + + int attributes() const; + void setAttributes(int value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + friend class QMetaPropertyBuilder; + + QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaMethodBuilderPrivate *d_func() const; +}; + +class QMetaPropertyBuilder +{ +public: + QMetaPropertyBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + QByteArray type() const; + + bool hasNotifySignal() const; + QMetaMethodBuilder notifySignal() const; + void setNotifySignal(const QMetaMethodBuilder& value); + void removeNotifySignal(); + + bool isReadable() const; + bool isWritable() const; + bool isResettable() const; + bool isDesignable() const; + bool isScriptable() const; + bool isStored() const; + bool isEditable() const; + bool isUser() const; + bool hasStdCppSet() const; + bool isEnumOrFlag() const; + + void setReadable(bool value); + void setWritable(bool value); + void setResettable(bool value); + void setDesignable(bool value); + void setScriptable(bool value); + void setStored(bool value); + void setEditable(bool value); + void setUser(bool value); + void setStdCppSet(bool value); + void setEnumOrFlag(bool value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaPropertyBuilderPrivate *d_func() const; +}; + +class QMetaEnumBuilder +{ +public: + QMetaEnumBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + + bool isFlag() const; + void setIsFlag(bool value); + + int keyCount() const; + QByteArray key(int index) const; + int value(int index) const; + + int addKey(const QByteArray& name, int value); + void removeKey(int index); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaEnumBuilderPrivate *d_func() const; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers) + +#endif diff --git a/tests/auto/dynamicobject/tst_qobject.cpp b/tests/auto/dynamicobject/tst_qobject.cpp new file mode 100644 index 0000000..18805f7 --- /dev/null +++ b/tests/auto/dynamicobject/tst_qobject.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +****************************************************************************/ + +#define QT3_SUPPORT +#include <QtTest/QtTest> + + +#include <qcoreapplication.h> + +#include <qmetaobject.h> + +#include "qobject.h" +#include "private/qobject_p.h" +#include "qmetaobjectbuilder.h" +#include "qdynamicmetaobject.h" + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QObject : public QObject +{ + Q_OBJECT + +public: + tst_QObject(); + virtual ~tst_QObject(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void addSignal(); + void addSlot(); + void addProperty(); + void dynamicProperty(); +}; + +//=========================================================================== + +class MyDynamicMetaObject : public QDynamicMetaObject +{ +public: + MyDynamicMetaObject(const QMetaObject *base); + + int createProperty(const QObject *object, const char *, const char *); + + virtual void callSlot(QObject *object, int id, const QList<QVariant> &args); + + virtual void writeProperty(QObject *, int id, const QVariant &value) { + props[property(id).name()] = value; + } + + virtual QVariant readProperty(QObject *, int id) const { + return props[property(id).name()]; + } + + QString calledSlot; + QString string; + +private: + QMap<QString,QVariant> props; +}; + +MyDynamicMetaObject::MyDynamicMetaObject(const QMetaObject *_base) + : QDynamicMetaObject(_base) +{ +} + +void MyDynamicMetaObject::callSlot(QObject *object, int id, const QList<QVariant> &args) +{ + calledSlot = method(id).signature(); + qDebug() << "Handled slot" << id << calledSlot << args; + if (calledSlot == "string(QString)") { + string = args[0].toString(); + } +} + +int MyDynamicMetaObject::createProperty(const QObject *, const char *name, const char *type) +{ + qDebug() << "createProperty" << name; + if (name == QString("dynamicProp")) { + addProperty(name, type); + int id = indexOfProperty(name); + return id; + } + + return -1; +} + +//=========================================================================== + +class MyDynamicObject : public QObject +{ + Q_OBJECT +public: + MyDynamicObject(); + + void addSignal(const char *sigName) { + dynamicMeta->addSignal(sigName); + } + + void addSignal(const char *sigName, const QList<QByteArray> ¶meterNames) { + dynamicMeta->addSignal(sigName, parameterNames); + } + + void emitSignal(const char *sigName) { + int idx = dynamicMeta->indexOfSignal(sigName); + if (idx >= 0) + dynamicMeta->activate(this, idx, 0); + } + + void emitSignal(const char *sigName, QGenericArgument val0 + , QGenericArgument val1=QGenericArgument(0) + , QGenericArgument val2=QGenericArgument(0) + , QGenericArgument val3=QGenericArgument(0) + , QGenericArgument val4=QGenericArgument(0) + , QGenericArgument val5=QGenericArgument(0) + , QGenericArgument val6=QGenericArgument(0) + , QGenericArgument val7=QGenericArgument(0)) + { + int idx = dynamicMeta->indexOfSignal(sigName); + if (idx >= 0) { + QGenericReturnArgument rv; + dynamicMeta->method(idx).invoke(this, Qt::DirectConnection, rv, + val0, val1, val2, val3, val4, val5, val6, val7); + } + } + + void addSlot(const char *slotName) { + dynamicMeta->addSlot(slotName); + } + + void addSlot(const char *slotName, const QList<QByteArray> ¶meterNames) { + dynamicMeta->addSlot(slotName, parameterNames); + } + + void addProperty(const char *name, const char *type, const char *notifier) { + dynamicMeta->addProperty(name, type, notifier); + } + + QString calledSlot() const { return dynamicMeta->calledSlot; } + + void emitNormalSignal() { emit normalSignal(); } + + MyDynamicMetaObject *dynamicMeta; + +public slots: + void normalSlot() {} + +signals: + void normalSignal(); + +}; + +MyDynamicObject::MyDynamicObject() + : QObject() +{ + dynamicMeta = new MyDynamicMetaObject(&staticMetaObject); + setDynamicMetaObject(dynamicMeta); +} + +//=========================================================================== + +class TestObject : public QObject +{ + Q_OBJECT +public: + TestObject() : slot1Called(false), slot2Called(false) {} + + void emitSignal() { emit triggered(); } + void setText(const QString &str) { emit textChanged(str); } + + bool slot1Called; + bool slot2Called; + QString string; + +public slots: + void slot1() { + slot1Called = true; + qDebug() << "Called slot1()"; + } + + void slot2() { + slot2Called = true; + qDebug() << "Called slot2()"; + } + + void slotString(QString str) { + string = str; + qDebug() << "Called slotString()" << str; + } + +signals: + void triggered(); + void textChanged(QString); +}; + + +tst_QObject::tst_QObject() +{ + +} + +tst_QObject::~tst_QObject() +{ + +} + +void tst_QObject::initTestCase() +{ +} + +void tst_QObject::cleanupTestCase() +{ +} + +void tst_QObject::init() +{ +} + +void tst_QObject::cleanup() +{ +} + +void tst_QObject::addSignal() +{ + MyDynamicObject myObj; + myObj.addSignal("testSignal()"); + + TestObject testObj; + + connect(&myObj, SIGNAL(testSignal()), &testObj, SLOT(slot1())); + connect(&myObj, SIGNAL(normalSignal()), &testObj, SLOT(slot2())); + + myObj.emitSignal("testSignal()"); + + QVERIFY(testObj.slot1Called); + QVERIFY(!testObj.slot2Called); + + testObj.slot1Called = false; + + myObj.emitNormalSignal(); + + QVERIFY(!testObj.slot1Called); + QVERIFY(testObj.slot2Called); + + // With parameter + myObj.addSignal("stringSignal(QString)"); + connect(&myObj, SIGNAL(stringSignal(QString)), &testObj, SLOT(slotString(QString))); + + QString param("Hello"); + myObj.emitSignal("stringSignal(QString)", Q_ARG(QString, param)); + + QCOMPARE(testObj.string, QString("Hello")); +} + +void tst_QObject::addSlot() +{ + MyDynamicObject myObj; + myObj.addSlot("testSlot1()"); + myObj.addSignal("testSignal()"); + myObj.addSlot("testSlot()"); + + TestObject testObj; + + connect(&testObj, SIGNAL(triggered()), &myObj, SLOT(testSlot())); + connect(&testObj, SIGNAL(triggered()), &myObj, SIGNAL(testSignal())); // signal chaining + connect(&myObj, SIGNAL(testSignal()), &testObj, SLOT(slot1())); + + testObj.emitSignal(); + + QCOMPARE(myObj.calledSlot(), QString("testSlot()")); + QVERIFY(testObj.slot1Called); + + // Verify parameter type and name + myObj.addSlot("string(QString)", QList<QByteArray>() << "name"); + int idx = myObj.metaObject()->indexOfSlot("string(QString)"); + QVERIFY(idx > 0); + QMetaMethod method = myObj.metaObject()->method(idx); + QVERIFY(method.parameterTypes()[0] == "QString"); + QVERIFY(method.parameterNames()[0] == "name"); + + connect(&testObj, SIGNAL(textChanged(QString)), &myObj, SLOT(string(QString))); + testObj.setText("Hello"); + QCOMPARE(myObj.dynamicMeta->string, QString("Hello")); +} + +void tst_QObject::addProperty() +{ + MyDynamicObject myObj; + myObj.addSignal("propChanged()"); + myObj.addProperty("myProp", QVariant::typeToName(QVariant::String), "propChanged()"); + + myObj.setProperty("myProp", QString("hello")); + qDebug() << "property value" << myObj.property("myProp").toString(); + QCOMPARE(myObj.property("myProp").toString(), QString("hello")); + + TestObject testObj; + connect(&myObj, SIGNAL(propChanged()), &testObj, SLOT(slot1())); + myObj.setProperty("myProp", QString("there")); + + QCOMPARE(myObj.property("myProp").toString(), QString("there")); + QVERIFY(testObj.slot1Called); +} + +void tst_QObject::dynamicProperty() +{ + MyDynamicObject myObj; + + myObj.setProperty("dynamicProp", QString("hello")); + qDebug() << "property value" << myObj.property("dynamicProp").toString(); + QCOMPARE(myObj.property("dynamicProp").toString(), QString("hello")); +} + +QTEST_MAIN(tst_QObject) +#include "tst_qobject.moc" diff --git a/tests/auto/math3d/math3d.pro b/tests/auto/math3d/math3d.pro new file mode 100644 index 0000000..d6189ef --- /dev/null +++ b/tests/auto/math3d/math3d.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = qmatrixnxn qquaternion qvectornd diff --git a/tests/auto/math3d/qmatrixnxn/qmatrixnxn.pro b/tests/auto/math3d/qmatrixnxn/qmatrixnxn.pro new file mode 100644 index 0000000..40c6cc0 --- /dev/null +++ b/tests/auto/math3d/qmatrixnxn/qmatrixnxn.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +VPATH += ../shared +INCLUDEPATH += ../shared +HEADERS += math3dincludes.h +SOURCES += tst_qmatrixnxn.cpp diff --git a/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp new file mode 100644 index 0000000..bb510fc --- /dev/null +++ b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp @@ -0,0 +1,3185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include "math3dincludes.h" + +class tst_QMatrix : public QObject +{ + Q_OBJECT +public: + tst_QMatrix() {} + ~tst_QMatrix() {} + +private slots: + void create2x2(); + void create3x3(); + void create4x4(); + void create4x3(); + + void isIdentity2x2(); + void isIdentity3x3(); + void isIdentity4x4(); + void isIdentity4x3(); + + void compare2x2(); + void compare3x3(); + void compare4x4(); + void compare4x3(); + + void transposed2x2(); + void transposed3x3(); + void transposed4x4(); + void transposed4x3(); + + void add2x2_data(); + void add2x2(); + void add3x3_data(); + void add3x3(); + void add4x4_data(); + void add4x4(); + void add4x3_data(); + void add4x3(); + + void subtract2x2_data(); + void subtract2x2(); + void subtract3x3_data(); + void subtract3x3(); + void subtract4x4_data(); + void subtract4x4(); + void subtract4x3_data(); + void subtract4x3(); + + void multiply2x2_data(); + void multiply2x2(); + void multiply3x3_data(); + void multiply3x3(); + void multiply4x4_data(); + void multiply4x4(); + void multiply4x3_data(); + void multiply4x3(); + + void multiplyFactor2x2_data(); + void multiplyFactor2x2(); + void multiplyFactor3x3_data(); + void multiplyFactor3x3(); + void multiplyFactor4x4_data(); + void multiplyFactor4x4(); + void multiplyFactor4x3_data(); + void multiplyFactor4x3(); + + void divideFactor2x2_data(); + void divideFactor2x2(); + void divideFactor3x3_data(); + void divideFactor3x3(); + void divideFactor4x4_data(); + void divideFactor4x4(); + void divideFactor4x3_data(); + void divideFactor4x3(); + + void negate2x2_data(); + void negate2x2(); + void negate3x3_data(); + void negate3x3(); + void negate4x4_data(); + void negate4x4(); + void negate4x3_data(); + void negate4x3(); + + void inverted4x4_data(); + void inverted4x4(); + + void orthonormalInverse4x4(); + + void scale4x4_data(); + void scale4x4(); + + void translate4x4_data(); + void translate4x4(); + + void rotate4x4_data(); + void rotate4x4(); + + void normalMatrix_data(); + void normalMatrix(); + + void optimizedTransforms(); + + void ortho(); + void frustum(); + void perspective(); + void flipCoordinates(); + + void convertGeneric(); + + void extractAxisRotation_data(); + void extractAxisRotation(); + + void extractTranslation_data(); + void extractTranslation(); + + void inferSpecialType_data(); + void inferSpecialType(); + + void columnsAndRows(); + + void convertQMatrix(); + void convertQTransform(); + + void fill(); + +private: + static void setMatrix(QMatrix2x2& m, const qreal *values); + static void setMatrixFixed(QMatrix2x2& m, const qreal *values); + static bool isSame(const QMatrix2x2& m, const qreal *values); + static bool isIdentity(const QMatrix2x2& m); + + static void setMatrix(QMatrix3x3& m, const qreal *values); + static void setMatrixFixed(QMatrix3x3& m, const qreal *values); + static bool isSame(const QMatrix3x3& m, const qreal *values); + static bool isIdentity(const QMatrix3x3& m); + + static void setMatrix(QMatrix4x4& m, const qreal *values); + static void setMatrixFixed(QMatrix4x4& m, const qreal *values); + static bool isSame(const QMatrix4x4& m, const qreal *values); + static bool isIdentity(const QMatrix4x4& m); + + static void setMatrix(QMatrix4x3& m, const qreal *values); + static void setMatrixFixed(QMatrix4x3& m, const qreal *values); + static bool isSame(const QMatrix4x3& m, const qreal *values); + static bool isIdentity(const QMatrix4x3& m); +}; + +static const qreal nullValues2[] = + {0.0f, 0.0f, + 0.0f, 0.0f}; + +static qreal const identityValues2[16] = + {1.0f, 0.0f, + 0.0f, 1.0f}; + +static const qreal doubleIdentity2[] = + {2.0f, 0.0f, + 0.0f, 2.0f}; + +static qreal const uniqueValues2[16] = + {1.0f, 2.0f, + 5.0f, 6.0f}; + +static qreal const transposedValues2[16] = + {1.0f, 5.0f, + 2.0f, 6.0f}; + +static const qreal nullValues3[] = + {0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues3[16] = + {1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f}; + +static const qreal doubleIdentity3[] = + {2.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 2.0f}; + +static qreal const uniqueValues3[16] = + {1.0f, 2.0f, 3.0f, + 5.0f, 6.0f, 7.0f, + 9.0f, 10.0f, 11.0f}; + +static qreal const transposedValues3[16] = + {1.0f, 5.0f, 9.0f, + 2.0f, 6.0f, 10.0f, + 3.0f, 7.0f, 11.0f}; + +static const qreal nullValues4[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues4[16] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + +static const qreal doubleIdentity4[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 2.0f}; + +static qreal const uniqueValues4[16] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f}; + +static qreal const transposedValues4[16] = + {1.0f, 5.0f, 9.0f, 13.0f, + 2.0f, 6.0f, 10.0f, 14.0f, + 3.0f, 7.0f, 11.0f, 15.0f, + 4.0f, 8.0f, 12.0f, 16.0f}; + +static const qreal nullValues4x3[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues4x3[12] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f}; + +static qreal const doubleIdentity4x3[12] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f}; + +static qreal const uniqueValues4x3[12] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f}; + +static qreal const transposedValues3x4[12] = + {1.0f, 5.0f, 9.0f, + 2.0f, 6.0f, 10.0f, + 3.0f, 7.0f, 11.0f, + 4.0f, 8.0f, 12.0f}; + +// Set a matrix to a specified array of values, which are assumed +// to be in row-major order. This sets the values using floating-point. +void tst_QMatrix::setMatrix(QMatrix2x2& m, const qreal *values) +{ + for (int row = 0; row < 2; ++row) + for (int col = 0; col < 2; ++col) + m(row, col) = values[row * 2 + col]; +} +void tst_QMatrix::setMatrix(QMatrix3x3& m, const qreal *values) +{ + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 3; ++col) + m(row, col) = values[row * 3 + col]; +} +void tst_QMatrix::setMatrix(QMatrix4x4& m, const qreal *values) +{ + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + m(row, col) = values[row * 4 + col]; +} +void tst_QMatrix::setMatrix(QMatrix4x3& m, const qreal *values) +{ + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 4; ++col) + m(row, col) = values[row * 4 + col]; +} + +// Set a matrix to a specified array of values, which are assumed +// to be in row-major order. This sets the values using fixed-point. +void tst_QMatrix::setMatrixFixed(QMatrix2x2& m, const qreal *values) +{ + float *data = m.data(); + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + data[row + col * 2] = values[row * 2 + col]; + } + } +} +void tst_QMatrix::setMatrixFixed(QMatrix3x3& m, const qreal *values) +{ + float *data = m.data(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + data[row + col * 3] = values[row * 3 + col]; + } + } +} +void tst_QMatrix::setMatrixFixed(QMatrix4x4& m, const qreal *values) +{ + float *data = m.data(); + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + data[row + col * 4] = values[row * 4 + col]; + } + } +} +void tst_QMatrix::setMatrixFixed(QMatrix4x3& m, const qreal *values) +{ + float *data = m.data(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 4; ++col) { + data[row + col * 3] = values[row * 4 + col]; + } + } +} + +// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion +// to fixed-point and back again. So create "fuzzier" compares. +static bool fuzzyCompare(float x, float y, qreal epsilon = 0.001) +{ + float diff = x - y; + if (diff < 0.0f) + diff = -diff; + return (diff < epsilon); +} + +static bool fuzzyCompare(const QVector3D &v1, const QVector3D &v2, qreal epsilon = 0.001) +{ + if (!fuzzyCompare(v1.x(), v2.x(), epsilon)) + return false; + if (!fuzzyCompare(v1.y(), v2.y(), epsilon)) + return false; + if (!fuzzyCompare(v1.z(), v2.z(), epsilon)) + return false; + return true; +} + +static bool matrixFuzzyCompare(const QMatrix4x4 &m1, const QMatrix4x4 &m2) +{ + bool ret = true; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + ret = ret && fuzzyCompare(m1(i, j), m2(i, j)); + } + } + + return ret; +} + +// Determine if a matrix is the same as a specified array of values. +// The values are assumed to be specified in row-major order. +bool tst_QMatrix::isSame(const QMatrix2x2& m, const qreal *values) +{ + const float *mv = m.constData(); + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + // Check the values using the operator() function. + if (!fuzzyCompare((float)(m(row, col)), (float)(values[row * 2 + col]))) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 2 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare((float)(mv[col * 2 + row]), (float)(values[row * 2 + col]))) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 2 + row] << "expected =" << values[row * 2 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrix::isSame(const QMatrix3x3& m, const qreal *values) +{ + const float *mv = m.constData(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare((float)(m(row, col)), (float)(values[row * 3 + col]))) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 3 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare((float)(mv[col * 3 + row]), (float)(values[row * 3 + col]))) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 3 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrix::isSame(const QMatrix4x4& m, const qreal *values) +{ + const float *mv = m.constData(); + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare((float)(m(row, col)), (float)(values[row * 4 + col]))) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare((float)(mv[col * 4 + row]), (float)(values[row * 4 + col]))) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 4 + row] << "expected =" << values[row * 4 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrix::isSame(const QMatrix4x3& m, const qreal *values) +{ + const float *mv = m.constData(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 4; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare((float)(m(row, col)), (float)(values[row * 4 + col]))) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare((float)(mv[col * 3 + row]), (float)(values[row * 4 + col]))) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 4 + col]; + return false; + } + } + } + return true; +} + +// Determine if a matrix is the identity. +bool tst_QMatrix::isIdentity(const QMatrix2x2& m) +{ + return isSame(m, identityValues2); +} +bool tst_QMatrix::isIdentity(const QMatrix3x3& m) +{ + return isSame(m, identityValues3); +} +bool tst_QMatrix::isIdentity(const QMatrix4x4& m) +{ + return isSame(m, identityValues4); +} +bool tst_QMatrix::isIdentity(const QMatrix4x3& m) +{ + return isSame(m, identityValues4x3); +} + +// Test the creation of QMatrix2x2 objects in various ways: +// construct, copy, and modify. +void tst_QMatrix::create2x2() +{ + QMatrix2x2 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix2x2 m2; + setMatrix(m2, uniqueValues2); + QVERIFY(isSame(m2, uniqueValues2)); + QVERIFY(!m2.isIdentity()); + + QMatrix2x2 m3; + setMatrixFixed(m3, uniqueValues2); + QVERIFY(isSame(m3, uniqueValues2)); + + QMatrix2x2 m4(m3); + QVERIFY(isSame(m4, uniqueValues2)); + + QMatrix2x2 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues2)); + + m5.setIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix2x2 m6(uniqueValues2); + QVERIFY(isSame(m6, uniqueValues2)); + qreal vals[4]; + m6.toValueArray(vals); + for (int index = 0; index < 4; ++index) + QCOMPARE((float)(vals[index]), (float)(uniqueValues2[index])); +} + +// Test the creation of QMatrix3x3 objects in various ways: +// construct, copy, and modify. +void tst_QMatrix::create3x3() +{ + QMatrix3x3 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix3x3 m2; + setMatrix(m2, uniqueValues3); + QVERIFY(isSame(m2, uniqueValues3)); + QVERIFY(!m2.isIdentity()); + + QMatrix3x3 m3; + setMatrixFixed(m3, uniqueValues3); + QVERIFY(isSame(m3, uniqueValues3)); + + QMatrix3x3 m4(m3); + QVERIFY(isSame(m4, uniqueValues3)); + + QMatrix3x3 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues3)); + + m5.setIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix3x3 m6(uniqueValues3); + QVERIFY(isSame(m6, uniqueValues3)); + qreal vals[9]; + m6.toValueArray(vals); + for (int index = 0; index < 9; ++index) + QCOMPARE((float)(vals[index]), (float)(uniqueValues3[index])); +} + +// Test the creation of QMatrix4x4 objects in various ways: +// construct, copy, and modify. +void tst_QMatrix::create4x4() +{ + QMatrix4x4 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix4x4 m2; + setMatrix(m2, uniqueValues4); + QVERIFY(isSame(m2, uniqueValues4)); + QVERIFY(!m2.isIdentity()); + + QMatrix4x4 m3; + setMatrixFixed(m3, uniqueValues4); + QVERIFY(isSame(m3, uniqueValues4)); + + QMatrix4x4 m4(m3); + QVERIFY(isSame(m4, uniqueValues4)); + + QMatrix4x4 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues4)); + + m5.setIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix4x4 m6(uniqueValues4); + QVERIFY(isSame(m6, uniqueValues4)); + qreal vals[16]; + m6.toValueArray(vals); + for (int index = 0; index < 16; ++index) + QCOMPARE((float)(vals[index]), (float)(uniqueValues4[index])); + + QMatrix4x4 m8 + (uniqueValues4[0], uniqueValues4[1], uniqueValues4[2], uniqueValues4[3], + uniqueValues4[4], uniqueValues4[5], uniqueValues4[6], uniqueValues4[7], + uniqueValues4[8], uniqueValues4[9], uniqueValues4[10], uniqueValues4[11], + uniqueValues4[12], uniqueValues4[13], uniqueValues4[14], uniqueValues4[15]); + QVERIFY(isSame(m8, uniqueValues4)); +} + +// Test the creation of QMatrix4x3 objects in various ways: +// construct, copy, and modify. +void tst_QMatrix::create4x3() +{ + QMatrix4x3 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix4x3 m2; + setMatrix(m2, uniqueValues4x3); + QVERIFY(isSame(m2, uniqueValues4x3)); + QVERIFY(!m2.isIdentity()); + + QMatrix4x3 m3; + setMatrixFixed(m3, uniqueValues4x3); + QVERIFY(isSame(m3, uniqueValues4x3)); + + QMatrix4x3 m4(m3); + QVERIFY(isSame(m4, uniqueValues4x3)); + + QMatrix4x3 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues4x3)); + + m5.setIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix4x3 m6(uniqueValues4x3); + QVERIFY(isSame(m6, uniqueValues4x3)); + qreal vals[12]; + m6.toValueArray(vals); + for (int index = 0; index < 12; ++index) + QCOMPARE((float)(vals[index]), (float)(uniqueValues4x3[index])); +} + +// Test isIdentity() for 2x2 matrices. +void tst_QMatrix::isIdentity2x2() +{ + for (int i = 0; i < 2 * 2; ++i) { + QMatrix2x2 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test isIdentity() for 3x3 matrices. +void tst_QMatrix::isIdentity3x3() +{ + for (int i = 0; i < 3 * 3; ++i) { + QMatrix3x3 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test isIdentity() for 4x4 matrices. +void tst_QMatrix::isIdentity4x4() +{ + for (int i = 0; i < 4 * 4; ++i) { + QMatrix4x4 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } + + // Force the "Identity" flag bit to be lost and check again. + QMatrix4x4 m2; + m2.data()[0] = 1.0f; + QVERIFY(m2.isIdentity()); +} + +// Test isIdentity() for 4x3 matrices. +void tst_QMatrix::isIdentity4x3() +{ + for (int i = 0; i < 4 * 3; ++i) { + QMatrix4x3 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test 2x2 matrix comparisons. +void tst_QMatrix::compare2x2() +{ + QMatrix2x2 m1(uniqueValues2); + QMatrix2x2 m2(uniqueValues2); + QMatrix2x2 m3(transposedValues2); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 3x3 matrix comparisons. +void tst_QMatrix::compare3x3() +{ + QMatrix3x3 m1(uniqueValues3); + QMatrix3x3 m2(uniqueValues3); + QMatrix3x3 m3(transposedValues3); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 4x4 matrix comparisons. +void tst_QMatrix::compare4x4() +{ + QMatrix4x4 m1(uniqueValues4); + QMatrix4x4 m2(uniqueValues4); + QMatrix4x4 m3(transposedValues4); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 4x3 matrix comparisons. +void tst_QMatrix::compare4x3() +{ + QMatrix4x3 m1(uniqueValues4x3); + QMatrix4x3 m2(uniqueValues4x3); + QMatrix4x3 m3(transposedValues3x4); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test matrix 2x2 transpose operations. +void tst_QMatrix::transposed2x2() +{ + // Transposing the identity should result in the identity. + QMatrix2x2 m1; + QMatrix2x2 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix2x2 m3(uniqueValues2); + QMatrix2x2 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues2)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues2)); +} + +// Test matrix 3x3 transpose operations. +void tst_QMatrix::transposed3x3() +{ + // Transposing the identity should result in the identity. + QMatrix3x3 m1; + QMatrix3x3 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix3x3 m3(uniqueValues3); + QMatrix3x3 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues3)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues3)); +} + +// Test matrix 4x4 transpose operations. +void tst_QMatrix::transposed4x4() +{ + // Transposing the identity should result in the identity. + QMatrix4x4 m1; + QMatrix4x4 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues4)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues4)); +} + +// Test matrix 4x3 transpose operations. +void tst_QMatrix::transposed4x3() +{ + QMatrix4x3 m3(uniqueValues4x3); + QMatrix3x4 m4 = m3.transposed(); + qreal values[12]; + m4.toValueArray(values); + for (int index = 0; index < 12; ++index) + QCOMPARE(values[index], transposedValues3x4[index]); +} + +// Test matrix addition for 2x2 matrices. +void tst_QMatrix::add2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("identity/null") + << (void *)identityValues2 << (void *)nullValues2 << (void *)identityValues2; + + QTest::newRow("identity/identity") + << (void *)identityValues2 << (void *)identityValues2 << (void *)doubleIdentity2; + + static qreal const sumValues[16] = + {2.0f, 7.0f, + 7.0f, 12.0f}; + QTest::newRow("unique") + << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)sumValues; +} +void tst_QMatrix::add2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix2x2 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 3x3 matrices. +void tst_QMatrix::add3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("identity/null") + << (void *)identityValues3 << (void *)nullValues3 << (void *)identityValues3; + + QTest::newRow("identity/identity") + << (void *)identityValues3 << (void *)identityValues3 << (void *)doubleIdentity3; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, + 7.0f, 12.0f, 17.0f, + 12.0f, 17.0f, 22.0f}; + QTest::newRow("unique") + << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)sumValues; +} +void tst_QMatrix::add3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix3x3 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 4x4 matrices. +void tst_QMatrix::add4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("identity/null") + << (void *)identityValues4 << (void *)nullValues4 << (void *)identityValues4; + + QTest::newRow("identity/identity") + << (void *)identityValues4 << (void *)identityValues4 << (void *)doubleIdentity4; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, 17.0f, + 7.0f, 12.0f, 17.0f, 22.0f, + 12.0f, 17.0f, 22.0f, 27.0f, + 17.0f, 22.0f, 27.0f, 32.0f}; + QTest::newRow("unique") + << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)sumValues; +} +void tst_QMatrix::add4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x4 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 4x3 matrices. +void tst_QMatrix::add4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues4x3; + + QTest::newRow("identity/null") + << (void *)identityValues4x3 << (void *)nullValues4x3 << (void *)identityValues4x3; + + QTest::newRow("identity/identity") + << (void *)identityValues4x3 << (void *)identityValues4x3 << (void *)doubleIdentity4x3; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, 6.0f, + 11.0f, 16.0f, 10.0f, 15.0f, + 20.0f, 14.0f, 19.0f, 24.0f}; + QTest::newRow("unique") + << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)sumValues; +} +void tst_QMatrix::add4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix4x3 m2((const qreal *)m2Values); + + QMatrix4x3 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x3 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix subtraction for 2x2 matrices. +void tst_QMatrix::subtract2x2_data() +{ + // Use the same test cases as the add test. + add2x2_data(); +} +void tst_QMatrix::subtract2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + QMatrix2x2 m3((const qreal *)m3Values); + + QMatrix2x2 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix2x2 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix2x2 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix2x2 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 3x3 matrices. +void tst_QMatrix::subtract3x3_data() +{ + // Use the same test cases as the add test. + add3x3_data(); +} +void tst_QMatrix::subtract3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + QMatrix3x3 m3((const qreal *)m3Values); + + QMatrix3x3 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix3x3 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix3x3 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix3x3 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 4x4 matrices. +void tst_QMatrix::subtract4x4_data() +{ + // Use the same test cases as the add test. + add4x4_data(); +} +void tst_QMatrix::subtract4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + QMatrix4x4 m3((const qreal *)m3Values); + + QMatrix4x4 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x4 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix4x4 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix4x4 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 4x3 matrices. +void tst_QMatrix::subtract4x3_data() +{ + // Use the same test cases as the add test. + add4x3_data(); +} +void tst_QMatrix::subtract4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix4x3 m2((const qreal *)m2Values); + QMatrix4x3 m3((const qreal *)m3Values); + + QMatrix4x3 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x3 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix4x3 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix4x3 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix multiplication for 2x2 matrices. +void tst_QMatrix::multiply2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("null/unique") + << (void *)nullValues2 << (void *)uniqueValues2 << (void *)nullValues2; + + QTest::newRow("unique/null") + << (void *)uniqueValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("unique/identity") + << (void *)uniqueValues2 << (void *)identityValues2 << (void *)uniqueValues2; + + QTest::newRow("identity/unique") + << (void *)identityValues2 << (void *)uniqueValues2 << (void *)uniqueValues2; + + static qreal uniqueResult[4]; + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 2; ++j) + sum += uniqueValues2[row * 2 + j] * transposedValues2[j * 2 + col]; + uniqueResult[row * 2 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)uniqueResult; +} +void tst_QMatrix::multiply2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 3x3 matrices. +void tst_QMatrix::multiply3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("null/unique") + << (void *)nullValues3 << (void *)uniqueValues3 << (void *)nullValues3; + + QTest::newRow("unique/null") + << (void *)uniqueValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("unique/identity") + << (void *)uniqueValues3 << (void *)identityValues3 << (void *)uniqueValues3; + + QTest::newRow("identity/unique") + << (void *)identityValues3 << (void *)uniqueValues3 << (void *)uniqueValues3; + + static qreal uniqueResult[9]; + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 3; ++j) + sum += uniqueValues3[row * 3 + j] * transposedValues3[j * 3 + col]; + uniqueResult[row * 3 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)uniqueResult; +} +void tst_QMatrix::multiply3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 4x4 matrices. +void tst_QMatrix::multiply4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("null/unique") + << (void *)nullValues4 << (void *)uniqueValues4 << (void *)nullValues4; + + QTest::newRow("unique/null") + << (void *)uniqueValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("unique/identity") + << (void *)uniqueValues4 << (void *)identityValues4 << (void *)uniqueValues4; + + QTest::newRow("identity/unique") + << (void *)identityValues4 << (void *)uniqueValues4 << (void *)uniqueValues4; + + static qreal uniqueResult[16]; + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 4; ++j) + sum += uniqueValues4[row * 4 + j] * transposedValues4[j * 4 + col]; + uniqueResult[row * 4 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)uniqueResult; +} +void tst_QMatrix::multiply4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m4; + m4 = m1; + m4 *= m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x4 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 4x3 matrices. +void tst_QMatrix::multiply4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; + + QTest::newRow("null/unique") + << (void *)nullValues4x3 << (void *)uniqueValues4x3 << (void *)nullValues3; + + QTest::newRow("unique/null") + << (void *)uniqueValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; + + static qreal uniqueResult[9]; + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 4; ++j) + sum += uniqueValues4x3[row * 4 + j] * transposedValues3x4[j * 3 + col]; + uniqueResult[row * 3 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)uniqueResult; +} +void tst_QMatrix::multiply4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix3x4 m2((const qreal *)m2Values); + + QGenericMatrix<3, 3, qreal, float> m4; + m4 = m1 * m2; + qreal values[9]; + m4.toValueArray(values); + for (int index = 0; index < 9; ++index) + QCOMPARE(values[index], ((const qreal *)m3Values)[index]); +} + +// Test matrix multiplication by a factor for 2x2 matrices. +void tst_QMatrix::multiplyFactor2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (qreal)1.0f << (void *)nullValues2; + + QTest::newRow("double identity") + << (void *)identityValues2 << (qreal)2.0f << (void *)doubleIdentity2; + + static qreal const values[16] = + {1.0f, 2.0f, + 5.0f, 6.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, + 10.0f, 12.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, + -10.0f, -12.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrix::multiplyFactor2x2() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix2x2 m1((const qreal *)m1Values); + + QMatrix2x2 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix2x2 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix2x2 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 3x3 matrices. +void tst_QMatrix::multiplyFactor3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (qreal)1.0f << (void *)nullValues3; + + QTest::newRow("double identity") + << (void *)identityValues3 << (qreal)2.0f << (void *)doubleIdentity3; + + static qreal const values[16] = + {1.0f, 2.0f, 3.0f, + 5.0f, 6.0f, 7.0f, + 9.0f, 10.0f, 11.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, 6.0f, + 10.0f, 12.0f, 14.0f, + 18.0f, 20.0f, 22.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, -6.0f, + -10.0f, -12.0f, -14.0f, + -18.0f, -20.0f, -22.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrix::multiplyFactor3x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix3x3 m1((const qreal *)m1Values); + + QMatrix3x3 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix3x3 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix3x3 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 4x4 matrices. +void tst_QMatrix::multiplyFactor4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (qreal)1.0f << (void *)nullValues4; + + QTest::newRow("double identity") + << (void *)identityValues4 << (qreal)2.0f << (void *)doubleIdentity4; + + static qreal const values[16] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, 6.0f, 8.0f, + 10.0f, 12.0f, 14.0f, 16.0f, + 18.0f, 20.0f, 22.0f, 24.0f, + 26.0f, 28.0f, 30.0f, 32.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, -6.0f, -8.0f, + -10.0f, -12.0f, -14.0f, -16.0f, + -18.0f, -20.0f, -22.0f, -24.0f, + -26.0f, -28.0f, -30.0f, -32.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrix::multiplyFactor4x4() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix4x4 m1((const qreal *)m1Values); + + QMatrix4x4 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix4x4 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x4 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 4x3 matrices. +void tst_QMatrix::multiplyFactor4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (qreal)1.0f << (void *)nullValues4x3; + + QTest::newRow("double identity") + << (void *)identityValues4x3 << (qreal)2.0f << (void *)doubleIdentity4x3; + + static qreal const values[12] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f}; + static qreal const doubleValues[12] = + {2.0f, 4.0f, 6.0f, 8.0f, + 10.0f, 12.0f, 14.0f, 16.0f, + 18.0f, 20.0f, 22.0f, 24.0f}; + static qreal const negDoubleValues[12] = + {-2.0f, -4.0f, -6.0f, -8.0f, + -10.0f, -12.0f, -14.0f, -16.0f, + -18.0f, -20.0f, -22.0f, -24.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4x3; +} +void tst_QMatrix::multiplyFactor4x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix4x3 m1((const qreal *)m1Values); + + QMatrix4x3 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix4x3 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x3 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix division by a factor for 2x2 matrices. +void tst_QMatrix::divideFactor2x2_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor2x2_data(); +} +void tst_QMatrix::divideFactor2x2() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix2x2 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 3x3 matrices. +void tst_QMatrix::divideFactor3x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor3x3_data(); +} +void tst_QMatrix::divideFactor3x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix3x3 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 4x4 matrices. +void tst_QMatrix::divideFactor4x4_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x4_data(); +} +void tst_QMatrix::divideFactor4x4() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix4x4 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 4x3 matrices. +void tst_QMatrix::divideFactor4x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x3_data(); +} +void tst_QMatrix::divideFactor4x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix4x3 m2((const qreal *)m2Values); + + QMatrix4x3 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix4x3 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix negation for 2x2 matrices. +void tst_QMatrix::negate2x2_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor2x2_data(); +} +void tst_QMatrix::negate2x2() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix2x2 m1(values); + + qreal negated[4]; + for (int index = 0; index < 4; ++index) + negated[index] = -values[index]; + + QMatrix2x2 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 3x3 matrices. +void tst_QMatrix::negate3x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor3x3_data(); +} +void tst_QMatrix::negate3x3() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix3x3 m1(values); + + qreal negated[9]; + for (int index = 0; index < 9; ++index) + negated[index] = -values[index]; + + QMatrix3x3 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 4x4 matrices. +void tst_QMatrix::negate4x4_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x4_data(); +} +void tst_QMatrix::negate4x4() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix4x4 m1(values); + + qreal negated[16]; + for (int index = 0; index < 16; ++index) + negated[index] = -values[index]; + + QMatrix4x4 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 4x3 matrices. +void tst_QMatrix::negate4x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x3_data(); +} +void tst_QMatrix::negate4x3() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix4x3 m1(values); + + qreal negated[12]; + for (int index = 0; index < 12; ++index) + negated[index] = -values[index]; + + QMatrix4x3 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Matrix inverted. This is a more straight-forward implementation +// of the algorithm at http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24 +// than the optimized version in the QMatrix4x4 code. Hopefully it is +// easier to verify that this version is the same as the reference. + +struct Matrix3 +{ + qreal v[9]; +}; +struct Matrix4 +{ + qreal v[16]; +}; + +static qreal m3Determinant(const Matrix3& m) +{ + return m.v[0] * (m.v[4] * m.v[8] - m.v[7] * m.v[5]) - + m.v[1] * (m.v[3] * m.v[8] - m.v[6] * m.v[5]) + + m.v[2] * (m.v[3] * m.v[7] - m.v[6] * m.v[4]); +} + +static bool m3Inverse(const Matrix3& min, Matrix3& mout) +{ + qreal det = m3Determinant(min); + if (det == 0.0f) + return false; + mout.v[0] = (min.v[4] * min.v[8] - min.v[5] * min.v[7]) / det; + mout.v[1] = -(min.v[1] * min.v[8] - min.v[2] * min.v[7]) / det; + mout.v[2] = (min.v[1] * min.v[5] - min.v[4] * min.v[2]) / det; + mout.v[3] = -(min.v[3] * min.v[8] - min.v[5] * min.v[6]) / det; + mout.v[4] = (min.v[0] * min.v[8] - min.v[6] * min.v[2]) / det; + mout.v[5] = -(min.v[0] * min.v[5] - min.v[3] * min.v[2]) / det; + mout.v[6] = (min.v[3] * min.v[7] - min.v[6] * min.v[4]) / det; + mout.v[7] = -(min.v[0] * min.v[7] - min.v[6] * min.v[1]) / det; + mout.v[8] = (min.v[0] * min.v[4] - min.v[1] * min.v[3]) / det; + return true; +} + +static void m3Transpose(Matrix3& m) +{ + qSwap(m.v[1], m.v[3]); + qSwap(m.v[2], m.v[6]); + qSwap(m.v[5], m.v[7]); +} + +static void m4Submatrix(const Matrix4& min, Matrix3& mout, int i, int j) +{ + for (int di = 0; di < 3; ++di) { + for (int dj = 0; dj < 3; ++dj) { + int si = di + ((di >= i) ? 1 : 0); + int sj = dj + ((dj >= j) ? 1 : 0); + mout.v[di * 3 + dj] = min.v[si * 4 + sj]; + } + } +} + +static qreal m4Determinant(const Matrix4& m) +{ + qreal det; + qreal result = 0.0f; + qreal i = 1.0f; + Matrix3 msub; + for (int n = 0; n < 4; ++n, i *= -1.0f) { + m4Submatrix(m, msub, 0, n); + det = m3Determinant(msub); + result += m.v[n] * det * i; + } + return result; +} + +static void m4Inverse(const Matrix4& min, Matrix4& mout) +{ + qreal det = m4Determinant(min); + Matrix3 msub; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + qreal sign = 1.0f - ((i + j) % 2) * 2.0f; + m4Submatrix(min, msub, i, j); + mout.v[i + j * 4] = (m3Determinant(msub) * sign) / det; + } + } +} + +// Test matrix inverted for 4x4 matrices. +void tst_QMatrix::inverted4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<bool>("invertible"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)identityValues4 << false; + + QTest::newRow("identity") + << (void *)identityValues4 << (void *)identityValues4 << true; + + QTest::newRow("unique") + << (void *)uniqueValues4 << (void *)identityValues4 << false; + + static Matrix4 const invertible = { + {5.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 6.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 7.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + static Matrix4 inverted; + m4Inverse(invertible, inverted); + + QTest::newRow("invertible") + << (void *)invertible.v << (void *)inverted.v << true; + + static Matrix4 const translate = { + {1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + static Matrix4 const inverseTranslate = { + {1.0f, 0.0f, 0.0f, -2.0f, + 0.0f, 1.0f, 0.0f, -3.0f, + 0.0f, 0.0f, 1.0f, -4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + + QTest::newRow("translate") + << (void *)translate.v << (void *)inverseTranslate.v << true; +} +void tst_QMatrix::inverted4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(bool, invertible); + + QMatrix4x4 m1((const qreal *)m1Values); + + if (invertible) + QVERIFY(m1.determinant() != 0.0f); + else + QVERIFY(m1.determinant() == 0.0f); + + Matrix4 m1alt; + memcpy(m1alt.v, (const qreal *)m1Values, sizeof(m1alt.v)); + + QCOMPARE((float)(m1.determinant()), (float)(m4Determinant(m1alt))); + + QMatrix4x4 m2; + bool inv; + m2 = m1.inverted(&inv); + QVERIFY(isSame(m2, (const qreal *)m2Values)); + + if (invertible) { + QVERIFY(inv); + + Matrix4 m2alt; + m4Inverse(m1alt, m2alt); + QVERIFY(isSame(m2, m2alt.v)); + + QMatrix4x4 m3; + m3 = m1 * m2; + QVERIFY(isIdentity(m3)); + + QMatrix4x4 m4; + m4 = m2 * m1; + QVERIFY(isIdentity(m4)); + } else { + QVERIFY(!inv); + } + + // Test again, after inferring the special matrix type. + m1.inferSpecialType(); + m2 = m1.inverted(&inv); + QVERIFY(isSame(m2, (const qreal *)m2Values)); + QCOMPARE(inv, invertible); +} + +void tst_QMatrix::orthonormalInverse4x4() +{ + QMatrix4x4 m1; + QVERIFY(matrixFuzzyCompare(m1.inverted(), m1)); + + QMatrix4x4 m2; + m2.rotate(45.0, 1.0, 0.0, 0.0); + m2.translate(10.0, 0.0, 0.0); + + // Use inferSpecialType() to drop the internal flags that + // mark the matrix as orthonormal. This will force inverted() + // to compute m3.inverted() the long way. We can then compare + // the result to what the faster algorithm produces on m2. + QMatrix4x4 m3 = m2; + m3.inferSpecialType(); + bool invertible; + QVERIFY(matrixFuzzyCompare(m2.inverted(&invertible), m3.inverted())); + QVERIFY(invertible); + + QMatrix4x4 m4; + m4.rotate(45.0, 0.0, 1.0, 0.0); + QMatrix4x4 m5 = m4; + m5.inferSpecialType(); + QVERIFY(matrixFuzzyCompare(m4.inverted(), m5.inverted())); + + QMatrix4x4 m6; + m1.rotate(88, 0.0, 0.0, 1.0); + m1.translate(-20.0, 20.0, 15.0); + m1.rotate(25, 1.0, 0.0, 0.0); + QMatrix4x4 m7 = m6; + m7.inferSpecialType(); + QVERIFY(matrixFuzzyCompare(m6.inverted(), m7.inverted())); +} + +// Test the generation and use of 4x4 scale matrices. +void tst_QMatrix::scale4x4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + static const qreal nullScale[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)nullScale; + + QTest::newRow("identity") + << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityValues4; + + static const qreal doubleScale[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("double") + << (qreal)2.0f << (qreal)2.0f << (qreal)2.0f << (void *)doubleScale; + + static const qreal complexScale[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 11.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -6.5f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex") + << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexScale; +} +void tst_QMatrix::scale4x4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 result((const qreal *)resultValues); + + QMatrix4x4 m1; + m1.scale(QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.scale(x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QCOMPARE(v2.x(), (qreal)(2.0f * x)); + QCOMPARE(v2.y(), (qreal)(3.0f * y)); + QCOMPARE(v2.z(), (qreal)(-4.0f * z)); + + v2 = v1 * m1; + QCOMPARE(v2.x(), (qreal)(2.0f * x)); + QCOMPARE(v2.y(), (qreal)(3.0f * y)); + QCOMPARE(v2.z(), (qreal)(-4.0f * z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v4 = m1 * v3; + QCOMPARE(v4.x(), (qreal)(2.0f * x)); + QCOMPARE(v4.y(), (qreal)(3.0f * y)); + QCOMPARE(v4.z(), (qreal)(-4.0f * z)); + QCOMPARE(v4.w(), (qreal)34.0f); + + v4 = v3 * m1; + QCOMPARE(v4.x(), (qreal)(2.0f * x)); + QCOMPARE(v4.y(), (qreal)(3.0f * y)); + QCOMPARE(v4.z(), (qreal)(-4.0f * z)); + QCOMPARE(v4.w(), (qreal)34.0f); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), (int)(2.0f * x)); + QCOMPARE(p2.y(), (int)(3.0f * y)); + + p2 = p1 * m1; + QCOMPARE(p2.x(), (int)(2.0f * x)); + QCOMPARE(p2.y(), (int)(3.0f * y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QCOMPARE(p4.x(), (qreal)(2.0f * x)); + QCOMPARE(p4.y(), (qreal)(3.0f * y)); + + p4 = p3 * m1; + QCOMPARE(p4.x(), (qreal)(2.0f * x)); + QCOMPARE(p4.y(), (qreal)(3.0f * y)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.scale(x, y, z); + QVERIFY(m4 == m3 * m1); + + if (x == y && y == z) { + QMatrix4x4 m5; + m5.scale(x); + QVERIFY(isSame(m5, (const qreal *)resultValues)); + } + + // Test coverage when the special matrix type is unknown. + + QMatrix4x4 m6; + m6(0, 0) = 1.0f; + m6.scale(QVector3D(x, y, z)); + QVERIFY(isSame(m6, (const qreal *)resultValues)); + + QMatrix4x4 m7; + m7(0, 0) = 1.0f; + m7.scale(x, y, z); + QVERIFY(isSame(m7, (const qreal *)resultValues)); + + if (x == y && y == z) { + QMatrix4x4 m8; + m8(0, 0) = 1.0f; + m8.scale(x); + QVERIFY(isSame(m8, (const qreal *)resultValues)); + + m8.inferSpecialType(); + m8.scale(1.0f); + QVERIFY(isSame(m8, (const qreal *)resultValues)); + + QMatrix4x4 m9; + m9.translate(0.0f, 0.0f, 0.0f); + m9.scale(x); + QVERIFY(isSame(m9, (const qreal *)resultValues)); + } +} + +// Test the generation and use of 4x4 translation matrices. +void tst_QMatrix::translate4x4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)identityValues4; + + static const qreal identityTranslate[] = + {1.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("identity") + << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityTranslate; + + static const qreal complexTranslate[] = + {1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 11.0f, + 0.0f, 0.0f, 1.0f, -6.5f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex") + << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexTranslate; +} +void tst_QMatrix::translate4x4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 result((const qreal *)resultValues); + + QMatrix4x4 m1; + m1.translate(QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.translate(x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QCOMPARE(v2.x(), (qreal)(2.0f + x)); + QCOMPARE(v2.y(), (qreal)(3.0f + y)); + QCOMPARE(v2.z(), (qreal)(-4.0f + z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); + QVector4D v4 = m1 * v3; + QCOMPARE(v4.x(), (qreal)(2.0f + x)); + QCOMPARE(v4.y(), (qreal)(3.0f + y)); + QCOMPARE(v4.z(), (qreal)(-4.0f + z)); + QCOMPARE(v4.w(), (qreal)1.0f); + + QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v6 = m1 * v5; + QCOMPARE(v6.x(), (qreal)(2.0f + x * 34.0f)); + QCOMPARE(v6.y(), (qreal)(3.0f + y * 34.0f)); + QCOMPARE(v6.z(), (qreal)(-4.0f + z * 34.0f)); + QCOMPARE(v6.w(), (qreal)34.0f); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), (int)(2.0f + x)); + QCOMPARE(p2.y(), (int)(3.0f + y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QCOMPARE(p4.x(), (qreal)(2.0f + x)); + QCOMPARE(p4.y(), (qreal)(3.0f + y)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.translate(x, y, z); + QVERIFY(m4 == m3 * m1); +} + +// Test the generation and use of 4x4 rotation matrices. +void tst_QMatrix::rotate4x4_data() +{ + QTest::addColumn<qreal>("angle"); + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + static const qreal nullRotate[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("null") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (void *)nullRotate; + + static const qreal noRotate[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("zerodegrees") + << (qreal)0.0f + << (qreal)2.0f << (qreal)3.0f << (qreal)-4.0f + << (void *)noRotate; + + static const qreal xRotate[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("xrotate") + << (qreal)90.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (void *)xRotate; + + static const qreal xRotateNeg[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-xrotate") + << (qreal)90.0f + << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f + << (void *)xRotateNeg; + + static const qreal yRotate[] = + {0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("yrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (void *)yRotate; + + static const qreal yRotateNeg[] = + {0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-yrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f + << (void *)yRotateNeg; + + static const qreal zRotate[] = + {0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("zrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (void *)zRotate; + + static const qreal zRotateNeg[] = + {0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-zrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f + << (void *)zRotateNeg; + + // Algorithm from http://en.wikipedia.org/wiki/Rotation_matrix. + // Deliberately different from the one in the code for cross-checking. + static qreal complexRotate[16]; + qreal x = 1.0f; + qreal y = 2.0f; + qreal z = -6.0f; + qreal angle = -45.0f; + qreal c = qCos(angle * M_PI / 180.0f); + qreal s = qSin(angle * M_PI / 180.0f); + qreal len = qSqrt(x * x + y * y + z * z); + qreal xu = x / len; + qreal yu = y / len; + qreal zu = z / len; + complexRotate[0] = (qreal)((1 - xu * xu) * c + xu * xu); + complexRotate[1] = (qreal)(-zu * s - xu * yu * c + xu * yu); + complexRotate[2] = (qreal)(yu * s - xu * zu * c + xu * zu); + complexRotate[3] = 0; + complexRotate[4] = (qreal)(zu * s - xu * yu * c + xu * yu); + complexRotate[5] = (qreal)((1 - yu * yu) * c + yu * yu); + complexRotate[6] = (qreal)(-xu * s - yu * zu * c + yu * zu); + complexRotate[7] = 0; + complexRotate[8] = (qreal)(-yu * s - xu * zu * c + xu * zu); + complexRotate[9] = (qreal)(xu * s - yu * zu * c + yu * zu); + complexRotate[10] = (qreal)((1 - zu * zu) * c + zu * zu); + complexRotate[11] = 0; + complexRotate[12] = 0; + complexRotate[13] = 0; + complexRotate[14] = 0; + complexRotate[15] = 1; + + QTest::newRow("complex") + << (qreal)angle + << (qreal)x << (qreal)y << (qreal)z + << (void *)complexRotate; +} +void tst_QMatrix::rotate4x4() +{ + QFETCH(qreal, angle); + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 m1; + m1.rotate(angle, QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.rotate(angle, x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.rotate(angle, x, y, z); + QVERIFY(matrixFuzzyCompare(m4, m3 * m1)); + + // Null vectors don't make sense for quaternion rotations. + if (x != 0 || y != 0 || z != 0) { + QMatrix4x4 m5; + m5.rotate(QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle)); + QVERIFY(isSame(m5, (const qreal *)resultValues)); + } + +#define ROTATE4(xin,yin,zin,win,xout,yout,zout,wout) \ + do { \ + xout = ((const qreal *)resultValues)[0] * xin + \ + ((const qreal *)resultValues)[1] * yin + \ + ((const qreal *)resultValues)[2] * zin + \ + ((const qreal *)resultValues)[3] * win; \ + yout = ((const qreal *)resultValues)[4] * xin + \ + ((const qreal *)resultValues)[5] * yin + \ + ((const qreal *)resultValues)[6] * zin + \ + ((const qreal *)resultValues)[7] * win; \ + zout = ((const qreal *)resultValues)[8] * xin + \ + ((const qreal *)resultValues)[9] * yin + \ + ((const qreal *)resultValues)[10] * zin + \ + ((const qreal *)resultValues)[11] * win; \ + wout = ((const qreal *)resultValues)[12] * xin + \ + ((const qreal *)resultValues)[13] * yin + \ + ((const qreal *)resultValues)[14] * zin + \ + ((const qreal *)resultValues)[15] * win; \ + } while (0) + + // Rotate various test vectors using the straight-forward approach. + qreal v1x, v1y, v1z, v1w; + ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v1x, v1y, v1z, v1w); + v1x /= v1w; + v1y /= v1w; + v1z /= v1w; + qreal v3x, v3y, v3z, v3w; + ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v3x, v3y, v3z, v3w); + qreal v5x, v5y, v5z, v5w; + ROTATE4(2.0f, 3.0f, -4.0f, 34.0f, v5x, v5y, v5z, v5w); + qreal p1x, p1y, p1z, p1w; + ROTATE4(2.0f, 3.0f, 0.0f, 1.0f, p1x, p1y, p1z, p1w); + p1x /= p1w; + p1y /= p1w; + p1z /= p1w; + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QVERIFY(fuzzyCompare(v2.x(), v1x)); + QVERIFY(fuzzyCompare(v2.y(), v1y)); + QVERIFY(fuzzyCompare(v2.z(), v1z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); + QVector4D v4 = m1 * v3; + QVERIFY(fuzzyCompare(v4.x(), v3x)); + QVERIFY(fuzzyCompare(v4.y(), v3y)); + QVERIFY(fuzzyCompare(v4.z(), v3z)); + QVERIFY(fuzzyCompare(v4.w(), v3w)); + + QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v6 = m1 * v5; + QVERIFY(fuzzyCompare(v6.x(), v5x)); + QVERIFY(fuzzyCompare(v6.y(), v5y)); + QVERIFY(fuzzyCompare(v6.z(), v5z)); + QVERIFY(fuzzyCompare(v6.w(), v5w)); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), qRound(p1x)); + QCOMPARE(p2.y(), qRound(p1y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QVERIFY(fuzzyCompare((float)(p4.x()), p1x)); + QVERIFY(fuzzyCompare((float)(p4.y()), p1y)); + + if (x != 0 || y != 0 || z != 0) { + QQuaternion q = QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle); + QVector3D vq = q.rotateVector(v1); + QVERIFY(fuzzyCompare(vq.x(), v1x)); + QVERIFY(fuzzyCompare(vq.y(), v1y)); + QVERIFY(fuzzyCompare(vq.z(), v1z)); + } +} + +static bool isSame(const QMatrix3x3& m1, const Matrix3& m2) +{ + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + if (!fuzzyCompare(m1(row, col), m2.v[row * 3 + col])) + return false; + } + } + return true; +} + +// Test the computation of normal matrices from 4x4 transformation matrices. +void tst_QMatrix::normalMatrix_data() +{ + QTest::addColumn<void *>("mValues"); + + QTest::newRow("identity") + << (void *)identityValues4; + QTest::newRow("unique") + << (void *)uniqueValues4; // Not invertible because determinant == 0. + + static qreal const translateValues[16] = + {1.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 1.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 1.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleValues[16] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 7.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues1[16] = + {0.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues2[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues3[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 0.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + + QTest::newRow("translate") << (void *)translateValues; + QTest::newRow("scale") << (void *)scaleValues; + QTest::newRow("both") << (void *)bothValues; + QTest::newRow("null scale 1") << (void *)nullScaleValues1; + QTest::newRow("null scale 2") << (void *)nullScaleValues2; + QTest::newRow("null scale 3") << (void *)nullScaleValues3; +} +void tst_QMatrix::normalMatrix() +{ + QFETCH(void *, mValues); + const qreal *values = (const qreal *)mValues; + + // Compute the expected answer the long way. + Matrix3 min; + Matrix3 answer; + min.v[0] = values[0]; + min.v[1] = values[1]; + min.v[2] = values[2]; + min.v[3] = values[4]; + min.v[4] = values[5]; + min.v[5] = values[6]; + min.v[6] = values[8]; + min.v[7] = values[9]; + min.v[8] = values[10]; + bool invertible = m3Inverse(min, answer); + m3Transpose(answer); + + // Perform the test. + QMatrix4x4 m1(values); + QMatrix3x3 n1 = m1.normalMatrix(); + + if (invertible) + QVERIFY(::isSame(n1, answer)); + else + QVERIFY(isIdentity(n1)); + + // Perform the test again, after inferring special matrix types. + // This tests the optimized paths in the normalMatrix() function. + m1.inferSpecialType(); + n1 = m1.normalMatrix(); + + if (invertible) + QVERIFY(::isSame(n1, answer)); + else + QVERIFY(isIdentity(n1)); +} + +// Test optimized transformations on 4x4 matrices. +void tst_QMatrix::optimizedTransforms() +{ + static qreal const translateValues[16] = + {1.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 1.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 1.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const translateDoubleValues[16] = + {1.0f, 0.0f, 0.0f, 8.0f, + 0.0f, 1.0f, 0.0f, 10.0f, + 0.0f, 0.0f, 1.0f, -6.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleValues[16] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 7.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleDoubleValues[16] = + {4.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 49.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 81.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothReverseValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f * 2.0f, + 0.0f, 7.0f, 0.0f, 5.0f * 7.0f, + 0.0f, 0.0f, 9.0f, -3.0f * 9.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothThenTranslateValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f + 2.0f * 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f + 7.0f * 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f + 9.0f * -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothThenScaleValues[16] = + {4.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 49.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 81.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + + QMatrix4x4 translate(translateValues); + QMatrix4x4 scale(scaleValues); + QMatrix4x4 both(bothValues); + + QMatrix4x4 m1; + m1.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m1, translateValues)); + m1.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m1, translateDoubleValues)); + + QMatrix4x4 m2; + m2.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m2, translateValues)); + m2.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m2, translateDoubleValues)); + + QMatrix4x4 m3; + m3.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m3, scaleValues)); + m3.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m3, scaleDoubleValues)); + + QMatrix4x4 m4; + m4.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m4, scaleValues)); + m4.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m4, scaleDoubleValues)); + + QMatrix4x4 m5; + m5.translate(4.0f, 5.0f, -3.0f); + m5.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m5, bothValues)); + m5.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m5, bothThenTranslateValues)); + + QMatrix4x4 m6; + m6.translate(QVector3D(4.0f, 5.0f, -3.0f)); + m6.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m6, bothValues)); + m6.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m6, bothThenTranslateValues)); + + QMatrix4x4 m7; + m7.scale(2.0f, 7.0f, 9.0f); + m7.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m7, bothReverseValues)); + + QMatrix4x4 m8; + m8.scale(QVector3D(2.0f, 7.0f, 9.0f)); + m8.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m8, bothReverseValues)); + + QMatrix4x4 m9; + m9.translate(4.0f, 5.0f, -3.0f); + m9.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m9, bothValues)); + m9.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m9, bothThenScaleValues)); + + QMatrix4x4 m10; + m10.translate(QVector3D(4.0f, 5.0f, -3.0f)); + m10.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m10, bothValues)); + m10.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m10, bothThenScaleValues)); +} + +// Test orthographic projections. +void tst_QMatrix::ortho() +{ + QMatrix4x4 m1; + m1.ortho(QRect(0, 0, 300, 150)); + QPointF p1 = m1 * QPointF(0, 0); + QPointF p2 = m1 * QPointF(300, 0); + QPointF p3 = m1 * QPointF(0, 150); + QPointF p4 = m1 * QPointF(300, 150); + QVector3D p5 = m1 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m2; + m2.ortho(QRectF(0, 0, 300, 150)); + p1 = m2 * QPointF(0, 0); + p2 = m2 * QPointF(300, 0); + p3 = m2 * QPointF(0, 150); + p4 = m2 * QPointF(300, 150); + p5 = m2 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m3; + m3.ortho(0, 300, 150, 0, -1, 1); + p1 = m3 * QPointF(0, 0); + p2 = m3 * QPointF(300, 0); + p3 = m3 * QPointF(0, 150); + p4 = m3 * QPointF(300, 150); + p5 = m3 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m4; + m4.ortho(0, 300, 150, 0, -2, 3); + p1 = m4 * QPointF(0, 0); + p2 = m4 * QPointF(300, 0); + p3 = m4 * QPointF(0, 150); + p4 = m4 * QPointF(300, 150); + p5 = m4 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-0.6)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.ortho(0, 0, 150, 0, -2, 3); + QVERIFY(m5.isIdentity()); + m5.ortho(0, 300, 150, 150, -2, 3); + QVERIFY(m5.isIdentity()); + m5.ortho(0, 300, 150, 0, 2, 2); + QVERIFY(m5.isIdentity()); +} + +// Test perspective frustum projections. +void tst_QMatrix::frustum() +{ + QMatrix4x4 m1; + m1.frustum(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); + QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); + QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); + QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); + QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); + QVERIFY(fuzzyCompare(p1.x(), -1.0f)); + QVERIFY(fuzzyCompare(p1.y(), -1.0f)); + QVERIFY(fuzzyCompare(p1.z(), -1.0f)); + QVERIFY(fuzzyCompare(p2.x(), 1.0f)); + QVERIFY(fuzzyCompare(p2.y(), -1.0f)); + QVERIFY(fuzzyCompare(p2.z(), -1.0f)); + QVERIFY(fuzzyCompare(p3.x(), -1.0f)); + QVERIFY(fuzzyCompare(p3.y(), 1.0f)); + QVERIFY(fuzzyCompare(p3.z(), -1.0f)); + QVERIFY(fuzzyCompare(p4.x(), 1.0f)); + QVERIFY(fuzzyCompare(p4.y(), 1.0f)); + QVERIFY(fuzzyCompare(p4.z(), -1.0f)); + QVERIFY(fuzzyCompare(p5.x(), 0.0f)); + QVERIFY(fuzzyCompare(p5.y(), 0.0f)); + QVERIFY(fuzzyCompare(p5.z(), -0.5f)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.frustum(0, 0, 150, 0, -2, 3); + QVERIFY(m5.isIdentity()); + m5.frustum(0, 300, 150, 150, -2, 3); + QVERIFY(m5.isIdentity()); + m5.frustum(0, 300, 150, 0, 2, 2); + QVERIFY(m5.isIdentity()); +} + +// Test perspective field-of-view projections. +void tst_QMatrix::perspective() +{ + QMatrix4x4 m1; + m1.perspective(45.0f, 1.0f, -1.0f, 1.0f); + QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); + QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); + QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); + QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); + QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); + QVERIFY(fuzzyCompare(p1.x(), 2.41421)); + QVERIFY(fuzzyCompare(p1.y(), 2.41421)); + QVERIFY(fuzzyCompare(p1.z(), -1)); + QVERIFY(fuzzyCompare(p2.x(), -2.41421)); + QVERIFY(fuzzyCompare(p2.y(), 2.41421)); + QVERIFY(fuzzyCompare(p2.z(), -1.0f)); + QVERIFY(fuzzyCompare(p3.x(), 2.41421)); + QVERIFY(fuzzyCompare(p3.y(), -2.41421)); + QVERIFY(fuzzyCompare(p3.z(), -1.0f)); + QVERIFY(fuzzyCompare(p4.x(), -2.41421)); + QVERIFY(fuzzyCompare(p4.y(), -2.41421)); + QVERIFY(fuzzyCompare(p4.z(), -1.0f)); + QVERIFY(fuzzyCompare(p5.x(), 0.0f)); + QVERIFY(fuzzyCompare(p5.y(), 0.0f)); + QVERIFY(fuzzyCompare(p5.z(), -0.5f)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.perspective(45.0f, 1.0f, 0.0f, 0.0f); + QVERIFY(m5.isIdentity()); + m5.perspective(45.0f, 0.0f, -1.0f, 1.0f); + QVERIFY(m5.isIdentity()); + m5.perspective(0.0f, 1.0f, -1.0f, 1.0f); + QVERIFY(m5.isIdentity()); +} + +// Test left-handed vs right-handed coordinate flipping. +void tst_QMatrix::flipCoordinates() +{ + QMatrix4x4 m1; + m1.flipCoordinates(); + QVector3D p1 = m1 * QVector3D(2, 3, 4); + QVERIFY(p1 == QVector3D(2, -3, -4)); + + QMatrix4x4 m2; + m2.scale(2.0f, 3.0f, 1.0f); + m2.flipCoordinates(); + QVector3D p2 = m2 * QVector3D(2, 3, 4); + QVERIFY(p2 == QVector3D(4, -9, -4)); + + QMatrix4x4 m3; + m3.translate(2.0f, 3.0f, 1.0f); + m3.flipCoordinates(); + QVector3D p3 = m3 * QVector3D(2, 3, 4); + QVERIFY(p3 == QVector3D(4, 0, -3)); + + QMatrix4x4 m4; + m4.rotate(90.0f, 0.0f, 0.0f, 1.0f); + m4.flipCoordinates(); + QVector3D p4 = m4 * QVector3D(2, 3, 4); + QVERIFY(p4 == QVector3D(3, 2, -4)); +} + +// Test conversion of generic matrices to and from the non-generic types. +void tst_QMatrix::convertGeneric() +{ + QMatrix4x3 m1(uniqueValues4x3); + + static qreal const unique4x4[16] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; +#if !defined(QT_NO_MEMBER_TEMPLATES) + QMatrix4x4 m4(m1); + QVERIFY(isSame(m4, unique4x4)); +#endif + QMatrix4x4 m5 = qGenericMatrixToMatrix4x4(m1); + QVERIFY(isSame(m5, unique4x4)); + + static qreal const conv4x4[12] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f + }; + QMatrix4x4 m9(uniqueValues4); +#if !defined(QT_NO_MEMBER_TEMPLATES) + QMatrix4x3 m10 = m9.toGenericMatrix<4, 3>(); + QVERIFY(isSame(m10, conv4x4)); +#endif + + QMatrix4x3 m11 = qGenericMatrixFromMatrix4x4<4, 3>(m9); + QVERIFY(isSame(m11, conv4x4)); +} + +void tst_QMatrix::extractAxisRotation_data() +{ + QTest::addColumn<float>("x"); + QTest::addColumn<float>("y"); + QTest::addColumn<float>("z"); + QTest::addColumn<float>("angle"); + + QTest::newRow("1, 0, 0, 0 deg") << 1.0f << 0.0f << 0.0f << 0.0f; + QTest::newRow("1, 0, 0, 90 deg") << 1.0f << 0.0f << 0.0f << 90.0f; + QTest::newRow("1, 0, 0, 270 deg") << 1.0f << 0.0f << 0.0f << 270.0f; + QTest::newRow("1, 0, 0, 45 deg") << 1.0f << 0.0f << 0.0f << 45.0f; + QTest::newRow("1, 0, 0, 120 deg") << 1.0f << 0.0f << 0.0f << 120.0f; + QTest::newRow("1, 0, 0, 300 deg") << 1.0f << 0.0f << 0.0f << 300.0f; + + QTest::newRow("0, 1, 0, 90 deg") << 0.0f << 1.0f << 0.0f << 90.0f; + QTest::newRow("0, 1, 0, 270 deg") << 0.0f << 1.0f << 0.0f << 270.0f; + QTest::newRow("0, 1, 0, 45 deg") << 0.0f << 1.0f << 0.0f << 45.0f; + QTest::newRow("0, 1, 0, 120 deg") << 0.0f << 1.0f << 0.0f << 120.0f; + QTest::newRow("0, 1, 0, 300 deg") << 0.0f << 1.0f << 0.0f << 300.0f; + + QTest::newRow("0, 0, 1, 90 deg") << 0.0f << 0.0f << 1.0f << 90.0f; + QTest::newRow("0, 0, 1, 270 deg") << 0.0f << 0.0f << 1.0f << 270.0f; + QTest::newRow("0, 0, 1, 45 deg") << 0.0f << 0.0f << 1.0f << 45.0f; + QTest::newRow("0, 0, 1, 120 deg") << 0.0f << 0.0f << 1.0f << 120.0f; + QTest::newRow("0, 0, 1, 300 deg") << 0.0f << 0.0f << 1.0f << 300.0f; + + QTest::newRow("1, 1, 1, 90 deg") << 1.0f << 1.0f << 1.0f << 90.0f; + QTest::newRow("1, 1, 1, 270 deg") << 1.0f << 1.0f << 1.0f << 270.0f; + QTest::newRow("1, 1, 1, 45 deg") << 1.0f << 1.0f << 1.0f << 45.0f; + QTest::newRow("1, 1, 1, 120 deg") << 1.0f << 1.0f << 1.0f << 120.0f; + QTest::newRow("1, 1, 1, 300 deg") << 1.0f << 1.0f << 1.0f << 300.0f; +} + +void tst_QMatrix::extractAxisRotation() +{ + QFETCH(float, x); + QFETCH(float, y); + QFETCH(float, z); + QFETCH(float, angle); + + QMatrix4x4 m; + QVector3D origAxis(x, y, z); + + m.rotate(angle, x, y, z); + + origAxis.normalize(); + QVector3D extractedAxis; + qreal extractedAngle; + + m.extractAxisRotation(extractedAngle, extractedAxis); + + qreal epsilon = 0.001; + + if (angle > 180) { + QVERIFY(fuzzyCompare(360.0f - angle, extractedAngle, epsilon)); + QVERIFY(fuzzyCompare(extractedAxis, -origAxis, epsilon)); + } else { + QVERIFY(fuzzyCompare(angle, extractedAngle, epsilon)); + QVERIFY(fuzzyCompare(extractedAxis, origAxis, epsilon)); + } +} + +void tst_QMatrix::extractTranslation_data() +{ + QTest::addColumn<QMatrix4x4>("rotation"); + QTest::addColumn<float>("x"); + QTest::addColumn<float>("y"); + QTest::addColumn<float>("z"); + + static QMatrix4x4 m1; + + QTest::newRow("identity, 100, 50, 25") + << m1 << 100.0f << 50.0f << 250.0f; + + m1.rotate(45.0, 1.0, 0.0, 0.0); + QTest::newRow("rotX 45 + 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f; + + m1.setIdentity(); + m1.rotate(45.0, 0.0, 1.0, 0.0); + QTest::newRow("rotY 45 + 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f; + + m1.setIdentity(); + m1.rotate(75, 0.0, 0.0, 1.0); + m1.rotate(25, 1.0, 0.0, 0.0); + m1.rotate(45, 0.0, 1.0, 0.0); + QTest::newRow("rotZ 75, rotX 25, rotY 45, 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f; +} + +void tst_QMatrix::extractTranslation() +{ + QFETCH(QMatrix4x4, rotation); + QFETCH(float, x); + QFETCH(float, y); + QFETCH(float, z); + + rotation.translate(x, y, z); + + QVector3D vec = rotation.extractTranslation(); + + qreal epsilon = 0.001; + + QVERIFY(fuzzyCompare(vec.x(), x, epsilon)); + QVERIFY(fuzzyCompare(vec.y(), y, epsilon)); + QVERIFY(fuzzyCompare(vec.z(), z, epsilon)); + + // Have to be careful with numbers here, it is really easy to blow away + // the precision of a fixed pointer number, especially when doing distance + // formula for vector normalization + + QMatrix4x4 lookAt; + QVector3D eye(1.5f, -2.5f, 2.5f); + lookAt.lookAt(eye, + QVector3D(10.0f, 10.0f, 10.0f), + QVector3D(0.0f, 1.0f, 0.0f)); + + QVector3D extEye = lookAt.extractTranslation(); + + QVERIFY(fuzzyCompare(eye.x(), -extEye.x(), epsilon)); + QVERIFY(fuzzyCompare(eye.y(), -extEye.y(), epsilon)); + QVERIFY(fuzzyCompare(eye.z(), -extEye.z(), epsilon)); +} + +// Copy of "flagBits" in qmatrix4x4.h. +enum { + Identity = 0x0001, // Identity matrix + General = 0x0002, // General matrix, unknown contents + Translation = 0x0004, // Contains a simple translation + Scale = 0x0008, // Contains a simple scale + Rotation = 0x0010 // Contains a simple rotation +}; + +// Structure that allows direct access to "flagBits" for testing. +struct Matrix4x4 +{ + float m[4][4]; + int flagBits; +}; + +// Test the inferring of special matrix types. +void tst_QMatrix::inferSpecialType_data() +{ + QTest::addColumn<void *>("mValues"); + QTest::addColumn<int>("flagBits"); + + QTest::newRow("null") + << (void *)nullValues4 << (int)General; + QTest::newRow("identity") + << (void *)identityValues4 << (int)Identity; + QTest::newRow("unique") + << (void *)uniqueValues4 << (int)General; + + static qreal scaleValues[16] = { + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 4.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scale") + << (void *)scaleValues << (int)Scale; + + static qreal translateValues[16] = { + 1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scale") + << (void *)translateValues << (int)Translation; + + static qreal bothValues[16] = { + 1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("both") + << (void *)bothValues << (int)(Scale | Translation); + + static qreal belowValues[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 4.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("below") + << (void *)belowValues << (int)General; +} +void tst_QMatrix::inferSpecialType() +{ + QFETCH(void *, mValues); + QFETCH(int, flagBits); + + QMatrix4x4 m((const qreal *)mValues); + m.inferSpecialType(); + + QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits); +} + +void tst_QMatrix::columnsAndRows() +{ + QMatrix4x4 m1(uniqueValues4); + + QVERIFY(m1.column(0) == QVector4D(1, 5, 9, 13)); + QVERIFY(m1.column(1) == QVector4D(2, 6, 10, 14)); + QVERIFY(m1.column(2) == QVector4D(3, 7, 11, 15)); + QVERIFY(m1.column(3) == QVector4D(4, 8, 12, 16)); + + QVERIFY(m1.row(0) == QVector4D(1, 2, 3, 4)); + QVERIFY(m1.row(1) == QVector4D(5, 6, 7, 8)); + QVERIFY(m1.row(2) == QVector4D(9, 10, 11, 12)); + QVERIFY(m1.row(3) == QVector4D(13, 14, 15, 16)); + + m1.setColumn(0, QVector4D(-1, -5, -9, -13)); + m1.setColumn(1, QVector4D(-2, -6, -10, -14)); + m1.setColumn(2, QVector4D(-3, -7, -11, -15)); + m1.setColumn(3, QVector4D(-4, -8, -12, -16)); + + QVERIFY(m1.column(0) == QVector4D(-1, -5, -9, -13)); + QVERIFY(m1.column(1) == QVector4D(-2, -6, -10, -14)); + QVERIFY(m1.column(2) == QVector4D(-3, -7, -11, -15)); + QVERIFY(m1.column(3) == QVector4D(-4, -8, -12, -16)); + + QVERIFY(m1.row(0) == QVector4D(-1, -2, -3, -4)); + QVERIFY(m1.row(1) == QVector4D(-5, -6, -7, -8)); + QVERIFY(m1.row(2) == QVector4D(-9, -10, -11, -12)); + QVERIFY(m1.row(3) == QVector4D(-13, -14, -15, -16)); + + m1.setRow(0, QVector4D(1, 5, 9, 13)); + m1.setRow(1, QVector4D(2, 6, 10, 14)); + m1.setRow(2, QVector4D(3, 7, 11, 15)); + m1.setRow(3, QVector4D(4, 8, 12, 16)); + + QVERIFY(m1.column(0) == QVector4D(1, 2, 3, 4)); + QVERIFY(m1.column(1) == QVector4D(5, 6, 7, 8)); + QVERIFY(m1.column(2) == QVector4D(9, 10, 11, 12)); + QVERIFY(m1.column(3) == QVector4D(13, 14, 15, 16)); + + QVERIFY(m1.row(0) == QVector4D(1, 5, 9, 13)); + QVERIFY(m1.row(1) == QVector4D(2, 6, 10, 14)); + QVERIFY(m1.row(2) == QVector4D(3, 7, 11, 15)); + QVERIFY(m1.row(3) == QVector4D(4, 8, 12, 16)); +} + +// Test converting QMatrix objects into QMatrix4x4 and then +// checking that transformations in the original perform the +// equivalent transformations in the new matrix. +void tst_QMatrix::convertQMatrix() +{ + QMatrix m1; + m1.translate(-3.5, 2.0); + QPointF p1 = m1.map(QPointF(100.0, 150.0)); + QCOMPARE(p1.x(), 100.0 - 3.5); + QCOMPARE(p1.y(), 150.0 + 2.0); + + QMatrix4x4 m2(m1); + QPointF p2 = m2 * QPointF(100.0, 150.0); + QCOMPARE((double)p2.x(), 100.0 - 3.5); + QCOMPARE((double)p2.y(), 150.0 + 2.0); + QVERIFY(m1 == m2.toAffine()); + + QMatrix m3; + m3.scale(1.5, -2.0); + QPointF p3 = m3.map(QPointF(100.0, 150.0)); + QCOMPARE(p3.x(), 1.5 * 100.0); + QCOMPARE(p3.y(), -2.0 * 150.0); + + QMatrix4x4 m4(m3); + QPointF p4 = m4 * QPointF(100.0, 150.0); + QCOMPARE((double)p4.x(), 1.5 * 100.0); + QCOMPARE((double)p4.y(), -2.0 * 150.0); + QVERIFY(m3 == m4.toAffine()); + + QMatrix m5; + m5.rotate(45.0); + QPointF p5 = m5.map(QPointF(100.0, 150.0)); + + QMatrix4x4 m6(m5); + QPointF p6 = m6 * QPointF(100.0, 150.0); + QVERIFY(fuzzyCompare(p5.x(), p6.x(), 0.005)); + QVERIFY(fuzzyCompare(p5.y(), p6.y(), 0.005)); + + QMatrix m7 = m6.toAffine(); + QVERIFY(fuzzyCompare(m5.m11(), m7.m11())); + QVERIFY(fuzzyCompare(m5.m12(), m7.m12())); + QVERIFY(fuzzyCompare(m5.m21(), m7.m21())); + QVERIFY(fuzzyCompare(m5.m22(), m7.m22())); + QVERIFY(fuzzyCompare(m5.dx(), m7.dx())); + QVERIFY(fuzzyCompare(m5.dy(), m7.dy())); +} + +// Test converting QTransform objects into QMatrix4x4 and then +// checking that transformations in the original perform the +// equivalent transformations in the new matrix. +void tst_QMatrix::convertQTransform() +{ + QTransform m1; + m1.translate(-3.5, 2.0); + QPointF p1 = m1.map(QPointF(100.0, 150.0)); + QCOMPARE(p1.x(), 100.0 - 3.5); + QCOMPARE(p1.y(), 150.0 + 2.0); + + QMatrix4x4 m2(m1); + QPointF p2 = m2 * QPointF(100.0, 150.0); + QCOMPARE((double)p2.x(), 100.0 - 3.5); + QCOMPARE((double)p2.y(), 150.0 + 2.0); + QVERIFY(m1 == m2.toTransform()); + + QTransform m3; + m3.scale(1.5, -2.0); + QPointF p3 = m3.map(QPointF(100.0, 150.0)); + QCOMPARE(p3.x(), 1.5 * 100.0); + QCOMPARE(p3.y(), -2.0 * 150.0); + + QMatrix4x4 m4(m3); + QPointF p4 = m4 * QPointF(100.0, 150.0); + QCOMPARE((double)p4.x(), 1.5 * 100.0); + QCOMPARE((double)p4.y(), -2.0 * 150.0); + QVERIFY(m3 == m4.toTransform()); + + QTransform m5; + m5.rotate(45.0); + QPointF p5 = m5.map(QPointF(100.0, 150.0)); + + QMatrix4x4 m6(m5); + QPointF p6 = m6 * QPointF(100.0, 150.0); + QVERIFY(fuzzyCompare(p5.x(), p6.x(), 0.005)); + QVERIFY(fuzzyCompare(p5.y(), p6.y(), 0.005)); + + QTransform m7 = m6.toTransform(); + QVERIFY(fuzzyCompare(m5.m11(), m7.m11())); + QVERIFY(fuzzyCompare(m5.m12(), m7.m12())); + QVERIFY(fuzzyCompare(m5.m21(), m7.m21())); + QVERIFY(fuzzyCompare(m5.m22(), m7.m22())); + QVERIFY(fuzzyCompare(m5.dx(), m7.dx())); + QVERIFY(fuzzyCompare(m5.dy(), m7.dy())); + QVERIFY(fuzzyCompare(m5.m13(), m7.m13())); + QVERIFY(fuzzyCompare(m5.m23(), m7.m23())); + QVERIFY(fuzzyCompare(m5.m33(), m7.m33())); +} + +// Test filling matrices with specific values. +void tst_QMatrix::fill() +{ + QMatrix4x4 m1; + m1.fill(0.0f); + QVERIFY(isSame(m1, nullValues4)); + + static const qreal fillValues4[] = + {2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f}; + m1.fill(2.5f); + QVERIFY(isSame(m1, fillValues4)); + + QMatrix4x3 m2; + m2.fill(0.0f); + QVERIFY(isSame(m2, nullValues4x3)); + + static const qreal fillValues4x3[] = + {2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f}; + m2.fill(2.5f); + QVERIFY(isSame(m2, fillValues4x3)); +} + +QTEST_APPLESS_MAIN(tst_QMatrix) + +#include "tst_qmatrixnxn.moc" diff --git a/tests/auto/math3d/qquaternion/qquaternion.pro b/tests/auto/math3d/qquaternion/qquaternion.pro new file mode 100644 index 0000000..eea84f0 --- /dev/null +++ b/tests/auto/math3d/qquaternion/qquaternion.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +VPATH += ../shared +INCLUDEPATH += ../shared +HEADERS += math3dincludes.h +SOURCES += tst_qquaternion.cpp diff --git a/tests/auto/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp new file mode 100644 index 0000000..f25f858 --- /dev/null +++ b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp @@ -0,0 +1,830 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include "math3dincludes.h" + +class tst_QQuaternion : public QObject +{ + Q_OBJECT +public: + tst_QQuaternion() {} + ~tst_QQuaternion() {} + +private slots: + void create(); + + void length_data(); + void length(); + + void normalized_data(); + void normalized(); + + void normalize_data(); + void normalize(); + + void compare(); + + void add_data(); + void add(); + + void subtract_data(); + void subtract(); + + void multiply_data(); + void multiply(); + + void multiplyFactor_data(); + void multiplyFactor(); + + void divide_data(); + void divide(); + + void negate_data(); + void negate(); + + void conjugate_data(); + void conjugate(); + + void fromAxisAndAngle_data(); + void fromAxisAndAngle(); + + void slerp_data(); + void slerp(); + + void nlerp_data(); + void nlerp(); +}; + +// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion +// to fixed-point and back again. So create "fuzzier" compares. +static bool fuzzyCompare(float x, float y) +{ + float diff = x - y; + if (diff < 0.0f) + diff = -diff; + return (diff < 0.001); +} + +// Test the creation of QQuaternion objects in various ways: +// construct, copy, and modify. +void tst_QQuaternion::create() +{ + QQuaternion identity; + QCOMPARE(identity.x(), (qreal)0.0f); + QCOMPARE(identity.y(), (qreal)0.0f); + QCOMPARE(identity.z(), (qreal)0.0f); + QCOMPARE(identity.scalar(), (qreal)1.0f); + QVERIFY(identity.isIdentity()); + + QQuaternion v1(34.0f, 1.0f, 2.5f, -89.25f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + QQuaternion v1i(34, 1, 2, -89); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QCOMPARE(v1i.scalar(), (qreal)34.0f); + QVERIFY(!v1i.isNull()); + + QQuaternion v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QCOMPARE(v2.scalar(), (qreal)34.0f); + QVERIFY(!v2.isNull()); + + QQuaternion v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QCOMPARE(v4.scalar(), (qreal)1.0f); + QVERIFY(v4.isIdentity()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QCOMPARE(v4.scalar(), (qreal)34.0f); + QVERIFY(!v4.isNull()); + + QQuaternion v9(34, QVector3D(1.0f, 2.5f, -89.25f)); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)-89.25f); + QCOMPARE(v9.scalar(), (qreal)34.0f); + QVERIFY(!v9.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setScalar(6.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + + v1.setVector(2.0f, 6.5f, -1.25f); + QCOMPARE(v1.x(), (qreal)2.0f); + QCOMPARE(v1.y(), (qreal)6.5f); + QCOMPARE(v1.z(), (qreal)-1.25f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + QVERIFY(v1.vector() == QVector3D(2.0f, 6.5f, -1.25f)); + + v1.setVector(QVector3D(-2.0f, -6.5f, 1.25f)); + QCOMPARE(v1.x(), (qreal)-2.0f); + QCOMPARE(v1.y(), (qreal)-6.5f); + QCOMPARE(v1.z(), (qreal)1.25f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + QVERIFY(v1.vector() == QVector3D(-2.0f, -6.5f, 1.25f)); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + v1.setScalar(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QCOMPARE(v1.scalar(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QVector4D v10 = v9.toVector4D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)-89.25f); + QCOMPARE(v10.w(), (qreal)34.0f); +} + +// Test length computation for quaternions. +void tst_QQuaternion::length_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("w"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)2.0f << (qreal)qSqrt(16.0f); +} +void tst_QQuaternion::length() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QQuaternion v(w, x, y, z); + QCOMPARE((float)(v.length()), (float)len); + QCOMPARE((float)(v.lengthSquared()), (float)(x * x + y * y + z * z + w * w)); +} + +// Test the unit vector conversion for quaternions. +void tst_QQuaternion::normalized_data() +{ + // Use the same test data as the length test. + length_data(); +} +void tst_QQuaternion::normalized() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QQuaternion v(w, x, y, z); + QQuaternion u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QCOMPARE((float)(u.length()), (float)1.0f); + QCOMPARE((float)(u.x() * len), (float)(v.x())); + QCOMPARE((float)(u.y() * len), (float)(v.y())); + QCOMPARE((float)(u.z() * len), (float)(v.z())); + QCOMPARE((float)(u.scalar() * len), (float)(v.scalar())); +} + +// Test the unit vector conversion for quaternions. +void tst_QQuaternion::normalize_data() +{ + // Use the same test data as the length test. + length_data(); +} +void tst_QQuaternion::normalize() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + + QQuaternion v(w, x, y, z); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QCOMPARE((float)(v.length()), (float)1.0f); +} + +// Test the comparison operators for quaternions. +void tst_QQuaternion::compare() +{ + QQuaternion v1(8, 1, 2, 4); + QQuaternion v2(8, 1, 2, 4); + QQuaternion v3(8, 3, 2, 4); + QQuaternion v4(8, 1, 3, 4); + QQuaternion v5(8, 1, 2, 3); + QQuaternion v6(3, 1, 2, 4); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); + QVERIFY(v1 != v6); +} + +// Test addition for quaternions. +void tst_QQuaternion::add_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f << (qreal)17.0f; +} +void tst_QQuaternion::add() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + QQuaternion v3(w3, x3, y3, z3); + + QVERIFY((v1 + v2) == v3); + + QQuaternion v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); + QCOMPARE(v4.scalar(), v1.scalar() + v2.scalar()); +} + +// Test subtraction for quaternions. +void tst_QQuaternion::subtract_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::subtract() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + QQuaternion v3(w3, x3, y3, z3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QQuaternion v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + QCOMPARE(v4.scalar(), v3.scalar() - v1.scalar()); + + QQuaternion v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); + QCOMPARE(v5.scalar(), v3.scalar() - v2.scalar()); +} + +// Test quaternion multiplication. +void tst_QQuaternion::multiply_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)7.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f << (qreal)8.0f; +} +void tst_QQuaternion::multiply() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion q1(w1, x1, y1, z1); + QQuaternion q2(w2, x2, y2, z2); + + // Use the simple algorithm at: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q53 + // to calculate the answer we expect to get. + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + qreal scalar = w1 * w2 - QVector3D::dotProduct(v1, v2); + QVector3D vector = w1 * v2 + w2 * v1 + QVector3D::crossProduct(v1, v2); + QQuaternion result(scalar, vector); + + QVERIFY((q1 * q2) == result); +} + +// Test multiplication by a factor for quaternions. +void tst_QQuaternion::multiplyFactor_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f << (qreal)8.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QQuaternion::multiplyFactor() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QQuaternion v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); + QCOMPARE(v3.scalar(), v1.scalar() * factor); +} + +// Test division by a factor for quaternions. +void tst_QQuaternion::divide_data() +{ + // Use the same test data as the multiply test. + multiplyFactor_data(); +} +void tst_QQuaternion::divide() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QQuaternion v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); + QCOMPARE(v3.scalar(), v2.scalar() / factor); +} + +// Test negation for quaternions. +void tst_QQuaternion::negate_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::negate() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(-w1, -x1, -y1, -z1); + + QVERIFY(-v1 == v2); +} + +// Test quaternion conjugate calculations. +void tst_QQuaternion::conjugate_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::conjugate() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w1, -x1, -y1, -z1); + + QVERIFY(v1.conjugate() == v2); +} + +// Test quaternion creation from an axis and an angle. +void tst_QQuaternion::fromAxisAndAngle_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("angle"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)90.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)180.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)270.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)45.0f; +} +void tst_QQuaternion::fromAxisAndAngle() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle); + + // Use a straight-forward implementation of the algorithm at: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56 + // to calculate the answer we expect to get. + QVector3D vector = QVector3D(x1, y1, z1).normalized(); + qreal sin_a = qSin((angle * M_PI / 180.0) / 2.0); + qreal cos_a = qCos((angle * M_PI / 180.0) / 2.0); + QQuaternion result((qreal)cos_a, + (qreal)(vector.x() * sin_a), + (qreal)(vector.y() * sin_a), + (qreal)(vector.z() * sin_a)); + result = result.normalized(); + + QQuaternion answer = QQuaternion::fromAxisAndAngle(QVector3D(x1, y1, z1), angle); + QVERIFY(fuzzyCompare(answer.x(), result.x())); + QVERIFY(fuzzyCompare(answer.y(), result.y())); + QVERIFY(fuzzyCompare(answer.z(), result.z())); + QVERIFY(fuzzyCompare(answer.scalar(), result.scalar())); + + answer = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle); + QVERIFY(fuzzyCompare(answer.x(), result.x())); + QVERIFY(fuzzyCompare(answer.y(), result.y())); + QVERIFY(fuzzyCompare(answer.z(), result.z())); + QVERIFY(fuzzyCompare(answer.scalar(), result.scalar())); +} + +// Test spherical interpolation of quaternions. +void tst_QQuaternion::slerp_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("angle1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("angle2"); + QTest::addColumn<qreal>("t"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("angle3"); + + QTest::newRow("first") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)0.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f; + QTest::newRow("first2") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)-0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f; + QTest::newRow("second") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)1.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f; + QTest::newRow("second2") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)1.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f; + QTest::newRow("middle") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)135.0f; + QTest::newRow("wide angle") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)0.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)270.0f + << (qreal)0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)-45.0f; +} +void tst_QQuaternion::slerp() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, angle2); + QFETCH(qreal, t); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, angle3); + + QQuaternion q1 = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle1); + QQuaternion q2 = QQuaternion::fromAxisAndAngle(x2, y2, z2, angle2); + QQuaternion q3 = QQuaternion::fromAxisAndAngle(x3, y3, z3, angle3); + + QQuaternion result = QQuaternion::slerp(q1, q2, t); + + QVERIFY(fuzzyCompare(result.x(), q3.x())); + QVERIFY(fuzzyCompare(result.y(), q3.y())); + QVERIFY(fuzzyCompare(result.z(), q3.z())); + QVERIFY(fuzzyCompare(result.scalar(), q3.scalar())); +} + +// Test normalized linear interpolation of quaternions. +void tst_QQuaternion::nlerp_data() +{ + slerp_data(); +} +void tst_QQuaternion::nlerp() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, angle2); + QFETCH(qreal, t); + + QQuaternion q1 = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle1); + QQuaternion q2 = QQuaternion::fromAxisAndAngle(x2, y2, z2, angle2); + + QQuaternion result = QQuaternion::nlerp(q1, q2, t); + + qreal resultx, resulty, resultz, resultscalar; + if (t <= 0.0f) { + resultx = q1.x(); + resulty = q1.y(); + resultz = q1.z(); + resultscalar = q1.scalar(); + } else if (t >= 1.0f) { + resultx = q2.x(); + resulty = q2.y(); + resultz = q2.z(); + resultscalar = q2.scalar(); + } else if (qAbs(angle1 - angle2) <= 180.f) { + resultx = q1.x() * (1 - t) + q2.x() * t; + resulty = q1.y() * (1 - t) + q2.y() * t; + resultz = q1.z() * (1 - t) + q2.z() * t; + resultscalar = q1.scalar() * (1 - t) + q2.scalar() * t; + } else { + // Angle greater than 180 degrees: negate q2. + resultx = q1.x() * (1 - t) - q2.x() * t; + resulty = q1.y() * (1 - t) - q2.y() * t; + resultz = q1.z() * (1 - t) - q2.z() * t; + resultscalar = q1.scalar() * (1 - t) - q2.scalar() * t; + } + + QQuaternion q3 = QQuaternion(resultscalar, resultx, resulty, resultz).normalized(); + + QVERIFY(fuzzyCompare(result.x(), q3.x())); + QVERIFY(fuzzyCompare(result.y(), q3.y())); + QVERIFY(fuzzyCompare(result.z(), q3.z())); + QVERIFY(fuzzyCompare(result.scalar(), q3.scalar())); +} + +QTEST_APPLESS_MAIN(tst_QQuaternion) + +#include "tst_qquaternion.moc" diff --git a/tests/auto/math3d/qvectornd/qvectornd.pro b/tests/auto/math3d/qvectornd/qvectornd.pro new file mode 100644 index 0000000..0981637 --- /dev/null +++ b/tests/auto/math3d/qvectornd/qvectornd.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +VPATH += ../shared +INCLUDEPATH += ../shared +HEADERS += math3dincludes.h +SOURCES += tst_qvectornd.cpp diff --git a/tests/auto/math3d/qvectornd/tst_qvectornd.cpp b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp new file mode 100644 index 0000000..a092fb0 --- /dev/null +++ b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp @@ -0,0 +1,2045 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include "math3dincludes.h" + +class tst_QVector : public QObject +{ + Q_OBJECT +public: + tst_QVector() {} + ~tst_QVector() {} + +private slots: + void create2(); + void create3(); + void create4(); + + void length2_data(); + void length2(); + void length3_data(); + void length3(); + void length4_data(); + void length4(); + + void normalized2_data(); + void normalized2(); + void normalized3_data(); + void normalized3(); + void normalized4_data(); + void normalized4(); + + void normalize2_data(); + void normalize2(); + void normalize3_data(); + void normalize3(); + void normalize4_data(); + void normalize4(); + + void compare2(); + void compare3(); + void compare4(); + + void add2_data(); + void add2(); + void add3_data(); + void add3(); + void add4_data(); + void add4(); + + void subtract2_data(); + void subtract2(); + void subtract3_data(); + void subtract3(); + void subtract4_data(); + void subtract4(); + + void multiply2_data(); + void multiply2(); + void multiply3_data(); + void multiply3(); + void multiply4_data(); + void multiply4(); + + void multiplyFactor2_data(); + void multiplyFactor2(); + void multiplyFactor3_data(); + void multiplyFactor3(); + void multiplyFactor4_data(); + void multiplyFactor4(); + + void divide2_data(); + void divide2(); + void divide3_data(); + void divide3(); + void divide4_data(); + void divide4(); + + void negate2_data(); + void negate2(); + void negate3_data(); + void negate3(); + void negate4_data(); + void negate4(); + + void crossProduct_data(); + void crossProduct(); + void normal_data(); + void normal(); + void distanceToPlane_data(); + void distanceToPlane(); + void distanceToLine_data(); + void distanceToLine(); + + void dotProduct2_data(); + void dotProduct2(); + void dotProduct3_data(); + void dotProduct3(); + void dotProduct4_data(); + void dotProduct4(); +}; + +// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion +// to fixed-point and back again. So create "fuzzier" compares. +static bool fuzzyCompare(float x, float y) +{ + float diff = x - y; + if (diff < 0.0f) + diff = -diff; + return (diff < 0.001); +} + +// Test the creation of QVector2D objects in various ways: +// construct, copy, and modify. +void tst_QVector::create2() +{ + QVector2D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector2D v1(1.0f, 2.5f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QVERIFY(!v1.isNull()); + + QVector2D v1i(1, 2); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QVERIFY(!v1i.isNull()); + + QVector2D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QVERIFY(!v2.isNull()); + + QVector2D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QVERIFY(!v4.isNull()); + + QVector2D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QVERIFY(!v5.isNull()); + + QVector2D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + QVector2D v7(QVector3D(1.0f, 2.5f, 54.25f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + QVector2D v8(QVector4D(1.0f, 2.5f, 54.25f, 34.0f)); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector3D v9 = v8.toVector3D(); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)0.0f); + + QVector4D v10 = v8.toVector4D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)0.0f); + QCOMPARE(v10.w(), (qreal)0.0f); +} + +// Test the creation of QVector3D objects in various ways: +// construct, copy, and modify. +void tst_QVector::create3() +{ + QVector3D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QCOMPARE(null.z(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector3D v1(1.0f, 2.5f, -89.25f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + QVector3D v1i(1, 2, -89); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QVERIFY(!v1i.isNull()); + + QVector3D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QVERIFY(!v2.isNull()); + + QVector3D v3(1.0f, 2.5f, 0.0f); + QCOMPARE(v3.x(), (qreal)1.0f); + QCOMPARE(v3.y(), (qreal)2.5f); + QCOMPARE(v3.z(), (qreal)0.0f); + QVERIFY(!v3.isNull()); + + QVector3D v3i(1, 2, 0); + QCOMPARE(v3i.x(), (qreal)1.0f); + QCOMPARE(v3i.y(), (qreal)2.0f); + QCOMPARE(v3i.z(), (qreal)0.0f); + QVERIFY(!v3i.isNull()); + + QVector3D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QVERIFY(!v4.isNull()); + + QVector3D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QCOMPARE(v5.z(), (qreal)0.0f); + QVERIFY(!v5.isNull()); + + QVector3D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QCOMPARE(v6.z(), (qreal)0.0f); + QVERIFY(!v6.isNull()); + + QVector3D v7(QVector2D(1.0f, 2.5f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QCOMPARE(v7.z(), (qreal)0.0f); + QVERIFY(!v7.isNull()); + + QVector3D v8(QVector2D(1.0f, 2.5f), 54.25f); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QCOMPARE(v8.z(), (qreal)54.25f); + QVERIFY(!v8.isNull()); + + QVector3D v9(QVector4D(1.0f, 2.5f, 54.25f, 34.0f)); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)54.25f); + QVERIFY(!v9.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector2D v10 = v8.toVector2D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + + QVector4D v11 = v8.toVector4D(); + QCOMPARE(v11.x(), (qreal)1.0f); + QCOMPARE(v11.y(), (qreal)2.5f); + QCOMPARE(v11.z(), (qreal)54.25f); + QCOMPARE(v11.w(), (qreal)0.0f); +} + +// Test the creation of QVector4D objects in various ways: +// construct, copy, and modify. +void tst_QVector::create4() +{ + QVector4D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QCOMPARE(null.z(), (qreal)0.0f); + QCOMPARE(null.w(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector4D v1(1.0f, 2.5f, -89.25f, 34.0f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + QVector4D v1i(1, 2, -89, 34); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QCOMPARE(v1i.w(), (qreal)34.0f); + QVERIFY(!v1i.isNull()); + + QVector4D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QCOMPARE(v2.w(), (qreal)34.0f); + QVERIFY(!v2.isNull()); + + QVector4D v3(1.0f, 2.5f, 0.0f, 0.0f); + QCOMPARE(v3.x(), (qreal)1.0f); + QCOMPARE(v3.y(), (qreal)2.5f); + QCOMPARE(v3.z(), (qreal)0.0f); + QCOMPARE(v3.w(), (qreal)0.0f); + QVERIFY(!v3.isNull()); + + QVector4D v3i(1, 2, 0, 0); + QCOMPARE(v3i.x(), (qreal)1.0f); + QCOMPARE(v3i.y(), (qreal)2.0f); + QCOMPARE(v3i.z(), (qreal)0.0f); + QCOMPARE(v3i.w(), (qreal)0.0f); + QVERIFY(!v3i.isNull()); + + QVector4D v3b(1.0f, 2.5f, -89.25f, 0.0f); + QCOMPARE(v3b.x(), (qreal)1.0f); + QCOMPARE(v3b.y(), (qreal)2.5f); + QCOMPARE(v3b.z(), (qreal)-89.25f); + QCOMPARE(v3b.w(), (qreal)0.0f); + QVERIFY(!v3b.isNull()); + + QVector4D v3bi(1, 2, -89, 0); + QCOMPARE(v3bi.x(), (qreal)1.0f); + QCOMPARE(v3bi.y(), (qreal)2.0f); + QCOMPARE(v3bi.z(), (qreal)-89.0f); + QCOMPARE(v3bi.w(), (qreal)0.0f); + QVERIFY(!v3bi.isNull()); + + QVector4D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QCOMPARE(v4.w(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QCOMPARE(v4.w(), (qreal)34.0f); + QVERIFY(!v4.isNull()); + + QVector4D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QCOMPARE(v5.z(), (qreal)0.0f); + QCOMPARE(v5.w(), (qreal)0.0f); + QVERIFY(!v5.isNull()); + + QVector4D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QCOMPARE(v6.z(), (qreal)0.0f); + QCOMPARE(v6.w(), (qreal)0.0f); + QVERIFY(!v6.isNull()); + + QVector4D v7(QVector2D(1.0f, 2.5f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QCOMPARE(v7.z(), (qreal)0.0f); + QCOMPARE(v7.w(), (qreal)0.0f); + QVERIFY(!v7.isNull()); + + QVector4D v8(QVector3D(1.0f, 2.5f, -89.25f)); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QCOMPARE(v8.z(), (qreal)-89.25f); + QCOMPARE(v8.w(), (qreal)0.0f); + QVERIFY(!v8.isNull()); + + QVector4D v9(QVector3D(1.0f, 2.5f, -89.25f), 34); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)-89.25f); + QCOMPARE(v9.w(), (qreal)34.0f); + QVERIFY(!v9.isNull()); + + QVector4D v10(QVector2D(1.0f, 2.5f), 23.5f, -8); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)23.5f); + QCOMPARE(v10.w(), (qreal)-8.0f); + QVERIFY(!v10.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setW(6.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.w(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + v1.setW(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QCOMPARE(v1.w(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector2D v11 = v8.toVector2D(); + QCOMPARE(v11.x(), (qreal)1.0f); + QCOMPARE(v11.y(), (qreal)2.5f); + + QVector3D v12 = v8.toVector3D(); + QCOMPARE(v12.x(), (qreal)1.0f); + QCOMPARE(v12.y(), (qreal)2.5f); + QCOMPARE(v12.z(), (qreal)-89.25f); + + QVector2D v13 = v9.toVector2DAffine(); + QVERIFY(fuzzyCompare(v13.x(), (qreal)(1.0f / 34.0f))); + QVERIFY(fuzzyCompare(v13.y(), (qreal)(2.5f / 34.0f))); + + QVector4D zerow(1.0f, 2.0f, 3.0f, 0.0f); + v13 = zerow.toVector2DAffine(); + QVERIFY(v13.isNull()); + + QVector3D v14 = v9.toVector3DAffine(); + QVERIFY(fuzzyCompare(v14.x(), (qreal)(1.0f / 34.0f))); + QVERIFY(fuzzyCompare(v14.y(), (qreal)(2.5f / 34.0f))); + QVERIFY(fuzzyCompare(v14.z(), (qreal)(-89.25f / 34.0f))); + + v14 = zerow.toVector3DAffine(); + QVERIFY(v14.isNull()); +} + +// Test vector length computation for 2D vectors. +void tst_QVector::length2_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)qSqrt(8.0f); +} +void tst_QVector::length2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, len); + + QVector2D v(x, y); + QCOMPARE((float)(v.length()), (float)len); + QCOMPARE((float)(v.lengthSquared()), (float)(x * x + y * y)); +} + +// Test vector length computation for 3D vectors. +void tst_QVector::length3_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)qSqrt(12.0f); +} +void tst_QVector::length3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, len); + + QVector3D v(x, y, z); + QCOMPARE((float)(v.length()), (float)len); + QCOMPARE((float)(v.lengthSquared()), (float)(x * x + y * y + z * z)); +} + +// Test vector length computation for 4D vectors. +void tst_QVector::length4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("w"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)2.0f << (qreal)qSqrt(16.0f); +} +void tst_QVector::length4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QVector4D v(x, y, z, w); + QCOMPARE((float)(v.length()), (float)len); + QCOMPARE((float)(v.lengthSquared()), (float)(x * x + y * y + z * z + w * w)); +} + +// Test the unit vector conversion for 2D vectors. +void tst_QVector::normalized2_data() +{ + // Use the same test data as the length test. + length2_data(); +} +void tst_QVector::normalized2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, len); + + QVector2D v(x, y); + QVector2D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QCOMPARE((float)(u.length()), (float)1.0f); + QCOMPARE((float)(u.x() * len), (float)(v.x())); + QCOMPARE((float)(u.y() * len), (float)(v.y())); +} + +// Test the unit vector conversion for 3D vectors. +void tst_QVector::normalized3_data() +{ + // Use the same test data as the length test. + length3_data(); +} +void tst_QVector::normalized3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, len); + + QVector3D v(x, y, z); + QVector3D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QCOMPARE((float)(u.length()), (float)1.0f); + QCOMPARE((float)(u.x() * len), (float)(v.x())); + QCOMPARE((float)(u.y() * len), (float)(v.y())); + QCOMPARE((float)(u.z() * len), (float)(v.z())); +} + +// Test the unit vector conversion for 4D vectors. +void tst_QVector::normalized4_data() +{ + // Use the same test data as the length test. + length4_data(); +} +void tst_QVector::normalized4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QVector4D v(x, y, z, w); + QVector4D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QCOMPARE((float)(u.length()), (float)1.0f); + QCOMPARE((float)(u.x() * len), (float)(v.x())); + QCOMPARE((float)(u.y() * len), (float)(v.y())); + QCOMPARE((float)(u.z() * len), (float)(v.z())); + QCOMPARE((float)(u.w() * len), (float)(v.w())); +} + +// Test the unit vector conversion for 2D vectors. +void tst_QVector::normalize2_data() +{ + // Use the same test data as the length test. + length2_data(); +} +void tst_QVector::normalize2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + + QVector2D v(x, y); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QCOMPARE((float)(v.length()), (float)1.0f); +} + +// Test the unit vector conversion for 3D vectors. +void tst_QVector::normalize3_data() +{ + // Use the same test data as the length test. + length3_data(); +} +void tst_QVector::normalize3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + + QVector3D v(x, y, z); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QCOMPARE((float)(v.length()), (float)1.0f); +} + +// Test the unit vector conversion for 4D vectors. +void tst_QVector::normalize4_data() +{ + // Use the same test data as the length test. + length4_data(); +} +void tst_QVector::normalize4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + + QVector4D v(x, y, z, w); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QCOMPARE((float)(v.length()), (float)1.0f); +} + +// Test the comparison operators for 2D vectors. +void tst_QVector::compare2() +{ + QVector2D v1(1, 2); + QVector2D v2(1, 2); + QVector2D v3(3, 2); + QVector2D v4(1, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); +} + +// Test the comparison operators for 3D vectors. +void tst_QVector::compare3() +{ + QVector3D v1(1, 2, 4); + QVector3D v2(1, 2, 4); + QVector3D v3(3, 2, 4); + QVector3D v4(1, 3, 4); + QVector3D v5(1, 2, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); +} + +// Test the comparison operators for 4D vectors. +void tst_QVector::compare4() +{ + QVector4D v1(1, 2, 4, 8); + QVector4D v2(1, 2, 4, 8); + QVector4D v3(3, 2, 4, 8); + QVector4D v4(1, 3, 4, 8); + QVector4D v5(1, 2, 3, 8); + QVector4D v6(1, 2, 4, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); + QVERIFY(v1 != v6); +} + +// Test vector addition for 2D vectors. +void tst_QVector::add2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)5.0f << (qreal)7.0f; +} +void tst_QVector::add2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v1 + v2) == v3); + + QVector2D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); +} + +// Test vector addition for 3D vectors. +void tst_QVector::add3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f; +} +void tst_QVector::add3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v1 + v2) == v3); + + QVector3D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); +} + +// Test vector addition for 4D vectors. +void tst_QVector::add4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f << (qreal)17.0f; +} +void tst_QVector::add4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v1 + v2) == v3); + + QVector4D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); + QCOMPARE(v4.w(), v1.w() + v2.w()); +} + +// Test vector subtraction for 2D vectors. +void tst_QVector::subtract2_data() +{ + // Use the same test data as the add test. + add2_data(); +} +void tst_QVector::subtract2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector2D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + + QVector2D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); +} + +// Test vector subtraction for 3D vectors. +void tst_QVector::subtract3_data() +{ + // Use the same test data as the add test. + add3_data(); +} +void tst_QVector::subtract3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector3D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + + QVector3D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); +} + +// Test vector subtraction for 4D vectors. +void tst_QVector::subtract4_data() +{ + // Use the same test data as the add test. + add4_data(); +} +void tst_QVector::subtract4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector4D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + QCOMPARE(v4.w(), v3.w() - v1.w()); + + QVector4D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); + QCOMPARE(v5.w(), v3.w() - v2.w()); +} + +// Test component-wise vector multiplication for 2D vectors. +void tst_QVector::multiply2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)4.0f << (qreal)10.0f; +} +void tst_QVector::multiply2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v1 * v2) == v3); + + QVector2D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); +} + +// Test component-wise vector multiplication for 3D vectors. +void tst_QVector::multiply3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f + << (qreal)4.0f << (qreal)10.0f << (qreal)-18.0f; +} +void tst_QVector::multiply3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v1 * v2) == v3); + + QVector3D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); + QCOMPARE(v4.z(), v1.z() * v2.z()); +} + +// Test component-wise vector multiplication for 4D vectors. +void tst_QVector::multiply4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)4.0f << (qreal)10.0f << (qreal)-18.0f << (qreal)72.0f; +} +void tst_QVector::multiply4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v1 * v2) == v3); + + QVector4D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); + QCOMPARE(v4.z(), v1.z() * v2.z()); + QCOMPARE(v4.w(), v1.w() * v2.w()); +} + +// Test vector multiplication by a factor for 2D vectors. +void tst_QVector::multiplyFactor2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVector::multiplyFactor2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector2D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); +} + +// Test vector multiplication by a factor for 3D vectors. +void tst_QVector::multiplyFactor3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVector::multiplyFactor3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector3D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); +} + +// Test vector multiplication by a factor for 4D vectors. +void tst_QVector::multiplyFactor4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f << (qreal)8.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVector::multiplyFactor4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector4D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); + QCOMPARE(v3.w(), v1.w() * factor); +} + +// Test vector division by a factor for 2D vectors. +void tst_QVector::divide2_data() +{ + // Use the same test data as the multiply test. + multiplyFactor2_data(); +} +void tst_QVector::divide2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector2D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); +} + +// Test vector division by a factor for 3D vectors. +void tst_QVector::divide3_data() +{ + // Use the same test data as the multiply test. + multiplyFactor3_data(); +} +void tst_QVector::divide3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector3D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); +} + +// Test vector division by a factor for 4D vectors. +void tst_QVector::divide4_data() +{ + // Use the same test data as the multiply test. + multiplyFactor4_data(); +} +void tst_QVector::divide4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector4D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); + QCOMPARE(v3.w(), v2.w() / factor); +} + +// Test vector negation for 2D vectors. +void tst_QVector::negate2_data() +{ + // Use the same test data as the add test. + add2_data(); +} +void tst_QVector::negate2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + + QVector2D v1(x1, y1); + QVector2D v2(-x1, -y1); + + QVERIFY(-v1 == v2); +} + +// Test vector negation for 3D vectors. +void tst_QVector::negate3_data() +{ + // Use the same test data as the add test. + add3_data(); +} +void tst_QVector::negate3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + + QVector3D v1(x1, y1, z1); + QVector3D v2(-x1, -y1, -z1); + + QVERIFY(-v1 == v2); +} + +// Test vector negation for 4D vectors. +void tst_QVector::negate4_data() +{ + // Use the same test data as the add test. + add4_data(); +} +void tst_QVector::negate4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(-x1, -y1, -z1, -w1); + + QVERIFY(-v1 == v2); +} + +// Test the computation of vector cross-products. +void tst_QVector::crossProduct_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f + << (qreal)-3.0f << (qreal)6.0f << (qreal)-3.0f + << (qreal)32.0f; +} +void tst_QVector::crossProduct() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVector3D v4 = QVector3D::crossProduct(v1, v2); + QVERIFY(v4 == v3); + + // Compute the cross-product long-hand and check again. + qreal xres = y1 * z2 - z1 * y2; + qreal yres = z1 * x2 - x1 * z2; + qreal zres = x1 * y2 - y1 * x2; + + QCOMPARE(v4.x(), xres); + QCOMPARE(v4.y(), yres); + QCOMPARE(v4.z(), zres); +} + +// Test the computation of normals. +void tst_QVector::normal_data() +{ + // Use the same test data as the crossProduct test. + crossProduct_data(); +} +void tst_QVector::normal() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY(QVector3D::normal(v1, v2) == v3.normalized()); + QVERIFY(QVector3D::normal(QVector3D(), v1, v2) == v3.normalized()); + + QVector3D point(1.0f, 2.0f, 3.0f); + QVERIFY(QVector3D::normal(point, v1 + point, v2 + point) == v3.normalized()); +} + +// Test distance to plane calculations. +void tst_QVector::distanceToPlane_data() +{ + QTest::addColumn<qreal>("x1"); // Point on plane + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); // Normal to plane + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); // Point to test for distance + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("x4"); // Second point on plane + QTest::addColumn<qreal>("y4"); + QTest::addColumn<qreal>("z4"); + QTest::addColumn<qreal>("x5"); // Third point on plane + QTest::addColumn<qreal>("y5"); + QTest::addColumn<qreal>("z5"); + QTest::addColumn<qreal>("distance"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("above") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)2.0f; + + QTest::newRow("below") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)-1.0f << (qreal)1.0f << (qreal)-2.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)-2.0f; +} +void tst_QVector::distanceToPlane() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, x4); + QFETCH(qreal, y4); + QFETCH(qreal, z4); + QFETCH(qreal, x5); + QFETCH(qreal, y5); + QFETCH(qreal, z5); + QFETCH(qreal, distance); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + QVector3D v4(x4, y4, z4); + QVector3D v5(x5, y5, z5); + + QCOMPARE(v3.distanceToPlane(v1, v2), distance); + QCOMPARE(v3.distanceToPlane(v1, v4, v5), distance); +} + +// Test distance to line calculations. +void tst_QVector::distanceToLine_data() +{ + QTest::addColumn<qreal>("x1"); // Point on line + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); // Direction of the line + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); // Point to test for distance + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("distance"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("on line") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)5.0f + << (qreal)0.0f; + + QTest::newRow("off line") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)1.0f; + + QTest::newRow("off line 2") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)-2.0f << (qreal)0.0f + << (qreal)2.0f; + + QTest::newRow("points") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)5.0f << (qreal)0.0f + << (qreal)5.0f; +} +void tst_QVector::distanceToLine() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, distance); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QCOMPARE(v3.distanceToLine(v1, v2), distance); +} + +// Test the computation of dot products for 2D vectors. +void tst_QVector::dotProduct2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)14.0f; +} +void tst_QVector::dotProduct2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, dot); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + QVERIFY(QVector2D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2; + + QCOMPARE(QVector2D::dotProduct(v1, v2), d); +} + +// Test the computation of dot products for 3D vectors. +void tst_QVector::dotProduct3_data() +{ + // Use the same test data as the crossProduct test. + crossProduct_data(); +} +void tst_QVector::dotProduct3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, dot); + + Q_UNUSED(x3); + Q_UNUSED(y3); + Q_UNUSED(z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + QVERIFY(QVector3D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2 + z1 * z2; + + QCOMPARE(QVector3D::dotProduct(v1, v2), d); +} + +// Test the computation of dot products for 4D vectors. +void tst_QVector::dotProduct4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)4.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f << (qreal)7.0f + << (qreal)60.0f; +} +void tst_QVector::dotProduct4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, dot); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + QVERIFY(QVector4D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2 + z1 * z2 + w1 * w2; + + QCOMPARE(QVector4D::dotProduct(v1, v2), d); +} + +QTEST_APPLESS_MAIN(tst_QVector) + +#include "tst_qvectornd.moc" diff --git a/tests/auto/math3d/shared/math3dincludes.h b/tests/auto/math3d/shared/math3dincludes.h new file mode 100644 index 0000000..1ac0c08 --- /dev/null +++ b/tests/auto/math3d/shared/math3dincludes.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MATH3DINCLUDES_H +#define MATH3DINCLUDES_H + +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qgenericmatrix.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> + +#endif diff --git a/tests/auto/q3filedialog/tst_q3filedialog.cpp b/tests/auto/q3filedialog/tst_q3filedialog.cpp index 74e2894..03e1c7e 100644 --- a/tests/auto/q3filedialog/tst_q3filedialog.cpp +++ b/tests/auto/q3filedialog/tst_q3filedialog.cpp @@ -115,13 +115,15 @@ void tst_Q3FileDialog::getSetCheck() obj1.setPreviewMode(Q3FileDialog::PreviewMode(Q3FileDialog::NoPreview)); QCOMPARE(obj1.previewMode(), Q3FileDialog::PreviewMode(Q3FileDialog::NoPreview)); - // Note: Q3FileDialog does not update the previewMode read-state until the - // user has actually started navigating to a file that has a functioning - // preview. + obj1.setContentsPreviewEnabled(true); + obj1.setInfoPreviewEnabled(false); obj1.setPreviewMode(Q3FileDialog::PreviewMode(Q3FileDialog::Contents)); - QCOMPARE(obj1.previewMode(), Q3FileDialog::PreviewMode(Q3FileDialog::NoPreview)); + QCOMPARE(obj1.previewMode(), Q3FileDialog::PreviewMode(Q3FileDialog::Contents)); + + obj1.setInfoPreviewEnabled(true); + obj1.setContentsPreviewEnabled(false); obj1.setPreviewMode(Q3FileDialog::PreviewMode(Q3FileDialog::Info)); - QCOMPARE(obj1.previewMode(), Q3FileDialog::PreviewMode(Q3FileDialog::NoPreview)); + QCOMPARE(obj1.previewMode(), Q3FileDialog::PreviewMode(Q3FileDialog::Info)); } QTEST_MAIN(tst_Q3FileDialog) diff --git a/tests/auto/q3tabdialog/tst_q3tabdialog.cpp b/tests/auto/q3tabdialog/tst_q3tabdialog.cpp index 6de68fa..214cb11 100644 --- a/tests/auto/q3tabdialog/tst_q3tabdialog.cpp +++ b/tests/auto/q3tabdialog/tst_q3tabdialog.cpp @@ -60,6 +60,7 @@ public: private slots: void getSetCheck(); + void task245918_show(); }; tst_Q3TabDialog::tst_Q3TabDialog() @@ -95,5 +96,32 @@ void tst_Q3TabDialog::getSetCheck() delete var1; } +class task245918_Dialog : public Q3TabDialog +{ + Q_OBJECT +public: + task245918_Dialog() + { + QTimer::singleShot(100, this, SLOT(closeWhenVisible())); + } + + private slots: + void closeWhenVisible() + { + if (isVisible()) + accept(); + else + QTimer::singleShot(100, this, SLOT(closeWhenVisible())); + } +}; + +void tst_Q3TabDialog::task245918_show() +{ + task245918_Dialog dialog; + QSignalSpy spy(&dialog, SIGNAL(aboutToShow())); + dialog.exec(); + QCOMPARE(spy.count(), 1); +} + QTEST_MAIN(tst_Q3TabDialog) #include "tst_q3tabdialog.moc" diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index dc52416..df770b3 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -4046,7 +4046,7 @@ void tst_QAccessibility::accelerators() window->show(); QAccessibleInterface *accLineEdit = QAccessible::queryAccessibleInterface(le); - QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString(QKeySequence(Qt::ALT) + QLatin1String("L"))); + QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QKeySequence(Qt::ALT).toString() + QLatin1String("L")); label->setText(tr("Q &")); QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString()); label->setText(tr("Q &&")); @@ -4054,11 +4054,11 @@ void tst_QAccessibility::accelerators() label->setText(tr("Q && A")); QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString()); label->setText(tr("Q &&&A")); - QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString(QKeySequence(Qt::ALT) + QLatin1String("A"))); + QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QKeySequence(Qt::ALT).toString() + QLatin1String("A")); label->setText(tr("Q &&A")); QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString()); label->setText(tr("Q &A&B")); - QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QString(QKeySequence(Qt::ALT) + QLatin1String("A"))); + QCOMPARE(accLineEdit->text(QAccessible::Accelerator, 0), QKeySequence(Qt::ALT).toString() + QLatin1String("A")); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(window); diff --git a/tests/auto/qaction/tst_qaction.cpp b/tests/auto/qaction/tst_qaction.cpp index 34f2dfd..1b73f06 100644 --- a/tests/auto/qaction/tst_qaction.cpp +++ b/tests/auto/qaction/tst_qaction.cpp @@ -46,6 +46,7 @@ #include <qevent.h> #include <qaction.h> #include <qmenu.h> +#include <qlineedit.h> //TESTED_CLASS= //TESTED_FILES= @@ -74,7 +75,10 @@ private slots: void setStandardKeys(); void alternateShortcuts(); void enabledVisibleInteraction(); + void invisibleActionWithComplexShortcut(); void task200823_tooltip(); + void task229128TriggeredSignalWithoutActiongroup(); + void task229128TriggeredSignalWhenInActiongroup(); private: int m_lastEventType; @@ -109,7 +113,7 @@ class MyWidget : public QWidget { Q_OBJECT public: - MyWidget(tst_QAction *tst, QWidget *parent=0) : QWidget(parent) { this->tst = tst; } + MyWidget(tst_QAction *tst, QWidget *parent = 0) : QWidget(parent) { this->tst = tst; } protected: virtual void actionEvent(QActionEvent *e) { tst->updateState(e); } @@ -141,7 +145,7 @@ void tst_QAction::initTestCase() void tst_QAction::cleanupTestCase() { QWidget *testWidget = m_tstWidget; - if ( testWidget ) { + if (testWidget) { testWidget->hide(); delete testWidget; } @@ -189,7 +193,7 @@ void tst_QAction::updateState(QActionEvent *e) { if (!e) { m_lastEventType = 0; - m_lastAction = 0; + m_lastAction = 0; } else { m_lastEventType = (int)e->type(); m_lastAction = e->action(); @@ -249,12 +253,12 @@ void tst_QAction::alternateShortcuts() { //test the alternate shortcuts (by adding more than 1 shortcut) - QWidget *wid=m_tstWidget; + QWidget *wid = m_tstWidget; { QAction act(wid); wid->addAction(&act); - QList<QKeySequence> shlist= QList<QKeySequence>() << QKeySequence("CTRL+P") <<QKeySequence("CTRL+A"); + QList<QKeySequence> shlist = QList<QKeySequence>() << QKeySequence("CTRL+P") << QKeySequence("CTRL+A"); act.setShortcuts(shlist); QSignalSpy spy(&act, SIGNAL(triggered())); @@ -322,5 +326,77 @@ void tst_QAction::task200823_tooltip() QCOMPARE(action->toolTip(), ref); } +void tst_QAction::task229128TriggeredSignalWithoutActiongroup() +{ + // test without a group + QAction *actionWithoutGroup = new QAction("Test", qApp); + QSignalSpy spyWithoutGroup(actionWithoutGroup, SIGNAL(triggered(bool))); + QCOMPARE(spyWithoutGroup.count(), 0); + actionWithoutGroup->trigger(); + // signal should be emitted + QCOMPARE(spyWithoutGroup.count(), 1); + + // it is now a checkable checked action + actionWithoutGroup->setCheckable(true); + actionWithoutGroup->setChecked(true); + spyWithoutGroup.clear(); + QCOMPARE(spyWithoutGroup.count(), 0); + actionWithoutGroup->trigger(); + // signal should be emitted + QCOMPARE(spyWithoutGroup.count(), 1); +} + +void tst_QAction::task229128TriggeredSignalWhenInActiongroup() +{ + QActionGroup ag(0); + QAction *action = new QAction("Test", &ag); + QAction *checkedAction = new QAction("Test 2", &ag); + ag.addAction(action); + action->setCheckable(true); + ag.addAction(checkedAction); + checkedAction->setCheckable(true); + checkedAction->setChecked(true); + + QSignalSpy actionSpy(checkedAction, SIGNAL(triggered(bool))); + QSignalSpy actionGroupSpy(&ag, SIGNAL(triggered(QAction *))); + QCOMPARE(actionGroupSpy.count(), 0); + QCOMPARE(actionSpy.count(), 0); + checkedAction->trigger(); + // check that both the group and the action have emitted the signal + QCOMPARE(actionGroupSpy.count(), 1); + QCOMPARE(actionSpy.count(), 1); +} + +void tst_QAction::invisibleActionWithComplexShortcut() +{ + QAction action(0); + action.setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::Key_1)); + + QLineEdit edit; + edit.addAction(&action); + edit.show(); + QTest::qWait(100); + + QSignalSpy spy(&action, SIGNAL(triggered())); + + action.setVisible(true); + QTest::keyPress(&edit, Qt::Key_E, Qt::ControlModifier); + QTest::keyRelease(&edit, Qt::Key_E, Qt::ControlModifier); + QTest::keyPress(&edit, Qt::Key_1, Qt::NoModifier); + QTest::keyRelease(&edit, Qt::Key_1, Qt::NoModifier); + QCOMPARE(spy.count(), 1); + QCOMPARE(edit.text(), QLatin1String("")); + + edit.clear(); + spy.clear(); + action.setVisible(false); + QTest::keyPress(&edit, Qt::Key_E, Qt::ControlModifier); + QTest::keyRelease(&edit, Qt::Key_E, Qt::ControlModifier); + QTest::keyPress(&edit, Qt::Key_1, Qt::NoModifier); + QTest::keyRelease(&edit, Qt::Key_1, Qt::NoModifier); + QCOMPARE(spy.count(), 0); + QCOMPARE(edit.text(), QLatin1String("1")); +} + QTEST_MAIN(tst_QAction) #include "tst_qaction.moc" diff --git a/tests/auto/qfiledialog/tst_qfiledialog.cpp b/tests/auto/qfiledialog/tst_qfiledialog.cpp index 695bfe7..13b13d6 100644 --- a/tests/auto/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/qfiledialog/tst_qfiledialog.cpp @@ -157,6 +157,8 @@ private slots: void task228844_ensurePreviousSorting(); void task239706_editableFilterCombo(); void task218353_relativePaths(); + void task251321_sideBarHiddenEntries(); + void task251341_sideBarRemoveEntries(); private: QByteArray userSettings; @@ -1852,5 +1854,119 @@ void tst_QFiledialog::task218353_relativePaths() appDir.rmdir("test"); } +void tst_QFiledialog::task251321_sideBarHiddenEntries() +{ + QNonNativeFileDialog fd; + + QDir current = QDir::currentPath(); + current.mkdir(".hidden"); + QDir hiddenDir = QDir(".hidden"); + hiddenDir.mkdir("subdir"); + QDir hiddenSubDir = QDir(".hidden/subdir"); + hiddenSubDir.mkdir("happy"); + hiddenSubDir.mkdir("happy2"); + + QList<QUrl> urls; + urls << QUrl::fromLocalFile(hiddenSubDir.absolutePath()); + fd.setSidebarUrls(urls); + fd.show(); + QTest::qWait(250); + + QSidebar *sidebar = qFindChild<QSidebar*>(&fd, "sidebar"); + sidebar->setFocus(); + sidebar->selectUrl(QUrl::fromLocalFile(hiddenSubDir.absolutePath())); + QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, 0, sidebar->visualRect(sidebar->model()->index(0, 0)).center()); + QTest::qWait(250); + + QFileSystemModel *model = qFindChild<QFileSystemModel*>(&fd, "qt_filesystem_model"); + QCOMPARE(model->rowCount(model->index(hiddenSubDir.absolutePath())), 2); + + hiddenSubDir.rmdir("happy2"); + hiddenSubDir.rmdir("happy"); + hiddenDir.rmdir("subdir"); + current.rmdir(".hidden"); +} + +class MyQSideBar : public QSidebar +{ +public : + MyQSideBar(QWidget *parent = 0) : QSidebar(parent) + {} + + void removeSelection() { + QList<QModelIndex> idxs = selectionModel()->selectedIndexes(); + QList<QPersistentModelIndex> indexes; + for (int i = 0; i < idxs.count(); i++) + indexes.append(idxs.at(i)); + + for (int i = 0; i < indexes.count(); ++i) + if (!indexes.at(i).data(Qt::UserRole + 1).toUrl().path().isEmpty()) + model()->removeRow(indexes.at(i).row()); + } +}; + +void tst_QFiledialog::task251341_sideBarRemoveEntries() +{ + QNonNativeFileDialog fd; + + QDir current = QDir::currentPath(); + current.mkdir("testDir"); + QDir testSubDir = QDir("testDir"); + + QList<QUrl> urls; + urls << QUrl::fromLocalFile(testSubDir.absolutePath()); + urls << QUrl::fromLocalFile("NotFound"); + fd.setSidebarUrls(urls); + fd.show(); + QTest::qWait(250); + + QSidebar *sidebar = qFindChild<QSidebar*>(&fd, "sidebar"); + sidebar->setFocus(); + //We enter in the first bookmark + sidebar->selectUrl(QUrl::fromLocalFile(testSubDir.absolutePath())); + QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, 0, sidebar->visualRect(sidebar->model()->index(0, 0)).center()); + QTest::qWait(250); + + QFileSystemModel *model = qFindChild<QFileSystemModel*>(&fd, "qt_filesystem_model"); + //There is no file + QCOMPARE(model->rowCount(model->index(testSubDir.absolutePath())), 0); + //Icon is not enabled QUrlModel::EnabledRole + QVariant value = sidebar->model()->index(0, 0).data(Qt::UserRole + 2); + QCOMPARE(qvariant_cast<bool>(value), true); + + sidebar->setFocus(); + //We enter in the second bookmark which is invalid + sidebar->selectUrl(QUrl::fromLocalFile("NotFound")); + QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, 0, sidebar->visualRect(sidebar->model()->index(1, 0)).center()); + QTest::qWait(250); + + //We fallback to root because the entry in the bookmark is invalid + QCOMPARE(model->rowCount(model->index("NotFound")), model->rowCount(model->index(model->rootPath()))); + //Icon is not enabled QUrlModel::EnabledRole + value = sidebar->model()->index(1, 0).data(Qt::UserRole + 2); + QCOMPARE(qvariant_cast<bool>(value), false); + + MyQSideBar mySideBar; + mySideBar.init(model, urls); + mySideBar.show(); + mySideBar.selectUrl(QUrl::fromLocalFile(testSubDir.absolutePath())); + QTest::qWait(1000); + mySideBar.removeSelection(); + + //We remove the first entry + QList<QUrl> expected; + expected << QUrl::fromLocalFile("NotFound"); + QCOMPARE(mySideBar.urls(), expected); + + mySideBar.selectUrl(QUrl::fromLocalFile("NotFound")); + mySideBar.removeSelection(); + + //We remove the second entry + expected.clear(); + QCOMPARE(mySideBar.urls(), expected); + + current.rmdir("testDir"); +} + QTEST_MAIN(tst_QFiledialog) #include "tst_qfiledialog.moc" diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index 826d278..59d57ce 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -45,6 +45,7 @@ #include <QFileIconProvider> #include "../../shared/util.h" #include <QTime> +#include <QStyle> #include <QtGlobal> //TESTED_CLASS= @@ -284,6 +285,33 @@ void tst_QFileSystemModel::readOnly() QVERIFY(model->flags(model->index(file.fileName())) & Qt::ItemIsEditable); } +class CustomFileIconProvider : public QFileIconProvider +{ +public: + CustomFileIconProvider() : QFileIconProvider() { + mb = qApp->style()->standardIcon(QStyle::SP_MessageBoxCritical); + dvd = qApp->style()->standardIcon(QStyle::SP_DriveDVDIcon); + } + + virtual QIcon icon(const QFileInfo &info) const + { + if (info.isDir()) + return mb; + + return QFileIconProvider::icon(info); + } + virtual QIcon icon(IconType type) const + { + if (type == QFileIconProvider::Folder) + return dvd; + + return QFileIconProvider::icon(type); + } +private: + QIcon mb; + QIcon dvd; +}; + void tst_QFileSystemModel::iconProvider() { QVERIFY(model->iconProvider()); @@ -292,6 +320,19 @@ void tst_QFileSystemModel::iconProvider() QCOMPARE(model->iconProvider(), p); model->setIconProvider(0); delete p; + + QFileSystemModel *myModel = new QFileSystemModel(); + myModel->setRootPath(QDir::homePath()); + //Let's wait to populate the model + QTest::qWait(250); + //We change the provider, icons must me updated + CustomFileIconProvider *custom = new CustomFileIconProvider(); + myModel->setIconProvider(custom); + + QPixmap mb = qApp->style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(50, 50); + QCOMPARE(myModel->fileIcon(myModel->index(QDir::homePath())).pixmap(50, 50), mb); + delete myModel; + delete custom; } bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount, const QStringList &initial_dirs, const QString &dir) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 5565aa6..57e441b 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -122,6 +122,7 @@ private slots: void construction(); void constructionWithParent(); void destruction(); + void deleteChildItem(); void scene(); void parentItem(); void setParentItem(); @@ -214,6 +215,7 @@ private slots: void tabChangesFocus(); void tabChangesFocus_data(); void cacheMode(); + void updateCachedItemAfterMove(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -510,6 +512,29 @@ void tst_QGraphicsItem::destruction() QCOMPARE(itemDeleted, 59); } QCOMPARE(itemDeleted, 109); + { + QGraphicsScene *scene = new QGraphicsScene; + QGraphicsRectItem *parent = new QGraphicsRectItem; + Item *child = new Item; + child->setParentItem(parent); + parent->setVisible(false); + scene->addItem(parent); + QCOMPARE(child->parentItem(), parent); + delete scene; + QCOMPARE(itemDeleted, 110); + } +} + +void tst_QGraphicsItem::deleteChildItem() +{ + QGraphicsScene scene; + QGraphicsItem *rect = scene.addRect(QRectF()); + QGraphicsItem *child1 = new QGraphicsRectItem(rect); + QGraphicsItem *child2 = new QGraphicsRectItem(rect); + QGraphicsItem *child3 = new QGraphicsRectItem(rect); + delete child1; + child2->setParentItem(0); + delete child2; } void tst_QGraphicsItem::scene() @@ -3093,150 +3118,134 @@ protected: void mouseReleaseEvent(QGraphicsSceneMouseEvent *) { ++counter; } }; + void tst_QGraphicsItem::handlesChildEvents() { - ChildEventTester *item2_level2 = new ChildEventTester(QRectF(0, 0, 25, 25)); - ChildEventTester *item1_level1 = new ChildEventTester(QRectF(0, 0, 50, 50)); - ChildEventTester *item_level0 = new ChildEventTester(QRectF(0, 0, 100, 100)); - ChildEventTester *item1_level2 = new ChildEventTester(QRectF(0, 0, 25, 25)); - ChildEventTester *item2_level1 = new ChildEventTester(QRectF(0, 0, 50, 50)); - - item_level0->setBrush(QBrush(Qt::blue)); - item1_level1->setBrush(QBrush(Qt::red)); - item2_level1->setBrush(QBrush(Qt::yellow)); - item1_level2->setBrush(QBrush(Qt::green)); - item2_level2->setBrush(QBrush(Qt::gray)); - item1_level1->setPos(50, 0); - item2_level1->setPos(50, 50); - item1_level2->setPos(25, 0); - item2_level2->setPos(25, 25); - item1_level1->setParentItem(item_level0); - item2_level1->setParentItem(item_level0); - item1_level2->setParentItem(item1_level1); - item2_level2->setParentItem(item1_level1); + ChildEventTester *blue = new ChildEventTester(QRectF(0, 0, 100, 100)); + ChildEventTester *red = new ChildEventTester(QRectF(0, 0, 50, 50)); + ChildEventTester *green = new ChildEventTester(QRectF(0, 0, 25, 25)); + ChildEventTester *gray = new ChildEventTester(QRectF(0, 0, 25, 25)); + ChildEventTester *yellow = new ChildEventTester(QRectF(0, 0, 50, 50)); + + blue->setBrush(QBrush(Qt::blue)); + red->setBrush(QBrush(Qt::red)); + yellow->setBrush(QBrush(Qt::yellow)); + green->setBrush(QBrush(Qt::green)); + gray->setBrush(QBrush(Qt::gray)); + red->setPos(50, 0); + yellow->setPos(50, 50); + green->setPos(25, 0); + gray->setPos(25, 25); + red->setParentItem(blue); + yellow->setParentItem(blue); + green->setParentItem(red); + gray->setParentItem(red); QGraphicsScene scene; - scene.addItem(item_level0); - - // Pull out the items, closest item first - QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect()); - QCOMPARE(items.at(4), (QGraphicsItem *)item_level0); - if (item1_level1 < item2_level1) { - QCOMPARE(items.at(3), (QGraphicsItem *)item1_level1); - if (item1_level2 < item2_level2) { - QCOMPARE(items.at(2), (QGraphicsItem *)item1_level2); - QCOMPARE(items.at(1), (QGraphicsItem *)item2_level2); - } else { - QCOMPARE(items.at(2), (QGraphicsItem *)item2_level2); - QCOMPARE(items.at(1), (QGraphicsItem *)item1_level2); - } - QCOMPARE(items.at(0), (QGraphicsItem *)item2_level1); - } else { - QCOMPARE(items.at(3), (QGraphicsItem *)item2_level1); - QCOMPARE(items.at(2), (QGraphicsItem *)item1_level1); - if (item1_level2 < item2_level2) { - QCOMPARE(items.at(1), (QGraphicsItem *)item1_level2); - QCOMPARE(items.at(0), (QGraphicsItem *)item2_level2); - } else { - QCOMPARE(items.at(1), (QGraphicsItem *)item2_level2); - QCOMPARE(items.at(0), (QGraphicsItem *)item1_level2); - } - } + scene.addItem(blue); QGraphicsView view(&scene); view.show(); QTest::qWait(1000); - QCOMPARE(item_level0->counter, 0); + // Pull out the items, closest item first + QList<QGraphicsItem *> items = scene.items(scene.itemsBoundingRect()); + QCOMPARE(items.at(0), (QGraphicsItem *)yellow); + QCOMPARE(items.at(1), (QGraphicsItem *)gray); + QCOMPARE(items.at(2), (QGraphicsItem *)green); + QCOMPARE(items.at(3), (QGraphicsItem *)red); + QCOMPARE(items.at(4), (QGraphicsItem *)blue); + + QCOMPARE(blue->counter, 0); // Send events to the toplevel item QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress); QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease); pressEvent.setButton(Qt::LeftButton); - pressEvent.setScenePos(item_level0->mapToScene(5, 5)); + pressEvent.setScenePos(blue->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); releaseEvent.setButton(Qt::LeftButton); - releaseEvent.setScenePos(item_level0->mapToScene(5, 5)); + releaseEvent.setScenePos(blue->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 2); + QCOMPARE(blue->counter, 2); // Send events to a level1 item - pressEvent.setScenePos(item1_level1->mapToScene(5, 5)); + pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level1->mapToScene(5, 5)); + releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 2); - QCOMPARE(item1_level1->counter, 2); + QCOMPARE(blue->counter, 2); + QCOMPARE(red->counter, 2); // Send events to a level2 item - pressEvent.setScenePos(item1_level2->mapToScene(5, 5)); + pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level2->mapToScene(5, 5)); + releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 2); - QCOMPARE(item1_level1->counter, 2); - QCOMPARE(item1_level2->counter, 2); + QCOMPARE(blue->counter, 2); + QCOMPARE(red->counter, 2); + QCOMPARE(green->counter, 2); - item_level0->setHandlesChildEvents(true); + blue->setHandlesChildEvents(true); // Send events to a level1 item - pressEvent.setScenePos(item1_level1->mapToScene(5, 5)); + pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level1->mapToScene(5, 5)); + releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 4); - QCOMPARE(item1_level1->counter, 2); + QCOMPARE(blue->counter, 4); + QCOMPARE(red->counter, 2); // Send events to a level2 item - pressEvent.setScenePos(item1_level2->mapToScene(5, 5)); + pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level2->mapToScene(5, 5)); + releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 6); - QCOMPARE(item1_level1->counter, 2); - QCOMPARE(item1_level2->counter, 2); + QCOMPARE(blue->counter, 6); + QCOMPARE(red->counter, 2); + QCOMPARE(green->counter, 2); - item_level0->setHandlesChildEvents(false); + blue->setHandlesChildEvents(false); // Send events to a level1 item - pressEvent.setScenePos(item1_level1->mapToScene(5, 5)); + pressEvent.setScenePos(red->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level1->mapToScene(5, 5)); + releaseEvent.setScenePos(red->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 6); - QCOMPARE(item1_level1->counter, 4); + QCOMPARE(blue->counter, 6); + QCOMPARE(red->counter, 4); // Send events to a level2 item - pressEvent.setScenePos(item1_level2->mapToScene(5, 5)); + pressEvent.setScenePos(green->mapToScene(5, 5)); pressEvent.setScreenPos(view.mapFromScene(pressEvent.scenePos())); - releaseEvent.setScenePos(item1_level2->mapToScene(5, 5)); + releaseEvent.setScenePos(green->mapToScene(5, 5)); releaseEvent.setScreenPos(view.mapFromScene(releaseEvent.scenePos())); QApplication::sendEvent(&scene, &pressEvent); QApplication::sendEvent(&scene, &releaseEvent); - QCOMPARE(item_level0->counter, 6); - QCOMPARE(item1_level1->counter, 4); - QCOMPARE(item1_level2->counter, 4); + QCOMPARE(blue->counter, 6); + QCOMPARE(red->counter, 4); + QCOMPARE(green->counter, 4); } void tst_QGraphicsItem::handlesChildEvents2() @@ -3654,6 +3663,8 @@ void tst_QGraphicsItem::defaultItemTest_QGraphicsEllipseItem() class ItemChangeTester : public QGraphicsRectItem { public: + ItemChangeTester(){} + ItemChangeTester(QGraphicsItem *parent) : QGraphicsRectItem(parent) {} QVariant itemChangeReturnValue; QGraphicsScene *itemSceneChangeTargetScene; @@ -3830,6 +3841,20 @@ void tst_QGraphicsItem::itemChange() QCOMPARE(tester.pos(), QPointF(42, 0)); } { + // ItemZValueChange / ItemZValueHasChanged + tester.itemChangeReturnValue = qreal(2.0); + tester.setZValue(1.0); + ++changeCount; // notification sent too + ++changeCount; + QCOMPARE(tester.changes.size(), changeCount); + QCOMPARE(tester.changes.at(tester.changes.size() - 2), QGraphicsItem::ItemZValueChange); + QCOMPARE(tester.changes.at(tester.changes.size() - 1), QGraphicsItem::ItemZValueHasChanged); + QCOMPARE(tester.values.at(tester.changes.size() - 2), QVariant(qreal(1.0))); + QCOMPARE(tester.values.at(tester.changes.size() - 1), QVariant(qreal(2.0))); + QCOMPARE(tester.oldValues.last(), QVariant(qreal(0.0))); + QCOMPARE(tester.zValue(), qreal(2.0)); + } + { // ItemFlagsChange tester.itemChangeReturnValue = QGraphicsItem::ItemIsSelectable; tester.setFlag(QGraphicsItem::ItemIsSelectable, false); @@ -3928,6 +3953,39 @@ void tst_QGraphicsItem::itemChange() QCOMPARE(tester.changes.size(), ++changeCount); QCOMPARE(tester.changes.last(), QGraphicsItem::ItemChildRemovedChange); QCOMPARE(qVariantValue<QGraphicsItem *>(tester.values.last()), (QGraphicsItem *)&testerHelper); + + // ItemChildRemovedChange 1 + ItemChangeTester *test = new ItemChangeTester; + test->itemSceneChangeTargetScene = 0; + int count = 0; + QGraphicsScene *scene = new QGraphicsScene; + scene->addItem(test); + count = test->changes.size(); + //We test here the fact that when a child is deleted the parent receive only one ItemChildRemovedChange + QGraphicsRectItem *child = new QGraphicsRectItem(test); + //We received ItemChildAddedChange + QCOMPARE(test->changes.size(), ++count); + QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildAddedChange); + delete child; + child = 0; + QCOMPARE(test->changes.size(), ++count); + QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange); + + ItemChangeTester *childTester = new ItemChangeTester(test); + //Changes contains all sceneHasChanged and so on, we don't want to test that + int childCount = childTester->changes.size(); + //We received ItemChildAddedChange + QCOMPARE(test->changes.size(), ++count); + child = new QGraphicsRectItem(childTester); + //We received ItemChildAddedChange + QCOMPARE(childTester->changes.size(), ++childCount); + QCOMPARE(childTester->changes.last(), QGraphicsItem::ItemChildAddedChange); + //Delete the child of the top level with all its children + delete childTester; + //Only one removal + QCOMPARE(test->changes.size(), ++count); + QCOMPARE(test->changes.last(), QGraphicsItem::ItemChildRemovedChange); + delete scene; } { // ItemChildRemovedChange 2 @@ -4605,7 +4663,7 @@ void tst_QGraphicsItem::itemClipsChildrenToShape2() QPainter painter(&image); scene.render(&painter); painter.end(); - + QCOMPARE(image.pixel(5, 5), QColor(0, 0, 255).rgba()); QCOMPARE(image.pixel(5, 10), QRgb(0)); QCOMPARE(image.pixel(10, 5), QRgb(0)); @@ -5262,7 +5320,7 @@ void tst_QGraphicsItem::task240400_clickOnTextItem() QVERIFY(selectable ? item->isSelected() : !item->isSelected()); - // + // if (textFlags & Qt::TextEditorInteraction) QVERIFY(item->textCursor().columnNumber() > column); else @@ -5308,7 +5366,7 @@ void tst_QGraphicsItem::task243707_addChildBeforeParent() // inconsistent internal state that can cause a crash. This test shows // one such crash. QGraphicsScene scene; - QGraphicsWidget *widget = new QGraphicsWidget; + QGraphicsWidget *widget = new QGraphicsWidget; QGraphicsWidget *widget2 = new QGraphicsWidget(widget); scene.addItem(widget2); QVERIFY(!widget2->parentItem()); @@ -5424,7 +5482,7 @@ void tst_QGraphicsItem::itemTransform_unrelated() QCOMPARE(stranger1->itemTransform(stranger2).map(QPointF(10, 10)), QPointF(10, 10)); QCOMPARE(stranger2->itemTransform(stranger1).map(QPointF(10, 10)), QPointF(10, 10)); } - + void tst_QGraphicsItem::opacity_data() { QTest::addColumn<qreal>("p_opacity"); @@ -5633,7 +5691,7 @@ void tst_QGraphicsItem::nestedClipping() l1->setData(0, "l1"); l2->setData(0, "l2"); l3->setData(0, "l3"); - + QGraphicsView view(&scene); view.show(); #ifdef Q_WS_X11 @@ -5661,7 +5719,7 @@ void tst_QGraphicsItem::nestedClipping() QCOMPARE(image.pixel(80, 130), qRgba(255, 255, 0, 255)); QCOMPARE(image.pixel(92, 105), qRgba(0, 255, 0, 255)); QCOMPARE(image.pixel(105, 105), qRgba(0, 0, 255, 255)); -#if 0 +#if 0 // Enable this to compare if the test starts failing. image.save("nestedClipping_reference.png"); #endif @@ -5803,7 +5861,7 @@ void tst_QGraphicsItem::tabChangesFocus_data() void tst_QGraphicsItem::tabChangesFocus() { QFETCH(bool, tabChangesFocus); - + QGraphicsScene scene; QGraphicsTextItem *item = scene.addText("Hello"); item->setTabChangesFocus(tabChangesFocus); @@ -6038,5 +6096,46 @@ void tst_QGraphicsItem::cacheMode() QCOMPARE(testerChild2->repaints, 6); } +void tst_QGraphicsItem::updateCachedItemAfterMove() +{ + // A simple item that uses ItemCoordinateCache + EventTester *tester = new EventTester; + tester->setCacheMode(QGraphicsItem::ItemCoordinateCache); + + // Add to a scene, show in a view, ensure it's painted and reset its + // repaint counter. + QGraphicsScene scene; + scene.addItem(tester); + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(125); + tester->repaints = 0; + + // Move the item, should not cause repaints + tester->setPos(10, 0); + QTest::qWait(125); + QCOMPARE(tester->repaints, 0); + + // Move then update, should cause one repaint + tester->setPos(20, 0); + tester->update(); + QTest::qWait(125); + QCOMPARE(tester->repaints, 1); + + // Hiding the item doesn't cause a repaint + tester->hide(); + QTest::qWait(125); + QCOMPARE(tester->repaints, 1); + + // Moving a hidden item doesn't cause a repaint + tester->setPos(30, 0); + tester->update(); + QTest::qWait(125); + QCOMPARE(tester->repaints, 1); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" diff --git a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index b99f111..d856024 100644 --- a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -175,6 +175,9 @@ private slots: void bypassGraphicsProxyWidget_data(); void bypassGraphicsProxyWidget(); void dragDrop(); + void windowFlags_data(); + void windowFlags(); + void comboboxWindowFlags(); }; // Subclass that exposes the protected functions. @@ -3153,6 +3156,67 @@ void tst_QGraphicsProxyWidget::dragDrop() QCOMPARE(edit->text(), QString("hei")); } +void tst_QGraphicsProxyWidget::windowFlags_data() +{ + QTest::addColumn<int>("proxyFlags"); + QTest::addColumn<int>("widgetFlags"); + QTest::addColumn<int>("resultingProxyFlags"); + QTest::addColumn<int>("resultingWidgetFlags"); + + QTest::newRow("proxy(0) widget(0)") << 0 << 0 << 0 << int(Qt::Window); + QTest::newRow("proxy(window)") << int(Qt::Window) << 0 << int(Qt::Window) << int(Qt::Window); + QTest::newRow("proxy(window) widget(window)") << int(Qt::Window) << int(Qt::Window) << int(Qt::Window) << int(Qt::Window); + QTest::newRow("proxy(0) widget(window)") << int(0) << int(Qt::Window) << int(0) << int(Qt::Window); +} + +void tst_QGraphicsProxyWidget::windowFlags() +{ + QFETCH(int, proxyFlags); + QFETCH(int, widgetFlags); + QFETCH(int, resultingProxyFlags); + QFETCH(int, resultingWidgetFlags); + Qt::WindowFlags proxyWFlags = Qt::WindowFlags(proxyFlags); + Qt::WindowFlags widgetWFlags = Qt::WindowFlags(widgetFlags); + Qt::WindowFlags resultingProxyWFlags = Qt::WindowFlags(resultingProxyFlags); + Qt::WindowFlags resultingWidgetWFlags = Qt::WindowFlags(resultingWidgetFlags); + + QGraphicsProxyWidget proxy(0, proxyWFlags); + QVERIFY((proxy.windowFlags() & proxyWFlags) == proxyWFlags); + + QWidget *widget = new QWidget(0, widgetWFlags); + QVERIFY((widget->windowFlags() & widgetWFlags) == widgetWFlags); + + proxy.setWidget(widget); + + if (resultingProxyFlags == 0) + QVERIFY(!proxy.windowFlags()); + else + QVERIFY((proxy.windowFlags() & resultingProxyWFlags) == resultingProxyWFlags); + QVERIFY((widget->windowFlags() & resultingWidgetWFlags) == resultingWidgetWFlags); +} + +void tst_QGraphicsProxyWidget::comboboxWindowFlags() +{ + QComboBox *comboBox = new QComboBox; + comboBox->addItem("Item 1"); + comboBox->addItem("Item 2"); + comboBox->addItem("Item 3"); + QWidget *embedWidget = comboBox; + + QGraphicsScene scene; + QGraphicsProxyWidget *proxy = scene.addWidget(embedWidget); + proxy->setWindowFlags(Qt::Window); + QVERIFY(embedWidget->isWindow()); + QVERIFY(proxy->isWindow()); + + comboBox->showPopup(); + + QCOMPARE(proxy->childItems().size(), 1); + QGraphicsItem *popupProxy = proxy->childItems().first(); + QVERIFY(popupProxy->isWindow()); + QVERIFY((static_cast<QGraphicsWidget *>(popupProxy)->windowFlags() & Qt::Popup) == Qt::Popup); +} + QTEST_MAIN(tst_QGraphicsProxyWidget) #include "tst_qgraphicsproxywidget.moc" diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index b5af115..ca88afc 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -72,6 +72,7 @@ Q_DECLARE_METATYPE(QList<QRectF>) Q_DECLARE_METATYPE(QMatrix) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(QPointF) +Q_DECLARE_METATYPE(QPolygonF) Q_DECLARE_METATYPE(QRectF) Q_DECLARE_METATYPE(Qt::ScrollBarPolicy) @@ -159,6 +160,7 @@ private slots: void itemAt2(); void mapToScene(); void mapToScenePoint(); + void mapToSceneRect_data(); void mapToSceneRect(); void mapToScenePoly(); void mapToScenePath(); @@ -187,6 +189,7 @@ private slots: void scrollAfterResize_data(); void scrollAfterResize(); void centerOnDirtyItem(); + void mouseTracking(); // task specific tests below me void task172231_untransformableItems(); @@ -1611,23 +1614,51 @@ void tst_QGraphicsView::mapToScenePoint() view.mapToScene(center) + QPointF(0, -10)); } +void tst_QGraphicsView::mapToSceneRect_data() +{ + QTest::addColumn<QRect>("viewRect"); + QTest::addColumn<QPolygonF>("scenePoly"); + QTest::addColumn<qreal>("rotation"); + + QTest::newRow("nil") << QRect() << QPolygonF() << qreal(0); + QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1) << QPolygonF(QRectF(0, 0, 1, 1)) << qreal(0); + QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10) << QPolygonF(QRectF(0, 0, 10, 10)) << qreal(0); + QTest::newRow("nil") << QRect() << QPolygonF() << qreal(90); + QPolygonF p; + p << QPointF(0, 0) << QPointF(0, -1) << QPointF(1, -1) << QPointF(1, 0) << QPointF(0, 0); + QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1) + << p + << qreal(90); + p.clear(); + p << QPointF(0, 0) << QPointF(0, -10) << QPointF(10, -10) << QPointF(10, 0) << QPointF(0, 0); + QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10) + << p + << qreal(90); +} + void tst_QGraphicsView::mapToSceneRect() { - QGraphicsScene scene; + QFETCH(QRect, viewRect); + QFETCH(QPolygonF, scenePoly); + QFETCH(qreal, rotation); + + QGraphicsScene scene(-1000, -1000, 2000, 2000); + scene.addRect(25, -25, 50, 50); QGraphicsView view(&scene); - view.rotate(90); - view.setFixedSize(117, 117); + view.setFrameStyle(0); + view.setAlignment(Qt::AlignTop | Qt::AlignLeft); + view.setFixedSize(200, 200); + view.setTransformationAnchor(QGraphicsView::NoAnchor); + view.setResizeAnchor(QGraphicsView::NoAnchor); view.show(); - QPoint center = view.viewport()->rect().center(); - QRect rect(center + QPoint(10, 0), QSize(10, 10)); - QPolygonF poly; - poly << view.mapToScene(rect.topLeft()); - poly << view.mapToScene(rect.topRight()); - poly << view.mapToScene(rect.bottomRight()); - poly << view.mapToScene(rect.bottomLeft()); + view.rotate(rotation); + + QPolygonF poly = view.mapToScene(viewRect); + if (!poly.isEmpty()) + poly << poly[0]; - QCOMPARE(view.mapToScene(rect), poly); + QCOMPARE(poly, scenePoly); } void tst_QGraphicsView::mapToScenePoly() @@ -2511,7 +2542,8 @@ void tst_QGraphicsView::replayMouseMove() // One mouse event should be translated into one scene event. for (int i = 0; i < 3; ++i) { - sendMouseMove(view.viewport(), view.viewport()->rect().center()); + sendMouseMove(view.viewport(), view.viewport()->rect().center(), + Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton)); QCOMPARE(viewSpy.count(), i + 1); QCOMPARE(sceneSpy.count(), i + 1); } @@ -2701,6 +2733,7 @@ void tst_QGraphicsView::task186827_deleteReplayedItem() MouseMoveCounter view; view.setScene(&scene); view.show(); + view.viewport()->setMouseTracking(true); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif @@ -3044,5 +3077,101 @@ void tst_QGraphicsView::centerOnDirtyItem() QCOMPARE(before, after); } +void tst_QGraphicsView::mouseTracking() +{ + // Mouse tracking should only be automatically enabled if items either accept hover events + // or have a cursor set. We never disable mouse tracking if it is already enabled. + + { // Make sure mouse tracking is disabled by default. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + QVERIFY(!view.viewport()->hasMouseTracking()); + } + + { // Make sure we don't disable mouse tracking in setupViewport/setScene. + QGraphicsView view; + QWidget *viewport = new QWidget; + viewport->setMouseTracking(true); + view.setViewport(viewport); + QVERIFY(viewport->hasMouseTracking()); + + QGraphicsScene scene(-10000, -10000, 20000, 20000); + view.setScene(&scene); + QVERIFY(viewport->hasMouseTracking()); + } + + // Make sure we enable mouse tracking when having items that accept hover events. + { + // Adding an item to the scene after the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setAcceptHoverEvents(true); + scene.addItem(item); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // Adding an item to the scene before the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setAcceptHoverEvents(true); + scene.addItem(item); + + QGraphicsView view(&scene); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // QGraphicsWidget implicitly accepts hover if it has window decoration. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsWidget *widget = new QGraphicsWidget; + scene.addItem(widget); + QVERIFY(!view.viewport()->hasMouseTracking()); + // Enable window decoraton. + widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint); + QVERIFY(view.viewport()->hasMouseTracking()); + } + + // Make sure we enable mouse tracking when having items with a cursor set. + { + // Adding an item to the scene after the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + QVERIFY(view.viewport()->hasMouseTracking()); + } + { + // Adding an item to the scene before the scene is set on the view. + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + + QGraphicsView view(&scene); + QVERIFY(view.viewport()->hasMouseTracking()); + } + + // Make sure we propagate mouse tracking to all views. + { + QGraphicsScene scene(-10000, -10000, 20000, 20000); + QGraphicsView view1(&scene); + QGraphicsView view2(&scene); + QGraphicsView view3(&scene); + + QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); + item->setCursor(Qt::CrossCursor); + scene.addItem(item); + + QVERIFY(view1.viewport()->hasMouseTracking()); + QVERIFY(view2.viewport()->hasMouseTracking()); + QVERIFY(view3.viewport()->hasMouseTracking()); + } +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp index f25a079..56737c3 100644 --- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp @@ -146,6 +146,11 @@ private slots: void setSizes(); void closePopupOnOutsideClick(); void defaultSize(); + void explicitMouseGrabber(); + void implicitMouseGrabber(); + void popupMouseGrabber(); + void windowFlags_data(); + void windowFlags(); // Task fixes void task236127_bspTreeIndexFails(); @@ -1732,6 +1737,10 @@ void tst_QGraphicsWidget::task236127_bspTreeIndexFails() widget->resize(10, 10); widget2->resize(10, 10); widget2->setZValue(1); + QCOMPARE(widget2->zValue(), qreal(1)); + QCOMPARE(widget->zValue(), qreal(0)); + widget->setData(0, "widget"); + widget2->setData(0, "widget2"); QGraphicsScene scene; scene.addItem(widget); @@ -1742,7 +1751,7 @@ void tst_QGraphicsWidget::task236127_bspTreeIndexFails() #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif - QTest::qWait(50); + QTest::qWait(100); QVERIFY(!scene.itemAt(25, 25)); widget->setGeometry(0, 112, 360, 528); @@ -1780,6 +1789,382 @@ void tst_QGraphicsWidget::defaultSize() } +void tst_QGraphicsWidget::explicitMouseGrabber() +{ + QGraphicsWidget *widget = new QGraphicsWidget; + EventSpy widgetGrabEventSpy(widget, QEvent::GrabMouse); + EventSpy widgetUngrabEventSpy(widget, QEvent::UngrabMouse); + + // Grab without scene + QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::grabMouse: cannot grab mouse without scene"); + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 0); + QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::ungrabMouse: cannot ungrab mouse without scene"); + widget->ungrabMouse(); + QCOMPARE(widgetUngrabEventSpy.count(), 0); + + // Add to scene + QGraphicsScene scene; + scene.addItem(widget); + + // Ungrab while not grabber + QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::ungrabMouse: not a mouse grabber"); + widget->ungrabMouse(); + + // Simple grab with scene + QVERIFY(!scene.mouseGrabberItem()); + widget->grabMouse(); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 1); + widget->ungrabMouse(); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + QCOMPARE(widgetUngrabEventSpy.count(), 1); + + // Grab while grabbing + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 2); + QTest::ignoreMessage(QtWarningMsg, "QGraphicsItem::grabMouse: already a mouse grabber"); + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 2); + QCOMPARE(widgetUngrabEventSpy.count(), 1); + widget->ungrabMouse(); + QCOMPARE(widgetUngrabEventSpy.count(), 2); + + // Add two more widgets to the scene + QGraphicsWidget *widget2 = new QGraphicsWidget; + scene.addItem(widget2); + EventSpy widget2GrabEventSpy(widget2, QEvent::GrabMouse); + EventSpy widget2UngrabEventSpy(widget2, QEvent::UngrabMouse); + QGraphicsWidget *widget3 = new QGraphicsWidget; + scene.addItem(widget3); + EventSpy widget3GrabEventSpy(widget3, QEvent::GrabMouse); + EventSpy widget3UngrabEventSpy(widget3, QEvent::UngrabMouse); + + widget->setData(0, "widget"); + widget2->setData(0, "widget2"); + widget3->setData(0, "widget3"); + + // Simple nested grabbing + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 3); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + widget2->grabMouse(); + QCOMPARE(widgetUngrabEventSpy.count(), 3); + QCOMPARE(widget2GrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + widget3->grabMouse(); + QCOMPARE(widget2UngrabEventSpy.count(), 1); + QCOMPARE(widget3GrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget3); + widget3->ungrabMouse(); + QCOMPARE(widget3UngrabEventSpy.count(), 1); + QCOMPARE(widget2GrabEventSpy.count(), 2); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + widget2->ungrabMouse(); + QCOMPARE(widget2UngrabEventSpy.count(), 2); + QCOMPARE(widgetGrabEventSpy.count(), 4); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + widget->ungrabMouse(); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + + // Out of order ungrab + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 5); + widget2->grabMouse(); + QCOMPARE(widget2GrabEventSpy.count(), 3); + widget3->grabMouse(); + QCOMPARE(widget3GrabEventSpy.count(), 2); + widget2->ungrabMouse(); + QCOMPARE(widget3UngrabEventSpy.count(), 2); + QCOMPARE(widget2UngrabEventSpy.count(), 4); + QCOMPARE(widgetGrabEventSpy.count(), 6); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); +} + +void tst_QGraphicsWidget::implicitMouseGrabber() +{ + QGraphicsScene scene; + QGraphicsWidget *widget = new QGraphicsWidget; + widget->setFlag(QGraphicsItem::ItemIsMovable); // can grab mouse + widget->resize(200, 200); + EventSpy widgetGrabEventSpy(widget, QEvent::GrabMouse); + EventSpy widgetUngrabEventSpy(widget, QEvent::UngrabMouse); + scene.addItem(widget); + + QVERIFY(!scene.mouseGrabberItem()); + + // Click on an item, see if gain and lose implicit mouse grab. + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 1); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + QCOMPARE(widgetGrabEventSpy.count(), 1); + QCOMPARE(widgetUngrabEventSpy.count(), 1); + + // Click on an item that already grabs the mouse. Shouldn't have any effect. + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 2); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 2); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 2); + QCOMPARE(widgetUngrabEventSpy.count(), 1); + widget->ungrabMouse(); + QCOMPARE(widgetUngrabEventSpy.count(), 2); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + + // Implicit mouse grabber tries to explicitly grab the mouse + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 3); + widget->grabMouse(); + QCOMPARE(widgetUngrabEventSpy.count(), 2); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMouseRelease); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(50, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 3); + QCOMPARE(widgetUngrabEventSpy.count(), 2); + widget->ungrabMouse(); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + QCOMPARE(widgetGrabEventSpy.count(), 3); + QCOMPARE(widgetUngrabEventSpy.count(), 3); + + // Arrival of a new widget + QGraphicsWidget *widget2 = new QGraphicsWidget; + widget2->setFlag(QGraphicsItem::ItemIsMovable); // can grab mouse + widget2->resize(200, 200); + widget2->setPos(205, 0); + EventSpy widget2GrabEventSpy(widget2, QEvent::GrabMouse); + EventSpy widget2UngrabEventSpy(widget2, QEvent::UngrabMouse); + scene.addItem(widget2); + + // Implicit grab while there's an explicit grab is not possible. + widget->grabMouse(); + QCOMPARE(widgetGrabEventSpy.count(), 4); + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(250, 50)); + qApp->sendEvent(&scene, &event); + } + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + QCOMPARE(widgetGrabEventSpy.count(), 4); + QCOMPARE(widget2GrabEventSpy.count(), 0); + QCOMPARE(widget2UngrabEventSpy.count(), 0); + + scene.removeItem(widget); + QCOMPARE(widgetUngrabEventSpy.count(), 4); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); +} + +void tst_QGraphicsWidget::popupMouseGrabber() +{ + QGraphicsScene scene; + QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Popup); + widget->setFlag(QGraphicsItem::ItemIsMovable); // can grab mouse + widget->resize(200, 200); + EventSpy widgetGrabEventSpy(widget, QEvent::GrabMouse); + EventSpy widgetUngrabEventSpy(widget, QEvent::UngrabMouse); + + // Simply adding a visible popup to the scene immediately grabs the mouse. + scene.addItem(widget); + QCOMPARE(widgetGrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + + // Hiding it loses the grab again. + widget->hide(); + QCOMPARE(widgetUngrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)0); + + // Showing it grabs the mosue again + widget->show(); + QCOMPARE(widgetGrabEventSpy.count(), 2); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget); + + // Add two popups + QGraphicsWidget *widget2 = new QGraphicsWidget(0, Qt::Popup); + widget2->setFlag(QGraphicsItem::ItemIsMovable); // can grab mouse + widget2->resize(200, 200); + EventSpy widget2GrabEventSpy(widget2, QEvent::GrabMouse); + EventSpy widget2UngrabEventSpy(widget2, QEvent::UngrabMouse); + QGraphicsWidget *widget3 = new QGraphicsWidget(0, Qt::Popup); + widget3->setFlag(QGraphicsItem::ItemIsMovable); // can grab mouse + widget3->resize(200, 200); + EventSpy widget3GrabEventSpy(widget3, QEvent::GrabMouse); + EventSpy widget3UngrabEventSpy(widget3, QEvent::UngrabMouse); + + // Adding to the scene grabs + scene.addItem(widget2); + QCOMPARE(widgetUngrabEventSpy.count(), 2); + QCOMPARE(widget2GrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + + // Adding to the scene grabs again + scene.addItem(widget3); + QCOMPARE(widget2UngrabEventSpy.count(), 1); + QCOMPARE(widget3GrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget3); + + // Hiding the topmost widget causes widget 2 to regain grab. + widget3->hide(); + QCOMPARE(widget2GrabEventSpy.count(), 2); + QCOMPARE(widget3UngrabEventSpy.count(), 1); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + widget3->show(); + QCOMPARE(widget2UngrabEventSpy.count(), 2); + QCOMPARE(widget3GrabEventSpy.count(), 2); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget3); + + // Clicking outside the popup still causes it to close (despite that it's + // an explicit mouse grabber). + { + QGraphicsSceneMouseEvent event(QEvent::GraphicsSceneMousePress); + event.ignore(); + event.setButton(Qt::LeftButton); + event.setScenePos(QPointF(500, 500)); // outside + qApp->sendEvent(&scene, &event); + } + QVERIFY(!widget3->isVisible()); + QCOMPARE(widget3UngrabEventSpy.count(), 2); + QCOMPARE(widget2GrabEventSpy.count(), 3); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + QVERIFY(widget2->isVisible()); + QVERIFY(widget->isVisible()); + widget3->show(); + QCOMPARE(widget3GrabEventSpy.count(), 3); + QCOMPARE(widget2UngrabEventSpy.count(), 3); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget3); + + // This is something of a curiosity. What happens if you call + // ungrabMouse() on a popup? The answer is - it loses the grab. If you + // hide and show the popup again, it will regain the grab. + widget3->ungrabMouse(); + QCOMPARE(widget3UngrabEventSpy.count(), 3); + QCOMPARE(widget2GrabEventSpy.count(), 4); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget2); + widget3->hide(); + widget3->show(); + QCOMPARE(widget3GrabEventSpy.count(), 4); + QCOMPARE(widget2UngrabEventSpy.count(), 4); + QCOMPARE(scene.mouseGrabberItem(), (QGraphicsItem *)widget3); +} + +void tst_QGraphicsWidget::windowFlags_data() +{ + QTest::addColumn<int>("inputFlags"); + QTest::addColumn<int>("outputFlags"); + + QTest::newRow("nil") << 0 << 0; + + // Window types + QTest::newRow("Qt::Window") << int(Qt::Window) + << int(Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint + | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + QTest::newRow("Qt::SubWindow") << int(Qt::SubWindow) + << int(Qt::SubWindow | Qt::WindowTitleHint | Qt::WindowSystemMenuHint + | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + QTest::newRow("Qt::Dialog") << int(Qt::Dialog) + << int(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint + | Qt::WindowContextHelpButtonHint); + QTest::newRow("Qt::Sheet") << int(Qt::Sheet) + << int(Qt::Sheet | Qt::WindowTitleHint | Qt::WindowSystemMenuHint + | Qt::WindowContextHelpButtonHint); + QTest::newRow("Qt::Tool") << int(Qt::Tool) + << int(Qt::Tool | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + + // Custom window flags + QTest::newRow("Qt::FramelessWindowHint") << int(Qt::FramelessWindowHint) + << int(Qt::FramelessWindowHint); + QTest::newRow("Qt::CustomizeWindowHint") << int(Qt::CustomizeWindowHint) + << int(Qt::CustomizeWindowHint); +} + +void tst_QGraphicsWidget::windowFlags() +{ + QFETCH(int, inputFlags); + QFETCH(int, outputFlags); + + // Construct with flags set already + QGraphicsWidget widget(0, Qt::WindowFlags(inputFlags)); + QCOMPARE(widget.windowFlags(), Qt::WindowFlags(outputFlags)); + + // Set flags after construction + QGraphicsWidget widget2; + widget2.setWindowFlags(Qt::WindowFlags(inputFlags)); + QCOMPARE(widget2.windowFlags(), Qt::WindowFlags(outputFlags)); + + // Reset flags + widget2.setWindowFlags(0); + QVERIFY(!widget2.windowFlags()); + + // Set flags back again + widget2.setWindowFlags(Qt::WindowFlags(inputFlags)); + QCOMPARE(widget2.windowFlags(), Qt::WindowFlags(outputFlags)); + + // Construct with custom flags set already + QGraphicsWidget widget3(0, Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + QCOMPARE(widget3.windowFlags(), Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + + // Set custom flags after construction + QGraphicsWidget widget4; + widget4.setWindowFlags(Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + QCOMPARE(widget4.windowFlags(), Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + + // Reset flags + widget4.setWindowFlags(0); + QVERIFY(!widget4.windowFlags()); + + // Set custom flags back again + widget4.setWindowFlags(Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + QCOMPARE(widget4.windowFlags(), Qt::WindowFlags(inputFlags | Qt::FramelessWindowHint)); + + QGraphicsWidget *widget5 = new QGraphicsWidget; + widget5->setWindowFlags(Qt::WindowFlags(inputFlags)); + QCOMPARE(widget5->windowFlags(), Qt::WindowFlags(outputFlags)); + QGraphicsWidget window(0, Qt::Window); + widget5->setParentItem(&window); + QCOMPARE(widget5->windowFlags(), Qt::WindowFlags(outputFlags)); +} + class ProxyStyle : public QCommonStyle { public: diff --git a/tests/auto/qheaderview/tst_qheaderview.cpp b/tests/auto/qheaderview/tst_qheaderview.cpp index 0867e48..6478854 100644 --- a/tests/auto/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/qheaderview/tst_qheaderview.cpp @@ -187,6 +187,7 @@ private slots: void emptySectionSpan(); void task236450_hidden_data(); void task236450_hidden(); + void task248050_hideRow(); protected: QHeaderView *view; @@ -1919,5 +1920,28 @@ void tst_QHeaderView::task236450_hidden() } +void tst_QHeaderView::task248050_hideRow() +{ + //this is the sequence of events that make the task fail + protected_QHeaderView header(Qt::Vertical); + QStandardItemModel model(0, 1); + header.setStretchLastSection(false); + header.setDefaultSectionSize(17); + header.setModel(&model); + header.doItemsLayout(); + + model.setRowCount(3); + + QCOMPARE(header.sectionPosition(2), 17*2); + + header.hideSection(1); + QCOMPARE(header.sectionPosition(2), 17); + + QTest::qWait(100); + //the size of the section shouldn't have changed + QCOMPARE(header.sectionPosition(2), 17); +} + + QTEST_MAIN(tst_QHeaderView) #include "tst_qheaderview.moc" diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index 34a64c8..ea1f79f 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -257,6 +257,7 @@ private slots: void task233101_cursorPosAfterInputMethod_data(); void task233101_cursorPosAfterInputMethod(); void task241436_passwordEchoOnEditRestoreEchoMode(); + void task248948_redoRemovedSelection(); protected slots: #ifdef QT3_SUPPORT @@ -3483,5 +3484,17 @@ void tst_QLineEdit::task241436_passwordEchoOnEditRestoreEchoMode() testWidget->setEchoMode(QLineEdit::Normal); } +void tst_QLineEdit::task248948_redoRemovedSelection() +{ + testWidget->setText("a"); + testWidget->selectAll(); + QTest::keyPress(testWidget, Qt::Key_Delete); + testWidget->undo(); + testWidget->redo(); + QTest::keyPress(testWidget, 'a'); + QTest::keyPress(testWidget, 'b'); + QCOMPARE(testWidget->text(), QLatin1String("ab")); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" diff --git a/tests/auto/qmake/testdata/bundle-spaces/some-file b/tests/auto/qmake/testdata/bundle-spaces/some-file index 9975dba..e69de29 100644 --- a/tests/auto/qmake/testdata/bundle-spaces/some-file +++ b/tests/auto/qmake/testdata/bundle-spaces/some-file @@ -1,6 +0,0 @@ -all: - C:\git\qt-kinetic-animations\bin\qmake qdir.pro -o Makefile -spec win32-msvc2008 - nmake -f Makefile -first: all -qmake: - C:\git\qt-kinetic-animations\bin\qmake qdir.pro -o Makefile -spec win32-msvc2008 diff --git a/tests/auto/qmenu/tst_qmenu.cpp b/tests/auto/qmenu/tst_qmenu.cpp index a86b754..5b6e54c 100644 --- a/tests/auto/qmenu/tst_qmenu.cpp +++ b/tests/auto/qmenu/tst_qmenu.cpp @@ -684,7 +684,7 @@ void tst_QMenu::task250673_activeMutliColumnSubMenuPosition() class MyMenu : public QMenu { public: - friend class tst_QMenu; + int columnCount() const { return QMenu::columnCount(); } }; QMenu sub; diff --git a/tests/auto/qpainterpath/tst_qpainterpath.cpp b/tests/auto/qpainterpath/tst_qpainterpath.cpp index 3d77f5e..38fb8d7 100644 --- a/tests/auto/qpainterpath/tst_qpainterpath.cpp +++ b/tests/auto/qpainterpath/tst_qpainterpath.cpp @@ -107,6 +107,8 @@ private slots: void operators(); void connectPathDuplicatePoint(); + + void translate(); }; // Testing get/set functions @@ -1167,6 +1169,44 @@ void tst_QPainterPath::connectPathDuplicatePoint() QCOMPARE(c, a); } +void tst_QPainterPath::translate() +{ + QPainterPath path; + + // Path with no elements. + QCOMPARE(path.currentPosition(), QPointF()); + path.translate(50.5, 50.5); + QCOMPARE(path.currentPosition(), QPointF()); + QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF()); + + // path.isEmpty(), but we have one MoveTo element that should be translated. + path.moveTo(50, 50); + QCOMPARE(path.currentPosition(), QPointF(50, 50)); + path.translate(99.9, 99.9); + QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9)); + path.translate(-99.9, -99.9); + QCOMPARE(path.currentPosition(), QPointF(50, 50)); + QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0)); + + // Complex path. + QRegion shape(100, 100, 300, 200, QRegion::Ellipse); + shape -= QRect(225, 175, 50, 50); + QPainterPath complexPath; + complexPath.addRegion(shape); + QVector<QPointF> untranslatedElements; + for (int i = 0; i < complexPath.elementCount(); ++i) + untranslatedElements.append(QPointF(complexPath.elementAt(i))); + + const QPainterPath untranslatedComplexPath(complexPath); + const QPointF offset(100, 100); + complexPath.translate(offset); + + for (int i = 0; i < complexPath.elementCount(); ++i) + QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i)); + + QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); +} + QTEST_APPLESS_MAIN(tst_QPainterPath) #include "tst_qpainterpath.moc" diff --git a/tests/auto/qpicture/tst_qpicture.cpp b/tests/auto/qpicture/tst_qpicture.cpp index 954be23..dfa61c7 100644 --- a/tests/auto/qpicture/tst_qpicture.cpp +++ b/tests/auto/qpicture/tst_qpicture.cpp @@ -47,6 +47,7 @@ #include <qimage.h> #include <qdesktopwidget.h> #include <qapplication.h> +#include <limits.h> //TESTED_CLASS= //TESTED_FILES= @@ -66,6 +67,9 @@ private slots: void operator_lt_lt(); void save_restore(); + + void boundaryValues_data(); + void boundaryValues(); }; // Testing get/set functions @@ -234,5 +238,39 @@ void tst_QPicture::save_restore() QVERIFY( pix1.toImage() == pix2.toImage() ); } +void tst_QPicture::boundaryValues_data() +{ + QTest::addColumn<int>("x"); + QTest::addColumn<int>("y"); + QTest::newRow("max x") << INT_MAX << 50; + QTest::newRow("max y") << 50 << INT_MAX; + QTest::newRow("max x and y") << INT_MAX << INT_MAX; + + QTest::newRow("min x") << INT_MIN << 50; + QTest::newRow("min y") << 50 << INT_MIN; + QTest::newRow("min x and y") << INT_MIN << INT_MIN; + + QTest::newRow("min x, max y") << INT_MIN << INT_MAX; + QTest::newRow("max x, min y") << INT_MAX << INT_MIN; + +} + +void tst_QPicture::boundaryValues() +{ + QPicture picture; + + QPainter painter; + painter.begin(&picture); + + QFETCH(int, x); + QFETCH(int, y); + painter.drawPoint(QPoint(x, y)); + + painter.end(); + + +} + + QTEST_MAIN(tst_QPicture) #include "tst_qpicture.moc" diff --git a/tests/auto/qpixmap/images/designer.png b/tests/auto/qpixmap/images/designer.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/designer.png diff --git a/tests/auto/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png b/tests/auto/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..a4a1924 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png b/tests/auto/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..1506af5 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_-10_dy_0_50_50_100_100.png b/tests/auto/qpixmap/images/dx_-10_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..8500ab1 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-10_dy_0_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_-10_dy_0_x_y_w_h.png b/tests/auto/qpixmap/images/dx_-10_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..2145c61 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-10_dy_0_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png b/tests/auto/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_-128_dy_0_x_y_w_h.png b/tests/auto/qpixmap/images/dx_-128_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_-128_dy_0_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_-10_50_50_100_100.png b/tests/auto/qpixmap/images/dx_0_dy_-10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..728ee79 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_-10_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_-10_x_y_w_h.png b/tests/auto/qpixmap/images/dx_0_dy_-10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..e9d5850 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_-10_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_-128_x_y_w_h.png b/tests/auto/qpixmap/images/dx_0_dy_-128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_-128_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_0_50_50_100_100.png b/tests/auto/qpixmap/images/dx_0_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_0_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_0_null.png b/tests/auto/qpixmap/images/dx_0_dy_0_null.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_0_null.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_0_x_y_w_h.png b/tests/auto/qpixmap/images/dx_0_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_0_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_10_50_50_100_100.png b/tests/auto/qpixmap/images/dx_0_dy_10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..7c09b17 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_10_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_10_x_y_w_h.png b/tests/auto/qpixmap/images/dx_0_dy_10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..70a6340 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_10_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_128_x_y_w_h.png b/tests/auto/qpixmap/images/dx_0_dy_128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_128_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_0_dy_1_null.png b/tests/auto/qpixmap/images/dx_0_dy_1_null.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_0_dy_1_null.png diff --git a/tests/auto/qpixmap/images/dx_10_dy_0_50_50_100_100.png b/tests/auto/qpixmap/images/dx_10_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..85abada --- /dev/null +++ b/tests/auto/qpixmap/images/dx_10_dy_0_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_10_dy_0_x_y_w_h.png b/tests/auto/qpixmap/images/dx_10_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..3e03450 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_10_dy_0_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_10_dy_10_50_50_100_100.png b/tests/auto/qpixmap/images/dx_10_dy_10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000..315fbe0 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_10_dy_10_50_50_100_100.png diff --git a/tests/auto/qpixmap/images/dx_10_dy_10_x_y_w_h.png b/tests/auto/qpixmap/images/dx_10_dy_10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..d91dc71 --- /dev/null +++ b/tests/auto/qpixmap/images/dx_10_dy_10_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_128_dy_0_x_y_w_h.png b/tests/auto/qpixmap/images/dx_128_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_128_dy_0_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_128_dy_128_64_64_128_128.png b/tests/auto/qpixmap/images/dx_128_dy_128_64_64_128_128.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_128_dy_128_64_64_128_128.png diff --git a/tests/auto/qpixmap/images/dx_128_dy_128_x_y_w_h.png b/tests/auto/qpixmap/images/dx_128_dy_128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_128_dy_128_x_y_w_h.png diff --git a/tests/auto/qpixmap/images/dx_1_dy_0_null.png b/tests/auto/qpixmap/images/dx_1_dy_0_null.png Binary files differnew file mode 100644 index 0000000..bca471d --- /dev/null +++ b/tests/auto/qpixmap/images/dx_1_dy_0_null.png diff --git a/tests/auto/qpixmap/qpixmap.pro b/tests/auto/qpixmap/qpixmap.pro index e5dace4..70be4be 100644 --- a/tests/auto/qpixmap/qpixmap.pro +++ b/tests/auto/qpixmap/qpixmap.pro @@ -13,5 +13,4 @@ wince*: { win32:LIBS += -lgdi32 -luser32 } - - +RESOURCES += qpixmap.qrc diff --git a/tests/auto/qpixmap/qpixmap.qrc b/tests/auto/qpixmap/qpixmap.qrc new file mode 100644 index 0000000..99fde61 --- /dev/null +++ b/tests/auto/qpixmap/qpixmap.qrc @@ -0,0 +1,29 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>images/designer.png</file> + <file>images/dx_0_dy_0_50_50_100_100.png</file> + <file>images/dx_0_dy_0_null.png</file> + <file>images/dx_0_dy_0_x_y_w_h.png</file> + <file>images/dx_0_dy_-10_50_50_100_100.png</file> + <file>images/dx_0_dy_10_50_50_100_100.png</file> + <file>images/dx_0_dy_-10_x_y_w_h.png</file> + <file>images/dx_0_dy_10_x_y_w_h.png</file> + <file>images/dx_0_dy_-128_x_y_w_h.png</file> + <file>images/dx_0_dy_128_x_y_w_h.png</file> + <file>images/dx_0_dy_1_null.png</file> + <file>images/dx_-10_dy_0_50_50_100_100.png</file> + <file>images/dx_10_dy_0_50_50_100_100.png</file> + <file>images/dx_-10_dy_0_x_y_w_h.png</file> + <file>images/dx_10_dy_0_x_y_w_h.png</file> + <file>images/dx_-10_dy_-10_50_50_100_100.png</file> + <file>images/dx_10_dy_10_50_50_100_100.png</file> + <file>images/dx_-10_dy_-10_x_y_w_h.png</file> + <file>images/dx_10_dy_10_x_y_w_h.png</file> + <file>images/dx_-128_dy_0_x_y_w_h.png</file> + <file>images/dx_128_dy_0_x_y_w_h.png</file> + <file>images/dx_128_dy_128_64_64_128_128.png</file> + <file>images/dx_-128_dy_-128_x_y_w_h.png</file> + <file>images/dx_128_dy_128_x_y_w_h.png</file> + <file>images/dx_1_dy_0_null.png</file> +</qresource> +</RCC> diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index ba117d8..8a6b63b 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -88,6 +88,9 @@ private slots: void testMetrics(); + void scroll_data(); + void scroll(); + void fill_data(); void fill(); void fill_transparent(); @@ -302,6 +305,99 @@ void tst_QPixmap::convertFromImage() QVERIFY( pixmapsAreEqual(&pix, &res) ); } +void tst_QPixmap::scroll_data() +{ + QTest::addColumn<QImage>("input"); + QTest::addColumn<int>("dx"); + QTest::addColumn<int>("dy"); + QTest::addColumn<QRect>("rect"); + QTest::addColumn<QRegion>("exposed"); + QTest::addColumn<bool>("newPix"); + + QImage input(":/images/designer.png"); + + // Noop tests + QTest::newRow("null") << QImage() << 0 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_0_null") << input << 0 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_1_dy_0_null") << input << 1 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_1_null") << input << 0 << 1 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_0_x_y_w_h") << input << 0 << 0 << input.rect() << QRegion() << false; + + QRegion r; + // Scroll whole pixmap + r = QRegion(); r += QRect(0, 0, 128, 10); + QTest::newRow("dx_0_dy_10_x_y_w_h") << input << 0 << 10 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 0, 10, 128); + QTest::newRow("dx_10_dy_0_x_y_w_h") << input << 10 << 0 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 0, 128, 10); r += QRect(0, 10, 10, 118); + QTest::newRow("dx_10_dy_10_x_y_w_h") << input << 10 << 10 << input.rect() << r << true; + r = QRegion(); r += QRect(118, 0, 10, 128); + QTest::newRow("dx_-10_dy_0_x_y_w_h") << input << -10 << 0 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 118, 128, 10); + QTest::newRow("dx_0_dy_-10_x_y_w_h") << input << 0 << -10 << input.rect() << r << true; + r = QRegion(); r += QRect(118, 0, 10, 118); r += QRect(0, 118, 128, 10); + QTest::newRow("dx_-10_dy_-10_x_y_w_h") << input << -10 << -10 << input.rect() << r << true; + + // Scroll part of pixmap + QTest::newRow("dx_0_dy_0_50_50_100_100") << input << 0 << 0 << QRect(50, 50, 100, 100) << QRegion() << false; + r = QRegion(); r += QRect(50, 50, 10, 78); + QTest::newRow("dx_10_dy_0_50_50_100_100") << input << 10 << 0 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 50, 78, 10); + QTest::newRow("dx_0_dy_10_50_50_100_100") << input << 0 << 10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 50, 78, 10); r += QRect(50, 60, 10, 68); + QTest::newRow("dx_10_dy_10_50_50_100_100") << input << 10 << 10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(118, 50, 10, 78); + QTest::newRow("dx_-10_dy_0_50_50_100_100") << input << -10 << 0 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 118, 78, 10); + QTest::newRow("dx_0_dy_-10_50_50_100_100") << input << 0 << -10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(118, 50, 10, 68); r += QRect(50, 118, 78, 10); + QTest::newRow("dx_-10_dy_-10_50_50_100_100") << input << -10 << -10 << QRect(50, 50, 100, 100) << r << true; + + // Scroll away the whole pixmap + r = input.rect(); + QTest::newRow("dx_128_dy_0_x_y_w_h") << input << 128 << 0 << input.rect() << r << false; + QTest::newRow("dx_0_dy_128_x_y_w_h") << input << 0 << 128 << input.rect() << r << false; + QTest::newRow("dx_128_dy_128_x_y_w_h") << input << 128 << 128 << input.rect() << r << false; + QTest::newRow("dx_-128_dy_0_x_y_w_h") << input << -128 << 0 << input.rect() << r << false; + QTest::newRow("dx_0_dy_-128_x_y_w_h") << input << 0 << -128 << input.rect() << r << false; + QTest::newRow("dx_-128_dy_-128_x_y_w_h") << input << -128 << -128 << input.rect() << r << false; + + // Scroll away part of the pixmap + r = QRegion(); r += QRect(64, 64, 64, 64); + QTest::newRow("dx_128_dy_128_64_64_128_128") << input << 128 << 128 << QRect(64, 64, 128, 128) << r << false; +} + +void tst_QPixmap::scroll() +{ + QFETCH(QImage, input); + QFETCH(int, dx); + QFETCH(int, dy); + QFETCH(QRect, rect); + QFETCH(QRegion, exposed); + QFETCH(bool, newPix); + + QPixmap pixmap(input); + QRegion exp; + qint64 oldKey = pixmap.cacheKey(); + pixmap.scroll(dx, dy, rect, &exp); + if (!newPix) + QCOMPARE(pixmap.cacheKey(), oldKey); + else + QVERIFY(pixmap.cacheKey() != oldKey); + +#if 0 + // Remember to add to resources. + QString fileName = QString("images/%1.png").arg(QTest::currentDataTag()); + pixmap.toImage().save(fileName); +#else + QString fileName = QString(":/images/%1.png").arg(QTest::currentDataTag()); +#endif + QImage output(fileName); + QVERIFY(input.isNull() == output.isNull()); + QCOMPARE(pixmap.toImage(), output); + QCOMPARE(exp, exposed); +} + void tst_QPixmap::fill_data() { QTest::addColumn<uint>("pixel"); diff --git a/tests/auto/qpoint/tst_qpoint.cpp b/tests/auto/qpoint/tst_qpoint.cpp index 67fefa8..16d55fc 100644 --- a/tests/auto/qpoint/tst_qpoint.cpp +++ b/tests/auto/qpoint/tst_qpoint.cpp @@ -60,6 +60,8 @@ public: private slots: void getSetCheck(); void division(); + + void manhattanLength(); }; tst_QPoint::tst_QPoint() @@ -70,6 +72,24 @@ tst_QPoint::~tst_QPoint() { } + + +void tst_QPoint::manhattanLength() +{ + { + QPoint p(10, 20); + QCOMPARE(p.manhattanLength(), 30); + } + { + QPointF p(10., 20.); + QCOMPARE(p.manhattanLength(), 30.); + } + { + QPointF p(10.1, 20.2); + QCOMPARE(p.manhattanLength(), 30.3); + } +} + // Testing get/set functions void tst_QPoint::getSetCheck() { diff --git a/tests/auto/qprocess/qprocess.pro b/tests/auto/qprocess/qprocess.pro index 4600f02..ed59f10 100644 --- a/tests/auto/qprocess/qprocess.pro +++ b/tests/auto/qprocess/qprocess.pro @@ -3,6 +3,7 @@ SUBDIRS = testProcessCrash \ testProcessEcho \ testProcessEcho2 \ testProcessEcho3 \ + testProcessEnvironment \ testProcessLoopback \ testProcessNormal \ testProcessOutput \ diff --git a/tests/auto/qprocess/testProcessEnvironment/main.cpp b/tests/auto/qprocess/testProcessEnvironment/main.cpp new file mode 100644 index 0000000..b5e75bc --- /dev/null +++ b/tests/auto/qprocess/testProcessEnvironment/main.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char **argv) +{ +#if defined(_WIN32_WCE) + // no environment in Windows CE + return 0; +#else + if (argc == 1) + return 1; + + char *env = getenv(argv[1]); + if (env) { + printf("%s", env); + return 0; + } + return 1; +#endif +} diff --git a/tests/auto/qprocess/testProcessEnvironment/testProcessEnvironment.pro b/tests/auto/qprocess/testProcessEnvironment/testProcessEnvironment.pro new file mode 100644 index 0000000..14ddae5 --- /dev/null +++ b/tests/auto/qprocess/testProcessEnvironment/testProcessEnvironment.pro @@ -0,0 +1,12 @@ +SOURCES = main.cpp +CONFIG -= qt +CONFIG += console +DESTDIR = ./ + +mac { + CONFIG -= app_bundle +} + +# no install rule for application used by test +INSTALLS = + diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index 801cce8..ba034ee 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -124,6 +124,8 @@ private slots: void spaceArgsTest_data(); void spaceArgsTest(); void exitCodeTest(); + void setEnvironment_data(); + void setEnvironment(); void systemEnvironment(); void spaceInName(); void lockupsInStartDetached(); @@ -1615,13 +1617,117 @@ void tst_QProcess::removeFileWhileProcessIsRunning() } //----------------------------------------------------------------------------- +void tst_QProcess::setEnvironment_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<QString>("value"); + + QTest::newRow("setting-empty") << "tst_QProcess" << ""; + QTest::newRow("setting") << "tst_QProcess" << "value"; + +#ifdef Q_OS_WIN + QTest::newRow("unsetting") << "PROMPT" << QString(); + QTest::newRow("overriding") << "PROMPT" << "value"; +#else + QTest::newRow("unsetting") << "PATH" << QString(); + QTest::newRow("overriding") << "PATH" << "value"; +#endif +} + +void tst_QProcess::setEnvironment() +{ +#if !defined (Q_OS_WINCE) + // there is no concept of system variables on Windows CE as there is no console + + // make sure our environment variables are correct + QVERIFY(qgetenv("tst_QProcess").isEmpty()); + QVERIFY(!qgetenv("PATH").isEmpty()); +#ifdef Q_OS_WIN + QVERIFY(!qgetenv("PROMPT").isEmpty()); +#endif + + QFETCH(QString, name); + QFETCH(QString, value); + QString executable = QDir::currentPath() + "/testProcessEnvironment/testProcessEnvironment"; + + { + QProcess process; + QStringList environment = QProcess::systemEnvironment(); + if (value.isNull()) { + int pos; + QRegExp rx(name + "=.*"); +#ifdef Q_OS_WIN + rx.setCaseSensitivity(Qt::CaseInsensitive); +#endif + while ((pos = environment.indexOf(rx)) != -1) + environment.removeAt(pos); + } else { + environment.append(name + '=' + value); + } + process.setEnvironment(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (value.isNull()) + QCOMPARE(process.exitCode(), 1); + else if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } + + // re-do the test but set the environment twice, to make sure + // that the latter addition overrides + // this test doesn't make sense in unsetting + if (!value.isNull()) { + QProcess process; + QStringList environment = QProcess::systemEnvironment(); + environment.prepend(name + "=This is not the right value"); + environment.append(name + '=' + value); + process.setEnvironment(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } + + // use the hash variant now + { + QProcess process; + QHash<QString, QString> environment = QProcess::systemEnvironmentHash(); + if (value.isNull()) + environment.remove(name); + else + environment.insert(name, value); + process.setEnvironmentHash(environment); + process.start(executable, QStringList() << name); + + QVERIFY(process.waitForFinished()); + if (value.isNull()) + QCOMPARE(process.exitCode(), 1); + else if (!value.isEmpty()) + QCOMPARE(process.exitCode(), 0); + + QCOMPARE(process.readAll(), value.toLocal8Bit()); + } +#endif +} +//----------------------------------------------------------------------------- void tst_QProcess::systemEnvironment() { #if defined (Q_OS_WINCE) // there is no concept of system variables on Windows CE as there is no console QVERIFY(QProcess::systemEnvironment().isEmpty()); + QVERIFY(QProcess::systemEnvironmentHash().isEmpty()); #else QVERIFY(!QProcess::systemEnvironment().isEmpty()); + QVERIFY(!QProcess::systemEnvironmentHash().isEmpty()); + + QVERIFY(QProcess::systemEnvironmentHash().contains("PATH")); + QVERIFY(!QProcess::systemEnvironment().filter(QRegExp("^PATH=", Qt::CaseInsensitive)).isEmpty()); #endif } diff --git a/tests/auto/qset/tst_qset.cpp b/tests/auto/qset/tst_qset.cpp index 5601656..41e6ebd 100644 --- a/tests/auto/qset/tst_qset.cpp +++ b/tests/auto/qset/tst_qset.cpp @@ -74,6 +74,7 @@ private slots: void clear(); void remove(); void contains(); + void containsSet(); void begin(); void end(); void insert(); @@ -347,6 +348,40 @@ void tst_QSet::contains() } } +void tst_QSet::containsSet() +{ + QSet<QString> set1; + QSet<QString> set2; + + // empty set contains the empty set + QVERIFY(set1.contains(set2)); + + for (int i = 0; i < 500; ++i) { + set1.insert(QString::number(i)); + set2.insert(QString::number(i)); + } + QVERIFY(set1.contains(set2)); + + set2.remove(QString::number(19)); + set2.remove(QString::number(82)); + set2.remove(QString::number(7)); + QVERIFY(set1.contains(set2)); + + set1.remove(QString::number(23)); + QVERIFY(!set1.contains(set2)); + + // filled set contains the empty set as well + QSet<QString> set3; + QVERIFY(set1.contains(set3)); + + // the empty set doesn't contain a filled set + QVERIFY(!set3.contains(set1)); + + // verify const signature + const QSet<QString> set4; + QVERIFY(set3.contains(set4)); +} + void tst_QSet::begin() { QSet<int> set1; diff --git a/tests/auto/qshortcut/tst_qshortcut.cpp b/tests/auto/qshortcut/tst_qshortcut.cpp index 69ebf74..cd80204 100644 --- a/tests/auto/qshortcut/tst_qshortcut.cpp +++ b/tests/auto/qshortcut/tst_qshortcut.cpp @@ -987,17 +987,16 @@ void tst_QShortcut::keypressConsumption() cut1->setEnabled(false); cut2->setEnabled(false); - // Make sure keypresses is passed on, since all multiple keysequences - // with Ctrl+I are disabled + edit->clear(); sendKeyEvents(edit, Qt::CTRL + Qt::Key_I, 0); // Send key to edit QCOMPARE( currentResult, NoResult ); QCOMPARE( ambigResult, NoResult ); - QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>")); + QVERIFY(edit->toPlainText().isEmpty()); sendKeyEvents(edit, Qt::Key_A, 'a'); // Send key to edit QCOMPARE( currentResult, NoResult ); QCOMPARE( ambigResult, NoResult ); - QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>a")); + QVERIFY(edit->toPlainText().isEmpty()); clearAllShortcuts(); } diff --git a/tests/auto/qsplitter/qsplitter.pro b/tests/auto/qsplitter/qsplitter.pro index 99f27b4..a7ff0a6 100644 --- a/tests/auto/qsplitter/qsplitter.pro +++ b/tests/auto/qsplitter/qsplitter.pro @@ -8,4 +8,7 @@ wince*: { addFiles.sources = extradata.txt setSizes3.dat addFiles.path = . DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\"./\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" } diff --git a/tests/auto/qsplitter/tst_qsplitter.cpp b/tests/auto/qsplitter/tst_qsplitter.cpp index b463f7f..33404e4 100644 --- a/tests/auto/qsplitter/tst_qsplitter.cpp +++ b/tests/auto/qsplitter/tst_qsplitter.cpp @@ -213,7 +213,7 @@ void tst_QSplitter::setSizes3_data() QTest::addColumn<IntList>("collapsibleStates"); QTest::addColumn<bool>("childrenCollapse"); - QFile file("setSizes3.dat"); + QFile file(SRCDIR "setSizes3.dat"); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Can't open file, reason:" << file.errorString(); return; diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 611077f..ef51285 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -217,7 +217,7 @@ public: // addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3309, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 5.0.18 Linux // addDb( "QMYSQL3", "testdb", "troll", "trond", "iceblink.nokia.troll.no" ); // MySQL 5.0.13 Windows // addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql4-nokia.trolltech.com.au" ); // MySQL 4.1.22-2.el4 linux -// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql5-nokia.trolltech.com.au" ); // MySQL 5.0.45-7.el5 linux +// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql5-nokia.trolltech.com.au" ); // MySQL 5.0.45-7.el5 linux // addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no" ); // V7.2 NOT SUPPORTED! // addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5434 ); // V7.2 NOT SUPPORTED! Multi-byte @@ -238,14 +238,15 @@ public: // addDb( "QIBASE", "/opt/firebird/databases/testdb.fdb", "testuser", "Ee4Gabf6_", "firebird2-nokia.trolltech.com.au" ); // Firebird 2.1.1 // use in-memory database to prevent local files - addDb("QSQLITE", ":memory:"); -// addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); +// addDb("QSQLITE", ":memory:"); + addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); // addDb( "QSQLITE2", QDir::toNativeSeparators(QDir::tempPath()+"/foo2.db") ); // addDb( "QODBC3", "DRIVER={SQL SERVER};SERVER=iceblink.nokia.troll.no\\ICEBLINK", "troll", "trond", "" ); // addDb( "QODBC3", "DRIVER={SQL Native Client};SERVER=silence.nokia.troll.no\\SQLEXPRESS", "troll", "trond", "" ); -// addDb( "QODBC", "DRIVER={MySQL ODBC 3.51 Driver};SERVER=mysql5-nokia.trolltech.com.au;DATABASE=testdb", "testuser", "Ee4Gabf6_", "" ); -// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=horsehead.nokia.troll.no;DATABASE=testdb;PORT=4101;UID=troll;PWD=trondk", "troll", "trondk", "" ); +// addDb( "QODBC", "DRIVER={MySQL ODBC 3.51 Driver};SERVER=mysql5-nokia.trolltech.com.au;DATABASE=testdb", "testuser", "Ee4Gabf6_", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=horsehead.nokia.troll.no;DATABASE=testdb;PORT=4101;UID=troll;PWD=trondk", "troll", "trondk", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=silence.nokia.troll.no;DATABASE=testdb;PORT=2392;UID=troll;PWD=trond", "troll", "trond", "" ); } @@ -312,17 +313,21 @@ public: QSqlQuery q( db ); QStringList dbtables=db.tables(); - foreach(QString tableName, tableNames) + foreach(const QString &tableName, tableNames) { wasDropped = true; QString table=tableName; if ( db.driver()->isIdentifierEscaped(table, QSqlDriver::TableName)) table = db.driver()->stripDelimiters(table, QSqlDriver::TableName); - if ( dbtables.contains( table, Qt::CaseSensitive ) ) - wasDropped = q.exec( "drop table " + tableName); - else if ( dbtables.contains( table, Qt::CaseInsensitive ) ) - wasDropped = q.exec( "drop table " + tableName); + foreach(const QString dbtablesName, dbtables) { + if(dbtablesName.toUpper() == table.toUpper()) { + dbtables.removeAll(dbtablesName); + wasDropped = q.exec("drop table " + db.driver()->escapeIdentifier( dbtablesName, QSqlDriver::TableName )); + if(!wasDropped) + wasDropped = q.exec("drop table " + dbtablesName); + } + } if ( !wasDropped ) qWarning() << dbToString(db) << "unable to drop table" << tableName << ':' << q.lastError().text() << "tables:" << dbtables; @@ -396,12 +401,26 @@ public: static QByteArray printError( const QSqlError& err ) { - return QString( "'" + err.driverText() + "' || '" + err.databaseText() + "'" ).toLocal8Bit(); + QString result; + if(err.number() > 0) + result += '(' + QString::number(err.number()) + ") "; + result += '\''; + if(!err.driverText().isEmpty()) + result += err.driverText() + "' || '"; + result += err.databaseText() + "'"; + return result.toLocal8Bit(); } static QByteArray printError( const QSqlError& err, const QSqlDatabase& db ) { - return QString( dbToString(db) + ": '" + err.driverText() + "' || '" + err.databaseText() + "'" ).toLocal8Bit(); + QString result(dbToString(db) + ": "); + if(err.number() > 0) + result += '(' + QString::number(err.number()) + ") "; + result += '\''; + if(!err.driverText().isEmpty()) + result += err.driverText() + "' || '"; + result += err.databaseText() + "'"; + return result.toLocal8Bit(); } static bool isSqlServer( QSqlDatabase db ) diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 4f98624..b9725fd 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -133,6 +133,7 @@ private slots: void addCaCertificates2(); void ciphers(); void connectToHostEncrypted(); + void connectToHostEncryptedWithVerificationPeerName(); void sessionCipher(); void flush(); void isEncrypted(); @@ -597,6 +598,32 @@ void tst_QSslSocket::connectToHostEncrypted() QVERIFY(socket->waitForDisconnected()); } +void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + socket->addCaCertificates(QLatin1String("certs/qt-test-server-cacert.pem")); +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + + // connect to the server with its local name, but use the full name for verification. + socket->connectToHostEncrypted(QtNetworkSettings::serverLocalName(), 443, QtNetworkSettings::serverName()); + + // This should pass unconditionally when using fluke's CA certificate. + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); + + QCOMPARE(socket->mode(), QSslSocket::SslClientMode); +} + void tst_QSslSocket::sessionCipher() { if (!QSslSocket::supportsSsl()) diff --git a/tests/auto/qtabbar/tst_qtabbar.cpp b/tests/auto/qtabbar/tst_qtabbar.cpp index 433eb86..31722de 100644 --- a/tests/auto/qtabbar/tst_qtabbar.cpp +++ b/tests/auto/qtabbar/tst_qtabbar.cpp @@ -92,6 +92,8 @@ private slots: void moveTab_data(); void moveTab(); + + void task251184_removeTab(); }; // Testing get/set functions @@ -503,5 +505,35 @@ void tst_QTabBar::moveTab() bar.callMoveTab(from, to); } + +class MyTabBar : public QTabBar +{ + Q_OBJECT +public slots: + void onCurrentChanged() + { + //we just want this to be done once + disconnect(this, SIGNAL(currentChanged(int)), this, SLOT(onCurrentChanged())); + removeTab(0); + } +}; + +void tst_QTabBar::task251184_removeTab() +{ + MyTabBar bar; + bar.addTab("bar1"); + bar.addTab("bar2"); + QCOMPARE(bar.count(), 2); + QCOMPARE(bar.currentIndex(), 0); + + bar.connect(&bar, SIGNAL(currentChanged(int)), SLOT(onCurrentChanged())); + bar.setCurrentIndex(1); + + QCOMPARE(bar.count(), 1); + QCOMPARE(bar.currentIndex(), 0); + QCOMPARE(bar.tabText(bar.currentIndex()), QString("bar2")); +} + + QTEST_MAIN(tst_QTabBar) #include "tst_qtabbar.moc" diff --git a/tests/auto/qtableview/tst_qtableview.cpp b/tests/auto/qtableview/tst_qtableview.cpp index a9b41d8..9595155 100644 --- a/tests/auto/qtableview/tst_qtableview.cpp +++ b/tests/auto/qtableview/tst_qtableview.cpp @@ -2540,6 +2540,7 @@ void tst_QTableView::span_data() << 2 << 1 << false; + /* This makes no sens. QTest::newRow("top left 2x0") << 10 << 10 << -1 << -1 @@ -2554,7 +2555,7 @@ void tst_QTableView::span_data() << 0 << 0 << 0 << 2 << 0 << 2 - << false; + << false;*/ QTest::newRow("invalid 2x2") << 10 << 10 @@ -2628,7 +2629,7 @@ void tst_QTableView::span() view.hideRow(hiddenRow); view.hideColumn(hiddenColumn); view.show(); - + QCOMPARE(view.rowSpan(row, column), expectedRowSpan); QCOMPARE(view.columnSpan(row, column), expectedColumnSpan); diff --git a/tests/auto/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index 6edaee3..46f5f0c 100644 --- a/tests/auto/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -2309,7 +2309,7 @@ void tst_QTextDocumentFragment::html_tbody() QVERIFY(table); QCOMPARE(table->columns(), 1); QCOMPARE(table->rows(), 2); - QVERIFY(table->format().headerRowCount(), 1); + QCOMPARE(table->format().headerRowCount(), 1); QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell")); QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell")); } diff --git a/tests/auto/qtoolbutton/tst_qtoolbutton.cpp b/tests/auto/qtoolbutton/tst_qtoolbutton.cpp index 2c0a0cb..1dbf99b 100644 --- a/tests/auto/qtoolbutton/tst_qtoolbutton.cpp +++ b/tests/auto/qtoolbutton/tst_qtoolbutton.cpp @@ -65,6 +65,7 @@ private slots: void getSetCheck(); void triggered(); void task230994_iconSize(); + void task176137_autoRepeatOfAction(); protected slots: void sendMouseClick(); @@ -179,6 +180,25 @@ void tst_QToolButton::task230994_iconSize() QVERIFY(option.iconSize.isValid()); } +void tst_QToolButton::task176137_autoRepeatOfAction() +{ + QAction action(0); + QToolButton tb; + tb.setDefaultAction (&action); + tb.show(); + QSignalSpy spy(&action,SIGNAL(triggered())); + QTest::mousePress ( &tb, Qt::LeftButton); + QTest::mouseRelease ( &tb, Qt::LeftButton, 0, QPoint (), 2000); + QCOMPARE(spy.count(),1); + + // try again with auto repeat + tb.setAutoRepeat (true); + QSignalSpy repeatSpy(&action,SIGNAL(triggered())); // new spy + QTest::mousePress ( &tb, Qt::LeftButton); + QTest::mouseRelease ( &tb, Qt::LeftButton, 0, QPoint (), 2000); + QCOMPARE (repeatSpy.count(), (2000 - tb.autoRepeatDelay()) / tb.autoRepeatInterval() + 1); +} + void tst_QToolButton::sendMouseClick() { diff --git a/tests/auto/qtreeview/tst_qtreeview.cpp b/tests/auto/qtreeview/tst_qtreeview.cpp index 655ea4e..37cb5b0 100644 --- a/tests/auto/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/qtreeview/tst_qtreeview.cpp @@ -225,6 +225,7 @@ private slots: void task238873_avoidAutoReopening(); void task244304_clickOnDecoration(); void task246536_scrollbarsNotWorking(); + void task250683_wrongSectionSize(); }; class QtTestModel: public QAbstractItemModel @@ -3272,5 +3273,22 @@ void tst_QTreeView::task246536_scrollbarsNotWorking() QVERIFY(o.count > 0); } + +void tst_QTreeView::task250683_wrongSectionSize() +{ + QDirModel model; + QTreeView treeView; + treeView.header()->setResizeMode(QHeaderView::ResizeToContents); + treeView.setModel(&model); + treeView.setColumnHidden(2, true); + treeView.setColumnHidden(3, true); + + treeView.show(); + QTest::qWait(100); + + QCOMPARE(treeView.header()->sectionSize(0) + treeView.header()->sectionSize(1), treeView.viewport()->width()); +} + + QTEST_MAIN(tst_QTreeView) #include "tst_qtreeview.moc" diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index a052034..9547c8f 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -1544,6 +1544,10 @@ void tst_QWidget::focusChainOnReparent() QCOMPARE(w, expectedOriginalChain[i]); w = w->nextInFocusChain(); } + for (int i = 7; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedOriginalChain[i]); + } QWidget window2; child2->setParent(&window2); @@ -1554,6 +1558,10 @@ void tst_QWidget::focusChainOnReparent() QCOMPARE(w, expectedNewChain[i]); w = w->nextInFocusChain(); } + for (int i = 4; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedNewChain[i]); + } QWidget *expectedOldChain[5] = {&window, child1, child3, child4, &window}; w = &window; @@ -1561,6 +1569,10 @@ void tst_QWidget::focusChainOnReparent() QCOMPARE(w, expectedOldChain[i]); w = w->nextInFocusChain(); } + for (int i = 4; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedOldChain[i]); + } } @@ -5775,6 +5787,35 @@ void tst_QWidget::setToolTip() widget.setToolTip(QString()); QCOMPARE(widget.toolTip(), QString()); QCOMPARE(spy.count(), 2); + + + + for (int pass = 0; pass < 2; ++pass) { + QWidget *popup = new QWidget(0, Qt::Popup); + popup->resize(150, 50); + QFrame *frame = new QFrame(popup); + frame->setGeometry(0, 0, 50, 50); + frame->setFrameStyle(QFrame::Box | QFrame::Plain); + EventSpy spy1(frame, QEvent::ToolTip); + EventSpy spy2(popup, QEvent::ToolTip); + frame->setMouseTracking(pass == 0 ? false : true); + frame->setToolTip(QLatin1String("TOOLTIP FRAME")); + popup->setToolTip(QLatin1String("TOOLTIP POPUP")); + popup->show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(popup); +#endif + QTest::qWait(100); + QTest::mouseMove(frame); + QTest::qWait(900); // delay is 700 + + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy2.count(), 0); + if (pass == 0) + QTest::qWait(2200); // delay is 2000 + QTest::mouseMove(popup); + delete popup; + } } void tst_QWidget::testWindowIconChangeEventPropagation() diff --git a/tests/auto/selftests/badxml/badxml.pro b/tests/auto/selftests/badxml/badxml.pro new file mode 100644 index 0000000..323791a --- /dev/null +++ b/tests/auto/selftests/badxml/badxml.pro @@ -0,0 +1,11 @@ +load(qttest_p4) + +SOURCES += tst_badxml.cpp +QT = core + +mac:CONFIG -= app_bundle +CONFIG -= debug_and_release_target +!win32:CONFIG += debug + +TARGET = badxml + diff --git a/tests/auto/selftests/badxml/tst_badxml.cpp b/tests/auto/selftests/badxml/tst_badxml.cpp new file mode 100644 index 0000000..6b2e4c4 --- /dev/null +++ b/tests/auto/selftests/badxml/tst_badxml.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore> +#include <QtTest/QtTest> + +/* + This test makes a testlog containing lots of characters which have a special meaning in + XML, with the purpose of exposing bugs in testlib's XML output code. +*/ +class tst_BadXml : public QObject +{ + Q_OBJECT + +private slots: + void badDataTag() const; + void badDataTag_data() const; + + void badMessage() const; + void badMessage_data() const; + +public: + static QList<QByteArray> const& badStrings(); +}; + +/* + Custom metaobject to make it possible to change class name at runtime. +*/ +class EmptyClass : public tst_BadXml +{ Q_OBJECT }; + +class tst_BadXmlSub : public tst_BadXml +{ +public: + const QMetaObject* metaObject() const; + + static char const* className; +}; +char const* tst_BadXmlSub::className = "tst_BadXml"; + +const QMetaObject* tst_BadXmlSub::metaObject() const +{ + const QMetaObject& empty = EmptyClass::staticMetaObject; + static QMetaObject mo = { + { empty.d.superdata, empty.d.stringdata, empty.d.data, empty.d.extradata } + }; + static char currentClassName[1024]; + qstrcpy(currentClassName, className); + int len = qstrlen(className); + currentClassName[len] = 0; + currentClassName[len+1] = 0; + + mo.d.stringdata = currentClassName; + + return &mo; +} + +/* + Outputs incidents and benchmark results with the current data tag set to a bad string. +*/ +void tst_BadXml::badDataTag() const +{ + qDebug("a message"); + + QBENCHMARK { + } + + QFAIL("a failure"); +} + +void tst_BadXml::badDataTag_data() const +{ + QTest::addColumn<int>("dummy"); + + foreach (char const* str, badStrings()) { + QTest::newRow(str) << 0; + } +} + +/* + Outputs a message containing a bad string. +*/ +void tst_BadXml::badMessage() const +{ + QFETCH(QByteArray, message); + qDebug("%s", message.constData()); +} + +void tst_BadXml::badMessage_data() const +{ + QTest::addColumn<QByteArray>("message"); + + int i = 0; + foreach (QByteArray const& str, badStrings()) { + QTest::newRow(qPrintable(QString::fromLatin1("string %1").arg(i++))) << str; + } +} + +/* + Returns a list of strings likely to expose bugs in XML output code. +*/ +QList<QByteArray> const& tst_BadXml::badStrings() +{ + static QList<QByteArray> out; + if (out.isEmpty()) { + out << "end cdata ]]> text ]]> more text"; + out << "quotes \" text\" more text"; + out << "xml close > open < tags < text"; + out << "all > \" mixed ]]> up > \" in < the ]]> hopes < of triggering \"< ]]> bugs"; + } + return out; +} + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + /* + tst_selftests can't handle multiple XML documents in a single testrun, so we'll + decide before we begin which of our "bad strings" we want to use for our testcase + name. + */ + int badstring = -1; + QVector<char const*> args; + for (int i = 0; i < argc; ++i) { + if (!strcmp(argv[i], "-badstring")) { + bool ok = false; + if (i < argc-1) { + badstring = QByteArray(argv[i+1]).toInt(&ok); + ++i; + } + if (!ok) { + qFatal("Bad `-badstring' option"); + } + } + else { + args << argv[i]; + } + } + /* + We just want testlib to output a benchmark result, we don't actually care about the value, + so just do one iteration to save time. + */ + args << "-iterations" << "1"; + + if (badstring == -1) { + tst_BadXml test; + return QTest::qExec(&test, args.count(), const_cast<char**>(args.data())); + } + + QList<QByteArray> badstrings = tst_BadXml::badStrings(); + if (badstring >= badstrings.count()) + qFatal("`-badstring %d' is out of range", badstring); + + tst_BadXmlSub test; + test.className = badstrings[badstring].constData(); + return QTest::qExec(&test, args.count(), const_cast<char**>(args.data())); +} + +#include "tst_badxml.moc" diff --git a/tests/auto/selftests/expected_skip.txt b/tests/auto/selftests/expected_skip.txt index ba41e67..88c0426 100644 --- a/tests/auto/selftests/expected_skip.txt +++ b/tests/auto/selftests/expected_skip.txt @@ -1,13 +1,13 @@ ********* Start testing of tst_Skip ********* -Config: Using QTest library 4.3.0, Qt 4.3.0 +Config: Using QTest library 4.6.0, Qt 4.6.0 PASS : tst_Skip::initTestCase() SKIP : tst_Skip::test() skipping all - Loc: [/home/fenglich/dev/qt-4.3/tests/auto/selftests/skip/tst_skip.cpp(35)] + Loc: [/home/rmcgover/depot/qt-git/mainline/tests/auto/selftests/skip/tst_skip.cpp(68)] SKIP : tst_Skip::emptytest() skipping all - Loc: [/home/fenglich/dev/qt-4.3/tests/auto/selftests/skip/tst_skip.cpp(45)] + Loc: [/home/rmcgover/depot/qt-git/mainline/tests/auto/selftests/skip/tst_skip.cpp(78)] SKIP : tst_Skip::singleSkip(local 1) skipping one - Loc: [/home/fenglich/dev/qt-4.3/tests/auto/selftests/skip/tst_skip.cpp(64)] -this line should only be reached once (true) + Loc: [/home/rmcgover/depot/qt-git/mainline/tests/auto/selftests/skip/tst_skip.cpp(97)] +QDEBUG : tst_Skip::singleSkip(local 2) this line should only be reached once (true) PASS : tst_Skip::singleSkip() PASS : tst_Skip::cleanupTestCase() Totals: 3 passed, 0 failed, 3 skipped diff --git a/tests/auto/selftests/expected_xunit.txt b/tests/auto/selftests/expected_xunit.txt new file mode 100644 index 0000000..0f7e70a --- /dev/null +++ b/tests/auto/selftests/expected_xunit.txt @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<testsuite errors="3" failures="2" tests="6" name="tst_Xunit"> + <properties> + <property value="4.6.0" name="QTestVersion"/> + <property value="4.6.0" name="QtVersion"/> + </properties> + <testcase result="pass" name="initTestCase"/> + <testcase result="pass" name="testFunc1"> + <error message="just a QWARN() !" type="warn"/> + </testcase> + <testcase result="fail" name="testFunc2"> + <error message="a qDebug() call!" type="qdebug"/> + <failure message="Compared values are not the same + Actual (2): 2 + Expected (3): 3" result="fail"/> + </testcase> + <testcase name="testFunc3"> + <error message="skipping this function!" type="skip"/> + </testcase> + <testcase result="fail" name="testFunc4"> + <failure message="a forced failure!" result="fail"/> + </testcase> + <testcase result="pass" name="cleanupTestCase"/> +</testsuite> diff --git a/tests/auto/selftests/selftests.pro b/tests/auto/selftests/selftests.pro index 2fa1d50..ca69afa 100644 --- a/tests/auto/selftests/selftests.pro +++ b/tests/auto/selftests/selftests.pro @@ -5,7 +5,7 @@ SUBDIRS = subtest test warnings maxwarnings cmptest globaldata skipglobal skip \ skipinit skipinitdata datetime singleskip assert waitwithoutgui differentexec \ exception qexecstringlist datatable commandlinedata\ benchlibwalltime benchlibcallgrind benchlibeventcounter benchlibtickcounter \ - benchliboptions + benchliboptions xunit badxml INSTALLS = diff --git a/tests/auto/selftests/selftests.qrc b/tests/auto/selftests/selftests.qrc index 125619e..d57ff29 100644 --- a/tests/auto/selftests/selftests.qrc +++ b/tests/auto/selftests/selftests.qrc @@ -34,5 +34,6 @@ <file>expected_benchlibeventcounter.txt</file> <file>expected_benchliboptions.txt</file> <file>expected_benchlibtickcounter.txt</file> + <file>expected_xunit.txt</file> </qresource> </RCC> diff --git a/tests/auto/selftests/skip/tst_skip.cpp b/tests/auto/selftests/skip/tst_skip.cpp index b1a3936..437cf62 100644 --- a/tests/auto/selftests/skip/tst_skip.cpp +++ b/tests/auto/selftests/skip/tst_skip.cpp @@ -70,7 +70,7 @@ void tst_Skip::test_data() void tst_Skip::test() { - printf("this line should never be reached, since we skip in the _data function\n"); + qDebug("this line should never be reached, since we skip in the _data function"); } void tst_Skip::emptytest_data() @@ -80,7 +80,7 @@ void tst_Skip::emptytest_data() void tst_Skip::emptytest() { - printf("this line should never be reached, since we skip in the _data function\n"); + qDebug("this line should never be reached, since we skip in the _data function"); } void tst_Skip::singleSkip_data() @@ -95,7 +95,7 @@ void tst_Skip::singleSkip() QFETCH(bool, booll); if (!booll) QSKIP("skipping one", SkipSingle); - printf("this line should only be reached once (%s)\n", booll ? "true" : "false"); + qDebug("this line should only be reached once (%s)", booll ? "true" : "false"); } QTEST_MAIN(tst_Skip) diff --git a/tests/auto/selftests/tst_selftests.cpp b/tests/auto/selftests/tst_selftests.cpp index 103fd79..aa1048b 100644 --- a/tests/auto/selftests/tst_selftests.cpp +++ b/tests/auto/selftests/tst_selftests.cpp @@ -54,9 +54,13 @@ private slots: void runSubTest(); void checkXML() const; void checkXML_data(); + void checkXunitxml() const; + void checkXunitxml_data(); private: QStringList m_checkXMLBlacklist; + QStringList m_checkXunitBlacklist; + void doRunSubTest(QString &subdir, QStringList &arguments ); }; struct BenchmarkResult @@ -186,17 +190,16 @@ void tst_Selftests::runSubTest_data() QTest::newRow("benchlibtickcounter") << "benchlibtickcounter" << QStringList("-tickcounter"); #endif + QTest::newRow("xunit") << "xunit" << QStringList("-xunitxml"); + } -void tst_Selftests::runSubTest() +void tst_Selftests::doRunSubTest(QString &subdir, QStringList &arguments ) { - QFETCH(QString, subdir); - QFETCH(QStringList, arguments); - QProcess proc; proc.setEnvironment(QStringList("")); proc.start(subdir + "/" + subdir, arguments); - QVERIFY(proc.waitForFinished()); + QVERIFY2(proc.waitForFinished(), qPrintable(proc.errorString())); const QByteArray out(proc.readAllStandardOutput()); const QByteArray err(proc.readAllStandardError()); @@ -206,8 +209,8 @@ void tst_Selftests::runSubTest() #if defined(Q_OS_WIN) if(subdir != QLatin1String("exception") && subdir != QLatin1String("fetchbogus")) #endif - QVERIFY2(err.isEmpty(), err.constData()); - + if(subdir != QLatin1String("xunit")) + QVERIFY2(err.isEmpty(), err.constData()); QList<QByteArray> res = splitLines(out); QList<QByteArray> exp = expectedResult(subdir); @@ -255,8 +258,8 @@ void tst_Selftests::runSubTest() { if(output != expected && qstrcmp(QTest::currentDataTag(), "subtest") == 0) { - /* The floating point formatting differs between platforms, so let's just skip it. */ - continue; + /* The floating point formatting differs between platforms, so let's just skip it. */ + continue; } else { /* @@ -284,6 +287,14 @@ void tst_Selftests::runSubTest() } } +void tst_Selftests::runSubTest() +{ + QFETCH(QString, subdir); + QFETCH(QStringList, arguments); + + doRunSubTest(subdir, arguments); +} + void tst_Selftests::initTestCase() { m_checkXMLBlacklist.append("crashes"); // This test crashes @@ -295,6 +306,14 @@ void tst_Selftests::initTestCase() m_checkXMLBlacklist.append("differentexec"); m_checkXMLBlacklist.append("qexecstringlist"); m_checkXMLBlacklist.append("benchliboptions"); + + m_checkXunitBlacklist = m_checkXMLBlacklist; + m_checkXunitBlacklist.append("benchlibwalltime"); + m_checkXunitBlacklist.append("benchlibeventcounter"); + m_checkXunitBlacklist.append("benchlibcallgrind"); + m_checkXunitBlacklist.append("subtest"); + m_checkXunitBlacklist.append("globaldata"); + m_checkXunitBlacklist.append("warnings"); } void tst_Selftests::checkXML() const @@ -306,6 +325,45 @@ void tst_Selftests::checkXML() const return; arguments.prepend("-xml"); + arguments.prepend("-flush"); + + QProcess proc; + proc.setEnvironment(QStringList("")); + proc.start(subdir + "/" + subdir, arguments); + QVERIFY(proc.waitForFinished()); + + QByteArray out(proc.readAllStandardOutput()); + QByteArray err(proc.readAllStandardError()); + + /* Some platforms decides to output a message for uncaught exceptions. For instance, + * this is what windows platforms says: + * "This application has requested the Runtime to terminate it in an unusual way. + * Please contact the application's support team for more information." */ + if(subdir != QLatin1String("exception") && subdir != QLatin1String("fetchbogus")) + QVERIFY2(err.isEmpty(), err.constData()); + + QXmlStreamReader reader(out); + + while(!reader.atEnd()) + reader.readNext(); + + QVERIFY2(!reader.error(), qPrintable(QString("line %1, col %2: %3") + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString()) + )); +} + +void tst_Selftests::checkXunitxml() const +{ + QFETCH(QString, subdir); + QFETCH(QStringList, arguments); + + if(m_checkXunitBlacklist.contains(subdir)) + return; + + arguments.prepend("-xunitxml"); + arguments.prepend("-flush"); QProcess proc; proc.setEnvironment(QStringList("")); @@ -315,6 +373,8 @@ void tst_Selftests::checkXML() const QByteArray out(proc.readAllStandardOutput()); QByteArray err(proc.readAllStandardError()); +// qDebug()<<out; + /* Some platforms decides to output a message for uncaught exceptions. For instance, * this is what windows platforms says: * "This application has requested the Runtime to terminate it in an unusual way. @@ -327,12 +387,26 @@ void tst_Selftests::checkXML() const while(!reader.atEnd()) reader.readNext(); - QVERIFY(!reader.error()); + QVERIFY2(!reader.error(), qPrintable(QString("line %1, col %2: %3") + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString()) + )); +} + +void tst_Selftests::checkXunitxml_data() +{ + checkXML_data(); } void tst_Selftests::checkXML_data() { runSubTest_data(); + QTest::newRow("badxml 1") << "badxml" << QStringList(); + QTest::newRow("badxml 2") << "badxml" << (QStringList() << "-badstring" << "0"); + QTest::newRow("badxml 3") << "badxml" << (QStringList() << "-badstring" << "1"); + QTest::newRow("badxml 4") << "badxml" << (QStringList() << "-badstring" << "2"); + QTest::newRow("badxml 5") << "badxml" << (QStringList() << "-badstring" << "3"); } /* Parse line into the BenchmarkResult it represents. */ diff --git a/tests/auto/selftests/xunit/tst_xunit b/tests/auto/selftests/xunit/tst_xunit Binary files differnew file mode 100755 index 0000000..31d03a8 --- /dev/null +++ b/tests/auto/selftests/xunit/tst_xunit diff --git a/tests/auto/selftests/xunit/tst_xunit.cpp b/tests/auto/selftests/xunit/tst_xunit.cpp new file mode 100644 index 0000000..d0b585f --- /dev/null +++ b/tests/auto/selftests/xunit/tst_xunit.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +class tst_Xunit : public QObject +{ + Q_OBJECT + +public: + tst_Xunit(); + +private slots: + void testFunc1(); + void testFunc2(); + void testFunc3(); + void testFunc4(); +}; + +tst_Xunit::tst_Xunit() +{ +} + +void tst_Xunit::testFunc1() +{ + QWARN("just a QWARN() !"); + QCOMPARE(1,1); +} + +void tst_Xunit::testFunc2() +{ + qDebug("a qDebug() call!"); + QCOMPARE(2, 3); +} + +void tst_Xunit::testFunc3() +{ + QSKIP("skipping this function!", SkipAll); +} + +void tst_Xunit::testFunc4() +{ + QFAIL("a forced failure!"); +} + + +QTEST_APPLESS_MAIN(tst_Xunit) +#include "tst_xunit.moc" diff --git a/tests/auto/selftests/xunit/xunit.pro b/tests/auto/selftests/xunit/xunit.pro new file mode 100644 index 0000000..81ca157 --- /dev/null +++ b/tests/auto/selftests/xunit/xunit.pro @@ -0,0 +1,15 @@ +load(qttest_p4) +SOURCES += tst_xunit.cpp + +wince*: { + addImages.sources = images/* + addImages.path = images + DEPLOYMENT += addImages + DEFINES += SRCDIR=\\\".\\\" +} else { + contains(QT_CONFIG, qt3support): QT += qt3support + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +TARGET = xunit + diff --git a/tests/auto/uiloader/baseline/css_splitter.ui b/tests/auto/uiloader/baseline/css_splitter.ui new file mode 100644 index 0000000..99dbc18 --- /dev/null +++ b/tests/auto/uiloader/baseline/css_splitter.ui @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>424</width> + <height>364</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <property name="styleSheet"> + <string notr="true"> QSplitter::handle:vertical { + image: url(images/splitter_horizontal.png); + } + + QSplitter::handle:horizontal { + image: url(images/splitter_vertical.png); + } + +#big_splitter::handle { background-color: blue; border: 3px dashed green; height:50px; } + + + QSplitter::handle:hover { + background-color: qlineargradient(spread:repeat, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 255), stop:0.17 rgba(255, 0, 0, 255), stop:0.18 rgba(255, 255, 255, 255), stop:0.210212 rgba(255, 255, 255, 255), stop:0.220212 rgba(0, 16, 255, 255), stop:0.279897 rgba(0, 16, 255, 255), stop:0.289897 rgba(255, 255, 255, 255), stop:0.32 rgba(255, 255, 255, 255), stop:0.33 rgba(255, 0, 0, 255), stop:1 rgba(255, 0, 0, 255)) + } + + QSplitter::handle:pressed { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255)); + }</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QSplitter" name="splitter_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QSplitter" name="big_splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QTextEdit" name="textEdit"/> + <widget class="QTextEdit" name="textEdit_5"/> + <widget class="QTextEdit" name="textEdit_4"/> + </widget> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QTextEdit" name="textEdit_2"/> + <widget class="QTextEdit" name="textEdit_3"/> + </widget> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> |