package repositoryroutecontract

import (
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
)

func TestParseRawRequest(t *testing.T) {
	t.Parallel()
	for _, test := range []struct {
		name, method, path string
		want               RawRequest
		wantError          bool
		url                *url.URL
	}{
		{name: "escaped ref and file", method: http.MethodGet, path: "/acme/repo/raw/feature%2Ftopic/docs/hello%20world.md", want: RawRequest{Owner: "acme", Repository: "repo", Ref: "feature/topic", FilePath: "docs/hello world.md", Capability: "repo:read"}},
		{name: "post", method: http.MethodPost, path: "/acme/repo/raw/main/README.md", wantError: true},
		{name: "empty ref", method: http.MethodGet, path: "/acme/repo/raw//README.md", wantError: true},
		{name: "empty file", method: http.MethodGet, path: "/acme/repo/raw/main/", wantError: true},
		{name: "double leading slash", method: http.MethodGet, path: "//acme/repo/raw/main/file", wantError: true},
		{name: "middle empty segment", method: http.MethodGet, path: "/acme/repo/raw/main/docs//file", wantError: true},
		{name: "dot segment", method: http.MethodGet, path: "/acme/repo/raw/main/../secret", wantError: true},
		{name: "encoded slash changes file hierarchy", method: http.MethodGet, path: "/acme/repo/raw/main/docs%2Fsecret", wantError: true},
		{name: "encoded backslash changes file hierarchy", method: http.MethodGet, path: "/acme/repo/raw/main/docs%5Csecret", wantError: true},
		{name: "encoded control", method: http.MethodGet, path: "/acme/repo/raw/main/docs/%00secret", wantError: true},
		{name: "dot ref segment", method: http.MethodGet, path: "/acme/repo/raw/feature%2F..%2Ftopic/docs/file", wantError: true},
		{name: "empty ref segment", method: http.MethodGet, path: "/acme/repo/raw/feature%2F%2Ftopic/docs/file", wantError: true},
		{name: "invalid escape", method: http.MethodGet, url: &url.URL{Path: "/acme/repo/raw/main/file", RawPath: "/acme/repo/raw/%zz/file"}, wantError: true},
		{name: "raw path mismatch", method: http.MethodGet, url: &url.URL{Path: "/acme/repo/raw/main/file", RawPath: "/acme/repo/raw/other/file"}, wantError: true},
		{name: "decode once", method: http.MethodGet, path: "/acme/repo/raw/feature%252Ftopic/docs/file", want: RawRequest{Owner: "acme", Repository: "repo", Ref: "feature%2Ftopic", FilePath: "docs/file", Capability: "repo:read"}},
	} {
		t.Run(test.name, func(t *testing.T) {
			var request *http.Request
			if test.url != nil {
				request = &http.Request{Method: test.method, URL: test.url}
			} else {
				request = httptest.NewRequest(test.method, test.path, nil)
			}
			got, err := ParseRawRequest(request)
			if test.wantError {
				if err == nil {
					t.Fatal("expected error")
				}
				return
			}
			if err != nil {
				t.Fatalf("ParseRawRequest: %v", err)
			}
			if !reflect.DeepEqual(test.want, got) {
				t.Fatalf("got %+v, want %+v", got, test.want)
			}
		})
	}
}
