1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QObject> |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include <Qt3DCore/private/qboundedcircularbuffer_p.h> |
33 | |
34 | using namespace Qt3DCore; |
35 | |
36 | class tst_QBoundedCircularBuffer : public QObject |
37 | { |
38 | Q_OBJECT |
39 | private Q_SLOTS: |
40 | void construction(); |
41 | void clear(); |
42 | void push(); |
43 | void pop(); |
44 | void at(); |
45 | void producerConsumer(); |
46 | }; |
47 | |
48 | class MyComplexType |
49 | { |
50 | public: |
51 | MyComplexType(int xx = 0) |
52 | : x(xx), |
53 | magicCheck(ms_magic) |
54 | { |
55 | ++ms_activeCount; |
56 | } |
57 | |
58 | MyComplexType(const MyComplexType &other) |
59 | : x(other.x), |
60 | magicCheck(other.magicCheck) |
61 | { |
62 | ++ms_activeCount; |
63 | } |
64 | |
65 | ~MyComplexType() |
66 | { |
67 | // Check that the constructor was actually called |
68 | QVERIFY(ms_magic == magicCheck); |
69 | --ms_activeCount; |
70 | } |
71 | |
72 | MyComplexType &operator=(const MyComplexType &other) |
73 | { |
74 | if (this == &other) |
75 | return *this; |
76 | x = other.x; |
77 | magicCheck = other.magicCheck; |
78 | return *this; |
79 | } |
80 | |
81 | int x; |
82 | int magicCheck; |
83 | |
84 | static const int ms_magic = 0xfefefefe; |
85 | static int ms_activeCount; |
86 | }; |
87 | |
88 | int MyComplexType::ms_activeCount = 0; |
89 | |
90 | void tst_QBoundedCircularBuffer::construction() |
91 | { |
92 | QBoundedCircularBuffer<int> buffer(10); |
93 | QVERIFY(buffer.capacity() == 10); |
94 | QVERIFY(buffer.freeSize() == 10); |
95 | QVERIFY(buffer.size() == 0); |
96 | QVERIFY(buffer.isEmpty() == true); |
97 | QVERIFY(buffer.isFull() == false); |
98 | } |
99 | |
100 | void tst_QBoundedCircularBuffer::clear() |
101 | { |
102 | QBoundedCircularBuffer<int> buffer(10); |
103 | buffer.clear(); |
104 | QVERIFY(buffer.capacity() == 10); |
105 | QVERIFY(buffer.freeSize() == 10); |
106 | QVERIFY(buffer.size() == 0); |
107 | QVERIFY(buffer.isEmpty() == true); |
108 | QVERIFY(buffer.isFull() == false); |
109 | } |
110 | |
111 | void tst_QBoundedCircularBuffer::push() |
112 | { |
113 | QBoundedCircularBuffer<MyComplexType> buffer(20); |
114 | QVERIFY(buffer.freeSize() == 20); |
115 | for (int i = 0; i < 15; i++) { |
116 | const MyComplexType value(i); |
117 | buffer.push(t: value); |
118 | const MyComplexType testValue = buffer.back(); |
119 | QVERIFY(testValue.x == value.x); |
120 | } |
121 | QVERIFY(buffer.freeSize() == 5); |
122 | QVERIFY(buffer.size() == 15); |
123 | } |
124 | |
125 | void tst_QBoundedCircularBuffer::pop() |
126 | { |
127 | QBoundedCircularBuffer<MyComplexType> buffer(20); |
128 | for (int i = 0; i < 15; i++) { |
129 | const MyComplexType value(i); |
130 | buffer.push(t: value); |
131 | } |
132 | |
133 | for (int j = 0; j < 10; j++) { |
134 | const MyComplexType value = buffer.pop(); |
135 | QVERIFY(value.x == j); |
136 | } |
137 | QVERIFY(buffer.freeSize() == 15); |
138 | QVERIFY(buffer.size() == 5); |
139 | } |
140 | |
141 | void tst_QBoundedCircularBuffer::at() |
142 | { |
143 | QBoundedCircularBuffer<MyComplexType> buffer(20); |
144 | for (int i = 0; i < 10; i++) { |
145 | const MyComplexType value(i); |
146 | buffer.append(t: value); |
147 | } |
148 | |
149 | for (int i = 0; i < 10; i++) |
150 | QVERIFY(buffer.at(i).x == i); |
151 | } |
152 | |
153 | class MyProducer : public QThread |
154 | { |
155 | Q_OBJECT |
156 | public: |
157 | MyProducer(QBoundedCircularBuffer<MyComplexType> *buffer) |
158 | : QThread(), |
159 | m_buffer(buffer) |
160 | { |
161 | } |
162 | |
163 | void run() |
164 | { |
165 | for (int i = 0; i < 10000; i++ ) { |
166 | //qDebug() << "Producing" << i; |
167 | const MyComplexType value(i); |
168 | //if ( m_buffer->isFull() ) |
169 | // qDebug() << i << "The buffer is full. Waiting for consumer..."; |
170 | m_buffer->push(t: value); |
171 | |
172 | // Uncomment and adjust this to slow the producer down |
173 | // usleep(130); |
174 | } |
175 | } |
176 | |
177 | private: |
178 | QBoundedCircularBuffer<MyComplexType>* m_buffer; |
179 | }; |
180 | |
181 | class MyConsumer : public QThread |
182 | { |
183 | Q_OBJECT |
184 | public: |
185 | MyConsumer(QBoundedCircularBuffer<MyComplexType>* buffer) |
186 | : QThread(), |
187 | m_buffer(buffer) |
188 | {} |
189 | |
190 | void run() |
191 | { |
192 | for (int i = 0; i < 10000; i++) { |
193 | //qDebug() << "Consuming" << i; |
194 | //if (m_buffer->isEmpty()) |
195 | // qDebug() << i << "The buffer is empty. Waiting for producer..."; |
196 | const MyComplexType value = m_buffer->pop(); |
197 | QVERIFY(value.x == i); |
198 | |
199 | // Uncomment and adjust this to slow the consumer down |
200 | //usleep(100); |
201 | } |
202 | } |
203 | |
204 | private: |
205 | QBoundedCircularBuffer<MyComplexType>* m_buffer; |
206 | }; |
207 | |
208 | void tst_QBoundedCircularBuffer::producerConsumer() |
209 | { |
210 | QBoundedCircularBuffer<MyComplexType> *buffer = new QBoundedCircularBuffer<MyComplexType>(20); |
211 | MyProducer producer(buffer); |
212 | MyConsumer consumer(buffer); |
213 | |
214 | // Produce and consume... |
215 | producer.start(); |
216 | consumer.start(); |
217 | |
218 | // Wait until both threads are done |
219 | producer.wait(); |
220 | consumer.wait(); |
221 | |
222 | // Check all items have been consumed |
223 | QVERIFY(buffer->freeSize() == 20); |
224 | QVERIFY(buffer->size() == 0); |
225 | |
226 | // Cleanup |
227 | delete buffer; |
228 | } |
229 | |
230 | QTEST_APPLESS_MAIN(tst_QBoundedCircularBuffer) |
231 | #include "tst_qboundedcircularbuffer.moc" |
232 |