|
34 | 34 | SENTINEL_END = re.compile(r"^# INSTALL_SAFETY_END", re.MULTILINE) |
35 | 35 |
|
36 | 36 |
|
| 37 | +def _read_install_sh() -> str: |
| 38 | + """Read install.sh in a shell-safe form across platforms. |
| 39 | +
|
| 40 | + GitHub Actions on Windows can check out files with CRLF line endings. Bash |
| 41 | + treats stray carriage returns in the sourced function block as syntax |
| 42 | + errors, so normalize them before extracting or asserting on the script. |
| 43 | + """ |
| 44 | + return INSTALL_SH.read_text(encoding="utf-8").replace("\r\n", "\n").replace("\r", "\n") |
| 45 | + |
| 46 | + |
37 | 47 | def _load_validator(): |
38 | 48 | """Extract the apm_lib_dir_validate() block from install.sh and return the |
39 | 49 | source text of the function plus a small driver wrapper. Tests source the |
40 | 50 | result into a fresh shell to invoke the function in isolation -- no network |
41 | 51 | and no real installation side effects. |
42 | 52 | """ |
43 | | - text = INSTALL_SH.read_text(encoding="utf-8") |
| 53 | + text = _read_install_sh() |
44 | 54 | match_end = SENTINEL_END.search(text) |
45 | 55 | assert match_end is not None, "INSTALL_SAFETY_END sentinel missing in install.sh" |
46 | 56 | match_begin = SENTINEL_BEGIN.search(text) |
@@ -340,11 +350,11 @@ class TestSentinelInvariants: |
340 | 350 | """ |
341 | 351 |
|
342 | 352 | def test_begin_sentinel_present(self): |
343 | | - text = INSTALL_SH.read_text(encoding="utf-8") |
| 353 | + text = _read_install_sh() |
344 | 354 | assert SENTINEL_BEGIN.search(text) is not None |
345 | 355 |
|
346 | 356 | def test_end_sentinel_present(self): |
347 | | - text = INSTALL_SH.read_text(encoding="utf-8") |
| 357 | + text = _read_install_sh() |
348 | 358 | assert SENTINEL_END.search(text) is not None |
349 | 359 |
|
350 | 360 | def test_function_defined_in_extracted_block(self): |
|
0 commit comments