Commit ae5cd9f

Eric Bower  ·  2026-08-01 09:40:30 -0400 EDT
parent 2ce4484
fix: scp <file> pgs.sh:/<project> works
2 files changed,  +92, -0
+5, -0
 1@@ -29,6 +29,11 @@ func GetProjectName(entry *utils.FileEntry) string {
 2 	} else if len(list) == 1 {
 3 		return list[0]
 4 	}
 5+	// When filepath is like "/bin" (root-level file), dir is "/" and
 6+	// split produces ["", ""]. Use the filename as the project name.
 7+	if list[1] == "" {
 8+		return filepath.Base(entry.Filepath)
 9+	}
10 	return list[1]
11 }
12 
+87, -0
 1@@ -0,0 +1,87 @@
 2+package shared
 3+
 4+import (
 5+	"io/fs"
 6+	"testing"
 7+
 8+	"github.com/picosh/pico/pkg/send/utils"
 9+)
10+
11+func TestGetProjectName(t *testing.T) {
12+	tests := []struct {
13+		name     string
14+		filepath string
15+		isDir    bool
16+		want     string
17+	}{
18+		// Standard cases: /project/file -> project
19+		{
20+			name:     "standard project with file",
21+			filepath: "/myproject/index.html",
22+			isDir:    false,
23+			want:     "myproject",
24+		},
25+		{
26+			name:     "nested path",
27+			filepath: "/myproject/subdir/file.txt",
28+			isDir:    false,
29+			want:     "myproject",
30+		},
31+		// Root-level file (the bug case): /bin -> bin
32+		{
33+			name:     "root-level file (scp file pgs.sh:/bin)",
34+			filepath: "/bin",
35+			isDir:    false,
36+			want:     "bin",
37+		},
38+		{
39+			name:     "root-level file with different name",
40+			filepath: "/myproject",
41+			isDir:    false,
42+			want:     "myproject",
43+		},
44+		// Directory cases
45+		{
46+			name:     "directory with no slash",
47+			filepath: "myproject",
48+			isDir:    true,
49+			want:     "myproject",
50+		},
51+		{
52+			name:     "directory at root level",
53+			filepath: "/myproject",
54+			isDir:    true,
55+			want:     "myproject",
56+		},
57+		// Edge cases (caught by uploader validation, not valid inputs)
58+		{
59+			name:     "empty path",
60+			filepath: "",
61+			isDir:    false,
62+			want:     ".",
63+		},
64+		{
65+			name:     "root path",
66+			filepath: "/",
67+			isDir:    false,
68+			want:     "/",
69+		},
70+	}
71+
72+	for _, tt := range tests {
73+		t.Run(tt.name, func(t *testing.T) {
74+			entry := &utils.FileEntry{
75+				Filepath: tt.filepath,
76+				Mode:     fs.FileMode(0644),
77+			}
78+			if tt.isDir {
79+				entry.Mode = fs.ModeDir
80+			}
81+
82+			got := GetProjectName(entry)
83+			if got != tt.want {
84+				t.Errorf("GetProjectName(%q, isDir=%v) = %q, want %q", tt.filepath, tt.isDir, got, tt.want)
85+			}
86+		})
87+	}
88+}