Fixes to, test for metadata streaming.

This commit is contained in:
Andrzej Kapolka 2014-03-17 16:10:30 -07:00
parent 6d14ad6ab5
commit eb95b01aa1
4 changed files with 97 additions and 31 deletions

View file

@ -107,6 +107,14 @@ Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, QObject
_sharedObjectStreamer(*this) {
}
void Bitstream::addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject) {
_metaObjectSubstitutions.insert(className, metaObject);
}
void Bitstream::addTypeSubstitution(const QByteArray& typeName, int type) {
_typeStreamerSubstitutions.insert(typeName, getTypeStreamers().value(type));
}
const int LAST_BIT_POSITION = BITS_IN_BYTE - 1;
Bitstream& Bitstream::write(const void* data, int bits, int offset) {
@ -496,7 +504,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
objectReader = ObjectReader();
return *this;
}
const QMetaObject* metaObject = getMetaObjects().value(className);
const QMetaObject* metaObject = _metaObjectSubstitutions.value(className);
if (!metaObject) {
metaObject = getMetaObjects().value(className);
}
if (!metaObject) {
qWarning() << "Unknown class name: " << className << "\n";
}
@ -523,6 +534,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
// for hash metadata, check the names/types of the properties as well as the name hash against our own class
if (_metadataType == HASH_METADATA) {
QCryptographicHash hash(QCryptographicHash::Md5);
bool matches = true;
if (metaObject) {
int propertyIndex = 0;
for (int i = 0; i < metaObject->propertyCount(); i++) {
@ -536,21 +548,20 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
}
if (propertyIndex >= properties.size() ||
!properties.at(propertyIndex).getReader().matchesExactly(typeStreamer)) {
objectReader = ObjectReader(className, metaObject, properties);
return *this;
matches = false;
break;
}
hash.addData(property.name(), strlen(property.name()) + 1);
propertyIndex++;
}
if (propertyIndex != properties.size()) {
objectReader = ObjectReader(className, metaObject, properties);
return *this;
matches = false;
}
}
QByteArray localHashResult = hash.result();
QByteArray remoteHashResult(localHashResult.size(), 0);
read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE);
if (metaObject && localHashResult == remoteHashResult) {
if (metaObject && matches && localHashResult == remoteHashResult) {
objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject));
return *this;
}
@ -589,7 +600,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
Bitstream& Bitstream::operator>(TypeReader& reader) {
QByteArray typeName;
*this >> typeName;
const TypeStreamer* streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName);
if (!streamer) {
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
}
if (!streamer) {
qWarning() << "Unknown type name: " << typeName << "\n";
}

View file

@ -222,6 +222,12 @@ public:
/// Creates a new bitstream. Note: the stream may be used for reading or writing, but not both.
Bitstream(QDataStream& underlying, MetadataType metadataType = NO_METADATA, QObject* parent = NULL);
/// Substitutes the supplied metaobject for the given class name's default mapping.
void addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject);
/// Substitutes the supplied type for the given type name's default mapping.
void addTypeSubstitution(const QByteArray& typeName, int type);
/// Writes a set of bits to the underlying stream.
/// \param bits the number of bits to write
/// \param offset the offset of the first bit
@ -363,6 +369,9 @@ private:
WeakSharedObjectHash _weakSharedObjectHash;
QHash<QByteArray, const QMetaObject*> _metaObjectSubstitutions;
QHash<QByteArray, const TypeStreamer*> _typeStreamerSubstitutions;
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
static QHash<int, const TypeStreamer*>& getTypeStreamers();

View file

