10510fcb99
Protocol Buffers interaction is just another serialization standard, while its widespread it has fortunately mostly been kept out of anything relevant or important. Mostly due to the fact that is really quite bad from a technical perspective. This adds simple and basic support for creating and parsing protocol buffer messages, mostly to allow interoperability. If you want quality: use the MessagBuilder/MessageParser ones instead.
225 lines
7.1 KiB
C++
225 lines
7.1 KiB
C++
/*
|
|
* This file is part of the Flowee project
|
|
* Copyright (C) 2021-2023 Tom Zander <tom@flowee.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "TestProtoBuf.h"
|
|
#include "fusion.pb.h"
|
|
#include "streaming/BufferPools.h"
|
|
|
|
#include <array>
|
|
#include <fstream>
|
|
#include <uint256.h>
|
|
|
|
#include <streaming/ConstBuffer.h>
|
|
#include <streaming/ProtoBuilder.h>
|
|
#include <streaming/ProtoParser.h>
|
|
|
|
template <class T>
|
|
Streaming::ConstBuffer store(T object)
|
|
{
|
|
std::string data;
|
|
object->SerializeToString(&data);
|
|
auto &pool = Streaming::pool(data.size());
|
|
memcpy(pool.begin(), data.c_str(), data.size());
|
|
return pool.commit(data.size());
|
|
}
|
|
|
|
TestProtoBuf::TestProtoBuf()
|
|
: testString("testApp1"),
|
|
hash(uint256S("0x1234567890aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
|
{
|
|
}
|
|
|
|
void TestProtoBuf::testParser()
|
|
{
|
|
auto oc = new fusion::ClientHello;
|
|
oc->set_version(testString);
|
|
auto stored = store(oc);
|
|
|
|
Streaming::ProtoParser pp(stored);
|
|
QCOMPARE(pp.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp.tag(), 1);
|
|
QCOMPARE(pp.isByteArray(), true);
|
|
QCOMPARE(pp.dataLength(), testString.size());
|
|
QCOMPARE(pp.stringData(), testString);
|
|
QCOMPARE(pp.next(), Streaming::EndOfDocument);
|
|
|
|
oc->set_genesis_hash(hash.begin(), 32);
|
|
stored = store(oc);
|
|
Streaming::ProtoParser pp2(stored);
|
|
QCOMPARE(pp2.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp2.tag(), 1);
|
|
QCOMPARE(pp2.isByteArray(), true);
|
|
QCOMPARE(pp2.dataLength(), testString.size());
|
|
QCOMPARE(pp2.stringData(), testString);
|
|
QCOMPARE(pp2.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp2.tag(), 2);
|
|
QCOMPARE(pp2.isByteArray(), true);
|
|
QCOMPARE(pp2.dataLength(), 32);
|
|
QCOMPARE(pp2.uint256Data(), hash);
|
|
QCOMPARE(pp2.next(), Streaming::EndOfDocument);
|
|
|
|
auto ic = new fusion::InputComponent;
|
|
ic->set_prev_txid(hash.begin(), 32);
|
|
ic->set_prev_index(130);
|
|
ic->set_pubkey(testString);
|
|
ic->set_amount(50000);
|
|
stored = store(ic);
|
|
Streaming::ProtoParser pp3(stored);
|
|
QCOMPARE(pp3.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp3.tag(), 1);
|
|
QCOMPARE(pp3.isByteArray(), true);
|
|
QCOMPARE(pp3.dataLength(), 32);
|
|
QCOMPARE(pp3.uint256Data(), hash);
|
|
|
|
// defined as an uint32 in the proto file.
|
|
// this is stored as a VarInt
|
|
QCOMPARE(pp3.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp3.tag(), 2);
|
|
QCOMPARE(pp3.isByteArray(), false);
|
|
QCOMPARE(pp3.isLong(), true);
|
|
QCOMPARE(pp3.isInt(), true);
|
|
QCOMPARE(pp3.intData(), 130);
|
|
|
|
QCOMPARE(pp3.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp3.tag(), 3);
|
|
QCOMPARE(pp3.isByteArray(), true);
|
|
QCOMPARE(pp3.dataLength(), testString.size());
|
|
QCOMPARE(pp3.stringData(), testString);
|
|
|
|
// defined as an uint64 in the proto file.
|
|
// this is stored as a VarInt
|
|
QCOMPARE(pp3.next(), Streaming::FoundTag);
|
|
QCOMPARE(pp3.tag(), 4);
|
|
QCOMPARE(pp3.isByteArray(), false);
|
|
QCOMPARE(pp3.isLong(), true);
|
|
QCOMPARE(pp3.isInt(), true);
|
|
QCOMPARE(pp3.intData(), 50000);
|
|
QCOMPARE(pp3.next(), Streaming::EndOfDocument);
|
|
|
|
// test varint with different numbers
|
|
std::array<uint64_t, 5> tests = { 1000000, 123452156, 91713727327389, 200, 2200000000 };
|
|
for (auto i = 0; i < tests.size(); ++i) {
|
|
ic->set_amount(tests[i]);
|
|
stored = store(ic);
|
|
Streaming::ProtoParser parser(stored);
|
|
while (parser.next() == Streaming::FoundTag) {
|
|
if (parser.tag() == 4) {
|
|
QCOMPARE(parser.longData(), tests[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestProtoBuf::testBuilder()
|
|
{
|
|
Streaming::ProtoBuilder builder(Streaming::pool(100));
|
|
builder.add(1, testString);
|
|
builder.add(2, hash);
|
|
auto stored = builder.buffer();
|
|
|
|
auto oc = new fusion::ClientHello;
|
|
QVERIFY(oc->ParseFromArray(stored.begin(), stored.size()));
|
|
QCOMPARE(oc->version(), testString);
|
|
QCOMPARE(oc->genesis_hash(), std::string(hash.begin(), hash.end()));
|
|
}
|
|
|
|
void TestProtoBuf::testBuilder2()
|
|
{
|
|
Streaming::ProtoBuilder builder(Streaming::pool(100));
|
|
builder.add(1, hash);
|
|
builder.add(2, 300);
|
|
builder.add(3, testString);
|
|
builder.add(4, 50000);
|
|
auto stored = builder.buffer();
|
|
|
|
auto ic = new fusion::InputComponent;
|
|
QVERIFY(ic->ParseFromArray(stored.begin(), stored.size()));
|
|
uint256 prevTxId(ic->prev_txid().c_str());
|
|
QCOMPARE(prevTxId, hash);
|
|
QCOMPARE(ic->prev_index(), 300);
|
|
QCOMPARE(ic->pubkey(), testString);
|
|
QCOMPARE(ic->amount(), 50000);
|
|
}
|
|
|
|
void TestProtoBuf::testNestedBuilder()
|
|
{
|
|
Streaming::ProtoBuilder builder(Streaming::pool(100));
|
|
builder.add(1, 123456789);
|
|
builder.add(1, 126666600);
|
|
auto nested = builder.addNestedMessage(2);
|
|
nested->add(1, testString);
|
|
nested->add(2, 5);
|
|
nested = nullptr;
|
|
|
|
auto stored = builder.buffer();
|
|
auto jp = new fusion::JoinPools;
|
|
QVERIFY(jp->ParseFromArray(stored.begin(), stored.size()));
|
|
QCOMPARE(jp->tiers_size(), 2);
|
|
QCOMPARE(jp->tiers(0), 123456789);
|
|
QCOMPARE(jp->tiers(1), 126666600);
|
|
QCOMPARE(jp->tags_size(), 1);
|
|
auto t = jp->tags(0);
|
|
QCOMPARE(t.id(), testString);
|
|
QCOMPARE(t.limit(), 5);
|
|
}
|
|
|
|
void TestProtoBuf::testNestedParser()
|
|
{
|
|
auto jp = new fusion::JoinPools;
|
|
jp->add_tiers(50);
|
|
jp->add_tiers(800);
|
|
auto *tag = jp->add_tags();
|
|
tag->set_id(testString);
|
|
tag->set_limit(601);
|
|
auto stored = store(jp);
|
|
|
|
Streaming::ProtoParser parser(stored);
|
|
QCOMPARE(parser.next(), Streaming::FoundTag);
|
|
QCOMPARE(parser.tag(), 1);
|
|
QCOMPARE(parser.intData(), 50);
|
|
QCOMPARE(parser.next(), Streaming::FoundTag);
|
|
QCOMPARE(parser.tag(), 1);
|
|
QCOMPARE(parser.intData(), 800);
|
|
QCOMPARE(parser.next(), Streaming::FoundTag);
|
|
QCOMPARE(parser.tag(), 2);
|
|
QCOMPARE(parser.isByteArray(), true);
|
|
QCOMPARE(parser.depth(), 1);
|
|
parser.enterData();
|
|
QCOMPARE(parser.depth(), 2);
|
|
QCOMPARE(parser.next(), Streaming::FoundTag);
|
|
QCOMPARE(parser.tag(), 1);
|
|
QCOMPARE(parser.isByteArray(), true);
|
|
QCOMPARE(parser.dataLength(), testString.size());
|
|
QCOMPARE(parser.stringData(), testString);
|
|
QCOMPARE(parser.next(), Streaming::FoundTag);
|
|
QCOMPARE(parser.tag(), 2);
|
|
QCOMPARE(parser.isInt(), true);
|
|
QCOMPARE(parser.intData(), 601);
|
|
QCOMPARE(parser.next(), Streaming::EndOfDocument);
|
|
QCOMPARE(parser.depth(), 2);
|
|
parser.closeData();
|
|
QCOMPARE(parser.depth(), 1);
|
|
QCOMPARE(parser.next(), Streaming::EndOfDocument);
|
|
// repeated calls have no effect.
|
|
parser.closeData();
|
|
QCOMPARE(parser.depth(), 1);
|
|
QCOMPARE(parser.next(), Streaming::EndOfDocument);
|
|
}
|
|
|
|
|
|
QTEST_MAIN(TestProtoBuf)
|