File indexing completed on 2024-04-14 14:27:03

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include <QTest>
0008 
0009 #include "datasource/HistoryProxySource.h"
0010 #include "datasource/ModelSource.h"
0011 #include "datasource/SingleValueSource.h"
0012 
0013 #define qs QStringLiteral
0014 
0015 class TestModel : public QAbstractListModel
0016 {
0017     Q_OBJECT
0018     Q_PROPERTY(int minimum READ minimum NOTIFY minimumChanged)
0019     Q_PROPERTY(int maximum READ maximum NOTIFY maximumChanged)
0020 
0021 public:
0022     TestModel(QObject *parent = nullptr)
0023         : QAbstractListModel(parent)
0024     {
0025         m_items.fill(1, 10);
0026     }
0027 
0028     int rowCount(const QModelIndex &parent) const override
0029     {
0030         if (parent.isValid()) {
0031             return 0;
0032         } else {
0033             return 10;
0034         }
0035     }
0036 
0037     QVariant data(const QModelIndex &index, int role) const override
0038     {
0039         Q_UNUSED(role)
0040 
0041         if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) {
0042             qDebug() << "index invalid";
0043             return QVariant{};
0044         }
0045 
0046         return m_items.at(index.row());
0047     }
0048 
0049     void set(int item, int value)
0050     {
0051         if (item < 0 || item >= 10) {
0052             return;
0053         }
0054 
0055         m_items[item] = value;
0056         Q_EMIT dataChanged(index(item, 0), index(item, 0));
0057         Q_EMIT minimumChanged();
0058         Q_EMIT maximumChanged();
0059     }
0060 
0061     int minimum()
0062     {
0063         return *std::min_element(m_items.cbegin(), m_items.cend());
0064     }
0065 
0066     int maximum()
0067     {
0068         return *std::max_element(m_items.cbegin(), m_items.cend());
0069     }
0070 
0071     Q_SIGNAL void minimumChanged();
0072     Q_SIGNAL void maximumChanged();
0073 
0074 private:
0075     QVector<int> m_items;
0076 };
0077 
0078 class HistoryProxySourceTest : public QObject
0079 {
0080     Q_OBJECT
0081 
0082 private Q_SLOTS:
0083     void testCreate()
0084     {
0085         // Basic creation should create an empty source.
0086         auto source = new HistoryProxySource{};
0087 
0088         QCOMPARE(source->itemCount(), 0);
0089         QCOMPARE(source->item(0), QVariant{});
0090         QCOMPARE(source->minimum(), QVariant{});
0091         QCOMPARE(source->maximum(), QVariant{});
0092         QCOMPARE(source->source(), nullptr);
0093     }
0094 
0095     void testWithValue()
0096     {
0097         auto valueSource = std::make_unique<SingleValueSource>();
0098 
0099         // Simple case first, using default values for maximum history and fill
0100         // mode. This should lead to 10 history items with the most recent value
0101         // being the first item.
0102         auto historySource = std::make_unique<HistoryProxySource>();
0103         historySource->setSource(valueSource.get());
0104         historySource->setMaximumHistory(10);
0105         historySource->setFillMode(HistoryProxySource::DoNotFill);
0106 
0107         for (int i = 0; i < 15; i++) {
0108             valueSource->setValue(i);
0109             QCOMPARE(historySource->itemCount(), std::min(i + 1, 10));
0110 
0111             for (int item = 0; item < historySource->itemCount(); ++item) {
0112                 QCOMPARE(historySource->item(item), i - item);
0113             }
0114         }
0115 
0116         // Minimum and maximum should be minimum and maximum of current history
0117         // items.
0118         QCOMPARE(historySource->minimum(), 5);
0119         QCOMPARE(historySource->maximum(), 14);
0120 
0121         // Clearing will reset the history.
0122         QCOMPARE(historySource->itemCount(), 10);
0123         historySource->clear();
0124         QCOMPARE(historySource->itemCount(), 0);
0125 
0126         valueSource->setValue(5);
0127 
0128         // With an interval, we should be getting maximumHistory items of the
0129         // same value if we simply wait for at least interval * 10 milliseconds.
0130         historySource->setInterval(50);
0131 
0132         QTest::qWait(750);
0133 
0134         QCOMPARE(historySource->itemCount(), 10);
0135         for (int i = 0; i < historySource->itemCount(); ++i) {
0136             QCOMPARE(historySource->item(i), 5);
0137         }
0138 
0139         historySource->setInterval(0);
0140 
0141         // Increasing history size does not delete existing history.
0142         historySource->setMaximumHistory(20);
0143 
0144         QCOMPARE(historySource->itemCount(), 10);
0145 
0146         // Changing fill mode resets history and should now report
0147         // maximumHistory number of items. Empty items should use the same
0148         // QVariant type as the value source does.
0149 
0150         historySource->setFillMode(HistoryProxySource::FillFromStart);
0151 
0152         QCOMPARE(historySource->item(0), QVariant{QVariant::Int});
0153         QCOMPARE(historySource->itemCount(), 20);
0154         QCOMPARE(historySource->item(19), QVariant{QVariant::Int});
0155 
0156         // Using the FillFromEnd fill mode adds items to the end while itemCount
0157         // is less than maximumHistory.
0158 
0159         historySource->setFillMode(HistoryProxySource::FillFromEnd);
0160         QCOMPARE(historySource->itemCount(), 20);
0161 
0162         for (int i = 0; i < 19; ++i) {
0163             valueSource->setValue(i);
0164             QCOMPARE(historySource->item(0), QVariant{QVariant::Int});
0165             for (int item = 19; item > 1; --item) {
0166                 if ((item - 19) + i < 0) {
0167                     QCOMPARE(historySource->item(item), QVariant{QVariant::Int});
0168                 } else {
0169                     QCOMPARE(historySource->item(item), 19 - item);
0170                 }
0171             }
0172         }
0173     }
0174 
0175     void testWithModel()
0176     {
0177         auto model = std::make_unique<TestModel>();
0178         auto modelSource = std::make_unique<ModelSource>();
0179         modelSource->setModel(model.get());
0180         modelSource->setRole(Qt::DisplayRole);
0181 
0182         auto historySource = std::make_unique<HistoryProxySource>();
0183         historySource->setSource(modelSource.get());
0184         historySource->setMaximumHistory(10);
0185         historySource->setFillMode(HistoryProxySource::DoNotFill);
0186 
0187         // When there is a source with an itemCount > 1, we can use setItem to
0188         // indicate which item should be watched.
0189         historySource->setItem(2);
0190 
0191         // When we then change the model, the history source should record an
0192         // item.
0193         for (int i = 0; i < 10; ++i) {
0194             model->set(2, i);
0195             QCOMPARE(historySource->itemCount(), i + 1);
0196             for (int item = 0; item < historySource->itemCount(); ++item) {
0197                 QCOMPARE(historySource->item(item), i - item);
0198             }
0199         }
0200 
0201         historySource->clear();
0202 
0203         model->set(2, 5);
0204         model->set(2, 2);
0205 
0206         // When the model has a minimum and a maximum property, those will be
0207         // used for the history source's minimum and maximum rather than
0208         // calculating it based on the items in the history.
0209 
0210         QCOMPARE(historySource->minimum(), 1);
0211         QCOMPARE(historySource->maximum(), 2);
0212     }
0213 };
0214 
0215 QTEST_GUILESS_MAIN(HistoryProxySourceTest)
0216 
0217 #include "HistoryProxySourceTest.moc"