testmark-go

EXAMPLE.md

Testmark v2 Examples๐Ÿ”—

This document demonstrates the key improvements in testmark v2.

Before: v1 Pain Points๐Ÿ”—

// 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๐Ÿ”—

// 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๐Ÿ”—

// 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๐Ÿ”—

// v2: Original documents never change
original := testmark.MustReadFile("data.md")
modified := original.Patch(newHunk)
// 'original' is unchanged, 'modified' is new

โœ… Safe Iterators๐Ÿ”—

// 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๐Ÿ”—

// v2: Fluent API
doc := testmark.MustReadFile("data.md")
    .EnablePatching()
    .Patches()
    .Add(newHunk)

โœ… Contemporary Patterns๐Ÿ”—

// 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.

v2/EXAMPLE.md ยท 3.7 KiB ยท 07c6e4c9e7