test(16.3-04): pin Journal token scope registration and lang keys

Assert journal and journal:read scopes, methods, permissions, and
phrase keys in en/pl lang.yaml.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-11 13:17:41 +02:00
parent 09308d9552
commit 7bbafcbf28

117
token_scopes_test.go Normal file
View File

@@ -0,0 +1,117 @@
package journal_test
import (
"os"
"path/filepath"
"testing"
journal "git.golem15.com/golem15/sm-journal-plugin"
"git.golem15.com/golem15/summercms/modules/pact"
"github.com/goccy/go-yaml"
)
func TestJournalTokenScopes(t *testing.T) {
p := &journal.Plugin{}
scopes := p.TokenScopes()
if len(scopes) != 2 {
t.Fatalf("TokenScopes len = %d, want 2", len(scopes))
}
byName := map[string]pact.TokenScope{}
for _, s := range scopes {
byName[s.Name] = s
}
journalScope, ok := byName["journal"]
if !ok {
t.Fatal("missing journal scope")
}
readScope, ok := byName["journal:read"]
if !ok {
t.Fatal("missing journal:read scope")
}
if len(journalScope.Permissions) != 1 || journalScope.Permissions[0] != "golem15.journal.*" {
t.Fatalf("journal permissions = %#v", journalScope.Permissions)
}
if len(readScope.Permissions) != 1 || readScope.Permissions[0] != "golem15.journal.*" {
t.Fatalf("journal:read permissions = %#v", readScope.Permissions)
}
all := []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"}
if got := journalScope.Methods; !stringSlicesEqual(got, all) {
t.Fatalf("journal methods = %#v, want %#v", got, all)
}
if got := readScope.Methods; !stringSlicesEqual(got, []string{"GET", "HEAD"}) {
t.Fatalf("journal:read methods = %#v", got)
}
keys := []string{
journalScope.Label, journalScope.Description,
readScope.Label, readScope.Description,
}
for _, lang := range []string{"en", "pl"} {
path := filepath.Join("lang", lang, "lang.yaml")
raw, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read %s: %v", path, err)
}
var root map[string]any
if err := yaml.Unmarshal(raw, &root); err != nil {
t.Fatalf("yaml %s: %v", path, err)
}
for _, key := range keys {
if !phraseExists(root, key) {
t.Fatalf("%s missing phrase key %s", path, key)
}
}
}
}
func stringSlicesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// phraseExists resolves plugin keys like golem15.journal::lang.scopes.journal
// against the plugin lang.yaml root (scopes.journal under the file).
func phraseExists(root map[string]any, key string) bool {
const prefix = "golem15.journal::lang."
if len(key) < len(prefix) || key[:len(prefix)] != prefix {
return false
}
parts := splitDot(key[len(prefix):])
var cur any = root
for _, p := range parts {
m, ok := cur.(map[string]any)
if !ok {
return false
}
cur, ok = m[p]
if !ok {
return false
}
}
switch v := cur.(type) {
case string:
return v != ""
default:
return cur != nil
}
}
func splitDot(s string) []string {
out := []string{}
start := 0
for i := 0; i < len(s); i++ {
if s[i] == '.' {
out = append(out, s[start:i])
start = i + 1
}
}
out = append(out, s[start:])
return out
}