Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
30ce358
Add unit testing discovery document
briaguya0 Mar 25, 2026
1783a9e
Fix inaccuracies and add missing items to testing discovery doc
briaguya0 Mar 25, 2026
41c0560
Add unit testing implementation plan
briaguya0 Mar 25, 2026
29cd841
Set up Google Test framework with smoke test
briaguya0 Mar 25, 2026
5ef371a
Add BinaryReader basic type read tests
briaguya0 Mar 26, 2026
d02a601
Add BinaryReader string, seek, and endianness tests
briaguya0 Mar 26, 2026
e314d79
Add BinaryWriter and round-trip tests
briaguya0 Mar 26, 2026
5771605
Add StringHelper tests
briaguya0 Mar 26, 2026
1882dbc
Add TorchUtils tests
briaguya0 Mar 26, 2026
8964b11
Add Decompressor and segmented address macro tests
briaguya0 Mar 26, 2026
20497be
Add P1 testing implementation plan
briaguya0 Mar 26, 2026
bd8fbae
Add Vec3D construction and field access tests
briaguya0 Mar 26, 2026
f08c6ec
Add Vec3D width, precision, and stream output tests
briaguya0 Mar 26, 2026
a6acd95
Add TextureUtils CalculateTextureSize tests
briaguya0 Mar 26, 2026
668e266
Add alloc_ia8_text_from_i1 tests
briaguya0 Mar 26, 2026
afeb5b5
Add VtxFactory unit tests
briaguya0 Mar 26, 2026
9a8ffeb
Add DisplayListFactory unit tests
briaguya0 Mar 26, 2026
14886cc
Add P2 testing implementation plan
briaguya0 Mar 26, 2026
50515dc
Add ViewportFactory unit tests
briaguya0 Mar 26, 2026
8516f1f
Add LightsFactory unit tests
briaguya0 Mar 26, 2026
0ddb2de
Add FloatFactory unit tests
briaguya0 Mar 26, 2026
ad209ff
Add MtxFactory unit tests
briaguya0 Mar 26, 2026
535598f
Add SM64 CollisionFactory data structure unit tests
briaguya0 Mar 26, 2026
d574eeb
Add SM64 GeoLayout data structure unit tests
briaguya0 Mar 26, 2026
da77c2e
Add SM64 BehaviorScript data structure unit tests
briaguya0 Mar 26, 2026
2089226
Add CommandMacros unit tests
briaguya0 Mar 26, 2026
fab9ba4
Add Companion factory registration unit tests
briaguya0 Mar 26, 2026
c84ab5d
Add P3 testing implementation plan
briaguya0 Mar 26, 2026
b097268
Add strhash64 CRC64 unit tests
briaguya0 Mar 26, 2026
f2b976a
Add n64graphics RGBA conversion unit tests
briaguya0 Mar 26, 2026
76b3d60
Add n64graphics IA/I format conversion tests
briaguya0 Mar 26, 2026
ebfdda2
Add n64graphics CI format conversion tests
briaguya0 Mar 26, 2026
ceb1c5c
Add NAudio AudioContext string conversion tests
briaguya0 Mar 26, 2026
1819feb
Add NAudio v1 data structure unit tests
briaguya0 Mar 26, 2026
78ed627
Add SF64 Skeleton and Message data structure tests
briaguya0 Mar 26, 2026
ed762ba
Add TextureFactory data structure unit tests
briaguya0 Mar 26, 2026
ffe0003
Add P4 testing implementation plan
briaguya0 Mar 26, 2026
5dcba43
Add MK64 factory data structure tests
briaguya0 Mar 26, 2026
6173fda
Add F-Zero X ghost record checksum and data tests
briaguya0 Mar 26, 2026
7664aaa
Add F-Zero X course data and checksum tests
briaguya0 Mar 26, 2026
f8a59e5
Add F-Zero X EAD animation, limb, SoundFont, and Sequence tests
briaguya0 Mar 26, 2026
6d1c176
Add PM64 shape/entity gfx and SM64 animation data tests
briaguya0 Mar 26, 2026
8f5130b
Add integration testing plan doc
briaguya0 Mar 26, 2026
a2c00ec
Add integration test infrastructure
briaguya0 Mar 26, 2026
f8a87fd
Add SM64 US texture RGBA16 integration test
briaguya0 Mar 26, 2026
3664ab0
Add SM64 US vertex integration test
briaguya0 Mar 26, 2026
69ac710
Add SM64 US blob integration test
briaguya0 Mar 26, 2026
d735cf5
Add SM64 US collision integration test
briaguya0 Mar 26, 2026
aefc1e2
Add error handling integration tests
briaguya0 Mar 26, 2026
a68f744
Add plan for additional SM64 factory integration tests
briaguya0 Mar 26, 2026
6659c31
Add GFX and LIGHTS integration tests
briaguya0 Mar 26, 2026
f452a76
Add SM64 animation, dialog, and text integration tests
briaguya0 Mar 26, 2026
5f47abf
Add SM64 macro, movtex, trajectory, and painting integration tests
briaguya0 Mar 26, 2026
1d61ea9
Add SM64 dictionary integration test
briaguya0 Mar 26, 2026
d5dc487
Add CI workflow for unit and integration tests
briaguya0 Mar 26, 2026
bda2162
Add test review document for unit-testing-discovery branch
briaguya0 Mar 26, 2026
a0097ff
Add remediation plan for test review feedback
briaguya0 Mar 26, 2026
52a528b
Expand PM64 exclusion rationale in remediation plan
briaguya0 Mar 26, 2026
dadf4ed
Move plan documents into docs/plans/ with index prefixes
briaguya0 Mar 26, 2026
d9ddc1b
Implement test review remediation: fixes and BinaryReader upgrades
briaguya0 Mar 26, 2026
f0e209b
Add code coverage reporting plan document
briaguya0 Mar 26, 2026
8188b41
Add code coverage reporting to CI and local builds
briaguya0 Mar 26, 2026
cab9bf5
Add coverage artifacts to .gitignore
briaguya0 Mar 26, 2026
4302db2
Add SM64 integration test coverage gap analysis
briaguya0 Mar 26, 2026
437f28d
Add SM64 integration tests for level collision and non-quad movtex
briaguya0 Mar 26, 2026
7238099
Add JRB water collision integration test
briaguya0 Mar 26, 2026
7a8fc45
Add mist actor geo layout integration test
briaguya0 Mar 26, 2026
e81796b
Broaden .gitignore coverage info pattern to *.info
briaguya0 Mar 26, 2026
c796fa5
Add bowser bomb geo layout integration test
briaguya0 Mar 26, 2026
2f2a5ef
Add goomba geo layout integration test
briaguya0 Mar 26, 2026
b4eda84
Add future improvements plan document
briaguya0 Mar 26, 2026
4dfa0f9
Add summary document for plan directory
briaguya0 Mar 26, 2026
8106899
Remove plan documents from repo
briaguya0 Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Tests

