mirror of
https://github.com/github/codeql.git
synced 2026-05-14 11:19:27 +02:00
These tests consist of various Python constructions (hopefully a somewhat comprehensive set) with specific timestamp annotations scattered throughout. When the tests are run using the Python 3 interpreter, these annotations are checked and compared to the "current timestamp" to see that they are in agreement. This is what makes the tests "self-validating". There are a few different kinds of annotations: the basic `t[4]` style (meaning this is executed at timestamp 4), the `t[dead(4)]` variant (meaning this _would_ happen at timestamp 4, but it is in a dead branch), and `t[never]` (meaning this is never executed at all). In addition to this, there is a query, MissingAnnotations, which checks whether we have applied these annotations maximally. Many expression nodes are not actually annotatable, so there is a sizeable list of excluded nodes for that query.
75 lines
1.9 KiB
Python
75 lines
1.9 KiB
Python
"""Class definitions — evaluation order."""
|
|
|
|
from timer import test
|
|
|
|
|
|
@test
|
|
def test_simple_class(t):
|
|
"""Simple class definition and instantiation."""
|
|
class Foo:
|
|
pass
|
|
obj = (Foo @ t[0])() @ t[1]
|
|
|
|
|
|
@test
|
|
def test_class_with_bases(t):
|
|
"""Base class expressions evaluated at class definition time."""
|
|
class Base:
|
|
pass
|
|
class Derived(Base @ t[0]):
|
|
pass
|
|
obj = (Derived @ t[1])() @ t[2]
|
|
|
|
|
|
@test
|
|
def test_class_with_methods(t):
|
|
"""Object evaluated before method is called."""
|
|
class Foo:
|
|
def greet(self, name):
|
|
return ("hello " @ t[5] + name @ t[6]) @ t[7]
|
|
obj = (Foo @ t[0])() @ t[1]
|
|
msg = ((obj @ t[2]).greet @ t[3])("world" @ t[4]) @ t[8]
|
|
|
|
|
|
@test
|
|
def test_class_instantiation(t):
|
|
"""Arguments to __init__ evaluate before instantiation completes."""
|
|
class Foo:
|
|
def __init__(self, x):
|
|
(self @ t[3]).x = x @ t[2]
|
|
obj = (Foo @ t[0])(42 @ t[1]) @ t[4]
|
|
val = (obj @ t[5]).x @ t[6]
|
|
|
|
|
|
@test
|
|
def test_method_call(t):
|
|
"""Method arguments evaluate left-to-right before the call."""
|
|
class Calculator:
|
|
def __init__(self, value):
|
|
(self @ t[3]).value = value @ t[2]
|
|
def add(self, x):
|
|
return ((self @ t[8]).value @ t[9] + x @ t[10]) @ t[11]
|
|
calc = (Calculator @ t[0])(10 @ t[1]) @ t[4]
|
|
result = ((calc @ t[5]).add @ t[6])(5 @ t[7]) @ t[12]
|
|
|
|
|
|
@test
|
|
def test_class_level_attribute(t):
|
|
"""Multiple attribute accesses in a single expression."""
|
|
class Config:
|
|
debug = True @ t[0]
|
|
version = 1 @ t[1]
|
|
x = ((Config @ t[2]).debug @ t[3], (Config @ t[4]).version @ t[5]) @ t[6]
|
|
|
|
|
|
@test
|
|
def test_class_decorator(t):
|
|
"""Decorator expression evaluated, class defined, then decorator called."""
|
|
def add_marker(cls):
|
|
(cls @ t[2]).marked = True @ t[1]
|
|
return cls @ t[3]
|
|
@(add_marker @ t[0])
|
|
class Foo:
|
|
pass
|
|
result = (Foo @ t[4]).marked @ t[5]
|