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

Side by Side Diff: pkg/watcher/test/utils.dart

Issue 18612013: File watching package. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove reference to old unittest config. Created 7 years, 5 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
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library watcher.test.utils;
6
7 import 'dart:async';
8 import 'dart:io';
9
10 import 'package:pathos/path.dart' as pathos;
11 import 'package:scheduled_test/scheduled_test.dart';
12 import 'package:unittest/compact_vm_config.dart';
13 import 'package:watcher/watcher.dart';
14 import 'package:watcher/src/stat.dart';
15
16 /// The path to the temporary sandbox created for each test. All file
17 /// operations are implicitly relative to this directory.
18 String _sandboxDir;
19
20 /// The [DirectoryWatcher] being used for the current scheduled test.
21 DirectoryWatcher _watcher;
22
23 /// The index in [_watcher]'s event stream for the next event. When event
24 /// expectations are set using [expectEvent] (et. al.), they use this to
25 /// expect a series of events in order.
26 var _nextEvent = 0;
27
28 /// The mock modification times (in milliseconds since epoch) for each file.
29 ///
30 /// The actual file system has pretty coarse granularity for file modification
31 /// times. This means using the real file system requires us to put delays in
32 /// the tests to ensure we wait long enough between operations for the mod time
33 /// to be different.
34 ///
35 /// Instead, we'll just mock that out. Each time a file is written, we manually
36 /// increment the mod time for that file instantly.
37 Map<String, int> _mockFileModificationTimes;
38
39 void initConfig() {
40 useCompactVMConfiguration();
41 }
42
43 /// Creates a new [DirectoryWatcher] that watches a temporary directory.
44 ///
45 /// Normally, this will pause the schedule until the watcher is done scanning
46 /// and is polling for changes. If you pass `false` for [waitForReady], it will
47 /// not schedule this delay.
48 DirectoryWatcher createWatcher({bool waitForReady}) {
49 _ensureSandbox();
50 _watcher = new DirectoryWatcher(_sandboxDir);
51
52 // Wait until the scan is finished so that we don't miss changes to files
53 // that could occur before the scan completes.
54 if (waitForReady != false) {
55 schedule(() => _watcher.ready);
56 }
57
58 currentSchedule.onComplete.schedule(() {
59 _nextEvent = 0;
60 _watcher = null;
61 }, "reset watcher");
62
63 return _watcher;
64 }
65
66 void expectEvent(ChangeType type, String path) {
67 // Immediately create the future. This ensures we don't register too late and
68 // drop the event before we receive it.
69 var future = _watcher.events.elementAt(_nextEvent++).then((event) {
70 expect(event, new _ChangeMatcher(type, path));
71 });
72
73 // Make sure the schedule is watching it in case it fails.
74 currentSchedule.wrapFuture(future);
75
76 // Schedule it so that later file modifications don't occur until after this
77 // event is received.
78 schedule(() => future);
79 }
80
81 void expectAddEvent(String path) {
82 expectEvent(ChangeType.ADD, pathos.join(_sandboxDir, path));
83 }
84
85 void expectModifyEvent(String path) {
86 expectEvent(ChangeType.MODIFY, pathos.join(_sandboxDir, path));
87 }
88
89 void expectRemoveEvent(String path) {
90 expectEvent(ChangeType.REMOVE, pathos.join(_sandboxDir, path));
91 }
92
93 /// Schedules writing a file in the sandbox at [path] with [contents].
94 ///
95 /// If [contents] is omitted, creates an empty file. If [updatedModified] is
96 /// `false`, the mock file modification time is not changed.
97 void writeFile(String path, {String contents, bool updateModified}) {
98 if (contents == null) contents = "";
99 if (updateModified == null) updateModified = true;
100
101 _ensureSandbox();
102 schedule(() {
103 var fullPath = pathos.join(_sandboxDir, path);
104
105 // Create any needed subdirectories.
106 var dir = new Directory(pathos.dirname(fullPath));
107 if (!dir.existsSync()) {
108 dir.createSync(recursive: true);
109 }
110
111 new File(fullPath).writeAsStringSync(contents);
112
113 // Manually update the mock modification time for the file.
114 if (updateModified) {
115 var milliseconds = _mockFileModificationTimes.putIfAbsent(path, () => 0);
116 _mockFileModificationTimes[path]++;
117 }
118 });
119 }
120
121 /// Schedules deleting a file in the sandbox at [path].
122 void deleteFile(String path) {
123 _ensureSandbox();
124 schedule(() {
125 new File(pathos.join(_sandboxDir, path)).deleteSync();
126 });
127 }
128
129 /// Schedules renaming a file in the sandbox from [from] to [to].
130 ///
131 /// If [contents] is omitted, creates an empty file.
132 void renameFile(String from, String to) {
133 _ensureSandbox();
134 schedule(() {
135 new File(pathos.join(_sandboxDir, from)).renameSync(
136 pathos.join(_sandboxDir, to));
137
138 // Manually update the mock modification time for the file.
139 var milliseconds = _mockFileModificationTimes.putIfAbsent(to, () => 0);
140 _mockFileModificationTimes[to]++;
141 });
142 }
143
144 /// Makes sure the sandbox directory has been created for this schedule.
145 void _ensureSandbox() {
146 if (_sandboxDir != null) return;
147
148 var dir = new Directory("").createTempSync();
149 _sandboxDir = dir.path;
150
151 _mockFileModificationTimes = new Map<String, int>();
152 mockGetModificationTime((path) {
153 path = pathos.relative(path, from: _sandboxDir);
154
155 // Make sure we got a path in the sandbox.
156 assert(pathos.isRelative(path) && !path.startsWith(".."));
157
158 return new DateTime.fromMillisecondsSinceEpoch(
159 _mockFileModificationTimes[path]);
160 });
161
162 currentSchedule.onComplete.schedule(() {
163 if (_sandboxDir != null) {
164 new Directory(_sandboxDir).deleteSync(recursive: true);
165 _sandboxDir = null;
166 }
167
168 _mockFileModificationTimes = null;
169 mockGetModificationTime(null);
170 }, "delete sandbox");
171 }
172
173 /// A [Matcher] for [WatchEvent]s.
174 class _ChangeMatcher extends BaseMatcher {
175 /// The expected change.
176 final ChangeType type;
177
178 /// The expected path.
179 final String path;
180
181 _ChangeMatcher(this.type, this.path);
182
183 Description describe(Description description) {
184 description.add("$type $path");
185 }
186
187 bool matches(item, Map matchState) =>
188 item is WatchEvent && item.type == type && item.path == path;
189 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698