Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / test / data / file_manager / unit_tests / metadata_cache_unittest.js
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.
4
5 /**
6  * Mock of MetadataProvider.
7  *
8  * @param {string} type Type of metadata provided by the class.
9  * @constructor
10  */
11 function MockProvider(type) {
12   MetadataProvider.call(this);
13   this.type = type;
14   this.callbackPool = [];
15   Object.freeze(this);
16 }
17
18 MockProvider.prototype = {
19   __proto__: MetadataProvider.prototype
20 };
21
22 MockProvider.prototype.supportsEntry = function(entry) {
23   return true;
24 };
25
26 MockProvider.prototype.providesType = function(type) {
27   return type === this.type;
28 };
29
30 MockProvider.prototype.getId = function() {
31   return this.type;
32 };
33
34 MockProvider.prototype.fetch = function(entry, type, callback) {
35   this.callbackPool.push(callback);
36 };
37
38 /**
39  * Short hand for the metadataCache.get.
40  *
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.
45  */
46 function getMetadata(metadataCache, entries, type) {
47   return new Promise(metadataCache.get.bind(metadataCache, entries, type));
48 };
49
50 /**
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.
56  */
57 function getLatest(metadataCache, entries, type) {
58   return new Promise(metadataCache.getLatest.bind(
59       metadataCache, entries, type));
60 }
61
62 /**
63  * Invokes a callback function depending on the result of promise.
64  *
65  * @param {Promise} promise Promise.
66  * @param {function(boolean)} calllback Callback function. True is passed if the
67  * test failed.
68  */
69 function reportPromise(promise, callback) {
70   promise.then(function() {
71     callback(/* error */ false);
72   }, function(error) {
73     console.error(error.stack || error);
74     callback(/* error */ true);
75   });
76 }
77
78 /**
79  * Confirms metadata is cached for the same entry.
80  *
81  * @param {function(boolean=)} callback Callback to be called when test
82  *     completes. If the test fails, true is passed to the function.
83  */
84 function testCache(callback) {
85   var provider = new MockProvider('instrument');
86   var metadataCache = new MetadataCache([provider]);
87   var entry = new MockFileEntry('volumeId', '/music.txt');
88
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');
97
98   // Provide should be called only once.
99   assertEquals(1, provider.callbackPool.length);
100
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]);
109   }), callback);
110 }
111
112 /**
113  * Confirms metadata is not cached for different entries.
114  *
115  * @param {function(boolean=)} callback Callback to be called when test
116  *     completes. If the test fails, true is passed to the function.
117  */
118 function testNoCacheForDifferentEntries(callback) {
119   var provider = new MockProvider('instrument');
120   var metadataCache = new MetadataCache([provider]);
121
122   var entry1 = new MockFileEntry('volumeId', '/music1.txt');
123   var entry2 = new MockFileEntry('volumeId', '/music2.txt');
124
125   var entry1MetadataPromise =
126       getMetadata(metadataCache, [entry1], 'instrument');
127   var entry2MetadataPromise =
128       getMetadata(metadataCache, [entry2], 'instrument');
129
130   // Provide should be called for each entry.
131   assertEquals(2, provider.callbackPool.length);
132
133   provider.callbackPool[0]({instrument: {name: 'banjo'}});
134   provider.callbackPool[1]({instrument: {name: 'fiddle'}});
135
136   reportPromise(Promise.all([
137     entry1MetadataPromise,
138     entry2MetadataPromise
139   ]).then(function(metadata) {
140     assertDeepEquals([{name: 'banjo'}], metadata[0]);
141     assertDeepEquals([{name: 'fiddle'}], metadata[1]);
142   }), callback);
143 }
144
145 /**
146  * Confirms metadata is not cached for different entries.
147  *
148  * @param {function(boolean=)} callback Callback to be called when test
149  *     completes. If the test fails, true is passed to the function.
150  */
151 function testNoCacheForDifferentTypes(callback) {
152   var providers = [
153     new MockProvider('instrument'),
154     new MockProvider('beat')
155   ];
156   var metadataCache = new MetadataCache(providers);
157
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);
164
165   providers[0].callbackPool[0]({instrument: {name: 'banjo'}});
166   providers[1].callbackPool[0]({beat: {number: 2}});
167   reportPromise(Promise.all([
168     instrumentMedatataPromise,
169     beatMetadataPromise
170   ]).then(function(metadata) {
171     assertDeepEquals([{name: 'banjo'}], metadata[0]);
172     assertDeepEquals([{number: 2}], metadata[1]);
173   }), callback);
174 }
175
176 /**
177  * Tests to call MetadataCache.get in verious order.
178  *
179  * @param {function(boolean=)} callback Callback to be called when test
180  *     completes. If the test fails, true is passed to the function.
181  */
182 function testGetDiffrentTypesInVeriousOrders(callback) {
183   var providers = [
184     new MockProvider('instrument'),
185     new MockProvider('beat')
186   ];
187   var metadataCache = new MetadataCache(providers);
188
189   var getAndCheckMetadata = function(entry, type, expected) {
190     return getMetadata(metadataCache, [entry], type).then(function(metadata) {
191       assertDeepEquals([expected], metadata);
192     });
193   };
194
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}),
199     getAndCheckMetadata(
200         entry1,
201         'instrument|beat',
202         {instrument: {name: 'banjo'}, beat: {number: 2}})
203   ]);
204   assertEquals(1, providers[0].callbackPool.length);
205   assertEquals(1, providers[1].callbackPool.length);
206
207   var entry2 = new MockFileEntry('volumeId', '/music2.txt');
208   var promise2 = Promise.all([
209     getAndCheckMetadata(entry2, 'instrument', {name: 'banjo'}),
210     getAndCheckMetadata(
211         entry2,
212         'instrument|beat',
213         {instrument: {name: 'banjo'}, beat: {number: 2}}),
214     getAndCheckMetadata(entry2, 'beat', {number: 2})
215   ]);
216   assertEquals(2, providers[0].callbackPool.length);
217   assertEquals(2, providers[1].callbackPool.length);
218
219   var entry3 = new MockFileEntry('volumeId', '/music3.txt');
220   var promise3 = Promise.all([
221     getAndCheckMetadata(
222         entry3,
223         'instrument|beat',
224         {instrument: {name: 'banjo'}, beat: {number: 2}}),
225     getAndCheckMetadata(entry3, 'instrument', {name: 'banjo'}),
226     getAndCheckMetadata(entry3, 'beat', {number: 2})
227   ]);
228   assertEquals(3, providers[0].callbackPool.length);
229   assertEquals(3, providers[1].callbackPool.length);
230
231   for (var i = 0; i < providers[0].callbackPool.length; i++) {
232     providers[0].callbackPool[i]({instrument: {name: 'banjo'}});
233   }
234   for (var i = 0; i < providers[1].callbackPool.length; i++) {
235     providers[1].callbackPool[i]({beat: {number: 2}});
236   }
237
238   reportPromise(
239       Promise.all([promise1, promise2, promise3]),
240       callback);
241 }
242
243 /**
244  * Tests MetadataCache.getCached.
245  *
246  * @param {function(boolean=)} callback Callback to be called when test
247  *     completes. If the test fails, true is passed to the function.
248  */
249 function testGetCached(callback) {
250   var provider = new MockProvider('instrument');
251   var metadataCache = new MetadataCache([provider]);
252
253   var entry = new MockFileEntry('volumeId', '/music.txt');
254
255   // Check the cache does exist before calling getMetadata.
256   assertEquals(null, metadataCache.getCached(entry, 'instrument'));
257   var promise = getMetadata(metadataCache, [entry], 'instrument');
258
259   // Check the cache does exist after calling getMetadata but before receiving
260   // metadata from a provider.
261   assertEquals(null, metadataCache.getCached(entry, 'instrument'));
262
263   provider.callbackPool[0]({instrument: {name: 'banjo'}});
264   reportPromise(promise.then(function(metadata) {
265     assertDeepEquals([{name: 'banjo'}], metadata);
266     assertDeepEquals(
267         {name: 'banjo'},
268         metadataCache.getCached(entry, 'instrument'));
269   }), callback);
270 }
271
272 /**
273  * Tests MetadataCache.getLatest.
274  *
275  * @param {function(boolean=)} callback Callback to be called when test
276  *     completes. If the test fails, true is passed to the function.
277  */
278 function testGetLatest(callback) {
279   var provider = new MockProvider('instrument');
280   var metadataCache = new MetadataCache([provider]);
281   var entry = new MockFileEntry('volumeId', '/music.txt');
282
283   var promise = getLatest(metadataCache, [entry], 'instrument');
284   assertEquals(1, provider.callbackPool.length);
285   provider.callbackPool[0]({instrument: {name: 'banjo'}});
286
287   reportPromise(promise.then(function(metadata) {
288     assertDeepEquals([{name: 'banjo'}], metadata);
289   }), callback);
290 };
291
292 /**
293  * Tests that MetadataCache.getLatest ignore the existing cache.
294  *
295  * @param {function(boolean=)} callback Callback to be called when test
296  *     completes. If the test fails, true is passed to the function.
297  */
298 function testGetLatestToIgnoreCache(callback) {
299   var provider = new MockProvider('instrument');
300   var metadataCache = new MetadataCache([provider]);
301   var entry = new MockFileEntry('volumeId', '/music.txt');
302
303   var promise1 = getMetadata(metadataCache, [entry], 'instrument');
304   assertEquals(1, provider.callbackPool.length);
305   provider.callbackPool[0]({instrument: {name: 'banjo'}});
306   assertDeepEquals(
307       {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
308   var promise2 = getLatest(metadataCache, [entry], 'instrument');
309   assertEquals(2, provider.callbackPool.length);
310   assertDeepEquals(
311       {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
312   provider.callbackPool[1]({instrument: {name: 'fiddle'}});
313   assertDeepEquals(
314       {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument'));
315
316   reportPromise(Promise.all([promise1, promise2]).then(function(metadata) {
317     assertDeepEquals([{name: 'banjo'}], metadata[0]);
318     assertDeepEquals([{name: 'fiddle'}], metadata[1]);
319   }), callback);
320 }
321
322 /**
323  * Tests that the result of getLatest does not passed to the previous call of
324  * getMetadata.
325  *
326  * @param {function(boolean=)} callback Callback to be called when test
327  *     completes. If the test fails, true is passed to the function.
328  */
329 function testGetLatestAndPreviousCall(callback) {
330   var provider = new MockProvider('instrument');
331   var metadataCache = new MetadataCache([provider]);
332   var entry = new MockFileEntry('volumeId', '/music.txt');
333
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);
338
339   provider.callbackPool[1]({instrument: {name: 'fiddle'}});
340   provider.callbackPool[0]({instrument: {name: 'banjo'}});
341   assertDeepEquals(
342       {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
343
344   reportPromise(Promise.all([promise1, promise2]).then(function(metadata) {
345     assertDeepEquals([{name: 'banjo'}], metadata[0]);
346     assertDeepEquals([{name: 'fiddle'}], metadata[1]);
347   }), callback);
348 }
349
350 /**
351  * Tests the MetadataCache#clear method.
352  *
353  * @param {function(boolean=)} callback Callback to be called when test
354  *     completes. If the test fails, true is passed to the function.
355  */
356 function testClear(callback) {
357   var providers = [
358     new MockProvider('instrument'),
359     new MockProvider('beat')
360   ];
361   var metadataCache = new MetadataCache(providers);
362   var entry = new MockFileEntry('volumeId', '/music.txt');
363
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}});
370   assertDeepEquals(
371       {name: 'banjo'}, metadataCache.getCached(entry, 'instrument'));
372   assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat'));
373
374   metadataCache.clear([entry], 'instrument');
375   assertEquals(
376       null, metadataCache.getCached(entry, 'instrument'));
377   assertDeepEquals({number: 2}, metadataCache.getCached(entry, 'beat'));
378
379   var promise3 = getMetadata(metadataCache, [entry], 'instrument');
380   assertEquals(2, providers[0].callbackPool.length);
381   providers[0].callbackPool[1]({instrument: {name: 'fiddle'}});
382   assertDeepEquals(
383       {name: 'fiddle'}, metadataCache.getCached(entry, 'instrument'));
384
385   reportPromise(Promise.all([promise1, promise2, promise3]).then(
386       function(metadata) {
387         assertDeepEquals([{name: 'banjo'}], metadata[0]);
388         assertDeepEquals([{number: 2}], metadata[1]);
389         assertDeepEquals([{name: 'fiddle'}], metadata[2]);
390       }), callback);
391 }
392
393 /**
394  * Tests the MetadataCache#addObserver method.
395  */
396 function testAddObserver() {
397   var providers = [
398     new MockProvider('instrument'),
399     new MockProvider('beat')
400   ];
401   var metadataCache = new MetadataCache(providers);
402
403   var directoryEntry = new MockFileEntry(
404       'volumeId',
405       '/mu\\^$.*.+?|&{}[si]()<>cs');
406   var observerCalls = [];
407   var observerCallback = function(entries, properties) {
408     observerCalls.push({entries: entries, properties: properties});
409   };
410
411   metadataCache.addObserver(directoryEntry, MetadataCache.CHILDREN,
412       'filesystem', observerCallback);
413
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]);
421
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]);
429
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);
435
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);
441 }