Skip to content
quarry Artifact [0d79907423]
Login

Artifact [0d79907423]

Artifact 0d7990742368753fe97de007e64bd964366a3a8d123b85bbf40eb75ce9955109:


package web

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/ops"
)

// The Rich composer's pickers ask ref.suggest what a sigil could name,
// and insert what comes back as typed: a numbered ticket as #N, one
// without a number by its hash, a landing as !N, a person as @handle,
// a wiki page as [[Title]]. What the reader typed after the sigil
// narrows the list by the reference or its title.
func TestRefSuggestOffersReferencesAsTyped(t *testing.T) {
	type listIn struct {
		Repo  string `json:"repo"`
		State string `json:"state"`
		Limit int    `json:"limit"`
		Q     string `json:"q"`
	}
	type ticket struct {
		ID     string `json:"id"`
		Title  string `json:"title"`
		Number int    `json:"number,omitempty"`
	}
	type tickets struct {
		Tickets []ticket `json:"tickets"`
	}
	type landing struct {
		Title  string `json:"title"`
		Number int    `json:"number,omitempty"`
	}
	type landings struct {
		Landings []landing `json:"landings"`
	}
	type handle struct {
		Handle string `json:"handle"`
	}
	type handles struct {
		Handles []handle `json:"handles"`
	}
	type page struct {
		Title string `json:"title"`
	}
	type pages struct {
		Pages []page `json:"pages"`
	}
	r := ops.NewRegistry()
	must := func(err error) {
		if err != nil {
			t.Fatal(err)
		}
	}
	must(ops.Register(r, ops.Op[listIn, tickets]{Name: "ticket.list", Doc: "stub", Kind: ops.Query, Auth: ops.Anonymous,
		Route: "GET /api/v1/r/{repo}/tickets",
		Run: func(context.Context, listIn) (tickets, error) {
			return tickets{[]ticket{{ID: "aaaa1111bbbb2222", Title: "Accept is slow", Number: 263},
				{ID: "cccc3333dddd4444", Title: "Accent colour in dark mode"},
				{ID: "eeee5555ffff6666", Title: "Send the file view whole", Number: 350}}}, nil
		}}))
	must(ops.Register(r, ops.Op[listIn, landings]{Name: "landing.list", Doc: "stub", Kind: ops.Query, Auth: ops.Anonymous,
		Route: "GET /api/v1/r/{repo}/landings",
		Run: func(context.Context, listIn) (landings, error) {
			return landings{[]landing{{Title: "Rich editor", Number: 1051}, {Title: "never numbered"}}}, nil
		}}))
	must(ops.Register(r, ops.Op[listIn, handles]{Name: "people.mention", Doc: "stub", Kind: ops.Query, Auth: ops.Anonymous,
		Route: "GET /api/v1/r/{repo}/mention",
		Run: func(_ context.Context, in listIn) (handles, error) {
			return handles{[]handle{{Handle: "zeitgeist"}}}, nil
		}}))
	must(ops.Register(r, ops.Op[listIn, pages]{Name: "wiki.list", Doc: "stub", Kind: ops.Query, Auth: ops.Anonymous,
		Route: "GET /api/v1/r/{repo}/wiki",
		Run: func(context.Context, listIn) (pages, error) {
			return pages{[]page{{Title: "checkin/0123456789abcdef"}, {Title: "Deploy ritual"}, {Title: "Home"}}}, nil
		}}))
	verify := Verify(func(repo, user, pass string, need ops.Auth) api.Decision { return api.Allowed })
	srv := httptest.NewServer(HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "dan", roles: map[string]ops.Auth{"alpha": ops.Token}})}, verify))
	t.Cleanup(srv.Close)
	ask := func(q string) []string {
		req, _ := http.NewRequest("GET", srv.URL+"/r/alpha/ref.suggest?"+q, nil)
		req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Fatal(err)
		}
		defer resp.Body.Close()
		var out struct {
			Picks []refPick `json:"picks"`
		}
		if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
			t.Fatalf("FAIL: %s: %d, not a list: %v", q, resp.StatusCode, err)
		}
		var toks []string
		for _, p := range out.Picks {
			toks = append(toks, p.Tok)
		}
		return toks
	}
	cases := []struct {
		q    string
		want []string
	}{
		{"k=ticket", []string{"#263", "[cccc3333dddd]", "#350"}},
		{"k=ticket&q=acc", []string{"#263", "[cccc3333dddd]"}},
		{"k=ticket&q=35", []string{"#350"}},
		{"k=landing", []string{"!1051"}},
		{"k=person&q=zeit", []string{"@zeitgeist"}},
		{"k=wiki&q=deploy", []string{"[[Deploy ritual]]"}},
		{"k=wiki", []string{"[[Deploy ritual]]", "[[Home]]"}},
	}
	for _, c := range cases {
		got := ask(c.q)
		if len(got) != len(c.want) {
			t.Errorf("FAIL: %s offered %q, want %q", c.q, got, c.want)
			continue
		}
		for i := range got {
			if got[i] != c.want[i] {
				t.Errorf("FAIL: %s offered %q, want %q", c.q, got, c.want)
				break
			}
		}
	}
	t.Log("ok: each picker offers references as they are typed")
}