summaryrefslogtreecommitdiff
path: root/docs/handbook/libnbtplusplus/testing.md
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-05 17:37:54 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-05 17:37:54 +0300
commit32f5f761bc8e960293b4f4feaf973dd0da26d0f8 (patch)
tree8d0436fdd093d5255c3b75e45f9741882b22e2e4 /docs/handbook/libnbtplusplus/testing.md
parent64f4ddfa97c19f371fe1847b20bd26803f0a25d5 (diff)
downloadProject-Tick-32f5f761bc8e960293b4f4feaf973dd0da26d0f8.tar.gz
Project-Tick-32f5f761bc8e960293b4f4feaf973dd0da26d0f8.zip
NOISSUE Project Tick Handbook is Released!
Assisted-by: Claude:Opus-4.6-High Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'docs/handbook/libnbtplusplus/testing.md')
-rw-r--r--docs/handbook/libnbtplusplus/testing.md291
1 files changed, 291 insertions, 0 deletions
diff --git a/docs/handbook/libnbtplusplus/testing.md b/docs/handbook/libnbtplusplus/testing.md
new file mode 100644
index 0000000000..807f0fbaa8
--- /dev/null
+++ b/docs/handbook/libnbtplusplus/testing.md
@@ -0,0 +1,291 @@
+# Testing
+
+## Overview
+
+libnbt++ uses the **CxxTest** testing framework. Tests are defined as C++ header files with test classes inheriting from `CxxTest::TestSuite`. The test suite covers all tag types, I/O operations, endian conversion, zlib streams, and value semantics.
+
+Build configuration is in `test/CMakeLists.txt`.
+
+---
+
+## Build Configuration
+
+```cmake
+# test/CMakeLists.txt
+if(NOT (UNIX AND (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i[3-6]86")))
+ message(WARNING "Tests are only supported on Linux x86/x86_64")
+ return()
+endif()
+
+find_package(CxxTest REQUIRED)
+```
+
+Tests are **Linux x86/x86_64 only** due to the use of `objcopy` for embedding binary test data.
+
+### CMake Options
+
+Tests are controlled by the `NBT_BUILD_TESTS` option:
+
+```cmake
+option(NBT_BUILD_TESTS "Build libnbt++ tests" ON)
+
+if(NBT_BUILD_TESTS)
+ enable_testing()
+ add_subdirectory(test)
+endif()
+```
+
+### Binary Test Data Embedding
+
+Test data files (e.g., `bigtest.nbt`, `bigtest_uncompr`, `littletest.nbt`) are converted to object files via `objcopy` and linked directly into test executables:
+
+```cmake
+set(BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/")
+
+function(add_nbt_test name)
+ # ...
+ foreach(binfile ${ARGN})
+ set(obj "${CMAKE_CURRENT_BINARY_DIR}/${binfile}.o")
+ add_custom_command(
+ OUTPUT ${obj}
+ COMMAND objcopy -I binary -O elf64-x86-64
+ -B i386:x86-64 ${binfile} ${obj}
+ WORKING_DIRECTORY ${BINARY_DIR}
+ DEPENDS ${BINARY_DIR}/${binfile}
+ )
+ target_sources(${name} PRIVATE ${obj})
+ endforeach()
+endfunction()
+```
+
+The embedded data is accessed via extern symbols declared in `test/data.h`:
+
+```cpp
+// test/data.h
+#define DECLARE_BINARY(name) \
+ extern "C" const char _binary_##name##_start[]; \
+ extern "C" const char _binary_##name##_end[];
+
+DECLARE_BINARY(bigtest_nbt)
+DECLARE_BINARY(bigtest_uncompr)
+DECLARE_BINARY(littletest_nbt)
+DECLARE_BINARY(littletest_uncompr)
+DECLARE_BINARY(errortest_eof_nbt)
+DECLARE_BINARY(errortest_negative_length_nbt)
+DECLARE_BINARY(errortest_excessive_depth_nbt)
+```
+
+---
+
+## Test Targets
+
+| Target | Source | Tests |
+|--------|--------|-------|
+| `nbttest` | `test/nbttest.h` | Core tag types, value, compound, list, visitor |
+| `endian_str_test` | `test/endian_str_test.h` | Endian read/write roundtrips |
+| `read_test` | `test/read_test.h` | stream_reader, big/little endian, errors |
+| `write_test` | `test/write_test.h` | stream_writer, payload writing, roundtrips |
+| `zlibstream_test` | `test/zlibstream_test.h` | izlibstream, ozlibstream, compression roundtrip |
+| `format_test` | `test/format_test.cpp` | JSON text formatting |
+| `test_value` | `test/test_value.h` | Value numeric assignment and conversion |
+
+Test registration in CMake:
+
+```cmake
+add_nbt_test(nbttest nbttest.h)
+add_nbt_test(endian_str_test endian_str_test.h)
+add_nbt_test(read_test read_test.h
+ bigtest.nbt bigtest_uncompr littletest.nbt littletest_uncompr
+ errortest_eof.nbt errortest_negative_length.nbt
+ errortest_excessive_depth.nbt)
+add_nbt_test(write_test write_test.h
+ bigtest_uncompr littletest_uncompr)
+if(NBT_HAVE_ZLIB)
+ add_nbt_test(zlibstream_test zlibstream_test.h
+ bigtest.nbt bigtest_uncompr)
+endif()
+add_nbt_test(test_value test_value.h)
+```
+
+`zlibstream_test` is only built when `NBT_HAVE_ZLIB` is defined.
+
+---
+
+## Test Details
+
+### nbttest.h — Core Functionality
+
+Tests the fundamental tag and value operations:
+
+```cpp
+class NbtTest : public CxxTest::TestSuite
+{
+public:
+ void test_tag_primitive(); // Constructors, get/set, implicit conversion
+ void test_tag_string(); // String constructors, conversion operators
+ void test_tag_compound(); // Insertion, lookup, iteration, has_key()
+ void test_tag_list(); // Type enforcement, push_back, of<T>()
+ void test_tag_array(); // Vector access, constructors
+ void test_value(); // Type erasure, numeric assignment
+ void test_visitor(); // Double dispatch, visitor invocation
+ void test_equality(); // operator==, operator!= for all types
+ void test_clone(); // clone() and move_clone() correctness
+ void test_as(); // tag::as<T>() casting, bad_cast
+};
+```
+
+### read_test.h — Deserialization
+
+Tests `stream_reader` against known binary data:
+
+```cpp
+class ReadTest : public CxxTest::TestSuite
+{
+public:
+ void test_read_bigtest(); // Verifies full bigtest.nbt structure
+ void test_read_littletest(); // Little-endian variant
+ void test_read_bigtest_uncompr(); // Uncompressed big-endian
+ void test_read_littletest_uncompr(); // Uncompressed little-endian
+ void test_read_eof(); // Truncated data → input_error
+ void test_read_negative_length(); // Negative array length → input_error
+ void test_read_excessive_depth(); // >1024 nesting → input_error
+};
+```
+
+The "bigtest" validates a complex nested compound with all tag types — the standard NBT test file from the Minecraft community. Fields verified include:
+
+- `"byteTest"`: `tag_byte` with value 127
+- `"shortTest"`: `tag_short` with value 32767
+- `"intTest"`: `tag_int` with value 2147483647
+- `"longTest"`: `tag_long` with value 9223372036854775807
+- `"floatTest"`: `tag_float` with value ~0.498...
+- `"doubleTest"`: `tag_double` with value ~0.493...
+- `"stringTest"`: UTF-8 string "HELLO WORLD THIS IS A TEST STRING ÅÄÖ!"
+- `"byteArrayTest"`: 1000-element byte array
+- `"listTest (long)"`: List of 5 longs
+- `"listTest (compound)"`: List of compounds
+- Nested compound within compound
+
+### write_test.h — Serialization
+
+Tests `stream_writer` and write-then-read roundtrips:
+
+```cpp
+class WriteTest : public CxxTest::TestSuite
+{
+public:
+ void test_write_bigtest(); // Write and compare against reference
+ void test_write_littletest(); // Little-endian write
+ void test_write_payload(); // Individual payload writing
+ void test_roundtrip(); // Write → read → compare equality
+};
+```
+
+### endian_str_test.h — Byte Order
+
+Tests all numeric types through read/write roundtrips in both endiannesses:
+
+```cpp
+class EndianStrTest : public CxxTest::TestSuite
+{
+public:
+ void test_read_big();
+ void test_read_little();
+ void test_write_big();
+ void test_write_little();
+ void test_roundtrip_big();
+ void test_roundtrip_little();
+ void test_float_big();
+ void test_float_little();
+ void test_double_big();
+ void test_double_little();
+};
+```
+
+### zlibstream_test.h — Compression
+
+Tests zlib stream wrappers:
+
+```cpp
+class ZlibstreamTest : public CxxTest::TestSuite
+{
+public:
+ void test_inflate_gzip(); // Decompress gzip data
+ void test_inflate_zlib(); // Decompress zlib data
+ void test_inflate_corrupt(); // Corrupt data → zlib_error
+ void test_inflate_eof(); // Truncated data → EOF
+ void test_inflate_trailing(); // Data after compressed stream
+ void test_deflate_roundtrip(); // Compress → decompress → compare
+ void test_deflate_gzip(); // Gzip format output
+};
+```
+
+### test_value.h — Value Semantics
+
+Tests the `value` class's numeric assignment and conversion:
+
+```cpp
+class TestValue : public CxxTest::TestSuite
+{
+public:
+ void test_assign_byte();
+ void test_assign_short();
+ void test_assign_int();
+ void test_assign_long();
+ void test_assign_float();
+ void test_assign_double();
+ void test_assign_widening(); // int8 → int16 → int32 → int64
+ void test_assign_narrowing(); // Narrowing disallowed
+ void test_assign_string();
+};
+```
+
+### format_test.cpp — Text Output
+
+A standalone test (not CxxTest) that constructs a compound, serializes it, reads it back, and prints JSON:
+
+```cpp
+// Constructs a compound with nested types
+// Writes to stringstream, reads back
+// Outputs via operator<< (json_formatter)
+```
+
+---
+
+## Running Tests
+
+```bash
+mkdir build && cd build
+cmake .. -DNBT_BUILD_TESTS=ON
+cmake --build .
+ctest
+```
+
+Or run individual tests:
+
+```bash
+./test/nbttest
+./test/read_test
+./test/write_test
+./test/endian_str_test
+./test/zlibstream_test
+./test/test_value
+```
+
+---
+
+## Test Data Files
+
+Located in `test/`:
+
+| File | Description |
+|------|-------------|
+| `bigtest.nbt` | Standard NBT test file, gzip-compressed, big-endian |
+| `bigtest_uncompr` | Same as bigtest but uncompressed |
+| `littletest.nbt` | Little-endian NBT test file, compressed |
+| `littletest_uncompr` | Little-endian, uncompressed |
+| `errortest_eof.nbt` | Truncated NBT for error testing |
+| `errortest_negative_length.nbt` | NBT with negative array length |
+| `errortest_excessive_depth.nbt` | NBT with >1024 nesting levels |
+
+These files are embedded into test binaries via `objcopy` and accessed through the `DECLARE_BINARY` macros in `data.h`.