Skip to content

Commit 77ce646

Browse files
authored
[mypyc] Fail run test if default driver does not find test cases (#19420)
If a `run-` test doesn't define a custom `driver.py`, the default one looks for functions prefixed `test_` and calls them. If the prefix is missing or misspelled, or there is some other issue that causes the test to have no test cases, the test succeeds without running the cases. To try to prevent this, the default driver will now fail if it doesn't find any test cases. Existing tests are changed to conform to this requirement in this PR. For most tests that meant simply moving the statements from top level to a function, but some were revealed to have been broken and weren't actually run, for example because `[typing fixtures/typing-full.pyi]` was at the top of the test instead of at the bottom, which made the test setup code ignore all of the test case.
1 parent a794ae3 commit 77ce646

14 files changed

+167
-118
lines changed

mypyc/test-data/driver/driver.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import native
1212

1313
failures = []
14+
tests_run = 0
1415

1516
for name in dir(native):
1617
if name.startswith('test_'):
1718
test_func = getattr(native, name)
19+
tests_run += 1
1820
try:
1921
test_func()
2022
except Exception as e:
@@ -46,3 +48,5 @@ def extract_line(tb):
4648
print(f'<< {failures[-1][0]} >>')
4749
sys.stdout.flush()
4850
raise failures[-1][1][1]
51+
52+
assert tests_run > 0, 'Default test driver did not find any functions prefixed "test_" to run.'

mypyc/test-data/fixtures/ir.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,12 @@ class GeneratorExit(BaseException): pass
350350

351351
def any(i: Iterable[_T]) -> bool: pass
352352
def all(i: Iterable[_T]) -> bool: pass
353-
def sum(i: Iterable[_T]) -> int: pass
353+
@overload
354+
def sum(i: Iterable[bool]) -> int: pass
355+
@overload
356+
def sum(i: Iterable[_T]) -> _T: pass
357+
@overload
358+
def sum(i: Iterable[_T], start: _T) -> _T: pass
354359
def reversed(object: Sequence[_T]) -> Iterator[_T]: ...
355360
def id(o: object) -> int: pass
356361
# This type is obviously wrong but the test stubs don't have Sized anymore

mypyc/test-data/run-bools.test

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ def test_mixed_comparisons_i64() -> None:
223223
assert gt_mixed_i64(n, x) == (n > int(x))
224224

225225
[case testBoolMixInt]
226-
y = False
227-
print((y or 0) and True)
226+
def test_mix() -> None:
227+
y = False
228+
print((y or 0) and True)
228229
[out]
229230
0

mypyc/test-data/run-bytes.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ class bytes_subclass(bytes):
277277
return b'spook'
278278

279279
[case testBytesFormatting]
280-
[typing fixtures/typing-full.pyi]
281280
from testutil import assertRaises
282281

283282
# https://www.python.org/dev/peps/pep-0461/
@@ -314,6 +313,7 @@ def test_bytes_formatting_2() -> None:
314313
aa = b'\xe4\xbd\xa0\xe5\xa5\xbd%b' % b'\xe4\xbd\xa0\xe5\xa5\xbd'
315314
assert aa == b'\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd'
316315
assert aa.decode() == '你好你好'
316+
[typing fixtures/typing-full.pyi]
317317

318318

319319
class A:

mypyc/test-data/run-classes.test

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,9 +1278,10 @@ class Bar(Foo):
12781278
def f(self, *args: int, **kwargs: int) -> None:
12791279
print("stuff", args, kwargs)
12801280

1281-
z: Foo = Bar()
1282-
z.f(1, z=50)
1283-
z.f()
1281+
def test_override() -> None:
1282+
z: Foo = Bar()
1283+
z.f(1, z=50)
1284+
z.f()
12841285

12851286
[out]
12861287
stuff (1,) {'z': 50}
@@ -1300,18 +1301,19 @@ class Foo:
13001301
def baz_f(self: Any, *args: int, **kwargs: int) -> None:
13011302
print("Baz", args, kwargs)
13021303

1303-
# Make an "interpreted" subtype of Foo
1304-
type2: Any = type
1305-
Bar = type2('Bar', (Foo,), {})
1306-
Baz = type2('Baz', (Foo,), {'f': baz_f})
1304+
def test_override() -> None:
1305+
# Make an "interpreted" subtype of Foo
1306+
type2: Any = type
1307+
Bar = type2('Bar', (Foo,), {})
1308+
Baz = type2('Baz', (Foo,), {'f': baz_f})
13071309

1308-
y: Foo = Bar()
1309-
y.f(1, z=2)
1310-
y.f()
1310+
y: Foo = Bar()
1311+
y.f(1, z=2)
1312+
y.f()
13111313

1312-
z: Foo = Baz()
1313-
z.f(1, z=2)
1314-
z.f()
1314+
z: Foo = Baz()
1315+
z.f(1, z=2)
1316+
z.f()
13151317

13161318
[out]
13171319
Foo 1 2
@@ -1330,9 +1332,10 @@ class Bar(Foo):
13301332
def f(self, x: Optional[int]=None) -> None:
13311333
print(x)
13321334

1333-
z: Foo = Bar()
1334-
z.f(1)
1335-
z.f()
1335+
def test_override() -> None:
1336+
z: Foo = Bar()
1337+
z.f(1)
1338+
z.f()
13361339

13371340
[out]
13381341
1
@@ -1349,10 +1352,11 @@ class Bar(Foo):
13491352
def f(self, *args: int, **kwargs: int) -> None:
13501353
print("Bar", args, kwargs)
13511354

1352-
z: Foo = Bar()
1353-
z.f(1, z=2)
1354-
z.f(1, 2, 3)
1355-
# z.f(x=5) # Not tested because we (knowingly) do the wrong thing and pass it as positional
1355+
def test_override() -> None:
1356+
z: Foo = Bar()
1357+
z.f(1, z=2)
1358+
z.f(1, 2, 3)
1359+
# z.f(x=5) # Not tested because we (knowingly) do the wrong thing and pass it as positional
13561360

13571361
[out]
13581362
Bar (1,) {'z': 2}
@@ -1370,10 +1374,11 @@ class Bar(Foo):
13701374
def f(self, x: int = 10, *args: int, **kwargs: int) -> None:
13711375
print("Bar", x, args, kwargs)
13721376

1373-
z: Foo = Bar()
1374-
z.f(1, z=2)
1375-
z.f(1, 2, 3)
1376-
z.f()
1377+
def test_override() -> None:
1378+
z: Foo = Bar()
1379+
z.f(1, z=2)
1380+
z.f(1, 2, 3)
1381+
z.f()
13771382

13781383
[out]
13791384
Bar 1 () {'z': 2}
@@ -1397,18 +1402,19 @@ class Foo:
13971402
def baz_f(self, a: int=30, y: int=50) -> None:
13981403
print("Baz", a, y)
13991404

1400-
# Make an "interpreted" subtype of Foo
1401-
type2: Any = type
1402-
Baz = type2('Baz', (Foo,), {'f': baz_f})
1405+
def test_override() -> None:
1406+
# Make an "interpreted" subtype of Foo
1407+
type2: Any = type
1408+
Baz = type2('Baz', (Foo,), {'f': baz_f})
14031409

1404-
z: Foo = Baz()
1405-
z.f()
1406-
z.f(y=1)
1407-
z.f(1, 2)
1408-
# Not tested because we don't (and probably won't) match cpython here
1409-
# from testutil import assertRaises
1410-
# with assertRaises(TypeError):
1411-
# z.f(x=7)
1410+
z: Foo = Baz()
1411+
z.f()
1412+
z.f(y=1)
1413+
z.f(1, 2)
1414+
# Not tested because we don't (and probably won't) match cpython here
1415+
# from testutil import assertRaises
1416+
# with assertRaises(TypeError):
1417+
# z.f(x=7)
14121418

14131419
[out]
14141420
Baz 30 50
@@ -2591,7 +2597,8 @@ class Base:
25912597
class Derived(Base):
25922598
pass
25932599

2594-
assert Derived()() == 1
2600+
def test_inherited() -> None:
2601+
assert Derived()() == 1
25952602

25962603
[case testClassWithFinalAttribute]
25972604
from typing import Final

mypyc/test-data/run-dunders-special.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ class UsesNotImplemented:
66
def __eq__(self, b: object) -> bool:
77
return NotImplemented
88

9-
assert UsesNotImplemented() != object()
9+
def test_not_implemented() -> None:
10+
assert UsesNotImplemented() != object()

mypyc/test-data/run-functions.test

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,13 +1235,11 @@ from contextlib import contextmanager
12351235
def f() -> Iterator[None]:
12361236
yield
12371237

1238-
def g() -> None:
1238+
def test_special_case() -> None:
12391239
a = ['']
12401240
with f():
12411241
a.pop()
12421242

1243-
g()
1244-
12451243
[case testUnpackKwargsCompiled]
12461244
from typing import TypedDict
12471245
from typing_extensions import Unpack
@@ -1253,8 +1251,9 @@ class Person(TypedDict):
12531251
def foo(**kwargs: Unpack[Person]) -> None:
12541252
print(kwargs["name"])
12551253

1256-
# This is not really supported yet, just test that we behave reasonably.
1257-
foo(name='Jennifer', age=38)
1254+
def test_unpack() -> None:
1255+
# This is not really supported yet, just test that we behave reasonably.
1256+
foo(name='Jennifer', age=38)
12581257
[typing fixtures/typing-full.pyi]
12591258
[out]
12601259
Jennifer
@@ -1269,8 +1268,9 @@ def foo() -> None:
12691268
print(inner.__dict__) # type: ignore[attr-defined]
12701269
print(inner.x) # type: ignore[attr-defined]
12711270

1272-
if sys.version_info >= (3, 12): # type: ignore
1273-
foo()
1271+
def test_nested() -> None:
1272+
if sys.version_info >= (3, 12): # type: ignore
1273+
foo()
12741274
[out]
12751275
[out version>=3.12]
12761276
{}
@@ -1285,7 +1285,8 @@ def bar() -> None:
12851285
functools.update_wrapper(inner, bar) # type: ignore
12861286
print(inner.__dict__) # type: ignore
12871287

1288-
bar()
1288+
def test_update() -> None:
1289+
bar()
12891290
[typing fixtures/typing-full.pyi]
12901291
[out]
12911292
{'__module__': 'native', '__name__': 'bar', '__qualname__': 'bar', '__doc__': None, '__wrapped__': <built-in function bar>}

mypyc/test-data/run-generators.test

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,16 +617,22 @@ else:
617617
from typing import Iterator
618618

619619
class Foo:
620-
flag: bool
620+
flag = False
621621

622622
class C:
623-
foo: Foo
623+
foo = Foo()
624624

625625
def genf(self) -> Iterator[None]:
626626
self.foo.flag = True
627627
yield
628628
self.foo.flag = False
629629

630+
def test_near_yield() -> None:
631+
c = C()
632+
for x in c.genf():
633+
pass
634+
assert c.foo.flag == False
635+
630636
[case testGeneratorEarlyReturnWithBorrows]
631637
from typing import Iterator
632638
class Bar:
@@ -639,6 +645,12 @@ class Foo:
639645
return
640646
yield 0
641647

648+
def test_early_return() -> None:
649+
foo = Foo()
650+
for x in foo.f():
651+
pass
652+
assert foo.bar.bar == 1
653+
642654
[case testBorrowingInGeneratorInTupleAssignment]
643655
from typing import Iterator
644656

mypyc/test-data/run-generics.test

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,23 @@ def fn_typeddict(t: T) -> None:
2727
print([x for x in t.keys()])
2828
print({k: v for k, v in t.items()})
2929

30-
fn_mapping({})
31-
print("=====")
32-
fn_mapping({"a": 1, "b": 2})
33-
print("=====")
30+
def test_mapping() -> None:
31+
fn_mapping({})
32+
print("=====")
33+
fn_mapping({"a": 1, "b": 2})
34+
print("=====")
3435

35-
fn_union({"a": 1, "b": 2})
36-
print("=====")
37-
fn_union({"a": "1", "b": "2"})
38-
print("=====")
36+
fn_union({"a": 1, "b": 2})
37+
print("=====")
38+
fn_union({"a": "1", "b": "2"})
39+
print("=====")
3940

40-
orig: Union[Dict[str, int], Dict[str, str]] = {"a": 1, "b": 2}
41-
fn_union(orig)
42-
print("=====")
41+
orig: Union[Dict[str, int], Dict[str, str]] = {"a": 1, "b": 2}
42+
fn_union(orig)
43+
print("=====")
4344

44-
td: TD = {"foo": 1}
45-
fn_typeddict(td)
45+
td: TD = {"foo": 1}
46+
fn_typeddict(td)
4647
[typing fixtures/typing-full.pyi]
4748
[out]
4849
\[]
@@ -96,8 +97,9 @@ def deco(func: Callable[P, int]) -> Callable[P, int]:
9697
def f(x: int, y: str) -> int:
9798
return x
9899

99-
assert f(1, 'a') == 1
100-
assert f(2, y='b') == 2
100+
def test_usable() -> None:
101+
assert f(1, 'a') == 1
102+
assert f(2, y='b') == 2
101103
[out]
102104
\[1, 'a']
103105
{}

mypyc/test-data/run-imports.test

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,10 @@ import shared
212212
def do_import() -> None:
213213
import a
214214

215-
assert shared.counter == 0
216-
do_import()
217-
assert shared.counter == 1
215+
def test_lazy() -> None:
216+
assert shared.counter == 0
217+
do_import()
218+
assert shared.counter == 1
218219

219220
[file a.py]
220221
import shared
@@ -224,9 +225,10 @@ shared.counter += 1
224225
counter = 0
225226

226227
[case testDelayedImport]
227-
import a
228-
print("inbetween")
229-
import b
228+
def test_delayed() -> None:
229+
import a
230+
print("inbetween")
231+
import b
230232

231233
[file a.py]
232234
print("first")
@@ -240,19 +242,21 @@ inbetween
240242
last
241243

242244
[case testImportErrorLineNumber]
243-
try:
244-
import enum
245-
import dataclasses, missing # type: ignore[import]
246-
except ImportError as e:
247-
line = e.__traceback__.tb_lineno # type: ignore[attr-defined]
248-
assert line == 3, f"traceback's line number is {line}, expected 3"
245+
def test_error() -> None:
246+
try:
247+
import enum
248+
import dataclasses, missing # type: ignore[import]
249+
except ImportError as e:
250+
line = e.__traceback__.tb_lineno # type: ignore[attr-defined]
251+
assert line == 4, f"traceback's line number is {line}, expected 4"
249252

250253
[case testImportGroupIsolation]
251254
def func() -> None:
252255
import second
253256

254-
import first
255-
func()
257+
def test_isolation() -> None:
258+
import first
259+
func()
256260

257261
[file first.py]
258262
print("first")

0 commit comments

Comments
 (0)