freezeray generate
Generate FreezeRay artifacts (fixtures, schema tests, or migration tests) with granular control over the workflow.
Synopsis
freezeray generate <SUBCOMMAND> [OPTIONS]
# Short alias
freezeray g <SUBCOMMAND> [OPTIONS]
Description
The generate command provides granular operations for creating FreezeRay artifacts separately.
Most important: Use generate migration-tests when starting work on a new schema version. This lets you write and test migrations as you develop.
The other subcommands (fixtures, schema-tests) are rarely needed because freeze handles them automatically.
Subcommands
migration-tests - Generate migration tests ⭐
freezeray generate migration-tests --from-schema <VERSION> --to-schema <VERSION>
Generates a migration test file that validates data migration between two schema versions.
This is the primary use case for the generate command.
See detailed documentation →
fixtures - Generate frozen fixtures (Advanced)
freezeray generate fixtures --schema <VERSION>
Generates frozen SwiftData fixtures for a specific schema version.
Rarely needed: freeze does this automatically.
See detailed documentation →
schema-tests - Generate drift tests (Advanced)
freezeray generate schema-tests --schema <VERSION>
Generates a drift test file that validates a frozen schema hasn’t changed.
Rarely needed: freeze does this automatically.
See detailed documentation →
Why Use generate migration-tests?
The Correct Workflow
Migration tests should be created when you start working on a new schema version, not after:
# 1. Freeze V2
freezeray freeze 2.0.0
# 2. Generate migration test WHEN STARTING V3 work
freezeray generate migration-tests --from-schema 2.0.0 --to-schema 3.0.0
# 3. Edit the generated test, add custom assertions
# 4. Implement V3 schema + migration
# 5. Iterate: run test → fix migration → run test (⌘U)
# 6. When ready, freeze V3
freezeray freeze 3.0.0
This lets you develop with the migration test as you build the new schema.
Key insight: freeze does NOT generate migration tests. You must explicitly run generate migration-tests when starting work on a new schema version.
generate fixtures
Generate frozen fixtures for a specific schema version.
Synopsis
freezeray generate fixtures --schema <VERSION> [OPTIONS]
Description
Generates frozen SwiftData fixtures by:
- Discovering the
@FreezeSchema(version: "X.Y.Z") annotation
- Running a freeze test in iOS Simulator
- Extracting fixtures from
/tmp to FreezeRay/Fixtures/<VERSION>/
Arguments
--schema <VERSION>, -s <VERSION>
Required. The schema version to freeze (e.g., “1.0.0”).
Must match a @FreezeSchema annotation in your source code:
@FreezeSchema(version: "3.0.0")
enum AppSchemaV3: VersionedSchema {
// ...
}
Options
--simulator <NAME>
Default: iPhone 17
iOS Simulator to use for freezing:
freezeray generate fixtures --schema 3.0.0 --simulator "iPhone 15 Pro"
--scheme <NAME>
Default: Auto-detected
Xcode scheme to build:
freezeray generate fixtures --schema 3.0.0 --scheme MyApp
--force
Overwrite existing fixtures (dangerous!):
freezeray generate fixtures --schema 3.0.0 --force
Only use --force during development before shipping to production. Overwriting frozen fixtures breaks immutability.
--output <PATH>
Default: FreezeRay/Fixtures
Custom output directory:
freezeray generate fixtures --schema 3.0.0 --output /custom/path
--config <PATH>
Path to FreezeRay.yaml config file (experimental):
freezeray generate fixtures --schema 3.0.0 --config .freezeray.yml
What Gets Created
FreezeRay/Fixtures/3.0.0/
├── App-3.0.0.sqlite # Frozen SQLite database
├── App-3.0.0.sqlite-shm # SQLite shared memory file
├── schema-3.0.0.sql # SQL DDL statements
├── schema-3.0.0.json # Human-readable schema metadata
├── schema-3.0.0.sha256 # SHA256 checksum for drift detection
└── export_metadata.txt # Timestamp and version info
Examples
Basic usage
freezeray generate fixtures --schema 3.0.0
Output:
🔍 Generating fixtures for schema version 3.0.0...
📱 Running freeze test in simulator (iPhone 17)...
📦 Extracting fixtures from simulator...
✅ Generated fixtures: FreezeRay/Fixtures/3.0.0/
- App-3.0.0.sqlite
- schema-3.0.0.sql
- schema-3.0.0.json
- schema-3.0.0.sha256
- export_metadata.txt
- App-3.0.0.sqlite-shm
freezeray g fixtures -s 3.0.0
Custom simulator
freezeray generate fixtures --schema 3.0.0 --simulator "iPhone 15"
Common Errors
”No @FreezeSchema found for version X.Y.Z”
Cause: The version doesn’t match any @FreezeSchema annotation.
Fix: Add the annotation to your schema:
@FreezeSchema(version: "3.0.0")
enum AppSchemaV3: VersionedSchema {
// ...
}
“Fixtures already exist”
Cause: Fixtures for this version already exist.
Solutions:
During development (before shipping):
freezeray generate fixtures --schema 3.0.0 --force
After shipping to production:
# Create new version instead
freezeray generate fixtures --schema 3.0.1
generate schema-tests
Generate drift test for a frozen schema version.
Synopsis
freezeray generate schema-tests --schema <VERSION> [OPTIONS]
Description
Generates a drift test file that validates the current schema definition matches the frozen fixtures.
Requirements:
- Fixtures must already exist for the specified version
- Run
freezeray generate fixtures first if needed
Arguments
--schema <VERSION>, -s <VERSION>
Required. The schema version to generate tests for (e.g., “3.0.0”).
Options
--force
Overwrite existing test file:
freezeray generate schema-tests --schema 3.0.0 --force
By default, existing test files are never overwritten (they’re user-owned).
--config <PATH>
Path to config file (experimental):
freezeray generate schema-tests --schema 3.0.0 --config .freezeray.yml
What Gets Created
// FreezeRay/Tests/AppSchemaV3_DriftTests.swift
import Testing
import FreezeRay
@testable import MyApp
/// Drift test for AppSchemaV3 v3.0.0
///
/// This test verifies that the current schema definition matches the frozen fixture.
/// If this test fails, it means the schema has been modified since it was frozen.
///
/// Note: Tests run serially to avoid SwiftData store conflicts
@Suite(.serialized)
struct AppSchemaV3_3_0_0_DriftTests {
@Test("AppSchemaV3 v3.0.0 has not drifted")
func testAppSchemaV3_3_0_0_Drift() throws {
// Call the macro-generated check function
try AppSchemaV3.__freezeray_check_3_0_0()
// TODO: Add custom data validation here
// Example:
// - Verify specific model properties exist
// - Check relationship configurations
// - Validate index definitions
}
}
Generated tests use @Suite(.serialized) to prevent parallel execution issues with SwiftData stores.
Examples
Basic usage
freezeray generate schema-tests --schema 3.0.0
Output:
🔍 Generating schema tests for version 3.0.0...
✅ Generated drift test: AppSchemaV3_DriftTests.swift
freezeray g schema-tests -s 3.0.0
Regenerate (overwrite)
freezeray generate schema-tests --schema 3.0.0 --force
Common Errors
”No fixtures found for version X.Y.Z”
Cause: Fixtures don’t exist for the specified version.
Fix: Generate fixtures first:
freezeray generate fixtures --schema 3.0.0
freezeray generate schema-tests --schema 3.0.0
“Test file already exists”
Cause: The drift test file was already generated.
Solutions:
If you want to keep your custom assertions:
# Do nothing - the existing test is yours to maintain
If you want to regenerate:
freezeray generate schema-tests --schema 3.0.0 --force
generate migration-tests
Generate migration test from one schema version to another.
Synopsis
freezeray generate migration-tests --from-schema <VERSION> --to-schema <VERSION> [OPTIONS]
Description
Generates a migration test file that validates data migration between two schema versions.
This is the key innovation of the generate command: you can create the migration test early in your development workflow, not after the fact.
Requirements:
- Fixtures must exist for
--from-schema version
@FreezeSchema must exist in code for --to-schema version
SchemaMigrationPlan must have a migration stage between versions
Behavior if test file exists:
- Does NOT overwrite (preserves user’s custom assertions)
- Prints skip message
- Use
--force to overwrite
Arguments
--from-schema <VERSION>, -f <VERSION>
Required. Source schema version (e.g., “2.0.0”).
--to-schema <VERSION>, -t <VERSION>
Required. Target schema version (e.g., “3.0.0”).
Options
--force
Overwrite existing test file:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Only use --force if you’re sure you want to discard custom assertions you’ve added to the test.
--config <PATH>
Path to config file (experimental):
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --config .freezeray.yml
What Gets Created
// FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
import Testing
import FreezeRay
@testable import MyApp
/// Migration test from v2.0.0 → v3.0.0
///
/// This test verifies that the migration path between these versions works correctly.
///
/// Note: Tests run serially to avoid SwiftData store conflicts
@Suite(.serialized)
struct MigrateV2_0_0toV3_0_0_Tests {
@Test("Migrate v2.0.0 → v3.0.0")
func testMigrateV2_0_0toV3_0_0() throws {
// Test the migration using FreezeRayRuntime
try FreezeRayRuntime.testMigration(
from: AppSchemaV2.self,
to: AppSchemaV3.self,
migrationPlan: AppMigrations.self
)
// TODO: Add data integrity checks here
// Example:
// - Verify data is preserved during migration
// - Check that new fields have default values
// - Validate relationship updates
// - Ensure no data loss for critical fields
}
}
The generated test includes @Suite(.serialized) to fix parallel execution issues that cause SwiftData store conflicts.
Examples
Basic usage (early workflow)
# When starting V3 development
freezeray generate migration-tests --from-schema 2.0.0 --to-schema 3.0.0
# Edit generated test, add assertions
# Implement V3 schema + migration
# Iterate: run test → fix migration → run test
Output:
🔍 Generating migration test: v2.0.0 → v3.0.0...
✅ Generated migration test: MigrateV2_0_0toV3_0_0_Tests.swift
Edit this file to add custom migration assertions
freezeray g migration-tests -f 2.0.0 -t 3.0.0
Regenerate (overwrite custom assertions)
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Output:
✅ Generated migration test: MigrateV2_0_0toV3_0_0_Tests.swift
Common Errors
”No fixtures found for version X.Y.Z”
Cause: Source schema fixtures don’t exist.
Fix: Freeze the source version first:
freezeray freeze 2.0.0
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“No @FreezeSchema found for version X.Y.Z”
Cause: Target schema doesn’t exist in code yet.
Fix: Define the target schema:
@FreezeSchema(version: "3.0.0")
enum AppSchemaV3: VersionedSchema {
// ...
}
Then generate the test:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“No SchemaMigrationPlan found in codebase”
Cause: You haven’t defined a migration plan.
Fix: Create a migration plan:
enum AppMigrations: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[AppSchemaV1.self, AppSchemaV2.self, AppSchemaV3.self]
}
static var stages: [MigrationStage] {
[migrateV1toV2, migrateV2toV3]
}
static let migrateV2toV3 = MigrationStage.custom(
fromVersion: AppSchemaV2.self,
toVersion: AppSchemaV3.self,
willMigrate: nil,
didMigrate: { context in
// Migration logic
}
)
}
Then generate the test:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
“Migration test already exists”
Cause: You’ve already generated the migration test.
Solutions:
If you’ve added custom assertions:
# Do nothing - keep your custom test
If you want to start over:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0 --force
Complete Workflow Example
# 1. Ship V2
freezeray freeze 2.0.0
# 2. Start V3 development - generate migration test immediately
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# 3. Edit generated test, add custom assertions
vim FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
# 4. Implement V3 schema + migration
# (edit schema files, add migration stage)
# 5. Iterate: run tests normally as you develop
# ⌘U in Xcode or:
xcodebuild test -scheme MyApp
# 6. Ship V3
freezeray freeze 3.0.0 # Just generates fixtures + drift test
Key point: You develop with the migration test from the start, not after the fact.
Parallel Execution Fix
All generated tests now use @Suite(.serialized) to prevent parallel execution issues.
Problem (Before)
Migration tests failed when run in parallel (Swift Testing default):
swift test
# ❌ All 3 migration tests fail due to parallel execution
Running individually worked:
swift test --filter MigrateV2toV3
# ✅ Passes
Cause: Tests create/destroy SwiftData stores in temp directories with potential collisions.
Solution (After)
Generated tests now use @Suite(.serialized):
@Suite(.serialized) // ← Prevents parallel execution
struct MigrateV2_0_0toV3_0_0_Tests {
@Test func testMigrateV2_0_0toV3_0_0() throws {
// ...
}
}
Now tests work in default harness:
swift test
# ✅ All tests pass
Best Practices
1. Generate Migration Tests Early
Generate the migration test when you start working on the migration:
# ✅ Good: Generate early
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# Edit test, add assertions
# Implement migration
# Iterate until test passes
# ❌ Bad: Generate after implementing
# (implement migration)
# (write custom test)
freezeray freeze 3.0.0 # Conflict!
2. Never Overwrite User Tests
The generate commands never overwrite existing test files by default:
# First time: creates file
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# ✅ Generated migration test
# Second time: skips
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# ⚠️ Migration test already exists (preserving custom assertions)
This protects your custom assertions.
3. Use freeze for Complete Workflow
For most users, freeze is still the recommended command:
# This is still the easiest workflow
freezeray freeze 1.0.0 # Does everything
Only use generate when you need fine-grained control:
- Generate migration tests early ✅
- Regenerate specific artifacts ✅
- Customize the workflow ✅
4. Commit Generated Tests
Generated tests are yours to maintain:
freezeray generate migration-tests -f 2.0.0 -t 3.0.0
# Add custom assertions
vim FreezeRay/Tests/MigrateV2_0_0toV3_0_0_Tests.swift
# Commit with schema changes
git add FreezeRay/Tests/
git commit -m "Add migration test for V2→V3 with data integrity checks"
Test files evolve with your schema, just like any other test.
What freeze Does
The freeze command is simpler than generate - it only creates fixtures and drift tests:
Internally equivalent to:
# 1. Generate fixtures (via simulator)
freezeray generate fixtures --schema 3.0.0
# 2. Generate drift test (if doesn't exist)
freezeray generate schema-tests --schema 3.0.0
That’s it! freeze does NOT touch migration tests.
Migration tests are managed separately with generate migration-tests.
Requirements
Same as freezeray freeze:
- macOS 14+
- Xcode 15+
- iOS Simulator (iPhone 17 recommended)
- Project structure:
@FreezeSchema(version: "X.X.X") annotations
- Test target for running freeze tests
- Xcode project or Swift Package with iOS target
Next Steps