> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/dolphin-emu/dolphin/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing Practices

> Unit testing framework and best practices for Dolphin Emulator

## Overview

Dolphin uses **Google Test (gtest)** as its unit testing framework. The test suite helps ensure code quality and prevent regressions across the emulator's various components.

## Test Organization

Tests are organized in the `Source/UnitTests/` directory by component:

```
Source/UnitTests/
├── Common/          # Common utilities tests
├── Core/            # Core emulation tests
│   ├── PowerPC/     # PowerPC CPU tests
│   ├── IOS/         # IOS system tests
│   └── DSP/         # DSP tests
├── VideoCommon/     # Video backend tests
├── UnitTestsMain.cpp
└── StubHost.cpp
```

## Running Tests

### Build and Execute

<Tabs>
  <Tab title="CMake">
    ```bash theme={null}
    # Build the test target
    cmake --build . --target tests

    # Run all tests
    ctest --output-on-failure

    # Or run the tests executable directly
    ./Binaries/Tests/tests
    ```
  </Tab>

  <Tab title="Custom Target">
    ```bash theme={null}
    # Build and run tests in one command
    cmake --build . --target unittests
    ```

    <Info>
      The `unittests` target automatically runs all tests after building.
    </Info>
  </Tab>
</Tabs>

### Running Specific Tests

```bash theme={null}
# Run tests matching a pattern
./Binaries/Tests/tests --gtest_filter="BitField.*"

# Run a specific test case
./Binaries/Tests/tests --gtest_filter="BitField.Storage"

# List all available tests
./Binaries/Tests/tests --gtest_list_tests
```

## Writing Unit Tests

### Test Structure

Dolphin tests use the standard Google Test macros and structure:

```cpp theme={null}
// Copyright [year] Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <gtest/gtest.h>

#include "Common/BitField.h"
#include "Common/CommonTypes.h"

TEST(ComponentName, TestName)
{
  // Arrange
  int value = 42;
  
  // Act
  int result = ProcessValue(value);
  
  // Assert
  EXPECT_EQ(84, result);
}
```

### Common Test Patterns

<Tabs>
  <Tab title="Basic Assertions">
    ```cpp theme={null}
    TEST(MathUtils, BasicOperations)
    {
      EXPECT_EQ(4, 2 + 2);           // Equality
      EXPECT_NE(5, 2 + 2);           // Not equal
      EXPECT_LT(3, 5);               // Less than
      EXPECT_LE(3, 3);               // Less or equal
      EXPECT_GT(5, 3);               // Greater than
      EXPECT_GE(5, 5);               // Greater or equal
      EXPECT_TRUE(condition);         // Boolean true
      EXPECT_FALSE(!condition);       // Boolean false
    }
    ```
  </Tab>

  <Tab title="Table-Driven Tests">
    ```cpp theme={null}
    TEST(BitField, Read)
    {
      // Table of test values
      static u64 table[] = {
        0x0000000000000000ull,
        0xffffffffffffffffull,
        0x7fffffffffffffffull,
        0x8000000000000000ull,
      };
      
      TestUnion object;
      for (u64 val : table)
      {
        object.hex = val;
        EXPECT_EQ(val, object.full_u64);
        EXPECT_EQ(*(s64*)&val, object.full_s64);
      }
    }
    ```
  </Tab>

  <Tab title="Type Tests">
    ```cpp theme={null}
    TEST(BitField, Storage)
    {
      TestUnion object;
      
      // Verify memory layout
      EXPECT_EQ((void*)&object.hex, (void*)&object.field);
      
      // Verify sizes
      EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex));
      EXPECT_EQ(sizeof(TestUnion), sizeof(object.field));
    }
    ```
  </Tab>

  <Tab title="Fixture Tests">
    ```cpp theme={null}
    class MyTestFixture : public ::testing::Test
    {
    protected:
      void SetUp() override
      {
        // Initialize test data
        test_value = 42;
      }
      
      void TearDown() override
      {
        // Clean up
      }
      
      int test_value;
    };

    TEST_F(MyTestFixture, TestWithFixture)
    {
      EXPECT_EQ(42, test_value);
    }
    ```
  </Tab>
</Tabs>

### Real-World Example

Here's an actual test from `Source/UnitTests/Common/BitFieldTest.cpp`:

```cpp theme={null}
TEST(BitField, Assignment)
{
  TestUnion object;

  for (u64 val : table)
  {
    // Assignments with fixed values
    object.full_u64 = val;
    EXPECT_EQ(val, object.full_u64);

    object.full_s64 = (s64)val;
    EXPECT_EQ(val, object.full_u64);

    object.regular_field_unsigned = val;
    EXPECT_EQ(val & 0x7, object.regular_field_unsigned);

    object.at_dword_boundary = val;
    EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);

    // Assignment from other BitField
    object.at_dword_boundary = object.regular_field_signed;
    EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
  }
}
```

## Test Categories

### Common Component Tests

Tests for utility classes and common functionality:

* **BitField**: Bitfield manipulation (`BitFieldTest.cpp`)
* **StringUtil**: String operations (`StringUtilTest.cpp`)
* **MathUtil**: Mathematical utilities (`MathUtilTest.cpp`)
* **FileUtil**: File system operations (`FileUtilTest.cpp`)
* **Crypto**: Cryptographic functions (`SHA1Test.cpp`, `EcTest.cpp`)
* **Threading**: Thread synchronization primitives (`MutexTest.cpp`, `EventTest.cpp`)

