"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var yok_1 = require("../../../yok");
var chai_1 = require("chai");
var stubs_1 = require("../stubs");
var application_manager_base_1 = require("../../../mobile/application-manager-base");
var Future = require("fibers/future");
var currentlyAvailableAppsForDebugging, currentlyInstalledApps, currentlyAvailableAppWebViewsForDebugging;
var ApplicationManager = (function (_super) {
    __extends(ApplicationManager, _super);
    function ApplicationManager($logger) {
        _super.call(this, $logger);
    }
    ApplicationManager.prototype.isLiveSyncSupported = function (appIdentifier) {
        return Future.fromResult(true);
    };
    ApplicationManager.prototype.installApplication = function (packageFilePath) {
        return Future.fromResult();
    };
    ApplicationManager.prototype.uninstallApplication = function (appIdentifier) {
        return Future.fromResult();
    };
    ApplicationManager.prototype.startApplication = function (appIdentifier, framework) {
        return Future.fromResult();
    };
    ApplicationManager.prototype.stopApplication = function (appIdentifier) {
        return Future.fromResult();
    };
    ApplicationManager.prototype.getInstalledApplications = function () {
        return Future.fromResult(_.cloneDeep(currentlyInstalledApps));
    };
    ApplicationManager.prototype.getApplicationInfo = function (applicationIdentifier) {
        return Future.fromResult(null);
    };
    ApplicationManager.prototype.canStartApplication = function () {
        return true;
    };
    ApplicationManager.prototype.getDebuggableApps = function () {
        return Future.fromResult(currentlyAvailableAppsForDebugging);
    };
    ApplicationManager.prototype.getDebuggableAppViews = function (appIdentifiers) {
        return Future.fromResult(_.cloneDeep(currentlyAvailableAppWebViewsForDebugging));
    };
    return ApplicationManager;
}(application_manager_base_1.ApplicationManagerBase));
function createTestInjector() {
    var testInjector = new yok_1.Yok();
    testInjector.register("logger", stubs_1.CommonLoggerStub);
    testInjector.register("applicationManager", ApplicationManager);
    return testInjector;
}
function createAppsAvailableForDebugging(count) {
    return _.times(count, function (index) { return ({
        deviceIdentifier: "deviceId",
        appIdentifier: "appId_" + index,
        framework: "framework"
    }); });
}
function createDebuggableWebView(uniqueId) {
    return {
        description: "description_" + uniqueId,
        devtoolsFrontendUrl: "devtoolsFrontendUrl_" + uniqueId,
        id: "" + uniqueId,
        title: "title_" + uniqueId,
        type: "type_" + uniqueId,
        url: "url_" + uniqueId,
        webSocketDebuggerUrl: "webSocketDebuggerUrl_" + uniqueId,
    };
}
function createDebuggableWebViews(appInfos, numberOfViews) {
    var result = {};
    _.each(appInfos, function (appInfo, index) {
        result[appInfo.appIdentifier] = _.times(numberOfViews, function (currentViewIndex) { return createDebuggableWebView(index + "_" + currentViewIndex); });
    });
    return result;
}
describe("ApplicationManagerBase", function () {
    var applicationManager, testInjector;
    beforeEach(function () {
        testInjector = createTestInjector();
        currentlyAvailableAppsForDebugging = null;
        currentlyAvailableAppWebViewsForDebugging = null;
        applicationManager = testInjector.resolve("applicationManager");
    });
    describe("checkForApplicationUpdates", function () {
        describe("debuggableApps", function () {
            it("emits debuggableAppFound when new application is available for debugging", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var foundAppsForDebug = [];
                applicationManager.on("debuggableAppFound", function (d) {
                    foundAppsForDebug.push(d);
                    if (foundAppsForDebug.length === currentlyAvailableAppsForDebugging.length) {
                        _.each(foundAppsForDebug, function (f, index) {
                            chai_1.assert.deepEqual(f, currentlyAvailableAppsForDebugging[index]);
                        });
                        done();
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableAppFound when new application is available for debugging (several calls)", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(1);
                var foundAppsForDebug = [], isFinalCheck = false;
                applicationManager.on("debuggableAppFound", function (d) {
                    foundAppsForDebug.push(d);
                    if (foundAppsForDebug.length === currentlyAvailableAppsForDebugging.length) {
                        _.each(foundAppsForDebug, function (f, index) {
                            chai_1.assert.deepEqual(f, currentlyAvailableAppsForDebugging[index]);
                        });
                        if (isFinalCheck) {
                            done();
                        }
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                applicationManager.checkForApplicationUpdates().wait();
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(4);
                isFinalCheck = true;
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableAppLost when application cannot be debugged anymore", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var expectedAppsToBeLost = currentlyAvailableAppsForDebugging, lostAppsForDebug = [];
                applicationManager.on("debuggableAppLost", function (d) {
                    lostAppsForDebug.push(d);
                    if (lostAppsForDebug.length === expectedAppsToBeLost.length) {
                        _.each(lostAppsForDebug, function (f, index) {
                            chai_1.assert.deepEqual(f, expectedAppsToBeLost[index]);
                        });
                        done();
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                currentlyAvailableAppsForDebugging = [];
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableAppLost when application cannot be debugged anymore (several calls)", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(4);
                var lostAppsForDebug = [], isFinalCheck = false, initialAppsAvailableForDebug = currentlyAvailableAppsForDebugging;
                applicationManager.on("debuggableAppLost", function (d) {
                    lostAppsForDebug.push(d);
                    _.each(lostAppsForDebug, function (f, index) {
                        chai_1.assert.deepEqual(f, _.find(initialAppsAvailableForDebug, function (t) { return t.appIdentifier === f.appIdentifier; }));
                    });
                    if (lostAppsForDebug.length === initialAppsAvailableForDebug.length && isFinalCheck) {
                        done();
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                applicationManager.checkForApplicationUpdates().wait();
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(0);
                isFinalCheck = true;
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableAppFound and debuggableAppLost when applications are changed", function () {
                var allAppsForDebug = createAppsAvailableForDebugging(4);
                currentlyAvailableAppsForDebugging = _.take(allAppsForDebug, 2);
                var remainingAppsForDebugging = _.difference(allAppsForDebug, currentlyAvailableAppsForDebugging);
                var foundAppsForDebug = [], futures = [];
                applicationManager.checkForApplicationUpdates().wait();
                var foundAppsFuture = new Future();
                futures.push(foundAppsFuture);
                applicationManager.on("debuggableAppFound", function (d) {
                    foundAppsForDebug.push(d);
                    if (foundAppsForDebug.length === remainingAppsForDebugging.length) {
                        _.each(foundAppsForDebug, function (f, index) {
                            chai_1.assert.deepEqual(f, remainingAppsForDebugging[index]);
                        });
                        foundAppsFuture.return();
                    }
                });
                var lostAppsFuture = new Future();
                futures.push(lostAppsFuture);
                applicationManager.on("debuggableAppLost", function (d) {
                    chai_1.assert.deepEqual(d, allAppsForDebug[0], "Debuggable app lost does not match.");
                    lostAppsFuture.return();
                });
                currentlyAvailableAppsForDebugging = _.drop(allAppsForDebug, 1);
                applicationManager.checkForApplicationUpdates().wait();
                Future.wait(futures);
            });
            it("emits debuggableViewFound when new views are available for debug", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var numberOfViewsPerApp = 2;
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, numberOfViewsPerApp);
                var currentDebuggableViews = {};
                applicationManager.on("debuggableViewFound", function (appIdentifier, d) {
                    currentDebuggableViews[appIdentifier] = currentDebuggableViews[appIdentifier] || [];
                    currentDebuggableViews[appIdentifier].push(d);
                    var numberOfFoundViewsPerApp = _.uniq(_.values(currentDebuggableViews).map(function (arr) { return arr.length; }));
                    if (_.keys(currentDebuggableViews).length === currentlyAvailableAppsForDebugging.length
                        && numberOfFoundViewsPerApp.length === 1
                        && numberOfFoundViewsPerApp[0] === numberOfViewsPerApp) {
                        _.each(currentDebuggableViews, function (webViews, appId) {
                            _.each(webViews, function (webView) {
                                var expectedWebView = _.find(currentlyAvailableAppWebViewsForDebugging[appId], function (c) { return c.id === webView.id; });
                                chai_1.assert.isTrue(_.isEqual(webView, expectedWebView));
                            });
                        });
                        setTimeout(done, 0);
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableViewLost when views for debug are removed", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var numberOfViewsPerApp = 2;
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, numberOfViewsPerApp);
                var expectedResults = _.cloneDeep(currentlyAvailableAppWebViewsForDebugging);
                var currentDebuggableViews = {};
                applicationManager.checkForApplicationUpdates().wait();
                applicationManager.on("debuggableViewLost", function (appIdentifier, d) {
                    currentDebuggableViews[appIdentifier] = currentDebuggableViews[appIdentifier] || [];
                    currentDebuggableViews[appIdentifier].push(d);
                    var numberOfFoundViewsPerApp = _.uniq(_.values(currentDebuggableViews).map(function (arr) { return arr.length; }));
                    if (_.keys(currentDebuggableViews).length === currentlyAvailableAppsForDebugging.length
                        && numberOfFoundViewsPerApp.length === 1
                        && numberOfFoundViewsPerApp[0] === numberOfViewsPerApp) {
                        _.each(currentDebuggableViews, function (webViews, appId) {
                            _.each(webViews, function (webView) {
                                var expectedWebView = _.find(expectedResults[appId], function (c) { return c.id === webView.id; });
                                chai_1.assert.isTrue(_.isEqual(webView, expectedWebView));
                            });
                        });
                        setTimeout(done, 0);
                    }
                });
                currentlyAvailableAppWebViewsForDebugging = _.mapValues(currentlyAvailableAppWebViewsForDebugging, function (a) { return []; });
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableViewFound when new views are available for debug", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var numberOfViewsPerApp = 2;
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, numberOfViewsPerApp);
                applicationManager.checkForApplicationUpdates().wait();
                var expectedViewToBeFound = createDebuggableWebView("uniqueId"), expectedAppIdentifier = currentlyAvailableAppsForDebugging[0].appIdentifier, isLastCheck = false;
                applicationManager.on("debuggableViewFound", function (appIdentifier, d) {
                    chai_1.assert.deepEqual(appIdentifier, expectedAppIdentifier);
                    chai_1.assert.isTrue(_.isEqual(d, expectedViewToBeFound));
                    if (isLastCheck) {
                        setTimeout(done, 0);
                    }
                });
                currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].push(_.cloneDeep(expectedViewToBeFound));
                applicationManager.checkForApplicationUpdates().wait();
                expectedViewToBeFound = createDebuggableWebView("uniqueId1");
                currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].push(_.cloneDeep(expectedViewToBeFound));
                applicationManager.checkForApplicationUpdates().wait();
                expectedViewToBeFound = createDebuggableWebView("uniqueId2");
                expectedAppIdentifier = currentlyAvailableAppsForDebugging[1].appIdentifier;
                isLastCheck = true;
                currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].push(_.cloneDeep(expectedViewToBeFound));
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableViewLost when views for debug are not available anymore", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(2);
                var numberOfViewsPerApp = 2;
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, numberOfViewsPerApp);
                applicationManager.checkForApplicationUpdates().wait();
                var expectedAppIdentifier = currentlyAvailableAppsForDebugging[0].appIdentifier, expectedViewToBeLost = currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].splice(0, 1)[0], isLastCheck = false;
                applicationManager.on("debuggableViewLost", function (appIdentifier, d) {
                    chai_1.assert.deepEqual(appIdentifier, expectedAppIdentifier);
                    chai_1.assert.isTrue(_.isEqual(d, expectedViewToBeLost));
                    if (isLastCheck) {
                        setTimeout(done, 0);
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                expectedViewToBeLost = currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].splice(0, 1)[0];
                applicationManager.checkForApplicationUpdates().wait();
                expectedAppIdentifier = currentlyAvailableAppsForDebugging[1].appIdentifier;
                expectedViewToBeLost = currentlyAvailableAppWebViewsForDebugging[expectedAppIdentifier].splice(0, 1)[0];
                isLastCheck = true;
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("emits debuggableViewChanged when view's property is modified (each one except id)", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(1);
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, 2);
                var viewToChange = currentlyAvailableAppWebViewsForDebugging[currentlyAvailableAppsForDebugging[0].appIdentifier][0];
                var expectedView = _.cloneDeep(viewToChange);
                expectedView.title = "new title";
                applicationManager.on("debuggableViewChanged", function (appIdentifier, d) {
                    chai_1.assert.isTrue(_.isEqual(d, expectedView));
                    setTimeout(done, 0);
                });
                applicationManager.checkForApplicationUpdates().wait();
                viewToChange.title = "new title";
                applicationManager.checkForApplicationUpdates().wait();
            });
            it("does not emit debuggableViewChanged when id is modified", function (done) {
                currentlyAvailableAppsForDebugging = createAppsAvailableForDebugging(1);
                currentlyAvailableAppWebViewsForDebugging = createDebuggableWebViews(currentlyAvailableAppsForDebugging, 2);
                var viewToChange = currentlyAvailableAppWebViewsForDebugging[currentlyAvailableAppsForDebugging[0].appIdentifier][0];
                var expectedView = _.cloneDeep(viewToChange);
                applicationManager.checkForApplicationUpdates().wait();
                applicationManager.on("debuggableViewChanged", function (appIdentifier, d) {
                    setTimeout(function () { return done(new Error("When id is changed, debuggableViewChanged must not be emitted.")); }, 0);
                });
                applicationManager.on("debuggableViewLost", function (appIdentifier, d) {
                    chai_1.assert.isTrue(_.isEqual(d, expectedView));
                });
                applicationManager.on("debuggableViewFound", function (appIdentifier, d) {
                    expectedView.id = "new id";
                    chai_1.assert.isTrue(_.isEqual(d, expectedView));
                    setTimeout(done, 0);
                });
                viewToChange.id = "new id";
                applicationManager.checkForApplicationUpdates().wait();
            });
        });
        describe("installed and uninstalled apps", function () {
            it("reports installed applications when initially there are apps", function () {
                currentlyInstalledApps = ["app1", "app2", "app3"];
                var reportedInstalledApps = [], future = new Future();
                applicationManager.on("applicationInstalled", function (app) {
                    reportedInstalledApps.push(app);
                    if (reportedInstalledApps.length === currentlyInstalledApps.length) {
                        future.return();
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                future.wait();
                _.each(currentlyInstalledApps, function (c, index) {
                    chai_1.assert.deepEqual(c, reportedInstalledApps[index]);
                });
                chai_1.assert.deepEqual(reportedInstalledApps.length, currentlyInstalledApps.length);
            });
            it("reports installed applications when apps are changed between executions", function () {
                currentlyInstalledApps = ["app1", "app2", "app3"];
                var reportedInstalledApps = [], future;
                applicationManager.on("applicationInstalled", function (app) {
                    reportedInstalledApps.push(app);
                    if (reportedInstalledApps.length === currentlyInstalledApps.length) {
                        future.return();
                    }
                });
                var testInstalledAppsResults = function () {
                    future = new Future();
                    applicationManager.checkForApplicationUpdates().wait();
                    future.wait();
                    _.each(currentlyInstalledApps, function (c, index) {
                        chai_1.assert.deepEqual(c, reportedInstalledApps[index]);
                    });
                    chai_1.assert.deepEqual(reportedInstalledApps.length, currentlyInstalledApps.length);
                };
                testInstalledAppsResults();
                currentlyInstalledApps.push("app4", "app5");
                testInstalledAppsResults();
                currentlyInstalledApps.push("app6", "app7");
                testInstalledAppsResults();
            });
            it("reports uninstalled applications when initially there are apps and all are uninstalled", function () {
                currentlyInstalledApps = ["app1", "app2", "app3"];
                var reportedUninstalledApps = [], initiallyInstalledApps = _.cloneDeep(currentlyInstalledApps), future = new Future();
                applicationManager.checkForApplicationUpdates().wait();
                currentlyInstalledApps = [];
                applicationManager.on("applicationUninstalled", function (app) {
                    reportedUninstalledApps.push(app);
                    if (reportedUninstalledApps.length === initiallyInstalledApps.length) {
                        future.return();
                    }
                });
                applicationManager.checkForApplicationUpdates().wait();
                future.wait();
                _.each(initiallyInstalledApps, function (c, index) {
                    chai_1.assert.deepEqual(c, reportedUninstalledApps[index]);
                });
                chai_1.assert.deepEqual(reportedUninstalledApps.length, initiallyInstalledApps.length);
            });
            it("reports uninstalled applications when apps are changed between executions", function () {
                currentlyInstalledApps = ["app1", "app2", "app3", "app4", "app5", "app6"];
                var reportedUninstalledApps = [], removedApps = [], future;
                applicationManager.checkForApplicationUpdates().wait();
                applicationManager.on("applicationUninstalled", function (app) {
                    reportedUninstalledApps.push(app);
                    if (reportedUninstalledApps.length === removedApps.length) {
                        future.return();
                    }
                });
                var testInstalledAppsResults = function () {
                    future = new Future();
                    applicationManager.checkForApplicationUpdates().wait();
                    future.wait();
                    _.each(removedApps, function (c, index) {
                        chai_1.assert.deepEqual(c, reportedUninstalledApps[index]);
                    });
                    chai_1.assert.deepEqual(reportedUninstalledApps.length, removedApps.length);
                };
                while (currentlyInstalledApps.length) {
                    var currentlyRemovedApps = currentlyInstalledApps.splice(0, 2);
                    removedApps.push.apply(removedApps, currentlyRemovedApps);
                    testInstalledAppsResults();
                }
            });
            it("reports installed and uninstalled apps when apps are changed between executions", function () {
                currentlyInstalledApps = ["app1", "app2", "app3", "app4", "app5", "app6"];
                var reportedUninstalledApps = [], reportedInstalledApps = [], installedApps = [], removedApps = [], appUninstalledFuture, appInstalledFuture, waitForAppInstalledFuture = true;
                applicationManager.checkForApplicationUpdates().wait();
                applicationManager.on("applicationUninstalled", function (app) {
                    reportedUninstalledApps.push(app);
                    if (reportedUninstalledApps.length === removedApps.length) {
                        appUninstalledFuture.return();
                    }
                });
                applicationManager.on("applicationInstalled", function (app) {
                    reportedInstalledApps.push(app);
                    if (reportedInstalledApps.length === installedApps.length) {
                        appInstalledFuture.return();
                    }
                });
                var testInstalledAppsResults = function () {
                    appInstalledFuture = new Future();
                    appUninstalledFuture = new Future();
                    applicationManager.checkForApplicationUpdates().wait();
                    if (!waitForAppInstalledFuture) {
                        appInstalledFuture.return();
                    }
                    Future.wait([appInstalledFuture, appUninstalledFuture]);
                    _.each(removedApps, function (c, index) {
                        chai_1.assert.deepEqual(c, reportedUninstalledApps[index]);
                    });
                    chai_1.assert.deepEqual(reportedUninstalledApps.length, removedApps.length);
                    _.each(installedApps, function (c, index) {
                        chai_1.assert.deepEqual(c, reportedInstalledApps[index]);
                    });
                    chai_1.assert.deepEqual(reportedInstalledApps.length, installedApps.length);
                };
                for (var index = 10; index < 13; index++) {
                    var currentlyRemovedApps = currentlyInstalledApps.splice(0, 2);
                    removedApps.push.apply(removedApps, currentlyRemovedApps);
                    var currentlyAddedApps = [("app" + index)];
                    currentlyInstalledApps.push.apply(currentlyInstalledApps, currentlyAddedApps);
                    installedApps.push.apply(installedApps, currentlyAddedApps);
                    testInstalledAppsResults();
                }
            });
        });
    });
    describe("isApplicationInstalled", function () {
        it("returns true when app is installed", function () {
            currentlyInstalledApps = ["app1", "app2"];
            chai_1.assert.isTrue(applicationManager.isApplicationInstalled("app1").wait(), "app1 is installed, so result of isAppInstalled must be true.");
            chai_1.assert.isTrue(applicationManager.isApplicationInstalled("app2").wait(), "app2 is installed, so result of isAppInstalled must be true.");
        });
        it("returns false when app is NOT installed", function () {
            currentlyInstalledApps = ["app1", "app2"];
            chai_1.assert.isFalse(applicationManager.isApplicationInstalled("app3").wait(), "app3 is NOT installed, so result of isAppInstalled must be false.");
            chai_1.assert.isFalse(applicationManager.isApplicationInstalled("app4").wait(), "app4 is NOT installed, so result of isAppInstalled must be false.");
        });
    });
    describe("restartApplication", function () {
        it("calls stopApplication with correct arguments", function () {
            var stopApplicationParam;
            applicationManager.stopApplication = function (appId) {
                stopApplicationParam = appId;
                return Future.fromResult();
            };
            applicationManager.restartApplication("appId").wait();
            chai_1.assert.deepEqual(stopApplicationParam, "appId", "When bundleIdentifier is not passed to restartApplication, stopApplication must be called with application identifier.");
            applicationManager.restartApplication("appId", "bundleIdentifier").wait();
            chai_1.assert.deepEqual(stopApplicationParam, "bundleIdentifier", "When bundleIdentifier is passed to restartApplication, stopApplication must be called with bundleIdentifier.");
        });
        it("calls startApplication with correct arguments", function () {
            var startApplicationAppIdParam, startApplicationFrameworkParam;
            applicationManager.startApplication = function (appId, framework) {
                startApplicationAppIdParam = appId;
                startApplicationFrameworkParam = framework;
                return Future.fromResult();
            };
            applicationManager.restartApplication("appId").wait();
            chai_1.assert.deepEqual(startApplicationAppIdParam, "appId", "startApplication must be called with application identifier.");
            chai_1.assert.deepEqual(startApplicationFrameworkParam, undefined, "When framework is not passed to restartApplication, startApplication must be called with undefined framework.");
            applicationManager.restartApplication("appId", null, "cordova").wait();
            chai_1.assert.deepEqual(startApplicationAppIdParam, "appId", "startApplication must be called with application identifier.");
            chai_1.assert.deepEqual(startApplicationFrameworkParam, "cordova", "When framework is passed to restartApplication, startApplication must be called with this framework.");
        });
        it("calls stopApplication and startApplication in correct order", function () {
            var isStartApplicationCalled = false, isStopApplicationCalled = false;
            applicationManager.stopApplication = function (appId) {
                isStopApplicationCalled = true;
                return Future.fromResult();
            };
            applicationManager.startApplication = function (appId, framework) {
                chai_1.assert.isTrue(isStopApplicationCalled, "When startApplication is called, stopApplication must have been resolved.");
                isStartApplicationCalled = true;
                return Future.fromResult();
            };
            applicationManager.restartApplication("appId").wait();
            chai_1.assert.isTrue(isStopApplicationCalled, "stopApplication must be called.");
            chai_1.assert.isTrue(isStartApplicationCalled, "startApplication must be called.");
        });
    });
    describe("tryStartApplication", function () {
        it("calls startApplication, when canStartApplication returns true", function () {
            var startApplicationAppIdParam, startApplicationFrameworkParam;
            applicationManager.canStartApplication = function () { return true; };
            applicationManager.startApplication = function (appId, framework) {
                startApplicationAppIdParam = appId;
                startApplicationFrameworkParam = framework;
                return Future.fromResult();
            };
            applicationManager.tryStartApplication("appId").wait();
            chai_1.assert.deepEqual(startApplicationAppIdParam, "appId");
            chai_1.assert.deepEqual(startApplicationFrameworkParam, undefined);
            applicationManager.tryStartApplication("appId2", "framework").wait();
            chai_1.assert.deepEqual(startApplicationAppIdParam, "appId2");
            chai_1.assert.deepEqual(startApplicationFrameworkParam, "framework");
        });
        it("does not call startApplication, when canStartApplication returns false", function () {
            var isStartApplicationCalled = false;
            applicationManager.canStartApplication = function () { return false; };
            applicationManager.startApplication = function (appId, framework) {
                isStartApplicationCalled = true;
                return Future.fromResult();
            };
            applicationManager.tryStartApplication("appId").wait();
            chai_1.assert.isFalse(isStartApplicationCalled, "startApplication must not be called when canStartApplication returns false.");
        });
        describe("does not throw Error", function () {
            var error = new Error("Throw!");
            var isStartApplicationCalled = false;
            var logger;
            beforeEach(function () {
                isStartApplicationCalled = false;
                logger = testInjector.resolve("logger");
            });
            var assertDoesNotThrow = function (opts) {
                chai_1.assert.deepEqual(logger.traceOutput, "");
                applicationManager.startApplication = function (appId, framework) {
                    return (function () {
                        if (opts && opts.shouldStartApplicatinThrow) {
                            throw error;
                        }
                        isStartApplicationCalled = true;
                    }).future()();
                };
                applicationManager.tryStartApplication("appId").wait();
                chai_1.assert.isFalse(isStartApplicationCalled, "startApplication must not be called when there's an error.");
                chai_1.assert.isTrue(logger.traceOutput.indexOf("Throw!") !== -1, "Error message must be shown in trace output.");
                chai_1.assert.isTrue(logger.traceOutput.indexOf("Unable to start application") !== -1, "'Unable to start application' must be shown in trace output.");
            };
            it("when canStartApplication throws error", function () {
                applicationManager.canStartApplication = function () {
                    throw error;
                };
                applicationManager.isApplicationInstalled = function (appId) { return Future.fromResult(true); };
                assertDoesNotThrow();
            });
            it("when startApplications throws", function () {
                applicationManager.canStartApplication = function () { return true; };
                applicationManager.isApplicationInstalled = function (appId) { return Future.fromResult(true); };
                assertDoesNotThrow({ shouldStartApplicatinThrow: true });
            });
        });
    });
    describe("reinstallApplication", function () {
        it("calls uninstallApplication with correct arguments", function () {
            var uninstallApplicationAppIdParam;
            applicationManager.uninstallApplication = function (appId) {
                uninstallApplicationAppIdParam = appId;
                return Future.fromResult();
            };
            applicationManager.reinstallApplication("appId", "packageFilePath").wait();
            chai_1.assert.deepEqual(uninstallApplicationAppIdParam, "appId");
        });
        it("calls installApplication with correct arguments", function () {
            var installApplicationPackageFilePathParam;
            applicationManager.installApplication = function (packageFilePath) {
                installApplicationPackageFilePathParam = packageFilePath;
                return Future.fromResult();
            };
            applicationManager.reinstallApplication("appId", "packageFilePath").wait();
            chai_1.assert.deepEqual(installApplicationPackageFilePathParam, "packageFilePath");
        });
        it("calls uninstallApplication and installApplication in correct order", function () {
            var isInstallApplicationCalled = false, isUninstallApplicationCalled = false;
            applicationManager.uninstallApplication = function (appId) {
                chai_1.assert.isFalse(isInstallApplicationCalled, "When uninstallApplication is called, installApplication should not have been called.");
                isUninstallApplicationCalled = true;
                return Future.fromResult();
            };
            applicationManager.installApplication = function (packageFilePath) {
                chai_1.assert.isTrue(isUninstallApplicationCalled, "When installApplication is called, uninstallApplication should have been called.");
                isInstallApplicationCalled = true;
                return Future.fromResult();
            };
            applicationManager.reinstallApplication("appId", "packageFilePath").wait();
            chai_1.assert.isTrue(isUninstallApplicationCalled, "uninstallApplication should have been called.");
            chai_1.assert.isTrue(isInstallApplicationCalled, "installApplication should have been called.");
        });
    });
});
