GENERICS_EXAMPLE.md
Testmark v2 Generic Constructor Examples๐
Testmark v2 uses Go generics to provide a clean, type-safe constructor that accepts multiple input types.
Basic Generic Usage๐
package main
import (
"fmt"
"strings"
testmark "github.com/warpfork/go-testmark/v2"
)
func main() {
// ๐ All these work with the same NewHunk function!
// With string (most common)
hunk1 := testmark.NewHunk("config", "json", `{"host": "localhost"}`)
// With []byte (for binary data)
binaryData := []byte{0x89, 0x50, 0x4E, 0x47} // PNG header
hunk2 := testmark.NewHunk("image", "binary", binaryData)
// With io.Reader (for streams/files)
reader := strings.NewReader("data from stream")
hunk3 := testmark.NewHunkFromReader("stream", "text", reader)
fmt.Printf("Config: %s\n", hunk1.String())
fmt.Printf("Image size: %d bytes\n", len(hunk2.Body()))
fmt.Printf("Stream: %s\n", hunk3.String())
}
Type Safety Benefits๐
// โ
These all compile and work correctly
stringHunk := testmark.NewHunk("test", "text", "hello")
byteHunk := testmark.NewHunk("test", "binary", []byte{1, 2, 3})
// โ This won't compile (type safety!)
// intHunk := testmark.NewHunk("test", "text", 42) // compile error
Compared to v1๐
v1 required different functions:
// v1: Multiple functions, easy to forget which one to use
hunk1 := testmark.Hunk{Name: "test1", Body: []byte("string content")}
hunk2 := testmark.Hunk{Name: "test2", Body: bodyBytes}
// No built-in io.Reader support
v2 uses one generic function:
// v2: One function, type-safe, supports more input types
hunk1 := testmark.NewHunk("test1", "text", "string content")
hunk2 := testmark.NewHunk("test2", "binary", bodyBytes)
hunk3 := testmark.NewHunkFromReader("test3", "json", reader)
Real-World Example๐
func generateTestData() *testmark.Document {
doc := testmark.MustParseString(`# API Tests\n`)
// JSON from string
apiResponse := testmark.NewHunk("api/users", "json", `{
"users": [{"id": 1, "name": "Alice"}]
}`)
// Binary data from []byte
imageData := loadImageFile() // returns []byte
profilePic := testmark.NewHunk("images/profile", "png", imageData)
// Configuration from io.Reader (file, network, etc.)
configFile := openConfigFile() // returns io.Reader
config := testmark.NewHunkFromReader("config/main", "yaml", configFile)
return doc.Patch(apiResponse, profilePic, config)
}
Legacy Compatibility๐
The old constructors still work for backward compatibility:
// These still work (but NewHunk is preferred)
hunk1 := testmark.NewHunkString("test", "text", "content")
hunk2 := testmark.NewHunkBytes("test", "binary", []byte{1, 2, 3})
Error Handling๐
// NewHunk panics on invalid input (fail-fast design)
// This will panic:
// testmark.NewHunk("", "", "content") // empty name
// testmark.NewHunk("bad name", "", "content") // whitespace in name
// NewHunkFromReader panics if reader fails:
// Will panic if the reader returns an error
badReader := &failingReader{}
// testmark.NewHunkFromReader("test", "", badReader) // panics
Key Benefits๐
- ๐ฏ Type Safety: Compile-time checking prevents wrong types
- ๐งน Clean API: One function instead of multiple
- ๐ Multiple Inputs: string, []byte, and io.Reader support
- ๐ Backward Compatible: Old functions still work
- โก Performance: No runtime type checking overhead
- ๐ ๏ธ IDE Support: Better autocomplete and error detection
The generic constructor makes testmark v2 much more ergonomic while maintaining full type safety!
v2/GENERICS_EXAMPLE.md ยท 3.6 KiB ยท 93c0df2a6e