// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2022 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include <QtTest/qtest.h>

#include <QtCore/qhash.h>
#include <QtProtobuf/qprotobufserializer.h>

#include "unknownfield.qpb.h"

// NOTE: all test data in this file is generated by generate_unknownfield_data.py
// located in the ./proto folder!

class tst_protobuf_unknown_field : public QObject
{
    Q_OBJECT
private slots:
    void unknownStringField();
    void unknownIntField();
    void unknownMapField();
    void unknownRepeatedField();
};

// Deserialize a full known message into a type for which one of the fields is
// unknown, then serialize the message back to bytes.
void partialMessageRoundtrip_common(QByteArrayView data, QByteArray *out)
{
    Q_ASSERT(out);
    qtproto::tests::PartialMessage pm;
    QProtobufSerializer serializer;
    pm.deserialize(&serializer, data);

    QCOMPARE(pm.aaa(), 2);
    QCOMPARE(pm.timestamp(), 42);
    pm.setTimestamp(64); // update one field, will not affect other fields
    *out = pm.serialize(&serializer);
}

template<typename TargetType>
void partialMessageRoundtrip(QByteArrayView data, TargetType *targetMessage)
{
    Q_ASSERT(targetMessage);
    QByteArray roundtrippedProto;
    partialMessageRoundtrip_common(data, &roundtrippedProto);

    QProtobufSerializer serializer;
    targetMessage->deserialize(&serializer, roundtrippedProto);

    QCOMPARE(targetMessage->aaa(), 2);
    QCOMPARE(targetMessage->timestamp(), 64);
}

void tst_protobuf_unknown_field::unknownStringField()
{
    // "2, 42, Hello World"
    QByteArray payload = QByteArray::fromHex("0802102a1a0b48656c6c6f20576f726c64");
    qtproto::tests::StringMessage sm;
    partialMessageRoundtrip<>(payload, &sm);

    QCOMPARE(sm.stringField(), u"Hello World");

    // "2, 42, Hello World"
    // Same as above but the field number of the string is huge
    payload = QByteArray::fromHex("0802102aa2ffffff0f0b48656c6c6f20576f726c64");
    qtproto::tests::LargeIndexStringMessage lsm;
    partialMessageRoundtrip<>(payload, &lsm);

    QCOMPARE(lsm.stringField(), u"Hello World");

}

void tst_protobuf_unknown_field::unknownIntField()
{
    // "2, 42, 242"
    QByteArray payload = QByteArray::fromHex("0802102a18f201");
    qtproto::tests::IntMessage im;
    partialMessageRoundtrip<>(payload, &im);

    QCOMPARE(im.intField(), 242);
}

void tst_protobuf_unknown_field::unknownMapField()
{
    // "2, 42, {1: 2, 2: 4, 3: 6}"
    QByteArray payload = QByteArray::fromHex("0802102a1a04080110021a04080310061a0408021004");
    qtproto::tests::MapMessage mm;
    partialMessageRoundtrip<>(payload, &mm);

    QHash<QtProtobuf::int32, QtProtobuf::int32> expected{
        { 1, 2 },
        { 2, 4 },
        { 3, 6 },
    };
    QCOMPARE(mm.mapField(), expected);
}

void tst_protobuf_unknown_field::unknownRepeatedField()
{
    // "2, 42, [1, 1, 2, 3, 5, -5, -3, -2, -1, -1]"
    QByteArray payload = QByteArray::fromHex("0802102a1a370101020305fbffffffffffffffff01fdfffffffff"
                                             "fffffff01feffffffffffffffff01ffffffffffffffffff01ffff"
                                             "ffffffffffffff01");
    qtproto::tests::RepeatedMessage mm;
    partialMessageRoundtrip<>(payload, &mm);

    QList<QtProtobuf::int32> expected{ 1, 1, 2, 3, 5, -5, -3, -2, -1, -1 };
    QCOMPARE(mm.repeatedField(), expected);
}

QTEST_MAIN(tst_protobuf_unknown_field)
#include "tst_protobuf_unknown_field.moc"
