Skip to content
quarry Artifact [532cf44163]
Login

Artifact [532cf44163]

Artifact 532cf441632cb6d03962805adeba2af6882e4917922bb958df10513465cf6516:


package api

import (
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/oltp"
)

// account.explain's two halves must not contradict each other.
//
// The `can` sentence came from oltp.Explain, which asks HasAny and so
// reads `a` as a wildcard. The letter list came from oltp.Decode via
// Closure, which has no entry for `a`. Both were internally consistent
// and the ANSWER contradicted itself: a repository admin was told they
// could check in and edit tickets, above a list showing no i, k, w or
// f (8ea1e46d, G-84).
//
// Asserted at the op's own composition rather than only in oltp,
// because the defect was not in either function — it was in feeding
// them different inputs.
func TestExplainsSentenceAndLettersAgreeForAnAdmin(t *testing.T) {
	const caps = "a"
	sentence := oltp.Explain("jan", oltp.CapSet(caps))
	// The composition the op performs. If this drifts from register.go
	// the assertion below is worthless, so it is spelled the same way.
	grants := oltp.Decode(oltp.AsGated(caps))
	joined := strings.Join(grants, " | ")

	for _, claim := range []string{"check in", "edit tickets", "edit wiki pages"} {
		if !strings.Contains(sentence, claim) {
			continue // the sentence does not make this claim; nothing to match
		}
		// The sentence claims it, so the letters must carry it.
		var found bool
		for _, g := range grants {
			if strings.Contains(g, strings.TrimSuffix(claim, "s")) {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("FAIL: the sentence says an admin can %q and the letter list does not "+
				"carry it.\n  sentence: %s\n  letters:  %s", claim, sentence, joined)
		}
	}
	if len(grants) < 10 {
		t.Errorf("FAIL: an admin's letter list has %d entries; `a` is not expanding, so the "+
			"page will contradict its own sentence again", len(grants))
	}
}

// A SITE admin's list matches its sentence too.
//
// This is the case my first fix missed and my first guard could not
// see. AsGated expanded `a` and not `s`, so explain told zeitgeist —
// who holds s — that they "can do everything" above a list of seven
// read-ish abilities. The same contradiction, one umbrella cap over,
// live on production after the fix that was supposed to end it.
//
// The guard in oltp could not catch it because it compares HasAny to
// HasAny, and HasAny has always expanded s: the invariant held
// trivially on both sides while the human-readable list was wrong.
// What was broken is what DECODE reports, so that is what this
// asserts.
func TestASiteAdminsLettersMatchItsSentence(t *testing.T) {
	for _, caps := range []string{"s", "gjorzh2mncs"} {
		sentence := oltp.Explain("zeitgeist", oltp.CapSet(caps))
		grants := oltp.Decode(oltp.AsGated(caps))
		if !strings.Contains(sentence, "everything") {
			t.Fatalf("FAIL: with caps %q the sentence no longer claims everything (%q); this "+
				"test is asserting nothing", caps, sentence)
		}
		// "Everything" has to mean everything: the list must carry an
		// entry for every ability, x and y included, which is what s
		// grants and a does not.
		if len(grants) < len(oltp.Abilities)-2 {
			t.Errorf("FAIL: caps %q says %q and lists only %d of %d abilities; the page "+
				"contradicts itself", caps, "can do everything", len(grants), len(oltp.Abilities))
		}
		for _, claim := range []string{"see private branches", "push unversioned files"} {
			var found bool
			for _, g := range grants {
				if strings.Contains(g, claim) {
					found = true
					break
				}
			}
			if !found {
				t.Errorf("FAIL: caps %q claims everything but its letters omit %q, which s "+
					"grants", caps, claim)
			}
		}
	}
}