package source

import (
	"bytes"
	"io"
	"testing"

	"tsne.dev/hopper/internal/log"
)

func TestCleanArchivePath(t *testing.T) {
	tests := []struct {
		raw     string
		want    string
		wantErr bool
		warn    bool
	}{
		{"a/b.js", "a/b.js", false, false},
		{"./a//b.js", "a/b.js", false, false},
		{"/abs/x", "", true, false},
		{"../escape", "", true, false},
		{"a/../../escape", "", true, false},
		{"a/../b.js", "b.js", false, true}, // contained .. but stays in root
	}
	for _, tt := range tests {
		var warn bytes.Buffer
		log.Init(io.Discard, &warn)
		got, err := cleanArchivePath(tt.raw)
		if tt.wantErr {
			if err == nil {
				t.Errorf("%q: expected error", tt.raw)
			}
			continue
		}
		if err != nil {
			t.Errorf("%q: unexpected error %v", tt.raw, err)
			continue
		}
		if got != tt.want {
			t.Errorf("%q: got %q want %q", tt.raw, got, tt.want)
		}
		if tt.warn && warn.Len() == 0 {
			t.Errorf("%q: expected warning", tt.raw)
		}
		if !tt.warn && warn.Len() != 0 {
			t.Errorf("%q: unexpected warning %q", tt.raw, warn.String())
		}
	}
}

func TestSelectPath(t *testing.T) {
	tests := []struct {
		cleaned string
		root    string
		want    string
		wantOK  bool
	}{
		{"assets/x.js", "", "assets/x.js", true},
		{"README.md", "", "README.md", true},
		{"app/assets/x.js", "app", "assets/x.js", true},
		{"README.md", "app", "", false},
		{"app", "app", "", false},
		{"appendix/x", "app", "", false},
		{"dist/public/index.html", "dist/public", "index.html", true},
		{"dist/private/x", "dist/public", "", false},
	}
	for _, tt := range tests {
		s := &TarGzSource{root: tt.root}
		got, ok := s.selectPath(tt.cleaned)
		if ok != tt.wantOK {
			t.Errorf("selectPath(%q, %q): ok = %v, want %v", tt.cleaned, tt.root, ok, tt.wantOK)
			continue
		}
		if ok && got != tt.want {
			t.Errorf("selectPath(%q, %q) = %q, want %q", tt.cleaned, tt.root, got, tt.want)
		}
	}
}

func TestContainsDotDot(t *testing.T) {
	cases := map[string]bool{
		"a/b/c":   false,
		"..":      true,
		"../x":    true,
		"a/../b":  true,
		"a/..b/c": false,
		"":        false,
		"a/b/..":  true,
	}
	for in, want := range cases {
		if got := containsDotDot(in); got != want {
			t.Errorf("containsDotDot(%q) = %v, want %v", in, got, want)
		}
	}
}
