chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package languages
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
)
|
||||
|
||||
// Helper: return all EdgeThrows targets in the result, deduped.
|
||||
func tsThrowsTargets(edges []*graph.Edge) []string {
|
||||
seen := map[string]bool{}
|
||||
var out []string
|
||||
for _, e := range edges {
|
||||
if e.Kind != graph.EdgeThrows {
|
||||
continue
|
||||
}
|
||||
if seen[e.To] {
|
||||
continue
|
||||
}
|
||||
seen[e.To] = true
|
||||
out = append(out, e.To)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestTSThrows_NewExpression(t *testing.T) {
|
||||
src := `function validate(x: number): void {
|
||||
if (x < 0) {
|
||||
throw new RangeError("negative");
|
||||
}
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/v.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
want := []string{"unresolved::RangeError"}
|
||||
if len(targets) != 1 || targets[0] != want[0] {
|
||||
t.Errorf("got %v, want %v", targets, want)
|
||||
}
|
||||
// Origin should be ASTInferred (TS doesn't enforce checked exceptions).
|
||||
for _, e := range edges {
|
||||
if e.Kind == graph.EdgeThrows && e.Origin != graph.OriginASTInferred {
|
||||
t.Errorf("EdgeThrows origin = %q, want ast_inferred", e.Origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_BareIdentifier(t *testing.T) {
|
||||
src := `function rethrow(err: Error): never {
|
||||
throw err;
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/r.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 1 || targets[0] != "unresolved::err" {
|
||||
t.Errorf("got %v, want [unresolved::err]", targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_NamespacedConstructor(t *testing.T) {
|
||||
src := `function load(): void {
|
||||
throw new errors.NotFoundError("missing");
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/n.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 1 || targets[0] != "unresolved::NotFoundError" {
|
||||
t.Errorf("got %v, want [unresolved::NotFoundError]", targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_MemberExpression(t *testing.T) {
|
||||
src := `function fail(kind: string): void {
|
||||
throw errors.kinds.MyError;
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/m.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 1 || targets[0] != "unresolved::MyError" {
|
||||
t.Errorf("got %v, want [unresolved::MyError]", targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_StringLiteralSkipped(t *testing.T) {
|
||||
src := `function bad(): void {
|
||||
throw "oops";
|
||||
throw 42;
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/s.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 0 {
|
||||
t.Errorf("string/numeric throws should NOT emit edges; got %v", targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_DedupesPerFunction(t *testing.T) {
|
||||
src := `function many(): void {
|
||||
if (1) throw new MyError("a");
|
||||
if (2) throw new MyError("b");
|
||||
if (3) throw new MyError("c");
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/d.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 1 {
|
||||
t.Errorf("expected one deduped target, got %d (%v)", len(targets), targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTSThrows_MultipleDistinctTypes(t *testing.T) {
|
||||
src := `function many(): void {
|
||||
throw new TypeError("a");
|
||||
throw new RangeError("b");
|
||||
throw new MyCustomError("c");
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/multi.ts", src)
|
||||
targets := tsThrowsTargets(edges)
|
||||
if len(targets) != 3 {
|
||||
t.Errorf("expected 3 distinct targets, got %d (%v)", len(targets), targets)
|
||||
}
|
||||
}
|
||||
|
||||
// Nested function bodies should NOT contribute their throws to the
|
||||
// outer function — they're emitted against the nested function's own
|
||||
// ID via its own emitFunction call.
|
||||
func TestTSThrows_SkipsNestedFunctionScope(t *testing.T) {
|
||||
src := `function outer(): void {
|
||||
throw new OuterError("a");
|
||||
function inner(): void {
|
||||
throw new InnerError("b");
|
||||
}
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/nest.ts", src)
|
||||
// outer should see only OuterError; inner should see only InnerError.
|
||||
outerEdges := []string{}
|
||||
innerEdges := []string{}
|
||||
for _, e := range edges {
|
||||
if e.Kind != graph.EdgeThrows {
|
||||
continue
|
||||
}
|
||||
switch e.From {
|
||||
case "src/nest.ts::outer":
|
||||
outerEdges = append(outerEdges, e.To)
|
||||
case "src/nest.ts::inner":
|
||||
innerEdges = append(innerEdges, e.To)
|
||||
}
|
||||
}
|
||||
if len(outerEdges) != 1 || outerEdges[0] != "unresolved::OuterError" {
|
||||
t.Errorf("outer throws = %v, want [unresolved::OuterError]", outerEdges)
|
||||
}
|
||||
if len(innerEdges) != 1 || innerEdges[0] != "unresolved::InnerError" {
|
||||
t.Errorf("inner throws = %v, want [unresolved::InnerError]", innerEdges)
|
||||
}
|
||||
}
|
||||
|
||||
// Arrow-function bodies inside a method don't leak their throws to
|
||||
// the enclosing method.
|
||||
func TestTSThrows_SkipsArrowFunctionScope(t *testing.T) {
|
||||
src := `class S {
|
||||
handle(): void {
|
||||
throw new HandleError("a");
|
||||
const cb = (): void => { throw new CbError("b"); };
|
||||
cb();
|
||||
}
|
||||
}
|
||||
`
|
||||
_, edges := runTSExtract(t, "src/cls.ts", src)
|
||||
for _, e := range edges {
|
||||
if e.Kind != graph.EdgeThrows {
|
||||
continue
|
||||
}
|
||||
// The method's throws should NOT include CbError.
|
||||
if e.From == "src/cls.ts::S.handle" && e.To == "unresolved::CbError" {
|
||||
t.Errorf("method.handle should NOT see arrow's CbError")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user