summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp')
-rw-r--r--tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
new file mode 100644
index 0000000000..89bd1d7ff6
--- /dev/null
+++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qatomicscopedvaluerollback.h>
+
+#include <QTest>
+
+class tst_QAtomicScopedValueRollback : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void leavingScope();
+ void leavingScopeAfterCommit();
+ void rollbackToPreviousCommit();
+ void exceptions();
+ void earlyExitScope();
+private:
+ void earlyExitScope_helper(int exitpoint, std::atomic<int> &member);
+};
+
+void tst_QAtomicScopedValueRollback::leavingScope()
+{
+ QAtomicInt i = 0;
+ QBasicAtomicInteger<bool> b = false;
+ std::atomic<bool> b2 = false;
+ int x = 0, y = 42;
+ QBasicAtomicPointer<int> p = &x;
+
+ //test rollback on going out of scope
+ {
+ QAtomicScopedValueRollback ri(i);
+ QAtomicScopedValueRollback rb(b);
+ QAtomicScopedValueRollback rb2(b2, true);
+ QAtomicScopedValueRollback rp(p);
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(b2, true);
+ QCOMPARE(i.loadRelaxed(), 0);
+ QCOMPARE(p.loadRelaxed(), &x);
+ b.storeRelaxed(true);
+ i.storeRelaxed(1);
+ p.storeRelaxed(&y);
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i.loadRelaxed(), 1);
+ QCOMPARE(p.loadRelaxed(), &y);
+ }
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(b2, false);
+ QCOMPARE(i.loadRelaxed(), 0);
+ QCOMPARE(p.loadRelaxed(), &x);
+}
+
+void tst_QAtomicScopedValueRollback::leavingScopeAfterCommit()
+{
+ std::atomic<int> i = 0;
+ QAtomicInteger<bool> b = false;
+
+ //test rollback on going out of scope
+ {
+ QAtomicScopedValueRollback ri(i);
+ QAtomicScopedValueRollback rb(b);
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(i, 0);
+ b.storeRelaxed(true);
+ i = 1;
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i, 1);
+ ri.commit();
+ rb.commit();
+ }
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i, 1);
+}
+
+void tst_QAtomicScopedValueRollback::rollbackToPreviousCommit()
+{
+ QBasicAtomicInt i = 0;
+ {
+ QAtomicScopedValueRollback ri(i);
+ i++;
+ ri.commit();
+ i++;
+ }
+ QCOMPARE(i.loadRelaxed(), 1);
+ {
+ QAtomicScopedValueRollback ri1(i);
+ i++;
+ ri1.commit();
+ i++;
+ ri1.commit();
+ i++;
+ }
+ QCOMPARE(i.loadRelaxed(), 3);
+}
+
+void tst_QAtomicScopedValueRollback::exceptions()
+{
+ std::atomic<bool> b = false;
+ bool caught = false;
+ QT_TRY
+ {
+ QAtomicScopedValueRollback rb(b);
+ b = true;
+ QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop
+ rb.commit(); //if Qt compiled without exceptions, true is committed
+ }
+ QT_CATCH(...)
+ {
+ caught = true;
+ }
+ QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise
+}
+
+void tst_QAtomicScopedValueRollback::earlyExitScope()
+{
+ QAtomicInt ai = 0;
+ std::atomic<int> aj = 0;
+ while (true) {
+ QAtomicScopedValueRollback ri(ai);
+ ++ai;
+ aj = ai.loadRelaxed();
+ if (ai.loadRelaxed() > 8) break;
+ ri.commit();
+ }
+ QCOMPARE(ai.loadRelaxed(), 8);
+ QCOMPARE(aj.load(), 9);
+
+ for (int i = 0; i < 5; ++i) {
+ aj = 1;
+ earlyExitScope_helper(i, aj);
+ QCOMPARE(aj.load(), 1 << i);
+ }
+}
+
+static void operator*=(std::atomic<int> &lhs, int rhs)
+{
+ int expected = lhs.load();
+ while (!lhs.compare_exchange_weak(expected, expected * rhs))
+ ;
+}
+
+void tst_QAtomicScopedValueRollback::earlyExitScope_helper(int exitpoint, std::atomic<int>& member)
+{
+ QAtomicScopedValueRollback r(member);
+ member *= 2;
+ if (exitpoint == 0)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 1)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 2)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 3)
+ return;
+ r.commit();
+}
+
+QTEST_MAIN(tst_QAtomicScopedValueRollback)
+#include "tst_qatomicscopedvaluerollback.moc"