OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 'use strict'; |
| 6 |
| 7 /** |
| 8 * Sends a test message. |
| 9 * @param {Object} message Message to be sent. It is converted into JSON string |
| 10 * before sending. |
| 11 * @return {Promise} Promise to be fulfilled with a returned value. |
| 12 */ |
| 13 function sendTestMessage(message) { |
| 14 return new Promise(function(fulfill) { |
| 15 chrome.test.sendMessage(JSON.stringify(message), fulfill); |
| 16 }); |
| 17 } |
| 18 |
| 19 /** |
| 20 * Returns promise to be fulfilled after the given milliseconds. |
| 21 * @param {number} time Time in milliseconds. |
| 22 */ |
| 23 function wait(time) { |
| 24 return new Promise(function(callback) { |
| 25 setTimeout(callback, time); |
| 26 }); |
| 27 } |
| 28 |
| 29 /** |
| 30 * Interval milliseconds between checks of repeatUntil. |
| 31 * @type {number} |
| 32 * @const |
| 33 */ |
| 34 var REPEAT_UNTIL_INTERVAL = 200; |
| 35 |
| 36 /** |
| 37 * Interval milliseconds between log output of repeatUntil. |
| 38 * @type {number} |
| 39 * @const |
| 40 */ |
| 41 var LOG_INTERVAL = 3000; |
| 42 |
| 43 /** |
| 44 * Returns a pending marker. See also the repeatUntil function. |
| 45 * @param {string} message Pending reason including %s, %d, or %j markers. %j |
| 46 * format an object as JSON. |
| 47 * @param {Array.<*>} var_args Values to be assigined to %x markers. |
| 48 * @return {Object} Object which returns true for the expression: obj instanceof |
| 49 * pending. |
| 50 */ |
| 51 function pending(message, var_args) { |
| 52 var index = 1; |
| 53 var args = arguments; |
| 54 var formattedMessage = message.replace(/%[sdj]/g, function(pattern) { |
| 55 var arg = args[index++]; |
| 56 switch(pattern) { |
| 57 case '%s': return String(arg); |
| 58 case '%d': return Number(arg); |
| 59 case '%j': return JSON.stringify(arg); |
| 60 default: return pattern; |
| 61 } |
| 62 }); |
| 63 var pendingMarker = Object.create(pending.prototype); |
| 64 pendingMarker.message = formattedMessage; |
| 65 return pendingMarker; |
| 66 }; |
| 67 |
| 68 /** |
| 69 * Waits until the checkFunction returns a value but a pending marker. |
| 70 * @param {function():*} checkFunction Function to check a condition. It can |
| 71 * return a pending marker created by a pending function. |
| 72 * @return {Promise} Promise to be fulfilled with the return value of |
| 73 * checkFunction when the checkFunction reutrns a value but a pending |
| 74 * marker. |
| 75 */ |
| 76 function repeatUntil(checkFunction) { |
| 77 var logTime = Date.now() + LOG_INTERVAL; |
| 78 var step = function() { |
| 79 return Promise.resolve(checkFunction()).then(function(result) { |
| 80 if (result instanceof pending) { |
| 81 if (Date.now() > logTime) { |
| 82 console.log(result.message); |
| 83 logTime += LOG_INTERVAL; |
| 84 } |
| 85 return wait(REPEAT_UNTIL_INTERVAL).then(step); |
| 86 } else { |
| 87 return result; |
| 88 } |
| 89 }); |
| 90 }; |
| 91 return step(); |
| 92 }; |
| 93 |
| 94 /** |
| 95 * Adds the givin entries to the target volume(s). |
| 96 * @param {Array.<string>} volumeNames Names of target volumes. |
| 97 * @param {Array.<TestEntryInfo>} entries List of entries to be added. |
| 98 * @param {function(boolean)=} opt_callback Callback function to be passed the |
| 99 * result of function. The argument is true on success. |
| 100 * @return {Promise} Promise to be fulfilled when the entries are added. |
| 101 */ |
| 102 function addEntries(volumeNames, entries, opt_callback) { |
| 103 if (volumeNames.length == 0) { |
| 104 callback(true); |
| 105 return; |
| 106 } |
| 107 var volumeResultPromises = volumeNames.map(function(volume) { |
| 108 return sendTestMessage({ |
| 109 name: 'addEntries', |
| 110 volume: volume, |
| 111 entries: entries |
| 112 }).then(function(result) { |
| 113 if (result !== "onEntryAdded") |
| 114 return Promise.reject('Failed to add entries to ' + volume + '.'); |
| 115 }); |
| 116 }); |
| 117 var resultPromise = Promise.all(volumeResultPromises); |
| 118 if (opt_callback) { |
| 119 resultPromise.then(opt_callback.bind(null, true), |
| 120 opt_callback.bind(null, false)); |
| 121 } |
| 122 return resultPromise; |
| 123 }; |
| 124 |
| 125 /** |
| 126 * @enum {string} |
| 127 * @const |
| 128 */ |
| 129 var EntryType = Object.freeze({ |
| 130 FILE: 'file', |
| 131 DIRECTORY: 'directory' |
| 132 }); |
| 133 |
| 134 /** |
| 135 * @enum {string} |
| 136 * @const |
| 137 */ |
| 138 var SharedOption = Object.freeze({ |
| 139 NONE: 'none', |
| 140 SHARED: 'shared' |
| 141 }); |
| 142 |
| 143 /** |
| 144 * @enum {string} |
| 145 */ |
| 146 var RootPath = Object.seal({ |
| 147 DOWNLOADS: '/must-be-filled-in-test-setup', |
| 148 DRIVE: '/must-be-filled-in-test-setup', |
| 149 }); |
| 150 |
| 151 /** |
| 152 * File system entry information for tests. |
| 153 * |
| 154 * @param {EntryType} type Entry type. |
| 155 * @param {string} sourceFileName Source file name that provides file contents. |
| 156 * @param {string} targetName Name of entry on the test file system. |
| 157 * @param {string} mimeType Mime type. |
| 158 * @param {SharedOption} sharedOption Shared option. |
| 159 * @param {string} lastModifiedTime Last modified time as a text to be shown in |
| 160 * the last modified column. |
| 161 * @param {string} nameText File name to be shown in the name column. |
| 162 * @param {string} sizeText Size text to be shown in the size column. |
| 163 * @param {string} typeText Type name to be shown in the type column. |
| 164 * @constructor |
| 165 */ |
| 166 function TestEntryInfo(type, |
| 167 sourceFileName, |
| 168 targetPath, |
| 169 mimeType, |
| 170 sharedOption, |
| 171 lastModifiedTime, |
| 172 nameText, |
| 173 sizeText, |
| 174 typeText) { |
| 175 this.type = type; |
| 176 this.sourceFileName = sourceFileName || ''; |
| 177 this.targetPath = targetPath; |
| 178 this.mimeType = mimeType || ''; |
| 179 this.sharedOption = sharedOption; |
| 180 this.lastModifiedTime = lastModifiedTime; |
| 181 this.nameText = nameText; |
| 182 this.sizeText = sizeText; |
| 183 this.typeText = typeText; |
| 184 Object.freeze(this); |
| 185 }; |
| 186 |
| 187 TestEntryInfo.getExpectedRows = function(entries) { |
| 188 return entries.map(function(entry) { return entry.getExpectedRow(); }); |
| 189 }; |
| 190 |
| 191 /** |
| 192 * Obtains a expected row contents of the file in the file list. |
| 193 */ |
| 194 TestEntryInfo.prototype.getExpectedRow = function() { |
| 195 return [this.nameText, this.sizeText, this.typeText, this.lastModifiedTime]; |
| 196 }; |
| 197 |
| 198 /** |
| 199 * Filesystem entries used by the test cases. |
| 200 * @type {Object.<string, TestEntryInfo>} |
| 201 * @const |
| 202 */ |
| 203 var ENTRIES = { |
| 204 hello: new TestEntryInfo( |
| 205 EntryType.FILE, 'text.txt', 'hello.txt', |
| 206 'text/plain', SharedOption.NONE, 'Sep 4, 1998 12:34 PM', |
| 207 'hello.txt', '51 bytes', 'Plain text'), |
| 208 |
| 209 world: new TestEntryInfo( |
| 210 EntryType.FILE, 'video.ogv', 'world.ogv', |
| 211 'text/plain', SharedOption.NONE, 'Jul 4, 2012 10:35 AM', |
| 212 'world.ogv', '59 KB', 'OGG video'), |
| 213 |
| 214 unsupported: new TestEntryInfo( |
| 215 EntryType.FILE, 'random.bin', 'unsupported.foo', |
| 216 'application/x-foo', SharedOption.NONE, 'Jul 4, 2012 10:36 AM', |
| 217 'unsupported.foo', '8 KB', 'FOO file'), |
| 218 |
| 219 desktop: new TestEntryInfo( |
| 220 EntryType.FILE, 'image.png', 'My Desktop Background.png', |
| 221 'text/plain', SharedOption.NONE, 'Jan 18, 2038 1:02 AM', |
| 222 'My Desktop Background.png', '272 bytes', 'PNG image'), |
| 223 |
| 224 beautiful: new TestEntryInfo( |
| 225 EntryType.FILE, 'music.ogg', 'Beautiful Song.ogg', |
| 226 'text/plain', SharedOption.NONE, 'Nov 12, 2086 12:00 PM', |
| 227 'Beautiful Song.ogg', '14 KB', 'OGG audio'), |
| 228 |
| 229 photos: new TestEntryInfo( |
| 230 EntryType.DIRECTORY, null, 'photos', |
| 231 null, SharedOption.NONE, 'Jan 1, 1980 11:59 PM', |
| 232 'photos', '--', 'Folder'), |
| 233 |
| 234 testDocument: new TestEntryInfo( |
| 235 EntryType.FILE, null, 'Test Document', |
| 236 'application/vnd.google-apps.document', |
| 237 SharedOption.NONE, 'Apr 10, 2013 4:20 PM', |
| 238 'Test Document.gdoc', '--', 'Google document'), |
| 239 |
| 240 testSharedDocument: new TestEntryInfo( |
| 241 EntryType.FILE, null, 'Test Shared Document', |
| 242 'application/vnd.google-apps.document', |
| 243 SharedOption.SHARED, 'Mar 20, 2013 10:40 PM', |
| 244 'Test Shared Document.gdoc', '--', 'Google document'), |
| 245 |
| 246 newlyAdded: new TestEntryInfo( |
| 247 EntryType.FILE, 'music.ogg', 'newly added file.ogg', |
| 248 'audio/ogg', SharedOption.NONE, 'Sep 4, 1998 12:00 AM', |
| 249 'newly added file.ogg', '14 KB', 'OGG audio'), |
| 250 |
| 251 directoryA: new TestEntryInfo( |
| 252 EntryType.DIRECTORY, null, 'A', |
| 253 null, SharedOption.NONE, 'Jan 1, 2000 1:00 AM', |
| 254 'A', '--', 'Folder'), |
| 255 |
| 256 directoryB: new TestEntryInfo( |
| 257 EntryType.DIRECTORY, null, 'A/B', |
| 258 null, SharedOption.NONE, 'Jan 1, 2000 1:00 AM', |
| 259 'B', '--', 'Folder'), |
| 260 |
| 261 directoryC: new TestEntryInfo( |
| 262 EntryType.DIRECTORY, null, 'A/B/C', |
| 263 null, SharedOption.NONE, 'Jan 1, 2000 1:00 AM', |
| 264 'C', '--', 'Folder'), |
| 265 |
| 266 zipArchive: new TestEntryInfo( |
| 267 EntryType.FILE, 'archive.zip', 'archive.zip', |
| 268 'application/x-zip', SharedOption.NONE, 'Jan 1, 2014 1:00 AM', |
| 269 'archive.zip', '533 bytes', 'Zip archive') |
| 270 }; |
OLD | NEW |