summaryrefslogtreecommitdiff
path: root/cmd
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 /cmd
parent36be499ed342d92969ccaaff083c557a0951def9 (diff)
new version major refactorv0.2.0
Diffstat (limited to 'cmd')
-rw-r--r--cmd/yoga/main.go50
-rw-r--r--cmd/yoga/main_test.go85
2 files changed, 135 insertions, 0 deletions
diff --git a/cmd/yoga/main.go b/cmd/yoga/main.go
new file mode 100644
index 0000000..fbf11bd
--- /dev/null
+++ b/cmd/yoga/main.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "yoga/internal/app"
+ "yoga/internal/fsutil"
+ "yoga/internal/meta"
+)
+
+const defaultRoot = "~/Yoga"
+
+var (
+ runApp = app.Run
+ exit = os.Exit
+)
+
+func main() {
+ exit(run(os.Args[1:], os.Stdout, os.Stderr))
+}
+
+func run(args []string, stdout, stderr io.Writer) int {
+ fs := flag.NewFlagSet("yoga", flag.ContinueOnError)
+ fs.SetOutput(stderr)
+ rootFlag := fs.String("root", "", "Directory containing yoga videos (default ~/Yoga)")
+ cropFlag := fs.String("crop", "", "Optional crop aspect for VLC (e.g. 5:4)")
+ versionFlag := fs.Bool("version", false, "Print version and exit")
+ if err := fs.Parse(args); err != nil {
+ return 2
+ }
+ if *versionFlag {
+ fmt.Fprintf(stdout, "Yoga version %s\n", meta.Version)
+ return 0
+ }
+ root, err := fsutil.ResolveRootPath(*rootFlag, defaultRoot)
+ if err != nil {
+ fmt.Fprintf(stderr, "%v\n", err)
+ return 1
+ }
+ opts := app.Options{Root: root, Crop: strings.TrimSpace(*cropFlag)}
+ if err := runApp(opts); err != nil {
+ fmt.Fprintf(stderr, "error: %v\n", err)
+ return 1
+ }
+ return 0
+}
diff --git a/cmd/yoga/main_test.go b/cmd/yoga/main_test.go
new file mode 100644
index 0000000..d06ff33
--- /dev/null
+++ b/cmd/yoga/main_test.go
@@ -0,0 +1,85 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "yoga/internal/app"
+)
+
+func TestRunPrintsVersion(t *testing.T) {
+ var stdout, stderr bytes.Buffer
+ code := run([]string{"--version"}, &stdout, &stderr)
+ if code != 0 {
+ t.Fatalf("expected exit code 0, got %d", code)
+ }
+ if !bytes.Contains(stdout.Bytes(), []byte("Yoga version")) {
+ t.Fatalf("expected version output, got %s", stdout.String())
+ }
+}
+
+func TestRunSuccess(t *testing.T) {
+ var stdout, stderr bytes.Buffer
+ root := t.TempDir()
+ orig := runApp
+ runApp = func(opts app.Options) error { return nil }
+ defer func() { runApp = orig }()
+ code := run([]string{"--root", root}, &stdout, &stderr)
+ if code != 0 {
+ t.Fatalf("expected exit code 0, got %d", code)
+ }
+}
+
+func TestRunAppError(t *testing.T) {
+ var stdout, stderr bytes.Buffer
+ root := t.TempDir()
+ orig := runApp
+ runApp = func(app.Options) error { return errors.New("boom") }
+ defer func() { runApp = orig }()
+ code := run([]string{"--root", root}, &stdout, &stderr)
+ if code != 1 {
+ t.Fatalf("expected exit code 1, got %d", code)
+ }
+ if !bytes.Contains(stderr.Bytes(), []byte("error:")) {
+ t.Fatalf("expected error output, got %s", stderr.String())
+ }
+}
+
+func TestRunDefaultRootCreated(t *testing.T) {
+ var stdout, stderr bytes.Buffer
+ home := t.TempDir()
+ t.Setenv("HOME", home)
+ orig := runApp
+ runApp = func(opts app.Options) error {
+ if _, err := os.Stat(filepath.Join(home, "Yoga")); err != nil {
+ t.Fatalf("expected default directory: %v", err)
+ }
+ return nil
+ }
+ defer func() { runApp = orig }()
+ code := run(nil, &stdout, &stderr)
+ if code != 0 {
+ t.Fatalf("expected exit code 0, got %d", code)
+ }
+}
+
+func TestMainUsesExit(t *testing.T) {
+ root := t.TempDir()
+ origRun := runApp
+ origExit := exit
+ runApp = func(opts app.Options) error { return nil }
+ var code int
+ exit = func(c int) { code = c }
+ defer func() {
+ runApp = origRun
+ exit = origExit
+ }()
+ os.Args = []string{"yoga", "--root", root}
+ main()
+ if code != 0 {
+ t.Fatalf("expected exit code 0, got %d", code)
+ }
+}