arnaucube
arnaucube/openEventsPlatformAppPublic Self-hosted repository
openEventsPlatformApp/plugins/cordova-plugin-file/tests/tests.js
plugins/cordova-plugin-file/tests/tests.jsRaw
   1/*
   2 *
   3 * Licensed to the Apache Software Foundation (ASF) under one
   4 * or more contributor license agreements. See the NOTICE file
   5 * distributed with this work for additional information
   6 * regarding copyright ownership. The ASF licenses this file
   7 * to you under the Apache License, Version 2.0 (the
   8 * "License"); you may not use this file except in compliance
   9 * with the License. You may obtain a copy of the License at
  10 *
  11 * http://www.apache.org/licenses/LICENSE-2.0
  12 *
  13 * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an
  14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15 * KIND, either express or implied. See the License for the
  16 * specific language governing permissions and limitations
  17 * under the License.
  18 *
  19 */
  20
  21/* jshint jasmine: true */
  22/* global WebKitBlobBuilder */
  23
  24exports.defineAutoTests = function () {
  25    var isBrowser = (cordova.platformId === "browser");
  26    // Use feature detection to determine current browser instead of checking user-agent
  27    var isChrome = isBrowser && window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;
  28    var isIE = isBrowser && (window.msIndexedDB);
  29    var isIndexedDBShim = isBrowser && !isChrome;   // Firefox and IE for example
  30
  31    var isWindows = (cordova.platformId === "windows" || cordova.platformId === "windows8");
  32
  33    var MEDIUM_TIMEOUT = 15000;
  34
  35    describe('File API', function () {
  36        // Adding a Jasmine helper matcher, to report errors when comparing to FileError better.
  37        var fileErrorMap = {
  38            1 : 'NOT_FOUND_ERR',
  39            2 : 'SECURITY_ERR',
  40            3 : 'ABORT_ERR',
  41            4 : 'NOT_READABLE_ERR',
  42            5 : 'ENCODING_ERR',
  43            6 : 'NO_MODIFICATION_ALLOWED_ERR',
  44            7 : 'INVALID_STATE_ERR',
  45            8 : 'SYNTAX_ERR',
  46            9 : 'INVALID_MODIFICATION_ERR',
  47            10 : 'QUOTA_EXCEEDED_ERR',
  48            11 : 'TYPE_MISMATCH_ERR',
  49            12 : 'PATH_EXISTS_ERR'
  50        },
  51        root,
  52        temp_root,
  53        persistent_root;
  54        beforeEach(function (done) {
  55            // Custom Matchers
  56            jasmine.Expectation.addMatchers({
  57                toBeFileError : function () {
  58                    return {
  59                        compare : function (error, code) {
  60                            var pass = error.code === code;
  61                            return {
  62                                pass : pass,
  63                                message : 'Expected FileError with code ' + fileErrorMap[error.code] + ' (' + error.code + ') to be ' + fileErrorMap[code] + '(' + code + ')'
  64                            };
  65                        }
  66                    };
  67                },
  68                toCanonicallyMatch : function () {
  69                    return {
  70                        compare : function (currentPath, path) {
  71                            var a = path.split("/").join("").split("\\").join(""),
  72                            b = currentPath.split("/").join("").split("\\").join(""),
  73                            pass = a === b;
  74                            return {
  75                                pass : pass,
  76                                message : 'Expected paths to match : ' + path + ' should be ' + currentPath
  77                            };
  78                        }
  79                    };
  80                },
  81                toFailWithMessage : function () {
  82                    return {
  83                        compare : function (error, message) {
  84                            var pass = false;
  85                            return {
  86                                pass : pass,
  87                                message : message
  88                            };
  89                        }
  90                    };
  91                },
  92                toBeDataUrl: function () {
  93                    return {
  94                        compare : function (url) {
  95                            var pass = false;
  96                            // "data:application/octet-stream;base64,"
  97                            var header = url.substr(0, url.indexOf(','));
  98                            var headerParts = header.split(/[:;]/);
  99                            if (headerParts.length === 3 &&
 100                                headerParts[0] === 'data' &&
 101                                headerParts[2] === 'base64') {
 102                                pass = true;
 103                            }
 104                            var message = 'Expected ' + url + ' to be a valid data url. ' + header + ' is not valid header for data uris';
 105                            return {
 106                                pass : pass,
 107                                message : message
 108                            };
 109                        }
 110                    };
 111                }
 112            });
 113            //Define global variables
 114            var onError = function (e) {
 115                console.log('[ERROR] Problem setting up root filesystem for test running! Error to follow.');
 116                console.log(JSON.stringify(e));
 117            };
 118            window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
 119                root = fileSystem.root;
 120                // set in file.tests.js
 121                persistent_root = root;
 122                window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fileSystem) {
 123                    temp_root = fileSystem.root;
 124                    // set in file.tests.js
 125                    done();
 126                }, onError);
 127            }, onError);
 128        });
 129        // HELPER FUNCTIONS
 130        // deletes specified file or directory
 131        var deleteEntry = function (name, success, error) {
 132            // deletes entry, if it exists
 133            // entry.remove success callback is required: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#the-entry-interface
 134            success = success || function() {};
 135            error = error || failed.bind(null, success, 'deleteEntry failed.');
 136
 137            window.resolveLocalFileSystemURL(root.toURL() + '/' + name, function (entry) {
 138                if (entry.isDirectory === true) {
 139                    entry.removeRecursively(success, error);
 140                } else {
 141                    entry.remove(success, error);
 142                }
 143            }, success);
 144        };
 145        // deletes file, if it exists, then invokes callback
 146        var deleteFile = function (fileName, callback) {
 147            // entry.remove success callback is required: http://www.w3.org/TR/2011/WD-file-system-api-20110419/#the-entry-interface
 148            callback = callback || function() {};
 149
 150            root.getFile(fileName, null, // remove file system entry
 151                function (entry) {
 152                entry.remove(callback, function () {
 153                    console.log('[ERROR] deleteFile cleanup method invoked fail callback.');
 154                });
 155            }, // doesn't exist
 156                callback);
 157        };
 158        // deletes and re-creates the specified file
 159        var createFile = function (fileName, success, error) {
 160            deleteEntry(fileName, function () {
 161                root.getFile(fileName, {
 162                    create : true
 163                }, success, error);
 164            }, error);
 165        };
 166        // deletes and re-creates the specified directory
 167        var createDirectory = function (dirName, success, error) {
 168            deleteEntry(dirName, function () {
 169                root.getDirectory(dirName, {
 170                    create : true
 171                }, success, error);
 172            }, error);
 173        };
 174        function failed(done, msg, error) {
 175            var info = typeof msg == 'undefined' ? 'Unexpected error callback' : msg;
 176            var codeMsg = (error && error.code) ? (': ' + fileErrorMap[error.code]) : '';
 177            expect(true).toFailWithMessage(info + '\n' + JSON.stringify(error) + codeMsg);
 178            done();
 179        }
 180        var succeed = function (done, msg) {
 181            var info = typeof msg == 'undefined' ? 'Unexpected success callback' : msg;
 182            expect(true).toFailWithMessage(info);
 183            done();
 184        };
 185        var joinURL = function (base, extension) {
 186            if (base.charAt(base.length - 1) !== '/' && extension.charAt(0) !== '/') {
 187                return base + '/' + extension;
 188            }
 189            if (base.charAt(base.length - 1) === '/' && extension.charAt(0) === '/') {
 190                return base + extension.substring(1);
 191            }
 192            return base + extension;
 193        };
 194        describe('FileError object', function () {
 195            it("file.spec.1 should define FileError constants", function () {
 196                expect(FileError.NOT_FOUND_ERR).toBe(1);
 197                expect(FileError.SECURITY_ERR).toBe(2);
 198                expect(FileError.ABORT_ERR).toBe(3);
 199                expect(FileError.NOT_READABLE_ERR).toBe(4);
 200                expect(FileError.ENCODING_ERR).toBe(5);
 201                expect(FileError.NO_MODIFICATION_ALLOWED_ERR).toBe(6);
 202                expect(FileError.INVALID_STATE_ERR).toBe(7);
 203                expect(FileError.SYNTAX_ERR).toBe(8);
 204                expect(FileError.INVALID_MODIFICATION_ERR).toBe(9);
 205                expect(FileError.QUOTA_EXCEEDED_ERR).toBe(10);
 206                expect(FileError.TYPE_MISMATCH_ERR).toBe(11);
 207                expect(FileError.PATH_EXISTS_ERR).toBe(12);
 208            });
 209        });
 210        describe('LocalFileSystem', function () {
 211            it("file.spec.2 should define LocalFileSystem constants", function () {
 212                expect(LocalFileSystem.TEMPORARY).toBe(0);
 213                expect(LocalFileSystem.PERSISTENT).toBe(1);
 214            });
 215            describe('window.requestFileSystem', function () {
 216                it("file.spec.3 should be defined", function () {
 217                    expect(window.requestFileSystem).toBeDefined();
 218                });
 219                it("file.spec.4 should be able to retrieve a PERSISTENT file system", function (done) {
 220                    var win = function (fileSystem) {
 221                        expect(fileSystem).toBeDefined();
 222                        expect(fileSystem.name).toBeDefined();
 223                        if (isChrome) {
 224                            expect(fileSystem.name).toContain("Persistent");
 225                        } else {
 226                            expect(fileSystem.name).toBe("persistent");
 227                        }
 228                        expect(fileSystem.root).toBeDefined();
 229                        expect(fileSystem.root.filesystem).toBeDefined();
 230                        // Shouldn't use cdvfile by default.
 231                        expect(fileSystem.root.toURL()).not.toMatch(/^cdvfile:/);
 232                        // All DirectoryEntry URLs should always have a trailing slash.
 233                        expect(fileSystem.root.toURL()).toMatch(/\/$/);
 234                        done();
 235                    };
 236
 237                    // Request a little bit of space on the filesystem, unless we're running in a browser where that could cause a prompt.
 238                    var spaceRequired = isBrowser ? 0 : 1024;
 239
 240                    // retrieve PERSISTENT file system
 241                    window.requestFileSystem(LocalFileSystem.PERSISTENT, spaceRequired, win, failed.bind(null, done, 'window.requestFileSystem - Error retrieving PERSISTENT file system'));
 242                });
 243                it("file.spec.5 should be able to retrieve a TEMPORARY file system", function (done) {
 244                    var win = function (fileSystem) {
 245                        expect(fileSystem).toBeDefined();
 246                        if (isChrome) {
 247                            expect(fileSystem.name).toContain("Temporary");
 248                        } else {
 249                            expect(fileSystem.name).toBe("temporary");
 250                        }
 251                        expect(fileSystem.root).toBeDefined();
 252                        expect(fileSystem.root.filesystem).toBeDefined();
 253                        expect(fileSystem.root.filesystem).toBe(fileSystem);
 254                        done();
 255                    };
 256                    //retrieve TEMPORARY file system
 257                    window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, win, failed.bind(null, done, 'window.requestFileSystem - Error retrieving TEMPORARY file system'));
 258                });
 259                it("file.spec.6 should error if you request a file system that is too large", function (done) {
 260                    if (isBrowser) {
 261                        /*window.requestFileSystem TEMPORARY and PERSISTENT filesystem quota is not limited in Chrome.
 262                        Firefox filesystem size is not limited but every 50MB request user permission.
 263                        IE10 allows up to 10mb of combined AppCache and IndexedDB used in implementation
 264                        of filesystem without prompting, once you hit that level you will be asked if you
 265                        want to allow it to be increased up to a max of 250mb per site.
 266                        So `size` parameter for `requestFileSystem` function does not affect on filesystem in Firefox and IE.*/
 267                        pending();
 268                    }
 269
 270                    var fail = function (error) {
 271                        expect(error).toBeDefined();
 272                        expect(error).toBeFileError(FileError.QUOTA_EXCEEDED_ERR);
 273                        done();
 274                    };
 275                    //win = createWin('window.requestFileSystem');
 276                    // Request the file system
 277                    window.requestFileSystem(LocalFileSystem.TEMPORARY, 1000000000000000, failed.bind(null, done, 'window.requestFileSystem - Error retrieving TEMPORARY file system'), fail);
 278                });
 279                it("file.spec.7 should error out if you request a file system that does not exist", function (done) {
 280
 281                    var fail = function (error) {
 282                        expect(error).toBeDefined();
 283                        if (isChrome) {
 284                            /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of SYNTAX_ERR(code: 8)
 285                            on requesting of a non-existant filesystem.*/
 286                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
 287                        } else {
 288                            expect(error).toBeFileError(FileError.SYNTAX_ERR);
 289                        }
 290                        done();
 291                    };
 292                    // Request the file system
 293                    window.requestFileSystem(-1, 0, succeed.bind(null, done, 'window.requestFileSystem'), fail);
 294                });
 295            });
 296            describe('window.resolveLocalFileSystemURL', function () {
 297                it("file.spec.8 should be defined", function () {
 298                    expect(window.resolveLocalFileSystemURL).toBeDefined();
 299                });
 300                it("file.spec.9 should resolve a valid file name", function (done) {
 301                    var fileName = 'file.spec.9';
 302                    var win = function (fileEntry) {
 303                        expect(fileEntry).toBeDefined();
 304                        expect(fileEntry.isFile).toBe(true);
 305                        expect(fileEntry.isDirectory).toBe(false);
 306                        expect(fileEntry.name).toCanonicallyMatch(fileName);
 307                        expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL');
 308                        expect(fileEntry.toURL()).not.toMatch(/\/$/, 'URL should not end with a slash');
 309                        // Clean-up
 310                        deleteEntry(fileName, done);
 311                    };
 312                    createFile(fileName, function (entry) {
 313                        window.resolveLocalFileSystemURL(entry.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toURL()));
 314                    }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName), failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
 315                });
 316                it("file.spec.9.1 should resolve a file even with a terminating slash", function (done) {
 317                    var fileName = 'file.spec.9.1';
 318                    var win = function (fileEntry) {
 319                        expect(fileEntry).toBeDefined();
 320                        expect(fileEntry.isFile).toBe(true);
 321                        expect(fileEntry.isDirectory).toBe(false);
 322                        expect(fileEntry.name).toCanonicallyMatch(fileName);
 323                        expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL');
 324                        expect(fileEntry.toURL()).not.toMatch(/\/$/, 'URL should not end with a slash');
 325                        // Clean-up
 326                        deleteEntry(fileName, done);
 327                    };
 328                    createFile(fileName, function (entry) {
 329                        var entryURL = entry.toURL() + '/';
 330                        window.resolveLocalFileSystemURL(entryURL, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URL: ' + entryURL));
 331                    }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName), failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
 332                });
 333                it("file.spec.9.5 should resolve a directory", function (done) {
 334                    var fileName = 'file.spec.9.5';
 335                    var win = function (fileEntry) {
 336                        expect(fileEntry).toBeDefined();
 337                        expect(fileEntry.isFile).toBe(false);
 338                        expect(fileEntry.isDirectory).toBe(true);
 339                        expect(fileEntry.name).toCanonicallyMatch(fileName);
 340                        expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL');
 341                        expect(fileEntry.toURL()).toMatch(/\/$/, 'URL end with a slash');
 342                        // cleanup
 343                        deleteEntry(fileName, done);
 344                    };
 345                    function gotDirectory(entry) {
 346                        // lookup file system entry
 347                        window.resolveLocalFileSystemURL(entry.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving directory URL: ' + entry.toURL()));
 348                    }
 349                    createDirectory(fileName, gotDirectory, failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName), failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName));
 350                });
 351                it("file.spec.9.6 should resolve a directory even without a terminating slash", function (done) {
 352                    var fileName = 'file.spec.9.6';
 353                    var win = function (fileEntry) {
 354                        expect(fileEntry).toBeDefined();
 355                        expect(fileEntry.isFile).toBe(false);
 356                        expect(fileEntry.isDirectory).toBe(true);
 357                        expect(fileEntry.name).toCanonicallyMatch(fileName);
 358                        expect(fileEntry.toURL()).not.toMatch(/^cdvfile:/, 'should not use cdvfile URL');
 359                        expect(fileEntry.toURL()).toMatch(/\/$/, 'URL end with a slash');
 360                        // cleanup
 361                        deleteEntry(fileName, done);
 362                    };
 363                    function gotDirectory(entry) {
 364                        // lookup file system entry
 365                        var entryURL = entry.toURL();
 366                        entryURL = entryURL.substring(0, entryURL.length - 1);
 367                        window.resolveLocalFileSystemURL(entryURL, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving directory URL: ' + entryURL));
 368                    }
 369                    createDirectory(fileName, gotDirectory, failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName), failed.bind(null, done, 'createDirectory - Error creating directory: ' + fileName));
 370                });
 371
 372                it("file.spec.9.7 should resolve a file with valid nativeURL", function (done) {
 373                    var fileName = "de.create.file",
 374                    win = function (entry) {
 375                        var path = entry.nativeURL.split('///')[1];
 376                        expect(/\/{2,}/.test(path)).toBeFalsy();
 377                        // cleanup
 378                        deleteEntry(entry.name, done);
 379                    };
 380                    root.getFile(fileName, {
 381                        create: true
 382                    }, win, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName));
 383                });
 384
 385                it("file.spec.10 resolve valid file name with parameters", function (done) {
 386                    var fileName = "resolve.file.uri.params",
 387                    win = function (fileEntry) {
 388                        expect(fileEntry).toBeDefined();
 389                        if (fileEntry.toURL().toLowerCase().substring(0, 10) === "cdvfile://") {
 390                            expect(fileEntry.fullPath).toBe("/" + fileName + "?1234567890");
 391                        }
 392                        expect(fileEntry.name).toBe(fileName);
 393                        // cleanup
 394                        deleteEntry(fileName, done);
 395                    };
 396                    // create a new file entry
 397                    createFile(fileName, function (entry) {
 398                        window.resolveLocalFileSystemURL(entry.toURL() + "?1234567890", win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URI: ' + entry.toURL()));
 399                    }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
 400                });
 401                it("file.spec.11 should error (NOT_FOUND_ERR) when resolving (non-existent) invalid file name", function (done) {
 402                    var fileName = cordova.platformId === 'windowsphone' ? root.toURL() + "/" + "this.is.not.a.valid.file.txt" : joinURL(root.toURL(), "this.is.not.a.valid.file.txt"),
 403                        fail = function (error) {
 404                        expect(error).toBeDefined();
 405                        expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
 406                        done();
 407                    };
 408                    // lookup file system entry
 409                    window.resolveLocalFileSystemURL(fileName, succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Error unexpected callback resolving file URI: ' + fileName), fail);
 410                });
 411                it("file.spec.12 should error (ENCODING_ERR) when resolving invalid URI with leading /", function (done) {
 412                    var fileName = "/this.is.not.a.valid.url",
 413                        fail = function (error) {
 414                        expect(error).toBeDefined();
 415                        expect(error).toBeFileError(FileError.ENCODING_ERR);
 416                        done();
 417                    };
 418                    // lookup file system entry
 419                    window.resolveLocalFileSystemURL(fileName, succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Error unexpected callback resolving file URI: ' + fileName), fail);
 420                });
 421            });
 422        });
 423        //LocalFileSystem
 424        describe('Metadata interface', function () {
 425            it("file.spec.13 should exist and have the right properties", function () {
 426                var metadata = new Metadata();
 427                expect(metadata).toBeDefined();
 428                expect(metadata.modificationTime).toBeDefined();
 429            });
 430        });
 431        describe('Flags interface', function () {
 432            it("file.spec.14 should exist and have the right properties", function () {
 433                var flags = new Flags(false, true);
 434                expect(flags).toBeDefined();
 435                expect(flags.create).toBeDefined();
 436                expect(flags.create).toBe(false);
 437                expect(flags.exclusive).toBeDefined();
 438                expect(flags.exclusive).toBe(true);
 439            });
 440        });
 441        describe('FileSystem interface', function () {
 442            it("file.spec.15 should have a root that is a DirectoryEntry", function (done) {
 443                var win = function (entry) {
 444                    expect(entry).toBeDefined();
 445                    expect(entry.isFile).toBe(false);
 446                    expect(entry.isDirectory).toBe(true);
 447                    expect(entry.name).toBeDefined();
 448                    expect(entry.fullPath).toBeDefined();
 449                    expect(entry.getMetadata).toBeDefined();
 450                    expect(entry.moveTo).toBeDefined();
 451                    expect(entry.copyTo).toBeDefined();
 452                    expect(entry.toURL).toBeDefined();
 453                    expect(entry.remove).toBeDefined();
 454                    expect(entry.getParent).toBeDefined();
 455                    expect(entry.createReader).toBeDefined();
 456                    expect(entry.getFile).toBeDefined();
 457                    expect(entry.getDirectory).toBeDefined();
 458                    expect(entry.removeRecursively).toBeDefined();
 459                    done();
 460                };
 461                window.resolveLocalFileSystemURL(root.toURL(), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving file URI: ' + root.toURL()));
 462            });
 463        });
 464        describe('DirectoryEntry', function () {
 465            it("file.spec.16 getFile: get Entry for file that does not exist", function (done) {
 466                var fileName = "de.no.file",
 467                fail = function (error) {
 468                    expect(error).toBeDefined();
 469                    expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
 470                    done();
 471                };
 472                // create:false, exclusive:false, file does not exist
 473                root.getFile(fileName, {
 474                    create : false
 475                }, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName), fail);
 476            });
 477            it("file.spec.17 getFile: create new file", function (done) {
 478                var fileName = "de.create.file",
 479                filePath = joinURL(root.fullPath, fileName),
 480                win = function (entry) {
 481                    expect(entry).toBeDefined();
 482                    expect(entry.isFile).toBe(true);
 483                    expect(entry.isDirectory).toBe(false);
 484                    expect(entry.name).toCanonicallyMatch(fileName);
 485                    expect(entry.fullPath).toCanonicallyMatch(filePath);
 486                    // cleanup
 487                    deleteEntry(entry.name, done);
 488                };
 489                // create:true, exclusive:false, file does not exist
 490                root.getFile(fileName, {
 491                    create : true
 492                }, win, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName));
 493            });
 494            it("file.spec.18 getFile: create new file (exclusive)", function (done) {
 495                var fileName = "de.create.exclusive.file",
 496                filePath = joinURL(root.fullPath, fileName),
 497                win = function (entry) {
 498                    expect(entry).toBeDefined();
 499                    expect(entry.isFile).toBe(true);
 500                    expect(entry.isDirectory).toBe(false);
 501                    expect(entry.name).toBe(fileName);
 502                    expect(entry.fullPath).toCanonicallyMatch(filePath);
 503                    // cleanup
 504                    deleteEntry(entry.name, done);
 505                };
 506                // create:true, exclusive:true, file does not exist
 507                root.getFile(fileName, {
 508                    create : true,
 509                    exclusive : true
 510                }, win, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
 511            });
 512            it("file.spec.19 getFile: create file that already exists", function (done) {
 513                var fileName = "de.create.existing.file",
 514                filePath = joinURL(root.fullPath, fileName);
 515
 516                function win(entry) {
 517                    expect(entry).toBeDefined();
 518                    expect(entry.isFile).toBe(true);
 519                    expect(entry.isDirectory).toBe(false);
 520                    expect(entry.name).toCanonicallyMatch(fileName);
 521                    expect(entry.fullPath).toCanonicallyMatch(filePath);
 522                    // cleanup
 523                    deleteEntry(entry.name, done);
 524                }
 525
 526                function getFile(file) {
 527                    // create:true, exclusive:false, file exists
 528                    root.getFile(fileName, {
 529                        create : true
 530                    }, win, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
 531                }
 532
 533                // create file to kick off it
 534                root.getFile(fileName, {
 535                    create : true
 536                }, getFile, failed.bind(null, done, 'root.getFile - Error on initial creating file: ' + fileName));
 537            });
 538            it("file.spec.20 getFile: create file that already exists (exclusive)", function (done) {
 539                var fileName = "de.create.exclusive.existing.file",
 540                existingFile;
 541
 542                function fail(error) {
 543                    expect(error).toBeDefined();
 544                    if (isChrome) {
 545                        /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of PATH_EXISTS_ERR(code: 12)
 546                        on trying to exclusively create a file, which already exists in Chrome.*/
 547                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
 548                    } else {
 549                        expect(error).toBeFileError(FileError.PATH_EXISTS_ERR);
 550                    }
 551                    // cleanup
 552                    deleteEntry(existingFile.name, done);
 553                }
 554
 555                function getFile(file) {
 556                    existingFile = file;
 557                    // create:true, exclusive:true, file exists
 558                    root.getFile(fileName, {
 559                        create : true,
 560                        exclusive : true
 561                    }, succeed.bind(null, done, 'root.getFile - getFile function - Error unexpected callback, file should exists: ' + fileName), fail);
 562                }
 563
 564                // create file to kick off it
 565                root.getFile(fileName, {
 566                    create : true
 567                }, getFile, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
 568            });
 569            it("file.spec.21 DirectoryEntry.getFile: get Entry for existing file", function (done) {
 570                var fileName = "de.get.file",
 571                filePath = joinURL(root.fullPath, fileName),
 572                win = function (entry) {
 573                    expect(entry).toBeDefined();
 574                    expect(entry.isFile).toBe(true);
 575                    expect(entry.isDirectory).toBe(false);
 576                    expect(entry.name).toCanonicallyMatch(fileName);
 577                    expect(entry.fullPath).toCanonicallyMatch(filePath);
 578                    expect(entry.filesystem).toBeDefined();
 579                    expect(entry.filesystem).toBe(root.filesystem);
 580                    //clean up
 581                    deleteEntry(entry.name, done);
 582                },
 583                getFile = function (file) {
 584                    // create:false, exclusive:false, file exists
 585                    root.getFile(fileName, {
 586                        create : false
 587                    }, win, failed.bind(null, done, 'root.getFile - Error getting file entry: ' + fileName));
 588                };
 589                // create file to kick off it
 590                root.getFile(fileName, {
 591                    create : true
 592                }, getFile, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
 593            });
 594            it("file.spec.22 DirectoryEntry.getFile: get FileEntry for invalid path", function (done) {
 595                if (isBrowser) {
 596                    /*The plugin does not follow to ["8.3 Naming restrictions"]
 597                    (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions).*/
 598                    pending();
 599                }
 600
 601                var fileName = "de:invalid:path",
 602                fail = function (error) {
 603                    expect(error).toBeDefined();
 604                    expect(error).toBeFileError(FileError.ENCODING_ERR);
 605                    done();
 606                };
 607                // create:false, exclusive:false, invalid path
 608                root.getFile(fileName, {
 609                    create : false
 610                }, succeed.bind(null, done, 'root.getFile - Error unexpected callback, file should not exists: ' + fileName), fail);
 611            });
 612            it("file.spec.23 DirectoryEntry.getDirectory: get Entry for directory that does not exist", function (done) {
 613                var dirName = "de.no.dir",
 614                fail = function (error) {
 615                    expect(error).toBeDefined();
 616                    expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
 617                    done();
 618                };
 619                // create:false, exclusive:false, directory does not exist
 620                root.getDirectory(dirName, {
 621                    create : false
 622                }, succeed.bind(null, done, 'root.getDirectory - Error unexpected callback, directory should not exists: ' + dirName), fail);
 623            });
 624            it("file.spec.24 DirectoryEntry.getDirectory: create new dir with space then resolveLocalFileSystemURL", function (done) {
 625                var dirName = "de create dir";
 626
 627                function win(directory) {
 628                    expect(directory).toBeDefined();
 629                    expect(directory.isFile).toBe(false);
 630                    expect(directory.isDirectory).toBe(true);
 631                    expect(directory.name).toCanonicallyMatch(dirName);
 632                    expect(directory.fullPath).toCanonicallyMatch(joinURL(root.fullPath, dirName));
 633                    // cleanup
 634                    deleteEntry(directory.name, done);
 635                }
 636
 637                function getDir(dirEntry) {
 638                    expect(dirEntry.filesystem).toBeDefined();
 639                    expect(dirEntry.filesystem).toBe(root.filesystem);
 640                    var dirURI = dirEntry.toURL();
 641                    // now encode URI and try to resolve
 642                    window.resolveLocalFileSystemURL(dirURI, win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - getDir function - Error resolving directory: ' + dirURI));
 643                }
 644
 645                // create:true, exclusive:false, directory does not exist
 646                root.getDirectory(dirName, {
 647                    create : true
 648                }, getDir, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 649            });
 650            // This test is excluded, and should probably be removed. Filesystem
 651            // should always be properly encoded URLs, and *not* raw paths, and it
 652            // doesn't make sense to double-encode the URLs and expect that to be
 653            // handled by the implementation.
 654            // If a particular platform uses paths internally rather than URLs, // then that platform should careful to pass them correctly to its
 655            // backend.
 656            xit("file.spec.25 DirectoryEntry.getDirectory: create new dir with space resolveLocalFileSystemURL with encoded URI", function (done) {
 657                var dirName = "de create dir2",
 658                dirPath = joinURL(root.fullPath, dirName);
 659
 660                function win(directory) {
 661                    expect(directory).toBeDefined();
 662                    expect(directory.isFile).toBe(false);
 663                    expect(directory.isDirectory).toBe(true);
 664                    expect(directory.name).toCanonicallyMatch(dirName);
 665                    expect(directory.fullPath).toCanonicallyMatch(dirPath);
 666                    // cleanup
 667                    deleteEntry(directory.name, done);
 668                }
 669
 670                function getDir(dirEntry) {
 671                    var dirURI = dirEntry.toURL();
 672                    // now encode URI and try to resolve
 673                    window.resolveLocalFileSystemURL(encodeURI(dirURI), win, failed.bind(null, done, 'window.resolveLocalFileSystemURL - getDir function - Error resolving directory: ' + dirURI));
 674                }
 675
 676                // create:true, exclusive:false, directory does not exist
 677                root.getDirectory(dirName, {
 678                    create : true
 679                }, getDir, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 680            });
 681            it("file.spec.26 DirectoryEntry.getDirectory: create new directory", function (done) {
 682                var dirName = "de.create.dir",
 683                dirPath = joinURL(root.fullPath, dirName),
 684                win = function (directory) {
 685                    expect(directory).toBeDefined();
 686                    expect(directory.isFile).toBe(false);
 687                    expect(directory.isDirectory).toBe(true);
 688                    expect(directory.name).toCanonicallyMatch(dirName);
 689                    expect(directory.fullPath).toCanonicallyMatch(dirPath);
 690                    expect(directory.filesystem).toBeDefined();
 691                    expect(directory.filesystem).toBe(root.filesystem);
 692                    // cleanup
 693                    deleteEntry(directory.name, done);
 694                };
 695                // create:true, exclusive:false, directory does not exist
 696                root.getDirectory(dirName, {
 697                    create : true
 698                }, win, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 699            });
 700            it("file.spec.27 DirectoryEntry.getDirectory: create new directory (exclusive)", function (done) {
 701                var dirName = "de.create.exclusive.dir",
 702                dirPath = joinURL(root.fullPath, dirName),
 703                win = function (directory) {
 704                    expect(directory).toBeDefined();
 705                    expect(directory.isFile).toBe(false);
 706                    expect(directory.isDirectory).toBe(true);
 707                    expect(directory.name).toCanonicallyMatch(dirName);
 708                    expect(directory.fullPath).toCanonicallyMatch(dirPath);
 709                    expect(directory.filesystem).toBeDefined();
 710                    expect(directory.filesystem).toBe(root.filesystem);
 711                    // cleanup
 712                    deleteEntry(directory.name, done);
 713                };
 714                // create:true, exclusive:true, directory does not exist
 715                root.getDirectory(dirName, {
 716                    create : true,
 717                    exclusive : true
 718                }, win, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 719            });
 720            it("file.spec.28 DirectoryEntry.getDirectory: create directory that already exists", function (done) {
 721                var dirName = "de.create.existing.dir",
 722                dirPath = joinURL(root.fullPath, dirName),
 723                win = function (directory) {
 724                    expect(directory).toBeDefined();
 725                    expect(directory.isFile).toBe(false);
 726                    expect(directory.isDirectory).toBe(true);
 727                    expect(directory.name).toCanonicallyMatch(dirName);
 728                    expect(directory.fullPath).toCanonicallyMatch(dirPath);
 729                    // cleanup
 730                    deleteEntry(directory.name, done);
 731                };
 732                // create directory to kick off it
 733                root.getDirectory(dirName, {
 734                    create : true
 735                }, function () {
 736                    root.getDirectory(dirName, {
 737                        create : true
 738                    }, win, failed.bind(null, done, 'root.getDirectory - Error creating existent second directory : ' + dirName));
 739                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 740            });
 741            it("file.spec.29 DirectoryEntry.getDirectory: create directory that already exists (exclusive)", function (done) {
 742
 743                var dirName = "de.create.exclusive.existing.dir",
 744                existingDir,
 745                fail = function (error) {
 746                    expect(error).toBeDefined();
 747                    if (isChrome) {
 748                        /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of PATH_EXISTS_ERR(code: 12)
 749                        on trying to exclusively create a file or directory, which already exists (Chrome).*/
 750                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
 751                    } else {
 752                        expect(error).toBeFileError(FileError.PATH_EXISTS_ERR);
 753                    }
 754                    // cleanup
 755                    deleteEntry(existingDir.name, done);
 756                };
 757                // create directory to kick off it
 758                root.getDirectory(dirName, {
 759                    create : true
 760                }, function (directory) {
 761                    existingDir = directory;
 762                    // create:true, exclusive:true, directory exists
 763                    root.getDirectory(dirName, {
 764                        create : true,
 765                        exclusive : true
 766                    }, failed.bind(null, done, 'root.getDirectory - Unexpected success callback, second directory should not be created : ' + dirName), fail);
 767                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 768            });
 769            it("file.spec.30 DirectoryEntry.getDirectory: get Entry for existing directory", function (done) {
 770                var dirName = "de.get.dir",
 771                dirPath = joinURL(root.fullPath, dirName),
 772                win = function (directory) {
 773                    expect(directory).toBeDefined();
 774                    expect(directory.isFile).toBe(false);
 775                    expect(directory.isDirectory).toBe(true);
 776                    expect(directory.name).toCanonicallyMatch(dirName);
 777                    expect(directory.fullPath).toCanonicallyMatch(dirPath);
 778                    // cleanup
 779                    deleteEntry(directory.name, done);
 780                };
 781                // create directory to kick it off
 782                root.getDirectory(dirName, {
 783                    create : true
 784                }, function () {
 785                    root.getDirectory(dirName, {
 786                        create : false
 787                    }, win, failed.bind(null, done, 'root.getDirectory - Error getting directory entry : ' + dirName));
 788                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 789            });
 790            it("file.spec.31 DirectoryEntry.getDirectory: get DirectoryEntry for invalid path", function (done) {
 791                if (isBrowser) {
 792                    /*The plugin does not follow to ["8.3 Naming restrictions"]
 793                    (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions).*/
 794                    pending();
 795                }
 796
 797                var dirName = "de:invalid:path",
 798                fail = function (error) {
 799                    expect(error).toBeDefined();
 800                    expect(error).toBeFileError(FileError.ENCODING_ERR);
 801                    done();
 802                };
 803                // create:false, exclusive:false, invalid path
 804                root.getDirectory(dirName, {
 805                    create : false
 806                }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + dirName), fail);
 807            });
 808            it("file.spec.32 DirectoryEntry.getDirectory: get DirectoryEntry for existing file", function (done) {
 809                var fileName = "de.existing.file",
 810                existingFile,
 811                fail = function (error) {
 812                    expect(error).toBeDefined();
 813                    expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR);
 814                    // cleanup
 815                    deleteEntry(existingFile.name, done);
 816                };
 817                // create file to kick off it
 818                root.getFile(fileName, {
 819                    create : true
 820                }, function (file) {
 821                    existingFile = file;
 822                    root.getDirectory(fileName, {
 823                        create : false
 824                    }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + fileName), fail);
 825                }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
 826            });
 827            it("file.spec.33 DirectoryEntry.getFile: get FileEntry for existing directory", function (done) {
 828                var dirName = "de.existing.dir",
 829                existingDir,
 830                fail = function (error) {
 831                    expect(error).toBeDefined();
 832                    expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR);
 833                    // cleanup
 834                    deleteEntry(existingDir.name, done);
 835                };
 836                // create directory to kick off it
 837                root.getDirectory(dirName, {
 838                    create : true
 839                }, function (directory) {
 840                    existingDir = directory;
 841                    root.getFile(dirName, {
 842                        create : false
 843                    }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, file should not exists: ' + dirName), fail);
 844                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 845            });
 846            it("file.spec.34 DirectoryEntry.removeRecursively on directory", function (done) {
 847                var dirName = "de.removeRecursively",
 848                subDirName = "dir",
 849                dirExists = function (error) {
 850                    expect(error).toBeDefined();
 851                    expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
 852                    done();
 853                };
 854                // create a new directory entry to kick off it
 855                root.getDirectory(dirName, {
 856                    create : true
 857                }, function (entry) {
 858                    entry.getDirectory(subDirName, {
 859                        create : true
 860                    }, function (dir) {
 861                        entry.removeRecursively(function () {
 862                            root.getDirectory(dirName, {
 863                                create : false
 864                            }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory should not exists: ' + dirName), dirExists);
 865                        }, failed.bind(null, done, 'entry.removeRecursively - Error removing directory recursively : ' + dirName));
 866                    }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + subDirName));
 867                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 868            });
 869            it("file.spec.35 createReader: create reader on existing directory", function () {
 870                // create reader for root directory
 871                var reader = root.createReader();
 872                expect(reader).toBeDefined();
 873                expect(typeof reader.readEntries).toBe('function');
 874            });
 875            it("file.spec.36 removeRecursively on root file system", function (done) {
 876
 877                var remove = function (error) {
 878                    expect(error).toBeDefined();
 879                    if (isChrome) {
 880                        /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of
 881                        NO_MODIFICATION_ALLOWED_ERR(code: 6) on trying to call removeRecursively
 882                        on the root file system (Chrome).*/
 883                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
 884                    } else {
 885                        expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR);
 886                    }
 887                    done();
 888                };
 889                // remove root file system
 890                root.removeRecursively(succeed.bind(null, done, 'root.removeRecursively - Unexpected success callback, root cannot be removed'), remove);
 891            });
 892        });
 893        describe('DirectoryReader interface', function () {
 894            describe("readEntries", function () {
 895                it("file.spec.37 should read contents of existing directory", function (done) {
 896                    var reader,
 897                    win = function (entries) {
 898                        expect(entries).toBeDefined();
 899                        expect(entries instanceof Array).toBe(true);
 900                        done();
 901                    };
 902                    // create reader for root directory
 903                    reader = root.createReader();
 904                    // read entries
 905                    reader.readEntries(win, failed.bind(null, done, 'reader.readEntries - Error reading entries'));
 906                });
 907                it("file.spec.37.1 should read contents of existing directory", function (done) {
 908                    var dirName = 'readEntries.dir',
 909                    fileName = 'readeEntries.file';
 910                    root.getDirectory(dirName, {
 911                        create : true
 912                    }, function (directory) {
 913                        directory.getFile(fileName, {
 914                            create : true
 915                        }, function (fileEntry) {
 916                            var reader = directory.createReader();
 917                            reader.readEntries(function (entries) {
 918                                expect(entries).toBeDefined();
 919                                expect(entries instanceof Array).toBe(true);
 920                                expect(entries.length).toBe(1);
 921                                expect(entries[0].fullPath).toCanonicallyMatch(fileEntry.fullPath);
 922                                expect(entries[0].filesystem).not.toBe(null);
 923                                if (isChrome) {
 924                                    // Slicing '[object {type}]' -> '{type}'
 925                                    expect(entries[0].filesystem.toString().slice(8, -1)).toEqual("DOMFileSystem");
 926                                }
 927                                else {
 928                                    expect(entries[0].filesystem instanceof FileSystem).toBe(true);
 929                                }
 930
 931                                // cleanup
 932                                deleteEntry(directory.name, done);
 933                            }, failed.bind(null, done, 'reader.readEntries - Error reading entries from directory: ' + dirName));
 934                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + fileName));
 935                    }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 936                });
 937                it("file.spec.109 should return an empty entry list on the second call", function (done) {
 938                    var reader,
 939                    fileName = 'test109.txt';
 940                    // Add a file to ensure the root directory is non-empty and then read the contents of the directory.
 941                    root.getFile(fileName, {
 942                        create : true
 943                    }, function (entry) {
 944                        reader = root.createReader();
 945                        //First read
 946                        reader.readEntries(function (entries) {
 947                            expect(entries).toBeDefined();
 948                            expect(entries instanceof Array).toBe(true);
 949                            expect(entries.length).not.toBe(0);
 950                            //Second read
 951                            reader.readEntries(function (entries_) {
 952                                expect(entries_).toBeDefined();
 953                                expect(entries_ instanceof Array).toBe(true);
 954                                expect(entries_.length).toBe(0);
 955                                //Clean up
 956                                deleteEntry(entry.name, done);
 957                            }, failed.bind(null, done, 'reader.readEntries - Error during SECOND reading of entries from [root] directory'));
 958                        }, failed.bind(null, done, 'reader.readEntries - Error during FIRST reading of entries from [root] directory'));
 959                    }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
 960                });
 961            });
 962            it("file.spec.38 should read contents of directory that has been removed", function (done) {
 963                var dirName = "de.createReader.notfound";
 964                // create a new directory entry to kick off it
 965                root.getDirectory(dirName, {
 966                    create : true
 967                }, function (directory) {
 968                    directory.removeRecursively(function () {
 969                        var reader = directory.createReader();
 970                        reader.readEntries(succeed.bind(null, done, 'reader.readEntries - Unexpected success callback, it should not read entries from deleted dir: ' + dirName), function (error) {
 971                            expect(error).toBeDefined();
 972                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
 973                            root.getDirectory(dirName, {
 974                                create : false
 975                            }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, it should not get deleted directory: ' + dirName), function (err) {
 976                                expect(err).toBeDefined();
 977                                expect(err).toBeFileError(FileError.NOT_FOUND_ERR);
 978                                done();
 979                            });
 980                        });
 981                    }, failed.bind(null, done, 'directory.removeRecursively - Error removing directory recursively : ' + dirName));
 982                }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dirName));
 983            });
 984        });
 985        //DirectoryReader interface
 986        describe('File', function () {
 987            it("file.spec.39 constructor should be defined", function () {
 988                expect(File).toBeDefined();
 989                expect(typeof File).toBe('function');
 990            });
 991            it("file.spec.40 should be define File attributes", function () {
 992                var file = new File();
 993                expect(file.name).toBeDefined();
 994                expect(file.type).toBeDefined();
 995                expect(file.lastModifiedDate).toBeDefined();
 996                expect(file.size).toBeDefined();
 997            });
 998        });
 999        //File
1000        describe('FileEntry', function () {
1001
1002            it("file.spec.41 should be define FileEntry methods", function (done) {
1003                var fileName = "fe.methods",
1004                testFileEntry = function (fileEntry) {
1005                    expect(fileEntry).toBeDefined();
1006                    expect(typeof fileEntry.createWriter).toBe('function');
1007                    expect(typeof fileEntry.file).toBe('function');
1008                    // cleanup
1009                    deleteEntry(fileEntry.name, done);
1010                };
1011                // create a new file entry to kick off it
1012                root.getFile(fileName, {
1013                    create : true
1014                }, testFileEntry, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
1015            });
1016            it("file.spec.42 createWriter should return a FileWriter object", function (done) {
1017                var fileName = "fe.createWriter",
1018                testFile,
1019                testWriter = function (writer) {
1020                    expect(writer).toBeDefined();
1021                    if (isChrome) {
1022                        // Slicing '[object {type}]' -> '{type}'
1023                        expect(writer.toString().slice(8, -1)).toEqual("FileWriter");
1024                    }
1025                    else {
1026                        expect(writer instanceof FileWriter).toBe(true);
1027                    }
1028
1029                    // cleanup
1030                    deleteEntry(testFile.name, done);
1031                };
1032                // create a new file entry to kick off it
1033                root.getFile(fileName, {
1034                    create : true
1035                }, function (fileEntry) {
1036                    testFile = fileEntry;
1037                    fileEntry.createWriter(testWriter, failed.bind(null, done, 'fileEntry.createWriter - Error creating Writer from entry'));
1038                }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
1039            });
1040            it("file.spec.43 file should return a File object", function (done) {
1041                var fileName = "fe.file",
1042                newFile,
1043                testFile = function (file) {
1044                    expect(file).toBeDefined();
1045                    if (isChrome) {
1046                        // Slicing '[object {type}]' -> '{type}'
1047                        expect(file.toString().slice(8, -1)).toEqual("File");
1048                    }
1049                    else {
1050                        expect(file instanceof File).toBe(true);
1051                    }
1052
1053                    // cleanup
1054                    deleteEntry(newFile.name, done);
1055                };
1056                // create a new file entry to kick off it
1057                root.getFile(fileName, {
1058                    create : true
1059                }, function (fileEntry) {
1060                    newFile = fileEntry;
1061                    fileEntry.file(testFile, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name));
1062                }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
1063            });
1064            it("file.spec.44 file: on File that has been removed", function (done) {
1065                var fileName = "fe.no.file";
1066                // create a new file entry to kick off it
1067                root.getFile(fileName, {
1068                    create : true
1069                }, function (fileEntry) {
1070                    fileEntry.remove(function () {
1071                        fileEntry.file(succeed.bind(null, done, 'fileEntry.file - Unexpected success callback, file it should not be created from removed entry'), function (error) {
1072                            expect(error).toBeDefined();
1073                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1074                            done();
1075                        });
1076                    }, failed.bind(null, done, 'fileEntry.remove - Error removing entry : ' + fileName));
1077                }, failed.bind(null, done, 'root.getFile - Error creating file : ' + fileName));
1078            });
1079        });
1080        //FileEntry
1081        describe('Entry', function () {
1082            it("file.spec.45 Entry object", function (done) {
1083                var fileName = "entry",
1084                fullPath = joinURL(root.fullPath, fileName),
1085                winEntry = function (entry) {
1086                    expect(entry).toBeDefined();
1087                    expect(entry.isFile).toBe(true);
1088                    expect(entry.isDirectory).toBe(false);
1089                    expect(entry.name).toCanonicallyMatch(fileName);
1090                    expect(entry.fullPath).toCanonicallyMatch(fullPath);
1091                    expect(typeof entry.getMetadata).toBe('function');
1092                    expect(typeof entry.setMetadata).toBe('function');
1093                    expect(typeof entry.moveTo).toBe('function');
1094                    expect(typeof entry.copyTo).toBe('function');
1095                    expect(typeof entry.toURL).toBe('function');
1096                    expect(typeof entry.remove).toBe('function');
1097                    expect(typeof entry.getParent).toBe('function');
1098                    expect(typeof entry.createWriter).toBe('function');
1099                    expect(typeof entry.file).toBe('function');
1100                    // Clean up
1101                    deleteEntry(fileName, done);
1102                };
1103                // create a new file entry
1104                createFile(fileName, winEntry, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1105            });
1106            it("file.spec.46 Entry.getMetadata on file", function (done) {
1107                var fileName = "entry.metadata.file";
1108                // create a new file entry
1109                createFile(fileName, function (entry) {
1110                    entry.getMetadata(function (metadata) {
1111                        expect(metadata).toBeDefined();
1112                        expect(metadata.modificationTime instanceof Date).toBe(true);
1113                        expect(typeof metadata.size).toBe("number");
1114                        // cleanup
1115                        deleteEntry(fileName, done);
1116                    }, failed.bind(null, done, 'entry.getMetadata - Error getting metadata from entry : ' + fileName));
1117                }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1118            });
1119            it("file.spec.47 Entry.getMetadata on directory", function (done) {
1120                if (isIndexedDBShim) {
1121                    /* Does not support metadata for directories (Firefox, IE) */
1122                    pending();
1123                }
1124
1125                var dirName = "entry.metadata.dir";
1126                // create a new directory entry
1127                createDirectory(dirName, function (entry) {
1128                    entry.getMetadata(function (metadata) {
1129                        expect(metadata).toBeDefined();
1130                        expect(metadata.modificationTime instanceof Date).toBe(true);
1131                        expect(typeof metadata.size).toBe("number");
1132                        expect(metadata.size).toBe(0);
1133                        // cleanup
1134                        deleteEntry(dirName, done);
1135                    }, failed.bind(null, done, 'entry.getMetadata - Error getting metadata from entry : ' + dirName));
1136                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName));
1137            });
1138            it("file.spec.48 Entry.getParent on file in root file system", function (done) {
1139                var fileName = "entry.parent.file",
1140                rootPath = root.fullPath;
1141                // create a new file entry
1142                createFile(fileName, function (entry) {
1143                    entry.getParent(function (parent) {
1144                        expect(parent).toBeDefined();
1145                        expect(parent.fullPath).toCanonicallyMatch(rootPath);
1146                        // cleanup
1147                        deleteEntry(fileName, done);
1148                    }, failed.bind(null, done, 'entry.getParent - Error getting parent directory of file : ' + fileName));
1149                }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1150            });
1151            it("file.spec.49 Entry.getParent on directory in root file system", function (done) {
1152                var dirName = "entry.parent.dir",
1153                rootPath = root.fullPath;
1154                // create a new directory entry
1155                createDirectory(dirName, function (entry) {
1156                    entry.getParent(function (parent) {
1157                        expect(parent).toBeDefined();
1158                        expect(parent.fullPath).toCanonicallyMatch(rootPath);
1159                        // cleanup
1160                        deleteEntry(dirName, done);
1161                    }, failed.bind(null, done, 'entry.getParent - Error getting parent directory of directory : ' + dirName));
1162                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName));
1163            });
1164            it("file.spec.50 Entry.getParent on root file system", function (done) {
1165                var rootPath = root.fullPath,
1166                winParent = function (parent) {
1167                    expect(parent).toBeDefined();
1168                    expect(parent.fullPath).toCanonicallyMatch(rootPath);
1169                    done();
1170                };
1171                // create a new directory entry
1172                root.getParent(winParent, failed.bind(null, done, 'root.getParent - Error getting parent directory of root'));
1173            });
1174            it("file.spec.51 Entry.toURL on file", function (done) {
1175                var fileName = "entry.uri.file",
1176                rootPath = root.fullPath,
1177                winURI = function (entry) {
1178                    var uri = entry.toURL();
1179                    expect(uri).toBeDefined();
1180                    expect(uri.indexOf(rootPath)).not.toBe(-1);
1181                    // cleanup
1182                    deleteEntry(fileName, done);
1183                };
1184                // create a new file entry
1185                createFile(fileName, winURI, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1186            });
1187            it("file.spec.52 Entry.toURL on directory", function (done) {
1188                var dirName_1 = "num 1",
1189                dirName_2 = "num 2",
1190                rootPath = root.fullPath;
1191                createDirectory(dirName_1, function (entry) {
1192                    entry.getDirectory(dirName_2, {
1193                        create : true
1194                    }, function (entryFile) {
1195                        var uri = entryFile.toURL();
1196                        expect(uri).toBeDefined();
1197                        expect(uri).toContain('/num%201/num%202/');
1198                        expect(uri.indexOf(rootPath)).not.toBe(-1);
1199                        // cleanup
1200                        deleteEntry(dirName_1, done);
1201                    }, failed.bind(null, done, 'entry.getDirectory - Error creating directory : ' + dirName_2));
1202                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName_1));
1203            });
1204            it("file.spec.53 Entry.remove on file", function (done) {
1205                var fileName = "entr .rm.file";
1206                // create a new file entry
1207                createFile(fileName, function (entry) {
1208                    expect(entry).toBeDefined();
1209                    entry.remove(function () {
1210                        root.getFile(fileName, null, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get deleted file : ' + fileName), function (error) {
1211                            expect(error).toBeDefined();
1212                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1213                            // cleanup
1214                            deleteEntry(fileName, done);
1215                        });
1216                    }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + fileName));
1217                }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1218            });
1219            it("file.spec.53.1 Entry.remove on filename with #s", function (done) {
1220                var fileName = "entry.#rm#.file";
1221                // create a new file entry
1222                createFile(fileName, function (entry) {
1223                    expect(entry).toBeDefined();
1224                    entry.remove(function () {
1225                        root.getFile(fileName, null, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get deleted file : ' + fileName), function (error) {
1226                            expect(error).toBeDefined();
1227                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1228                            // cleanup
1229                            deleteEntry(fileName, done);
1230                        });
1231                    }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + fileName));
1232                }, failed.bind(null, done, 'createFile - Error creating file : ' + fileName));
1233            });
1234            it("file.spec.54 remove on empty directory", function (done) {
1235                var dirName = "entry.rm.dir";
1236                // create a new directory entry
1237                createDirectory(dirName, function (entry) {
1238                    expect(entry).toBeDefined();
1239                    entry.remove(function () {
1240                        root.getDirectory(dirName, null, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, it should not get deleted directory : ' + dirName), function (error) {
1241                            expect(error).toBeDefined();
1242                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1243                            // cleanup
1244                            deleteEntry(dirName, done);
1245                        });
1246                    }, failed.bind(null, done, 'entry.remove - Error removing entry : ' + dirName));
1247                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName));
1248            });
1249            it("file.spec.55 remove on non-empty directory", function (done) {
1250                if (isIndexedDBShim) {
1251                    /* Both Entry.remove and directoryEntry.removeRecursively don't fail when removing
1252                    non-empty directories - directories being removed are cleaned
1253                    along with contents instead (Firefox, IE)*/
1254                    pending();
1255                }
1256
1257                var dirName = "ent y.rm.dir.not.empty",
1258                fileName = "re ove.txt",
1259                fullPath = joinURL(root.fullPath, dirName);
1260                // create a new directory entry
1261                createDirectory(dirName, function (entry) {
1262                    entry.getFile(fileName, {
1263                        create : true
1264                    }, function (fileEntry) {
1265                        entry.remove(succeed.bind(null, done, 'entry.remove - Unexpected success callback, it should not remove a directory that contains files : ' + dirName), function (error) {
1266                            expect(error).toBeDefined();
1267                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1268                            root.getDirectory(dirName, null, function (entry) {
1269                                expect(entry).toBeDefined();
1270                                expect(entry.fullPath).toCanonicallyMatch(fullPath);
1271                                // cleanup
1272                                deleteEntry(dirName, done);
1273                            }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + dirName));
1274                        });
1275                    }, failed.bind(null, done, 'entry.getFile - Error creating file : ' + fileName + ' inside of ' + dirName));
1276                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName));
1277            });
1278            it("file.spec.56 remove on root file system", function (done) {
1279
1280                // remove entry that doesn't exist
1281                root.remove(succeed.bind(null, done, 'entry.remove - Unexpected success callback, it should not remove entry that it does not exists'), function (error) {
1282                    expect(error).toBeDefined();
1283                    if (isChrome) {
1284                        /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of
1285                        NO_MODIFICATION_ALLOWED_ERR(code: 6) on trying to call removeRecursively
1286                        on the root file system.*/
1287                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1288                    } else {
1289                        expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR);
1290                    }
1291                    done();
1292                });
1293            });
1294            it("file.spec.57 copyTo: file", function (done) {
1295                var file1 = "entry copy.file1",
1296                file2 = "entry copy.file2",
1297                fullPath = joinURL(root.fullPath, file2);
1298                // create a new file entry to kick off it
1299                deleteEntry(file2, function () {
1300                    createFile(file1, function (fileEntry) {
1301                        // copy file1 to file2
1302                        fileEntry.copyTo(root, file2, function (entry) {
1303                            expect(entry).toBeDefined();
1304                            expect(entry.isFile).toBe(true);
1305                            expect(entry.isDirectory).toBe(false);
1306                            expect(entry.fullPath).toCanonicallyMatch(fullPath);
1307                            expect(entry.name).toCanonicallyMatch(file2);
1308                            root.getFile(file2, {
1309                                create : false
1310                            }, function (entry2) {
1311                                expect(entry2).toBeDefined();
1312                                expect(entry2.isFile).toBe(true);
1313                                expect(entry2.isDirectory).toBe(false);
1314                                expect(entry2.fullPath).toCanonicallyMatch(fullPath);
1315                                expect(entry2.name).toCanonicallyMatch(file2);
1316                                // cleanup
1317                                deleteEntry(file1, function () {
1318                                    deleteEntry(file2, done);
1319                                });
1320                            }, failed.bind(null, done, 'root.getFile - Error getting copied file : ' + file2));
1321                        }, failed.bind(null, done, 'fileEntry.copyTo - Error copying file : ' + file2));
1322                    }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1323                }, failed.bind(null, done, 'deleteEntry - Error removing file : ' + file2));
1324            });
1325            it("file.spec.58 copyTo: file onto itself", function (done) {
1326                var file1 = "entry.copy.fos.file1";
1327                // create a new file entry to kick off it
1328                createFile(file1, function (entry) {
1329                    // copy file1 onto itself
1330                    entry.copyTo(root, null, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy a null file'), function (error) {
1331                        expect(error).toBeDefined();
1332                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1333                        // cleanup
1334                        deleteEntry(file1, done);
1335                    });
1336                }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1337            });
1338            it("file.spec.59 copyTo: directory", function (done) {
1339                if (isIndexedDBShim) {
1340                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1341                    pending();
1342                }
1343
1344                var file1 = "file1",
1345                srcDir = "entry.copy.srcDir",
1346                dstDir = "entry.copy.dstDir",
1347                dstPath = joinURL(root.fullPath, dstDir),
1348                filePath = joinURL(dstPath, file1);
1349                // create a new directory entry to kick off it
1350                deleteEntry(dstDir, function () {
1351                    createDirectory(srcDir, function (directory) {
1352                        // create a file within new directory
1353                        directory.getFile(file1, {
1354                            create : true
1355                        }, function () {
1356                            directory.copyTo(root, dstDir, function (directory) {
1357                                expect(directory).toBeDefined();
1358                                expect(directory.isFile).toBe(false);
1359                                expect(directory.isDirectory).toBe(true);
1360                                expect(directory.fullPath).toCanonicallyMatch(dstPath);
1361                                expect(directory.name).toCanonicallyMatch(dstDir);
1362                                root.getDirectory(dstDir, {
1363                                    create : false
1364                                }, function (dirEntry) {
1365                                    expect(dirEntry).toBeDefined();
1366                                    expect(dirEntry.isFile).toBe(false);
1367                                    expect(dirEntry.isDirectory).toBe(true);
1368                                    expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
1369                                    expect(dirEntry.name).toCanonicallyMatch(dstDir);
1370                                    dirEntry.getFile(file1, {
1371                                        create : false
1372                                    }, function (fileEntry) {
1373                                        expect(fileEntry).toBeDefined();
1374                                        expect(fileEntry.isFile).toBe(true);
1375                                        expect(fileEntry.isDirectory).toBe(false);
1376                                        expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1377                                        expect(fileEntry.name).toCanonicallyMatch(file1);
1378                                        // cleanup
1379                                        deleteEntry(srcDir, function () {
1380                                            deleteEntry(dstDir, done);
1381                                        });
1382                                    }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1));
1383                                }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory : ' + dstDir));
1384                            }, failed.bind(null, done, 'directory.copyTo - Error copying directory : ' + srcDir + ' to :' + dstDir));
1385                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1386                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1387                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1388            });
1389            it("file.spec.60 copyTo: directory to backup at same root directory", function (done) {
1390                if (isIndexedDBShim) {
1391                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1392                    pending();
1393                }
1394
1395                var file1 = "file1",
1396                srcDir = "entry.copy srcDirSame",
1397                dstDir = "entry.copy srcDirSame-backup",
1398                dstPath = joinURL(root.fullPath, dstDir),
1399                filePath = joinURL(dstPath, file1);
1400                // create a new directory entry to kick off it
1401                deleteEntry(dstDir, function () {
1402                    createDirectory(srcDir, function (directory) {
1403                        directory.getFile(file1, {
1404                            create : true
1405                        }, function () {
1406                            directory.copyTo(root, dstDir, function (directory) {
1407                                expect(directory).toBeDefined();
1408                                expect(directory.isFile).toBe(false);
1409                                expect(directory.isDirectory).toBe(true);
1410                                expect(directory.fullPath).toCanonicallyMatch(dstPath);
1411                                expect(directory.name).toCanonicallyMatch(dstDir);
1412                                root.getDirectory(dstDir, {
1413                                    create : false
1414                                }, function (dirEntry) {
1415                                    expect(dirEntry).toBeDefined();
1416                                    expect(dirEntry.isFile).toBe(false);
1417                                    expect(dirEntry.isDirectory).toBe(true);
1418                                    expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
1419                                    expect(dirEntry.name).toCanonicallyMatch(dstDir);
1420                                    dirEntry.getFile(file1, {
1421                                        create : false
1422                                    }, function (fileEntry) {
1423                                        expect(fileEntry).toBeDefined();
1424                                        expect(fileEntry.isFile).toBe(true);
1425                                        expect(fileEntry.isDirectory).toBe(false);
1426                                        expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1427                                        expect(fileEntry.name).toCanonicallyMatch(file1);
1428                                        // cleanup
1429                                        deleteEntry(srcDir, function () {
1430                                            deleteEntry(dstDir, done);
1431                                        });
1432                                    }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1));
1433                                }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory : ' + dstDir));
1434                            }, failed.bind(null, done, 'directory.copyTo - Error copying directory : ' + srcDir + ' to :' + dstDir));
1435                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1436                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1437                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1438            });
1439            it("file.spec.61 copyTo: directory onto itself", function (done) {
1440                if (isIndexedDBShim) {
1441                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1442                    pending();
1443                }
1444
1445                var file1 = "file1",
1446                srcDir = "entry.copy.dos.srcDir",
1447                srcPath = joinURL(root.fullPath, srcDir),
1448                filePath = joinURL(srcPath, file1);
1449                // create a new directory entry to kick off it
1450                createDirectory(srcDir, function (directory) {
1451                    // create a file within new directory
1452                    directory.getFile(file1, {
1453                        create : true
1454                    }, function (fileEntry) {
1455                        // copy srcDir onto itself
1456                        directory.copyTo(root, null, succeed.bind(null, done, 'directory.copyTo - Unexpected success callback, it should not copy file: ' + srcDir + ' to a null destination'), function (error) {
1457                            expect(error).toBeDefined();
1458                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1459                            root.getDirectory(srcDir, {
1460                                create : false
1461                            }, function (dirEntry) {
1462                                expect(dirEntry).toBeDefined();
1463                                expect(dirEntry.fullPath).toCanonicallyMatch(srcPath);
1464                                dirEntry.getFile(file1, {
1465                                    create : false
1466                                }, function (fileEntry) {
1467                                    expect(fileEntry).toBeDefined();
1468                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1469                                    // cleanup
1470                                    deleteEntry(srcDir, done);
1471                                }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1));
1472                            }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir));
1473                        });
1474                    }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1475                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1476            });
1477            it("file.spec.62 copyTo: directory into itself", function (done) {
1478                if (isIndexedDBShim) {
1479                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1480                    pending();
1481                }
1482
1483                var srcDir = "entry.copy.dis.srcDir",
1484                dstDir = "entry.copy.dis.dstDir",
1485                srcPath = joinURL(root.fullPath, srcDir);
1486                // create a new directory entry to kick off it
1487                createDirectory(srcDir, function (directory) {
1488                    // copy source directory into itself
1489                    directory.copyTo(directory, dstDir, succeed.bind(null, done, 'directory.copyTo - Unexpected success callback, it should not copy a directory ' + srcDir + ' into itself'), function (error) {
1490                        expect(error).toBeDefined();
1491                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1492                        root.getDirectory(srcDir, {
1493                            create : false
1494                        }, function (dirEntry) {
1495                            // returning confirms existence so just check fullPath entry
1496                            expect(dirEntry).toBeDefined();
1497                            expect(dirEntry.fullPath).toCanonicallyMatch(srcPath);
1498                            // cleanup
1499                            deleteEntry(srcDir, done);
1500                        }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir));
1501                    });
1502                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1503            });
1504            it("file.spec.63 copyTo: directory that does not exist", function (done) {
1505                var file1 = "entry.copy.dnf.file1",
1506                dirName = 'dir-foo';
1507                createFile(file1, function (fileEntry) {
1508                    createDirectory(dirName, function (dirEntry) {
1509                        dirEntry.remove(function () {
1510                            fileEntry.copyTo(dirEntry, null, succeed.bind(null, done, 'fileEntry.copyTo - Unexpected success callback, it should not copy a file ' + file1 + ' into a removed directory'), function (error) {
1511                                expect(error).toBeDefined();
1512                                expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1513                                done();
1514                            });
1515                        }, failed.bind(null, done, 'dirEntry.remove - Error removing directory : ' + dirName));
1516                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dirName));
1517                }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1518            });
1519            it("file.spec.64 copyTo: invalid target name", function (done) {
1520                if (isBrowser) {
1521                    /*The plugin does not follow ["8.3 Naming restrictions"]
1522                    (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions*/
1523                    pending();
1524                }
1525
1526                var file1 = "entry.copy.itn.file1",
1527                file2 = "bad:file:name";
1528                // create a new file entry
1529                createFile(file1, function (entry) {
1530                    // copy file1 to file2
1531                    entry.copyTo(root, file2, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy a file ' + file1 + ' to an invalid file name: ' + file2), function (error) {
1532                        expect(error).toBeDefined();
1533                        expect(error).toBeFileError(FileError.ENCODING_ERR);
1534                        // cleanup
1535                        deleteEntry(file1, done);
1536                    });
1537                }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1538            });
1539            it("file.spec.65 moveTo: file to same parent", function (done) {
1540                var file1 = "entry.move.fsp.file1",
1541                file2 = "entry.move.fsp.file2",
1542                dstPath = joinURL(root.fullPath, file2);
1543                // create a new file entry to kick off it
1544                createFile(file1, function (entry) {
1545                    // move file1 to file2
1546                    entry.moveTo(root, file2, function (entry) {
1547                        expect(entry).toBeDefined();
1548                        expect(entry.isFile).toBe(true);
1549                        expect(entry.isDirectory).toBe(false);
1550                        expect(entry.fullPath).toCanonicallyMatch(dstPath);
1551                        expect(entry.name).toCanonicallyMatch(file2);
1552                        root.getFile(file2, {
1553                            create : false
1554                        }, function (fileEntry) {
1555                            expect(fileEntry).toBeDefined();
1556                            expect(fileEntry.fullPath).toCanonicallyMatch(dstPath);
1557                            root.getFile(file1, {
1558                                create : false
1559                            }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) {
1560                                //expect(navigator.fileMgr.testFileExists(srcPath) === false, "original file should not exist.");
1561                                expect(error).toBeDefined();
1562                                expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1563                                // cleanup
1564                                deleteEntry(file1, function () {
1565                                    deleteEntry(file2, done);
1566                                });
1567                            });
1568                        }, failed.bind(null, done, 'root.getFile - Error getting file : ' + file2));
1569                    }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to root as: ' + file2));
1570                }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1571            });
1572            it("file.spec.66 moveTo: file to new parent", function (done) {
1573                var file1 = "entry.move.fnp.file1",
1574                dir = "entry.move.fnp.dir",
1575                dstPath = joinURL(joinURL(root.fullPath, dir), file1);
1576                // ensure destination directory is cleaned up first
1577                deleteEntry(dir, function () {
1578                    // create a new file entry to kick off it
1579                    createFile(file1, function (entry) {
1580                        // create a parent directory to move file to
1581                        root.getDirectory(dir, {
1582                            create : true
1583                        }, function (directory) {
1584                            // move file1 to new directory
1585                            // move the file
1586                            entry.moveTo(directory, null, function (entry) {
1587                                expect(entry).toBeDefined();
1588                                expect(entry.isFile).toBe(true);
1589                                expect(entry.isDirectory).toBe(false);
1590                                expect(entry.fullPath).toCanonicallyMatch(dstPath);
1591                                expect(entry.name).toCanonicallyMatch(file1);
1592                                // test the moved file exists
1593                                directory.getFile(file1, {
1594                                    create : false
1595                                }, function (fileEntry) {
1596                                    expect(fileEntry).toBeDefined();
1597                                    expect(fileEntry.fullPath).toCanonicallyMatch(dstPath);
1598                                    root.getFile(file1, {
1599                                        create : false
1600                                    }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) {
1601                                        expect(error).toBeDefined();
1602                                        expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1603                                        // cleanup
1604                                        deleteEntry(file1, function () {
1605                                            deleteEntry(dir, done);
1606                                        });
1607                                    });
1608                                }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + dir));
1609                            }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to: ' + dir + ' with the same name'));
1610                        }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dir));
1611                    }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1612                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dir));
1613            });
1614            it("file.spec.67 moveTo: directory to same parent", function (done) {
1615                if (isIndexedDBShim) {
1616                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1617                    pending();
1618                }
1619
1620                var file1 = "file1",
1621                srcDir = "entry.move.dsp.srcDir",
1622                dstDir = "entry.move.dsp.dstDir",
1623                dstPath = joinURL(root.fullPath, dstDir),
1624                filePath = joinURL(dstPath, file1);
1625                // ensure destination directory is cleaned up before it
1626                deleteEntry(dstDir, function () {
1627                    // create a new directory entry to kick off it
1628                    createDirectory(srcDir, function (directory) {
1629                        // create a file within directory
1630                        directory.getFile(file1, {
1631                            create : true
1632                        }, function () {
1633                            // move srcDir to dstDir
1634                            directory.moveTo(root, dstDir, function (directory) {
1635                                expect(directory).toBeDefined();
1636                                expect(directory.isFile).toBe(false);
1637                                expect(directory.isDirectory).toBe(true);
1638                                expect(directory.fullPath).toCanonicallyMatch(dstPath);
1639                                expect(directory.name).toCanonicallyMatch(dstDir);
1640                                // test that moved file exists in destination dir
1641                                directory.getFile(file1, {
1642                                    create : false
1643                                }, function (fileEntry) {
1644                                    expect(fileEntry).toBeDefined();
1645                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1646                                    // check that the moved file no longer exists in original dir
1647                                    root.getFile(file1, {
1648                                        create : false
1649                                    }, succeed.bind(null, done, 'directory.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) {
1650                                        expect(error).toBeDefined();
1651                                        expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1652                                        // cleanup
1653                                        deleteEntry(srcDir, function() {
1654                                            deleteEntry(dstDir, done);
1655                                        });
1656                                    });
1657                                }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + srcDir));
1658                            }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir));
1659                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1660                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1661                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1662            });
1663            it("file.spec.68 moveTo: directory to same parent with same name", function (done) {
1664                if (isIndexedDBShim) {
1665                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1666                    pending();
1667                }
1668
1669                var file1 = "file1",
1670                srcDir = "entry.move.dsp.srcDir",
1671                dstDir = "entry.move.dsp.srcDir-backup",
1672                dstPath = joinURL(root.fullPath, dstDir),
1673                filePath = joinURL(dstPath, file1);
1674                // ensure destination directory is cleaned up before it
1675                deleteEntry(dstDir, function () {
1676                    // create a new directory entry to kick off it
1677                    createDirectory(srcDir, function (directory) {
1678                        // create a file within directory
1679                        directory.getFile(file1, {
1680                            create : true
1681                        }, function () {
1682                            // move srcDir to dstDir
1683                            directory.moveTo(root, dstDir, function (directory) {
1684                                expect(directory).toBeDefined();
1685                                expect(directory.isFile).toBe(false);
1686                                expect(directory.isDirectory).toBe(true);
1687                                expect(directory.fullPath).toCanonicallyMatch(dstPath);
1688                                expect(directory.name).toCanonicallyMatch(dstDir);
1689                                // check that moved file exists in destination dir
1690                                directory.getFile(file1, {
1691                                    create : false
1692                                }, function (fileEntry) {
1693                                    expect(fileEntry).toBeDefined();
1694                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1695                                    // check that the moved file no longer exists in original dir
1696                                    root.getFile(file1, {
1697                                        create : false
1698                                    }, succeed.bind(null, done, 'directory.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) {
1699                                        expect(error).toBeDefined();
1700                                        expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1701                                        // cleanup
1702                                        deleteEntry(srcDir, function() {
1703                                            deleteEntry(dstDir, done);
1704                                        });
1705                                    });
1706                                }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + srcDir));
1707                            }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir));
1708                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1709                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1710                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1711            });
1712            it("file.spec.69 moveTo: directory to new parent", function (done) {
1713                if (isIndexedDBShim) {
1714                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1715                    pending();
1716                }
1717
1718                var file1 = "file1",
1719                srcDir = "entry.move.dnp.srcDir",
1720                dstDir = "entry.move.dnp.dstDir",
1721                dstPath = joinURL(root.fullPath, dstDir),
1722                filePath = joinURL(dstPath, file1);
1723                // ensure destination directory is cleaned up before it
1724                deleteEntry(dstDir, function () {
1725                    // create a new directory entry to kick off it
1726                    createDirectory(srcDir, function (directory) {
1727                        // create a file within directory
1728                        directory.getFile(file1, {
1729                            create : true
1730                        }, function () {
1731                            // move srcDir to dstDir
1732                            directory.moveTo(root, dstDir, function (dirEntry) {
1733                                expect(dirEntry).toBeDefined();
1734                                expect(dirEntry.isFile).toBe(false);
1735                                expect(dirEntry.isDirectory).toBe(true);
1736                                expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
1737                                expect(dirEntry.name).toCanonicallyMatch(dstDir);
1738                                // test that moved file exists in destination dir
1739                                dirEntry.getFile(file1, {
1740                                    create : false
1741                                }, function (fileEntry) {
1742                                    expect(fileEntry).toBeDefined();
1743                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1744                                    // test that the moved file no longer exists in original dir
1745                                    root.getFile(file1, {
1746                                        create : false
1747                                    }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not get invalid or moved file: ' + file1), function (error) {
1748                                        expect(error).toBeDefined();
1749                                        expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
1750                                        // cleanup
1751                                        deleteEntry(srcDir, function() {
1752                                            deleteEntry(dstDir, done);
1753                                        });
1754                                    });
1755                                }, failed.bind(null, done, 'directory.getFile - Error getting file : ' + file1 + ' from: ' + dstDir));
1756                            }, failed.bind(null, done, 'directory.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir));
1757                        }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1758                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1759                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1760            });
1761
1762            it("file.spec.131 moveTo: directories tree to new parent", function (done) {
1763                if (isIndexedDBShim) {
1764                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1765                    pending();
1766                }
1767
1768                var srcDir = "entry.move.dnp.srcDir";
1769                var srcDirNestedFirst = "entry.move.dnp.srcDir.Nested1";
1770                var srcDirNestedSecond = "entry.move.dnp.srcDir.Nested2";
1771                var dstDir = "entry.move.dnp.dstDir";
1772
1773                createDirectory(dstDir, function (dstDirectory) {
1774                    createDirectory(srcDir, function (srcDirectory) {
1775                        srcDirectory.getDirectory(srcDirNestedFirst, { create: true }, function () {
1776                            srcDirectory.getDirectory(srcDirNestedSecond, { create: true }, function () {
1777                                srcDirectory.moveTo(dstDirectory, srcDir, function successMove(transferredDirectory) {
1778                                    var directoryReader = transferredDirectory.createReader();
1779                                    directoryReader.readEntries(function successRead(entries) {
1780                                        expect(entries.length).toBe(2);
1781                                        expect(entries[0].name).toBe(srcDirNestedFirst);
1782                                        expect(entries[1].name).toBe(srcDirNestedSecond);
1783                                        deleteEntry(dstDir, done);
1784                                    }, failed.bind(null, done, 'Error getting entries from: ' + transferredDirectory));
1785                                }, failed.bind(null, done, 'directory.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir));
1786                            }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + srcDirNestedSecond));
1787                        }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + srcDirNestedFirst));
1788                    }, failed.bind(null, done, 'createDirectory - Error creating source directory : ' + srcDir));
1789                }, failed.bind(null, done, 'createDirectory - Error creating dest directory : ' + dstDir));
1790            });
1791
1792            it("file.spec.70 moveTo: directory onto itself", function (done) {
1793                if (isIndexedDBShim) {
1794                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1795                    pending();
1796                }
1797
1798                var file1 = "file1",
1799                srcDir = "entry.move.dos.srcDir",
1800                srcPath = joinURL(root.fullPath, srcDir),
1801                filePath = joinURL(srcPath, file1);
1802                // create a new directory entry to kick off it
1803                createDirectory(srcDir, function (directory) {
1804                    // create a file within new directory
1805                    directory.getFile(file1, {
1806                        create : true
1807                    }, function () {
1808                        // move srcDir onto itself
1809                        directory.moveTo(root, null, succeed.bind(null, done, 'directory.moveTo - Unexpected success callback, it should not move directory to invalid path'), function (error) {
1810                            expect(error).toBeDefined();
1811                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1812                            // test that original dir still exists
1813                            root.getDirectory(srcDir, {
1814                                create : false
1815                            }, function (dirEntry) {
1816                                // returning confirms existence so just check fullPath entry
1817                                expect(dirEntry).toBeDefined();
1818                                expect(dirEntry.fullPath).toCanonicallyMatch(srcPath);
1819                                dirEntry.getFile(file1, {
1820                                    create : false
1821                                }, function (fileEntry) {
1822                                    expect(fileEntry).toBeDefined();
1823                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1824                                    // cleanup
1825                                    deleteEntry(srcDir, done);
1826                                }, failed.bind(null, done, 'dirEntry.getFile - Error getting file : ' + file1 + ' from: ' + srcDir));
1827                            }, failed.bind(null, done, 'root.getDirectory - Error getting directory : ' + srcDir));
1828                        });
1829                    }, failed.bind(null, done, 'directory.getFile - Error creating file : ' + file1));
1830                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1831            });
1832            it("file.spec.71 moveTo: directory into itself", function (done) {
1833                if (isIndexedDBShim) {
1834                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1835                    pending();
1836                }
1837
1838                var srcDir = "entry.move.dis.srcDir",
1839                dstDir = "entry.move.dis.dstDir",
1840                srcPath = joinURL(root.fullPath, srcDir);
1841                // create a new directory entry to kick off it
1842                createDirectory(srcDir, function (directory) {
1843                    // move source directory into itself
1844                    directory.moveTo(directory, dstDir, succeed.bind(null, done, 'directory.moveTo - Unexpected success callback, it should not move a directory into itself: ' + srcDir), function (error) {
1845                        expect(error).toBeDefined();
1846                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1847                        // make sure original directory still exists
1848                        root.getDirectory(srcDir, {
1849                            create : false
1850                        }, function (entry) {
1851                            expect(entry).toBeDefined();
1852                            expect(entry.fullPath).toCanonicallyMatch(srcPath);
1853                            // cleanup
1854                            deleteEntry(srcDir, done);
1855                        }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir));
1856                    });
1857                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1858            });
1859            it("file.spec.130 moveTo: directory into similar directory", function (done) {
1860                if (isIndexedDBShim) {
1861                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1862                    pending();
1863                }
1864
1865                var srcDir = "entry.move.dis.srcDir",
1866                dstDir = "entry.move.dis.srcDir-backup";
1867                // create a new directory entry to kick off it
1868                createDirectory(srcDir, function (srcDirEntry) {
1869                deleteEntry(dstDir, function () {
1870                createDirectory(dstDir, function (dstDirEntry) {
1871                    // move source directory into itself
1872                    srcDirEntry.moveTo(dstDirEntry, 'file', function (newDirEntry) {
1873                        expect(newDirEntry).toBeDefined();
1874                        deleteEntry(dstDir, done);
1875                    }, failed.bind(null, done, 'directory.moveTo - Error moving a directory into a similarly-named directory: ' + srcDir));
1876                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + dstDir));
1877                }, failed.bind(null, done, 'deleteEntry - Error deleting directory : ' + dstDir));
1878                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1879            });
1880            it("file.spec.72 moveTo: file onto itself", function (done) {
1881                var file1 = "entry.move.fos.file1",
1882                filePath = joinURL(root.fullPath, file1);
1883                // create a new file entry to kick off it
1884                createFile(file1, function (entry) {
1885                    // move file1 onto itself
1886                    entry.moveTo(root, null, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move a file: ' + file1 + ' into the same parent'), function (error) {
1887                        expect(error).toBeDefined();
1888                        expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1889                        //test that original file still exists
1890                        root.getFile(file1, {
1891                            create : false
1892                        }, function (fileEntry) {
1893                            expect(fileEntry).toBeDefined();
1894                            expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1895                            // cleanup
1896                            deleteEntry(file1, done);
1897                        }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1));
1898                    });
1899                }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1900            });
1901            it("file.spec.73 moveTo: file onto existing directory", function (done) {
1902                var file1 = "entry.move.fod.file1",
1903                dstDir = "entry.move.fod.dstDir",
1904                subDir = "subDir",
1905                dirPath = joinURL(joinURL(root.fullPath, dstDir), subDir),
1906                filePath = joinURL(root.fullPath, file1);
1907                // ensure destination directory is cleaned up before it
1908                deleteEntry(dstDir, function () {
1909                    // create a new file entry to kick off it
1910                    createFile(file1, function (entry) {
1911                        // create top level directory
1912                        root.getDirectory(dstDir, {
1913                            create : true
1914                        }, function (directory) {
1915                            // create sub-directory
1916                            directory.getDirectory(subDir, {
1917                                create : true
1918                            }, function (subDirectory) {
1919                                // move file1 onto sub-directory
1920                                entry.moveTo(directory, subDir, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move a file: ' + file1 + ' into directory: ' + dstDir + '\n' + subDir + ' directory already exists'), function (error) {
1921                                    expect(error).toBeDefined();
1922                                    expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1923                                    // check that original dir still exists
1924                                    directory.getDirectory(subDir, {
1925                                        create : false
1926                                    }, function (dirEntry) {
1927                                        expect(dirEntry).toBeDefined();
1928                                        expect(dirEntry.fullPath).toCanonicallyMatch(dirPath);
1929                                        // check that original file still exists
1930                                        root.getFile(file1, {
1931                                            create : false
1932                                        }, function (fileEntry) {
1933                                            expect(fileEntry).toBeDefined();
1934                                            expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1935                                            // cleanup
1936                                            deleteEntry(file1, function () {
1937                                                deleteEntry(dstDir, done);
1938                                            });
1939                                        }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1));
1940                                    }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + subDir));
1941                                });
1942                            }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir));
1943                        }, failed.bind(null, done, 'root.getDirectory - Error creating directory : ' + dstDir));
1944                    }, failed.bind(null, done, 'createFile - Error creating file : ' + file1));
1945                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
1946            });
1947            it("file.spec.74 moveTo: directory onto existing file", function (done) {
1948                if (isIndexedDBShim) {
1949                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1950                    pending();
1951                }
1952
1953                var file1 = "entry.move.dof.file1",
1954                srcDir = "entry.move.dof.srcDir",
1955                dirPath = joinURL(root.fullPath, srcDir),
1956                filePath = joinURL(root.fullPath, file1);
1957                // create a new directory entry to kick off it
1958                createDirectory(srcDir, function (entry) {
1959                    // create file
1960                    root.getFile(file1, {
1961                        create : true
1962                    }, function (fileEntry) {
1963                        // move directory onto file
1964                        entry.moveTo(root, file1, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not move : \n' + srcDir + ' into root directory renamed as ' + file1 + '\n' + file1 + ' file already exists'), function (error) {
1965                            expect(error).toBeDefined();
1966                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
1967                            // test that original directory exists
1968                            root.getDirectory(srcDir, {
1969                                create : false
1970                            }, function (dirEntry) {
1971                                // returning confirms existence so just check fullPath entry
1972                                expect(dirEntry).toBeDefined();
1973                                expect(dirEntry.fullPath).toCanonicallyMatch(dirPath);
1974                                // test that original file exists
1975                                root.getFile(file1, {
1976                                    create : false
1977                                }, function (fileEntry) {
1978                                    expect(fileEntry).toBeDefined();
1979                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
1980                                    // cleanup
1981                                    deleteEntry(file1, function () {
1982                                        deleteEntry(srcDir, done);
1983                                    });
1984                                }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1));
1985                            }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir));
1986                        });
1987                    }, failed.bind(null, done, 'root.getFile - Error creating file : ' + file1));
1988                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
1989            });
1990            it("file.spec.75 copyTo: directory onto existing file", function (done) {
1991                if (isIndexedDBShim) {
1992                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
1993                    pending();
1994                }
1995
1996                var file1 = "entry.copy.dof.file1",
1997                srcDir = "entry.copy.dof.srcDir",
1998                dirPath = joinURL(root.fullPath, srcDir),
1999                filePath = joinURL(root.fullPath, file1);
2000                // create a new directory entry to kick off it
2001                createDirectory(srcDir, function (entry) {
2002                    // create file
2003                    root.getFile(file1, {
2004                        create : true
2005                    }, function () {
2006                        // copy directory onto file
2007                        entry.copyTo(root, file1, succeed.bind(null, done, 'entry.copyTo - Unexpected success callback, it should not copy : \n' + srcDir + ' into root directory renamed as ' + file1 + '\n' + file1 + ' file already exists'), function (error) {
2008                            expect(error).toBeDefined();
2009                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
2010                            //check that original dir still exists
2011                            root.getDirectory(srcDir, {
2012                                create : false
2013                            }, function (dirEntry) {
2014                                // returning confirms existence so just check fullPath entry
2015                                expect(dirEntry).toBeDefined();
2016                                expect(dirEntry.fullPath).toCanonicallyMatch(dirPath);
2017                                // test that original file still exists
2018                                root.getFile(file1, {
2019                                    create : false
2020                                }, function (fileEntry) {
2021                                    expect(fileEntry).toBeDefined();
2022                                    expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
2023                                    // cleanup
2024                                    deleteEntry(file1, function () {
2025                                        deleteEntry(srcDir, done);
2026                                    });
2027                                }, failed.bind(null, done, 'root.getFile - Error getting file, making sure that original file still exists: ' + file1));
2028                            }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir));
2029                        });
2030                    }, failed.bind(null, done, 'root.getFile - Error creating file : ' + file1));
2031                }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
2032            });
2033            it("file.spec.76 moveTo: directory onto directory that is not empty", function (done) {
2034                if (isIndexedDBShim) {
2035                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
2036                    pending();
2037                }
2038
2039                var srcDir = "entry.move.dod.srcDir",
2040                dstDir = "entry.move.dod.dstDir",
2041                subDir = "subDir",
2042                srcPath = joinURL(root.fullPath, srcDir),
2043                dstPath = joinURL(joinURL(root.fullPath, dstDir), subDir);
2044                // ensure destination directory is cleaned up before it
2045                deleteEntry(dstDir, function () {
2046                    // create a new file entry to kick off it
2047                    createDirectory(srcDir, function (entry) {
2048                        // create top level directory
2049                        root.getDirectory(dstDir, {
2050                            create : true
2051                        }, function (directory) {
2052                            // create sub-directory
2053                            directory.getDirectory(subDir, {
2054                                create : true
2055                            }, function () {
2056                                // move srcDir onto dstDir (not empty)
2057                                entry.moveTo(root, dstDir, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, it should not copy : \n' + srcDir + ' into root directory renamed as ' + dstDir + '\n' + dstDir + ' directory already exists'), function (error) {
2058                                    expect(error).toBeDefined();
2059                                    expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
2060                                    // making sure destination directory still exists
2061                                    directory.getDirectory(subDir, {
2062                                        create : false
2063                                    }, function (dirEntry) {
2064                                        // returning confirms existence so just check fullPath entry
2065                                        expect(dirEntry).toBeDefined();
2066                                        expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
2067                                        // making sure source directory exists
2068                                        root.getDirectory(srcDir, {
2069                                            create : false
2070                                        }, function (srcEntry) {
2071                                            expect(srcEntry).toBeDefined();
2072                                            expect(srcEntry.fullPath).toCanonicallyMatch(srcPath);
2073                                            // cleanup
2074                                            deleteEntry(srcDir, function () {
2075                                                deleteEntry(dstDir, done);
2076                                            });
2077                                        }, failed.bind(null, done, 'root.getDirectory - Error getting directory, making sure that original directory still exists: ' + srcDir));
2078                                    }, failed.bind(null, done, 'directory.getDirectory - Error getting directory, making sure that original directory still exists: ' + subDir));
2079                                });
2080                            }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir));
2081                        }, failed.bind(null, done, 'directory.getDirectory - Error creating directory : ' + subDir));
2082                    }, failed.bind(null, done, 'createDirectory - Error creating directory : ' + srcDir));
2083                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
2084            });
2085            it("file.spec.77 moveTo: file replace existing file", function (done) {
2086                var file1 = "entry.move.frf.file1",
2087                file2 = "entry.move.frf.file2",
2088                file2Path = joinURL(root.fullPath, file2);
2089                // create a new directory entry to kick off it
2090                createFile(file1, function (entry) {
2091                    // create file
2092                    root.getFile(file2, {
2093                        create : true
2094                    }, function () {
2095                        // replace file2 with file1
2096                        entry.moveTo(root, file2, function (entry2) {
2097                            expect(entry2).toBeDefined();
2098                            expect(entry2.isFile).toBe(true);
2099                            expect(entry2.isDirectory).toBe(false);
2100                            expect(entry2.fullPath).toCanonicallyMatch(file2Path);
2101                            expect(entry2.name).toCanonicallyMatch(file2);
2102                            // old file should not exists
2103                            root.getFile(file1, {
2104                                create : false
2105                            }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, file: ' + file1 + ' should not exists'), function (error) {
2106                                expect(error).toBeDefined();
2107                                expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
2108                                // test that new file exists
2109                                root.getFile(file2, {
2110                                    create : false
2111                                }, function (fileEntry) {
2112                                    expect(fileEntry).toBeDefined();
2113                                    expect(fileEntry.fullPath).toCanonicallyMatch(file2Path);
2114                                    // cleanup
2115                                    deleteEntry(file1, function () {
2116                                        deleteEntry(file2, done);
2117                                    });
2118                                }, failed.bind(null, done, 'root.getFile - Error getting moved file: ' + file2));
2119                            });
2120                        }, failed.bind(null, done, 'entry.moveTo - Error moving file : ' + file1 + ' to root as: ' + file2));
2121                    }, failed.bind(null, done, 'root.getFile - Error creating file: ' + file2));
2122                }, failed.bind(null, done, 'createFile - Error creating file: ' + file1));
2123            });
2124            it("file.spec.78 moveTo: directory replace empty directory", function (done) {
2125                if (isIndexedDBShim) {
2126                    /* `copyTo` and `moveTo` functions do not support directories (Firefox, IE) */
2127                    pending();
2128                }
2129
2130                var file1 = "file1",
2131                srcDir = "entry.move.drd.srcDir",
2132                dstDir = "entry.move.drd.dstDir",
2133                dstPath = joinURL(root.fullPath, dstDir),
2134                filePath = dstPath + '/' + file1;
2135                // ensure destination directory is cleaned up before it
2136                deleteEntry(dstDir, function () {
2137                    // create a new directory entry to kick off it
2138                    createDirectory(srcDir, function (directory) {
2139                        // create a file within source directory
2140                        directory.getFile(file1, {
2141                            create : true
2142                        }, function () {
2143                            // create destination directory
2144                            root.getDirectory(dstDir, {
2145                                create : true
2146                            }, function () {
2147                                // move srcDir to dstDir
2148                                directory.moveTo(root, dstDir, function (dirEntry) {
2149                                    expect(dirEntry).toBeDefined();
2150                                    expect(dirEntry.isFile).toBe(false);
2151                                    expect(dirEntry.isDirectory).toBe(true);
2152                                    expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
2153                                    expect(dirEntry.name).toCanonicallyMatch(dstDir);
2154                                    // check that old directory contents have been moved
2155                                    dirEntry.getFile(file1, {
2156                                        create : false
2157                                    }, function (fileEntry) {
2158                                        expect(fileEntry).toBeDefined();
2159                                        expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
2160                                        // check that old directory no longer exists
2161                                        root.getDirectory(srcDir, {
2162                                            create : false
2163                                        }, succeed.bind(null, done, 'root.getDirectory - Unexpected success callback, directory: ' + srcDir + ' should not exists'), function (error) {
2164                                            expect(error).toBeDefined();
2165                                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
2166                                            // cleanup
2167                                            deleteEntry(srcDir, function () {
2168                                                deleteEntry(dstDir, done);
2169                                            });
2170                                        });
2171                                    }, failed.bind(null, done, 'dirEntry.getFile - Error getting moved file: ' + file1));
2172                                }, failed.bind(null, done, 'entry.moveTo - Error moving directory : ' + srcDir + ' to root as: ' + dstDir));
2173                            }, failed.bind(null, done, 'root.getDirectory - Error creating directory: ' + dstDir));
2174                        }, failed.bind(null, done, 'root.getFile - Error creating file: ' + file1));
2175                    }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + srcDir));
2176                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
2177            });
2178            it("file.spec.79 moveTo: directory that does not exist", function (done) {
2179
2180                var file1 = "entry.move.dnf.file1",
2181                dstDir = "entry.move.dnf.dstDir",
2182                dstPath = joinURL(root.fullPath, dstDir);
2183                // create a new file entry to kick off it
2184                createFile(file1, function (entry) {
2185                    // move file to directory that does not exist
2186                    var directory = new DirectoryEntry();
2187                    directory.filesystem = root.filesystem;
2188                    directory.fullPath = dstPath;
2189                    entry.moveTo(directory, null, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, parent directory: ' + dstPath + ' should not exists'), function (error) {
2190                        expect(error).toBeDefined();
2191                        if (isChrome) {
2192                            /*INVALID_MODIFICATION_ERR (code: 9) is thrown instead of NOT_FOUND_ERR(code: 1)
2193                            on trying to moveTo directory that does not exist.*/
2194                            expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
2195                        } else {
2196                            expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
2197                        }
2198                        // cleanup
2199                        deleteEntry(file1, done);
2200                    });
2201                }, failed.bind(null, done, 'createFile - Error creating file: ' + file1));
2202            });
2203            it("file.spec.80 moveTo: invalid target name", function (done) {
2204                if (isBrowser) {
2205                    /*The plugin does not follow ["8.3 Naming restrictions"]
2206                    (http://www.w3.org/TR/2011/WD-file-system-api-20110419/#naming-restrictions*/
2207                    pending();
2208                }
2209
2210                var file1 = "entry.move.itn.file1",
2211                file2 = "bad:file:name";
2212                // create a new file entry to kick off it
2213                createFile(file1, function (entry) {
2214                    // move file1 to file2
2215                    entry.moveTo(root, file2, succeed.bind(null, done, 'entry.moveTo - Unexpected success callback, : ' + file1 + ' to root as: ' + file2), function (error) {
2216                        expect(error).toBeDefined();
2217                        expect(error).toBeFileError(FileError.ENCODING_ERR);
2218                        // cleanup
2219                        deleteEntry(file1, done);
2220                    });
2221                }, failed.bind(null, done, 'createFile - Error creating file: ' + file1));
2222            });
2223        });
2224        //Entry
2225        describe('FileReader', function () {
2226            it("file.spec.81 should have correct methods", function () {
2227                var reader = new FileReader();
2228                expect(reader).toBeDefined();
2229                expect(typeof reader.readAsBinaryString).toBe('function');
2230                expect(typeof reader.readAsDataURL).toBe('function');
2231                expect(typeof reader.readAsText).toBe('function');
2232                expect(typeof reader.readAsArrayBuffer).toBe('function');
2233                expect(typeof reader.abort).toBe('function');
2234                expect(reader.result).toBe(null);
2235            });
2236        });
2237        //FileReader
2238        describe('Read method', function () {
2239            it("file.spec.82 should error out on non-existent file", function (done) {
2240                var fileName = cordova.platformId === 'windowsphone' ? root.toURL() + "/" + "somefile.txt" : "somefile.txt",
2241                verifier = function (evt) {
2242                    expect(evt).toBeDefined();
2243                    expect(evt.target.error).toBeFileError(FileError.NOT_FOUND_ERR);
2244                    done();
2245                };
2246                root.getFile(fileName, {
2247                    create : true
2248                }, function (entry) {
2249                    entry.file(function (file) {
2250                        deleteEntry(fileName, function () {
2251                            //Create FileReader
2252                            var reader = new FileReader();
2253                            reader.onerror = verifier;
2254                            reader.onload = succeed.bind(null, done, 'reader.onload - Unexpected success callback, file: ' + fileName + ' it should not exists');
2255                            reader.readAsText(file);
2256                        }, failed.bind(null, done, 'deleteEntry - Error removing file: ' + fileName));
2257                    }, failed.bind(null, done, 'entry.file - Error reading file: ' + fileName));
2258                }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
2259            });
2260            it("file.spec.83 should be able to read native blob objects", function (done) {
2261                // Skip test if blobs are not supported (e.g.: Android 2.3).
2262                if (typeof window.Blob == 'undefined' || typeof window.Uint8Array == 'undefined') {
2263                    expect(true).toFailWithMessage('Platform does not supported this feature');
2264                    done();
2265                }
2266                var contents = 'asdf';
2267                var uint8Array = new Uint8Array(contents.length);
2268                for (var i = 0; i < contents.length; ++i) {
2269                    uint8Array[i] = contents.charCodeAt(i);
2270                }
2271                var Builder = window.BlobBuilder || window.WebKitBlobBuilder;
2272                var blob;
2273                if (Builder) {
2274                    var builder = new Builder();
2275                    builder.append(uint8Array.buffer);
2276                    builder.append(contents);
2277                    blob = builder.getBlob("text/plain");
2278                } else {
2279                    try {
2280                        // iOS 6 does not support Views, so pass in the buffer.
2281                        blob = new Blob([uint8Array.buffer, contents]);
2282                    } catch (e) {
2283                        // Skip the test if we can't create a blob (e.g.: iOS 5).
2284                        if (e instanceof TypeError) {
2285                            expect(true).toFailWithMessage('Platform does not supported this feature');
2286                            done();
2287                        }
2288                        throw e;
2289                    }
2290                }
2291                var verifier = function (evt) {
2292                    expect(evt).toBeDefined();
2293                    expect(evt.target.result).toBe('asdfasdf');
2294                    done();
2295                };
2296                var reader = new FileReader();
2297                reader.onloadend = verifier;
2298                reader.readAsText(blob);
2299            });
2300            function writeDummyFile(writeBinary, callback, done, fileContents) {
2301                var fileName = "dummy.txt",
2302                fileEntry = null,
2303                // use default string if file data is not provided
2304                fileData = fileContents !== undefined ? fileContents :
2305                    '\u20AC\xEB - There is an exception to every rule. Except this one.',
2306                fileDataAsBinaryString = fileContents !== undefined ? fileContents :
2307                    '\xe2\x82\xac\xc3\xab - There is an exception to every rule. Except this one.';
2308
2309                function createWriter(fe) {
2310                    fileEntry = fe;
2311                    fileEntry.createWriter(writeFile, failed.bind(null, done, 'fileEntry.createWriter - Error reading file: ' + fileName));
2312                }
2313
2314                // writes file and reads it back in
2315                function writeFile(writer) {
2316                    writer.onwriteend = function () {
2317                        fileEntry.file(function (f) {
2318                            callback(fileEntry, f, fileData, fileDataAsBinaryString);
2319                        }, failed.bind(null, done, 'writer.onwriteend - Error writing data on file: ' + fileName));
2320                    };
2321                    writer.write(fileData);
2322                }
2323
2324                fileData += writeBinary ? 'bin:\x01\x00' : '';
2325                fileDataAsBinaryString += writeBinary ? 'bin:\x01\x00' : '';
2326                // create a file, write to it, and read it in again
2327                createFile(fileName, createWriter, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2328            }
2329            function runReaderTest(funcName, writeBinary, done, progressFunc, verifierFunc, sliceStart, sliceEnd, fileContents) {
2330                writeDummyFile(writeBinary, function (fileEntry, file, fileData, fileDataAsBinaryString) {
2331                    var verifier = function (evt) {
2332                        expect(evt).toBeDefined();
2333                        verifierFunc(evt, fileData, fileDataAsBinaryString);
2334                    };
2335                    var reader = new FileReader();
2336                    reader.onprogress = progressFunc;
2337                    reader.onload = verifier;
2338                    reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + file + ' using function: ' + funcName);
2339                    if (sliceEnd !== undefined) {
2340                        // 'type' is specified so that is will be preserved in the resulting file:
2341                        // http://www.w3.org/TR/FileAPI/#slice-method-algo -> "6.4.1. The slice method" -> 4. A), 6. c)
2342                        file = file.slice(sliceStart, sliceEnd, file.type);
2343                    } else if (sliceStart !== undefined) {
2344                        file = file.slice(sliceStart, file.size, file.type);
2345                    }
2346                    reader[funcName](file);
2347                }, done, fileContents);
2348            }
2349            function arrayBufferEqualsString(ab, str) {
2350                var buf = new Uint8Array(ab);
2351                var match = buf.length == str.length;
2352                for (var i = 0; match && i < buf.length; i++) {
2353                    match = buf[i] == str.charCodeAt(i);
2354                }
2355                return match;
2356            }
2357            it("file.spec.84 should read file properly, readAsText", function (done) {
2358                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2359                    expect(evt.target.result).toBe(fileData);
2360                    done();
2361                });
2362            });
2363            it("file.spec.84.1 should read JSON file properly, readAsText", function (done) {
2364                var testObject = {key1: "value1", key2: 2};
2365                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2366                    expect(evt.target.result).toEqual(JSON.stringify(testObject));
2367                    done();
2368                }, undefined, undefined, JSON.stringify(testObject));
2369            });
2370            it("file.spec.85 should read file properly, Data URI", function (done) {
2371                runReaderTest('readAsDataURL', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2372                    /* `readAsDataURL` function is supported, but the mediatype in Chrome depends on entry name extension,
2373                        mediatype in IE is always empty (which is the same as `text-plain` according the specification),
2374                        the mediatype in Firefox is always `application/octet-stream`.
2375                        For example, if the content is `abcdefg` then Firefox returns `data:application/octet-stream;base64,YWJjZGVmZw==`,
2376                        IE returns `data:;base64,YWJjZGVmZw==`, Chrome returns `data:<mediatype depending on extension of entry name>;base64,YWJjZGVmZw==`. */
2377                    expect(evt.target.result).toBeDataUrl();
2378
2379                    //The atob function it is completely ignored during mobilespec execution, besides the returned object: evt
2380                    //it is encoded and the atob function is aimed to decode a string. Even with btoa (encode) the function it gets stucked
2381                    //because of the Unicode characters that contains the fileData object.
2382                    //Issue reported at JIRA with all the details: CB-7095
2383
2384                    //expect(evt.target.result.slice(23)).toBe(atob(fileData));
2385
2386                    done();
2387                });
2388            });
2389            it("file.spec.86 should read file properly, readAsBinaryString", function (done) {
2390                if (isIE) {
2391                    /*`readAsBinaryString` function is not supported by IE and has not the stub.*/
2392                    pending();
2393                }
2394
2395                runReaderTest('readAsBinaryString', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2396                    expect(evt.target.result).toBe(fileDataAsBinaryString);
2397                    done();
2398                });
2399            });
2400            it("file.spec.87 should read file properly, readAsArrayBuffer", function (done) {
2401                // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3).
2402                if (typeof window.ArrayBuffer == 'undefined') {
2403                    expect(true).toFailWithMessage('Platform does not supported this feature');
2404                    done();
2405                }
2406                runReaderTest('readAsArrayBuffer', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2407                    expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString)).toBe(true);
2408                    done();
2409                });
2410            });
2411            it("file.spec.88 should read sliced file: readAsText", function (done) {
2412                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2413                    expect(evt.target.result).toBe(fileDataAsBinaryString.slice(10, 40));
2414                    done();
2415                }, 10, 40);
2416            });
2417            it("file.spec.89 should read sliced file: slice past eof", function (done) {
2418                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2419                    expect(evt.target.result).toBe(fileData.slice(-5, 9999));
2420                    done();
2421                }, -5, 9999);
2422            });
2423            it("file.spec.90 should read sliced file: slice to eof", function (done) {
2424                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2425                    expect(evt.target.result).toBe(fileData.slice(-5));
2426                    done();
2427                }, -5);
2428            });
2429            it("file.spec.91 should read empty slice", function (done) {
2430                runReaderTest('readAsText', false, done, null, function (evt, fileData, fileDataAsBinaryString) {
2431                    expect(evt.target.result).toBe('');
2432                    done();
2433                }, 0, 0);
2434            });
2435            it("file.spec.92 should read sliced file properly, readAsDataURL", function (done) {
2436                runReaderTest('readAsDataURL', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2437                    /* `readAsDataURL` function is supported, but the mediatype in Chrome depends on entry name extension,
2438                        mediatype in IE is always empty (which is the same as `text-plain` according the specification),
2439                        the mediatype in Firefox is always `application/octet-stream`.
2440                        For example, if the content is `abcdefg` then Firefox returns `data:application/octet-stream;base64,YWJjZGVmZw==`,
2441                        IE returns `data:;base64,YWJjZGVmZw==`, Chrome returns `data:<mediatype depending on extension of entry name>;base64,YWJjZGVmZw==`. */
2442                    expect(evt.target.result).toBeDataUrl();
2443
2444                    //The atob function it is completely ignored during mobilespec execution, besides the returned object: evt
2445                    //it is encoded and the atob function is aimed to decode a string. Even with btoa (encode) the function it gets stucked
2446                    //because of the Unicode characters that contains the fileData object.
2447                    //Issue reported at JIRA with all the details: CB-7095
2448
2449                    //expect(evt.target.result.slice(23)).toBe(atob(fileDataAsBinaryString.slice(10, -3)));
2450
2451                    done();
2452                }, 10, -3);
2453            });
2454            it("file.spec.93 should read sliced file properly, readAsBinaryString", function (done) {
2455                if (isIE) {
2456                    /*`readAsBinaryString` function is not supported by IE and has not the stub.*/
2457                    pending();
2458                }
2459
2460                runReaderTest('readAsBinaryString', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2461                    expect(evt.target.result).toBe(fileDataAsBinaryString.slice(-10, -5));
2462                    done();
2463                }, -10, -5);
2464            });
2465            it("file.spec.94 should read sliced file properly, readAsArrayBuffer", function (done) {
2466                // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3).
2467                if (typeof window.ArrayBuffer == 'undefined') {
2468                    expect(true).toFailWithMessage('Platform does not supported this feature');
2469                    done();
2470                }
2471                runReaderTest('readAsArrayBuffer', true, done, null, function (evt, fileData, fileDataAsBinaryString) {
2472                    expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString.slice(0, -1))).toBe(true);
2473                    done();
2474                }, 0, -1);
2475            });
2476            it("file.spec.94.5 should read large file in multiple chunks, readAsArrayBuffer", function (done) {
2477                // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3).
2478                if (typeof window.ArrayBuffer == 'undefined') {
2479                    expect(true).toFailWithMessage('Platform does not supported this feature');
2480                    done();
2481                }
2482
2483                var largeText = "";
2484                for (var i = 0; i < 1000; i++) {
2485                    largeText += "Test " + i + "\n";
2486                }
2487
2488                // Set the chunk size so that the read will take 5 chunks
2489                FileReader.READ_CHUNK_SIZE = Math.floor(largeText.length / 4) + 1;
2490
2491                var chunkCount = 0;
2492                var lastProgressValue = -1;
2493                var progressFunc = function (evt) {
2494                    expect(evt.loaded).toBeDefined();
2495                    expect(evt.total).toBeDefined();
2496
2497                    expect(evt.total >= largeText.length).toBe(true);
2498                    expect(evt.total <= largeText.length + 5).toBe(true);
2499                    expect(evt.loaded > lastProgressValue).toBe(true);
2500                    expect(evt.loaded <= evt.total).toBe(true);
2501
2502                    lastProgressValue = evt.loaded;
2503                    chunkCount++;
2504                };
2505
2506                runReaderTest(
2507                    'readAsArrayBuffer', true, done, progressFunc,
2508                    function (evt, fileData, fileDataAsBinaryString) {
2509                        expect(arrayBufferEqualsString(evt.target.result, fileDataAsBinaryString.slice(0, -1))).toBe(true);
2510                        expect(lastProgressValue >= largeText.length).toBe(true);
2511                        expect(lastProgressValue <= largeText.length + 5).toBe(true);
2512                        expect(chunkCount).toBe(5);
2513                        done();
2514                    },
2515                    0, -1, largeText);
2516            });
2517            it("file.spec.94.6 should read large file in multiple chunks, readAsDataURL", function (done) {
2518                var largeText = "";
2519                for (var i = 0; i < 10; i++) {
2520                    largeText += "Test " + i + "\n";
2521                }
2522
2523                // Set the chunk size so that the read will take 5 chunks
2524                FileReader.READ_CHUNK_SIZE = Math.floor(largeText.length / 4) + 1;
2525
2526                var lastProgressValue = 0;
2527                var progressFunc = function (evt) {
2528                    expect(evt.total).toBeDefined();
2529                    expect(evt.total).toEqual(largeText.length);
2530
2531                    expect(evt.loaded).toBeDefined();
2532                    expect(evt.loaded).toBeGreaterThan(lastProgressValue);
2533                    expect(evt.loaded).toBeLessThan(evt.total + 1);
2534
2535                    lastProgressValue = evt.loaded;
2536                };
2537
2538                runReaderTest('readAsDataURL', false, done, progressFunc,
2539                    function (evt, fileData, fileDataAsBinaryString) {
2540                        expect(function () {
2541                            // Cut off data uri prefix
2542                            var base64Data = evt.target.result.substring(evt.target.result.indexOf(',') + 1);
2543                            expect(window.atob(base64Data)).toEqual(fileData);
2544                        }).not.toThrow();
2545
2546                        expect(lastProgressValue).toEqual(largeText.length);
2547                        done();
2548                    },
2549                undefined, undefined, largeText);
2550            });
2551        });
2552        //Read method
2553        describe('FileWriter', function () {
2554            it("file.spec.95 should have correct methods", function (done) {
2555                // retrieve a FileWriter object
2556                var fileName = "writer.methods";
2557                // FileWriter
2558                root.getFile(fileName, {
2559                    create : true
2560                }, function (fileEntry) {
2561                    fileEntry.createWriter(function (writer) {
2562                        expect(writer).toBeDefined();
2563                        expect(typeof writer.write).toBe('function');
2564                        expect(typeof writer.seek).toBe('function');
2565                        expect(typeof writer.truncate).toBe('function');
2566                        expect(typeof writer.abort).toBe('function');
2567                        // cleanup
2568                        deleteFile(fileName, done);
2569                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2570                }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
2571            });
2572            it("file.spec.96 should be able to write and append to file, createWriter", function (done) {
2573                var fileName = "writer.append.createWriter", // file content
2574                content = "There is an exception to every rule.", // for checkin file length
2575                exception = " Except this one.",
2576                length = content.length;
2577                // create file, then write and append to it
2578                createFile(fileName, function (fileEntry) {
2579                    // writes initial file content
2580                    fileEntry.createWriter(function (writer) {
2581                        //Verifiers declaration
2582                        function verifier(evt) {
2583                            expect(writer.length).toBe(length);
2584                            expect(writer.position).toBe(length);
2585                            // Append some more data
2586                            writer.onwriteend = secondVerifier;
2587                            length += exception.length;
2588                            writer.seek(writer.length);
2589                            writer.write(exception);
2590                        }
2591                        function secondVerifier(evt) {
2592                            expect(writer.length).toBe(length);
2593                            expect(writer.position).toBe(length);
2594                            var reader = new FileReader();
2595                            reader.onloadend = thirdVerifier;
2596                            reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName);
2597                            fileEntry.file(function(f){reader.readAsText(f);});
2598                        }
2599                        function thirdVerifier(evt) {
2600                            expect(evt.target.result).toBe(content+exception);
2601                            // cleanup
2602                            deleteFile(fileName, done);
2603                        }
2604
2605                        //Write process
2606                        writer.onwriteend = verifier;
2607                        writer.write(content);
2608                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2609                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2610            });
2611            it("file.spec.97 should be able to write and append to file, File object", function (done) {
2612                var fileName = "writer.append.File", // file content
2613                content = "There is an exception to every rule.", // for checkin file length
2614                exception = " Except this one.",
2615                length = content.length;
2616                root.getFile(fileName, {
2617                    create : true
2618                }, function (fileEntry) {
2619                    fileEntry.createWriter(function (writer) {
2620                        //Verifiers declaration
2621                        function verifier() {
2622                            expect(writer.length).toBe(length);
2623                            expect(writer.position).toBe(length);
2624                            // Append some more data
2625                            writer.onwriteend = secondVerifier;
2626                            length += exception.length;
2627                            writer.seek(writer.length);
2628                            writer.write(exception);
2629                        }
2630                        function secondVerifier() {
2631                            expect(writer.length).toBe(length);
2632                            expect(writer.position).toBe(length);
2633                            var reader = new FileReader();
2634                            reader.onloadend = thirdVerifier;
2635                            reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName);
2636                            fileEntry.file(function(f){reader.readAsText(f);});
2637                        }
2638                        function thirdVerifier(evt) {
2639                            expect(evt.target.result).toBe(content+exception);
2640                            // cleanup
2641                            deleteFile(fileName, done);
2642                        }
2643
2644                        //Write process
2645                        writer.onwriteend = verifier;
2646                        writer.write(content);
2647                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2648                }, failed.bind(null, done, 'root.getFile - Error creating file: ' + fileName));
2649            });
2650            it("file.spec.98 should be able to seek to the middle of the file and write more data than file.length", function (done) {
2651                var fileName = "writer.seek.write", // file content
2652                content = "This is our sentence.", // for checking file length
2653                exception = "newer sentence.",
2654                length = content.length;
2655                // create file, then write and append to it
2656                createFile(fileName, function (fileEntry) {
2657                    fileEntry.createWriter(function (writer) {
2658                        //Verifiers declaration
2659                        function verifier(evt) {
2660                            expect(writer.length).toBe(length);
2661                            expect(writer.position).toBe(length);
2662                            // Append some more data
2663                            writer.onwriteend = secondVerifier;
2664                            length = 12 + exception.length;
2665                            writer.seek(12);
2666                            writer.write(exception);
2667                        }
2668                        function secondVerifier(evt) {
2669                            expect(writer.length).toBe(length);
2670                            expect(writer.position).toBe(length);
2671                            var reader = new FileReader();
2672                            reader.onloadend = thirdVerifier;
2673                            reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName);
2674                            fileEntry.file(function(f){reader.readAsText(f);});
2675                        }
2676                        function thirdVerifier(evt) {
2677                            expect(evt.target.result).toBe(content.substr(0,12)+exception);
2678                            // cleanup
2679                            deleteFile(fileName, done);
2680                        }
2681
2682                        //Write process
2683                        writer.onwriteend = verifier;
2684                        writer.write(content);
2685                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2686                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2687            });
2688            it("file.spec.99 should be able to seek to the middle of the file and write less data than file.length", function (done) {
2689                if (isChrome) {
2690                    /* Chrome (re)writes as follows: "This is our sentence." -> "This is new.sentence.",
2691                       i.e. the length is not being changed from content.length and writer length will be equal 21 */
2692                    pending();
2693                }
2694
2695                var fileName = "writer.seek.write2", // file content
2696                content = "This is our sentence.", // for checking file length
2697                exception = "new.",
2698                length = content.length;
2699                // create file, then write and append to it
2700                createFile(fileName, function (fileEntry) {
2701                    fileEntry.createWriter(function (writer) {
2702                        // Verifiers declaration
2703                        function verifier(evt) {
2704                            expect(writer.length).toBe(length);
2705                            expect(writer.position).toBe(length);
2706                            // Append some more data
2707                            writer.onwriteend = secondVerifier;
2708                            length = 8 + exception.length;
2709                            writer.seek(8);
2710                            writer.write(exception);
2711                        }
2712                        function secondVerifier(evt) {
2713                            expect(writer.length).toBe(length);
2714                            expect(writer.position).toBe(length);
2715                            var reader = new FileReader();
2716                            reader.onloadend = thirdVerifier;
2717                            reader.onerror = failed.bind(null, done, 'reader.onerror - Error reading file: ' + fileName);
2718                            fileEntry.file(function(f){reader.readAsText(f);});
2719                        }
2720                        function thirdVerifier(evt) {
2721                            expect(evt.target.result).toBe(content.substr(0,8)+exception);
2722                            // cleanup
2723                            deleteFile(fileName, done);
2724                        }
2725
2726                        //Write process
2727                        writer.onwriteend = verifier;
2728                        writer.write(content);
2729                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2730                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2731            });
2732            it("file.spec.100 should be able to write XML data", function (done) {
2733                var fileName = "writer.xml", // file content
2734                content = '<?xml version="1.0" encoding="UTF-8"?>\n<test prop="ack">\nData\n</test>\n', // for testing file length
2735                length = content.length;
2736                // creates file, then write XML data
2737                createFile(fileName, function (fileEntry) {
2738                    fileEntry.createWriter(function (writer) {
2739                        //Verifier content
2740                        var verifier = function (evt) {
2741                            expect(writer.length).toBe(length);
2742                            expect(writer.position).toBe(length);
2743                            // cleanup
2744                            deleteFile(fileName, done);
2745                        };
2746                        //Write process
2747                        writer.onwriteend = verifier;
2748                        writer.write(content);
2749                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2750                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2751            });
2752            it("file.spec.101 should be able to write JSON data", function (done) {
2753                var fileName = "writer.json", // file content
2754                content = '{ "name": "Guy Incognito", "email": "here@there.com" }', // for testing file length
2755                length = content.length;
2756                // creates file, then write JSON content
2757                createFile(fileName, function (fileEntry) {
2758                    fileEntry.createWriter(function (writer) {
2759                        //Verifier declaration
2760                        var verifier = function (evt) {
2761                            expect(writer.length).toBe(length);
2762                            expect(writer.position).toBe(length);
2763                            // cleanup
2764                            deleteFile(fileName, done);
2765                        };
2766                        //Write process
2767                        writer.onwriteend = verifier;
2768                        writer.write(content);
2769                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2770                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2771            });
2772            it("file.spec.102 should be able to seek", function (done) {
2773                var fileName = "writer.seek", // file content
2774                content = "There is an exception to every rule. Except this one.", // for testing file length
2775                length = content.length;
2776                // creates file, then write JSON content
2777                createFile(fileName, function (fileEntry) {
2778                    // writes file content and tests writer.seek
2779                    fileEntry.createWriter(function (writer) {
2780                        //Verifier declaration
2781                        var verifier = function () {
2782                            expect(writer.position).toBe(length);
2783                            writer.seek(-5);
2784                            expect(writer.position).toBe(length - 5);
2785                            writer.seek(length + 100);
2786                            expect(writer.position).toBe(length);
2787                            writer.seek(10);
2788                            expect(writer.position).toBe(10);
2789                            // cleanup
2790                            deleteFile(fileName, done);
2791                        };
2792                        //Write process
2793                        writer.onwriteend = verifier;
2794                        writer.seek(-100);
2795                        expect(writer.position).toBe(0);
2796                        writer.write(content);
2797                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2798                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2799            });
2800            it("file.spec.103 should be able to truncate", function (done) {
2801                if (isIndexedDBShim) {
2802                    /* `abort` and `truncate` functions are not supported (Firefox, IE) */
2803                    pending();
2804                }
2805
2806                var fileName = "writer.truncate",
2807                content = "There is an exception to every rule. Except this one.";
2808                // creates file, writes to it, then truncates it
2809                createFile(fileName, function (fileEntry) {
2810                    fileEntry.createWriter(function (writer) {
2811                        // Verifier declaration
2812                        var verifier = function () {
2813                            expect(writer.length).toBe(36);
2814                            expect(writer.position).toBe(36);
2815                            // cleanup
2816                            deleteFile(fileName, done);
2817                        };
2818                        //Write process
2819                        writer.onwriteend = function () {
2820                            //Truncate process after write
2821                            writer.onwriteend = verifier;
2822                            writer.truncate(36);
2823                        };
2824                        writer.write(content);
2825                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2826                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2827            });
2828            it("file.spec.104 should be able to write binary data from an ArrayBuffer", function (done) {
2829                // Skip test if ArrayBuffers are not supported (e.g.: Android 2.3).
2830                if (typeof window.ArrayBuffer == 'undefined') {
2831                    expect(true).toFailWithMessage('Platform does not supported this feature');
2832                    done();
2833                    return;
2834                }
2835                var fileName = "bufferwriter.bin", // file content
2836                data = new ArrayBuffer(32),
2837                dataView = new Int8Array(data), // for verifying file length
2838                length = 32;
2839                for (var i = 0; i < dataView.length; i++) {
2840                    dataView[i] = i;
2841                }
2842                // creates file, then write content
2843                createFile(fileName, function (fileEntry) {
2844                    // writes file content
2845                    fileEntry.createWriter(function (writer) {
2846                        //Verifier declaration
2847                        var verifier = function () {
2848                            expect(writer.length).toBe(length);
2849                            expect(writer.position).toBe(length);
2850                            // cleanup
2851                            deleteFile(fileName, done);
2852                        };
2853                        //Write process
2854                        writer.onwriteend = verifier;
2855                        writer.write(data);
2856                    }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2857                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2858            });
2859            it("file.spec.105 should be able to write binary data from a Blob", function (done) {
2860                // Skip test if Blobs are not supported (e.g.: Android 2.3).
2861                if ((typeof window.Blob == 'undefined' && typeof window.WebKitBlobBuilder == 'undefined') || typeof window.ArrayBuffer == 'undefined') {
2862                    expect(true).toFailWithMessage('Platform does not supported this feature');
2863                    done();
2864                    return;
2865                }
2866                var fileName = "blobwriter.bin", // file content
2867                data = new ArrayBuffer(32),
2868                dataView = new Int8Array(data),
2869                blob, // for verifying file length
2870                length = 32;
2871                for (var i = 0; i < dataView.length; i++) {
2872                    dataView[i] = i;
2873                }
2874                try {
2875                    // Mobile Safari: Use Blob constructor
2876                    blob = new Blob([data], {
2877                            "type" : "application/octet-stream"
2878                        });
2879                } catch (e) {
2880                    if (window.WebKitBlobBuilder) {
2881                        // Android Browser: Use deprecated BlobBuilder
2882                        var builder = new WebKitBlobBuilder();
2883                        builder.append(data);
2884                        blob = builder.getBlob('application/octet-stream');
2885                    } else {
2886                        // We have no way defined to create a Blob, so fail
2887                        fail();
2888                    }
2889                }
2890                if (typeof blob !== 'undefined') {
2891                    // creates file, then write content
2892                    createFile(fileName, function (fileEntry) {
2893                        fileEntry.createWriter(function (writer) {
2894                            //Verifier declaration
2895                            var verifier = function () {
2896                                expect(writer.length).toBe(length);
2897                                expect(writer.position).toBe(length);
2898                                // cleanup
2899                                deleteFile(fileName, done);
2900                            };
2901                            //Write process
2902                            writer.onwriteend = verifier;
2903                            writer.write(blob);
2904                        }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2905                    }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2906                }
2907            });
2908            it("file.spec.106 should be able to write a File to a FileWriter", function (done) {
2909                var dummyFileName = 'dummy.txt',
2910                outputFileName = 'verify.txt',
2911                dummyFileText = 'This text should be written to two files',
2912                verifier = function (outputFileWriter) {
2913                    expect(outputFileWriter.length).toBe(dummyFileText.length);
2914                    expect(outputFileWriter.position).toBe(dummyFileText.length);
2915                    deleteFile(outputFileName, done);
2916                },
2917                writeFile = function (fileName, fileData, win) {
2918                    var theWriter,
2919                    write_file = function (fileEntry) {
2920                        // writes file content to new file
2921                        fileEntry.createWriter(function (writer) {
2922                            theWriter = writer;
2923                            writer.onwriteend = function (ev) {
2924                                if (typeof fileData.length !== "undefined") {
2925                                    expect(theWriter.length).toBe(fileData.length);
2926                                    expect(theWriter.position).toBe(fileData.length);
2927                                }
2928                                win(theWriter);
2929                            };
2930                            writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName);
2931                            writer.write(fileData);
2932                        }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2933                    };
2934                    createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2935                },
2936                openFile = function (fileName, callback) {
2937                    root.getFile(fileName, {
2938                        create : false
2939                    }, function (fileEntry) {
2940                        fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name));
2941                    }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName));
2942                };
2943                writeFile(dummyFileName, dummyFileText, function (dummyFileWriter) {
2944                    openFile(dummyFileName, function (file) {
2945                        writeFile(outputFileName, file, verifier);
2946                    });
2947                });
2948            });
2949            it("file.spec.107 should be able to write a sliced File to a FileWriter", function (done) {
2950                var dummyFileName = 'dummy2.txt',
2951                outputFileName = 'verify2.txt',
2952                dummyFileText = 'This text should be written to two files',
2953                verifier = function (outputFileWriter) {
2954                    expect(outputFileWriter.length).toBe(10);
2955                    expect(outputFileWriter.position).toBe(10);
2956                    deleteFile(outputFileName, done);
2957                },
2958                writeFile = function (fileName, fileData, win) {
2959                    var theWriter,
2960                    write_file = function (fileEntry) {
2961                        // writes file content to new file
2962                        fileEntry.createWriter(function (writer) {
2963                            theWriter = writer;
2964                            writer.onwriteend = function (ev) {
2965                                if (typeof fileData.length !== "undefined") {
2966                                    expect(theWriter.length).toBe(fileData.length);
2967                                    expect(theWriter.position).toBe(fileData.length);
2968                                }
2969                                win(theWriter);
2970                            };
2971                            writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName);
2972                            writer.write(fileData);
2973                        }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
2974                    };
2975                    createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
2976                },
2977                openFile = function (fileName, callback) {
2978                    root.getFile(fileName, {
2979                        create : false
2980                    }, function (fileEntry) {
2981                        fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name));
2982                    }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName));
2983                };
2984                writeFile(dummyFileName, dummyFileText, function (dummyFileWriter) {
2985                    openFile(dummyFileName, function (file) {
2986                        writeFile(outputFileName, file.slice(10, 20), verifier);
2987                    });
2988                });
2989            });
2990            it("file.spec.108 should be able to write binary data from a File", function (done) {
2991                // Skip test if Blobs are not supported (e.g.: Android 2.3).
2992                if (typeof window.Blob == 'undefined' && typeof window.WebKitBlobBuilder == 'undefined') {
2993                    expect(true).toFailWithMessage('Platform does not supported this feature');
2994                    done();
2995                }
2996                var dummyFileName = "blobwriter.bin",
2997                outputFileName = 'verify.bin', // file content
2998                data = new ArrayBuffer(32),
2999                dataView = new Int8Array(data),
3000                blob, // for verifying file length
3001                length = 32,
3002                verifier = function (outputFileWriter) {
3003                    expect(outputFileWriter.length).toBe(length);
3004                    expect(outputFileWriter.position).toBe(length);
3005                    // cleanup
3006                    deleteFile(outputFileName);
3007                    done();
3008                },
3009                writeFile = function (fileName, fileData, win) {
3010                    var theWriter,
3011                    write_file = function (fileEntry) {
3012                        // writes file content to new file
3013                        fileEntry.createWriter(function (writer) {
3014                            theWriter = writer;
3015                            writer.onwriteend = function (ev) {
3016                                if (typeof fileData.length !== "undefined") {
3017                                    expect(theWriter.length).toBe(fileData.length);
3018                                    expect(theWriter.position).toBe(fileData.length);
3019                                }
3020                                win(theWriter);
3021                            };
3022                            writer.onerror = failed.bind(null, done, 'writer.onerror - Error writing content on file: ' + fileName);
3023                            writer.write(fileData);
3024                        }, failed.bind(null, done, 'fileEntry.createWriter - Error creating writer using fileEntry: ' + fileEntry.name));
3025                    };
3026                    createFile(fileName, write_file, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3027                },
3028                openFile = function (fileName, callback) {
3029                    root.getFile(fileName, {
3030                        create : false
3031                    }, function (fileEntry) {
3032                        fileEntry.file(callback, failed.bind(null, done, 'fileEntry.file - Error reading file using fileEntry: ' + fileEntry.name));
3033                    }, failed.bind(null, done, 'root.getFile - Error getting file: ' + fileName));
3034                };
3035                for (var i = 0; i < dataView.length; i++) {
3036                    dataView[i] = i;
3037                }
3038                try {
3039                    // Mobile Safari: Use Blob constructor
3040                    blob = new Blob([data], {
3041                            "type" : "application/octet-stream"
3042                        });
3043                } catch (e) {
3044                    if (window.WebKitBlobBuilder) {
3045                        // Android Browser: Use deprecated BlobBuilder
3046                        var builder = new WebKitBlobBuilder();
3047                        builder.append(data);
3048                        blob = builder.getBlob('application/octet-stream');
3049                    } else {
3050                        // We have no way defined to create a Blob, so fail
3051                        fail();
3052                    }
3053                }
3054                if (typeof blob !== 'undefined') {
3055                    // creates file, then write content
3056                    writeFile(dummyFileName, blob, function (dummyFileWriter) {
3057                        openFile(dummyFileName, function (file) {
3058                            writeFile(outputFileName, file, verifier);
3059                        });
3060                    });
3061                }
3062            });
3063        });
3064        //FileWritter
3065        describe('Backwards compatibility', function () {
3066            /* These specs exist to test that the File plugin can still recognize file:///
3067             * URLs, and can resolve them to FileEntry and DirectoryEntry objects.
3068             * They rely on an undocumented interface to File which provides absolute file
3069             * paths, which are not used internally anymore.
3070             * If that interface is not present, then these tests will silently succeed.
3071             */
3072            it("file.spec.109 should be able to resolve a file:/// URL", function (done) {
3073                var localFilename = 'file.txt';
3074                var originalEntry;
3075                root.getFile(localFilename, {
3076                    create : true
3077                }, function (entry) {
3078                    originalEntry = entry;
3079                    /* This is an undocumented interface to File which exists only for testing
3080                     * backwards compatibilty. By obtaining the raw filesystem path of the download
3081                     * location, we can pass that to ft.download() to make sure that previously-stored
3082                     * paths are still valid.
3083                     */
3084                    cordova.exec(function (localPath) {
3085                        window.resolveLocalFileSystemURL("file://" + encodeURI(localPath), function (fileEntry) {
3086                            expect(fileEntry.toURL()).toEqual(originalEntry.toURL());
3087                            // cleanup
3088                            deleteFile(localFilename);
3089                            done();
3090                        }, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving URI: file://' + encodeURI(localPath)));
3091                    }, done, 'File', '_getLocalFilesystemPath', [entry.toURL()]);
3092                }, failed.bind(null, done, 'root.getFile - Error creating file: ' + localFilename));
3093            });
3094        });
3095        //Backwards Compatibility
3096        describe('Parent References', function () {
3097            /* These specs verify that paths with parent references i("..") in them
3098             * work correctly, and do not cause the application to crash.
3099             */
3100            it("file.spec.110 should not throw exception resolving parent refefences", function (done) {
3101                /* This is a direct copy of file.spec.9, with the filename changed, * as reported in CB-5721.
3102                 */
3103                var fileName = "resolve.file.uri";
3104                var dirName = "resolve.dir.uri";
3105                // create a new file entry
3106                createDirectory(dirName, function () {
3107                    createFile(dirName+"/../" + fileName, function (entry) {
3108                        // lookup file system entry
3109                        window.resolveLocalFileSystemURL(entry.toURL(), function (fileEntry) {
3110                            expect(fileEntry).toBeDefined();
3111                            expect(fileEntry.name).toCanonicallyMatch(fileName);
3112                            // cleanup
3113                            deleteEntry(fileName, done);
3114                        }, failed.bind(null, done, 'window.resolveLocalFileSystemURL - Error resolving URI: ' + entry.toURL()));
3115                    }, failed.bind(null, done, 'createFile - Error creating file: ../' + fileName));
3116                }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + dirName));
3117            });
3118            it("file.spec.111 should not traverse above above the root directory", function (done) {
3119                var fileName = "traverse.file.uri";
3120                // create a new file entry
3121                createFile(fileName, function (entry) {
3122                    // lookup file system entry
3123                    root.getFile('../' + fileName, {
3124                        create : false
3125                    }, function (fileEntry) {
3126                        // Note: we expect this to still resolve, as the correct behaviour is to ignore the ../, not to fail out.
3127                        expect(fileEntry).toBeDefined();
3128                        expect(fileEntry.name).toBe(fileName);
3129                        expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath +'/' + fileName);
3130                        // cleanup
3131                        deleteEntry(fileName, done);
3132                    }, failed.bind(null, done, 'root.getFile - Error getting file: ../' + fileName));
3133                }, failed.bind(null, done, 'createFile - Error creating file: ../' + fileName));
3134            });
3135            it("file.spec.112 should traverse above above the current directory", function (done) {
3136                var fileName = "traverse2.file.uri",
3137                dirName = "traverse2.subdir";
3138                // create a new directory and a file entry
3139                createFile(fileName, function () {
3140                    createDirectory(dirName, function (entry) {
3141                        // lookup file system entry
3142                        entry.getFile('../' + fileName, {
3143                            create : false
3144                        }, function (fileEntry) {
3145                            expect(fileEntry).toBeDefined();
3146                            expect(fileEntry.name).toBe(fileName);
3147                            expect(fileEntry.fullPath).toCanonicallyMatch('/' + fileName);
3148                            // cleanup
3149                            deleteEntry(fileName, function () {
3150                                deleteEntry(dirName, done);
3151                            });
3152                        }, failed.bind(null, done, 'entry.getFile - Error getting file: ' + fileName + ' recently created above: ' + dirName));
3153                    }, failed.bind(null, done, 'createDirectory - Error creating directory: ' + dirName));
3154                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3155            });
3156            it("file.spec.113 getFile: get Entry should error for missing file above root directory", function (done) {
3157                var fileName = "../missing.file";
3158                // create:false, exclusive:false, file does not exist
3159                root.getFile(fileName, {
3160                    create : false
3161                }, succeed.bind(null, done, 'root.getFile - Unexpected success callback, it should not locate nonexistent file: ' + fileName), function (error) {
3162                    expect(error).toBeDefined();
3163                    expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
3164                    done();
3165                });
3166            });
3167        });
3168        //Parent References
3169        describe('toNativeURL interface', function () {
3170            /* These specs verify that FileEntries have a toNativeURL method
3171             * which appears to be sane.
3172             */
3173            var pathExpect = cordova.platformId === 'windowsphone' ? "//nativ" : "file://";
3174            if (isChrome) {
3175                pathExpect = 'filesystem:file://';
3176            }
3177            it("file.spec.114 fileEntry should have a toNativeURL method", function (done) {
3178                var fileName = "native.file.uri";
3179                if (isWindows) {
3180                    var rootPath = root.fullPath;
3181                    pathExpect = rootPath.substr(0, rootPath.indexOf(":"));
3182                }
3183                // create a new file entry
3184                createFile(fileName, function (entry) {
3185                    expect(entry.toNativeURL).toBeDefined();
3186                    expect(entry.name).toCanonicallyMatch(fileName);
3187                    expect(typeof entry.toNativeURL).toBe('function');
3188                    var nativeURL = entry.toNativeURL();
3189                    expect(typeof nativeURL).toBe("string");
3190                    expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect);
3191                    expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName);
3192                    // cleanup
3193                    deleteEntry(fileName, done);
3194                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3195            });
3196            it("file.spec.115 DirectoryReader should return entries with toNativeURL method", function (done) {
3197                var dirName = 'nativeEntries.dir',
3198                fileName = 'nativeEntries.file',
3199                directory,
3200                checkEntries = function (entries) {
3201                    expect(entries).toBeDefined();
3202                    expect(entries instanceof Array).toBe(true);
3203                    expect(entries.length).toBe(1);
3204                    expect(entries[0].toNativeURL).toBeDefined();
3205                    expect(typeof entries[0].toNativeURL).toBe('function');
3206                    var nativeURL = entries[0].toNativeURL();
3207                    expect(typeof nativeURL).toBe("string");
3208                    expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect);
3209                    expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName);
3210                    // cleanup
3211                    directory.removeRecursively(null, null);
3212                    done();
3213                };
3214                // create a new file entry
3215                root.getDirectory(dirName, {
3216                    create : true
3217                }, function (dir) {
3218                    directory = dir;
3219                    directory.getFile(fileName, {
3220                        create : true
3221                    }, function (fileEntry) {
3222                        var reader = directory.createReader();
3223                        reader.readEntries(checkEntries, failed.bind(null, done, 'reader.readEntries - Error reading entries from directory: ' + dirName));
3224                    }, failed.bind(null, done, 'directory.getFile - Error creating file: ' + fileName));
3225                }, failed.bind(null, done, 'root.getDirectory - Error creating directory: ' + dirName));
3226            });
3227            it("file.spec.116 resolveLocalFileSystemURL should return entries with toNativeURL method", function (done) {
3228                var fileName = "native.resolve.uri";
3229                // create a new file entry
3230                createFile(fileName, function (entry) {
3231                    resolveLocalFileSystemURL(entry.toURL(), function (entry) {
3232                        expect(entry.toNativeURL).toBeDefined();
3233                        expect(entry.name).toCanonicallyMatch(fileName);
3234                        expect(typeof entry.toNativeURL).toBe('function');
3235                        var nativeURL = entry.toNativeURL();
3236                        expect(typeof nativeURL).toBe("string");
3237                        expect(nativeURL.substring(0, pathExpect.length)).toEqual(pathExpect);
3238                        expect(nativeURL.substring(nativeURL.length - fileName.length)).toEqual(fileName);
3239                        // cleanup
3240                        deleteEntry(fileName, done);
3241                    }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toURL()));
3242                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3243            });
3244        });
3245        //toNativeURL interface
3246        describe('resolveLocalFileSystemURL on file://', function () {
3247            /* These specs verify that window.resolveLocalFileSystemURL works correctly on file:// URLs
3248             */
3249            it("file.spec.117 should not resolve native URLs outside of FS roots", function (done) {
3250                // lookup file system entry
3251                window.resolveLocalFileSystemURL("file:///this.is.an.invalid.url", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file:///this.is.an.invalid.url'), function (error) {
3252                    expect(error).toBeDefined();
3253                    done();
3254                });
3255            });
3256            it("file.spec.118 should not resolve native URLs outside of FS roots", function (done) {
3257                // lookup file system entry
3258                window.resolveLocalFileSystemURL("file://localhost/this.is.an.invalid.url", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost/this.is.an.invalid.url'), function (error) {
3259                    expect(error).toBeDefined();
3260                    done();
3261                });
3262            });
3263            it("file.spec.119 should not resolve invalid native URLs", function (done) {
3264                // lookup file system entry
3265                window.resolveLocalFileSystemURL("file://localhost", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost'), function (error) {
3266                    expect(error).toBeDefined();
3267                    done();
3268                });
3269            });
3270            it("file.spec.120 should not resolve invalid native URLs with query strings", function (done) {
3271                // lookup file system entry
3272                window.resolveLocalFileSystemURL("file://localhost?test/test", succeed.bind(null, done, 'window.resolveLocalFileSystemURL - Unexpected success callback, it should not resolve invalid URL: file://localhost?test/test'), function (error) {
3273                    expect(error).toBeDefined();
3274                    done();
3275                });
3276            });
3277            it("file.spec.121 should resolve native URLs returned by API", function (done) {
3278                var fileName = "native.resolve.uri1";
3279                // create a new file entry
3280                createFile(fileName, function (entry) {
3281                    resolveLocalFileSystemURL(entry.toNativeURL(), function (fileEntry) {
3282                        expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName);
3283                        // cleanup
3284                        deleteEntry(fileName, done);
3285                    }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + entry.toNativeURL()));
3286                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3287            });
3288            it("file.spec.122 should resolve native URLs returned by API with localhost", function (done) {
3289                var fileName = "native.resolve.uri2";
3290                // create a new file entry
3291                createFile(fileName, function (entry) {
3292                    var url = entry.toNativeURL();
3293                    url = url.replace("///", "//localhost/");
3294                    resolveLocalFileSystemURL(url, function (fileEntry) {
3295                        expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName);
3296                        // cleanup
3297                        deleteEntry(fileName, done);
3298                    }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url));
3299                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3300            });
3301            it("file.spec.123 should resolve native URLs returned by API with query string", function (done) {
3302                var fileName = "native.resolve.uri3";
3303                // create a new file entry
3304                createFile(fileName, function (entry) {
3305                    var url = entry.toNativeURL();
3306                    url = url + "?test/test";
3307                    resolveLocalFileSystemURL(url, function (fileEntry) {
3308                        expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName);
3309                        // cleanup
3310                        deleteEntry(fileName, done);
3311                    }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url));
3312                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3313            });
3314            it("file.spec.124 should resolve native URLs returned by API with localhost and query string", function (done) {
3315                var fileName = "native.resolve.uri4";
3316                // create a new file entry
3317                createFile(fileName, function (entry) {
3318                    var url = entry.toNativeURL();
3319                    url = url.replace("///", "//localhost/") + "?test/test";
3320                    resolveLocalFileSystemURL(url, function (fileEntry) {
3321                        expect(fileEntry.fullPath).toCanonicallyMatch(root.fullPath + "/" + fileName);
3322                        // cleanup
3323                        deleteEntry(fileName, done);
3324                    }, failed.bind(null, done, 'resolveLocalFileSystemURL - Error resolving file URL: ' + url));
3325                }, failed.bind(null, done, 'createFile - Error creating file: ' + fileName));
3326            });
3327        });
3328        //resolveLocalFileSystemURL on file://
3329        describe('cross-file-system copy and move', function () {
3330            /* These specs verify that Entry.copyTo and Entry.moveTo work correctly
3331             * when crossing filesystem boundaries.
3332             */
3333            it("file.spec.125 copyTo: temporary -> persistent", function (done) {
3334                var file1 = "entry.copy.file1a",
3335                file2 = "entry.copy.file2a",
3336                sourceEntry,
3337                fullPath = joinURL(root.fullPath, file2),
3338                validateFile = function (entry) {
3339                    // a bit redundant since copy returned this entry already
3340                    expect(entry).toBeDefined();
3341                    expect(entry.isFile).toBe(true);
3342                    expect(entry.isDirectory).toBe(false);
3343                    expect(entry.name).toCanonicallyMatch(file2);
3344                    expect(entry.fullPath).toCanonicallyMatch(fullPath);
3345                    expect(entry.filesystem).toBeDefined();
3346                    if (isChrome) {
3347                        expect(entry.filesystem.name).toContain("Persistent");
3348                    } else {
3349                        expect(entry.filesystem.name).toEqual("persistent");
3350                    }
3351                    // cleanup
3352                    deleteEntry(entry.name);
3353                    deleteEntry(sourceEntry.name, done);
3354                },
3355                createSourceAndTransfer = function () {
3356                    temp_root.getFile(file1, {
3357                        create : true
3358                    }, function (entry) {
3359                        expect(entry.filesystem).toBeDefined();
3360                        if (isChrome) {
3361                            expect(entry.filesystem.name).toContain("Temporary");
3362                        } else {
3363                            expect(entry.filesystem.name).toEqual("temporary");
3364                        }
3365                        sourceEntry = entry;
3366                        // Save for later cleanup
3367                        entry.copyTo(persistent_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + file1 + ' to PERSISTENT root as: ' + file2));
3368                    }, failed.bind(null, done, 'temp_root.getFile - Error creating file: ' + file1 + 'at TEMPORAL root'));
3369                };
3370                // Delete any existing file to start things off
3371                persistent_root.getFile(file2, {}, function (entry) {
3372                    entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3373                }, createSourceAndTransfer);
3374            });
3375            it("file.spec.126 copyTo: persistent -> temporary", function (done) {
3376                var file1 = "entry.copy.file1b",
3377                file2 = "entry.copy.file2b",
3378                sourceEntry,
3379                fullPath = joinURL(temp_root.fullPath, file2),
3380                validateFile = function (entry) {
3381                    expect(entry).toBeDefined();
3382                    expect(entry.isFile).toBe(true);
3383                    expect(entry.isDirectory).toBe(false);
3384                    expect(entry.name).toCanonicallyMatch(file2);
3385                    expect(entry.fullPath).toCanonicallyMatch(fullPath);
3386                    if (isChrome) {
3387                        expect(entry.filesystem.name).toContain("Temporary");
3388                    } else {
3389                        expect(entry.filesystem.name).toEqual("temporary");
3390                    }
3391                    // cleanup
3392                    deleteEntry(entry.name);
3393                    deleteEntry(sourceEntry.name, done);
3394                },
3395                createSourceAndTransfer = function () {
3396                    persistent_root.getFile(file1, {
3397                        create : true
3398                    }, function (entry) {
3399                        expect(entry).toBeDefined();
3400                        expect(entry.filesystem).toBeDefined();
3401                        if (isChrome) {
3402                            expect(entry.filesystem.name).toContain("Persistent");
3403                        } else {
3404                            expect(entry.filesystem.name).toEqual("persistent");
3405                        }
3406                        sourceEntry = entry;
3407                        // Save for later cleanup
3408                        entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + file1 + ' to TEMPORAL root as: ' + file2));
3409                    }, failed.bind(null, done, 'persistent_root.getFile - Error creating file: ' + file1 + 'at PERSISTENT root'));
3410                };
3411                // Delete any existing file to start things off
3412                temp_root.getFile(file2, {}, function (entry) {
3413                    entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3414                }, createSourceAndTransfer);
3415            });
3416            it("file.spec.127 moveTo: temporary -> persistent", function (done) {
3417                var file1 = "entry.copy.file1a",
3418                file2 = "entry.copy.file2a",
3419                sourceEntry,
3420                fullPath = joinURL(root.fullPath, file2),
3421                validateFile = function (entry) {
3422                    // a bit redundant since copy returned this entry already
3423                    expect(entry).toBeDefined();
3424                    expect(entry.isFile).toBe(true);
3425                    expect(entry.isDirectory).toBe(false);
3426                    expect(entry.name).toCanonicallyMatch(file2);
3427                    expect(entry.fullPath).toCanonicallyMatch(fullPath);
3428                    expect(entry.filesystem).toBeDefined();
3429                    if (isChrome) {
3430                        expect(entry.filesystem.name).toContain("Persistent");
3431                    } else {
3432                        expect(entry.filesystem.name).toEqual("persistent");
3433                    }
3434                    // cleanup
3435                    deleteEntry(entry.name);
3436                    deleteEntry(sourceEntry.name, done);
3437                },
3438                createSourceAndTransfer = function () {
3439                    temp_root.getFile(file1, {
3440                        create : true
3441                    }, function (entry) {
3442                        expect(entry.filesystem).toBeDefined();
3443                        if (isChrome) {
3444                            expect(entry.filesystem.name).toContain("Temporary");
3445                        } else {
3446                            expect(entry.filesystem.name).toEqual("temporary");
3447                        }
3448                        sourceEntry = entry;
3449                        // Save for later cleanup
3450                        entry.moveTo(persistent_root, file2, validateFile, failed.bind(null, done, 'entry.moveTo - Error moving file: ' + file1 + ' to PERSISTENT root as: ' + file2));
3451                    }, failed.bind(null, done, 'temp_root.getFile - Error creating file: ' + file1 + 'at TEMPORAL root'));
3452                };
3453                // Delete any existing file to start things off
3454                persistent_root.getFile(file2, {}, function (entry) {
3455                    entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3456                }, createSourceAndTransfer);
3457            });
3458            it("file.spec.128 moveTo: persistent -> temporary", function (done) {
3459                var file1 = "entry.copy.file1b",
3460                file2 = "entry.copy.file2b",
3461                sourceEntry,
3462                fullPath = joinURL(temp_root.fullPath, file2),
3463                validateFile = function (entry) {
3464                    expect(entry).toBeDefined();
3465                    expect(entry.isFile).toBe(true);
3466                    expect(entry.isDirectory).toBe(false);
3467                    expect(entry.name).toCanonicallyMatch(file2);
3468                    expect(entry.fullPath).toCanonicallyMatch(fullPath);
3469                    if(isChrome) {
3470                        expect(entry.filesystem.name).toContain("Temporary");
3471                    } else {
3472                        expect(entry.filesystem.name).toEqual("temporary");
3473                    }
3474                    // cleanup
3475                    deleteEntry(entry.name);
3476                    deleteEntry(sourceEntry.name, done);
3477                },
3478                createSourceAndTransfer = function () {
3479                    persistent_root.getFile(file1, {
3480                        create : true
3481                    }, function (entry) {
3482                        expect(entry).toBeDefined();
3483                        expect(entry.filesystem).toBeDefined();
3484                        if (isChrome) {
3485                            expect(entry.filesystem.name).toContain("Persistent");
3486                        } else {
3487                            expect(entry.filesystem.name).toEqual("persistent");
3488                        }
3489                        sourceEntry = entry;
3490                        // Save for later cleanup
3491                        entry.moveTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.moveTo - Error moving file: ' + file1 + ' to TEMPORAL root as: ' + file2));
3492                    }, failed.bind(null, done, 'persistent_root.getFile - Error creating file: ' + file1 + 'at PERSISTENT root'));
3493                };
3494                // Delete any existing file to start things off
3495                temp_root.getFile(file2, {}, function (entry) {
3496                    entry.remove(createSourceAndTransfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3497                }, createSourceAndTransfer);
3498            });
3499            it("file.spec.129 cordova.file.*Directory are set", function () {
3500                var expectedPaths = ['applicationDirectory', 'applicationStorageDirectory', 'dataDirectory', 'cacheDirectory'];
3501                if (cordova.platformId == 'android' || cordova.platformId == 'amazon-fireos') {
3502                    if (cordova.file.externalApplicationStorageDirectory !== null) {
3503                        // https://issues.apache.org/jira/browse/CB-10411
3504                        // If external storage can't be mounted, the cordova.file.external* properties are null.
3505                        expectedPaths.push('externalApplicationStorageDirectory', 'externalRootDirectory', 'externalCacheDirectory', 'externalDataDirectory');
3506                    }
3507                } else if (cordova.platformId == 'blackberry10') {
3508                    expectedPaths.push('externalRootDirectory', 'sharedDirectory');
3509                } else if (cordova.platformId == 'ios') {
3510                    expectedPaths.push('syncedDataDirectory', 'documentsDirectory', 'tempDirectory');
3511                } else if (cordova.platformId == 'osx') {
3512                    expectedPaths.push('documentsDirectory', 'tempDirectory', 'rootDirectory');
3513                } else {
3514                    console.log('Skipping test due on unsupported platform.');
3515                    return;
3516                }
3517                for (var i = 0; i < expectedPaths.length; ++i) {
3518                    expect(typeof cordova.file[expectedPaths[i]]).toBe('string');
3519                    expect(cordova.file[expectedPaths[i]]).toMatch(/\/$/, 'Path should end with a slash');
3520                }
3521            });
3522        });
3523        describe('resolveLocalFileSystemURL on cdvfile://', function () {
3524            it("file.spec.147 should be able to resolve cdvfile applicationDirectory fs root", function(done) {
3525                var cdvfileApplicationDirectoryFsRootName;
3526                if (cordova.platformId === 'android') {
3527                    cdvfileApplicationDirectoryFsRootName = 'assets';
3528                } else if (cordova.platformId === 'ios') {
3529                    cdvfileApplicationDirectoryFsRootName = 'bundle';
3530                } else {
3531                    pending();
3532                }
3533
3534                resolveLocalFileSystemURL('cdvfile://localhost/' + cdvfileApplicationDirectoryFsRootName + '/', function(applicationDirectoryRoot) {
3535                    expect(applicationDirectoryRoot.isFile).toBe(false);
3536                    expect(applicationDirectoryRoot.isDirectory).toBe(true);
3537                    expect(applicationDirectoryRoot.name).toCanonicallyMatch('');
3538                    expect(applicationDirectoryRoot.fullPath).toCanonicallyMatch('/');
3539                    expect(applicationDirectoryRoot.filesystem.name).toEqual(cdvfileApplicationDirectoryFsRootName);
3540
3541                    // Requires HelloCordova www assets, <allow-navigation href="cdvfile:*" /> in config.xml or
3542                    // cdvfile: in CSP and <access origin="cdvfile://*" /> in config.xml
3543                    resolveLocalFileSystemURL('cdvfile://localhost/' + cdvfileApplicationDirectoryFsRootName + '/www/img/logo.png', function(entry) {
3544                        expect(entry.isFile).toBe(true);
3545                        expect(entry.isDirectory).toBe(false);
3546                        expect(entry.name).toCanonicallyMatch('logo.png');
3547                        expect(entry.fullPath).toCanonicallyMatch('/www/img/logo.png');
3548                        expect(entry.filesystem.name).toEqual(cdvfileApplicationDirectoryFsRootName);
3549
3550                        var img = new Image();
3551                        img.onerror = function(err) {
3552                            expect(err).not.toBeDefined();
3553                            done();
3554                        };
3555                        img.onload = function() {
3556                            done();
3557                        };
3558                        img.src = entry.toInternalURL();
3559                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for cdvfile applicationDirectory'));
3560                }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for cdvfile applicationDirectory'));
3561            });
3562        });
3563        //cross-file-system copy and move
3564        describe('IndexedDB-based impl', function () {
3565            it("file.spec.131 Nested file or nested directory should be removed when removing a parent directory", function (done) {
3566                var parentDirName = 'deletedDir131',
3567                    nestedDirName = 'nestedDir131',
3568                    nestedFileName = 'nestedFile131.txt';
3569
3570                createDirectory(parentDirName, function (parent) {
3571                    parent.getDirectory(nestedDirName, { create: true}, function () {
3572                        parent.getFile(nestedFileName, { create: true}, function () {
3573                            parent.removeRecursively(function() {
3574                                root.getDirectory(parentDirName,{ create: false}, failed.bind(this, done, 'root.getDirectory - unexpected success callback : ' + parentDirName), function(){
3575                                    parent.getFile(nestedFileName,{ create: false}, failed.bind(this, done, 'getFile - unexpected success callback : ' + nestedFileName), function(){
3576                                            parent.getDirectory(nestedDirName, { create: false}, failed.bind(this, done, 'getDirectory - unexpected success callback : ' + nestedDirName), done);
3577                                        });
3578                                    });
3579                                }, failed.bind(this, done, 'removeRecursively - Error removing directory : ' + parentDirName));
3580                        }, failed.bind(this, done, 'getFile - Error creating file : ' + nestedFileName));
3581                    },failed.bind(this, done, 'getDirectory - Error creating directory : ' + nestedDirName));
3582                }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + parentDirName));
3583            });
3584            it("file.spec.132 Entry should be created succesfully when using relative paths if its parent directory exists", function (done) {
3585                /* Directory entries have to be created successively.
3586                   For example, the call `fs.root.getDirectory('dir1/dir2', {create:true}, successCallback, errorCallback)`
3587                   will fail if dir1 did not exist. */
3588                var parentName = 'parentName132';
3589                var nestedName = 'nestedName132';
3590                var path = parentName + '/' + nestedName;
3591
3592                var win = function(directory){
3593                    expect(directory).toBeDefined();
3594                    expect(directory.isFile).toBe(false);
3595                    expect(directory.isDirectory).toBe(true);
3596                    expect(directory.name).toCanonicallyMatch(nestedName);
3597                    expect(directory.fullPath).toCanonicallyMatch('/' + path + '/');
3598                    deleteEntry(directory.name);
3599                    deleteEntry(parentName, done);
3600                };
3601
3602                createDirectory(parentName, function() {
3603                    root.getDirectory(parentName + '/' + nestedName, {create:true}, win,
3604                        failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + path));
3605                }, failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + parentName));
3606            });
3607            it("file.spec.133 A file being removed should not affect another file with name being a prefix of the removed file name.", function (done) {
3608
3609                // Names include special symbols so that we check the IndexedDB range used
3610                var deletedFileName = 'deletedFile.0',
3611                secondFileName = 'deletedFile.0.1';
3612
3613                var win = function(fileEntry){
3614                    expect(fileEntry).toBeDefined();
3615                    expect(fileEntry.isFile).toBe(true);
3616                    expect(fileEntry.isDirectory).toBe(false);
3617                    expect(fileEntry.name).toCanonicallyMatch(secondFileName);
3618                    deleteEntry(fileEntry.name, done);
3619                };
3620
3621                createFile(deletedFileName, function (deletedFile) {
3622                    createFile(secondFileName, function () {
3623                        deletedFile.remove(function() {
3624                            root.getFile(deletedFileName, {create: false}, failed.bind(this, done, 'getFile - unexpected success callback getting deleted file : ' + deletedFileName), function(){
3625                                root.getFile(secondFileName, {create: false}, win, failed.bind(this, done, 'getFile - Error getting file after deleting deletedFile : ' + secondFileName));
3626                            });
3627                        }, failed.bind(this, done, 'remove - Error removing file : ' + deletedFileName));
3628                    }, failed.bind(this, done, 'getFile - Error creating file : ' + secondFileName));
3629                }, failed.bind(this, done, 'getFile - Error creating file : ' + deletedFileName));
3630            });
3631            it("file.spec.134 A directory being removed should not affect another directory with name being a prefix of the removed directory name.", function (done) {
3632
3633                // Names include special symbols so that we check the IndexedDB range used
3634                var deletedDirName = 'deletedDir.0',
3635                secondDirName = 'deletedDir.0.1';
3636
3637                var win = function(directory){
3638                    expect(directory).toBeDefined();
3639                    expect(directory.isFile).toBe(false);
3640                    expect(directory.isDirectory).toBe(true);
3641                    expect(directory.name).toCanonicallyMatch(secondDirName);
3642                    deleteEntry(directory.name, done);
3643                };
3644
3645                createDirectory(deletedDirName, function (deletedDir) {
3646                    createDirectory(secondDirName, function () {
3647                        deletedDir.remove(function() {
3648                            root.getDirectory(deletedDirName, {create: false}, failed.bind(this, done, 'getDirectory - unexpected success callback getting deleted directory : ' + deletedDirName), function() {
3649                                root.getDirectory(secondDirName, {create: false}, win, failed.bind(this, done, 'getDirectory - Error getting directory after deleting deletedDirectory : ' + secondDirName));
3650                            });
3651                        }, failed.bind(this, done, 'remove - Error removing directory : ' + deletedDirName));
3652                    }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + secondDirName));
3653                }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + deletedDirName));
3654            });
3655            it("file.spec.135 Deletion of a child directory should not affect the parent directory.", function (done) {
3656
3657                var parentName = 'parentName135';
3658                var childName = 'childName135';
3659
3660                var win = function(directory){
3661                    expect(directory).toBeDefined();
3662                    expect(directory.isFile).toBe(false);
3663                    expect(directory.isDirectory).toBe(true);
3664                    expect(directory.name).toCanonicallyMatch(parentName);
3665                    deleteEntry(directory.name, done);
3666                };
3667
3668                createDirectory(parentName, function(parent){
3669                    parent.getDirectory(childName, {create: true}, function(child){
3670                        child.removeRecursively(function(){
3671                            root.getDirectory(parentName, {create: false}, win, failed.bind(this, done, 'root.getDirectory - Error getting parent directory : ' + parentName));
3672                        },
3673                        failed.bind(this, done, 'getDirectory - Error removing directory : ' + childName));
3674                    }, failed.bind(this, done, 'getDirectory - Error creating directory : ' + childName));
3675                }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + parentName));
3676            });
3677            it("file.spec.136 Paths should support Unicode symbols.", function (done) {
3678
3679                var dirName = '文件插件';
3680
3681                var win = function(directory){
3682                    expect(directory).toBeDefined();
3683                    expect(directory.isFile).toBe(false);
3684                    expect(directory.isDirectory).toBe(true);
3685                    expect(directory.name).toCanonicallyMatch(dirName);
3686                    deleteEntry(directory.name, done);
3687                };
3688
3689                createDirectory(dirName, function(){
3690                    root.getDirectory(dirName, {create: false}, win,
3691                        failed.bind(this, done, 'root.getDirectory - Error getting directory : ' + dirName));
3692                }, failed.bind(this, done, 'root.getDirectory - Error creating directory : ' + dirName));
3693            });
3694        });
3695        // Content and Asset URLs
3696        if (cordova.platformId == 'android') {
3697            describe('content: URLs', function() {
3698                // Warning: Default HelloWorld www directory structure is required for these tests (www/index.html at least)
3699                function testContentCopy(src, done) {
3700                    var file2 = "entry.copy.file2b",
3701                    fullPath = joinURL(temp_root.fullPath, file2),
3702                    validateFile = function (entry) {
3703                        expect(entry.isFile).toBe(true);
3704                        expect(entry.isDirectory).toBe(false);
3705                        expect(entry.name).toCanonicallyMatch(file2);
3706                        expect(entry.fullPath).toCanonicallyMatch(fullPath);
3707                        expect(entry.filesystem.name).toEqual("temporary");
3708                        // cleanup
3709                        deleteEntry(entry.name, done);
3710                    },
3711                    transfer = function () {
3712                        resolveLocalFileSystemURL(src, function(entry) {
3713                            expect(entry).toBeDefined();
3714                            expect(entry.filesystem.name).toEqual("content");
3715                            entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2));
3716                        }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider'));
3717                    };
3718                    // Delete any existing file to start things off
3719                    temp_root.getFile(file2, {}, function (entry) {
3720                        entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3721                    }, transfer);
3722                }
3723                it("file.spec.138 copyTo: content", function(done) {
3724                    testContentCopy('content://org.apache.cordova.file.testprovider/www/index.html', done);
3725                });
3726                it("file.spec.139 copyTo: content /w space and query", function(done) {
3727                    testContentCopy('content://org.apache.cordova.file.testprovider/?name=foo%20bar&realPath=%2Fwww%2Findex.html', done);
3728                });
3729                it("file.spec.140 delete: content should fail", function(done) {
3730                    resolveLocalFileSystemURL('content://org.apache.cordova.file.testprovider/www/index.html', function(entry) {
3731                        entry.remove(failed.bind(null, done, 'expected delete to fail'), done);
3732                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for content provider'));
3733                });
3734            });
3735
3736            // these tests ensure that you can read and copy from android_asset folder
3737            // for details see https://issues.apache.org/jira/browse/CB-6428
3738            // and https://mail-archives.apache.org/mod_mbox/cordova-dev/201508.mbox/%3C782154441.8406572.1440182722528.JavaMail.yahoo%40mail.yahoo.com%3E
3739            describe('asset: URLs', function() {
3740                it("file.spec.141 filePaths.applicationStorage", function() {
3741                    expect(cordova.file.applicationDirectory).toEqual('file:///android_asset/');
3742                }, MEDIUM_TIMEOUT);
3743                it("file.spec.142 assets should be enumerable", function(done) {
3744                    resolveLocalFileSystemURL('file:///android_asset/www/fixtures/asset-test', function(entry) {
3745                        var reader = entry.createReader();
3746                        reader.readEntries(function (entries) {
3747                            expect(entries.length).not.toBe(0);
3748                            done();
3749                        }, failed.bind(null, done, 'reader.readEntries - Error during reading of entries from assets directory'));
3750                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
3751                }, MEDIUM_TIMEOUT);
3752                it("file.spec.145 asset subdirectories should be obtainable", function(done) {
3753                    resolveLocalFileSystemURL('file:///android_asset/www/fixtures', function(entry) {
3754                        entry.getDirectory('asset-test', { create: false }, function (subDir) {
3755                            expect(subDir).toBeDefined();
3756                            expect(subDir.isFile).toBe(false);
3757                            expect(subDir.isDirectory).toBe(true);
3758                            expect(subDir.name).toCanonicallyMatch('asset-test');
3759                            done();
3760                        }, failed.bind(null, done, 'entry.getDirectory - Error getting asset subdirectory'));
3761                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
3762                }, MEDIUM_TIMEOUT);
3763                it("file.spec.146 asset files should be readable", function(done) {
3764                    resolveLocalFileSystemURL('file:///android_asset/www/fixtures/asset-test/asset-test.txt', function(entry) {
3765                        expect(entry.isFile).toBe(true);
3766                        entry.file(function (file) {
3767                            expect(file).toBeDefined();
3768                            var reader = new FileReader();
3769                            reader.onerror = failed.bind(null, done, 'reader.readAsText - Error reading asset text file');
3770                            reader.onloadend = function () {
3771                                expect(this.result).toBeDefined();
3772                                expect(this.result.length).not.toBe(0);
3773                                done();
3774                            };
3775                            reader.readAsText(file);
3776                        }, failed.bind(null, done, 'entry.file - Error reading asset file'));
3777                    }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
3778                }, MEDIUM_TIMEOUT);
3779                it("file.spec.143 copyTo: asset -> temporary", function(done) {
3780                    var file2 = "entry.copy.file2b",
3781                    fullPath = joinURL(temp_root.fullPath, file2),
3782                    validateFile = function (entry) {
3783                        expect(entry.isFile).toBe(true);
3784                        expect(entry.isDirectory).toBe(false);
3785                        expect(entry.name).toCanonicallyMatch(file2);
3786                        expect(entry.fullPath).toCanonicallyMatch(fullPath);
3787                        expect(entry.filesystem.name).toEqual("temporary");
3788                        // cleanup
3789                        deleteEntry(entry.name, done);
3790                    },
3791                    transfer = function () {
3792                        resolveLocalFileSystemURL('file:///android_asset/www/index.html', function(entry) {
3793                            expect(entry.filesystem.name).toEqual('assets');
3794                            entry.copyTo(temp_root, file2, validateFile, failed.bind(null, done, 'entry.copyTo - Error copying file: ' + entry.toURL() + ' to TEMPORAL root as: ' + file2));
3795                        }, failed.bind(null, done, 'resolveLocalFileSystemURL failed for assets'));
3796                    };
3797                    // Delete any existing file to start things off
3798                    temp_root.getFile(file2, {}, function (entry) {
3799                        entry.remove(transfer, failed.bind(null, done, 'entry.remove - Error removing file: ' + file2));
3800                    }, transfer);
3801                }, MEDIUM_TIMEOUT);
3802            });
3803            it("file.spec.144 copyTo: asset directory", function (done) {
3804                var srcUrl = 'file:///android_asset/www/fixtures/asset-test';
3805                var dstDir = "entry.copy.dstDir";
3806                var dstPath = joinURL(root.fullPath, dstDir);
3807                // create a new directory entry to kick off it
3808                deleteEntry(dstDir, function () {
3809                    resolveLocalFileSystemURL(srcUrl, function(directory) {
3810                        directory.copyTo(root, dstDir, function (directory) {
3811                            expect(directory).toBeDefined();
3812                            expect(directory.isFile).toBe(false);
3813                            expect(directory.isDirectory).toBe(true);
3814                            expect(directory.fullPath).toCanonicallyMatch(dstPath);
3815                            expect(directory.name).toCanonicallyMatch(dstDir);
3816                            root.getDirectory(dstDir, {
3817                                create : false
3818                            }, function (dirEntry) {
3819                                expect(dirEntry).toBeDefined();
3820                                expect(dirEntry.isFile).toBe(false);
3821                                expect(dirEntry.isDirectory).toBe(true);
3822                                expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
3823                                expect(dirEntry.name).toCanonicallyMatch(dstDir);
3824                                dirEntry.getFile('asset-test.txt', {
3825                                    create : false
3826                                }, function (fileEntry) {
3827                                    expect(fileEntry).toBeDefined();
3828                                    expect(fileEntry.isFile).toBe(true);
3829                                    // cleanup
3830                                    deleteEntry(dstDir, done);
3831                                }, failed.bind(null, done, 'dirEntry.getFile - Error getting subfile'));
3832                            }, failed.bind(null, done, 'root.getDirectory - Error getting copied directory'));
3833                        }, failed.bind(null, done, 'directory.copyTo - Error copying directory'));
3834                    }, failed.bind(null, done, 'resolving src dir'));
3835                }, failed.bind(null, done, 'deleteEntry - Error removing directory : ' + dstDir));
3836            }, MEDIUM_TIMEOUT);
3837        }
3838    });
3839
3840};
3841//******************************************************************************************
3842//***************************************Manual Tests***************************************
3843//******************************************************************************************
3844
3845exports.defineManualTests = function (contentEl, createActionButton) {
3846
3847    function resolveFs(fsname) {
3848        var fsURL = "cdvfile://localhost/" + fsname + "/";
3849        logMessage("Resolving URL: " + fsURL);
3850        resolveLocalFileSystemURL(fsURL, function (entry) {
3851            logMessage("Success", 'green');
3852            logMessage(entry.toURL(), 'blue');
3853            logMessage(entry.toInternalURL(), 'blue');
3854            logMessage("Resolving URL: " + entry.toURL());
3855            resolveLocalFileSystemURL(entry.toURL(), function (entry2) {
3856                logMessage("Success", 'green');
3857                logMessage(entry2.toURL(), 'blue');
3858                logMessage(entry2.toInternalURL(), 'blue');
3859            }, logError("resolveLocalFileSystemURL"));
3860        }, logError("resolveLocalFileSystemURL"));
3861    }
3862
3863    function testPrivateURL() {
3864        requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fileSystem) {
3865            logMessage("Temporary root is at " + fileSystem.root.toNativeURL());
3866            fileSystem.root.getFile("testfile", {
3867                create : true
3868            }, function (entry) {
3869                logMessage("Temporary file is at " + entry.toNativeURL());
3870                if (entry.toNativeURL().substring(0, 12) == "file:///var/") {
3871                    logMessage("File starts with /var/, trying /private/var");
3872                    var newURL = "file://localhost/private/var/" + entry.toNativeURL().substring(12) + "?and=another_thing";
3873                    //var newURL = entry.toNativeURL();
3874                    logMessage(newURL, 'blue');
3875                    resolveLocalFileSystemURL(newURL, function (newEntry) {
3876                        logMessage("Successfully resolved.", 'green');
3877                        logMessage(newEntry.toURL(), 'blue');
3878                        logMessage(newEntry.toNativeURL(), 'blue');
3879                    }, logError("resolveLocalFileSystemURL"));
3880                }
3881            }, logError("getFile"));
3882        }, logError("requestFileSystem"));
3883    }
3884
3885    function resolveFsContactImage() {
3886        navigator.contacts.pickContact(function(contact) {
3887            var logBox = document.getElementById("logContactBox");
3888            logBox.innerHTML = "";
3889            var resolveResult = document.createElement("p");
3890            if (contact.photos) {
3891                var photoURL = contact.photos[0].value;
3892                resolveLocalFileSystemURL(photoURL, function(entry) {
3893                    var contactImage = document.createElement("img");
3894                    var contactLabelImage = document.createElement("p");                       
3895                    contactLabelImage.innerHTML = "Result contact image";                   
3896                    contactImage.setAttribute("src", entry.toURL());
3897                    resolveResult.innerHTML = "Success resolve\n" + entry.toURL();
3898                    logBox.appendChild(contactLabelImage);
3899                    logBox.appendChild(contactImage);
3900                    logBox.appendChild(resolveResult);
3901                }, 
3902                function(err) {
3903                    console.log("resolve error" + err);
3904                }); 
3905            }
3906            else {
3907                resolveResult.innerHTML = "Contact has no photos";
3908                logBox.appendChild(resolveResult);
3909            }
3910        }, 
3911        function(err) {
3912            console.log("contact pick error" + err);
3913        });
3914    }    
3915
3916    function clearLog() {
3917        var log = document.getElementById("info");
3918        log.innerHTML = "";
3919    }
3920
3921    function logMessage(message, color) {
3922        var log = document.getElementById("info");
3923        var logLine = document.createElement('div');
3924        if (color) {
3925            logLine.style.color = color;
3926        }
3927        logLine.innerHTML = message;
3928        log.appendChild(logLine);
3929    }
3930
3931    function logError(serviceName) {
3932        return function (err) {
3933            logMessage("ERROR: " + serviceName + " " + JSON.stringify(err), "red");
3934        };
3935    }
3936
3937    var fsRoots = {
3938        "ios" : "library,library-nosync,documents,documents-nosync,cache,bundle,root,private",
3939        "osx" : "library,library-nosync,documents,documents-nosync,cache,bundle,root,private",
3940        "android" : "files,files-external,documents,sdcard,cache,cache-external,assets,root",
3941        "amazon-fireos" : "files,files-external,documents,sdcard,cache,cache-external,root",
3942        "windows": "temporary,persistent"
3943    };
3944
3945    //Add title and align to content
3946    var div = document.createElement('h2');
3947    div.appendChild(document.createTextNode('File Systems'));
3948    div.setAttribute("align", "center");
3949    contentEl.appendChild(div);
3950
3951    div = document.createElement('h3');
3952    div.appendChild(document.createTextNode('Results are displayed in yellow status box below with expected results noted under that'));
3953    div.setAttribute("align", "center");
3954    contentEl.appendChild(div);
3955
3956    div = document.createElement('div');
3957    div.setAttribute("id", "button");
3958    div.setAttribute("align", "center");
3959    contentEl.appendChild(div);
3960    if (fsRoots.hasOwnProperty(cordova.platformId)) {
3961        (fsRoots[cordova.platformId].split(',')).forEach(function (fs) {
3962            if (cordova.platformId === 'ios' && fs === 'private') {
3963                createActionButton("Test private URL (iOS)", function () {
3964                    clearLog();
3965                    testPrivateURL();
3966                }, 'button');
3967            } else {
3968                createActionButton(fs, function () {
3969                    clearLog();
3970                    resolveFs(fs);
3971                }, 'button');
3972            }
3973        });
3974    }
3975
3976
3977    div = document.createElement('div');
3978    div.setAttribute("id", "info");
3979    div.setAttribute("align", "center");
3980    contentEl.appendChild(div);
3981
3982    div = document.createElement('h3');
3983    div.appendChild(document.createTextNode('For each test above, file or directory should be successfully found. ' +
3984        'Status box should say Resolving URL was Success. The first URL resolved is the internal URL. ' +
3985        'The second URL resolved is the absolute URL. Blue URLs must match.'));
3986    contentEl.appendChild(div);
3987
3988    div = document.createElement('h3');
3989    div.appendChild(document.createTextNode('For Test private URL (iOS), the private URL (first blue URL in status box) ' +
3990        'should be successfully resolved. Status box should say Successfully resolved. Both blue URLs below ' +
3991        'that should match.'));
3992    contentEl.appendChild(div);
3993
3994    div = document.createElement('h2');
3995    div.appendChild(document.createTextNode('Resolving content urls'));
3996    div.setAttribute("align", "center");
3997    contentEl.appendChild(div);
3998
3999    div = document.createElement('div');
4000    div.setAttribute("id", "contactButton");
4001    div.setAttribute("align", "center");
4002    contentEl.appendChild(div);
4003
4004    div = document.createElement('div');
4005    div.setAttribute("id", "logContactBox");
4006    div.setAttribute("align", "center");
4007    contentEl.appendChild(div);
4008
4009    createActionButton('show-contact-image', function () {
4010        resolveFsContactImage();
4011    }, 'contactButton');    
4012};