Compare commits

...

3 Commits

Author SHA1 Message Date
BodgeMaster 3ba4171da3 test/nbt_size_helpers: Implement tests for valid input 2022-08-13 17:23:35 +02:00
BodgeMaster cecb2381b0 test/assert: Add line number to assertion failed message 2022-08-13 17:08:13 +02:00
BodgeMaster 2a8082139a lib/nbt: Change behavior of totalTagSize to treat encounters of compounds and lists as errors
I stumbled over this when writing the unit test. Previously, it would return
an error code but explicitly mark it as not being an error. This was intended
behavior but I decided to change it because I didn’t anticipate it when writing
the test.

Technically `ErrorOr<T>` can be used to pass any message alongside `T`,
but practically, it is reasonable to assume that the error code is
`ErrorCodes::SUCCESS` when `isError` is false. Therefore, this feature
should be really only used in the weirdest edge cases - if at all.
Even then, it is most likely still preferable to flag it as an error and
just hand the resulting `T` back using the long constructor
`ErrorOr<T>(bool, uint8_t, T)`.
2022-08-13 16:55:49 +02:00
3 changed files with 208 additions and 13 deletions

View File

@ -395,8 +395,8 @@ namespace NBT {
} else { } else {
nextTag = data[currentPosition]; nextTag = data[currentPosition];
} }
// deal with compound tags separately // deal with compound tags and lists separately
if (nextTag == TagType::COMPOUND || nextTag == TagType::LIST) return ErrorOr<uint64_t>(false, ErrorCodes::NOT_YET_KNOWN); if (nextTag == TagType::COMPOUND || nextTag == TagType::LIST) return ErrorOr<uint64_t>(true, ErrorCodes::NOT_YET_KNOWN);
// deal with end tag before trying to access the name // deal with end tag before trying to access the name
if (nextTag == TagType::END) return ErrorOr<uint64_t>(1); if (nextTag == TagType::END) return ErrorOr<uint64_t>(1);

View File

@ -15,4 +15,4 @@
#include <iostream> #include <iostream>
#define ASSERT(truth) if ((truth)); else { std::cout << "Assertion failed: " << #truth << std::endl; return 1; } #define ASSERT(truth) if ((truth)); else { std::cout << "On line " << __LINE__ << ": Assertion failed: " << #truth << std::endl; return 1; }

View File

