| 
4 | 4 | import pathlib  | 
5 | 5 | import platform  | 
6 | 6 | import pytest  | 
7 |  | -from testutils import simplecpp, format_include_path_arg, format_include  | 
 | 7 | +from testutils import (  | 
 | 8 | +    simplecpp,  | 
 | 9 | +    format_include_path_arg,  | 
 | 10 | +    format_framework_path_arg,  | 
 | 11 | +    format_iframework_path_arg,  | 
 | 12 | +    format_include,  | 
 | 13 | +    mk_framework,  | 
 | 14 | +    mk_framework_private,  | 
 | 15 | +)  | 
8 | 16 | 
 
  | 
9 | 17 | def __test_relative_header_create_header(dir, with_pragma_once=True):  | 
10 | 18 |     header_file = os.path.join(dir, 'test.h')  | 
@@ -236,6 +244,190 @@ def test_same_name_header(record_property, tmpdir):  | 
236 | 244 |     assert "OK" in stdout  | 
237 | 245 |     assert stderr == ""  | 
238 | 246 | 
 
  | 
 | 247 | +def test_framework_basic_F_headers(record_property, tmpdir):  | 
 | 248 | +    # Arrange framework: <tmp>/FwRoot/MyKit.framework/Headers/MyKit.h  | 
 | 249 | +    fw_root = os.path.join(tmpdir, "FwRoot")  | 
 | 250 | +    mk_framework(tmpdir, "FwRoot", "MyKit", "MyKit.h",  | 
 | 251 | +                 '#define ORIGIN "FROM_FRAMEWORK"\n'  | 
 | 252 | +                 'int __force_line_emission; /* anything non-preprocessor */\n')  | 
 | 253 | + | 
 | 254 | +    # Source uses the macro defined in the framework header  | 
 | 255 | +    source = os.path.join(tmpdir, "t.c")  | 
 | 256 | +    with open(source, "wt") as f:  | 
 | 257 | +        f.write("""  | 
 | 258 | +                #include <MyKit/MyKit.h>  | 
 | 259 | +                ORIGIN  | 
 | 260 | +                """)  | 
 | 261 | + | 
 | 262 | +    args = [format_framework_path_arg(fw_root), source]  | 
 | 263 | +    print("*" * 10, args)  | 
 | 264 | +    _, stdout, stderr = simplecpp(args, cwd=tmpdir)  | 
 | 265 | +    record_property("stdout", stdout)  | 
 | 266 | +    record_property("stderr", stderr)  | 
 | 267 | + | 
 | 268 | +    assert stderr == ""  | 
 | 269 | +    assert 'FROM_FRAMEWORK' in stdout  | 
 | 270 | +    # And we should see a #line to the physical framework header path:  | 
 | 271 | +    assert ("/MyKit.framework/Headers/MyKit.h" in stdout.replace("\\", "/"))  | 
 | 272 | + | 
 | 273 | +def test_framework_privateheaders_when_no_headers(record_property, tmpdir):  | 
 | 274 | +    # Arrange framework with only PrivateHeaders  | 
 | 275 | +    fw_root = os.path.join(tmpdir, "FwRoot2")  | 
 | 276 | +    mk_framework_private(tmpdir, "FwRoot2", "MyKit", "Component.h",  | 
 | 277 | +                         '#define WHERE "PRIVATE"\n'  | 
 | 278 | +                         'int __force_line_emission; /* anything non-preprocessor */\n')  | 
 | 279 | +    # No Headers/Component.h  | 
 | 280 | + | 
 | 281 | +    source = os.path.join(tmpdir, "t.c")  | 
 | 282 | +    with open(source, "wt") as f:  | 
 | 283 | +        f.write("""  | 
 | 284 | +                #include <MyKit/Component.h>  | 
 | 285 | +                WHERE  | 
 | 286 | +                """)  | 
 | 287 | + | 
 | 288 | +    args = [format_framework_path_arg(fw_root), source]  | 
 | 289 | +    _, stdout, stderr = simplecpp(args, cwd=tmpdir)  | 
 | 290 | +    record_property("stdout", stdout)  | 
 | 291 | +    record_property("stderr", stderr)  | 
 | 292 | + | 
 | 293 | +    assert stderr == ""  | 
 | 294 | +    assert "PRIVATE" in stdout  | 
 | 295 | +    # confirm we actually found PrivateHeaders:  | 
 | 296 | +    assert ("/MyKit.framework/PrivateHeaders/Component.h" in stdout.replace("\\", "/"))  | 
 | 297 | + | 
 | 298 | +def test_order_I_then_F_prefers_I(record_property, tmpdir):  | 
 | 299 | +    incdir = os.path.join(tmpdir, "inc")  | 
 | 300 | +    fw_root = os.path.join(tmpdir, "Fw")  | 
 | 301 | + | 
 | 302 | +    os.mkdir(incdir)  | 
 | 303 | + | 
 | 304 | +    # Normal include tree: inc/MyKit/MyKit.h  | 
 | 305 | +    mykit_mykit_h = os.path.join(incdir, "MyKit", "MyKit.h")  | 
 | 306 | +    os.mkdir(os.path.join(incdir, "MyKit"))  | 
 | 307 | +    with open(mykit_mykit_h, "wt") as f:  | 
 | 308 | +        f.write("""  | 
 | 309 | +                #define ORIGIN "FROM_INCLUDE"  | 
 | 310 | +                int __force_line_emission; /* anything non-preprocessor */  | 
 | 311 | +                """)  | 
 | 312 | + | 
 | 313 | +    # Framework: Fw/MyKit.framework/Headers/MyKit.h  | 
 | 314 | +    mk_framework(tmpdir, "Fw", "MyKit", "MyKit.h",  | 
 | 315 | +                 '#define ORIGIN "FROM_FRAMEWORK"\n'  | 
 | 316 | +                 'int __force_line_emission; /* anything non-preprocessor */\n')  | 
 | 317 | + | 
 | 318 | +    source = os.path.join(tmpdir, "t.c")  | 
 | 319 | +    with open(source, "wt") as f:  | 
 | 320 | +        f.write("""  | 
 | 321 | +                #include <MyKit/MyKit.h>  | 
 | 322 | +                ORIGIN  | 
 | 323 | +                """)  | 
 | 324 | + | 
 | 325 | +    # ORDER: -I first, then -F  | 
 | 326 | +    args = [format_include_path_arg(incdir), format_framework_path_arg(fw_root), source]  | 
 | 327 | +    _, stdout, stderr = simplecpp(args, cwd=tmpdir)  | 
 | 328 | +    record_property("stdout", stdout)  | 
 | 329 | +    record_property("stderr", stderr)  | 
 | 330 | + | 
 | 331 | +    assert stderr == ""  | 
 | 332 | +    assert "FROM_INCLUDE" in stdout  | 
 | 333 | +    assert "FROM_FRAMEWORK" not in stdout  | 
 | 334 | +    # path should point to the include tree:  | 
 | 335 | +    assert (f'{pathlib.PurePath(incdir).as_posix()}/MyKit/MyKit.h') in stdout  | 
 | 336 | + | 
 | 337 | +def test_order_F_then_I_prefers_F(record_property, tmpdir):  | 
 | 338 | +    fw_root = os.path.join(tmpdir, "Fw")  | 
 | 339 | +    incdir = os.path.join(tmpdir, "inc")  | 
 | 340 | + | 
 | 341 | +    os.mkdir(incdir)  | 
 | 342 | + | 
 | 343 | +    mk_framework(tmpdir, "Fw", "MyKit", "MyKit.h",  | 
 | 344 | +                 '#define ORIGIN "FROM_FRAMEWORK"\n'  | 
 | 345 | +                 'int __force_line_emission; /* anything non-preprocessor */\n')  | 
 | 346 | + | 
 | 347 | +    mykit_mykit_h = os.path.join(incdir, "MyKit", "MyKit.h")  | 
 | 348 | +    os.mkdir(os.path.join(incdir, "MyKit"))  | 
 | 349 | +    with open(mykit_mykit_h, "wt") as f:  | 
 | 350 | +        f.write("""  | 
 | 351 | +                #define ORIGIN "FROM_INCLUDE"  | 
 | 352 | +                int __force_line_emission; /* anything non-preprocessor */  | 
 | 353 | +                """)  | 
 | 354 | + | 
 | 355 | +    source = os.path.join(tmpdir, "t.c")  | 
 | 356 | +    with open(source, "wt") as f:  | 
 | 357 | +        f.write("""  | 
 | 358 | +                #include <MyKit/MyKit.h>  | 
 | 359 | +                ORIGIN  | 
 | 360 | +                """)  | 
 | 361 | + | 
 | 362 | +    # ORDER: -F first, then -I  | 
 | 363 | +    args = [format_framework_path_arg(fw_root), format_include_path_arg(incdir), source]  | 
 | 364 | +    _, stdout, stderr = simplecpp(args, cwd=tmpdir)  | 
 | 365 | +    record_property("stdout", stdout)  | 
 | 366 | +    record_property("stderr", stderr)  | 
 | 367 | + | 
 | 368 | +    assert stderr == ""  | 
 | 369 | +    assert "FROM_FRAMEWORK" in stdout  | 
 | 370 | +    assert "FROM_INCLUDE" not in stdout  | 
 | 371 | +    assert ("/MyKit.framework/Headers/MyKit.h" in stdout.replace("\\", "/"))  | 
 | 372 | + | 
 | 373 | +def test_interleaved_multiple_paths(record_property, tmpdir):  | 
 | 374 | +    # Layout:  | 
 | 375 | +    #   I1/MyKit/MyKit.h          -> "I1"  | 
 | 376 | +    #   F1/MyKit.framework/...    -> "F1"  | 
 | 377 | +    #   I2/MyKit/MyKit.h          -> "I2"  | 
 | 378 | +    #   F2/MyKit.framework/...    -> "F2"  | 
 | 379 | + | 
 | 380 | +    I1 = os.path.join(tmpdir, "I1")  | 
 | 381 | +    F1 = os.path.join(tmpdir, "F1")  | 
 | 382 | +    I2 = os.path.join(tmpdir, "I2")  | 
 | 383 | +    F2 = os.path.join(tmpdir, "F2")  | 
 | 384 | + | 
 | 385 | +    os.mkdir(I1)  | 
 | 386 | +    os.mkdir(I2)  | 
 | 387 | + | 
 | 388 | +    i1_mykit_mykit_h = os.path.join(I1, "MyKit", "MyKit.h")  | 
 | 389 | +    os.mkdir(os.path.join(I1, "MyKit"))  | 
 | 390 | +    with open(i1_mykit_mykit_h, "wt") as f:  | 
 | 391 | +        f.write("""  | 
 | 392 | +                #define ORIGIN "I1"  | 
 | 393 | +                """)  | 
 | 394 | + | 
 | 395 | +    mk_framework(tmpdir, "F1", "MyKit", "MyKit.h", '#define ORIGIN "F1"\n')  | 
 | 396 | + | 
 | 397 | +    i2_mykit_mykit_h = os.path.join(I2, "MyKit", "MyKit.h")  | 
 | 398 | +    os.mkdir(os.path.join(I2, "MyKit"))  | 
 | 399 | +    with open(i2_mykit_mykit_h, "wt") as f:  | 
 | 400 | +        f.write("""  | 
 | 401 | +                #define ORIGIN "I2"  | 
 | 402 | +                """)  | 
 | 403 | + | 
 | 404 | +    mk_framework(tmpdir, "F2", "MyKit", "MyKit.h", '#define ORIGIN "F2"\n')  | 
 | 405 | + | 
 | 406 | +    source = os.path.join(tmpdir, "t.c")  | 
 | 407 | +    with open(source, "wt") as f:  | 
 | 408 | +        f.write("""  | 
 | 409 | +                #include <MyKit/MyKit.h>  | 
 | 410 | +                ORIGIN  | 
 | 411 | +                """)  | 
 | 412 | + | 
 | 413 | +    # Choose an ordering to validate precedence:  | 
 | 414 | +    # e.g. I1, F1, I2, F2  -> expect I1  | 
 | 415 | +    args = [  | 
 | 416 | +        format_include_path_arg(I1),  | 
 | 417 | +        format_framework_path_arg(F1),  | 
 | 418 | +        format_include_path_arg(I2),  | 
 | 419 | +        format_framework_path_arg(F2),  | 
 | 420 | +        source  | 
 | 421 | +    ]  | 
 | 422 | +    _, stdout, stderr = simplecpp(args, cwd=tmpdir)  | 
 | 423 | +    record_property("stdout", stdout)  | 
 | 424 | +    record_property("stderr", stderr)  | 
 | 425 | + | 
 | 426 | +    assert stderr == ""  | 
 | 427 | +    assert '"I1"' in stdout  | 
 | 428 | +    for other in ("\"F1\"", "\"I2\"", "\"F2\""):  | 
 | 429 | +        assert other not in stdout  | 
 | 430 | + | 
239 | 431 | def test_pragma_once_matching(record_property, tmpdir):  | 
240 | 432 |     test_dir = os.path.join(tmpdir, "test_dir")  | 
241 | 433 |     test_subdir = os.path.join(test_dir, "test_subdir")  | 
 | 
0 commit comments