Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

179 lines
5.1 KiB
Go

package contracts
import (
"testing"
)
// TestExtractFirstCallArg covers the call-site-parsing contract every
// other piece of wrapper inlining relies on. If this goes wrong then
// InlineWrappers silently skips real callers or emits nonsense
// contracts — both failure modes are invisible in end-to-end tests
// until they corrupt match counts, so it's worth exhaustively
// specifying the allowed inputs here.
func TestExtractFirstCallArg(t *testing.T) {
tests := []struct {
name string
src string
line int
wrapper string
lang string
wantKind argKind
wantValue string
wantMethod string
}{
{
name: "string literal",
src: "function f() {\n return request('/v1/users', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/users",
},
{
name: "template literal with param",
src: "function f() {\n return request(`/v1/users/${id}`, getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/users/${id}",
},
{
name: "string literal + object method",
src: "function f() {\n return request('/v1/tucks', getToken, {method: 'POST', body: JSON.stringify(d)});\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/tucks",
wantMethod: "POST",
},
{
name: "double-quoted method with backticks in wrapper",
src: "function f() {\n return request(`/v1/tucks/${id}`, getToken, { method: \"PATCH\" });\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/tucks/${id}",
wantMethod: "PATCH",
},
{
name: "bare parameter identifier",
src: "function doFetch(path, token) {\n return fetch(path, opts);\n}\n",
line: 2,
wrapper: "fetch",
lang: "javascript",
wantKind: argBareParam,
},
{
name: "pure interpolation template — wrapper forwarding",
src: "function f(url) {\n return request(`${url}`, getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argBareParam,
},
{
name: "generic type params on TS wrapper",
src: "function f() {\n return request<User>('/v1/me', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/me",
},
{
name: "runtime expression — not a literal, not a bare ident",
src: "function f() {\n return request(buildPath() + '/v1/x', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argUnknown,
},
{
name: "go-ish call with nested map options",
src: "func f() {\n\treturn request(\"/v1/tucks\", token, map[string]any{\"method\": \"DELETE\"})\n}\n",
line: 2,
wrapper: "request",
lang: "go",
wantKind: argLiteral,
wantValue: "/v1/tucks",
wantMethod: "DELETE",
},
{
name: "multi-line call spanning across object-literal body",
src: "function f() {\n return request('/v1/tucks', getToken, {\n method: 'POST',\n body: JSON.stringify(data),\n });\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argLiteral,
wantValue: "/v1/tucks",
wantMethod: "POST",
},
{
name: "wrapper name not on the target line",
src: "function f() {\n const x = 1;\n return request('/v1/users', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argUnknown,
},
{
name: "different function name on the line",
src: "function f() {\n return callApi('/v1/users', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argUnknown,
},
{
name: "word-boundary — xrequest should not match request",
src: "function f() {\n return xrequest('/v1/users', getToken);\n}\n",
line: 2,
wrapper: "request",
lang: "typescript",
wantKind: argUnknown,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractFirstCallArg([]byte(tt.src), tt.line, tt.wrapper, tt.lang)
if got.Kind != tt.wantKind {
t.Errorf("Kind: want %v, got %v", tt.wantKind, got.Kind)
}
if tt.wantKind == argLiteral && got.Value != tt.wantValue {
t.Errorf("Value: want %q, got %q", tt.wantValue, got.Value)
}
if got.Method != tt.wantMethod {
t.Errorf("Method: want %q, got %q", tt.wantMethod, got.Method)
}
})
}
}
func TestIsWrapperPath(t *testing.T) {
tests := []struct {
path string
want bool
}{
{"/{path}", true},
{"/{url}", true},
{"/{endpoint}", true},
{"/path", true},
{"/url", true},
{"/v1/tucks", false},
{"/v1/tucks/{id}", false},
{"/", false},
{"", false},
{"/{id}/suffix", false},
}
for _, tt := range tests {
if got := isWrapperPath(tt.path); got != tt.want {
t.Errorf("isWrapperPath(%q) = %v, want %v", tt.path, got, tt.want)
}
}
}