209 lines
5.1 KiB
Go
209 lines
5.1 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
)
|
|
|
|
func TestValidatePath(t *testing.T) {
|
|
valid := []string{
|
|
"report.md",
|
|
"daily/report.md",
|
|
"a-b_1.2/report.html",
|
|
}
|
|
for _, path := range valid {
|
|
t.Run("valid "+path, func(t *testing.T) {
|
|
if err := ValidatePath(path); err != nil {
|
|
t.Fatalf("ValidatePath(%q) error = %v", path, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
invalid := []string{
|
|
"",
|
|
"/absolute",
|
|
"../outside",
|
|
"nested/../outside",
|
|
"nested/./file",
|
|
"nested//file",
|
|
`nested\file`,
|
|
}
|
|
for _, path := range invalid {
|
|
t.Run("invalid "+path, func(t *testing.T) {
|
|
err := ValidatePath(path)
|
|
if !IsInvalidPath(err) {
|
|
t.Fatalf("ValidatePath(%q) error = %v, want invalid path", path, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidatePrefixAllowsRoot(t *testing.T) {
|
|
if err := ValidatePrefix(""); err != nil {
|
|
t.Fatalf("ValidatePrefix(\"\") error = %v", err)
|
|
}
|
|
if err := ValidatePrefix("a/.."); !IsInvalidPath(err) {
|
|
t.Fatalf("ValidatePrefix traversal error = %v, want invalid path", err)
|
|
}
|
|
}
|
|
|
|
func TestStatePath(t *testing.T) {
|
|
tests := map[string]string{
|
|
"": StateFileName,
|
|
"bundle": "bundle/" + StateFileName,
|
|
}
|
|
for bundlePath, want := range tests {
|
|
t.Run(bundlePath, func(t *testing.T) {
|
|
got, err := StatePath(bundlePath)
|
|
if err != nil {
|
|
t.Fatalf("StatePath(%q) error = %v", bundlePath, err)
|
|
}
|
|
if got != want {
|
|
t.Fatalf("StatePath(%q) = %q, want %q", bundlePath, got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDisplayPath(t *testing.T) {
|
|
tests := map[string]string{
|
|
"": ".",
|
|
"bundle": "bundle",
|
|
}
|
|
for path, want := range tests {
|
|
t.Run(path, func(t *testing.T) {
|
|
if got := DisplayPath(path); got != want {
|
|
t.Fatalf("DisplayPath(%q) = %q, want %q", path, got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestManagedBundleTargets(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
bundlePath string
|
|
outputs []string
|
|
want []string
|
|
}{
|
|
{
|
|
name: "root",
|
|
outputs: []string{"report.html", "assets/style.css"},
|
|
want: []string{"report.html", "assets/style.css", StateFileName},
|
|
},
|
|
{
|
|
name: "nested",
|
|
bundlePath: "daily",
|
|
outputs: []string{"report.html"},
|
|
want: []string{"daily/report.html", "daily/" + StateFileName},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := ManagedBundleTargets(tt.bundlePath, tt.outputs)
|
|
if err != nil {
|
|
t.Fatalf("ManagedBundleTargets() error = %v", err)
|
|
}
|
|
if len(got) != len(tt.want) {
|
|
t.Fatalf("targets = %v, want %v", got, tt.want)
|
|
}
|
|
for i := range got {
|
|
if got[i] != tt.want[i] {
|
|
t.Fatalf("targets = %v, want %v", got, tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestManagedBundleTargetsRejectsInvalidOutputPath(t *testing.T) {
|
|
if _, err := ManagedBundleTargets("bundle", []string{"../outside"}); !IsInvalidPath(err) {
|
|
t.Fatalf("ManagedBundleTargets() error = %v, want invalid path", err)
|
|
}
|
|
}
|
|
|
|
func TestListSortsEntries(t *testing.T) {
|
|
backend := walkBackend{
|
|
entries: []Entry{
|
|
{Path: "z.txt", Type: EntryTypeFile},
|
|
{Path: "a.txt", Type: EntryTypeFile},
|
|
},
|
|
}
|
|
|
|
entries, err := List(context.Background(), backend, "", WalkOptions{})
|
|
if err != nil {
|
|
t.Fatalf("List() error = %v", err)
|
|
}
|
|
if got, want := []string{entries[0].Path, entries[1].Path}, []string{"a.txt", "z.txt"}; got[0] != want[0] || got[1] != want[1] {
|
|
t.Fatalf("paths = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestTypedErrorPredicates(t *testing.T) {
|
|
err := NewError(OpReadFile, "test", "missing", ErrNotFound, errors.New("missing"))
|
|
if !IsNotFound(err) {
|
|
t.Fatalf("IsNotFound(%v) = false, want true", err)
|
|
}
|
|
if IsInvalidPath(err) {
|
|
t.Fatalf("IsInvalidPath(%v) = true, want false", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistry(t *testing.T) {
|
|
registry := NewRegistry()
|
|
if err := registry.Register("test", func(context.Context, OpenConfig) (Backend, error) {
|
|
return walkBackend{}, nil
|
|
}); err != nil {
|
|
t.Fatalf("Register() error = %v", err)
|
|
}
|
|
if _, err := registry.Open(context.Background(), "test", nil); err != nil {
|
|
t.Fatalf("Open() error = %v", err)
|
|
}
|
|
if _, err := registry.Open(context.Background(), "missing", nil); !IsUnsupported(err) {
|
|
t.Fatalf("Open() error = %v, want unsupported", err)
|
|
}
|
|
}
|
|
|
|
type walkBackend struct {
|
|
entries []Entry
|
|
}
|
|
|
|
func (b walkBackend) ReadFile(context.Context, string) ([]byte, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (b walkBackend) OpenReader(context.Context, string) (io.ReadCloser, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (b walkBackend) WriteFile(context.Context, string, []byte, WriteOptions) (Entry, error) {
|
|
return Entry{}, nil
|
|
}
|
|
|
|
func (b walkBackend) WriteFrom(context.Context, string, io.Reader, WriteOptions) (Entry, error) {
|
|
return Entry{}, nil
|
|
}
|
|
|
|
func (b walkBackend) Stat(context.Context, string) (Entry, error) {
|
|
return Entry{}, nil
|
|
}
|
|
|
|
func (b walkBackend) Walk(_ context.Context, _ string, _ WalkOptions, fn WalkFunc) error {
|
|
for _, entry := range b.entries {
|
|
if err := fn(entry); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b walkBackend) HasAny(context.Context, string) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
func (b walkBackend) DeleteManagedBundle(context.Context, string, []string, DeleteOptions) error {
|
|
return nil
|
|
}
|