# Copyright (c) 2017-2026 Juancarlo Añez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
"""
Unit tests for safe_eval using the 'check' naming convention.
Generated by Gemini on 2026-01-25.
"""

import ast

import pytest

from tatsu.util.safeeval import SecurityError, check_safe_eval, safe_eval


class MockObj:
    def __init__(self, val):
        self.val = val

    def do_it(self):
        return self.val


def test_simple_context_eval():
    context = {'a': 1, 'b': 2}
    expression = 'seen: {a} {b}'
    expected = "seen: 1 2"

    with pytest.raises(SecurityError, match='Invalid expression syntax'):
        safe_eval(expression, context)
        check_safe_eval(expression, context)
        result = safe_eval(expression, context)
        assert result == expected

    with pytest.raises(SyntaxError):
        result = ast.literal_eval(expression)  # Should not raise
        assert result == expected

    eval_expression = f'{"f" + repr(expression.strip())}'
    result = safe_eval(eval_expression, context)
    assert result == expected


def test_safe_eval_flow():
    ctx = {"MockObj": MockObj, "x": 10}
    assert safe_eval("MockObj(x).do_it()", ctx) == 10


def test_unauthorized_call():
    with pytest.raises(SecurityError, match="Unauthorized function call"):
        check_safe_eval("open('file.txt')", {"x": 1})


def test_dunder_block():
    with pytest.raises(SecurityError, match="Dunder access prohibited"):
        check_safe_eval("x.__class__", {"x": 1})


def test_name_mismatch():
    with pytest.raises(SecurityError, match="Context name mismatch"):
        check_safe_eval("fake_fn()", {"fake_fn": abs})  # abs.__name__ is 'abs'


def test_no_excetions_for_eval():
    class MyException(BaseException):
        pass

    context = {"MyException": MyException}
    with pytest.raises(SecurityError, match="Exception class forbidden at context"):
        check_safe_eval("1 + 1", context)
        safe_eval("1 + 1", context)


def test_bad_argcount():
    context = {'object': object, 'type': type}
    with pytest.raises(SecurityError, match="Bad argument count"):
        safe_eval("type('Evil', (object,), {})", context)
