Files
thehub/testing/protobuf/TestProtoBuf.cpp
tomFlowee 10510fcb99 Add ProtoBuilder / ProtoParser classes
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.
2023-07-14 11:45:47 +02:00

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)