Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 07:39:19 -05:00
pkg-proxy/internal/jsonscan/jsonscan_test.go
Andrew Nesbitt 8ed0edb90a Extract portable npm metadata transformations
npm metadata rewriting depended on handler.Proxy, which pulls SQL
drivers, cloud SDKs and metrics into its import graph. Move the
transformation into internal/metadata/npm with explicit policy,
evaluation time, public URL and hosted-version inputs, and share the
JSON scanner between npm and Composer through internal/jsonscan.

Rebased onto main: rewritten tarball URLs are still logged once per
document, now through an OnTarballsRewritten callback that reports the
count.
2026-10-25 22:21:37 +01:00

155 lines
4.8 KiB
Go

package jsonscan
import (
"bytes"
"errors"
"testing"
)
func TestLookupJSONString(t *testing.T) {
doc := []byte(`{
"name": "demo",
"versions": {
"1.0.0": {"dist": {"tarball": "https://example.com/a.tgz", "shasum": "x"}},
"2.0.0": {"readme": "a } tricky \" string ] with {brackets}", "dist": {"tarball": "https://example.com/b.tgz"}},
"3.0.0": "not an object",
"4.0.0": {"dist": {"tarball": 42}}
},
"time": {"1.0.0": "2020-01-01T00:00:00Z", "1.0.0": "2021-01-01T00:00:00Z"},
"n": -1.5e3, "t": true, "z": null, "list": [1, {"a": []}, "]"]
}`)
cases := []struct {
path []string
want string
wantOK bool
}{
{[]string{"versions", "1.0.0", "dist", "tarball"}, "https://example.com/a.tgz", true},
{[]string{"versions", "2.0.0", "dist", "tarball"}, "https://example.com/b.tgz", true},
{[]string{"versions", "3.0.0", "dist", "tarball"}, "", false},
{[]string{"versions", "4.0.0", "dist", "tarball"}, "", false},
{[]string{"versions", "9.9.9", "dist", "tarball"}, "", false},
{[]string{"time", "1.0.0"}, "2021-01-01T00:00:00Z", true}, // last duplicate wins
{[]string{"name"}, "demo", true},
{[]string{"name", "x"}, "", false},
}
for _, c := range cases {
got, ok, err := LookupString(doc, c.path...)
if err != nil || ok != c.wantOK || got != c.want {
t.Errorf("lookup %v = %q, %v, %v; want %q, %v", c.path, got, ok, err, c.want, c.wantOK)
}
}
}
func TestLookupJSONEscapedKey(t *testing.T) {
doc := []byte(`{"versions": {"1.0.0": {"dist": {"tarball": "u"}}}}`)
got, ok, err := LookupString(doc, "versions", "1.0.0", "dist", "tarball")
if err != nil || !ok || got != "u" {
t.Errorf("lookup = %q, %v, %v", got, ok, err)
}
}
func TestLookupJSONMalformed(t *testing.T) {
for _, doc := range []string{
`{"versions": {"1.0.0": {"dist": `,
`{"versions" {}}`,
`{"versions": {"a": 1 "b": 2}}`,
`{"a": "unterminated}`,
`{"a": [1, 2}`,
} {
_, _, err := LookupString([]byte(doc), "versions", "1.0.0", "dist", "tarball")
if !errors.Is(err, ErrMalformed) {
t.Errorf("%s: err = %v, want ErrMalformed", doc, err)
}
}
}
func TestForEachJSONMemberOffsets(t *testing.T) {
doc := []byte(` { "a" : 1 , "b":{"c":[true,null]} ,"d":"x\"y" } `)
var got [][2]string
err := EachMember(doc, func(m Member) error {
got = append(got, [2]string{string(m.Key(doc)), string(m.Value(doc))})
return nil
})
want := [][2]string{{`"a"`, `1`}, {`"b"`, `{"c":[true,null]}`}, {`"d"`, `"x\"y"`}}
if err != nil || len(got) != len(want) {
t.Fatalf("members = %v, %v", got, err)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("member %d = %v, want %v", i, got[i], want[i])
}
}
if err := EachMember([]byte(`[1]`), func(Member) error { return nil }); !errors.Is(err, ErrNotObject) {
t.Errorf("array: err = %v, want ErrNotObject", err)
}
if err := EachMember([]byte(`{}`), func(Member) error { t.Error("called for empty object"); return nil }); err != nil {
t.Errorf("empty object: err = %v", err)
}
}
func TestWriteFilteredJSONObject(t *testing.T) {
var out bytes.Buffer
err := WriteFilteredObject(&out, []byte(`{"a": 1, "b": {"x": 2}, "c": 3}`), func(k string) bool { return k != "b" }, nil)
if err != nil || out.String() != `{"a": 1,"c": 3}` {
t.Errorf("filtered = %s, %v", out.String(), err)
}
}
func TestForEachJSONElement(t *testing.T) {
var got []string
err := EachElement([]byte(` [ 1, "a,]", {"b": [2]} ,[] ] `), func(e []byte) error {
got = append(got, string(e))
return nil
})
want := []string{`1`, `"a,]"`, `{"b": [2]}`, `[]`}
if err != nil || len(got) != len(want) {
t.Fatalf("elements = %q, %v; want %q", got, err, want)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("element %d = %s, want %s", i, got[i], want[i])
}
}
if err := EachElement([]byte(`[]`), func([]byte) error { t.Error("called for empty array"); return nil }); err != nil {
t.Errorf("empty array: err = %v", err)
}
for _, bad := range []string{`{}`, `[1,`, `[1 2]`, `[1`} {
if err := EachElement([]byte(bad), func([]byte) error { return nil }); err == nil {
t.Errorf("%s: expected an error", bad)
}
}
}
func TestRewriteJSONMembers(t *testing.T) {
obj := []byte(`{ "a": 1, "b": [2], "c" : 3 }`)
var out bytes.Buffer
err := RewriteMembers(&out, obj, func(out *bytes.Buffer, m Member) (bool, error) {
if !KeyIs(m.Key(obj), "b") {
return false, nil
}
out.WriteString(`"B"`)
return true, nil
})
if want := `{ "a": 1, "b": "B", "c" : 3 }`; err != nil || out.String() != want {
t.Errorf("rewritten = %s, %v; want %s", out.String(), err, want)
}
}
func TestJSONStringIs(t *testing.T) {
for raw, want := range map[string]bool{
`"~dev"`: true,
`"~\u0064ev"`: true,
`"~dev2"`: false,
`{"~dev":1}`: false,
`"`: false,
``: false,
`["~dev"]`: false,
} {
if got := StringIs([]byte(raw), "~dev"); got != want {
t.Errorf("StringIs(%s) = %v, want %v", raw, got, want)
}
}
}