Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9994)

Unified Diff: chrome/common/extensions/docs/server2/test_file_system.py

Issue 151883009: Docserver: Make MockFileSystem not iterate over the entire file system as part (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: yoz and then some Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/common/extensions/docs/server2/test_file_system.py
diff --git a/chrome/common/extensions/docs/server2/test_file_system.py b/chrome/common/extensions/docs/server2/test_file_system.py
index 911057871e59f4e714f7ec14f8fcbb7c3c2849f4..e4f94987f0d5b531581132d29558d3a325fcbc93 100644
--- a/chrome/common/extensions/docs/server2/test_file_system.py
+++ b/chrome/common/extensions/docs/server2/test_file_system.py
@@ -4,6 +4,7 @@
from file_system import FileSystem, FileNotFoundError, StatInfo
from future import Future
+from path_util import IsDirectory
def MoveTo(base, obj):
@@ -28,6 +29,70 @@ def MoveAllTo(base, obj):
return result
+def _List(file_system):
+ '''Returns a list of '/' separated paths derived from |file_system|.
+ For example, {'index.html': '', 'www': {'file.txt': ''}} would return
+ ['index.html', 'www/file.txt'].
+ '''
+ assert isinstance(file_system, dict)
+ result = {}
+ def update_result(item, path):
+ if isinstance(item, dict):
+ if path != '':
+ path += '/'
+ result[path] = [p if isinstance(content, basestring) else (p + '/')
+ for p, content in item.iteritems()]
+ for subpath, subitem in item.iteritems():
+ update_result(subitem, path + subpath)
+ elif isinstance(item, basestring):
+ result[path] = item
+ else:
+ raise ValueError('Unsupported item type: %s' % type(item))
+ update_result(file_system, '')
+ return result
+
+
+class _StatTracker(object):
+ '''Maintains the versions of paths in a file system. The versions of files
+ are changed either by |Increment| or |SetVersion|. The versions of
+ directories are derived from the versions of files within it.
+ '''
+
+ def __init__(self):
+ self._path_stats = {}
+ self._global_stat = 0
+
+ def Increment(self, path=None, by=1):
+ if path is None:
+ self._global_stat += by
+ else:
+ self.SetVersion(path, self._path_stats.get(path, 0) + by)
+
+ def SetVersion(self, path, new_version):
+ if IsDirectory(path):
+ raise ValueError('Only files have an incrementable stat, '
+ 'but "%s" is a directory' % path)
+
+ # Update version of that file.
+ self._path_stats[path] = new_version
+
+ # Update all parent directory versions as well.
+ slash_index = 0 # (deliberately including '' in the dir paths)
+ while slash_index != -1:
+ dir_path = path[:slash_index] + '/'
+ self._path_stats[dir_path] = max(self._path_stats.get(dir_path, 0),
+ new_version)
+ if dir_path == '/':
+ # Legacy support for '/' being the root of the file system rather
+ # than ''. Eventually when the path normalisation logic is complete
+ # this will be impossible and this logic will change slightly.
+ self._path_stats[''] = self._path_stats['/']
+ slash_index = path.find('/', slash_index + 1)
+
+ def GetVersion(self, path):
+ return self._global_stat + self._path_stats.get(path, 0)
+
+
class TestFileSystem(FileSystem):
'''A FileSystem backed by an object. Create with an object representing file
paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello',
@@ -37,93 +102,42 @@ class TestFileSystem(FileSystem):
def __init__(self, obj, relative_to=None, identity=None):
assert obj is not None
- self._obj = obj if relative_to is None else MoveTo(relative_to, obj)
+ if relative_to is not None:
+ obj = MoveTo(relative_to, obj)
self._identity = identity or type(self).__name__
- self._path_stats = {}
- self._global_stat = 0
+ self._path_values = _List(obj)
+ self._stat_tracker = _StatTracker()
#
# FileSystem implementation.
#
def Read(self, paths):
- test_fs = self
- class Delegate(object):
- def Get(self):
- return dict((path, test_fs._ResolvePath(path)) for path in paths)
- return Future(delegate=Delegate())
+ for path in paths:
+ if path not in self._path_values:
+ return FileNotFoundError.RaiseInFuture(path)
+ return Future(value=dict((k, v) for k, v in self._path_values.iteritems()
+ if k in paths))
def Refresh(self):
return Future(value=())
- def _ResolvePath(self, path):
- def Resolve(parts):
- '''Resolves |parts| of a path info |self._obj|.
- '''
- result = self._obj.get(parts[0])
- for part in parts[1:]:
- if not isinstance(result, dict):
- raise FileNotFoundError(
- '%s at %s did not resolve to a dict, instead %s' %
- (path, part, result))
- result = result.get(part)
- return result
-
- def GetPaths(obj):
- '''Lists the paths within |obj|; this is basially keys() but with
- directory paths (i.e. dicts) with a trailing /.
- '''
- def ToPath(k, v):
- if isinstance(v, basestring):
- return k
- if isinstance(v, dict):
- return '%s/' % k
- raise ValueError('Cannot convert type %s to path', type(v))
- return [ToPath(k, v) for k, v in obj.items()]
-
- path = path.lstrip('/')
-
- if path == '':
- return GetPaths(self._obj)
-
- parts = path.split('/')
- if parts[-1] != '':
- file_contents = Resolve(parts)
- if not isinstance(file_contents, basestring):
- raise FileNotFoundError(
- '%s (%s) did not resolve to a string, instead %s' %
- (path, parts, file_contents))
- return file_contents
-
- dir_contents = Resolve(parts[:-1])
- if not isinstance(dir_contents, dict):
- raise FileNotFoundError(
- '%s (%s) did not resolve to a dict, instead %s' %
- (path, parts, dir_contents))
-
- return GetPaths(dir_contents)
-
def Stat(self, path):
- read_result = self.Read([path]).Get().get(path)
- stat_result = StatInfo(self._SinglePathStat(path))
+ read_result = self.ReadSingle(path).Get()
+ stat_result = StatInfo(str(self._stat_tracker.GetVersion(path)))
if isinstance(read_result, list):
stat_result.child_versions = dict(
- (file_result, self._SinglePathStat('%s%s' % (path, file_result)))
+ (file_result,
+ str(self._stat_tracker.GetVersion('%s%s' % (path, file_result))))
for file_result in read_result)
return stat_result
- def _SinglePathStat(self, path):
- return str(self._global_stat + self._path_stats.get(path, 0))
-
#
# Testing methods.
#
def IncrementStat(self, path=None, by=1):
- if path is not None:
- self._path_stats[path] = self._path_stats.get(path, 0) + by
- else:
- self._global_stat += by
+ self._stat_tracker.Increment(path, by=by)
def GetIdentity(self):
return self._identity

Powered by Google App Engine
This is Rietveld 408576698