@@ -1339,3 +1339,129 @@ class Multi(Base, Mixin):
13391339 assert any (n .endswith ('Mixin' ) for n in iface_names )
13401340 finally :
13411341 _cleanup_mapping (mapping , tmpdir , client )
1342+
1343+
1344+ class TestGenericTypeVariable :
1345+ """Tests for typeVar → GenericTypeVariable conversion."""
1346+
1347+ def test_plain_typevar_creates_generic_type_variable (self ):
1348+ """A typeVar descriptor with just a name should create a GenericTypeVariable."""
1349+ mapping = PythonTypeMapping ("" , file_path = None )
1350+ mapping ._type_registry [100 ] = {
1351+ 'kind' : 'typeVar' ,
1352+ 'name' : 'T' ,
1353+ 'variance' : 'invariant' ,
1354+ }
1355+
1356+ result = mapping ._resolve_type (100 )
1357+ assert isinstance (result , JavaType .GenericTypeVariable )
1358+ assert result .name == 'T'
1359+ assert result .variance == JavaType .GenericTypeVariable .Variance .Invariant
1360+ assert result .bounds == []
1361+
1362+ def test_covariant_typevar (self ):
1363+ """A typeVar with covariant variance should map correctly."""
1364+ mapping = PythonTypeMapping ("" , file_path = None )
1365+ mapping ._type_registry [100 ] = {
1366+ 'kind' : 'typeVar' ,
1367+ 'name' : 'T_co' ,
1368+ 'variance' : 'covariant' ,
1369+ }
1370+
1371+ result = mapping ._resolve_type (100 )
1372+ assert isinstance (result , JavaType .GenericTypeVariable )
1373+ assert result .name == 'T_co'
1374+ assert result .variance == JavaType .GenericTypeVariable .Variance .Covariant
1375+
1376+ def test_contravariant_typevar (self ):
1377+ """A typeVar with contravariant variance should map correctly."""
1378+ mapping = PythonTypeMapping ("" , file_path = None )
1379+ mapping ._type_registry [100 ] = {
1380+ 'kind' : 'typeVar' ,
1381+ 'name' : 'T_contra' ,
1382+ 'variance' : 'contravariant' ,
1383+ }
1384+
1385+ result = mapping ._resolve_type (100 )
1386+ assert isinstance (result , JavaType .GenericTypeVariable )
1387+ assert result .name == 'T_contra'
1388+ assert result .variance == JavaType .GenericTypeVariable .Variance .Contravariant
1389+
1390+ def test_typevar_with_upper_bound (self ):
1391+ """A typeVar with an upperBound should have a bounds list."""
1392+ mapping = PythonTypeMapping ("" , file_path = None )
1393+ mapping ._type_registry [100 ] = {
1394+ 'kind' : 'typeVar' ,
1395+ 'name' : 'T' ,
1396+ 'variance' : 'invariant' ,
1397+ 'upperBound' : 101 ,
1398+ }
1399+ mapping ._type_registry [101 ] = {
1400+ 'kind' : 'instance' ,
1401+ 'className' : 'int' ,
1402+ }
1403+
1404+ result = mapping ._resolve_type (100 )
1405+ assert isinstance (result , JavaType .GenericTypeVariable )
1406+ assert result .name == 'T'
1407+ assert len (result .bounds ) == 1
1408+ assert result .bounds [0 ] is JavaType .Primitive .Int
1409+
1410+ def test_typevar_with_class_upper_bound (self ):
1411+ """A typeVar bounded by a class should resolve the bound."""
1412+ mapping = PythonTypeMapping ("" , file_path = None )
1413+ mapping ._type_registry [100 ] = {
1414+ 'kind' : 'typeVar' ,
1415+ 'name' : 'T' ,
1416+ 'variance' : 'covariant' ,
1417+ 'upperBound' : 101 ,
1418+ }
1419+ mapping ._type_registry [101 ] = {
1420+ 'kind' : 'instance' ,
1421+ 'className' : 'Comparable' ,
1422+ 'moduleName' : 'builtins' ,
1423+ }
1424+
1425+ result = mapping ._resolve_type (100 )
1426+ assert isinstance (result , JavaType .GenericTypeVariable )
1427+ assert result .variance == JavaType .GenericTypeVariable .Variance .Covariant
1428+ assert len (result .bounds ) == 1
1429+ assert isinstance (result .bounds [0 ], JavaType .Class )
1430+ assert result .bounds [0 ].fully_qualified_name == 'Comparable'
1431+
1432+ def test_typevar_without_variance_defaults_to_invariant (self ):
1433+ """A typeVar without explicit variance should default to Invariant."""
1434+ mapping = PythonTypeMapping ("" , file_path = None )
1435+ mapping ._type_registry [100 ] = {
1436+ 'kind' : 'typeVar' ,
1437+ 'name' : 'T' ,
1438+ }
1439+
1440+ result = mapping ._resolve_type (100 )
1441+ assert isinstance (result , JavaType .GenericTypeVariable )
1442+ assert result .name == 'T'
1443+ assert result .variance == JavaType .GenericTypeVariable .Variance .Invariant
1444+
1445+ def test_typevar_without_name_returns_unknown (self ):
1446+ """A typeVar without a name should return Unknown."""
1447+ mapping = PythonTypeMapping ("" , file_path = None )
1448+ mapping ._type_registry [100 ] = {
1449+ 'kind' : 'typeVar' ,
1450+ 'name' : '' ,
1451+ }
1452+
1453+ result = mapping ._resolve_type (100 )
1454+ assert isinstance (result , JavaType .Unknown )
1455+
1456+ def test_typevar_cached_by_type_id (self ):
1457+ """Resolved GenericTypeVariable should be cached by type_id."""
1458+ mapping = PythonTypeMapping ("" , file_path = None )
1459+ mapping ._type_registry [100 ] = {
1460+ 'kind' : 'typeVar' ,
1461+ 'name' : 'T' ,
1462+ 'variance' : 'invariant' ,
1463+ }
1464+
1465+ result1 = mapping ._resolve_type (100 )
1466+ result2 = mapping ._resolve_type (100 )
1467+ assert result1 is result2
0 commit comments