def test_expr_validation_bad_set_attr() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ tags.anything }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'TagsCtx' has no attribute 'anything'"
def test_expr_validation_not_context_field() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ flow.foo }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'BatchFlowCtx' has no attribute 'foo'"
def test_expr_validation_bad_subcontext_lookup() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ needs.task.foo }}",
    )
    errors = validate_expr(expr, BatchTaskContext, known_needs={"task"})
    assert errors[0].args[0] == "'DepCtx' has no attribute 'foo'"
def test_expr_validation_unknown_context() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ something_new }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "Unknown context 'something_new'"
def test_expr_validation_ok_for_property_access() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ volumes.volume.ref_rw }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
def test_expr_validation_list_comp_ok() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ [x * x for x in range(5) ] }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
def test_expr_validation_ok() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ flow.flow_id }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
def test_expr_validation_set_indexing() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ tags['flow_id'] }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'TagsCtx' is not subscriptable"
def test_expr_validation_invalid_need() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ needs.fff }}",
    )
    errors = validate_expr(expr, BatchTaskContext, known_needs=set())
    assert errors[0].args[
        0] == "Task 'fff' is not available under needs context"
def test_expr_validation_invalid_input() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ inputs.fff }}",
    )
    errors = validate_expr(expr,
                           BatchActionContext[EmptyRoot],
                           known_inputs=set())
    assert errors[0].args[0] == "Input 'fff' is undefined"