@@ -13,6 +13,66 @@ import (
1313 require "github.com/stretchr/testify/require"
1414)
1515
16+ func TestExpandShorthand (t * testing.T ) {
17+ tests := []struct {
18+ name string
19+ input string
20+ want string
21+ }{
22+ {
23+ name : "single segment uses default org and skills repo" ,
24+ input : "skill-creator" ,
25+ want : "https://github.com/inference-gateway/skills/tree/main/skills/skill-creator" ,
26+ },
27+ {
28+ name : "two segments use given org and skills repo" ,
29+ input : "acme/foo" ,
30+ want : "https://github.com/acme/skills/tree/main/skills/foo" ,
31+ },
32+ {
33+ name : "https URL is returned unchanged" ,
34+ input : "https://github.com/anthropics/skills/tree/main/skills/pdf" ,
35+ want : "https://github.com/anthropics/skills/tree/main/skills/pdf" ,
36+ },
37+ {
38+ name : "http URL is returned unchanged" ,
39+ input : "http://example.com/x" ,
40+ want : "http://example.com/x" ,
41+ },
42+ {
43+ name : "empty input is returned unchanged" ,
44+ input : "" ,
45+ want : "" ,
46+ },
47+ {
48+ name : "three segments fall through unchanged" ,
49+ input : "a/b/c" ,
50+ want : "a/b/c" ,
51+ },
52+ {
53+ name : "leading and trailing slashes are trimmed" ,
54+ input : "/skill/" ,
55+ want : "https://github.com/inference-gateway/skills/tree/main/skills/skill" ,
56+ },
57+ {
58+ name : "empty middle segment falls through unchanged" ,
59+ input : "a//b" ,
60+ want : "a//b" ,
61+ },
62+ {
63+ name : "single slash falls through unchanged" ,
64+ input : "/" ,
65+ want : "/" ,
66+ },
67+ }
68+
69+ for _ , tt := range tests {
70+ t .Run (tt .name , func (t * testing.T ) {
71+ require .Equal (t , tt .want , ExpandShorthand (tt .input ))
72+ })
73+ }
74+ }
75+
1676func TestParseGitHubTreeURL (t * testing.T ) {
1777 tests := []struct {
1878 name string
@@ -168,6 +228,30 @@ func TestInstallFromGitHub_HappyPath(t *testing.T) {
168228 require .True (t , os .IsNotExist (err ))
169229}
170230
231+ func TestInstallFromGitHub_ShorthandResolves (t * testing.T ) {
232+ // Shorthand "acme/skill-creator" should resolve to the "skills" repo
233+ // under the acme org with path "skills/skill-creator". The mock server
234+ // doesn't care about owner/repo/ref segments — it just looks at the
235+ // repo path prefix — so we need a SKILL.md at
236+ // skills/skill-creator/SKILL.md to match the resolved tree path.
237+ repo := fakeRepo {
238+ Files : map [string ]string {
239+ "skills/skill-creator/SKILL.md" : validSkillBody ("skill-creator" , "Test skill." ),
240+ },
241+ }
242+ srv := newMockServer (t , repo )
243+ defer srv .Close ()
244+
245+ dest := t .TempDir ()
246+ got , err := newTestInstaller (srv .URL ).InstallFromGitHub (context .Background (),
247+ "acme/skill-creator" , dest , false )
248+ require .NoError (t , err )
249+
250+ abs , _ := filepath .Abs (filepath .Join (dest , "skill-creator" ))
251+ require .Equal (t , abs , got )
252+ require .FileExists (t , filepath .Join (dest , "skill-creator" , "SKILL.md" ))
253+ }
254+
171255func TestInstallFromGitHub_RepoNotFound (t * testing.T ) {
172256 mux := http .NewServeMux ()
173257 mux .HandleFunc ("/repos/" , func (w http.ResponseWriter , r * http.Request ) {
0 commit comments