annotate base/test/TestById.h @ 1752:6d09d68165a4 by-id

Further review of ById: make IDs only available when adding a model to the ById store, not by querying the item directly. This means any id encountered in the wild must have been added to the store at some point (even if later released), which simplifies reasoning about lifecycles
author Chris Cannam
date Fri, 05 Jul 2019 15:28:07 +0100
parents 52705a328b34
children 043e05c956fb
rev   line source
Chris@1742 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1742 2
Chris@1742 3 /*
Chris@1742 4 Sonic Visualiser
Chris@1742 5 An audio file viewer and annotation editor.
Chris@1742 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1742 7
Chris@1742 8 This program is free software; you can redistribute it and/or
Chris@1742 9 modify it under the terms of the GNU General Public License as
Chris@1742 10 published by the Free Software Foundation; either version 2 of the
Chris@1742 11 License, or (at your option) any later version. See the file
Chris@1742 12 COPYING included with this distribution for more information.
Chris@1742 13 */
Chris@1742 14
Chris@1742 15 #include "../ById.h"
Chris@1742 16
Chris@1742 17 #include <QObject>
Chris@1742 18 #include <QtTest>
Chris@1742 19
Chris@1742 20 #include <iostream>
Chris@1742 21
Chris@1742 22 using namespace std;
Chris@1742 23
Chris@1742 24 struct WithoutId {};
Chris@1742 25
Chris@1752 26 // We'll need to change access levels for getId() and getUntypedId()
Chris@1752 27 // to test the raw calls
Chris@1752 28
Chris@1752 29 struct A : public WithTypedId<A> { public: using WithTypedId<A>::getId; };
Chris@1742 30 struct B1 : public A {};
Chris@1742 31 struct B2 : public A {};
Chris@1742 32
Chris@1742 33 struct M {};
Chris@1742 34
Chris@1742 35 typedef TypedById<A, A::Id> AById;
Chris@1742 36
Chris@1752 37 struct X : virtual public WithId { public: using WithId::getUntypedId; };
Chris@1742 38 struct Y : public X, public B2, public M {};
Chris@1742 39
Chris@1742 40 class TestById : public QObject
Chris@1742 41 {
Chris@1742 42 Q_OBJECT
Chris@1742 43
Chris@1742 44 private slots:
Chris@1742 45 void ids() {
Chris@1742 46 // Verify that ids are unique across all classes, not just
Chris@1742 47 // within a class. These must be the first two WithId objects
Chris@1742 48 // allocated in the first test in the suite, otherwise they
Chris@1742 49 // could be different even if they were allocated from
Chris@1742 50 // separate pools.
Chris@1742 51 A a;
Chris@1742 52 X x;
Chris@1742 53 if (a.getId().untyped == x.getUntypedId()) {
Chris@1742 54 cerr << "ERROR: a and x have the same id: " << a.getId() << endl;
Chris@1742 55 }
Chris@1742 56 QVERIFY(a.getId().untyped != x.getUntypedId());
Chris@1742 57
Chris@1742 58 A aa;
Chris@1742 59 QVERIFY(aa.getId().untyped != a.getId().untyped);
Chris@1742 60 QVERIFY(aa.getId().untyped != x.getUntypedId());
Chris@1742 61
Chris@1742 62 // Check the actual ids that have been allocated. This is
Chris@1742 63 // supposed to be a hidden implementation detail, but we want
Chris@1742 64 // to make sure the test itself hasn't become broken in terms
Chris@1742 65 // of allocation order (see comment above)
Chris@1742 66 QCOMPARE(a.getId().untyped, 0);
Chris@1742 67 QCOMPARE(x.getUntypedId(), 1);
Chris@1742 68 QCOMPARE(aa.getId().untyped, 2);
Chris@1742 69
Chris@1742 70 QVERIFY(!a.getId().isNone());
Chris@1742 71 QVERIFY(A::Id().isNone());
Chris@1742 72 }
Chris@1742 73
Chris@1742 74 // NB each test must release all the items it adds to the ById store
Chris@1742 75
Chris@1742 76 void anyEmpty() {
Chris@1742 77 auto p = AnyById::get(0);
Chris@1742 78 QVERIFY(!p);
Chris@1742 79 }
Chris@1742 80
Chris@1742 81 void anySimple() {
Chris@1742 82 auto a = std::make_shared<A>();
Chris@1752 83 int id = AnyById::add(a);
Chris@1752 84 QCOMPARE(id, a->getId().untyped);
Chris@1742 85
Chris@1752 86 auto aa = AnyById::getAs<A>(id);
Chris@1742 87 QVERIFY(!!aa);
Chris@1742 88 QCOMPARE(aa->getId(), a->getId());
Chris@1742 89 QCOMPARE(aa.get(), a.get()); // same object, not just same id!
Chris@1752 90 AnyById::release(id);
Chris@1742 91 }
Chris@1742 92
Chris@1742 93 void typedEmpty() {
Chris@1742 94 auto p = AById::get({});
Chris@1742 95 QVERIFY(!p);
Chris@1742 96 }
Chris@1742 97
Chris@1742 98 void typedSimple() {
Chris@1742 99 auto a = std::make_shared<A>();
Chris@1742 100 AById::add(a);
Chris@1742 101
Chris@1742 102 auto aa = AById::get(a->getId());
Chris@1742 103 QVERIFY(!!aa);
Chris@1742 104 QCOMPARE(aa->getId(), a->getId());
Chris@1742 105 QCOMPARE(aa.get(), a.get()); // same object, not just same id!
Chris@1742 106 AById::release(a);
Chris@1742 107 }
Chris@1742 108
Chris@1752 109 void typedReleaseById() {
Chris@1742 110 auto a = std::make_shared<A>();
Chris@1752 111 auto aid = AById::add(a);
Chris@1742 112
Chris@1752 113 auto aa = AById::get(aid);
Chris@1752 114 QVERIFY(!!aa);
Chris@1752 115 AById::release(aid);
Chris@1752 116
Chris@1752 117 aa = AById::get(aid);
Chris@1752 118 QVERIFY(!aa);
Chris@1752 119 }
Chris@1752 120
Chris@1752 121 void typedReleaseByItem() {
Chris@1752 122 auto a = std::make_shared<A>();
Chris@1752 123 auto aid = AById::add(a);
Chris@1752 124
Chris@1752 125 auto aa = AById::get(aid);
Chris@1742 126 QVERIFY(!!aa);
Chris@1742 127 AById::release(a);
Chris@1742 128
Chris@1752 129 aa = AById::get(aid);
Chris@1742 130 QVERIFY(!aa);
Chris@1742 131 }
Chris@1742 132
Chris@1742 133 void typedDowncast() {
Chris@1742 134 auto a = std::make_shared<A>();
Chris@1742 135 auto b1 = std::make_shared<B1>();
Chris@1742 136 AById::add(a);
Chris@1742 137 AById::add(b1);
Chris@1742 138
Chris@1742 139 auto bb1 = AById::getAs<B1>(a->getId());
Chris@1742 140 QVERIFY(!bb1);
Chris@1742 141
Chris@1742 142 bb1 = AById::getAs<B1>(b1->getId());
Chris@1742 143 QVERIFY(!!bb1);
Chris@1742 144 QCOMPARE(bb1->getId(), b1->getId());
Chris@1742 145
Chris@1742 146 auto bb2 = AById::getAs<B2>(b1->getId());
Chris@1742 147 QVERIFY(!bb2);
Chris@1742 148
Chris@1742 149 AById::release(a);
Chris@1742 150 AById::release(b1);
Chris@1742 151 }
Chris@1742 152
Chris@1742 153 void typedCrosscast() {
Chris@1742 154 auto y = std::make_shared<Y>();
Chris@1742 155 AById::add(y);
Chris@1742 156
Chris@1742 157 auto yy = AById::getAs<Y>(y->getId());
Chris@1742 158 QVERIFY(!!yy);
Chris@1742 159 QCOMPARE(yy->getId(), y->getId());
Chris@1742 160
Chris@1742 161 yy = AnyById::getAs<Y>(y->getId().untyped);
Chris@1742 162 QVERIFY(!!yy);
Chris@1742 163 QCOMPARE(yy->getId(), y->getId());
Chris@1742 164
Chris@1742 165 auto xx = AById::getAs<X>(y->getId());
Chris@1742 166 QVERIFY(!!xx);
Chris@1742 167 QCOMPARE(xx->getUntypedId(), y->getId().untyped);
Chris@1742 168 QCOMPARE(xx.get(), yy.get());
Chris@1742 169
Chris@1742 170 xx = AnyById::getAs<X>(y->getId().untyped);
Chris@1742 171 QVERIFY(!!xx);
Chris@1742 172 QCOMPARE(xx->getUntypedId(), y->getId().untyped);
Chris@1742 173 QCOMPARE(xx.get(), yy.get());
Chris@1742 174
Chris@1742 175 auto mm = AnyById::getAs<M>(y->getId().untyped);
Chris@1742 176 QVERIFY(!!mm);
Chris@1742 177 QCOMPARE(mm.get(), yy.get());
Chris@1742 178
Chris@1742 179 AById::release(y);
Chris@1742 180 }
Chris@1742 181
Chris@1742 182 void duplicateAdd() {
Chris@1742 183 auto a = std::make_shared<A>();
Chris@1742 184 AById::add(a);
Chris@1742 185 try {
Chris@1742 186 AById::add(a);
Chris@1742 187 cerr << "Failed to catch expected exception in duplicateAdd" << endl;
Chris@1742 188 QVERIFY(false);
Chris@1742 189 } catch (const std::logic_error &) {
Chris@1742 190 }
Chris@1742 191 AById::release(a);
Chris@1742 192 }
Chris@1742 193
Chris@1742 194 void unknownRelease() {
Chris@1742 195 auto a = std::make_shared<A>();
Chris@1742 196 auto b1 = std::make_shared<B1>();
Chris@1742 197 AById::add(a);
Chris@1742 198 try {
Chris@1742 199 AById::release(b1);
Chris@1742 200 cerr << "Failed to catch expected exception in unknownRelease" << endl;
Chris@1742 201 QVERIFY(false);
Chris@1742 202 } catch (const std::logic_error &) {
Chris@1742 203 }
Chris@1742 204 AById::release(a);
Chris@1742 205 }
Chris@1742 206 };
Chris@1742 207