### Core Emulation Tests

Tests for CPU, memory, and system emulation:

* **PowerPC**: CPU instruction tests (`DivUtilsTest.cpp`)
* **JIT**: JIT compiler tests (`Fres.cpp`, `Frsqrte.cpp`, `FPRF.cpp`)
* **IOS**: IOS filesystem and USB emulation (`FileSystemTest.cpp`, `SkylandersTest.cpp`)
* **DSP**: DSP assembly and acceleration (`DSPAssemblyTest.cpp`, `DSPAcceleratorTest.cpp`)
* **Memory**: Memory management (`PageFaultTest.cpp`, `MMIOTest.cpp`)

### Video Tests

Tests for graphics rendering components:

* **VertexLoader**: Vertex data processing (`VertexLoaderTest.cpp`)

## Adding New Tests

<Steps>
  <Step title="Create test file">
    Create a new `.cpp` file in the appropriate directory under `Source/UnitTests/`:

    ```cpp theme={null}
    // Source/UnitTests/Common/MyNewTest.cpp
    #include <gtest/gtest.h>
    #include "Common/MyNewFeature.h"

    TEST(MyNewFeature, BasicFunctionality)
    {
      // Test code here
      EXPECT_TRUE(true);
    }
    ```
  </Step>

  <Step title="Update CMakeLists.txt">
    Add your test file to the appropriate `CMakeLists.txt`:

    ```cmake theme={null}
    # Source/UnitTests/Common/CMakeLists.txt
    add_dolphin_test(CommonTests
      # ... existing files ...
      MyNewTest.cpp
    )
    ```
  </Step>

  <Step title="Build and run">
    Build and verify your tests pass:

    ```bash theme={null}
    cmake --build . --target tests
    ./Binaries/tests --gtest_filter="MyNewFeature.*"
    ```
  </Step>
</Steps>

## Test Framework Details

### Main Test Harness

The test suite is initialized in `UnitTestsMain.cpp`:

```cpp theme={null}
int main(int argc, char** argv)
{
  fmt::print(stderr, "Running main() from UnitTestsMain.cpp\n");
  Common::RegisterMsgAlertHandler(TestMsgHandler);

  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
```

<Info>
  The custom message handler prevents tests from breaking on assertions by automatically returning "yes" to any questions.
</Info>

### CMake Integration

The test build system is configured in `Source/UnitTests/CMakeLists.txt`:

```cmake theme={null}
enable_testing()
add_custom_target(unittests)
add_custom_command(TARGET unittests POST_BUILD 
  COMMAND ${CMAKE_CTEST_COMMAND} "--output-on-failure")

add_executable(tests EXCLUDE_FROM_ALL UnitTestsMain.cpp StubHost.cpp)
target_link_libraries(tests PRIVATE fmt::fmt gtest::gtest core uicommon)
add_test(NAME tests COMMAND tests)

macro(add_dolphin_test target)
  add_library(${target} OBJECT ${ARGN})
  target_link_libraries(${target} PUBLIC fmt::fmt gtest::gtest PRIVATE core uicommon)
  target_link_libraries(tests PRIVATE ${target})
endmacro()
```

## Best Practices

<Steps>
  <Step title="Test one thing">
    Each test should verify a single aspect of functionality:

    ```cpp theme={null}
    // Good
    TEST(Parser, HandlesEmptyInput) { }
    TEST(Parser, HandlesValidInput) { }

    // Bad - tests too many things
    TEST(Parser, Everything) { }
    ```
  </Step>

  <Step title="Use descriptive names">
    Test names should clearly describe what is being tested:

    ```cpp theme={null}
    TEST(BitField, ReadOperationsPreserveUnderlyingData)  // Good
    TEST(BitField, Test1)                                 // Bad
    ```
  </Step>

  <Step title="Prefer EXPECT over ASSERT">
    Use `EXPECT_*` instead of `ASSERT_*` to continue testing after failures:

    ```cpp theme={null}
    EXPECT_EQ(expected, actual);  // Continues on failure
    ASSERT_EQ(expected, actual);  // Stops on failure
    ```

    <Note>
      Only use `ASSERT_*` when continuing after a failure would cause crashes.
    </Note>
  </Step>

  <Step title="Test edge cases">
    Include boundary conditions and error cases:

    ```cpp theme={null}
    TEST(MathUtils, ClampHandlesBoundaries)
    {
      EXPECT_EQ(0, Clamp(-1, 0, 10));
      EXPECT_EQ(10, Clamp(11, 0, 10));
      EXPECT_EQ(5, Clamp(5, 0, 10));
    }
    ```
  </Step>

  <Step title="Keep tests fast">
    Unit tests should run quickly. Avoid slow operations or use test fixtures to share expensive setup.
  </Step>

  <Step title="Make tests independent">
    Tests should not depend on each other or on execution order.
  </Step>
</Steps>

<Warning>
  Always run the full test suite before submitting a pull request to ensure your changes don't break existing functionality.
</Warning>

## Continuous Integration

Dolphin's CI system automatically runs all tests on every pull request. Tests must pass before code can be merged.

## Next Steps

<CardGroup cols={2}>
  <Card title="Code Style" icon="code" href="/contributing/code-style">
    Review C++ coding standards
  </Card>

  <Card title="Debugging" icon="bug" href="/contributing/debugging">
    Learn debugging techniques
  </Card>
</CardGroup>
