193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik# Copyright 2014 The Chromium Authors. All rights reserved. 293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik# Use of this source code is governed by a BSD-style license that can be 393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik# found in the LICENSE file. 4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 5f516a629824f0019315b9841dc2df76dc7862ddeChris Craikimport codecs 693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikimport os 793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikimport sys 893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikimport collections 993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikimport StringIO 1093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 1293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikclass WithableStringIO(StringIO.StringIO): 13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 1493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def __enter__(self, *args): 1593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return self 1693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 1793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def __exit__(self, *args): 1893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik pass 1993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 2193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craikclass FakeFS(object): 22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 2393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def __init__(self, initial_filenames_and_contents=None): 2493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._file_contents = {} 2593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if initial_filenames_and_contents: 26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik for k, v in initial_filenames_and_contents.iteritems(): 2793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._file_contents[k] = v 2893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 2993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._bound = False 30f516a629824f0019315b9841dc2df76dc7862ddeChris Craik self._real_codecs_open = codecs.open 3193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._real_open = sys.modules['__builtin__'].open 32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik self._real_abspath = os.path.abspath 3393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._real_exists = os.path.exists 3493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._real_walk = os.walk 3593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._real_listdir = os.listdir 3693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 3793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def __enter__(self): 3893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self.Bind() 3993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return self 4093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 4193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def __exit__(self, *args): 4293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self.Unbind() 4393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 4493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def Bind(self): 4593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik assert not self._bound 46f516a629824f0019315b9841dc2df76dc7862ddeChris Craik codecs.open = self._FakeCodecsOpen 4793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik sys.modules['__builtin__'].open = self._FakeOpen 48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik os.path.abspath = self._FakeAbspath 4993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.path.exists = self._FakeExists 5093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.walk = self._FakeWalk 5193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.listdir = self._FakeListDir 5293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._bound = True 5393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 5493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def Unbind(self): 5593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik assert self._bound 56f516a629824f0019315b9841dc2df76dc7862ddeChris Craik codecs.open = self._real_codecs_open 5793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik sys.modules['__builtin__'].open = self._real_open 58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik os.path.abspath = self._real_abspath 5993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.path.exists = self._real_exists 6093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.walk = self._real_walk 6193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik os.listdir = self._real_listdir 6293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._bound = False 6393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 6493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def AddFile(self, path, contents): 6593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik assert path not in self._file_contents 66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik path = os.path.normpath(path) 6793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik self._file_contents[path] = contents 6893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 6993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def _FakeOpen(self, path, mode=None): 70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if mode is None: 7193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik mode = 'r' 7293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if mode == 'r' or mode == 'rU' or mode == 'rb': 7393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if path not in self._file_contents: 7493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return self._real_open(path, mode) 7593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return WithableStringIO(self._file_contents[path]) 7693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 7793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik raise NotImplementedError() 7893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def _FakeCodecsOpen(self, path, mode=None, 80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik encoding=None): # pylint: disable=unused-argument 81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if mode is None: 82f516a629824f0019315b9841dc2df76dc7862ddeChris Craik mode = 'r' 83f516a629824f0019315b9841dc2df76dc7862ddeChris Craik if mode == 'r' or mode == 'rU' or mode == 'rb': 84f516a629824f0019315b9841dc2df76dc7862ddeChris Craik if path not in self._file_contents: 85f516a629824f0019315b9841dc2df76dc7862ddeChris Craik return self._real_open(path, mode) 86f516a629824f0019315b9841dc2df76dc7862ddeChris Craik return WithableStringIO(self._file_contents[path]) 87f516a629824f0019315b9841dc2df76dc7862ddeChris Craik 88f516a629824f0019315b9841dc2df76dc7862ddeChris Craik raise NotImplementedError() 89f516a629824f0019315b9841dc2df76dc7862ddeChris Craik 90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik def _FakeAbspath(self, path): 91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik """Normalize the path and ensure it starts with os.path.sep. 92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik The tests all assume paths start with things like '/my/project', 94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik and this abspath implementaion makes that assumption work correctly 95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik on Windows. 96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik """ 97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik normpath = os.path.normpath(path) 98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if not normpath.startswith(os.path.sep): 99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik normpath = os.path.sep + normpath 100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik return normpath 101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik 10293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def _FakeExists(self, path): 10393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if path in self._file_contents: 10493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return True 10593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik return self._real_exists(path) 10693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 10793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def _FakeWalk(self, top): 10893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik assert os.path.isabs(top) 10993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik all_filenames = self._file_contents.keys() 11093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik pending_prefixes = collections.deque() 11193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik pending_prefixes.append(top) 11293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik visited_prefixes = set() 11393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik while len(pending_prefixes): 11493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik prefix = pending_prefixes.popleft() 11593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if prefix in visited_prefixes: 11693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik continue 11793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik visited_prefixes.add(prefix) 118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik if prefix.endswith(os.path.sep): 11993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik prefix_with_trailing_sep = prefix 12093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik else: 121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik prefix_with_trailing_sep = prefix + os.path.sep 12293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 12393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirs = set() 12493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik files = [] 12593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik for filename in all_filenames: 12693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if not filename.startswith(prefix_with_trailing_sep): 12793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik continue 12893216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik relative_to_prefix = os.path.relpath(filename, prefix) 12993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 13093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirpart = os.path.dirname(relative_to_prefix) 13193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if len(dirpart) == 0: 13293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik files.append(relative_to_prefix) 13393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik continue 134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik parts = dirpart.split(os.sep) 13593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik if len(parts) == 0: 13693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirs.add(dirpart) 13793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik else: 138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik pending = os.path.join(prefix, parts[0]) 13993216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirs.add(parts[0]) 14093216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik pending_prefixes.appendleft(pending) 14193216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 14293216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirs = list(dirs) 14393216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik dirs.sort() 14493216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik yield prefix, dirs, files 14593216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik 14693216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik def _FakeListDir(self, dirname): 14793216d0b8afcc23eb8811175ca32338cd09c9dcaChris Craik raise NotImplementedError() 148