@ -34,23 +34,65 @@ static int streamedBytesReceived = 0;
static int sharedObjectsCreated = 0;
static int sharedObjectsDestroyed = 0;
static QByteArray createRandomBytes(int minimumSize, int maximumSize) {
QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0);
for (int i = 0; i < bytes.size(); i++) {
bytes[i] = rand();
}
return bytes;
}
static QByteArray createRandomBytes() {
const int MIN_BYTES = 4;
const int MAX_BYTES = 16;
return createRandomBytes(MIN_BYTES, MAX_BYTES);
}
static bool testSerialization(Bitstream::MetadataType metadataType) {
QByteArray array;
QDataStream outStream(&array, QIODevice::WriteOnly);
Bitstream out(outStream, metadataType);
SharedObjectPointer testObjectWritten = new TestSharedObjectA(randFloat());
out << testObjectWritten;
SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat());
out << testObjectWrittenA;
SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes());
out << testObjectWrittenB;
QByteArray endWritten = "end";
out << endWritten;
out.flush();
QDataStream inStream(array);
Bitstream in(inStream, metadataType);
SharedObjectPointer testObjectRead;
in >> testObjectRead;
in.addMetaObjectSubstitution("TestSharedObjectA", &TestSharedObjectB::staticMetaObject);
in.addMetaObjectSubstitution("TestSharedObjectB", &TestSharedObjectA::staticMetaObject);
SharedObjectPointer testObjectReadA, testObjectReadB;
in >> testObjectReadA >> testObjectReadB;
if (!testObjectWritten->equals(testObjectRead)) {
QDebug debug = qDebug() << "Read/write mismatch";
testObjectWritten->dump(debug);
testObjectRead->dump(debug);
if (!testObjectReadA || testObjectReadA->metaObject() != &TestSharedObjectB::staticMetaObject) {
qDebug() << "Wrong class for A" << testObjectReadA << metadataType;
return true;
}
if (metadataType == Bitstream::FULL_METADATA && static_cast<TestSharedObjectA*>(testObjectWrittenA.data())->getFoo() !=
static_cast<TestSharedObjectB*>(testObjectReadA.data())->getFoo()) {
QDebug debug = qDebug() << "Failed to transfer shared field from A to B";
testObjectWrittenA->dump(debug);
testObjectReadA->dump(debug);
}
if (!testObjectReadB || testObjectReadB->metaObject() != &TestSharedObjectA::staticMetaObject) {
qDebug() << "Wrong class for B" << testObjectReadB << metadataType;
return true;
}
if (metadataType == Bitstream::FULL_METADATA && static_cast<TestSharedObjectB*>(testObjectWrittenB.data())->getFoo() !=
static_cast<TestSharedObjectA*>(testObjectReadB.data())->getFoo()) {
QDebug debug = qDebug() << "Failed to transfer shared field from B to A";
testObjectWrittenB->dump(debug);
testObjectReadB->dump(debug);
}
QByteArray endRead;
in >> endRead;
if (endWritten != endRead) {
qDebug() << "End tag mismatch." << endRead;
return true;
}
@ -100,20 +142,6 @@ bool MetavoxelTests::run() {
return false;
}
static QByteArray createRandomBytes(int minimumSize, int maximumSize) {
QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0);
for (int i = 0; i < bytes.size(); i++) {
bytes[i] = rand();
}
return bytes;
}
static QByteArray createRandomBytes() {
const int MIN_BYTES = 4;
const int MAX_BYTES = 16;
return createRandomBytes(MIN_BYTES, MAX_BYTES);
}
static SharedObjectPointer createRandomSharedObject() {
switch (randIntInRange(0, 2)) {
case 0: return new TestSharedObjectA(randFloat());
@ -354,7 +382,9 @@ void TestSharedObjectA::setFoo(float foo) {
}
}
TestSharedObjectB::TestSharedObjectB() {
TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar) :
_foo(foo),
_bar(bar) {
sharedObjectsCreated++;
}

View file

@ -89,11 +89,24 @@ private:
/// Another simple shared object.
class TestSharedObjectB : public SharedObject {
Q_OBJECT
Q_PROPERTY(float foo READ getFoo WRITE setFoo)
Q_PROPERTY(QByteArray bar READ getBar WRITE setBar)
public:
Q_INVOKABLE TestSharedObjectB();
Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray());
virtual ~TestSharedObjectB();
void setFoo(float foo) { _foo = foo; }
float getFoo() const { return _foo; }
void setBar(const QByteArray& bar) { _bar = bar; }
const QByteArray& getBar() const { return _bar; }
private:
float _foo;
QByteArray _bar;
};
/// A simple test message.