Cthulhu is no longer a fork. Now it is a screen reader written in Golang.
This commit is contained in:
1 parent
a998fe67de
commit
069fc674dc
708 files changed
+112482
-532
No files matched your search
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
package tentacle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func repository_files() map[string]string {
|
||||
return map[string]string{
|
||||
"repository.toml": "format-version = 1\nid = 'example.tentacles'\nname = 'Example tentacles'\ndescription = 'Test catalog'\nmaintainer = 'Maintainer'\n",
|
||||
"catalog.toml": "format-version = 1\n[[tentacles]]\nid = 'echo'\nmanifest = 'echo/tentacle.toml'\n",
|
||||
"echo/tentacle.toml": "format-version = 1\nid = 'echo'\nname = 'Echo'\nversion = '0.1'\ndescription = 'An example'\ncapabilities = ['presentation']\n",
|
||||
}
|
||||
}
|
||||
func read_repository_fixture(files map[string]string) (Repository, error) {
|
||||
return read_repository("https://example.org/team/tentacles", strings.Repeat("a", 40), func(filename string) ([]byte, error) {
|
||||
data, found := files[filename]
|
||||
if !found {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return []byte(data), nil
|
||||
})
|
||||
}
|
||||
func TestRepositoryMetadataDiscoveryValidation(t *testing.T) {
|
||||
repository, err := read_repository_fixture(repository_files())
|
||||
if err != nil || repository.ID != "example.tentacles" || len(repository.Tentacles) != 1 || repository.Tentacles[0].Name != "Echo" {
|
||||
t.Fatalf("discovery: %+v %v", repository, err)
|
||||
}
|
||||
for _, problem := range []string{"missing root", "version", "missing manifest", "traversal", "nested", "mismatch", "duplicate", "oversized", "invalid id"} {
|
||||
t.Run(problem, func(t *testing.T) {
|
||||
files := repository_files()
|
||||
switch problem {
|
||||
case "missing root":
|
||||
delete(files, "repository.toml")
|
||||
case "version":
|
||||
files["repository.toml"] = strings.Replace(files["repository.toml"], "format-version = 1", "format-version = 2", 1)
|
||||
case "missing manifest":
|
||||
delete(files, "echo/tentacle.toml")
|
||||
case "traversal":
|
||||
files["catalog.toml"] = strings.Replace(files["catalog.toml"], "echo/tentacle.toml", "../tentacle.toml", 1)
|
||||
case "nested":
|
||||
files["catalog.toml"] = strings.Replace(files["catalog.toml"], "echo/tentacle.toml", "a/b/tentacle.toml", 1)
|
||||
case "mismatch":
|
||||
files["echo/tentacle.toml"] = strings.Replace(files["echo/tentacle.toml"], "id = 'echo'", "id = 'different'", 1)
|
||||
case "duplicate":
|
||||
files["catalog.toml"] += "[[tentacles]]\nid='echo'\nmanifest='echo/tentacle.toml'\n"
|
||||
case "oversized":
|
||||
files["repository.toml"] += "#" + strings.Repeat("x", MaxFrameBytes)
|
||||
case "invalid id":
|
||||
files["echo/tentacle.toml"] = strings.Replace(files["echo/tentacle.toml"], "id = 'echo'", "id = 'Echo!'", 1)
|
||||
}
|
||||
if _, err := read_repository_fixture(files); err == nil {
|
||||
t.Fatal("accepted invalid metadata")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestRepositoryURLAndLabel(t *testing.T) {
|
||||
origin, err := RepositoryURL(" https://EXAMPLE.org/team/tentacles.git/ ")
|
||||
if err != nil || origin != "https://example.org/team/tentacles.git" || RepositoryLabel(origin) != "team/tentacles" {
|
||||
t.Fatalf("URL %q %v", origin, err)
|
||||
}
|
||||
for _, origin := range []string{"file:///tmp/source", "http://example.org/team/repo", "ssh://example.org/team/repo", "https://Username@example.org/team/repo", "https://example.org/", "https://example.org/team/../repo", "https://example.org/team/repo?ref=main", "https://example.org/team/repo#ref", "https://example.org/team/%00repo"} {
|
||||
if _, err := RepositoryURL(origin); err == nil {
|
||||
t.Fatalf("accepted %q", origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestRepositorySnapshotPersistenceAndIsolation(t *testing.T) {
|
||||
repository, err := read_repository_fixture(repository_files())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
registry := &Registry{Path: filepath.Join(t.TempDir(), "tentacles.toml")}
|
||||
entries, err := registry.Load()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := registry.SaveState(entries, []Repository{repository}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reopened := &Registry{Path: registry.Path}
|
||||
if _, err := reopened.Load(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cached := reopened.Repositories()
|
||||
if len(cached) != 1 || cached[0].Tentacles[0].Name != "Echo" {
|
||||
t.Fatal(cached)
|
||||
}
|
||||
cached[0].Tentacles[0].Name = "mutated"
|
||||
if reopened.Repositories()[0].Tentacles[0].Name != "Echo" {
|
||||
t.Fatal("shared snapshot storage")
|
||||
}
|
||||
if err := reopened.Save(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := registry.Load(); err != nil || len(registry.Repositories()) != 1 {
|
||||
t.Fatalf("entry save dropped catalog: %v", err)
|
||||
}
|
||||
}
|
||||
func TestRepositoryGitIgnoresInheritedConfigAndReadsBlobs(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
// A poisoned inherited config must not affect even Git initialization.
|
||||
t.Setenv("GIT_CONFIG_COUNT", "1")
|
||||
t.Setenv("GIT_CONFIG_KEY_0", "core.bare")
|
||||
t.Setenv("GIT_CONFIG_VALUE_0", "invalid")
|
||||
ctx := context.Background()
|
||||
if _, err := repository_git(ctx, directory, "init", "--bare", "--template="); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
source := t.TempDir()
|
||||
for name, data := range repository_files() {
|
||||
filename := filepath.Join(source, name)
|
||||
if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filename, []byte(data), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Populate a local test snapshot without enabling file transport in the
|
||||
// production fetch path or contacting a real repository.
|
||||
run := func(args ...string) string {
|
||||
command := exec.Command("git", args...)
|
||||
command.Dir = source
|
||||
command.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + source, "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null", "GIT_AUTHOR_NAME=Maintainer", "GIT_AUTHOR_EMAIL=maintainer@example.invalid", "GIT_COMMITTER_NAME=Maintainer", "GIT_COMMITTER_EMAIL=maintainer@example.invalid"}
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("git: %s %v", output, err)
|
||||
}
|
||||
return strings.TrimSpace(string(output))
|
||||
}
|
||||
run("init", "--template=")
|
||||
run("add", ".")
|
||||
run("commit", "-m", "Fixture")
|
||||
setHead := func() {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(filepath.Join(source, ".git", "FETCH_HEAD"), []byte(run("rev-parse", "HEAD")+"\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
setHead()
|
||||
repository, err := read_git_repository(ctx, source, "https://example.org/team/tentacles")
|
||||
if err != nil || len(repository.Tentacles) != 1 {
|
||||
t.Fatalf("Git discovery: %+v %v", repository, err)
|
||||
}
|
||||
revision := run("rev-parse", "HEAD")
|
||||
data, err := repository_git(ctx, source, "show", revision+":repository.toml")
|
||||
if err != nil || !strings.Contains(string(data), "example.tentacles") {
|
||||
t.Fatalf("read blob: %s %v", data, err)
|
||||
}
|
||||
// A regular-looking root symlink must be rejected rather than interpreted
|
||||
// as metadata, including when it references an otherwise valid file.
|
||||
if err := os.Remove(filepath.Join(source, "repository.toml")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink("echo/tentacle.toml", filepath.Join(source, "repository.toml")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
run("add", ".")
|
||||
run("commit", "-m", "Symlink fixture")
|
||||
setHead()
|
||||
if _, err := read_git_repository(ctx, source, "https://example.org/team/tentacles"); err == nil {
|
||||
t.Fatal("accepted symlink metadata")
|
||||
}
|
||||
cancelled, cancel := context.WithCancel(ctx)
|
||||
cancel()
|
||||
if _, err := repository_git(cancelled, source, "status"); err == nil {
|
||||
t.Fatal("ignored cancellation")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user