filename:
test/stratos_test.cpp
branch:
feature/world
back to repo
/*
*
* _____ _ _
* / ___|| | | |
* \ `--. | |_ _ __ __ _ | |_ ___ ___
* `--. \| __|| '__| / _` || __| / _ \ / __|
* /\__/ /| |_ | | | (_| || |_ | (_) |\__ \
* \____/ \__||_| \__,_| \__| \___/ |___/
*
*
* 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.
*
* Copyright (C) 2025 Armen Deroian
*
*/
#include "nbt/CompoundTag.h"
#include "nbt/io/NBTBuffer.h"
#include "nbt/ListTag.h"
#include "nbt/NBT.h"
#include "nbt/PrimitiveTag.h"
#include "nbt/StringTag.h"
#include "network/protocol/PacketSerialization.h"
#include "utils/collection/PalettedStorage.h"
#include "utils/config/Config.h"
#include "utils/io/ByteBuffer.h"
#include "utils/io/CompressionUtils.h"
#include "utils/io/FileUtils.h"
#include "utils/Predicate.h"
#include "utils/StringUtils.h"
#include "utils/Validate.h"
#include <cassert>
#include <iostream>
#include <ostream>
#include <string>
void networkSerializationTest() {
std::cout << "Running network serialization test..." << std::endl;
stratos::ByteBuffer buffer;
size_t offset = 0;
// Test writing and reading a boolean
std::cout << "Testing boolean serialization..." << std::endl;
buffer.writeBoolean(true);
buffer.writeBoolean(false);
assert(buffer.readBoolean() == true);
assert(buffer.readBoolean() == false);
// Test writing and reading a byte
std::cout << "Testing byte serialization..." << std::endl;
buffer.writeByte(42);
buffer.writeByte(-42);
buffer.writeUnsignedByte(230);
assert(buffer.readByte() == 42);
assert(buffer.readByte() == -42);
assert(buffer.readUnsignedByte() == 230);
// Test writing and reading a short
std::cout << "Testing short serialization..." << std::endl;
buffer.writeShort(12345);
buffer.writeShort(-12345);
buffer.writeUnsignedShort(54321);
assert(buffer.readShort() == 12345);
assert(buffer.readShort() == -12345);
assert(buffer.readUnsignedShort() == 54321);
// Test writing and reading an int
std::cout << "Testing int serialization..." << std::endl;
buffer.writeInt(123456789);
buffer.writeInt(-123456789);
assert(buffer.readInt() == 123456789);
assert(buffer.readInt() == -123456789);
// Test writing and reading a long
std::cout << "Testing long serialization..." << std::endl;
buffer.writeLong(1234567890123456789LL);
buffer.writeLong(-1234567890123456789LL);
assert(buffer.readLong() == 1234567890123456789LL);
assert(buffer.readLong() == -1234567890123456789LL);
// Test writing and reading a float
std::cout << "Testing float serialization..." << std::endl;
buffer.writeFloat(3.14f);
buffer.writeFloat(-3.14f);
assert(buffer.readFloat() == 3.14f);
assert(buffer.readFloat() == -3.14f);
// Test writing and reading a double
std::cout << "Testing double serialization..." << std::endl;
buffer.writeDouble(3.141592653589793);
buffer.writeDouble(-3.141592653589793);
assert(buffer.readDouble() == 3.141592653589793);
assert(buffer.readDouble() == -3.141592653589793);
// Test writing and reading a VarInt
std::cout << "Testing VarInt serialization..." << std::endl;
buffer.writeVarInt(123456);
buffer.writeVarInt(-123456);
assert(buffer.readVarInt() == 123456);
assert(buffer.readVarInt() == -123456);
// Test writing and reading a string
std::cout << "Testing string serialization..." << std::endl;
const std::string testString = "Hello, world!";
buffer.writeString(testString, 100);
const std::string testString2 = "Another test string with special characters: !@#$%^&*()";
buffer.writeString(testString2, 100);
std::string testString3 = "A string with a length that exceeds the maximum allowed length.";
try {
buffer.writeString(testString, 10);
assert(false); // Should not reach here
} catch (const stratos::PacketSerializationException& e) {
}
assert(buffer.readString(100) == testString);
assert(buffer.readString(100) == testString2);
// Test writing and reading a VarLong
std::cout << "Testing VarLong serialization..." << std::endl;
buffer.writeVarLong(1234567890123456789LL);
buffer.writeVarLong(-1234567890123456789LL);
assert(buffer.readVarLong() == 1234567890123456789LL);
assert(buffer.readVarLong() == -1234567890123456789LL);
}
void fileUtilsTest() {
stratos::Path path("fileUtils");
if (path.exists()) {
assert(path.isDirectory());
assert(path.rmdir());
}
assert(!path.exists());
assert(!path.isDirectory());
assert(path.mkdir());
assert(path.exists());
assert(!path.isAbsolute());
assert(path.isRelative());
assert(!path.isFile());
stratos::Path file = path.resolve("test.txt");
assert(!file.exists());
assert(!file.isFile());
{
std::fstream fs = stratos::open(file, std::ios::out);
fs << "Hello, Stratos!";
stratos::close(fs);
}
assert(file.exists());
assert(file.isFile());
{
std::fstream fs = stratos::open(file, std::ios::in);
std::string content;
std::getline(fs, content);
stratos::close(fs);
assert(content == "Hello, Stratos!");
}
file.remove();
assert(!file.exists());
assert(!file.isFile());
assert(path.exists() && path.isDirectory());
assert(path.rmdir());
assert(!path.exists());
assert(!path.isDirectory());
stratos::Path configDir("config");
if (configDir.exists()) {
assert(configDir.isDirectory());
assert(configDir.rmdir());
}
assert(!configDir.exists());
assert(!configDir.isDirectory());
assert(configDir.mkdir());
assert(configDir.exists());
assert(configDir.isDirectory());
stratos::Path defaultFile = configDir.resolve("testDefault.properties");
assert(!defaultFile.exists());
assert(!defaultFile.isFile());
{
stratos::PropertiesConfig config(defaultFile, "key1=value1\nkey2=value2");
config.close();
}
assert(defaultFile.exists());
assert(defaultFile.isFile());
{
stratos::PropertiesConfig config(defaultFile);
auto prop1 = config.getProperty("key1");
assert(prop1.has_value() && prop1->get().asString() == "value1");
auto prop2 = config.getProperty("key2");
assert(prop2.has_value() && prop2->get().asString() == "value2");
config.writeProperty({"key3", "value3"});
config.close();
}
{
stratos::PropertiesConfig config(defaultFile);
auto prop3 = config.getProperty("key3");
assert(prop3.has_value() && prop3->get().asString() == "value3");
config.close();
}
stratos::Path testUnder = configDir.resolve("testUnder.properties");
{
stratos::PropertiesConfig config(testUnder, "key1=value1\nkey2=value2");
config.removeProperty("key2");
config.close();
}
{
stratos::PropertiesConfig config(testUnder);
auto prop1 = config.getProperty("key1");
assert(prop1.has_value() && prop1->get().asString() == "value1");
auto prop2 = config.getProperty("key2");
assert(!prop2.has_value());
}
path.mkdirs();
stratos::Path testBytes = path.resolve("testBytes.dat");
{
stratos::ByteBuffer buffer;
buffer.writeString("Hello, Stratos!", 100);
stratos::writeAllBytes(testBytes, buffer.data());
}
{
auto bytes = stratos::readAllBytes(testBytes);
stratos::ByteBuffer buffer(bytes);
std::string readStr = buffer.readString(100);
assert(readStr == "Hello, Stratos!");
}
}
void stringUtilsTest() {
std::string trim1 = " Hello, Stratos! ";
std::string trimmed1 = stratos::trim(trim1);
assert(trimmed1 == "Hello, Stratos!");
std::string trim2 = "\t\n\r \tStratos is great!\n\r\t ";
std::string trimmed2 = stratos::trim(trim2);
assert(trimmed2 == "Stratos is great!");
std::string lower = "Hello, Stratos!";
std::string lowercased = stratos::toLower(lower);
assert(lowercased == "hello, stratos!");
std::string upper = "Hello, Stratos!";
std::string uppercased = stratos::toUpper(upper);
assert(uppercased == "HELLO, STRATOS!");
std::string replaceAllStr = "Hello, Stratos! Hello, Stratos!";
std::string replacedAll = stratos::replaceAll(replaceAllStr, "Stratos", "World");
assert(replacedAll == "Hello, World! Hello, World!");
std::string replaceFirstStr = "Hello, Stratos! Hello, Stratos!";
std::string replacedFirst = stratos::replaceFirst(replaceFirstStr, "Stratos", "World");
assert(replacedFirst == "Hello, World! Hello, Stratos!");
std::vector<std::string> elements = {"Hello", "Stratos", "World"};
std::string joined = stratos::join(", ", elements);
assert(joined == "Hello, Stratos, World");
std::string splitStr = "Hello,Stratos,World";
std::vector<std::string> splitByComma = stratos::split(splitStr, ',');
assert(splitByComma.size() == 3 && splitByComma[0] == "Hello" && splitByComma[1] == "Stratos" && splitByComma[2] == "World");
std::vector<std::string> splitBySpace = stratos::split("Hello Stratos World", " ");
assert(splitBySpace.size() == 3 && splitBySpace[0] == "Hello" && splitBySpace[1] == "Stratos" && splitBySpace[2] == "World");
}
void testReadBoolean() {
std::cout << "Testing readBoolean()..." << std::endl;
// Test data: true (0x01), false (0x00), true (0xFF)
ByteVec data = {0x01, 0x00, 0xFF};
stratos::ByteBuffer buffer(data);
assert(buffer.readBoolean() == true);
assert(buffer.readBoolean() == false);
assert(buffer.readBoolean() == true); // Non-zero is true
std::cout << "✓ readBoolean() passed" << std::endl;
}
void testReadByte() {
std::cout << "Testing readByte()..." << std::endl;
// Test data: 127, -128, 0, -1
ByteVec data = {0x7F, 0x80, 0x00, 0xFF};
stratos::ByteBuffer buffer(data);
assert(buffer.readByte() == 127);
assert(buffer.readByte() == -128);
assert(buffer.readByte() == 0);
assert(buffer.readByte() == -1);
std::cout << "✓ readByte() passed" << std::endl;
}
void testReadUnsignedByte() {
std::cout << "Testing readUnsignedByte()..." << std::endl;
// Test data: 0, 127, 128, 255
ByteVec data = {0x00, 0x7F, 0x80, 0xFF};
stratos::ByteBuffer buffer(data);
assert(buffer.readUnsignedByte() == 0);
assert(buffer.readUnsignedByte() == 127);
assert(buffer.readUnsignedByte() == 128);
assert(buffer.readUnsignedByte() == 255);
std::cout << "✓ readUnsignedByte() passed" << std::endl;
}
void testReadShort() {
std::cout << "Testing readShort()..." << std::endl;
// Test data (big-endian): 0x1234, 0x8000 (-32768), 0x7FFF (32767), 0x0000
ByteVec data = {0x12, 0x34, 0x80, 0x00, 0x7F, 0xFF, 0x00, 0x00};
stratos::ByteBuffer buffer(data);
assert(buffer.readShort() == 0x1234);
assert(buffer.readShort() == -32768);
assert(buffer.readShort() == 32767);
assert(buffer.readShort() == 0);
std::cout << "✓ readShort() passed" << std::endl;
}
void testReadUnsignedShort() {
std::cout << "Testing readUnsignedShort()..." << std::endl;
// Test data (big-endian): 0x1234, 0x8000, 0xFFFF, 0x0000
ByteVec data = {0x12, 0x34, 0x80, 0x00, 0xFF, 0xFF, 0x00, 0x00};
stratos::ByteBuffer buffer(data);
assert(buffer.readUnsignedShort() == 0x1234);
assert(buffer.readUnsignedShort() == 0x8000);
assert(buffer.readUnsignedShort() == 0xFFFF);
assert(buffer.readUnsignedShort() == 0x0000);
std::cout << "✓ readUnsignedShort() passed" << std::endl;
}
void testReadInt() {
std::cout << "Testing readInt()..." << std::endl;
// Test data (big-endian): 0x12345678, 0x80000000 (-2147483648), 0x7FFFFFFF (2147483647)
ByteVec data = {
0x12, 0x34, 0x56, 0x78,
0x80, 0x00, 0x00, 0x00,
0x7F, 0xFF, 0xFF, 0xFF
};
stratos::ByteBuffer buffer(data);
assert(buffer.readInt() == 0x12345678);
assert(buffer.readInt() == -2147483648);
assert(buffer.readInt() == 2147483647);
std::cout << "✓ readInt() passed" << std::endl;
}
void testReadLong() {
std::cout << "Testing readLong()..." << std::endl;
// Test data (big-endian): 0x123456789ABCDEF0, 0x8000000000000000 (min long), 0x7FFFFFFFFFFFFFFF (max long)
ByteVec data = {
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
stratos::ByteBuffer buffer(data);
assert(buffer.readLong() == 0x123456789ABCDEF0);
assert(buffer.readLong() == (int64_t)0x8000000000000000);
assert(buffer.readLong() == 0x7FFFFFFFFFFFFFFF);
std::cout << "✓ readLong() passed" << std::endl;
}
void testReadFloat() {
std::cout << "Testing readFloat()..." << std::endl;
// Test data (IEEE 754 big-endian): 3.14159f, -1.0f, 0.0f
// 3.14159f = 0x40490FDB, -1.0f = 0xBF800000, 0.0f = 0x00000000
ByteVec data = {
0x40, 0x49, 0x0F, 0xDB,
0xBF, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
stratos::ByteBuffer buffer(data);
float pi = buffer.readFloat();
float negOne = buffer.readFloat();
float zero = buffer.readFloat();
assert(abs(pi - 3.14159f) < 0.0001f);
assert(negOne == -1.0f);
assert(zero == 0.0f);
std::cout << "✓ readFloat() passed" << std::endl;
}
void testReadDouble() {
std::cout << "Testing readDouble()..." << std::endl;
// Test data (IEEE 754 big-endian): 3.141592653589793, -1.0, 0.0
// 3.141592653589793 = 0x400921FB54442D18
// -1.0 = 0xBFF0000000000000
// 0.0 = 0x0000000000000000
ByteVec data = {
0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18,
0xBF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
stratos::ByteBuffer buffer(data);
double pi = buffer.readDouble();
double negOne = buffer.readDouble();
double zero = buffer.readDouble();
assert(abs(pi - 3.141592653589793) < 0.000000000000001);
assert(negOne == -1.0);
assert(zero == 0.0);
std::cout << "✓ readDouble() passed" << std::endl;
}
void testReadString() {
std::cout << "Testing readString()..." << std::endl;
// Test data: length (VarInt) + UTF-8 string "Hello"
// Length = 5, then "Hello" in UTF-8
ByteVec data = {
0x05, // Length: 5
'H', 'e', 'l', 'l', 'o'
};
stratos::ByteBuffer buffer(data);
std::string result = buffer.readString(10); // Max 10 chars
assert(result == "Hello");
std::cout << "✓ readString() passed" << std::endl;
}
void testReadVarInt() {
std::cout << "Testing readVarInt()..." << std::endl;
// Test data: VarInt encoding
// 0 = 0x00
// 127 = 0x7F
// 128 = 0x80, 0x01
// 300 = 0xAC, 0x02 (300 = 0x12C, encoded as 0xAC 0x02)
ByteVec data = {
0x00, // 0
0x7F, // 127
0x80, 0x01, // 128
0xAC, 0x02 // 300
};
stratos::ByteBuffer buffer(data);
assert(buffer.readVarInt() == 0);
assert(buffer.readVarInt() == 127);
assert(buffer.readVarInt() == 128);
assert(buffer.readVarInt() == 300);
std::cout << "✓ readVarInt() passed" << std::endl;
}
void testReadVarLong() {
std::cout << "Testing readVarLong()..." << std::endl;
// Test data: VarLong encoding
// 0 = 0x00
// 127 = 0x7F
// 128 = 0x80, 0x01
ByteVec data = {
0x00, // 0
0x7F, // 127
0x80, 0x01 // 128
};
stratos::ByteBuffer buffer(data);
assert(buffer.readVarLong() == 0);
assert(buffer.readVarLong() == 127);
assert(buffer.readVarLong() == 128);
std::cout << "✓ readVarLong() passed" << std::endl;
}
void testReadBitSet() {
std::cout << "Testing readBitSet()..." << std::endl;
// Test data: VarInt length + bit data
// Length = 2 (2 longs), then two 64-bit values
ByteVec data = {
0x02, // VarInt: 2 longs
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, // First long: 15
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0 // Second long: 240
};
stratos::ByteBuffer buffer(data);
std::vector<uint64_t> bitset = buffer.readBitSet();
assert(bitset.size() == 2);
assert(bitset[0] == 15);
assert(bitset[1] == 240);
std::cout << "✓ readBitSet() passed" << std::endl;
}
void testReadFixedBitSet() {
std::cout << "Testing readFixedBitSet()..." << std::endl;
// Test data: 16 bits = 2 bytes
// 0x3C = 00111100, 0xA5 = 10100101
ByteVec data = {0x3C, 0xA5};
stratos::ByteBuffer buffer(data);
std::vector<bool> bits = buffer.readFixedBitSet(16);
assert(bits.size() == 16);
// Check specific bits (remember: bit 0 is LSB of first byte)
assert(bits[2] == true); // Bit 2 of 0x3C
assert(bits[3] == true); // Bit 3 of 0x3C
assert(bits[4] == true); // Bit 4 of 0x3C
assert(bits[5] == true); // Bit 5 of 0x3C
assert(bits[8] == true); // Bit 0 of 0xA5
assert(bits[10] == true); // Bit 2 of 0xA5
std::cout << "✓ readFixedBitSet() passed" << std::endl;
}
void testReadByteArray() {
std::cout << "Testing readByteArray()..." << std::endl;
// Test data: arbitrary bytes
ByteVec data = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE};
stratos::ByteBuffer buffer(data);
ByteVec result = buffer.readByteArray(4);
assert(result.size() == 4);
assert(result[0] == 0xDE);
assert(result[1] == 0xAD);
assert(result[2] == 0xBE);
assert(result[3] == 0xEF);
std::cout << "✓ readByteArray() passed" << std::endl;
}
void testBufferUnderflow() {
std::cout << "Testing buffer underflow exception..." << std::endl;
ByteVec data = {0x01, 0x02};
stratos::ByteBuffer buffer(data);
// Read the two bytes
buffer.readByte();
buffer.readByte();
// Try to read beyond buffer
bool exceptionThrown = false;
try {
buffer.readByte();
} catch (const stratos::BufferUnderflowException& e) {
exceptionThrown = true;
}
assert(exceptionThrown);
std::cout << "✓ BufferUnderflowException test passed" << std::endl;
}
void testUtilityMethods() {
std::cout << "Testing utility methods..." << std::endl;
stratos::ByteBuffer buffer;
// Test append
ByteVec data1 = {0x01, 0x02};
ByteVec data2 = {0x03, 0x04};
buffer.append(data1);
buffer.append(std::move(data2));
assert(buffer.readByte() == 0x01);
assert(buffer.readByte() == 0x02);
assert(buffer.readByte() == 0x03);
assert(buffer.readByte() == 0x04);
// Test clear
buffer.clear();
// Test resize and reserve
buffer.resize(10);
buffer.reserve(20);
std::cout << "✓ Utility methods test passed" << std::endl;
}
void bufferTest() {
std::cout << "Running ByteBuffer tests...\n" << std::endl;
try {
testReadBoolean();
testReadByte();
testReadUnsignedByte();
testReadShort();
testReadUnsignedShort();
testReadInt();
testReadLong();
testReadFloat();
testReadDouble();
testReadString();
testReadVarInt();
testReadVarLong();
testReadBitSet();
testReadFixedBitSet();
testReadByteArray();
testBufferUnderflow();
testUtilityMethods();
std::cout << "\n🎉 All tests passed!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "❌ Test failed: " << e.what() << std::endl;
}
}
namespace nbt = stratos::nbt;
void nbtTest() {
std::cout << "Running NBT tests" << std::endl;
stratos::Path nbtPath("nbt_test");
if (!nbtPath.exists()) {
throw std::runtime_error("Please create and add test files to the 'nbt_test' directory.");
}
{
std::cout << "Testing hello_world.nbt";
stratos::Path testFile = nbtPath.resolve("hello_world.nbt");
nbt::NBTBuffer buffer(stratos::readAllBytes(testFile));
auto [name, tag] = buffer.readTag<nbt::CompoundTag>();
assert(name == "hello world");
assert(tag->hasKey("name"));
assert((*tag)["name"].getType() == nbt::TagType::String);
assert((*tag)["name"].as<nbt::StringTag>().get() == "Bananrama");
}
{
std::cout << "Testing bigtest.nbt";
stratos::Path testFile = nbtPath.resolve("bigtest.nbt");
std::ifstream file(testFile.getNativePath(), std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
std::cout << "File size: " << size << "\n";
std::cout << "Buffer size " << stratos::readAllBytes(testFile).size() << "\n";
stratos::ByteBuffer bytes(stratos::readAllBytes(testFile));
nbt::NBTBuffer buffer((stratos::decompress(bytes).data()));
auto [name, tag] = buffer.readTag<nbt::CompoundTag>();
assert(name == "Level");
assert(tag->size() == 11);
assert(tag->hasKey("nested compound test"));
assert(tag->hasKey("intTest"));
assert(tag->hasKey("byteTest"));
assert(tag->hasKey("stringTest"));
assert(tag->hasKey("listTest (long)"));
assert(tag->hasKey("doubleTest"));
assert(tag->hasKey("floatTest"));
assert(tag->hasKey("longTest"));
assert(tag->hasKey("listTest (compound)"));
assert(tag->hasKey("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"));
assert(tag->hasKey("shortTest"));
auto nested = (*tag)["nested compound test"].as<nbt::CompoundTag>();
assert(nested.hasKey("egg"));
assert(nested.hasKey("ham"));
assert(nested["egg"].getType() == nbt::TagType::Compound);
assert(nested["ham"].getType() == nbt::TagType::Compound);
auto egg = nested["egg"].as<nbt::CompoundTag>();
auto ham = nested["ham"].as<nbt::CompoundTag>();
assert(egg.hasKey("name"));
assert(egg.hasKey("value"));
assert(ham.hasKey("name"));
assert(ham.hasKey("value"));
assert(egg["name"].getType() == nbt::TagType::String);
assert(egg["value"].getType() == nbt::TagType::Float);
assert(egg["name"].as<nbt::StringTag>().get() == "Eggbert");
assert(egg["value"].as<nbt::FloatTag>().get() == 0.5f);
assert(ham["name"].getType() == nbt::TagType::String);
assert(ham["value"].getType() == nbt::TagType::Float);
assert(ham["name"].as<nbt::StringTag>().get() == "Hampus");
assert(ham["value"].as<nbt::FloatTag>().get() == 0.75f);
assert((*tag)["intTest"].getType() == nbt::TagType::Int);
assert((*tag)["intTest"].as<nbt::IntTag>().get() == 2147483647);
assert((*tag)["byteTest"].getType() == nbt::TagType::Byte);
assert((*tag)["byteTest"].as<nbt::ByteTag>().get() == 127);
assert((*tag)["stringTest"].getType() == nbt::TagType::String);
assert((*tag)["stringTest"].as<nbt::StringTag>().get() == "HELLO WORLD THIS IS A TEST STRING ÅÄÖ!");
auto listTag = (*tag)["listTest (long)"].as<nbt::ListTag>();
assert(listTag.getListType() == nbt::TagType::Long);
assert(listTag.size() == 5);
assert(listTag[0].as<nbt::LongTag>().get() == 11LL);
assert(listTag[1].as<nbt::LongTag>().get() == 12LL);
assert(listTag.at(2).as<nbt::LongTag>().get() == 13LL);
assert(listTag[3].as<nbt::LongTag>().get() == 14LL);
assert(listTag[4].as<nbt::LongTag>().get() == 15LL);
assert((*tag)["doubleTest"].getType() == nbt::TagType::Double);
assert((*tag)["doubleTest"].as<nbt::DoubleTag>().get() == 0.49312871321823148);
assert((*tag)["floatTest"].getType() == nbt::TagType::Float);
assert((*tag)["floatTest"].as<nbt::FloatTag>().get() == 0.49823147058486938f);
assert((*tag)["longTest"].getType() == nbt::TagType::Long);
assert((*tag)["longTest"].as<nbt::LongTag>().get() == 9223372036854775807LL);
auto compoundList = (*tag)["listTest (compound)"].as<nbt::ListTag>();
assert(compoundList.getListType() == nbt::TagType::Compound);
assert(compoundList.size() == 2);
auto first = compoundList[0].as<nbt::CompoundTag>();
auto second = compoundList[1].as<nbt::CompoundTag>();
assert(first.hasKey("created-on"));
assert(second.hasKey("created-on"));
assert(first.hasKey("name"));
assert(second.hasKey("name"));
assert(first["created-on"].getType() == nbt::TagType::Long);
assert(first["name"].getType() == nbt::TagType::String);
assert(second["created-on"].getType() == nbt::TagType::Long);
assert(second["name"].getType() == nbt::TagType::String);
assert(first["created-on"].as<nbt::LongTag>().get() == 1264099775885LL);
assert(first["name"].as<nbt::StringTag>().get() == "Compound tag #0");
assert(second["created-on"].as<nbt::LongTag>().get() == 1264099775885LL);
assert(second["name"].as<nbt::StringTag>().get() == "Compound tag #1");
assert((*tag)["byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"].getType() == nbt::TagType::ByteArray);
assert((*tag)["byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"].as<nbt::ByteArrayTag>().size() == 1000);
auto byteArray = (*tag)["byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"].as<nbt::ByteArrayTag>();
for (int i = 0; i < 1000; i++) {
byteArray[i] == (i*i*255+i*7)%100;
}
assert((*tag)["shortTest"].getType() == nbt::TagType::Short);
assert((*tag)["shortTest"].as<nbt::ShortTag>().get() == 32767);
}
{
const nbt::CompoundTag plainsBiome{
nbt::CompoundTag::CompoundElement{"has_precipitation", nbt::ByteTag{true}}, nbt::CompoundTag::CompoundElement{"temperature", nbt::FloatTag{0.8}},
nbt::CompoundTag::CompoundElement{"downfall", nbt::FloatTag{0.4}},
nbt::CompoundTag::CompoundElement{
"effects",
nbt::CompoundTag{nbt::CompoundTag::CompoundElement{"fog_color", nbt::IntTag{12638463}}, nbt::CompoundTag::CompoundElement{"water_color", nbt::IntTag{4159204}},
nbt::CompoundTag::CompoundElement{"water_fog_color", nbt::IntTag{329011}}, nbt::CompoundTag::CompoundElement{"sky_color", nbt::IntTag{329011}},
nbt::CompoundTag::CompoundElement{"mood_sound", nbt::CompoundTag{nbt::CompoundTag::CompoundElement{"tick_delay", nbt::IntTag{6000}},
nbt::CompoundTag::CompoundElement{"block_search_extent", nbt::IntTag{8}},
nbt::CompoundTag::CompoundElement{"sound", nbt::StringTag{"minecraft:ambient.cave"}},
nbt::CompoundTag::CompoundElement{"offset", nbt::FloatTag{2.0f}}}}}}};
ByteVec bytes = nbt::writeNetworkNBT(plainsBiome);
auto tag = nbt::readNetworkNBT(nbt::NBTBuffer(bytes));
}
}
void paletteTest() {
// Empty Palette
{
stratos::PackedIntegerContainer palette(2, 10); // 2 bits per entry, 10 entries, max value 3 (0, 1, 2, 3)
assert(palette.getBitsPerEntry() == 2);
assert(palette.getMaxValue() == 3);
assert(palette.getSize() == 10);
// Out of range checks
try {
palette.set(0, 4);
} catch (stratos::ValidateException& e) {
assert(e.what() == std::string("Value is out of range"));
} catch (std::exception&) {
assert(false);
}
try {
palette.set(11, 0);
} catch (stratos::ValidateException& e) {
assert(e.what() == std::string("Value is out of range"));
} catch (std::exception&) {
assert(false);
}
// Populate
palette.set(0, 0);
palette.set(1, 1);
palette.set(2, 2);
palette.set(3, 3);
palette.set(4, 0);
palette.set(5, 1);
palette.set(6, 2);
palette.set(7, 3);
palette.set(8, 0);
palette.set(9, 1);
// Test Get
assert(palette.get(0) == 0);
assert(palette.get(1) == 1);
assert(palette.get(2) == 2);
assert(palette.get(3) == 3);
assert(palette.get(4) == 0);
assert(palette.get(5) == 1);
assert(palette.get(6) == 2);
assert(palette.get(7) == 3);
assert(palette.get(8) == 0);
assert(palette.get(9) == 1);
// Test Out of Range
try {
assert(palette.get(11) == 0);
} catch (stratos::ValidateException& e) {
assert(e.what() == std::string("Value is out of range"));
} catch (std::exception&) {
assert(false);
}
// Test Swap
assert(palette.swap(0, 1) == 0);
assert(palette.get(0) == 1);
assert(palette.get(1) == 1);
assert(palette.swap(1, 2) == 1);
assert(palette.get(1) == 2);
// Test Write Indices
const std::vector expected = {1, 2, 2, 3, 0, 1, 2, 3, 0, 1};
std::vector<int> out;
palette.writeIndices(out);
assert(out == expected);
}
}
class PredicateIntValue {
public:
int value;
explicit PredicateIntValue(int v) : value(v) {}
[[nodiscard]] bool isZero() const { return value == 0; }
[[nodiscard]] bool isPositive() const { return value > 0; }
[[nodiscard]] bool isNegative() const { return value < 0; }
[[nodiscard]] bool isGreaterThan(int v) const { return value > v; }
[[nodiscard]] bool isLessThan(int v) const { return value < v; }
};
void predicateTest() {
// No Args Predicate
{
stratos::Predicate predicate = &PredicateIntValue::isPositive;
PredicateIntValue value(5);
assert(predicate(value) == true);
}
// Arg Predicate
{
stratos::Predicate predicate = stratos::makePredicate(&PredicateIntValue::isGreaterThan, 3);
PredicateIntValue value(5);
assert(predicate(value) == true);
}
// AND Predicate
{
stratos::Predicate predicate1 = &PredicateIntValue::isPositive;
stratos::Predicate predicate2 = stratos::makePredicate(&PredicateIntValue::isGreaterThan, 3);
stratos::Predicate andPredicate = predicate1 && predicate2;
PredicateIntValue value(5);
assert(andPredicate(value) == true);
}
// OR Predicate
{
stratos::Predicate predicate1 = &PredicateIntValue::isPositive;
stratos::Predicate predicate2 = &PredicateIntValue::isNegative;
stratos::Predicate orPredicate = predicate1 || predicate2;
PredicateIntValue value(-5);
assert(orPredicate(value) == true);
}
// NOT Predicate
{
stratos::Predicate predicate = &PredicateIntValue::isPositive;
stratos::Predicate notPredicate = !predicate;
PredicateIntValue value(-5);
assert(notPredicate(value) == true);
}
// AND Predicate Callable
{
stratos::Predicate predicate1 = stratos::makePredicate(&PredicateIntValue::isGreaterThan, 3);
stratos::Predicate andPredicate = predicate1 && &PredicateIntValue::isNegative;
PredicateIntValue value(5);
assert(andPredicate(value) == false);
}
// OR Predicate Callable
{
stratos::Predicate predicate1 = stratos::makePredicate(&PredicateIntValue::isGreaterThan, 3);
stratos::Predicate orPredicate = predicate1 || &PredicateIntValue::isZero;
PredicateIntValue value(5);
assert(orPredicate(value) == true);
}
// Polymorphic Predicate
{
stratos::Predicate predicate = PositiveNumberPredicate() && stratos::makePredicate(&PredicateIntValue::isGreaterThan, 3);
PredicateIntValue value(5);
assert(predicate(value) == true);
value.value = -5;
assert(predicate(value) == false);
}
}
int main(const int argc, char **argv) {
for (int i = 1; i < argc; ++i) {
if (std::string arg = argv[i]; arg == "--network-serialization") {
networkSerializationTest();
} else if (arg == "--file-utils") {
fileUtilsTest();
} else if (arg == "--string-utils") {
stringUtilsTest();
} else if (arg == "--byte-buffer") {
bufferTest();
} else if (arg == "--nbt") {
nbtTest();
} else if (arg == "--palette") {
paletteTest();
} else if (arg == "--predicate") {
predicateTest();
}
}
return 0;
}