# Testmark v2 Examples This document demonstrates the key improvements in testmark v2. ## Before: v1 Pain Points ```go // v1 required lots of boilerplate func oldWay() { doc, err := testmark.ReadFile("data.md") if err != nil { panic(err) } // Required manual step! doc.BuildDirIndex() // Manual patch accumulator setup patches := &testmark.PatchAccumulator{} // Direct field access (error-prone) for _, hunk := range doc.DataHunks { fmt.Println(hunk.Name) // Accessing fields directly if shouldUpdate { patches.AppendPatch(testmark.Hunk{ Name: hunk.Name, Body: []byte("new content"), }) } } // Complex patching newDoc := testmark.Patch(doc, patches.Patches...) // Manual directory navigation if doc.DirEnt != nil { child := doc.DirEnt.Children["config"] // null checks, manual iteration... } } ``` ## After: v2 Clean API ```go // v2 is much cleaner and safer func newWay() { // Auto-indexing, no BuildDirIndex needed! doc := testmark.MustReadFile("data.md") fmt.Printf("Loaded %d hunks\n", doc.Count()) // Safe iteration with clean accessors for iter := doc.Hunks(); iter.Next(); { hunk := iter.Hunk() fmt.Printf("%s: %s\n", hunk.Name(), hunk.String()) } // Clean patching newHunk := testmark.NewHunkString("config/db", "json", `{"host": "new-host"}`) updated := doc.Patch(newHunk) // Safe directory navigation config := doc.Root().Child("config") if config != nil { for iter := config.Children(); iter.Next(); { entry := iter.Entry() fmt.Printf("Config %s: %s\n", entry.Name(), entry.Hunk().String()) } } // Easy serialization fmt.Println(updated.String()) } ``` ## Key Improvements Summary ### ✅ **Eliminated Boilerplate** - No more `doc.BuildDirIndex()` - happens automatically - No more `&testmark.PatchAccumulator{}` setup - No more manual null checks and field access ### ✅ **Private Fields = Safer Code** ```go // v1: Error-prone direct access doc.DataHunks[0].Name = "oops" // Could break things! // v2: Clean accessors only hunk := doc.HunkByName("name") name := hunk.Name() // Read-only, safe ``` ### ✅ **Immutable Operations** ```go // v2: Original documents never change original := testmark.MustReadFile("data.md") modified := original.Patch(newHunk) // 'original' is unchanged, 'modified' is new ``` ### ✅ **Safe Iterators** ```go // v2: No direct slice access for iter := doc.Hunks(); iter.Next(); { hunk := iter.Hunk() // Safe, controlled access // No risk of modifying internal state } ``` ### ✅ **Method Chaining** ```go // v2: Fluent API doc := testmark.MustReadFile("data.md") .EnablePatching() .Patches() .Add(newHunk) ``` ### ✅ **Contemporary Patterns** ```go // v2: Modern flag handling var regenFlag = flag.Bool("testmark.regen", false, "regen fixtures") if testmark.ShouldRegen() { // Handle regeneration } ``` ## Migration Guide | v1 Pattern | v2 Replacement | |------------|----------------| | `doc.BuildDirIndex()` | *automatic* | | `doc.DataHunks` | `doc.Hunks()` iterator | | `doc.HunksByName[name]` | `doc.HunkByName(name)` | | `doc.DirEnt.Children[name]` | `doc.Root().Child(name)` | | `&testmark.PatchAccumulator{}` | `doc.EnablePatching().Patches()` | | Multiple package imports | Single `v2` import | | Direct field access | Private fields + accessors | | Mutable operations | Immutable (returns new docs) | The v2 API is designed to make the "right thing" easy and the "wrong thing" impossible through good API design.