11"""Utilities for testing."""
22
33import textwrap
4- from pathlib import PurePath
4+ from pathlib import PureWindowsPath , PurePosixPath
55from unittest import mock
66from io import StringIO
77import functools
@@ -11,16 +11,21 @@ def dedent_ftl(text):
1111 return textwrap .dedent (f"{ text .rstrip ()} \n " )
1212
1313
14- # Unify path separator, default path separator on Windows is \ not /
15- # Supports only relative paths
1614# Needed in test_falllback.py because it uses dict + string compare to make a virtual file structure
17- def _normalize_path (path ):
15+ def _normalize_file_path (path ):
1816 """Note: Does not support absolute paths or paths that
1917 contain '.' or '..' parts."""
20- path = PurePath (path )
21- if path .is_absolute () or "." in path .parts or ".." in path .parts :
18+ # Cannot use os.path or PurePath, because they only recognize
19+ # one kind of path separator
20+ if PureWindowsPath (path ).is_absolute () or PurePosixPath (path ).is_absolute ():
2221 raise ValueError (f"Unsupported path: { path } " )
23- return "/" .join (path .parts )
22+ parts = path .replace ("\\ " , "/" ).split ("/" )
23+ if "." in parts or ".." in parts :
24+ raise ValueError (f"Unsupported path: { path } " )
25+ if parts and parts [- 1 ] == "" :
26+ # path ends with a trailing pathsep
27+ raise ValueError (f"Path appears to be a directory, not a file: { path } " )
28+ return "/" .join (parts )
2429
2530
2631def patch_files (files : dict ):
@@ -32,12 +37,12 @@ def patch_files(files: dict):
3237
3338 The implementation may be changed to match the mechanism used.
3439 """
35- if files is None :
36- files = {}
40+
41+ # Here it is possible to validate file names, but skipped
3742
3843 def then (func ):
39- @mock .patch ("os.path.isfile" , side_effect = lambda p : _normalize_path (p ) in files )
40- @mock .patch ("codecs.open" , side_effect = lambda p , _ , __ : StringIO (files [_normalize_path (p )]))
44+ @mock .patch ("os.path.isfile" , side_effect = lambda p : _normalize_file_path (p ) in files )
45+ @mock .patch ("codecs.open" , side_effect = lambda p , _ , __ : StringIO (files [_normalize_file_path (p )]))
4146 @functools .wraps (func ) # Make ret look like func to later decorators
4247 def ret (* args , ** kwargs ):
4348 func (* args [:- 2 ], ** kwargs )
0 commit comments