1 // Copyright 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.
6 * Mock of MetadataProvider.
8 * @param {string} type Type of metadata provided by the class.
11 function MockProvider(type) {
12 MetadataProvider.call(this);
14 this.callbackPool = [];
18 MockProvider.prototype = {
19 __proto__: MetadataProvider.prototype
22 MockProvider.prototype.supportsEntry = function(entry) {
26 MockProvider.prototype.providesType = function(type) {
27 return type === this.type;
30 MockProvider.prototype.getId = function() {
34 MockProvider.prototype.fetch = function(entry, type, callback) {
35 this.callbackPool.push(callback);
39 * Short hand for the metadataCache.get.
41 * @param {MetadataCache} meatadataCache Metadata cache.
42 * @param {Array.<Entry>} entries Entries.
43 * @param {string} type Metadata type.
44 * @return {Promise} Promise to be fulfilled with the result metadata.
46 function getMetadata(metadataCache, entries, type) {
47 return new Promise(metadataCache.get.bind(metadataCache, entries, type));
51 * Short hand for the metadataCache.getLatest.
52 * @param {MetadataCache} meatadataCache Metadata cache.
53 * @param {Array.<Entry>} entries Entries.
54 * @param {string} type Metadata type.
55 * @return {Promise} Promise to be fulfilled with the result metadata.
57 function getLatest(metadataCache, entries, type) {
58 return new Promise(metadataCache.getLatest.bind(
59 metadataCache, entries, type));
63 * Invokes a callback function depending on the result of promise.
65 * @param {Promise} promise Promise.
66 * @param {function(boolean)} calllback Callback function. True is passed if the
69 function reportPromise(promise, callback) {
70 promise.then(function() {
71 callback(/* error */ false);
73 console.error(error.stack || error);
74 callback(/* error */ true);
79 * Confirms metadata is cached for the same entry.
81 * @param {function(boolean=)} callback Callback to be called when test
82 * completes. If the test fails, true is passed to the function.
84 function testCache(callback) {
85 var provider = new MockProvider('instrument');
86 var metadataCache = new MetadataCache([provider]);
87 var entry = new MockFileEntry('volumeId', '/music.txt');
89 var metadataFromProviderPromise =
90 getMetadata(metadataCache, [entry], 'instrument');
91 var cachedBeforeFetchingPromise =
92 getMetadata(metadataCache, [entry], 'instrument');
93 assertEquals(1, provider.callbackPool.length);
94 provider.callbackPool[0]({instrument: {name: 'banjo'}});
95 var cachedAfterFethingPromise =
96 getMetadata(metadataCache, [entry], 'instrument');
98 // Provide should be called only once.
99 assertEquals(1, provider.callbackPool.length);
101 reportPromise(Promise.all([
102 metadataFromProviderPromise,
103 cachedBeforeFetchingPromise,
104 cachedAfterFethingPromise
105 ]).then(function(metadata) {
106 assertDeepEquals([{name: 'banjo'}], metadata[0]);
107 assertDeepEquals([{name: 'banjo'}], metadata[1]);
108 assertDeepEquals([{name: 'banjo'}], metadata[1]);
113 * Confirms metadata is not cached for different entries.
115 * @param {function(boolean=)} callback Callback to be called when test
116 * completes. If the test fails, true is passed to the function.
118 function testNoCacheForDifferentEntries(callback) {
119 var provider = new MockProvider('instrument');
120 var metadataCache = new MetadataCache([provider]);
122 var entry1 = new MockFileEntry('volumeId', '/music1.txt');
123 var entry2 = new MockFileEntry('volumeId', '/music2.txt');
125 var entry1MetadataPromise =
126 getMetadata(metadataCache, [entry1], 'instrument');
127 var entry2MetadataPromise =
128 getMetadata(metadataCache, [entry2], 'instrument');
130 // Provide should be called for each entry.
131 assertEquals(2, provider.callbackPool.length);
133 provider.callbackPool[0]({instrument: {name: 'banjo'}});
134 provider.callbackPool[1]({instrument: {name: 'fiddle'}});
136 reportPromise(Promise.all([
137 entry1MetadataPromise,
138 entry2MetadataPromise
139 ]).then(function(metadata) {
140 assertDeepEquals([{name: 'banjo'}], metadata[0]);
141 assertDeepEquals([{name: 'fiddle'}], metadata[1]);
146 * Confirms metadata is not cached for different entries.
148 * @param {function(boolean=)} callback Callback to be called when test
149 * completes. If the test fails, true is passed to the function.
151 function testNoCacheForDifferentTypes(callback) {
153 new MockProvider('instrument'),
154 new MockProvider('beat')
156 var metadataCache = new MetadataCache(providers);
158 var entry = new MockFileEntry('volumeId', '/music.txt');
159 var instrumentMedatataPromise =
160 getMetadata(metadataCache, [entry], 'instrument');
161 var beatMetadataPromise = getMetadata(metadataCache, [entry], 'beat');
162 assertEquals(1, providers[0].callbackPool.length);
163 assertEquals(1, providers[1].callbackPool.length);
165 providers[0].callbackPool[0]({instrument: {name: 'banjo'}});
166 providers[1].callbackPool[0]({beat: {number: 2}});
167 reportPromise(Promise.all([
168 instrumentMedatataPromise,
170 ]).then(function(metadata) {
171 assertDeepEquals([{name: 'banjo'}], metadata[0]);
172 assertDeepEquals([{number: 2}], metadata[1]);
177 * Tests to call MetadataCache.get in verious order.
179 * @param {function(boolean=)} callback Callback to be called when test
180 * completes. If the test fails, true is passed to the function.
182 function testGetDiffrentTypesInVeriousOrders(callback) {
184 new MockProvider('instrument'),
185 new MockProvider('beat')
187 var metadataCache = new MetadataCache(providers);
189 var getAndCheckMetadata = function(entry, type, expected) {
190 return getMetadata(metadataCache, [entry], type).then(function(metadata) {
191 assertDeepEquals([expected], metadata);
195 var entry1 = new MockFileEntry('volumeId', '/music1.txt');
196 var promise1 = Promise.all([
197 getAndCheckMetadata(entry1, 'instrument', {name: 'banjo'}),
198 getAndCheckMetadata(entry1, 'beat', {number: 2}),
202 {instrument: {name: 'banjo'}, beat: {number: 2}})
204 assertEquals(1, providers[0].callbackPool.length);
205 assertEquals(1, providers[1].callbackPool.length);
207 var entry2 = new MockFileEntry('volumeId', '/music2.txt');
208 var promise2 = Promise.all([
209 getAndCheckMetadata(entry2, 'instrument', {name: 'banjo'}),
213 {instrument: {name: 'banjo'}, beat: {number: 2}}),
214 getAndCheckMetadata(entry2, 'beat', {number: 2})
216 assertEquals(2, providers[0].callbackPool.length);
217 assertEquals(2, providers[1].callbackPool.length);
219 var entry3 = new MockFileEntry('volumeId', '/music3.txt');
220 var promise3 = Promise.all([
224 {instrument: {name: 'banjo'}, beat: {number: 2}}),
225 getAndCheckMetadata(entry3, 'instrument', {name: 'banjo'}),
226 getAndCheckMetadata(entry3, 'beat', {number: 2})
228 assertEquals(3, providers[0].callbackPool.length);
229 assertEquals(3, providers[1].callbackPool.length);
231 for (var i = 0; i < providers[0].callbackPool.length; i++) {
232 providers[0].callbackPool[i]({instrument: {name: 'banjo'}});
234 for (var i = 0; i < providers[1].callbackPool.length; i++) {
235 providers[1].callbackPool[i]({beat: {number: 2}});
239 Promise.all([promise1, promise2, promise3]),
244 * Tests MetadataCache.getCached.
246 * @param {function(boolean=)} callback Callback to be called when test
247 * completes. If the test fails, true is passed to the function.
249 function testGetCached(callback) {
250 var provider = new MockProvider('instrument');
251 var metadataCache = new MetadataCache([provider]);
253 var entry = new MockFileEntry('volumeId', '/music.txt');
255 // Check the cache does exist before calling getMetadata.
256 assertEquals(null, metadataCache.getCached(entry, 'instrument'));
257 var promise = getMetadata(metadataCache, [entry], 'instrument');
259 // Check the cache does exist after calling getMetadata but before receiving
260 // metadata from a provider.
261 assertEquals(null, metadataCache.getCached(entry, 'instrument'));
263 provider.callbackPool[0]({instrument: {name: 'banjo'}});
264 reportPromise(promise.then(function(metadata) {
265 assertDeepEquals([{name: 'banjo'}], metadata);
268 metadataCache.getCached(entry, 'instrument'));
273 * Tests MetadataCache.getLatest.
275 * @param {function(boolean=)} callback Callback to be called when test
276 * completes. If the test fails, true is passed to the function.
278 function testGetLatest(callback) {
279 var provider = new MockProvider('instrument');
280 var metadataCache = new MetadataCache([provider]);
281 var entry = new MockFileEntry('volumeId', '/music.txt');
283 var promise = getLatest(metadataCache, [entry], 'instrument');
284 assertEquals(1, provider.callbackPool.length);
285 provider.callbackPool[0]({instrument: {name: 'banjo'}});
287 reportPromise(promise.then(function(metadata) {
288 assertDeepEquals([{name: 'banjo'}], metadata);
293 * Tests that MetadataCache.getLatest ignore the existing cache.
295 * @param {function(boolean=)} callback Callback to be called when test
296 * completes. If the test fails, true is passed to the function.
298 function testGetLatestToIgnoreCache(callback) {
299 var provider = new MockProvider('instrument');
300 var metadataCache = new MetadataCache([provider]);
301 var entry = new MockFileEntry('volumeId', '/music.txt');
303 var promise1 = getMetadata(metadataCache, [entry], 'instrument');
304 assertEquals(1, provider.callbackPool.length);
305 provider.callbackPool[0]({instrument: {name: 'banjo'}});
307 {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
308 var promise2 = getLatest(metadataCache, [entry], 'instrument');
309 assertEquals(2, provider.callbackPool.length);
311 {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
312 provider.callbackPool[1]({instrument: {name: 'fiddle'}});
314 {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument'));
316 reportPromise(Promise.all([promise1, promise2]).then(function(metadata) {
317 assertDeepEquals([{name: 'banjo'}], metadata[0]);
318 assertDeepEquals([{name: 'fiddle'}], metadata[1]);
323 * Tests that the result of getLatest does not passed to the previous call of
326 * @param {function(boolean=)} callback Callback to be called when test
327 * completes. If the test fails, true is passed to the function.
329 function testGetLatestAndPreviousCall(callback) {
330 var provider = new MockProvider('instrument');
331 var metadataCache = new MetadataCache([provider]);
332 var entry = new MockFileEntry('volumeId', '/music.txt');
334 var promise1 = getMetadata(metadataCache, [entry], 'instrument');
335 assertEquals(1, provider.callbackPool.length);
336 var promise2 = getLatest(metadataCache, [entry], 'instrument');
337 assertEquals(2, provider.callbackPool.length);
339 provider.callbackPool[1]({instrument: {name: 'fiddle'}});
340 provider.callbackPool[0]({instrument: {name: 'banjo'}});
342 {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
344 reportPromise(Promise.all([promise1, promise2]).then(function(metadata) {
345 assertDeepEquals([{name: 'banjo'}], metadata[0]);
346 assertDeepEquals([{name: 'fiddle'}], metadata[1]);
351 * Tests the MetadataCache#clear method.
353 * @param {function(boolean=)} callback Callback to be called when test
354 * completes. If the test fails, true is passed to the function.
356 function testClear(callback) {
358 new MockProvider('instrument'),
359 new MockProvider('beat')
361 var metadataCache = new MetadataCache(providers);
362 var entry = new MockFileEntry('volumeId', '/music.txt');
364 var promise1 = getMetadata(metadataCache, [entry], 'instrument');
365 var promise2 = getMetadata(metadataCache, [entry], 'beat');
366 assertEquals(1, providers[0].callbackPool.length);
367 assertEquals(1, providers[1].callbackPool.length);
368 providers[0].callbackPool[0]({instrument: {name: 'banjo'}});
369 providers[1].callbackPool[0]({beat: {number: 2}});
371 {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
372 assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat'));
374 metadataCache.clear([entry], 'instrument');
376 null, metadataCache.getCached(entry, 'instrument'));
377 assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat'));
379 var promise3 = getMetadata(metadataCache, [entry], 'instrument');
380 assertEquals(2, providers[0].callbackPool.length);
381 providers[0].callbackPool[1]({instrument: {name: 'fiddle'}});
383 {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument'));
385 reportPromise(Promise.all([promise1, promise2, promise3]).then(
387 assertDeepEquals([{name: 'banjo'}], metadata[0]);
388 assertDeepEquals([{number: 2}], metadata[1]);
389 assertDeepEquals([{name: 'fiddle'}], metadata[2]);
394 * Tests the MetadataCache#addObserver method.
396 function testAddObserver() {
398 new MockProvider('instrument'),
399 new MockProvider('beat')
401 var metadataCache = new MetadataCache(providers);
403 var directoryEntry = new MockFileEntry(
405 '/mu\\^$.*.+?|&{}[si]()<>cs');
406 var observerCalls = [];
407 var observerCallback = function(entries, properties) {
408 observerCalls.push({entries: entries, properties: properties});
411 metadataCache.addObserver(directoryEntry, MetadataCache.CHILDREN,
412 'filesystem', observerCallback);
414 var fileEntry1 = new MockFileEntry('volumeId',
415 '/mu\\^$.*.+?|&{}[si]()<>cs/foo.mp3');
416 var fileEntry1URL = fileEntry1.toURL();
417 metadataCache.set(fileEntry1, 'filesystem', 'test1');
418 assertEquals(1, observerCalls.length);
419 assertArrayEquals([fileEntry1], observerCalls[0].entries);
420 assertEquals('test1', observerCalls[0].properties[fileEntry1URL]);
422 var fileEntry2 = new MockFileEntry('volumeId',
423 '/mu\\^$.*.+?|&{}[si]()<>cs/f.[o]o.mp3');
424 var fileEntry2URL = fileEntry2.toURL();
425 metadataCache.set(fileEntry2, 'filesystem', 'test2');
426 assertEquals(2, observerCalls.length);
427 assertArrayEquals([fileEntry2], observerCalls[1].entries);
428 assertEquals('test2', observerCalls[1].properties[fileEntry2URL]);
430 // Descendant case does not invoke the observer.
431 var fileEntry3 = new MockFileEntry('volumeId',
432 '/mu\\^$.*.+?|&{}[si]()<>cs/foo/bar.mp3');
433 metadataCache.set(fileEntry3, 'filesystem', 'test3');
434 assertEquals(2, observerCalls.length);
436 // This case does not invoke the observer.
437 // (This is a case which matches when regexp special chars are not escaped).
438 var fileEntry4 = new MockFileEntry('volumeId', '/&{}i<>cs/foo.mp3');
439 metadataCache.set(fileEntry4);
440 assertEquals(2, observerCalls.length);