package dcf_test import ( "crypto/sha256" "encoding/hex" "os" "path/filepath" "strings" "testing" "git.eeqj.de/sneak/dcf/pkg/dcf" ) // newStore builds a store with two images and one video of known sizes, // so the count and size accessors have something deterministic to // report. func newStore(root string) *dcf.Store { return &dcf.Store{ RootDirectory: root, Images: []*dcf.Image{ {Object: dcf.Object{ StoreRoot: root, Path: "DCIM/100MSDCF/DSC00001.ARW", Size: 2000, Extension: ".ARW", }}, {Object: dcf.Object{ StoreRoot: root, Path: "DCIM/100MSDCF/DSC00002.JPG", Size: 500, Extension: ".JPG", }}, }, Videos: []*dcf.Video{ {Object: dcf.Object{ StoreRoot: root, Path: "PRIVATE/M4ROOT/CLIP/C0001.MP4", Size: 9000, Extension: ".MP4", }}, }, } } func TestObjectFullFilePath(t *testing.T) { t.Parallel() object := dcf.Object{ StoreRoot: filepath.Join("/mnt", "card"), Path: filepath.Join("DCIM", "100MSDCF", "DSC00001.ARW"), } want := filepath.Join("/mnt", "card", "DCIM", "100MSDCF", "DSC00001.ARW") if got := object.FullFilePath(); got != want { t.Fatalf("FullFilePath() = %q, want %q", got, want) } } func TestStoreCounts(t *testing.T) { t.Parallel() store := newStore("/mnt/card") if got := store.ImagesCount(); got != 2 { t.Errorf("ImagesCount() = %d, want 2", got) } if got := store.VideosCount(); got != 1 { t.Errorf("VideosCount() = %d, want 1", got) } } func TestStoreSizes(t *testing.T) { t.Parallel() store := newStore("/mnt/card") if got := store.TotalImageSize(); got != 2500 { t.Errorf("TotalImageSize() = %d, want 2500", got) } if got := store.TotalVideoSize(); got != 9000 { t.Errorf("TotalVideoSize() = %d, want 9000", got) } if got := store.TotalSize(); got != 11500 { t.Errorf("TotalSize() = %d, want 11500", got) } } func TestEmptyStoreSizesAreZero(t *testing.T) { t.Parallel() store := dcf.Store{RootDirectory: "/mnt/empty"} if got := store.TotalSize(); got != 0 { t.Fatalf("TotalSize() = %d, want 0", got) } } func TestStoreStringReportsHumanizedTotal(t *testing.T) { t.Parallel() got := newStore("/mnt/card").String() for _, want := range []string{"/mnt/card", "Images: 2", "Videos: 1", "12 kB"} { if !strings.Contains(got, want) { t.Errorf("String() = %q, want it to contain %q", got, want) } } } func TestImageAndVideoString(t *testing.T) { t.Parallel() image := dcf.Image{Object: dcf.Object{ Path: "DCIM/100MSDCF/DSC00001.ARW", Size: 2000, Extension: ".ARW", }} want := "Image{Path: DCIM/100MSDCF/DSC00001.ARW, Size: 2000, " + "Extension: .ARW}" if got := image.String(); got != want { t.Errorf("Image.String() = %q, want %q", got, want) } video := dcf.Video{Object: dcf.Object{ Path: "PRIVATE/M4ROOT/CLIP/C0001.MP4", Size: 9000, Extension: ".MP4", }} want = "Video{Path: PRIVATE/M4ROOT/CLIP/C0001.MP4, Size: 9000, " + "Extension: .MP4}" if got := video.String(); got != want { t.Errorf("Video.String() = %q, want %q", got, want) } } func TestObjectHashMatchesSHA256OfFile(t *testing.T) { t.Parallel() root := t.TempDir() contents := []byte("DSC00001.ARW contents") err := os.MkdirAll(filepath.Join(root, "DCIM"), 0o750) if err != nil { t.Fatalf("MkdirAll: %v", err) } err = os.WriteFile(filepath.Join(root, "DCIM", "a.arw"), contents, 0o600) if err != nil { t.Fatalf("WriteFile: %v", err) } object := dcf.Object{StoreRoot: root, Path: filepath.Join("DCIM", "a.arw")} got, err := object.Hash() if err != nil { t.Fatalf("Hash() returned error: %v", err) } sum := sha256.Sum256(contents) if want := hex.EncodeToString(sum[:]); got != want { t.Fatalf("Hash() = %q, want %q", got, want) } } func TestObjectHashOnMissingFileReturnsError(t *testing.T) { t.Parallel() object := dcf.Object{StoreRoot: t.TempDir(), Path: "absent.jpg"} _, err := object.Hash() if err == nil { t.Fatal("Hash() on a missing file returned no error") } }