# Testing Guide
## Overview
This crate includes unit and integration tests.
Unit tests run without external dependencies, test parsing, error handling, and FFI layer.
The integration tests require a valid 1Password service account token to test actual SDK operations
## Prerequisites
### Unit Tests
No setup required. Unit tests run automatically with:
```bash
cargo test --lib
```
### Integration Tests
1. **Create a 1Password service account**
- Go to your 1Password account settings
- Create a new service account
- Note: Personal account tokens are NOT supported
2. **Set up a test vault**
- Create or use an existing vault (e.g., "Development")
- Grant the service account access to this vault
3. **Create a test item**
- Create an item in the vault with a known field value
- Example: Create a "test-secret" item with a "password" field
## Environment Variables
| `OP_SERVICE_ACCOUNT_TOKEN` | Yes\* | Service account token (starts with `ops_`) |
| `TEST_SECRET_REF` | Yes\* | Secret reference in format `op://vault/item/field` |
| `TEST_SECRET_VALUE` | No | Expected value for verification |
\*Required for integration tests only
### Example Setup
```bash
export OP_SERVICE_ACCOUNT_TOKEN="ops_..."
export TEST_SECRET_REF="op://Development/test-secret/password"
export TEST_SECRET_VALUE="expected-value" # Optional
```
## Running Tests
### Unit Tests (No credentials needed)
```bash
# Run all unit tests
cargo test --lib
# Run specific module tests
cargo test --lib client::tests
cargo test --lib error::tests
cargo test --lib secret::tests
cargo test --lib ffi::loader::tests
cargo test --lib ffi::bindings::tests
cargo test --lib ffi::protocol::tests
cargo test --lib ffi::uniffi_types::tests
# Run with verbose output
cargo test --lib -- --nocapture
```
### Integration Tests (credentials required)
```bash
# Set environment variables first
export OP_SERVICE_ACCOUNT_TOKEN="ops_..."
export TEST_SECRET_REF="op://Vault/Item/field"
# Run integration tests only (ignored by default)
cargo test --lib -- --ignored
# Run ALL tests (unit + integration)
cargo test --lib -- --include-ignored
# Run external integration tests (tests/ directory)
cargo test --test integration -- --ignored
```
### Feature-specific tests
```bash
# Test with blocking feature
cargo test --lib --features blocking
# Test with tracing feature
cargo test --lib --features tracing
# Test with all features
cargo test --lib --all-features
# All features + integration tests
cargo test --lib --all-features -- --include-ignored
```
## Code Coverage
### Setup
```bash
# Install cargo-llvm-cov
cargo install cargo-llvm-cov
```
### Running Coverage
**Important:** Use `--ignore-filename-regex` to exclude test code from coverage metrics.
Without this flag, `#[ignore]` integration tests count as "missed lines" and artificially lower coverage.
```bash
# Run coverage on unit tests (recommended)
cargo llvm-cov --lib --ignore-filename-regex='mod tests'
# Run coverage including integration tests (credentials required)
# Note: Use --include-ignored to run BOTH unit AND integration tests
# Using just --ignored runs ONLY integration tests (skips unit tests!)
cargo llvm-cov --lib --ignore-filename-regex='mod tests' -- --include-ignored
# Generate HTML report
cargo llvm-cov --lib --ignore-filename-regex='mod tests' --html
# View at: target/llvm-cov/html/index.html
# Show text summary with line details
cargo llvm-cov --lib --ignore-filename-regex='mod tests' --text
```
### Understanding the Coverage Report
When you run `cargo llvm-cov`, you'll see a table like this:
```
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover
client.rs 258 102 60.5% 29 11 62.1% 151 55 63.6% 0 0 -
```
#### What Each Column Means
| **Regions** | Smallest trackable code units (blocks without branches). More granular than lines. |
| **Missed Regions** | Regions never executed during tests. |
| **Functions** | Total functions/methods in the file. |
| **Missed Functions** | Functions never called during tests. |
| **Lines** | Source code lines (most intuitive metric). |
| **Missed Lines** | Lines never executed during tests. |
| **Branches** | Decision points (if/else, match arms). Shows "-" when unavailable. |
#### Which Metric to Focus On
- **Lines**: Start here - "did this code run?"
- **Functions**: High-level view - "did we call this at all?"
- **Regions**: Fine-grained - useful when one line has multiple statements
- **Branches**: Decision coverage - "did we test both if and else?"
### What To Do With Missed Code
#### Is it dead code?
If a function shows 0% coverage:
| Dead code | Safe to remove |
| Future feature | Document why it exists |
| Feature-gated | Run tests with `--all-features` |
| Error handler | Keep it, hard to trigger but important |
#### Is it error handling?
Error paths often have low coverage. Options:
- Write tests that deliberately trigger errors
- Use mocks to simulate failure conditions
- Accept lower coverage for truly exceptional cases
#### Is it integration-only code?
Code requiring external dependencies (APIs, databases):
- Write integration tests with `#[ignore]` attribute
- Run `cargo llvm-cov --lib -- --ignored` with credentials
- Accept lower unit test coverage if integration tests verify it
#### Common patterns
| Unused `pub` function | Consider making private or removing |
| `impl Debug/Display` | Usually fine to leave untested |
| Match arm never hit | Verify it's reachable; if not, use `unreachable!()` |
| `From` impl never triggered | Write test that triggers the conversion |
### Coverage Targets
| **80%+ lines** | Good baseline for most projects |
| **90%+ lines** | High confidence |
| **100%** | Often impractical; diminishing returns |
### When Low Coverage Is Acceptable
- Generated code (FFI bindings, macros)
- Panic handlers and `unreachable!()` branches
- Platform-specific code (tested on other platforms)
- Debug-only code (`#[cfg(debug_assertions)]`)
## Need help?
### "Skipping: OP_SERVICE_ACCOUNT_TOKEN not set"
Integration tests are skipped when no token is available. This is expected behavior for unit test runs.
### "Authentication failed" errors
- Verify your token is valid and not expired
- Ensure the token starts with `ops_`
- Check that the service account has access to the vault
### "Secret not found" errors
- Verify the secret reference format: `op://vault/item/field`
- Check that the vault, item, and field names are correct
- Ensure the service account has read access to the item
### "Library not found" errors
The native 1Password SDK library is downloaded during build. If you see library errors:
```bash
# Clean and rebuild
cargo clean
cargo build
```
Or set a custom library path:
```bash
export ONEPASSWORD_LIB_PATH="/path/to/libop_uniffi_core.so"
```
**Security Note**: Never commit tokens to source control. Use CI secrets management.