X Tutup
# -*- coding: utf-8 -*- import ast import numbers from bpython.simpleeval import ( simple_eval, evaluate_current_expression, EvaluationError, safe_get_attribute, safe_get_attribute_new_style, ) from bpython.test import unittest from bpython._py3compat import py3 class TestSimpleEval(unittest.TestCase): def assertMatchesStdlib(self, expr): self.assertEqual(ast.literal_eval(expr), simple_eval(expr)) def test_matches_stdlib(self): """Should match the stdlib literal_eval if no names or indexing""" self.assertMatchesStdlib("[1]") self.assertMatchesStdlib("{(1,): [2,3,{}]}") def test_indexing(self): """Literals can be indexed into""" self.assertEqual(simple_eval("[1,2][0]"), 1) self.assertEqual(simple_eval("a", {"a": 1}), 1) def test_name_lookup(self): """Names can be lookup up in a namespace""" self.assertEqual(simple_eval("a", {"a": 1}), 1) self.assertEqual(simple_eval("map"), map) self.assertEqual(simple_eval("a[b]", {"a": {"c": 1}, "b": "c"}), 1) def test_allow_name_lookup(self): """Names can be lookup up in a namespace""" self.assertEqual(simple_eval("a", {"a": 1}), 1) def test_lookup_on_suspicious_types(self): class FakeDict(object): pass with self.assertRaises(ValueError): simple_eval("a[1]", {"a": FakeDict()}) class TrickyDict(dict): def __getitem__(self, index): self.fail("doing key lookup isn't safe") with self.assertRaises(ValueError): simple_eval("a[1]", {"a": TrickyDict()}) class SchrodingersDict(dict): def __getattribute__(inner_self, attr): self.fail("doing attribute lookup might have side effects") with self.assertRaises(ValueError): simple_eval("a[1]", {"a": SchrodingersDict()}) class SchrodingersCatsDict(dict): def __getattr__(inner_self, attr): self.fail("doing attribute lookup might have side effects") with self.assertRaises(ValueError): simple_eval("a[1]", {"a": SchrodingersDict()}) def test_operators_on_suspicious_types(self): class Spam(numbers.Number): def __add__(inner_self, other): self.fail("doing attribute lookup might have side effects") with self.assertRaises(ValueError): simple_eval("a + 1", {"a": Spam()}) def test_operators_on_numbers(self): self.assertEqual(simple_eval("-2"), -2) self.assertEqual(simple_eval("1 + 1"), 2) self.assertEqual(simple_eval("a - 2", {"a": 1}), -1) with self.assertRaises(ValueError): simple_eval("2 * 3") with self.assertRaises(ValueError): simple_eval("2 ** 3") def test_function_calls_raise(self): with self.assertRaises(ValueError): simple_eval("1()") def test_nonexistant_names_raise(self): with self.assertRaises(EvaluationError): simple_eval("a") def test_attribute_access(self): class Foo(object): abc = 1 self.assertEqual(simple_eval("foo.abc", {"foo": Foo()}), 1) class TestEvaluateCurrentExpression(unittest.TestCase): def assertEvaled(self, line, value, ns=None): assert line.count("|") == 1 cursor_offset = line.find("|") line = line.replace("|", "") self.assertEqual( evaluate_current_expression(cursor_offset, line, ns), value ) def assertCannotEval(self, line, ns=None): assert line.count("|") == 1 cursor_offset = line.find("|") line = line.replace("|", "") with self.assertRaises(EvaluationError): evaluate_current_expression(cursor_offset, line, ns) def test_simple(self): self.assertEvaled("[1].a|bc", [1]) self.assertEvaled("[1].abc|", [1]) self.assertEvaled("[1].|abc", [1]) self.assertEvaled("[1]. |abc", [1]) self.assertEvaled("[1] .|abc", [1]) self.assertCannotEval("[1].abc |", [1]) self.assertCannotEval("[1]. abc |", [1]) self.assertCannotEval("[2][1].a|bc", [1]) def test_nonsense(self): self.assertEvaled("!@#$ [1].a|bc", [1]) self.assertEvaled("--- [2][0].a|bc", 2) self.assertCannotEval('"asdf".centered()[1].a|bc') self.assertEvaled('"asdf"[1].a|bc', "s") def test_with_namespace(self): self.assertEvaled("a[1].a|bc", "d", {"a": "adsf"}) self.assertCannotEval("a[1].a|bc", {}) class A(object): a = "a" class B(A): b = "b" class Property(object): @property def prop(self): raise AssertionError("Property __get__ executed") class Slots(object): __slots__ = ["s1", "s2", "s3"] if not py3: @property def s3(self): raise AssertionError("Property __get__ executed") class SlotsSubclass(Slots): @property def s4(self): raise AssertionError("Property __get__ executed") class OverriddenGetattr(object): def __getattr__(self, attr): raise AssertionError("custom __getattr__ executed") a = 1 class OverriddenGetattribute(object): def __getattribute__(self, attr): raise AssertionError("custom __getattribute__ executed") a = 1 class OverriddenMRO(object): def __mro__(self): raise AssertionError("custom mro executed") a = 1 member_descriptor = type(Slots.s1) class TestSafeGetAttribute(unittest.TestCase): def test_lookup_on_object(self): a = A() a.x = 1 self.assertEqual(safe_get_attribute_new_style(a, "x"), 1) self.assertEqual(safe_get_attribute_new_style(a, "a"), "a") b = B() b.y = 2 self.assertEqual(safe_get_attribute_new_style(b, "y"), 2) self.assertEqual(safe_get_attribute_new_style(b, "a"), "a") self.assertEqual(safe_get_attribute_new_style(b, "b"), "b") def test_avoid_running_properties(self): p = Property() self.assertEqual(safe_get_attribute_new_style(p, "prop"), Property.prop) @unittest.skipIf(py3, "Old-style classes not in Python 3") def test_raises_on_old_style_class(self): class Old: pass with self.assertRaises(ValueError): safe_get_attribute_new_style(Old, "asdf") def test_lookup_with_slots(self): s = Slots() s.s1 = "s1" self.assertEqual(safe_get_attribute(s, "s1"), "s1") self.assertIsInstance( safe_get_attribute_new_style(s, "s1"), member_descriptor ) with self.assertRaises(AttributeError): safe_get_attribute(s, "s2") self.assertIsInstance( safe_get_attribute_new_style(s, "s2"), member_descriptor ) def test_lookup_on_slots_classes(self): sga = safe_get_attribute s = SlotsSubclass() self.assertIsInstance(sga(Slots, "s1"), member_descriptor) self.assertIsInstance(sga(SlotsSubclass, "s1"), member_descriptor) self.assertIsInstance(sga(SlotsSubclass, "s4"), property) self.assertIsInstance(sga(s, "s4"), property) @unittest.skipIf(py3, "Py 3 doesn't allow slots and prop in same class") def test_lookup_with_property_and_slots(self): sga = safe_get_attribute s = SlotsSubclass() self.assertIsInstance(sga(Slots, "s3"), property) self.assertEqual(safe_get_attribute(s, "s3"), Slots.__dict__["s3"]) self.assertIsInstance(sga(SlotsSubclass, "s3"), property) def test_lookup_on_overridden_methods(self): sga = safe_get_attribute self.assertEqual(sga(OverriddenGetattr(), "a"), 1) self.assertEqual(sga(OverriddenGetattribute(), "a"), 1) self.assertEqual(sga(OverriddenMRO(), "a"), 1) with self.assertRaises(AttributeError): sga(OverriddenGetattr(), "b") with self.assertRaises(AttributeError): sga(OverriddenGetattribute(), "b") with self.assertRaises(AttributeError): sga(OverriddenMRO(), "b") if __name__ == "__main__": unittest.main()
X Tutup