package web import ( "net/http" "net/url" "os" "path/filepath" "strings" "testing" "git.josie-c.com/josie/simplegit/internal/db" ) func TestNewRepoFormRequiresLogin(t *testing.T) { httpServer, _, _ := newTestServer(t) client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }} resp, err := client.Get(httpServer.URL + "/new") if err != nil { t.Fatalf("GET /new: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusSeeOther { t.Errorf("status = %d, want 303", resp.StatusCode) } if resp.Header.Get("Location") != "/login" { t.Errorf("Location = %q, want /login", resp.Header.Get("Location")) } loggedIn := newLoggedInClient(t, httpServer) resp, err = loggedIn.Get(httpServer.URL + "/new") if err != nil { t.Fatalf("GET /new signed in: %v", err) } body := readAll(t, resp) if resp.StatusCode != http.StatusOK || !strings.Contains(body, `name="name"`) { t.Errorf("signed-in GET /new = %d, form missing: %q", resp.StatusCode, body) } } func TestCreateRepoFlow(t *testing.T) { httpServer, database, dataDir := newTestServer(t) client := newLoggedInClient(t, httpServer) resp, err := client.PostForm(httpServer.URL+"/new", url.Values{ "name": {"my-repo"}, "description": {"a test repo"}, "visibility": {"public"}, }) if err != nil { t.Fatalf("POST /new: %v", err) } body := readAll(t, resp) if resp.StatusCode != http.StatusOK { t.Errorf("status = %d, want 200", resp.StatusCode) } if !strings.Contains(body, "git remote add origin") || !strings.Contains(body, "/josie/my-repo.git") { t.Errorf("no push instructions: %q", body) } repo, err := db.GetRepoByName(database, "josie", "my-repo") if err != nil { t.Fatalf("GetRepoByName: %v", err) } if repo.Visibility != "public" || repo.Description != "a test repo" { t.Errorf("repo = %+v, want public / %q stored", repo, "a test repo") } if repo.PushedAt.Valid { t.Errorf("PushedAt = %d, want NULL before first push", repo.PushedAt.Int64) } head, err := os.ReadFile(filepath.Join(dataDir, "repos", "josie", "my-repo.git", "HEAD")) if err != nil { t.Fatalf("bare repo HEAD missing: %v", err) } if !strings.Contains(string(head), "ref: refs/heads/"+repo.DefaultBranch) { t.Errorf("HEAD = %q, want default branch %q", head, repo.DefaultBranch) } } func TestCreateRepoRejectsBadNames(t *testing.T) { httpServer, _, _ := newTestServer(t) client := newLoggedInClient(t, httpServer) for _, name := range []string{"bad name", "ünicode", "", strings.Repeat("a", maxNameLen+1)} { resp, err := client.PostForm(httpServer.URL+"/new", url.Values{"name": {name}}) if err != nil { t.Fatalf("POST /new %q: %v", name, err) } body := readAll(t, resp) if resp.StatusCode != http.StatusUnprocessableEntity { t.Errorf("name %q: status = %d, want 422", name, resp.StatusCode) } if !strings.Contains(body, "invalid repository name") { t.Errorf("name %q: no error shown: %q", name, body) } } } func TestCreateRepoRejectsDuplicate(t *testing.T) { httpServer, database, _ := newTestServer(t) client := newLoggedInClient(t, httpServer) resp, err := client.PostForm(httpServer.URL+"/new", url.Values{"name": {"dup"}}) if err != nil { t.Fatalf("first POST /new: %v", err) } readAll(t, resp) resp, err = client.PostForm(httpServer.URL+"/new", url.Values{"name": {"dup"}}) if err != nil { t.Fatalf("second POST /new: %v", err) } body := readAll(t, resp) if resp.StatusCode != http.StatusUnprocessableEntity { t.Errorf("status = %d, want 422", resp.StatusCode) } if !strings.Contains(body, "already have a repository") { t.Errorf("no duplicate error shown: %q", body) } var count int if err := database.QueryRow( `SELECT count(*) FROM repos WHERE name = ?`, "dup", ).Scan(&count); err != nil { t.Fatalf("count repos: %v", err) } if count != 1 { t.Errorf("repos named dup = %d, want 1", count) } }