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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from file_system import FileSystem, FileNotFoundError, StatInfo 5 from file_system import FileSystem, FileNotFoundError, StatInfo
6 from future import Future 6 from future import Future
7 from path_util import IsDirectory
7 8
8 9
9 def MoveTo(base, obj): 10 def MoveTo(base, obj):
10 '''Returns an object as |obj| moved to |base|. That is, 11 '''Returns an object as |obj| moved to |base|. That is,
11 MoveTo('foo/bar', {'a': 'b'}) -> {'foo': {'bar': {'a': 'b'}}} 12 MoveTo('foo/bar', {'a': 'b'}) -> {'foo': {'bar': {'a': 'b'}}}
12 ''' 13 '''
13 result = {} 14 result = {}
14 leaf = result 15 leaf = result
15 for k in base.split('/'): 16 for k in base.split('/'):
16 leaf[k] = {} 17 leaf[k] = {}
17 leaf = leaf[k] 18 leaf = leaf[k]
18 leaf.update(obj) 19 leaf.update(obj)
19 return result 20 return result
20 21
21 22
22 def MoveAllTo(base, obj): 23 def MoveAllTo(base, obj):
23 '''Moves every value in |obj| to |base|. See MoveTo. 24 '''Moves every value in |obj| to |base|. See MoveTo.
24 ''' 25 '''
25 result = {} 26 result = {}
26 for key, value in obj.iteritems(): 27 for key, value in obj.iteritems():
27 result[key] = MoveTo(base, value) 28 result[key] = MoveTo(base, value)
28 return result 29 return result
29 30
30 31
32 def _List(file_system):
33 '''Returns a list of '/' separated paths derived from |file_system|.
34 For example, {'index.html': '', 'www': {'file.txt': ''}} would return
35 ['index.html', 'www/file.txt'].
36 '''
37 assert isinstance(file_system, dict)
38 result = {}
39 def update_result(item, path):
40 if isinstance(item, dict):
41 if path != '':
42 path += '/'
43 result[path] = [p if isinstance(content, basestring) else (p + '/')
44 for p, content in item.iteritems()]
45 for subpath, subitem in item.iteritems():
46 update_result(subitem, path + subpath)
47 elif isinstance(item, basestring):
48 result[path] = item
49 else:
50 raise ValueError('Unsupported item type: %s' % type(item))
51 update_result(file_system, '')
52 return result
53
54
55 class _StatTracker(object):
56 '''Maintains the versions of paths in a file system. The versions of files
57 are changed either by |Increment| or |SetVersion|. The versions of
58 directories are derived from the versions of files within it.
59 '''
60
61 def __init__(self):
62 self._path_stats = {}
63 self._global_stat = 0
64
65 def Increment(self, path=None, by=1):
66 if path is None:
67 self._global_stat += by
68 else:
69 self.SetVersion(path, self._path_stats.get(path, 0) + by)
70
71 def SetVersion(self, path, new_version):
72 if IsDirectory(path):
73 raise ValueError('Only files have an incrementable stat, '
74 'but "%s" is a directory' % path)
75
76 # Update version of that file.
77 self._path_stats[path] = new_version
78
79 # Update all parent directory versions as well.
80 slash_index = 0 # (deliberately including '' in the dir paths)
81 while slash_index != -1:
82 dir_path = path[:slash_index] + '/'
83 self._path_stats[dir_path] = max(self._path_stats.get(dir_path, 0),
84 new_version)
85 if dir_path == '/':
86 # Legacy support for '/' being the root of the file system rather
87 # than ''. Eventually when the path normalisation logic is complete
88 # this will be impossible and this logic will change slightly.
89 self._path_stats[''] = self._path_stats['/']
90 slash_index = path.find('/', slash_index + 1)
91
92 def GetVersion(self, path):
93 return self._global_stat + self._path_stats.get(path, 0)
94
95
31 class TestFileSystem(FileSystem): 96 class TestFileSystem(FileSystem):
32 '''A FileSystem backed by an object. Create with an object representing file 97 '''A FileSystem backed by an object. Create with an object representing file
33 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello', 98 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello',
34 Read('a/') as ['b'], and Stat determined by a value incremented via 99 Read('a/') as ['b'], and Stat determined by a value incremented via
35 IncrementStat. 100 IncrementStat.
36 ''' 101 '''
37 102
38 def __init__(self, obj, relative_to=None, identity=None): 103 def __init__(self, obj, relative_to=None, identity=None):
39 assert obj is not None 104 assert obj is not None
40 self._obj = obj if relative_to is None else MoveTo(relative_to, obj) 105 if relative_to is not None:
106 obj = MoveTo(relative_to, obj)
41 self._identity = identity or type(self).__name__ 107 self._identity = identity or type(self).__name__
42 self._path_stats = {} 108 self._path_values = _List(obj)
43 self._global_stat = 0 109 self._stat_tracker = _StatTracker()
44 110
45 # 111 #
46 # FileSystem implementation. 112 # FileSystem implementation.
47 # 113 #
48 114
49 def Read(self, paths): 115 def Read(self, paths):
50 test_fs = self 116 for path in paths:
51 class Delegate(object): 117 if path not in self._path_values:
52 def Get(self): 118 return FileNotFoundError.RaiseInFuture(path)
53 return dict((path, test_fs._ResolvePath(path)) for path in paths) 119 return Future(value=dict((k, v) for k, v in self._path_values.iteritems()
54 return Future(delegate=Delegate()) 120 if k in paths))
55 121
56 def Refresh(self): 122 def Refresh(self):
57 return Future(value=()) 123 return Future(value=())
58 124
59 def _ResolvePath(self, path):
60 def Resolve(parts):
61 '''Resolves |parts| of a path info |self._obj|.
62 '''
63 result = self._obj.get(parts[0])
64 for part in parts[1:]:
65 if not isinstance(result, dict):
66 raise FileNotFoundError(
67 '%s at %s did not resolve to a dict, instead %s' %
68 (path, part, result))
69 result = result.get(part)
70 return result
71
72 def GetPaths(obj):
73 '''Lists the paths within |obj|; this is basially keys() but with
74 directory paths (i.e. dicts) with a trailing /.
75 '''
76 def ToPath(k, v):
77 if isinstance(v, basestring):
78 return k
79 if isinstance(v, dict):
80 return '%s/' % k
81 raise ValueError('Cannot convert type %s to path', type(v))
82 return [ToPath(k, v) for k, v in obj.items()]
83
84 path = path.lstrip('/')
85
86 if path == '':
87 return GetPaths(self._obj)
88
89 parts = path.split('/')
90 if parts[-1] != '':
91 file_contents = Resolve(parts)
92 if not isinstance(file_contents, basestring):
93 raise FileNotFoundError(
94 '%s (%s) did not resolve to a string, instead %s' %
95 (path, parts, file_contents))
96 return file_contents
97
98 dir_contents = Resolve(parts[:-1])
99 if not isinstance(dir_contents, dict):
100 raise FileNotFoundError(
101 '%s (%s) did not resolve to a dict, instead %s' %
102 (path, parts, dir_contents))
103
104 return GetPaths(dir_contents)
105
106 def Stat(self, path): 125 def Stat(self, path):
107 read_result = self.Read([path]).Get().get(path) 126 read_result = self.ReadSingle(path).Get()
108 stat_result = StatInfo(self._SinglePathStat(path)) 127 stat_result = StatInfo(str(self._stat_tracker.GetVersion(path)))
109 if isinstance(read_result, list): 128 if isinstance(read_result, list):
110 stat_result.child_versions = dict( 129 stat_result.child_versions = dict(
111 (file_result, self._SinglePathStat('%s%s' % (path, file_result))) 130 (file_result,
131 str(self._stat_tracker.GetVersion('%s%s' % (path, file_result))))
112 for file_result in read_result) 132 for file_result in read_result)
113 return stat_result 133 return stat_result
114 134
115 def _SinglePathStat(self, path):
116 return str(self._global_stat + self._path_stats.get(path, 0))
117
118 # 135 #
119 # Testing methods. 136 # Testing methods.
120 # 137 #
121 138
122 def IncrementStat(self, path=None, by=1): 139 def IncrementStat(self, path=None, by=1):
123 if path is not None: 140 self._stat_tracker.Increment(path, by=by)
124 self._path_stats[path] = self._path_stats.get(path, 0) + by
125 else:
126 self._global_stat += by
127 141
128 def GetIdentity(self): 142 def GetIdentity(self):
129 return self._identity 143 return self._identity
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698