@ -28,17 +28,89 @@ int main() {
<< "################################################################################" << "################################################################################"
<< std::endl; << std::endl;
// end tag ######################################################### // a full copy of /resources/NBT_data/simple_nbt
// const uint8_t END = 0; //
uint8_t endTestData[] = { // This contains all tag types. It is most likely not suitable for
0x00, 0x0a, 0x00, 0x11, 0x63, 0x6f, 0x6d, 0x70, // tests chasing edge cases as it is - as the name says - really
0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6c, 0x65, 0x76, // basic NBT data.
0x65, 0x6c, 0x5f, 0x32, 0x62, 0x05, 0x00, 0x03, uint8_t simpleNBTData[] = {
0x33, 0x30, 0x30, 0x6e, 0x75, 0x6f, 0x70, 0x09, 0x0a, 0x00, 0x00, 0x08, 0x00, 0x3e, 0x53, 0x70,
0x00, 0x03 0x61, 0x63, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c,
0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74,
0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x20, 0x74, 0x61, 0x67, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x2c, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x3f, 0x00, 0x16, 0x49, 0x64,
0x6b, 0x2e, 0x20, 0x4c, 0x65, 0x74, 0xe2, 0x80,
0x99, 0x73, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x20,
0x6f, 0x75, 0x74, 0x2e, 0x0a, 0x00, 0x08, 0x63,
0x6f, 0x6d, 0x70, 0x6f, 0x75, 0x6e, 0x64, 0x03,
0x00, 0x0b, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x6e,
0x75, 0x6d, 0x62, 0x65, 0x72, 0xd3, 0x07, 0x23,
0x41, 0x08, 0x00, 0x09, 0x73, 0x6f, 0x6d, 0x65,
0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x0c, 0x65,
0x61, 0x74, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6f,
0x6b, 0x69, 0x65, 0x00, 0x06, 0x00, 0x06, 0x64,
0x6f, 0x75, 0x62, 0x6c, 0x65, 0x41, 0x23, 0x07,
0xd3, 0x4e, 0xfd, 0x07, 0xf1, 0x05, 0x00, 0x05,
0x66, 0x6c, 0x6f, 0x61, 0x74, 0x42, 0x0d, 0x12,
0x43, 0x02, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x31,
0x36, 0x07, 0xd0, 0x03, 0x00, 0x05, 0x69, 0x6e,
0x74, 0x33, 0x32, 0x00, 0x9a, 0x21, 0x12, 0x0b,
0x00, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f,
0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x00,
0x04, 0x17, 0xbf, 0xe8, 0x3c, 0x00, 0x00, 0xa8,
0xfb, 0x7f, 0xff, 0xff, 0xff, 0x61, 0x72, 0x72,
0x61, 0x04, 0x00, 0x05, 0x69, 0x6e, 0x74, 0x36,
0x34, 0x00, 0x00, 0x00, 0xbc, 0x97, 0xde, 0x9e,
0x3e, 0x0c, 0x00, 0x0b, 0x69, 0x6e, 0x74, 0x36,
0x34, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xa8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x01,
0x67, 0xe7, 0xbd, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0xab, 0xd8, 0x00,
0x00, 0xab, 0xd8, 0x00, 0x0b, 0x12, 0x21, 0x00,
0x79, 0x61, 0x72, 0x01, 0x00, 0x04, 0x69, 0x6e,
0x74, 0x38, 0x64, 0x07, 0x00, 0x0a, 0x69, 0x6e,
0x74, 0x38, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79,
0x00, 0x00, 0x00, 0x08, 0x71, 0x35, 0x77, 0x62,
0x54, 0x64, 0xf5, 0x32, 0x09, 0x00, 0x09, 0x6c,
0x69, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x38,
0x01, 0x00, 0x00, 0x00, 0x05, 0x41, 0x60, 0x4e,
0x7f, 0xfa, 0x09, 0x00, 0x0c, 0x6c, 0x69, 0x73,
0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
0x73, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06,
0x50, 0x61, 0x63, 0x6d, 0x61, 0x6e, 0x00, 0x03,
0x61, 0x74, 0x65, 0x00, 0x03, 0x61, 0x6c, 0x6c,
0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x04, 0x64,
0x6f, 0x74, 0x73, 0x00, 0x02, 0x73, 0x6f, 0x00,
0x03, 0x6e, 0x6f, 0x77, 0x00, 0x06, 0x68, 0x65,
0xe2, 0x80, 0x99, 0x73, 0x00, 0x06, 0x63, 0x6f,
0x6d, 0x69, 0x6e, 0x67, 0x00, 0x03, 0x66, 0x6f,
0x72, 0x00, 0x03, 0x74, 0x68, 0x65, 0x00, 0x06,
0x77, 0x6f, 0x72, 0x64, 0x73, 0x2e, 0x08, 0x00,
0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00
}; };
ErrorOr<uint64_t> totalSize = NBT::helper::totalTagSize(endTestData, 34, 0); uint64_t simpleNBTDataSize = 478;
ErrorOr<int32_t> dataLength = NBT::helper::containedDataLength(endTestData, 34, 0);
//##################################################################
// Basic valid data tests
//##################################################################
// const uint8_t END = 0;
ErrorOr<uint64_t> totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x93);
ErrorOr<int32_t> dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x93);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 1);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 0);
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 477);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 477);
ASSERT(!totalSize.isError); ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 1); ASSERT(totalSize.value == 1);
@ -46,17 +118,140 @@ int main() {
ASSERT(dataLength.value == 0); ASSERT(dataLength.value == 0);
//const uint8_t INT8 = 1; //const uint8_t INT8 = 1;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x133);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x133);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 8);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t INT16 = 2; //const uint8_t INT16 = 2;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xb1);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xb1);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 10);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t INT32 = 3; //const uint8_t INT32 = 3;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xbb);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xbb);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 12);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x67);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x67);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 18);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t INT64 = 4; //const uint8_t INT64 = 4;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xe9);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xe9);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 16);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t FLOAT = 5; //const uint8_t FLOAT = 5;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xa5);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xa5);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 12);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t DOUBLE = 6; //const uint8_t DOUBLE = 6;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x94);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x94);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 17);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 1);
//const uint8_t INT8_ARRAY = 7; //const uint8_t INT8_ARRAY = 7;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x13b);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x13b);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 25);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 8);
//const uint8_t STRING = 8; //const uint8_t STRING = 8;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x1c6);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x1c6);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 23);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 12);
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x79);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x79);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 26);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 12);
//const uint8_t LIST = 9; //const uint8_t LIST = 9;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x154);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x154);
ASSERT(totalSize.isError);
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 5);
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x16a);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x16a);
ASSERT(totalSize.isError);
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 12);
//const uint8_t COMPOUND = 10; //const uint8_t COMPOUND = 10;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0x5c);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0x5c);
ASSERT(totalSize.isError);
ASSERT(totalSize.errorCode == ErrorCodes::NOT_YET_KNOWN);
ASSERT(dataLength.isError);
ASSERT(dataLength.errorCode == ErrorCodes::NOT_YET_KNOWN);
//const uint8_t INT32_ARRAY= 11; //const uint8_t INT32_ARRAY= 11;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xc7);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xc7);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 34);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 4);
//const uint8_t INT64_ARRAY= 12; //const uint8_t INT64_ARRAY= 12;
totalSize = NBT::helper::totalTagSize(simpleNBTData, simpleNBTDataSize, 0xf9);
dataLength = NBT::helper::containedDataLength(simpleNBTData, simpleNBTDataSize, 0xf9);
ASSERT(!totalSize.isError);
ASSERT(totalSize.value == 58);
ASSERT(!dataLength.isError);
ASSERT(dataLength.value == 5);
std::cout << "Passed simple valid data test." << std::endl;
//TODO: add tests for errors and edge cases
return 0; return 0;
} }