|
@@ -111,11 +111,11 @@ func TestNameConsecutiveDots(t *testing.T) {
|
|
for i := 1; i < 10; i++ {
|
|
for i := 1; i < 10; i++ {
|
|
s := strings.Repeat(".", i)
|
|
s := strings.Repeat(".", i)
|
|
if i > 1 {
|
|
if i > 1 {
|
|
- if g := ParseNameFill(s, "").String(); g != "" {
|
|
|
|
|
|
+ if g := ParseName(s, FillNothing).String(); g != "" {
|
|
t.Errorf("ParseName(%q) = %q; want empty string", s, g)
|
|
t.Errorf("ParseName(%q) = %q; want empty string", s, g)
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- if g := ParseNameFill(s, "").String(); g != s {
|
|
|
|
|
|
+ if g := ParseName(s, FillNothing).String(); g != s {
|
|
t.Errorf("ParseName(%q) = %q; want %q", s, g, s)
|
|
t.Errorf("ParseName(%q) = %q; want %q", s, g, s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -148,14 +148,14 @@ func TestParseName(t *testing.T) {
|
|
s := prefix + baseName
|
|
s := prefix + baseName
|
|
|
|
|
|
t.Run(s, func(t *testing.T) {
|
|
t.Run(s, func(t *testing.T) {
|
|
- name := ParseNameFill(s, "")
|
|
|
|
|
|
+ name := ParseName(s, FillNothing)
|
|
got := fieldsFromName(name)
|
|
got := fieldsFromName(name)
|
|
if got != want {
|
|
if got != want {
|
|
t.Errorf("ParseName(%q) = %q; want %q", s, got, want)
|
|
t.Errorf("ParseName(%q) = %q; want %q", s, got, want)
|
|
}
|
|
}
|
|
|
|
|
|
// test round-trip
|
|
// test round-trip
|
|
- if !ParseNameFill(name.String(), "").EqualFold(name) {
|
|
|
|
|
|
+ if !ParseName(name.String(), FillNothing).EqualFold(name) {
|
|
t.Errorf("ParseName(%q).String() = %s; want %s", s, name.String(), baseName)
|
|
t.Errorf("ParseName(%q).String() = %s; want %s", s, name.String(), baseName)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
@@ -163,6 +163,47 @@ func TestParseName(t *testing.T) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func TestParseNameFill(t *testing.T) {
|
|
|
|
+ cases := []struct {
|
|
|
|
+ in string
|
|
|
|
+ fill string
|
|
|
|
+ want string
|
|
|
|
+ }{
|
|
|
|
+ {"mistral", "example.com/library/?:latest+Q4_0", "example.com/library/mistral:latest+Q4_0"},
|
|
|
|
+ {"mistral", "example.com/library/?:latest", "example.com/library/mistral:latest"},
|
|
|
|
+ {"llama2:x", "example.com/library/?:latest+Q4_0", "example.com/library/llama2:x+Q4_0"},
|
|
|
|
+
|
|
|
|
+ // Invalid
|
|
|
|
+ {"", "example.com/library/?:latest+Q4_0", ""},
|
|
|
|
+ {"llama2:?", "example.com/library/?:latest+Q4_0", ""},
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for _, tt := range cases {
|
|
|
|
+ t.Run(tt.in, func(t *testing.T) {
|
|
|
|
+ name := ParseName(tt.in, tt.fill)
|
|
|
|
+ if g := name.String(); g != tt.want {
|
|
|
|
+ t.Errorf("ParseName(%q, %q) = %q; want %q", tt.in, tt.fill, g, tt.want)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func TestParseNameHTTPDoublePrefixStrip(t *testing.T) {
|
|
|
|
+ cases := []string{
|
|
|
|
+ "http://https://valid.com/valid/valid:latest",
|
|
|
|
+ "https://http://valid.com/valid/valid:latest",
|
|
|
|
+ }
|
|
|
|
+ for _, s := range cases {
|
|
|
|
+ t.Run(s, func(t *testing.T) {
|
|
|
|
+ name := ParseName(s, FillNothing)
|
|
|
|
+ if name.IsValid() {
|
|
|
|
+ t.Errorf("expected invalid path; got %#v", name)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
func TestCompleteWithAndWithoutBuild(t *testing.T) {
|
|
func TestCompleteWithAndWithoutBuild(t *testing.T) {
|
|
cases := []struct {
|
|
cases := []struct {
|
|
in string
|
|
in string
|
|
@@ -179,7 +220,7 @@ func TestCompleteWithAndWithoutBuild(t *testing.T) {
|
|
|
|
|
|
for _, tt := range cases {
|
|
for _, tt := range cases {
|
|
t.Run(tt.in, func(t *testing.T) {
|
|
t.Run(tt.in, func(t *testing.T) {
|
|
- p := ParseNameFill(tt.in, "")
|
|
|
|
|
|
+ p := ParseName(tt.in, FillNothing)
|
|
t.Logf("ParseName(%q) = %#v", tt.in, p)
|
|
t.Logf("ParseName(%q) = %#v", tt.in, p)
|
|
if g := p.IsComplete(); g != tt.complete {
|
|
if g := p.IsComplete(); g != tt.complete {
|
|
t.Errorf("Complete(%q) = %v; want %v", tt.in, g, tt.complete)
|
|
t.Errorf("Complete(%q) = %v; want %v", tt.in, g, tt.complete)
|
|
@@ -194,7 +235,7 @@ func TestCompleteWithAndWithoutBuild(t *testing.T) {
|
|
// inlined when used in Complete, preventing any allocations or
|
|
// inlined when used in Complete, preventing any allocations or
|
|
// escaping to the heap.
|
|
// escaping to the heap.
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
- keep(ParseNameFill("complete.com/x/mistral:latest+Q4_0", "").IsComplete())
|
|
|
|
|
|
+ keep(ParseName("complete.com/x/mistral:latest+Q4_0", FillNothing).IsComplete())
|
|
})
|
|
})
|
|
if allocs > 0 {
|
|
if allocs > 0 {
|
|
t.Errorf("Complete allocs = %v; want 0", allocs)
|
|
t.Errorf("Complete allocs = %v; want 0", allocs)
|
|
@@ -211,7 +252,7 @@ func TestNameLogValue(t *testing.T) {
|
|
t.Run(s, func(t *testing.T) {
|
|
t.Run(s, func(t *testing.T) {
|
|
var b bytes.Buffer
|
|
var b bytes.Buffer
|
|
log := slog.New(slog.NewTextHandler(&b, nil))
|
|
log := slog.New(slog.NewTextHandler(&b, nil))
|
|
- name := ParseNameFill(s, "")
|
|
|
|
|
|
+ name := ParseName(s, FillNothing)
|
|
log.Info("", "name", name)
|
|
log.Info("", "name", name)
|
|
want := fmt.Sprintf("name=%s", name.GoString())
|
|
want := fmt.Sprintf("name=%s", name.GoString())
|
|
got := b.String()
|
|
got := b.String()
|
|
@@ -258,7 +299,7 @@ func TestNameGoString(t *testing.T) {
|
|
|
|
|
|
for _, tt := range cases {
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
- p := ParseNameFill(tt.in, "")
|
|
|
|
|
|
+ p := ParseName(tt.in, FillNothing)
|
|
tt.wantGoString = cmp.Or(tt.wantGoString, tt.in)
|
|
tt.wantGoString = cmp.Or(tt.wantGoString, tt.in)
|
|
if g := fmt.Sprintf("%#v", p); g != tt.wantGoString {
|
|
if g := fmt.Sprintf("%#v", p); g != tt.wantGoString {
|
|
t.Errorf("GoString() = %q; want %q", g, tt.wantGoString)
|
|
t.Errorf("GoString() = %q; want %q", g, tt.wantGoString)
|
|
@@ -286,11 +327,14 @@ func TestDisplayShortest(t *testing.T) {
|
|
{"example.com/library/mistral:Latest+Q4_0", "example.com/library/_:latest", "mistral", false},
|
|
{"example.com/library/mistral:Latest+Q4_0", "example.com/library/_:latest", "mistral", false},
|
|
{"example.com/library/mistral:Latest+q4_0", "example.com/library/_:latest", "mistral", false},
|
|
{"example.com/library/mistral:Latest+q4_0", "example.com/library/_:latest", "mistral", false},
|
|
|
|
|
|
|
|
+ // zero value
|
|
|
|
+ {"", MaskDefault, "", true},
|
|
|
|
+
|
|
// invalid mask
|
|
// invalid mask
|
|
{"example.com/library/mistral:latest+Q4_0", "example.com/mistral", "", true},
|
|
{"example.com/library/mistral:latest+Q4_0", "example.com/mistral", "", true},
|
|
|
|
|
|
// DefaultMask
|
|
// DefaultMask
|
|
- {"registry.ollama.ai/library/mistral:latest+Q4_0", DefaultMask, "mistral", false},
|
|
|
|
|
|
+ {"registry.ollama.ai/library/mistral:latest+Q4_0", MaskDefault, "mistral", false},
|
|
|
|
|
|
// Auto-Fill
|
|
// Auto-Fill
|
|
{"x", "example.com/library/_:latest", "x", false},
|
|
{"x", "example.com/library/_:latest", "x", false},
|
|
@@ -309,7 +353,7 @@ func TestDisplayShortest(t *testing.T) {
|
|
}
|
|
}
|
|
}()
|
|
}()
|
|
|
|
|
|
- p := ParseNameFill(tt.in, "")
|
|
|
|
|
|
+ p := ParseName(tt.in, FillNothing)
|
|
t.Logf("ParseName(%q) = %#v", tt.in, p)
|
|
t.Logf("ParseName(%q) = %#v", tt.in, p)
|
|
if g := p.DisplayShortest(tt.mask); g != tt.want {
|
|
if g := p.DisplayShortest(tt.mask); g != tt.want {
|
|
t.Errorf("got = %q; want %q", g, tt.want)
|
|
t.Errorf("got = %q; want %q", g, tt.want)
|
|
@@ -320,7 +364,7 @@ func TestDisplayShortest(t *testing.T) {
|
|
|
|
|
|
func TestParseNameAllocs(t *testing.T) {
|
|
func TestParseNameAllocs(t *testing.T) {
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
- keep(ParseNameFill("example.com/mistral:7b+Q4_0", ""))
|
|
|
|
|
|
+ keep(ParseName("example.com/mistral:7b+Q4_0", FillNothing))
|
|
})
|
|
})
|
|
if allocs > 0 {
|
|
if allocs > 0 {
|
|
t.Errorf("ParseName allocs = %v; want 0", allocs)
|
|
t.Errorf("ParseName allocs = %v; want 0", allocs)
|
|
@@ -331,7 +375,7 @@ func BenchmarkParseName(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ReportAllocs()
|
|
|
|
|
|
for range b.N {
|
|
for range b.N {
|
|
- keep(ParseNameFill("example.com/mistral:7b+Q4_0", ""))
|
|
|
|
|
|
+ keep(ParseName("example.com/mistral:7b+Q4_0", FillNothing))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -346,7 +390,7 @@ func FuzzParseName(f *testing.F) {
|
|
f.Add(":@!@")
|
|
f.Add(":@!@")
|
|
f.Add("...")
|
|
f.Add("...")
|
|
f.Fuzz(func(t *testing.T, s string) {
|
|
f.Fuzz(func(t *testing.T, s string) {
|
|
- r0 := ParseNameFill(s, "")
|
|
|
|
|
|
+ r0 := ParseName(s, FillNothing)
|
|
|
|
|
|
if strings.Contains(s, "..") && !r0.IsZero() {
|
|
if strings.Contains(s, "..") && !r0.IsZero() {
|
|
t.Fatalf("non-zero value for path with '..': %q", s)
|
|
t.Fatalf("non-zero value for path with '..': %q", s)
|
|
@@ -369,36 +413,15 @@ func FuzzParseName(f *testing.F) {
|
|
t.Errorf("String() did not round-trip with case insensitivity: %q\ngot = %q\nwant = %q", s, r0.String(), s)
|
|
t.Errorf("String() did not round-trip with case insensitivity: %q\ngot = %q\nwant = %q", s, r0.String(), s)
|
|
}
|
|
}
|
|
|
|
|
|
- r1 := ParseNameFill(r0.String(), "")
|
|
|
|
|
|
+ r1 := ParseName(r0.String(), FillNothing)
|
|
if !r0.EqualFold(r1) {
|
|
if !r0.EqualFold(r1) {
|
|
t.Errorf("round-trip mismatch: %+v != %+v", r0, r1)
|
|
t.Errorf("round-trip mismatch: %+v != %+v", r0, r1)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
-func TestFill(t *testing.T) {
|
|
|
|
- cases := []struct {
|
|
|
|
- dst string
|
|
|
|
- src string
|
|
|
|
- want string
|
|
|
|
- }{
|
|
|
|
- {"mistral", "o.com/library/PLACEHOLDER:latest+Q4_0", "o.com/library/mistral:latest+Q4_0"},
|
|
|
|
- {"o.com/library/mistral", "PLACEHOLDER:latest+Q4_0", "o.com/library/mistral:latest+Q4_0"},
|
|
|
|
- {"", "o.com/library/mistral:latest+Q4_0", "o.com/library/mistral:latest+Q4_0"},
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for _, tt := range cases {
|
|
|
|
- t.Run(tt.dst, func(t *testing.T) {
|
|
|
|
- r := Fill(ParseNameFill(tt.dst, ""), ParseNameFill(tt.src, ""))
|
|
|
|
- if r.String() != tt.want {
|
|
|
|
- t.Errorf("Fill(%q, %q) = %q; want %q", tt.dst, tt.src, r, tt.want)
|
|
|
|
- }
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func TestNameStringAllocs(t *testing.T) {
|
|
func TestNameStringAllocs(t *testing.T) {
|
|
- name := ParseNameFill("example.com/ns/mistral:latest+Q4_0", "")
|
|
|
|
|
|
+ name := ParseName("example.com/ns/mistral:latest+Q4_0", FillNothing)
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
allocs := testing.AllocsPerRun(1000, func() {
|
|
keep(name.String())
|
|
keep(name.String())
|
|
})
|
|
})
|
|
@@ -407,25 +430,16 @@ func TestNameStringAllocs(t *testing.T) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func ExampleFill() {
|
|
|
|
- defaults := ParseNameFill("registry.ollama.com/library/PLACEHOLDER:latest+Q4_0", "")
|
|
|
|
- r := Fill(ParseNameFill("mistral", ""), defaults)
|
|
|
|
- fmt.Println(r)
|
|
|
|
-
|
|
|
|
- // Output:
|
|
|
|
- // registry.ollama.com/library/mistral:latest+Q4_0
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func ExampleName_MapHash() {
|
|
func ExampleName_MapHash() {
|
|
m := map[uint64]bool{}
|
|
m := map[uint64]bool{}
|
|
|
|
|
|
// key 1
|
|
// key 1
|
|
- m[ParseNameFill("mistral:latest+q4", "").MapHash()] = true
|
|
|
|
- m[ParseNameFill("miSTRal:latest+Q4", "").MapHash()] = true
|
|
|
|
- m[ParseNameFill("mistral:LATest+Q4", "").MapHash()] = true
|
|
|
|
|
|
+ m[ParseName("mistral:latest+q4", FillNothing).MapHash()] = true
|
|
|
|
+ m[ParseName("miSTRal:latest+Q4", FillNothing).MapHash()] = true
|
|
|
|
+ m[ParseName("mistral:LATest+Q4", FillNothing).MapHash()] = true
|
|
|
|
|
|
// key 2
|
|
// key 2
|
|
- m[ParseNameFill("mistral:LATest", "").MapHash()] = true
|
|
|
|
|
|
+ m[ParseName("mistral:LATest", FillNothing).MapHash()] = true
|
|
|
|
|
|
fmt.Println(len(m))
|
|
fmt.Println(len(m))
|
|
// Output:
|
|
// Output:
|
|
@@ -434,9 +448,9 @@ func ExampleName_MapHash() {
|
|
|
|
|
|
func ExampleName_CompareFold_sort() {
|
|
func ExampleName_CompareFold_sort() {
|
|
names := []Name{
|
|
names := []Name{
|
|
- ParseNameFill("mistral:latest", ""),
|
|
|
|
- ParseNameFill("mistRal:7b+q4", ""),
|
|
|
|
- ParseNameFill("MIstral:7b", ""),
|
|
|
|
|
|
+ ParseName("mistral:latest", FillNothing),
|
|
|
|
+ ParseName("mistRal:7b+q4", FillNothing),
|
|
|
|
+ ParseName("MIstral:7b", FillNothing),
|
|
}
|
|
}
|
|
|
|
|
|
slices.SortFunc(names, Name.CompareFold)
|
|
slices.SortFunc(names, Name.CompareFold)
|
|
@@ -457,7 +471,7 @@ func ExampleName_completeAndResolved() {
|
|
"x/y/z:latest+q4_0",
|
|
"x/y/z:latest+q4_0",
|
|
"@sha123-1",
|
|
"@sha123-1",
|
|
} {
|
|
} {
|
|
- name := ParseNameFill(s, "")
|
|
|
|
|
|
+ name := ParseName(s, FillNothing)
|
|
fmt.Printf("complete:%v resolved:%v digest:%s\n", name.IsComplete(), name.IsResolved(), name.Digest())
|
|
fmt.Printf("complete:%v resolved:%v digest:%s\n", name.IsComplete(), name.IsResolved(), name.Digest())
|
|
}
|
|
}
|
|
|
|
|
|
@@ -468,7 +482,7 @@ func ExampleName_completeAndResolved() {
|
|
}
|
|
}
|
|
|
|
|
|
func ExampleName_DisplayShortest() {
|
|
func ExampleName_DisplayShortest() {
|
|
- name := ParseNameFill("example.com/jmorganca/mistral:latest+Q4_0", "")
|
|
|
|
|
|
+ name := ParseName("example.com/jmorganca/mistral:latest+Q4_0", FillNothing)
|
|
|
|
|
|
fmt.Println(name.DisplayShortest("example.com/jmorganca/_:latest"))
|
|
fmt.Println(name.DisplayShortest("example.com/jmorganca/_:latest"))
|
|
fmt.Println(name.DisplayShortest("example.com/_/_:latest"))
|
|
fmt.Println(name.DisplayShortest("example.com/_/_:latest"))
|
|
@@ -476,7 +490,7 @@ func ExampleName_DisplayShortest() {
|
|
fmt.Println(name.DisplayShortest("_/_/_:_"))
|
|
fmt.Println(name.DisplayShortest("_/_/_:_"))
|
|
|
|
|
|
// Default
|
|
// Default
|
|
- name = ParseNameFill("registry.ollama.ai/library/mistral:latest+Q4_0", "")
|
|
|
|
|
|
+ name = ParseName("registry.ollama.ai/library/mistral:latest+Q4_0", FillNothing)
|
|
fmt.Println(name.DisplayShortest(""))
|
|
fmt.Println(name.DisplayShortest(""))
|
|
|
|
|
|
// Output:
|
|
// Output:
|