Files
mesh-catalog/modules/gitea/cmd/npm-registry/refs_test.go
T
jochen 10b5e8188a
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
Refuse a yarn lockfile the scanner stopped in, and a forge answer the cap cut
Either was read as whole and could leave a pinned version unnamed (review of #128).
2026-10-08 14:52:06 +02:00

216 lines
8.9 KiB
Go

package main
import (
"sort"
"strings"
"testing"
)
var knownHere = map[string]bool{"@novox/mesh-sdk": true, "@novox/ui": true, "sdk": true}
func pins(ps []Pinned) string {
var out []string
for _, p := range ps {
out = append(out, p.Package+"@"+p.Version)
}
sort.Strings(out)
return strings.Join(out, " ")
}
func TestAManifestNamesItsRegistryRangesAndNothingElse(t *testing.T) {
got, err := ReadManifest([]byte(`{
"dependencies": {"@novox/mesh-sdk": "^0.1.0", "left-pad": "^1.0.0", "@novox/ui": "file:../ui"},
"devDependencies": {"sdk": "npm:@novox/ui@~2.0.0"},
"peerDependencies": {"@novox/ui": "workspace:*"},
"optionalDependencies": {"@novox/ui": "1.x"}
}`), "r:package.json", knownHere)
if err != nil {
t.Fatal(err)
}
var said []string
for _, w := range got {
said = append(said, w.Package+" "+w.Range)
}
sort.Strings(said)
if strings.Join(said, ",") != "@novox/mesh-sdk ^0.1.0,@novox/ui 1.x,@novox/ui ~2.0.0" {
t.Fatalf("read %v", said)
}
}
func TestAnNpmLockfileOfEveryVersionNamesWhatItPins(t *testing.T) {
v3 := `{"lockfileVersion":3,"packages":{"":{"name":"x"},
"node_modules/@novox/mesh-sdk":{"version":"0.1.3"},
"node_modules/a/node_modules/@novox/mesh-sdk":{"version":"0.1.1"},
"node_modules/sdk":{"name":"@novox/ui","version":"2.0.4"},
"node_modules/left-pad":{"version":"1.3.0"}}}`
got, err := ReadLock("package-lock.json", []byte(v3), "r:package-lock.json", knownHere)
if err != nil {
t.Fatal(err)
}
if pins(got) != "@novox/mesh-sdk@0.1.1 @novox/mesh-sdk@0.1.3 @novox/ui@2.0.4" {
t.Fatalf("v3: %s", pins(got))
}
v1 := `{"lockfileVersion":1,"dependencies":{"@novox/mesh-sdk":{"version":"0.1.2","dependencies":{"@novox/ui":{"version":"1.0.0"}}},
"sdk":{"version":"npm:@novox/ui@2.0.1"}}}`
got, err = ReadLock("npm-shrinkwrap.json", []byte(v1), "r", knownHere)
if err != nil {
t.Fatal(err)
}
if pins(got) != "@novox/mesh-sdk@0.1.2 @novox/ui@1.0.0 @novox/ui@2.0.1" {
t.Fatalf("v1: %s", pins(got))
}
if _, err := ReadLock("package-lock.json", []byte("{not json"), "r", knownHere); err == nil {
t.Fatal("a broken lockfile read as empty")
}
}
func TestAYarnLockOfEitherFormatNamesWhatItPins(t *testing.T) {
classic := "# yarn lockfile v1\n\n\"@novox/mesh-sdk@^0.1.0\", \"@novox/mesh-sdk@^0.1.2\":\n version \"0.1.4\"\n resolved \"x\"\n dependencies:\n left-pad \"^1\"\n\nleft-pad@^1:\n version \"1.3.0\"\n"
if got := pins(mustYarn(t, classic)); got != "@novox/mesh-sdk@0.1.4" {
t.Fatalf("classic: %s", got)
}
berry := "__metadata:\n version: 6\n\n\"@novox/ui@npm:^2.0.0\":\n version: 2.0.7\n resolution: \"@novox/ui@npm:2.0.7\"\n"
if got := pins(mustYarn(t, berry)); got != "@novox/ui@2.0.7" {
t.Fatalf("berry: %s", got)
}
}
func TestAPnpmLockNamesWhatItPinsInEachFormat(t *testing.T) {
lock := "lockfileVersion: '9.0'\npackages:\n '@novox/mesh-sdk@0.1.5':\n resolution: {}\n /@novox/ui/2.0.2:\n resolution: {}\n /@other/novox/ui@9.9.9:\n /x-sdk@1.0.0:\n"
if got := pins(readTextLock([]byte(lock), "r", knownHere)); got != "@novox/mesh-sdk@0.1.5 @novox/ui@2.0.2" {
t.Fatalf("pnpm: %s", got)
}
}
func TestOnlyTheRepositorysOwnManifestsAreRead(t *testing.T) {
for p, want := range map[string]bool{"package.json": true, "modules/x/package-lock.json": true, "yarn.lock": true,
"pnpm-lock.yaml": true, "node_modules/a/package.json": false, "README.md": false, "a/package.json.bak": false} {
if interesting(p) != want {
t.Errorf("%s: %v", p, !want)
}
}
}
// Lockfiles as npm writes them: a `packages` entry's `dependencies` is a map of name to range, which a
// reader expecting nested entries cannot read (the shape every lockfile on the forge had).
const lockV1 = `{
"name": "app", "version": "1.0.0", "lockfileVersion": 1, "requires": true,
"dependencies": {
"@novox/mesh-sdk": {
"version": "0.1.2",
"resolved": "https://forge.example/api/packages/novox/npm/@novox/mesh-sdk/-/0.1.2/mesh-sdk-0.1.2.tgz",
"integrity": "sha512-x",
"requires": {"@novox/ui": "^1.0.0", "left-pad": "^1.3.0"},
"dependencies": {
"@novox/ui": {"version": "1.0.0", "resolved": "https://forge.example/x.tgz", "integrity": "sha512-y",
"requires": {"left-pad": "^1.0.0"},
"dependencies": {"@novox/mesh-sdk": {"version": "0.1.0", "requires": {}}}}
}
},
"left-pad": {"version": "1.3.0", "dev": true},
"sdk": {"version": "npm:@novox/ui@2.0.1"},
"local": {"version": "file:../local", "requires": {"@novox/ui": "*"}}
}
}`
const lockV2 = `{
"name": "app", "version": "1.0.0", "lockfileVersion": 2, "requires": true,
"packages": {
"": {"name": "app", "version": "1.0.0", "dependencies": {"@novox/mesh-sdk": "^0.1.0"},
"devDependencies": {"@novox/ui": "~1.1.0"}, "engines": {"node": ">=20"}},
"node_modules/@novox/mesh-sdk": {"version": "0.1.3", "resolved": "https://forge.example/a.tgz",
"integrity": "sha512-a", "dependencies": {"left-pad": "^1.3.0"}, "peerDependencies": {"@novox/ui": "*"},
"optionalDependencies": {"fsevents": "^2"}, "bin": {"sdk": "bin/sdk.js"}, "engines": {"node": ">=18"}},
"node_modules/@novox/ui": {"version": "1.1.4", "dev": true, "funding": [{"type": "x", "url": "y"}]},
"node_modules/left-pad": {"version": "1.3.0"}
},
"dependencies": {
"@novox/mesh-sdk": {"version": "0.1.3", "requires": {"left-pad": "^1.3.0"}},
"@novox/ui": {"version": "1.1.4", "dev": true},
"left-pad": {"version": "1.3.0"}
}
}`
const lockV3 = `{
"name": "app", "version": "1.0.0", "lockfileVersion": 3, "requires": true,
"packages": {
"": {"name": "app", "workspaces": ["packages/*"], "dependencies": {"@novox/mesh-sdk": "^0.1.0", "sdk": "npm:@novox/ui@^2.0.0"}},
"node_modules/@novox/mesh-sdk": {"version": "0.1.5", "license": "MIT", "dependencies": {"@novox/ui": "^1.0.0"}},
"node_modules/@novox/ui": {"version": "1.0.9", "devDependencies": {"typescript": "^5"}},
"node_modules/a/node_modules/@novox/mesh-sdk": {"version": "0.1.1", "dependencies": {"left-pad": "1.x"}},
"node_modules/a/node_modules/b/node_modules/@novox/ui": {"version": "1.0.2"},
"node_modules/sdk": {"name": "@novox/ui", "version": "2.0.4", "resolved": "https://forge.example/u.tgz"},
"node_modules/@novox/workspace-thing": {"resolved": "packages/thing", "link": true},
"node_modules/@novox/linked": {"resolved": "packages/linked", "link": true, "version": "9.9.9"},
"packages/thing": {"name": "@novox/workspace-thing", "version": "0.0.1", "dependencies": {"@novox/ui": "^1.0.0"}},
"node_modules/left-pad": {"version": "1.3.0", "peerDependencies": {"x": "*"}, "optionalDependencies": {"y": "1"}}
}
}`
var knownLocks = map[string]bool{"@novox/mesh-sdk": true, "@novox/ui": true, "@novox/workspace-thing": true, "@novox/linked": true}
func TestALockfileVersion1NamesEveryNestedVersion(t *testing.T) {
got, err := ReadLock("package-lock.json", []byte(lockV1), "r", knownLocks)
if err != nil {
t.Fatal(err)
}
if pins(got) != "@novox/mesh-sdk@0.1.0 @novox/mesh-sdk@0.1.2 @novox/ui@1.0.0 @novox/ui@2.0.1" {
t.Fatalf("v1: %s", pins(got))
}
}
func TestALockfileVersion2ReadsBothHalves(t *testing.T) {
got, err := ReadLock("package-lock.json", []byte(lockV2), "r", knownLocks)
if err != nil {
t.Fatal(err)
}
// Each half names both; a version is kept once it is named, so naming it twice is harmless.
if pins(got) != "@novox/mesh-sdk@0.1.3 @novox/mesh-sdk@0.1.3 @novox/ui@1.1.4 @novox/ui@1.1.4" {
t.Fatalf("v2: %s", pins(got))
}
}
func TestALockfileVersion3ReadsPathsAliasesAndSkipsLinks(t *testing.T) {
got, err := ReadLock("package-lock.json", []byte(lockV3), "r", knownLocks)
if err != nil {
t.Fatal(err)
}
want := "@novox/mesh-sdk@0.1.1 @novox/mesh-sdk@0.1.5 @novox/ui@1.0.2 @novox/ui@1.0.9 @novox/ui@2.0.4"
if pins(got) != want {
t.Fatalf("v3: %s\nwant %s", pins(got), want)
}
}
func TestAnEntryOfAnUnknownShapeIsSaidAndTheRestIsRead(t *testing.T) {
lock := `{"lockfileVersion":3,"packages":{
"node_modules/@novox/ui":{"version":"1.0.0"},
"node_modules/@novox/mesh-sdk":{"version":{"odd":true}}},
"dependencies":{"@novox/ui":"not an object"}}`
got, err := ReadLock("package-lock.json", []byte(lock), "r", knownLocks)
if pins(got) != "@novox/ui@1.0.0" {
t.Fatalf("read %s", pins(got))
}
if err == nil || !strings.Contains(err.Error(), "2 entries not read") ||
!strings.Contains(err.Error(), `packages["node_modules/@novox/mesh-sdk"]`) {
t.Fatalf("got %v", err)
}
}
func mustYarn(t *testing.T, content string) []Pinned {
t.Helper()
out, err := readYarnLock([]byte(content), "r", knownHere)
if err != nil {
t.Fatal(err)
}
return out
}
// A yarn lockfile with a line longer than the scanner holds is an error, not a file read to its end.
func TestAYarnLockfileCutShortIsAnError(t *testing.T) {
long := "\"@novox/mesh-sdk@^0.1.0\":\n version \"0.1.4\"\n# " + strings.Repeat("x", 2<<20) + "\n\"@novox/ui@^2\":\n version \"2.0.7\"\n"
if _, err := readYarnLock([]byte(long), "r", knownHere); err == nil {
t.Fatal("a lockfile the scanner stopped in was read as whole")
}
}