(t *testing.T)
| 267 | } |
| 268 | |
| 269 | func TestExceedsDepthBoundedTraversal(t *testing.T) { |
| 270 | // Build a synthetic AST nested far deeper than the parser's recursion limit would ever produce. |
| 271 | // This is exactly the shape ExceedsDepth guards against, since such an AST can only enter through |
| 272 | // proto loading rather than the parser. Stacking depth unary '!' calls on a literal places the |
| 273 | // deepest node (the literal) at NavigableExpr.Depth() == depth. |
| 274 | const depth = 300 |
| 275 | fac := ast.NewExprFactory() |
| 276 | expr := fac.NewLiteral(1, types.Bool(true)) |
| 277 | for i := 0; i < depth; i++ { |
| 278 | expr = fac.NewCall(int64(i+2), operators.LogicalNot, expr) |
| 279 | } |
| 280 | deep := ast.NewAST(expr, ast.NewSourceInfo(nil)) |
| 281 | |
| 282 | tests := []struct { |
| 283 | name string |
| 284 | maxDepth int |
| 285 | want bool |
| 286 | }{ |
| 287 | {name: "below the deepest node", maxDepth: 250, want: true}, |
| 288 | // The traversal is bounded to maxDepth+1 levels, so it must still descend far enough to |
| 289 | // observe a node sitting exactly at maxDepth. |
| 290 | {name: "equal to the deepest node", maxDepth: depth, want: true}, |
| 291 | {name: "one past the deepest node", maxDepth: depth + 1, want: false}, |
| 292 | {name: "check disabled", maxDepth: 0, want: false}, |
| 293 | } |
| 294 | for _, tst := range tests { |
| 295 | tc := tst |
| 296 | t.Run(tc.name, func(t *testing.T) { |
| 297 | if got := ast.ExceedsDepth(deep, tc.maxDepth); got != tc.want { |
| 298 | t.Errorf("ExceedsDepth(deepAST(%d), %d) = %v, wanted %v", depth, tc.maxDepth, got, tc.want) |
| 299 | } |
| 300 | }) |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | func TestNavigableASTNilSafety(t *testing.T) { |
| 305 | tests := []struct { |
nothing calls this directly
no test coverage detected