on:
push:
branches: [ "*" ]
pull_request:
branches: [ "master" ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get install cmake ninja-build libbz2-dev lcov
- name: Configure
run: cmake -H. -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON -DBUILD_INTEGRATION_TESTS=ON -DENABLE_COVERAGE=ON
- name: Build
run: cmake --build build -j
- name: Unit Tests
run: build/torch_tests
- name: Integration Tests
# Integration tests require ROM files not present in CI.
# Tests will self-skip via GTEST_SKIP when ROMs are not found.
run: build/torch_integration_tests
- name: Collect Coverage
run: |
lcov --capture --directory build --output-file coverage.info --ignore-errors mismatch,inconsistent
lcov --remove coverage.info '/usr/*' '*/lib/*' '*/build/_deps/*' '*/tests/*' --output-file coverage.info --ignore-errors unused
genhtml coverage.info --output-directory coverage-report --ignore-errors inconsistent
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage-report/
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ tools/
modding/*
.cache

# Coverage
coverage-report/
*.info

# Doxygen output
docs/html
docs/latex
55 changes: 55 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ if(ENABLE_ASAN)
add_link_options(-fsanitize=address)
endif()

option(ENABLE_COVERAGE "Enable code coverage instrumentation" OFF)
if(ENABLE_COVERAGE)
add_compile_options(--coverage -fno-inline)
add_link_options(--coverage)
endif()

# Build
if (USE_STANDALONE)
add_definitions(-DSTANDALONE)
Expand Down Expand Up @@ -288,3 +294,52 @@ if(NOT USE_STANDALONE)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_include_directories(${PROJECT_NAME} PUBLIC ${yaml-cpp_SOURCE_DIR}/include)
endif()

# Unit Tests
option(BUILD_TESTS "Build unit tests" OFF)
if(BUILD_TESTS)
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.15.2
)
FetchContent_MakeAvailable(googletest)

enable_testing()

file(GLOB TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp)

set(TEST_SRC_DIR ${SRC_DIR})
list(FILTER TEST_SRC_DIR EXCLUDE REGEX "main\\.cpp$")

add_executable(torch_tests ${TEST_FILES} ${TEST_SRC_DIR})
target_include_directories(torch_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(torch_tests PRIVATE gtest_main yaml-cpp tinyxml2 N64Graphics BinaryTools spdlog)
add_test(NAME torch_tests COMMAND torch_tests)

# Integration Tests
option(BUILD_INTEGRATION_TESTS "Build integration tests (require ROM files)" OFF)
if(BUILD_INTEGRATION_TESTS)
file(GLOB INTEGRATION_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/integration/*.cpp)

add_executable(torch_integration_tests ${INTEGRATION_TEST_FILES} ${TEST_SRC_DIR})
target_include_directories(torch_integration_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/tests/integration
)
target_compile_definitions(torch_integration_tests PRIVATE
INTEGRATION_TEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/integration"
INTEGRATION_ROM_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/roms"
)
target_link_libraries(torch_integration_tests PRIVATE gtest_main yaml-cpp tinyxml2 N64Graphics BinaryTools spdlog)
add_test(NAME torch_integration_tests COMMAND torch_integration_tests)
endif()
endif()
2 changes: 0 additions & 2 deletions src/factories/sm64/AnimationFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

#include "utils/Decompressor.h"

#define ANIMINDEX_COUNT(boneCount) (((boneCount) + 1) * 6)

ExportResult SM64::AnimationBinaryExporter::Export(std::ostream& write, std::shared_ptr<IParsedData> raw,
std::string& entryName, YAML::Node& node, std::string* replacement) {
auto writer = LUS::BinaryWriter();
Expand Down
2 changes: 2 additions & 0 deletions src/factories/sm64/AnimationFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <factories/BaseFactory.h>

#define ANIMINDEX_COUNT(boneCount) (((boneCount) + 1) * 6)

namespace SM64 {
class AnimationData : public IParsedData {
public:
Expand Down
149 changes: 149 additions & 0 deletions tests/BinaryReaderTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include <gtest/gtest.h>
#include "lib/binarytools/BinaryReader.h"
#include "lib/binarytools/endianness.h"
#include "lib/binarytools/Stream.h"
#include <vector>
#include <cstring>

// Helper to create a BinaryReader from a vector of bytes
static LUS::BinaryReader MakeReader(std::vector<uint8_t>& buf, Torch::Endianness endianness = Torch::Endianness::Big) {
LUS::BinaryReader reader(buf.data(), buf.size());
reader.SetEndianness(endianness);
return reader;
}

TEST(BinaryReaderTest, ReadInt8) {
std::vector<uint8_t> buf = {0x7F};
auto reader = MakeReader(buf);
EXPECT_EQ(reader.ReadInt8(), 0x7F);
}

TEST(BinaryReaderTest, ReadInt8Negative) {
std::vector<uint8_t> buf = {0x80};
auto reader = MakeReader(buf);
EXPECT_EQ(reader.ReadInt8(), -128);
}

TEST(BinaryReaderTest, ReadUByte) {
std::vector<uint8_t> buf = {0xFF};
auto reader = MakeReader(buf);
EXPECT_EQ(reader.ReadUByte(), 0xFF);
}

TEST(BinaryReaderTest, ReadInt16BigEndian) {
std::vector<uint8_t> buf = {0x01, 0x00};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadInt16(), 256);
}

TEST(BinaryReaderTest, ReadUInt16BigEndian) {
std::vector<uint8_t> buf = {0xFF, 0xFE};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadUInt16(), 0xFFFE);
}

TEST(BinaryReaderTest, ReadInt32BigEndian) {
std::vector<uint8_t> buf = {0x00, 0x01, 0x00, 0x00};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadInt32(), 0x00010000);
}

TEST(BinaryReaderTest, ReadUInt32BigEndian) {
std::vector<uint8_t> buf = {0xDE, 0xAD, 0xBE, 0xEF};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadUInt32(), 0xDEADBEEF);
}

TEST(BinaryReaderTest, ReadUInt64BigEndian) {
std::vector<uint8_t> buf = {0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadUInt64(), 0x00000000DEADBEEF);
}

TEST(BinaryReaderTest, ReadFloat) {
// IEEE 754: 1.0f = 0x3F800000
std::vector<uint8_t> buf = {0x3F, 0x80, 0x00, 0x00};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_FLOAT_EQ(reader.ReadFloat(), 1.0f);
}

TEST(BinaryReaderTest, GetLength) {
std::vector<uint8_t> buf = {0x01, 0x02, 0x03, 0x04};
auto reader = MakeReader(buf);
EXPECT_EQ(reader.GetLength(), 4u);
}

TEST(BinaryReaderTest, ReadCString) {
// "Hi" + null terminator
std::vector<uint8_t> buf = {'H', 'i', '\0'};
auto reader = MakeReader(buf);
std::string result = reader.ReadCString();
// ReadCString includes the null terminator in the string
EXPECT_EQ(result.size(), 3u);
EXPECT_EQ(result[0], 'H');
EXPECT_EQ(result[1], 'i');
EXPECT_EQ(result[2], '\0');
}

TEST(BinaryReaderTest, ReadString) {
// ReadString reads a big-endian int32 length prefix, then that many chars
// Length = 3, then "abc"
std::vector<uint8_t> buf = {0x00, 0x00, 0x00, 0x03, 'a', 'b', 'c'};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadString(), "abc");
}

TEST(BinaryReaderTest, SeekFromStart) {
std::vector<uint8_t> buf = {0xAA, 0xBB, 0xCC, 0xDD};
auto reader = MakeReader(buf);
reader.Seek(2, LUS::SeekOffsetType::Start);
EXPECT_EQ(reader.ReadUByte(), 0xCC);
}

TEST(BinaryReaderTest, SeekFromCurrent) {
std::vector<uint8_t> buf = {0xAA, 0xBB, 0xCC, 0xDD};
auto reader = MakeReader(buf);
reader.ReadUByte(); // now at offset 1
reader.Seek(1, LUS::SeekOffsetType::Current); // skip to offset 2
EXPECT_EQ(reader.ReadUByte(), 0xCC);
}

TEST(BinaryReaderTest, GetBaseAddress) {
std::vector<uint8_t> buf = {0xAA, 0xBB, 0xCC, 0xDD};
auto reader = MakeReader(buf);
EXPECT_EQ(reader.GetBaseAddress(), 0u);
reader.ReadUByte();
EXPECT_EQ(reader.GetBaseAddress(), 1u);
reader.ReadUByte();
EXPECT_EQ(reader.GetBaseAddress(), 2u);
}

TEST(BinaryReaderTest, EndiannessSwitching) {
// 0x0102 as bytes
std::vector<uint8_t> buf = {0x01, 0x02};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadUInt16(), 0x0102);

// Reset and read as little-endian
reader.Seek(0, LUS::SeekOffsetType::Start);
reader.SetEndianness(Torch::Endianness::Native);
uint16_t native = reader.ReadUInt16();
// On little-endian (x86), native should read 0x0201
// On big-endian, native should read 0x0102
// Either way, it should differ from Big on little-endian platforms
EXPECT_EQ(reader.GetEndianness(), Torch::Endianness::Native);
(void)native; // value is platform-dependent
}

TEST(BinaryReaderTest, ReadMultipleValues) {
// Read a sequence: uint8, uint16, uint32
std::vector<uint8_t> buf = {
0xFF, // uint8
0x00, 0x0A, // uint16 = 10
0x00, 0x00, 0x01, 0x00 // uint32 = 256
};
auto reader = MakeReader(buf, Torch::Endianness::Big);
EXPECT_EQ(reader.ReadUByte(), 0xFF);
EXPECT_EQ(reader.ReadUInt16(), 10);
EXPECT_EQ(reader.ReadUInt32(), 256);
}
Loading