diff options
Diffstat (limited to 'pngmeta/metareader_test.go')
-rw-r--r-- | pngmeta/metareader_test.go | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/pngmeta/metareader_test.go b/pngmeta/metareader_test.go index 5d9a0e2..c075865 100644 --- a/pngmeta/metareader_test.go +++ b/pngmeta/metareader_test.go @@ -1,7 +1,19 @@ package pngmeta import ( + "bytes" + "elefant/models" + "encoding/base64" + "encoding/binary" + "encoding/json" + "errors" "fmt" + "image" + "image/color" + "image/png" + "io" + "os" + "path/filepath" "testing" ) @@ -28,3 +40,155 @@ func TestReadMeta(t *testing.T) { }) } } + +// Test helper: Create a simple PNG image with test shapes +func createTestImage(t *testing.T) string { + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) + // Fill background with white + for y := 0; y < 200; y++ { + for x := 0; x < 200; x++ { + img.Set(x, y, color.White) + } + } + // Draw a red square + for y := 50; y < 150; y++ { + for x := 50; x < 150; x++ { + img.Set(x, y, color.RGBA{R: 255, A: 255}) + } + } + // Draw a blue circle + center := image.Point{100, 100} + radius := 40 + for y := center.Y - radius; y <= center.Y+radius; y++ { + for x := center.X - radius; x <= center.X+radius; x++ { + dx := x - center.X + dy := y - center.Y + if dx*dx+dy*dy <= radius*radius { + img.Set(x, y, color.RGBA{B: 255, A: 255}) + } + } + } + // Create temp file + tmpDir := t.TempDir() + fpath := filepath.Join(tmpDir, "test-image.png") + f, err := os.Create(fpath) + if err != nil { + t.Fatalf("Error creating temp file: %v", err) + } + defer f.Close() + if err := png.Encode(f, img); err != nil { + t.Fatalf("Error encoding PNG: %v", err) + } + return fpath +} + +func TestWriteToPng(t *testing.T) { + // Create test image + srcPath := createTestImage(t) + dstPath := filepath.Join(filepath.Dir(srcPath), "output.png") + // dstPath := "test.png" + // Create test metadata + metadata := &models.CharCardSpec{ + Description: "Test image containing a red square and blue circle on white background", + } + // Embed metadata + if err := WriteToPng(metadata, srcPath, dstPath); err != nil { + t.Fatalf("WriteToPng failed: %v", err) + } + // Verify output file exists + if _, err := os.Stat(dstPath); os.IsNotExist(err) { + t.Fatalf("Output file not created: %v", err) + } + // Read and verify metadata + t.Run("VerifyMetadata", func(t *testing.T) { + data, err := os.ReadFile(dstPath) + if err != nil { + t.Fatalf("Error reading output file: %v", err) + } + // Verify PNG header + if string(data[:8]) != pngHeader { + t.Errorf("Invalid PNG header") + } + // Extract metadata + embedded := extractMetadata(t, data) + if embedded.Description != metadata.Description { + t.Errorf("Metadata mismatch\nWant: %q\nGot: %q", + metadata.Description, embedded.Description) + } + }) + // Optional: Add cleanup if needed + // t.Cleanup(func() { + // os.Remove(dstPath) + // }) +} + +// Helper to extract embedded metadata from PNG bytes +func extractMetadata(t *testing.T, data []byte) *models.CharCardSpec { + r := bytes.NewReader(data[8:]) // Skip PNG header + for { + var length uint32 + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + if errors.Is(err, io.EOF) { + break + } + t.Fatalf("Error reading chunk length: %v", err) + } + chunkType := make([]byte, 4) + if _, err := r.Read(chunkType); err != nil { + t.Fatalf("Error reading chunk type: %v", err) + } + // Read chunk data + chunkData := make([]byte, length) + if _, err := r.Read(chunkData); err != nil { + t.Fatalf("Error reading chunk data: %v", err) + } + // Read and discard CRC + if _, err := r.Read(make([]byte, 4)); err != nil { + t.Fatalf("Error reading CRC: %v", err) + } + if string(chunkType) == embType { + parts := bytes.SplitN(chunkData, []byte{0}, 2) + if len(parts) != 2 { + t.Fatalf("Invalid tEXt chunk format") + } + decoded, err := base64.StdEncoding.DecodeString(string(parts[1])) + if err != nil { + t.Fatalf("Base64 decode error: %v", err) + } + var result models.CharCardSpec + if err := json.Unmarshal(decoded, &result); err != nil { + t.Fatalf("JSON unmarshal error: %v", err) + } + return &result + } + } + t.Fatal("Metadata not found in PNG") + return nil +} + +func readTextChunk(t *testing.T, r io.ReadSeeker) *models.CharCardSpec { + var length uint32 + binary.Read(r, binary.BigEndian, &length) + chunkType := make([]byte, 4) + r.Read(chunkType) + data := make([]byte, length) + r.Read(data) + // Read CRC (but skip validation for test purposes) + crc := make([]byte, 4) + r.Read(crc) + parts := bytes.SplitN(data, []byte{0}, 2) // Split key-value pair + if len(parts) != 2 { + t.Fatalf("Invalid tEXt chunk format") + } + // key := string(parts[0]) + value := parts[1] + decoded, err := base64.StdEncoding.DecodeString(string(value)) + if err != nil { + t.Fatalf("Base64 decode error: %v; value: %s", err, string(value)) + } + var result models.CharCardSpec + if err := json.Unmarshal(decoded, &result); err != nil { + t.Fatalf("JSON unmarshal error: %v", err) + } + return &result +} |