Testing
This page describes the testing strategy, tools, and conventions used in token-privilege.
Test Runner
Tests are run with cargo-nextest instead of the built-in cargo test. nextest provides better output, parallel execution, and per-test timeouts.
just test # Run all tests
just test-all # Include ignored/slow tests
Run a single test by name:
cargo nextest run -E 'test(test_name)'
Test Organization
Unit Tests Per Module
Each source module has #[cfg(test)] mod tests at the bottom with unit tests for its internal logic:
error.rs– display formatting for each error variant,Send + Syncbounds.elevation.rs– (Windows only)is_elevated()returnsOk, result is consistent across calls.privilege.rs– (Windows only)SeChangeNotifyPrivilegeis enabled, invalid names return errors, enumeration is non-empty.ffi.rs– (Windows only) handle open/close cycle, elevation query, privilege lookup (valid and invalid), privilege check, enumeration.
Stub Tests
lib.rs contains stub tests gated with #[cfg(not(target_os = "windows"))] that verify all public functions return Err(TokenPrivilegeError::UnsupportedPlatform) on non-Windows platforms:
#[cfg(not(target_os = "windows"))]
#[cfg(test)]
mod stub_tests {
#[test]
fn is_elevated_returns_unsupported() { /* ... */ }
#[test]
fn is_privilege_enabled_returns_unsupported() { /* ... */ }
#[test]
fn has_privilege_returns_unsupported() { /* ... */ }
#[test]
fn enumerate_privileges_returns_unsupported() { /* ... */ }
}
Platform-Gated Tests
Windows-specific tests in elevation.rs, privilege.rs, and ffi.rs are compiled only when target_os = "windows" because those modules are conditionally compiled. This means:
- Linux/macOS CI runners execute the stub tests and
error.rstests. - Windows CI runners execute the full FFI test suite.
Reliable Test Privilege
SeChangeNotifyPrivilege is used as the canonical test privilege because it is enabled by default on all Windows process tokens. Tests relying on this privilege do not require Administrator elevation to pass.
Property-Based Testing
The crate includes proptest as a dev dependency for property-based testing. Proptest generates random inputs and verifies that invariants hold across many cases. This is particularly useful for testing error handling with arbitrary privilege name strings.
Coverage
Coverage is measured with cargo-llvm-cov and reported in LCOV format.
Running Coverage Locally
just coverage # Generate lcov.info
just coverage-check # Fail if line coverage < 85%
just coverage-report # HTML report, opens in browser
just coverage-summary # Print per-file summary
Coverage Target
The project enforces a minimum of 85% line coverage, checked by:
just coverage-check
This threshold is also enforced in the ci-check recipe and the CI pipeline.
Coverage in CI
The CI pipeline generates coverage on Ubuntu, uploads the LCOV report to Codecov, and reports results on pull requests.
CI Test Matrix
The CI workflow runs tests across multiple platforms:
| Runner | Platform | What Runs |
|---|---|---|
windows-latest | Windows | Code quality (fmt + clippy), full FFI test suite. |
ubuntu-latest | Linux | Stub tests, error tests. |
The pipeline structure is:
- quality – formatting and Clippy checks (Windows).
- test-windows – full test suite + release build (depends on quality).
- test-linux-stubs – stub validation on Linux (depends on quality).
- coverage – generate coverage and upload to Codecov (Windows, depends on test-windows).
Writing New Tests
When adding a new test:
- Place it in the
#[cfg(test)] mod testsblock of the relevant module. - Gate Windows-specific tests with
#[cfg(target_os = "windows")](handled automatically since the module is already conditionally compiled). - Use
SeChangeNotifyPrivilegewhen you need a privilege that is reliably present and enabled. - Return
Resultfrom tests when possible to avoid.unwrap()(which is denied by Clippy in non-test code but allowed in test modules). - Run
just coverage-checkto verify the 85% threshold is maintained.