summaryrefslogtreecommitdiff
path: root/internal/app/loader_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-10-02 08:38:03 +0300
committerPaul Buetow <paul@buetow.org>2025-10-02 08:38:03 +0300
commit0c1b108ff5fccf39ae5bc6dc06802ce565bda633 (patch)
tree914e65e04bae26d3eae565f9d6a64d08ade361d0 /internal/app/loader_test.go
parent36be499ed342d92969ccaaff083c557a0951def9 (diff)
new version major refactorv0.2.0
Diffstat (limited to 'internal/app/loader_test.go')
-rw-r--r--internal/app/loader_test.go162
1 files changed, 162 insertions, 0 deletions
diff --git a/internal/app/loader_test.go b/internal/app/loader_test.go
new file mode 100644
index 0000000..538bca0
--- /dev/null
+++ b/internal/app/loader_test.go
@@ -0,0 +1,162 @@
+package app
+
+import (
+ "os"
+ "path/filepath"
+ "runtime"
+ "testing"
+ "time"
+)
+
+func TestCollectVideoPathsDetectsMP4(t *testing.T) {
+ dir := t.TempDir()
+ lower := filepath.Join(dir, "video.mp4")
+ upper := filepath.Join(dir, "UPPER.MP4")
+ for _, path := range []string{lower, upper} {
+ if err := os.WriteFile(path, []byte("dummy"), 0o644); err != nil {
+ t.Fatalf("write %s: %v", path, err)
+ }
+ }
+ paths, err := CollectVideoPathsForTest(dir)
+ if err != nil {
+ t.Fatalf("collect paths: %v", err)
+ }
+ if len(paths) != 2 {
+ t.Fatalf("expected 2 paths, got %d", len(paths))
+ }
+ want := map[string]struct{}{lower: {}, upper: {}}
+ for _, got := range paths {
+ if _, ok := want[got]; !ok {
+ t.Fatalf("unexpected path %s", got)
+ }
+ }
+}
+
+func TestCollectVideoPathsFollowsSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("symlink permissions vary on Windows")
+ }
+ root := t.TempDir()
+ storage := t.TempDir()
+ video := filepath.Join(storage, "movie.mp4")
+ if err := os.WriteFile(video, []byte("dummy"), 0o644); err != nil {
+ t.Fatalf("write video: %v", err)
+ }
+ link := filepath.Join(root, "videos")
+ if err := os.Symlink(storage, link); err != nil {
+ t.Skipf("symlink not supported: %v", err)
+ }
+ paths, err := CollectVideoPathsForTest(root)
+ if err != nil {
+ t.Fatalf("collect paths: %v", err)
+ }
+ expected := filepath.Join(link, "movie.mp4")
+ if len(paths) != 1 || paths[0] != expected {
+ t.Fatalf("expected %s, got %v", expected, paths)
+ }
+}
+
+func TestLoadVideosWithCache(t *testing.T) {
+ dir := t.TempDir()
+ video := filepath.Join(dir, "video.mp4")
+ if err := os.WriteFile(video, []byte("dummy"), 0o644); err != nil {
+ t.Fatalf("write: %v", err)
+ }
+ cache := newDurationCache(filepath.Join(dir, "cache.json"))
+ info, err := os.Stat(video)
+ if err != nil {
+ t.Fatalf("stat: %v", err)
+ }
+ _ = cache.Record(video, info, time.Minute)
+ progress := &loadProgress{}
+ progress.Reset()
+ videos, pending, err := loadVideos(dir, cache, progress)
+ if err != nil {
+ t.Fatalf("loadVideos: %v", err)
+ }
+ if len(videos) != 1 || len(pending) != 0 {
+ t.Fatalf("expected cached video without pending: videos=%d pending=%d", len(videos), len(pending))
+ }
+ if videos[0].Duration != time.Minute {
+ t.Fatalf("expected cached duration")
+ }
+}
+
+func TestProbeDurationsCmdHandlesMissingBinary(t *testing.T) {
+ cmd := probeDurationsCmd("/no/such/file.mp4", nil)
+ msg := cmd()
+ update := msg.(durationUpdateMsg)
+ if update.err == nil {
+ t.Fatalf("expected error from ffprobe")
+ }
+}
+
+func TestProbeDurationSuccess(t *testing.T) {
+ dir := t.TempDir()
+ script := filepath.Join(dir, "ffprobe")
+ if err := os.WriteFile(script, []byte("#!/bin/sh\necho 5\n"), 0o755); err != nil {
+ t.Fatalf("write script: %v", err)
+ }
+ oldPath := os.Getenv("PATH")
+ t.Setenv("PATH", dir+":"+oldPath)
+ dur, err := probeDuration("dummy.mp4")
+ if err != nil {
+ t.Fatalf("probeDuration: %v", err)
+ }
+ if dur != 5*time.Second {
+ t.Fatalf("expected 5s duration, got %v", dur)
+ }
+}
+
+func TestPlayVideoCmdMissingBinary(t *testing.T) {
+ cmd := playVideoCmd("/no/such/file.mp4", "")
+ msg := cmd()
+ result := msg.(playVideoMsg)
+ if result.path != "/no/such/file.mp4" {
+ t.Fatalf("unexpected path %s", result.path)
+ }
+}
+
+func TestRecordIfVideo(t *testing.T) {
+ var acc []string
+ if err := recordIfVideo("test.mp4", &acc); err != nil {
+ t.Fatalf("recordIfVideo: %v", err)
+ }
+ if len(acc) != 1 {
+ t.Fatalf("expected video recorded")
+ }
+}
+
+func TestHandleSymlinkBrokenVideo(t *testing.T) {
+ dir := t.TempDir()
+ symlink := filepath.Join(dir, "clip.mp4")
+ target := filepath.Join(dir, "missing.mp4")
+ if err := os.Symlink(target, symlink); err != nil {
+ t.Skipf("symlink unsupported: %v", err)
+ }
+ var acc []string
+ if err := handleSymlink(symlink, symlink, map[string]struct{}{}, &acc); err != nil {
+ t.Fatalf("handleSymlink: %v", err)
+ }
+ if len(acc) != 1 {
+ t.Fatalf("expected symlink video recorded")
+ }
+}
+
+func TestLoadVideosHandlesStatError(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("symlink permissions vary on Windows")
+ }
+ dir := t.TempDir()
+ broken := filepath.Join(dir, "broken.mp4")
+ if err := os.Symlink(filepath.Join(dir, "missing.mp4"), broken); err != nil {
+ t.Skipf("symlink unsupported: %v", err)
+ }
+ videos, _, err := loadVideos(dir, nil, nil)
+ if err != nil {
+ t.Fatalf("loadVideos: %v", err)
+ }
+ if len(videos) != 1 || videos[0].Err == nil {
+ t.Fatalf("expected stat error recorded, got %+v", videos)
+ }
+}