QBitArray: fix fromBits() and actually test it

When I initially added it, it was ony for QCborValue, but I never added
the tests. Turns out there were two bugs:

[ChangeLog][QtCore][QBitArray] Fixed two bugs that caused QBitArrays
created using fromBits() not to compare equal to the equivalent
QBitArray created using other methods if the size was zero or not a
multiple of 4. If the size modulus 8 was 5, 6, or 7, the data was
actually incorrect.

Fixes: QTBUG-77285
Change-Id: Ife213d861bb14c1787e1fffd15b70573d162042c
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2019-08-01 22:56:30 -07:00
parent 39e937a538
commit 6ce9404a6e
2 changed files with 64 additions and 5 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Copyright (C) 2019 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -132,12 +132,12 @@ QT_BEGIN_NAMESPACE
* We overallocate the byte array by 1 byte. The first user bit is at
* d.data()[1]. On the extra first byte, we store the difference between the
* number of bits in the byte array (including this byte) and the number of
* bits in the bit array. Therefore, it's always a number between 8 and 15.
* bits in the bit array. Therefore, for a non-empty QBitArray, it's always a
* number between 8 and 15. For the empty one, d is the an empty QByteArray and
* *d.constData() is the QByteArray's terminating NUL (0) byte.
*
* This allows for fast calculation of the bit array size:
* inline int size() const { return (d.size() << 3) - *d.constData(); }
*
* Note: for an array of zero size, *d.constData() is the QByteArray implicit NUL.
*/
/*!
@ -326,6 +326,8 @@ void QBitArray::fill(bool value, int begin, int end)
QBitArray QBitArray::fromBits(const char *data, qsizetype size)
{
QBitArray result;
if (size == 0)
return result;
qsizetype nbytes = (size + 7) / 8;
result.d = QByteArray(nbytes + 1, Qt::Uninitialized);
@ -334,7 +336,7 @@ QBitArray QBitArray::fromBits(const char *data, qsizetype size)
// clear any unused bits from the last byte
if (size & 7)
bits[nbytes] &= 0xffU >> (size & 7);
bits[nbytes] &= 0xffU >> (8 - (size & 7));
*bits = result.d.size() * 8 - size;
return result;

View File

@ -84,6 +84,8 @@ private slots:
void operator_noteq();
void resize();
void fromBits_data();
void fromBits();
};
void tst_QBitArray::size_data()
@ -610,5 +612,60 @@ void tst_QBitArray::resize()
}
void tst_QBitArray::fromBits_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("size");
QTest::addColumn<QBitArray>("expected");
QTest::newRow("empty") << QByteArray() << 0 << QBitArray();
auto add = [](const QByteArray &tag, const char *data) {
QTest::newRow(tag) << QByteArray(data, (tag.size() + 7) / 8) << tag.size()
<< QStringToQBitArray(tag);
};
// "0" to "0000000000000000"
for (int i = 1; i < 16; ++i) {
char zero[2] = { 0, 0 };
QByteArray pattern(i, '0');
add(pattern, zero);
}
// "1" to "1111111111111111"
for (int i = 1; i < 16; ++i) {
char one[2] = { '\xff', '\xff' };
QByteArray pattern(i, '1');
add(pattern, one);
}
// trailing 0 and 1
char zero = 1;
char one = 0;
QByteArray pzero = "1";
QByteArray pone = "0";
for (int i = 2; i < 8; ++i) {
zero <<= 1;
pzero.prepend('0');
add(pzero, &zero);
one = (one << 1) | 1;
pone.prepend('1');
add(pone, &one);
}
}
void tst_QBitArray::fromBits()
{
QFETCH(QByteArray, data);
QFETCH(int, size);
QFETCH(QBitArray, expected);
QBitArray fromBits = QBitArray::fromBits(data, size);
QCOMPARE(fromBits, expected);
QCOMPARE(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected);
}
QTEST_APPLESS_MAIN(tst_QBitArray)
#include "tst_qbitarray.moc"