# 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 ```go 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 ```go // โœ… 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:** ```go // 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:** ```go // 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 ```go 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: ```go // These still work (but NewHunk is preferred) hunk1 := testmark.NewHunkString("test", "text", "content") hunk2 := testmark.NewHunkBytes("test", "binary", []byte{1, 2, 3}) ``` ## Error Handling ```go // 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 1. **๐ŸŽฏ Type Safety**: Compile-time checking prevents wrong types 2. **๐Ÿงน Clean API**: One function instead of multiple 3. **๐Ÿ“ Multiple Inputs**: string, []byte, and io.Reader support 4. **๐Ÿ”™ Backward Compatible**: Old functions still work 5. **โšก Performance**: No runtime type checking overhead 6. **๐Ÿ› ๏ธ IDE Support**: Better autocomplete and error detection The generic constructor makes testmark v2 much more ergonomic while maintaining full type safety!