diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..6efaa68af --- /dev/null +++ b/.editorconfig @@ -0,0 +1,43 @@ +# EditorConfig — https://editorconfig.org +# Complements .clang-format for non-C++ files + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{cpp,h,hpp,c,idl}] +# C/C++ formatting is handled by .clang-format +indent_size = 4 + +[*.{yml,yaml}] +indent_size = 2 + +[*.{json,jsonc}] +indent_size = 2 + +[*.{md,markdown}] +trim_trailing_whitespace = false + +[*.py] +indent_size = 4 + +[*.{ps1,psm1,psd1}] +indent_size = 4 + +[*.{xml,resw,resx,props,targets,nuspec}] +indent_size = 2 + +[*.cmake] +indent_size = 4 + +[CMakeLists.txt] +indent_size = 4 + +[Makefile] +indent_style = tab diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 91a47ebdb..d81fc4f82 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,17 +4,198 @@ WSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality. -## Working Effectively +## Coding Conventions + +### Naming + +- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`) +- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`) +- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`) +- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`) +- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`) +- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`) +- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`) +- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`) + +### Error Handling + +Use WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`: +- `THROW_IF_FAILED(hr)` — throw on HRESULT failure +- `THROW_HR_IF(hr, condition)` — conditional throw +- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message +- `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation +- `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error +- `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw) +- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path +- `LOG_IF_FAILED(hr)` — log but don't throw +- `CATCH_LOG()` — catch and log exceptions + +For user-facing errors, set a localized message before throwing: +```cpp +THROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value)); +``` + +At API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions. + +### Memory Management and RAII + +Use WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup: +- `wil::unique_handle` — kernel handles +- `wil::com_ptr` — COM objects +- `wil::unique_hfile` — file handles +- `wil::unique_hkey` — registry keys +- `wil::unique_event` — events +- `wil::unique_hlocal_string` — HLOCAL strings +- `wil::unique_cotaskmem_string` — CoTaskMem strings + +For non-standard resource types, use `wil::unique_any`. + +For cleanup scopes, use `wil::scope_exit`: +```cpp +auto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); }); +// ... work ... +cleanup.release(); // dismiss on success +``` + +### Synchronization + +Use `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations: +```cpp +mutable wil::srwlock m_lock; +_Guarded_by_(m_lock) std::vector m_entries; +``` + +### Strings + +- `std::wstring` / `std::wstring_view` are dominant throughout the codebase +- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions +- Use `std::format()` for formatting (the repo defines `std::formatter` for wide-to-narrow support) +- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion + +### Copy/Move Semantics + +Use macros from `defs.h` to declare copy/move behavior: +```cpp +NON_COPYABLE(MyClass); +NON_MOVABLE(MyClass); +DEFAULT_MOVABLE(MyClass); +``` + +### Headers + +- Use `#pragma once` (no traditional `#ifndef` include guards) +- In Windows C++ components, every `.cpp` file must start with `#include "precomp.h"` +- Linux-side code (`src/linux/`) does not use precompiled headers +- Use `.h` for C-compatible headers, `.hpp` for C++-only headers +- Include order is enforced by `.clang-format` (precomp first, then system, then project) + +### Copyright Headers + +Use this single-line format for new files: +```cpp +// Copyright (C) Microsoft Corporation. All rights reserved. +``` + +Some older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing. + +### Localization + +- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings +- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings +- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw` +- In Resources.resw comments, use `{Locked="..."}` to prevent translation of `.wslconfig` property key names + +### Telemetry and Logging + +- `WSL_LOG(Name, ...)` — standard trace event +- `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`) +- `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info +- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()` + +### Platform Conditionals + +Prefer `constexpr` checks over `#ifdef` where possible: +```cpp +if constexpr (wsl::shared::Debug) { /* debug-only code */ } +if constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ } +``` + +For compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux). + +### Formatting + +Enforced by `.clang-format`: +- 130 character column limit +- 4-space indentation, no tabs +- Allman-style braces (opening brace on new line for classes, functions, structs, control statements) +- Left-aligned pointers (`int* ptr`, not `int *ptr`) +- `InsertBraces: true` — all control statements must have braces + +### IDL / COM Conventions + +When modifying service interfaces (`src/windows/service/inc/`): +- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]` +- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings +- Handle params: `[in, system_handle(sh_file)] HANDLE` +- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error` +- **Adding methods to an existing interface is an ABI break** — create a new versioned interface with a new IID +- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)` + +### Config File (.wslconfig) Conventions + +When adding settings to `src/shared/configfile/`: +- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\` line continuation +- Use the `ConfigKey` template class for type-safe parsing +- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps +- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))` +- New settings require a corresponding localization string in Resources.resw + +## Repository Navigation + +### Key Directories +- `src/windows/` — Main Windows WSL service components +- `src/linux/` — Linux-side WSL components +- `src/shared/` — Shared code between Windows and Linux +- `test/windows/` — Windows-based tests (TAEF framework) +- `test/linux/unit_tests/` — Linux unit test suite +- `doc/` — Documentation source (MkDocs) +- `tools/` — Build and deployment scripts +- `distributions/` — Distribution validation and metadata +- `localization/` — Localized string resources + +### Namespace → Directory Map + +| Namespace | Location | +|---|---| +| `wsl::shared::` | `src/shared/` | +| `wsl::windows::common::` | `src/windows/common/` | +| `wsl::windows::service::` | `src/windows/service/exe/` | +| `wsl::core::` | `src/windows/service/exe/` | +| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` | +| `wsl::linux::` | `src/linux/init/` | + +### Key Files +- `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.) +- `src/shared/inc/stringshared.h` — String conversion utilities +- `src/windows/common/WslTelemetry.h` — Telemetry macros +- `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros +- `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions +- `src/windows/service/inc/wslc.idl` — Container COM interface definitions +- `src/windows/inc/WslPluginApi.h` — Plugin API header +- `src/shared/configfile/configfile.h` — Config file parser +- `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces) + +## Building and Deploying ### Critical Platform Requirements - **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100 -- **DO NOT attempt to build the main WSL components on Linux** - they require Windows-specific APIs, MSBuild, and Visual Studio toolchain +- **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain - Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts) -### Windows Build Requirements (Required for Full Development) +### Windows Build Requirements - CMake >= 3.25 (`winget install Kitware.CMake`) - Visual Studio with these components: - - Windows SDK 26100 + - Windows SDK 26100 - MSBuild - Universal Windows platform support for v143 build tools (X64 and ARM64) - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64) @@ -29,67 +210,49 @@ WSL is the Windows Subsystem for Linux - a compatibility layer for running Linux 1. Clone the repository 2. Generate Visual Studio solution: `cmake .` 3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio -4. **NEVER CANCEL: Build takes 20-45 minutes on typical hardware. Set timeout to 60+ minutes.** Build parameters: -- `cmake . -A arm64` - Build for ARM64 -- `cmake . -DCMAKE_BUILD_TYPE=Release` - Release build -- `cmake . -DBUILD_BUNDLE=TRUE` - Build bundle msix package (requires ARM64 built first) +- `cmake . -A arm64` — Build for ARM64 +- `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build +- `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first) -### Deploying WSL (Windows Only) +### Deploying WSL (Windows Only) - Install MSI: `bin\\\wsl.msi` - OR use script: `powershell tools\deploy\deploy-to-host.ps1` - For Hyper-V VM: `powershell tools\deploy\deploy-to-vm.ps1 -VmName -Username -Password ` -## Cross-Platform Development Tasks - -### Documentation (Works on Linux/Windows) -- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages` -- Build docs: `mkdocs build -f doc/mkdocs.yml` -- **Build time: ~0.5 seconds. Set timeout to 5+ minutes for safety.** -- Output location: `doc/site/` -- **Note**: May show warnings about mermaid CDN access on restricted networks +## Testing -### Code Formatting and Validation (Works on Linux/Windows) -- Format check: `clang-format --dry-run --style=file ` -- Apply formatting: `clang-format -i --style=file ` -- Format all source: `powershell formatsource.ps1` (available at repo root after running `cmake .`) -- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py` - - **Note**: Will report missing headers in generated/dependency files (_deps/), which is expected -- Validate localization: `python3 tools/devops/validate-localization.py` - - **Note**: Only works after Windows build (requires localization/strings/en-us/Resources.resw) +### Writing Tests (TAEF Framework) -### Distribution Validation (Limited on Linux) -- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json` -- **Note**: May fail on Linux due to network restrictions accessing distribution URLs +Tests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros. -## Testing +Key points: +- Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS` +- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.) +- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()` +- Test infrastructure is in `test/windows/Common.h` -### Unit Tests (Windows Only - TAEF Framework) +### Running Tests (Windows Only) **CRITICAL: ALWAYS build the ENTIRE project before running tests:** ```powershell -# Build everything first - this is required! cmake --build . -- -m - -# Then run tests bin\\\test.bat ``` **Why full build is required:** - Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.) -- Partial builds (e.g., only `configfile` or `wsltests`) will cause test failures -- Changed components must be built together to ensure compatibility +- Partial builds will cause test failures - **DO NOT skip the full build step even if only one file changed** Test execution: - Run all tests: `bin\\\test.bat` -- **NEVER CANCEL: Full test suite takes 30-60 minutes. Set timeout to 90+ minutes.** - Run subset: `bin\\\test.bat /name:*UnitTest*` - Run specific test: `bin\\\test.bat /name:::` - WSL1 tests: Add `-Version 1` flag - Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`) -- **Requires Administrator privileges** - test.bat will fail without admin rights +- **Requires Administrator privileges** Test debugging: - Wait for debugger: `/waitfordebugger` @@ -101,62 +264,58 @@ Test debugging: - Build script: `test/linux/unit_tests/build_tests.sh` - **Note**: Requires specific Linux build environment setup not covered in main build process -## Validation Scenarios +## Cross-Platform Validation Tasks -### Always Test These After Changes: -1. **Documentation Build**: Run `mkdocs build -f doc/mkdocs.yml` and verify no errors -2. **Code Formatting**: Run `clang-format --dry-run --style=file` on changed files -3. **Windows Build** (if on Windows): Full cmake build cycle -4. **Distribution Validation**: Run Python validation scripts on any distribution changes +### Documentation (Works on Linux/Windows) +- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages` +- Build docs: `mkdocs build -f doc/mkdocs.yml` +- Output location: `doc/site/` +- **Note**: May show warnings about mermaid CDN access on restricted networks -### Manual Validation Requirements -- **Windows builds**: Install MSI and test basic WSL functionality (`wsl --version`, `wsl -l`) -- **Documentation changes**: Review generated HTML in `doc/site/` -- **Distribution changes**: Test with actual WSL distribution installation +### Code Formatting and Validation +- Format all source (Windows, requires `cmake .` first): `.\FormatSource.ps1` +- Format check (Linux/cross-platform): `clang-format --dry-run --style=file ` +- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py` + - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected +- Validate localization: `python3 tools/devops/validate-localization.py` + - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`) -## Repository Navigation +### Distribution Validation (Limited on Linux) +- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json` +- **Note**: May fail on Linux due to network restrictions accessing distribution URLs -### Key Directories -- `src/windows/` - Main Windows WSL service components -- `src/linux/` - Linux-side WSL components -- `src/shared/` - Shared code between Windows and Linux -- `test/windows/` - Windows-based tests (TAEF framework) -- `test/linux/unit_tests/` - Linux unit test suite -- `doc/` - Documentation source (MkDocs) -- `tools/` - Build and deployment scripts -- `distributions/` - Distribution validation and metadata +### Pre-commit Checklist +Always run before committing: +1. `.\FormatSource.ps1` to verify formatting on changed C++ files +2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings) +3. `mkdocs build -f doc/mkdocs.yml` if documentation changed +4. Full Windows build if core components changed -### Key Files -- `CMakeLists.txt` - Main build configuration -- `doc/docs/dev-loop.md` - Developer build instructions -- `test/README.md` - Testing framework documentation -- `CONTRIBUTING.md` - Contribution guidelines -- `.clang-format` - Code formatting rules -- `UserConfig.cmake.sample` - Optional build customizations +**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files. -### Frequently Used Commands (Platform-Specific) +## Frequently Used Commands -#### Windows Development: -```bash +### Windows Development +```powershell # Initial setup cmake . -cmake --build . -- -m # 20-45 minutes, NEVER CANCEL +cmake --build . -- -m -# Deploy and test +# Deploy and test powershell tools\deploy\deploy-to-host.ps1 wsl --version # Run tests -bin\x64\debug\test.bat # 30-60 minutes, NEVER CANCEL +bin\x64\debug\test.bat ``` -#### Cross-Platform Validation: -```bash -# Documentation (0.5 seconds) +### Cross-Platform Validation +```powershell +# Documentation mkdocs build -f doc/mkdocs.yml -# Code formatting -find src -name "*.cpp" -o -name "*.h" | xargs clang-format --dry-run --style=file +# Code formatting (Windows) +.\FormatSource.ps1 # Copyright header validation (reports expected issues in _deps/) python3 tools/devops/validate-copyright-headers.py @@ -171,7 +330,7 @@ python3 distributions/validate.py distributions/DistributionInfo.json ```powershell # Collect traces wpr -start diagnostics\wsl.wprp -filemode -# [reproduce issue] +# [reproduce issue] wpr -stop logs.ETL # Available profiles: @@ -194,35 +353,28 @@ debugConsole=true ``` ### Common Debugging Commands -- Debug shell: `wsl --debug-shell` +- Debug shell: `wsl --debug-shell` - Collect WSL logs: `powershell diagnostics\collect-wsl-logs.ps1` - Network logs: `powershell diagnostics\collect-wsl-logs.ps1 -LogProfile networking` -## Critical Timing and Timeout Guidelines +## Timing and Timeout Guidelines -**NEVER CANCEL these operations - always wait for completion:** +**NEVER CANCEL these operations — always wait for completion:** -- **Full Windows build**: 20-45 minutes (set timeout: 60+ minutes) -- **Full test suite**: 30-60 minutes (set timeout: 90+ minutes) -- **Unit test subset**: 5-15 minutes (set timeout: 30+ minutes) -- **Documentation build**: ~0.5 seconds (set timeout: 5+ minutes) -- **Distribution validation**: 2-5 minutes (set timeout: 15+ minutes) +| Operation | Typical Duration | Minimum Timeout | +|---|---|---| +| Full Windows build | 20-45 minutes | 60+ minutes | +| Full test suite | 30-60 minutes | 90+ minutes | +| Unit test subset | 5-15 minutes | 30+ minutes | +| Documentation build | ~0.5 seconds | 5+ minutes | +| Distribution validation | 2-5 minutes | 15+ minutes | ## CI/CD Integration ### GitHub Actions -- **distributions.yml**: Validates distribution metadata (Linux) -- **documentation.yml**: Builds and deploys docs (Linux) -- **modern-distributions.yml**: Tests modern distribution support - -### Pre-commit Validation -Always run before committing: -1. `clang-format --dry-run --style=file` on changed C++ files -2. `python3 tools/devops/validate-copyright-headers.py` (ignore _deps/ warnings) -3. `mkdocs build -f doc/mkdocs.yml` if documentation changed -4. Full Windows build if core components changed - -**Note**: The `.gitignore` file properly excludes build artifacts (*.sln, *.dll, *.pdb, obj/, bin/, etc.) - do not commit these files. +- **distributions.yml** — Validates distribution metadata (Linux) +- **documentation.yml** — Builds and deploys docs (Linux) +- **modern-distributions.yml** — Tests modern distribution support ## Development Environment Setup @@ -233,11 +385,10 @@ Always run before committing: 4. Clone repository 5. Run `cmake .` to generate solution -### Linux (Documentation/Validation Only) +### Linux (Documentation/Validation Only) 1. Install Python 3.8+ -2. Install clang-format -3. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs` -4. Clone repository -5. Run validation commands as needed +2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs` +3. Clone repository +4. Run validation commands as needed Remember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio. \ No newline at end of file diff --git a/.github/copilot/commit.md b/.github/copilot/commit.md new file mode 100644 index 000000000..93a68b0b6 --- /dev/null +++ b/.github/copilot/commit.md @@ -0,0 +1,8 @@ +## Commit Message Guidelines for WSL + +This repo has no strict commit message format. Follow these general practices: + +- Write a concise summary under 72 characters +- Use imperative mood ("Fix crash" not "Fixed crash") +- Reference GitHub issues with `(#123)` or `Fixes #123` +- Add a body paragraph for non-obvious changes explaining *why* diff --git a/.github/copilot/review.md b/.github/copilot/review.md new file mode 100644 index 000000000..b49dd0ebb --- /dev/null +++ b/.github/copilot/review.md @@ -0,0 +1,23 @@ +## Code Review Guidelines for WSL + +When reviewing code, enforce the conventions in `.github/copilot-instructions.md`. Focus especially on these high-risk areas: + +### ABI Safety (Critical) +- **Flag** new methods added to existing COM interfaces without a new versioned interface/IID +- **Flag** changed struct layouts in IDL files +- **Flag** changes to `WSLPluginHooksV1` or `WSLPluginAPIV1` structs (public API) + +### Resource Safety +- **Flag** raw `CloseHandle()`, `delete`, `free()`, or manual resource cleanup — require WIL smart pointers +- **Flag** missing `NON_COPYABLE()` / `NON_MOVABLE()` on classes that hold resources +- **Flag** lock usage without `_Guarded_by_()` SAL annotations + +### User-Facing Changes +- **Flag** hardcoded English strings — require `Localization::MessageXxx()` and Resources.resw entry +- **Flag** new `.wslconfig` settings without corresponding Resources.resw localization string +- **Flag** silent fallback on invalid config values — require `EMIT_USER_WARNING()` + +### Error Handling +- **Flag** bare `if (FAILED(hr))` — require WIL macros +- **Flag** silently swallowed errors — require `CATCH_LOG()` or `LOG_IF_FAILED()` +- **Flag** telemetry events missing privacy data tags diff --git a/.github/copilot/test.md b/.github/copilot/test.md new file mode 100644 index 000000000..99ca47399 --- /dev/null +++ b/.github/copilot/test.md @@ -0,0 +1,96 @@ +## Test Generation Guidelines for WSL + +When generating tests for this repository, follow these patterns: + +### Framework +Tests use TAEF (Test Authoring and Execution Framework). Always include `"Common.h"`. + +### Test Class Structure +```cpp +#include "Common.h" + +namespace MyFeatureTests +{ +class MyFeatureTests +{ + WSL_TEST_CLASS(MyFeatureTests) + + TEST_CLASS_SETUP(TestClassSetup) + { + VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE); + return true; + } + + TEST_CLASS_CLEANUP(TestClassCleanup) + { + LxsstuUninitialize(FALSE); + return true; + } + + TEST_METHOD(DescriptiveTestName) + { + // Test implementation + } +}; +} +``` + +### Key Rules +- Use `WSL_TEST_CLASS(Name)` — never raw `BEGIN_TEST_CLASS` +- Setup/cleanup methods must `return true` on success +- Use `VERIFY_*` macros for assertions — never `assert()` or exceptions for test validation + +### Assertion Macros +- `VERIFY_ARE_EQUAL(expected, actual)` — value equality +- `VERIFY_ARE_NOT_EQUAL(a, b)` — value inequality +- `VERIFY_IS_TRUE(condition)` — boolean check +- `VERIFY_IS_FALSE(condition)` — negative boolean check +- `VERIFY_IS_NULL(ptr)` — null check +- `VERIFY_IS_NOT_NULL(ptr)` — non-null check +- `VERIFY_WIN32_BOOL_SUCCEEDED(expr)` — Win32 BOOL result +- `VERIFY_SUCCEEDED(hr)` — HRESULT success + +### Logging in Tests +- `LogInfo(fmt, ...)` — informational messages +- `LogError(fmt, ...)` — error messages +- `LogWarning(fmt, ...)` — warnings +- `LogPass(fmt, ...)` — explicit pass messages +- `LogSkipped(fmt, ...)` — skip messages + +### Conditional Skipping +Add skip macros at the start of a test method body when the test only applies to certain environments: +```cpp +TEST_METHOD(Wsl2SpecificTest) +{ + WSL2_TEST_ONLY(); + // ... test code ... +} +``` + +Available skip macros: +- `WSL1_TEST_ONLY()` — skip unless WSL1 +- `WSL2_TEST_ONLY()` — skip unless WSL2 +- `SKIP_TEST_ARM64()` — skip on ARM64 +- `SKIP_TEST_UNSTABLE()` — skip known-flaky tests +- `WINDOWS_11_TEST_ONLY()` — skip on pre-Windows 11 +- `WSL_TEST_VERSION_REQUIRED(version)` — skip if WSL version too old + +### RAII Test Helpers +- `WslKeepAlive` — prevents UVM timeout during long-running tests; create at test start +- `WslConfigChange` — RAII wrapper that applies a temporary `.wslconfig` and restores the original on destruction: +```cpp +TEST_METHOD(TestWithCustomConfig) +{ + WslConfigChange config(L"[wsl2]\nmemory=4GB\n"); + // ... test with custom config ... + // Original .wslconfig restored when config goes out of scope +} +``` + +### Memory in Tests +- Use `ALLOC(size)` / `FREE(ptr)` macros for direct heap allocation in tests +- Prefer RAII wrappers and smart pointers for production-like code paths + +### Test Naming +- Use descriptive PascalCase names that describe the scenario: `CreateInstanceWithInvalidGuidFails`, `EchoTest`, `MountPlan9Share` +- Group related tests in the same test class