You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ja...@apache.org on 2018/09/02 02:44:41 UTC

[cordova-android] branch master updated: Unit tests for android_sdk and AndroidProject (#464)

This is an automated email from the ASF dual-hosted git repository.

janpio pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-android.git


The following commit(s) were added to refs/heads/master by this push:
     new 7ab0cf1  Unit tests for android_sdk and AndroidProject (#464)
7ab0cf1 is described below

commit 7ab0cf123d1955ed2b41c6cf9ffbde17d6effbdd
Author: GearĂ³id <Me...@users.noreply.github.com>
AuthorDate: Sun Sep 2 11:44:37 2018 +0900

    Unit tests for android_sdk and AndroidProject (#464)
    
    <!--
    Please make sure the checklist boxes are all checked before submitting the PR. The checklist
    is intended as a quick reference, for complete details please see our Contributor Guidelines:
    
    http://cordova.apache.org/contribute/contribute_guidelines.html
    
    Thanks!
    -->
    
    ### Platforms affected
    Android
    
    ### What does this PR do?
    This is the last unit test PR for today, I promise! The `AndroidProject` tests were originally in #458. This PR also contains increased test coverage for `android_sdk.js`. I have also refactored that to remove `Q`, as with the other PRs I submitted today.
    
    ### What testing has been done on this change?
    Run unit tests
    
    ### Checklist
    - [x] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database
    - [x] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected.
    - [x] Added automated test coverage as appropriate for this change.
---
 bin/templates/cordova/lib/android_sdk.js |   3 +-
 spec/unit/AndroidProject.spec.js         | 134 ++++++++++++++++++++++++
 spec/unit/android_sdk.spec.js            | 168 ++++++++++++++++++-------------
 3 files changed, 234 insertions(+), 71 deletions(-)

diff --git a/bin/templates/cordova/lib/android_sdk.js b/bin/templates/cordova/lib/android_sdk.js
index 148f9f3..1c0ab20 100755
--- a/bin/templates/cordova/lib/android_sdk.js
+++ b/bin/templates/cordova/lib/android_sdk.js
@@ -17,7 +17,6 @@
        under the License.
 */
 
-var Q = require('q');
 var superspawn = require('cordova-common').superspawn;
 
 var suffix_number_regex = /(\d+)$/;
@@ -95,7 +94,7 @@ module.exports.list_targets = function () {
         } else throw err;
     }).then(function (targets) {
         if (targets.length === 0) {
-            return Q.reject(new Error('No android targets (SDKs) installed!'));
+            return Promise.reject(new Error('No android targets (SDKs) installed!'));
         }
         return targets;
     });
diff --git a/spec/unit/AndroidProject.spec.js b/spec/unit/AndroidProject.spec.js
new file mode 100644
index 0000000..9af09fc
--- /dev/null
+++ b/spec/unit/AndroidProject.spec.js
@@ -0,0 +1,134 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+const path = require('path');
+const rewire = require('rewire');
+
+describe('AndroidProject', () => {
+    const PROJECT_DIR = 'platforms/android';
+    let AndroidProject;
+    let AndroidStudioSpy;
+
+    beforeEach(() => {
+        AndroidProject = rewire('../../bin/templates/cordova/lib/AndroidProject');
+
+        AndroidStudioSpy = jasmine.createSpyObj('AndroidStudio', ['isAndroidStudioProject']);
+        AndroidProject.__set__('AndroidStudio', AndroidStudioSpy);
+    });
+
+    describe('constructor', () => {
+        it('should set the project directory', () => {
+            const project = new AndroidProject(PROJECT_DIR);
+            expect(project.projectDir).toBe(PROJECT_DIR);
+        });
+
+        it('should set www folder correctly if not Android Studio project', () => {
+            AndroidStudioSpy.isAndroidStudioProject.and.returnValue(false);
+
+            const project = new AndroidProject(PROJECT_DIR);
+            expect(project.www).toBe(path.join(PROJECT_DIR, 'assets/www'));
+        });
+
+        it('should set www folder correctly if it is an Android Studio project', () => {
+            AndroidStudioSpy.isAndroidStudioProject.and.returnValue(true);
+
+            const project = new AndroidProject(PROJECT_DIR);
+            expect(project.www).toBe(path.join(PROJECT_DIR, 'app/src/main/assets/www'));
+        });
+    });
+
+    describe('getProjectFile', () => {
+        it('should create and return a new project if one does not exist', () => {
+            const newProject = AndroidProject.getProjectFile(PROJECT_DIR);
+
+            expect(newProject).toEqual(jasmine.any(AndroidProject));
+        });
+
+        it('should cache created projects', () => {
+            const newProject = AndroidProject.getProjectFile(PROJECT_DIR);
+            const secondProject = AndroidProject.getProjectFile(PROJECT_DIR);
+
+            expect(newProject).toEqual(jasmine.any(AndroidProject));
+            expect(secondProject).toBe(newProject);
+        });
+    });
+
+    describe('purgeCache', () => {
+        beforeEach(() => {
+            AndroidProject.__set__('projectFileCache', {
+                project1: 'test',
+                project2: 'anothertest',
+                project3: 'finaltest'
+            });
+        });
+
+        it('should only remove the specified project from the cache', () => {
+            const projectToRemove = 'project2';
+            AndroidProject.purgeCache(projectToRemove);
+
+            const cache = AndroidProject.__get__('projectFileCache');
+            expect(Object.keys(cache).length).toBe(2);
+            expect(cache[projectToRemove]).toBe(undefined);
+        });
+
+        it('should remove all projects from cache', () => {
+            AndroidProject.purgeCache();
+
+            const cache = AndroidProject.__get__('projectFileCache');
+            expect(Object.keys(cache).length).toBe(0);
+        });
+    });
+
+    describe('getPackageName', () => {
+        let AndroidManifestSpy;
+        let AndroidManifestFns;
+        let androidProject;
+
+        beforeEach(() => {
+            AndroidManifestFns = jasmine.createSpyObj('AndroidManifestFns', ['getPackageId']);
+            AndroidManifestSpy = jasmine.createSpy('AndroidManifest').and.returnValue(AndroidManifestFns);
+            AndroidProject.__set__('AndroidManifest', AndroidManifestSpy);
+
+            androidProject = new AndroidProject(PROJECT_DIR);
+        });
+
+        it('should get the package name from the project root manifest', () => {
+            AndroidStudioSpy.isAndroidStudioProject.and.returnValue(false);
+
+            androidProject.getPackageName();
+
+            expect(AndroidManifestSpy).toHaveBeenCalledWith(path.join(PROJECT_DIR, 'AndroidManifest.xml'));
+        });
+
+        it('should get the package name from the Android Studio manifest', () => {
+            AndroidStudioSpy.isAndroidStudioProject.and.returnValue(true);
+
+            androidProject.getPackageName();
+
+            expect(AndroidManifestSpy).toHaveBeenCalledWith(path.join(PROJECT_DIR, 'app/src/main/AndroidManifest.xml'));
+        });
+
+        it('should return the package name', () => {
+            const packageName = 'io.cordova.unittest';
+            AndroidManifestFns.getPackageId.and.returnValue(packageName);
+
+            expect(androidProject.getPackageName()).toBe(packageName);
+        });
+    });
+});
diff --git a/spec/unit/android_sdk.spec.js b/spec/unit/android_sdk.spec.js
index 178b7e6..6554b72 100644
--- a/spec/unit/android_sdk.spec.js
+++ b/spec/unit/android_sdk.spec.js
@@ -17,25 +17,60 @@
     under the License.
 */
 
-var android_sdk = require('../../bin/templates/cordova/lib/android_sdk');
-var superspawn = require('cordova-common').superspawn;
-var fs = require('fs');
-var path = require('path');
-var Q = require('q');
-
-describe('android_sdk', function () {
-    describe('list_targets_with_android', function () {
-        it('should invoke `android` with the `list target` command and _not_ the `list targets` command, as the plural form is not supported in some Android SDK Tools versions', function () {
-            var deferred = Q.defer();
-            spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
+const superspawn = require('cordova-common').superspawn;
+const fs = require('fs');
+const path = require('path');
+const rewire = require('rewire');
+
+describe('android_sdk', () => {
+    let android_sdk;
+
+    beforeEach(() => {
+        android_sdk = rewire('../../bin/templates/cordova/lib/android_sdk');
+    });
+
+    describe('sort_by_largest_numerical_suffix', () => {
+        it('should return the newest version first', () => {
+            const ids = ['android-24', 'android-19', 'android-27', 'android-23'];
+            const sortedIds = ['android-27', 'android-24', 'android-23', 'android-19'];
+            expect(ids.sort(android_sdk.__get__('sort_by_largest_numerical_suffix'))).toEqual(sortedIds);
+        });
+
+        it('should return 0 (no sort) if one of the versions has no number', () => {
+            const ids = ['android-27', 'android-P'];
+            expect(android_sdk.__get__('sort_by_largest_numerical_suffix')(ids[0], ids[1])).toBe(0);
+        });
+    });
+
+    describe('print_newest_available_sdk_target', () => {
+        it('should log the newest version', () => {
+            const sortedIds = ['android-27', 'android-24', 'android-23', 'android-19'];
+            const logSpy = jasmine.createSpy('log');
+
+            spyOn(android_sdk, 'list_targets').and.returnValue(Promise.resolve(sortedIds));
+            spyOn(sortedIds, 'sort');
+
+            android_sdk.__set__({ console: { log: logSpy } });
+
+            return android_sdk.print_newest_available_sdk_target().then(() => {
+                expect(sortedIds.sort).toHaveBeenCalledWith(android_sdk.__get__('sort_by_largest_numerical_suffix'));
+                expect(logSpy).toHaveBeenCalledWith(sortedIds[0]);
+            });
+        });
+    });
+
+    describe('list_targets_with_android', () => {
+        it('should invoke `android` with the `list target` command and _not_ the `list targets` command, as the plural form is not supported in some Android SDK Tools versions', () => {
+            spyOn(superspawn, 'spawn').and.returnValue(new Promise(() => {}, () => {}));
             android_sdk.list_targets_with_android();
             expect(superspawn.spawn).toHaveBeenCalledWith('android', ['list', 'target']);
         });
-        it('should parse and return results from `android list targets` command', function (done) {
-            var deferred = Q.defer();
-            spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
-            deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_targets.txt'), 'utf-8'));
-            return android_sdk.list_targets_with_android().then(function (list) {
+
+        it('should parse and return results from `android list targets` command', () => {
+            const testTargets = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.2-android_list_targets.txt'), 'utf-8');
+            spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(testTargets));
+
+            return android_sdk.list_targets_with_android().then(list => {
                 [ 'Google Inc.:Google APIs:23',
                     'Google Inc.:Google APIs:22',
                     'Google Inc.:Google APIs:21',
@@ -46,79 +81,74 @@ describe('android_sdk', function () {
                     'android-MNC',
                     'android-22',
                     'android-21',
-                    'android-20' ].forEach(function (target) { expect(list).toContain(target); });
-            }).fail(function (err) {
-                console.log(err);
-                expect(err).toBeUndefined();
-            }).fin(function () {
-                done();
+                    'android-20' ].forEach((target) => expect(list).toContain(target));
             });
         });
     });
-    describe('list_targets_with_avdmanager', function () {
-        it('should parse and return results from `avdmanager list target` command', function (done) {
-            var deferred = Q.defer();
-            spyOn(superspawn, 'spawn').and.returnValue(deferred.promise);
-            deferred.resolve(fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_target.txt'), 'utf-8'));
-            return android_sdk.list_targets_with_avdmanager().then(function (list) {
+
+    describe('list_targets_with_avdmanager', () => {
+        it('should parse and return results from `avdmanager list target` command', () => {
+            const testTargets = fs.readFileSync(path.join('spec', 'fixtures', 'sdk25.3-avdmanager_list_target.txt'), 'utf-8');
+            spyOn(superspawn, 'spawn').and.returnValue(Promise.resolve(testTargets));
+
+            return android_sdk.list_targets_with_avdmanager().then(list => {
                 expect(list).toContain('android-25');
-            }).fail(function (err) {
-                console.log(err);
-                expect(err).toBeUndefined();
-            }).fin(function () {
-                done();
             });
         });
     });
-    describe('list_targets', function () {
-        it('should parse Android SDK installed target information with `avdmanager` command first', function () {
-            var deferred = Q.defer();
-            var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
+
+    describe('list_targets', () => {
+        it('should parse Android SDK installed target information with `avdmanager` command first', () => {
+            const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(new Promise(() => {}, () => {}));
             android_sdk.list_targets();
             expect(avdmanager_spy).toHaveBeenCalled();
         });
-        it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with ENOENT', function (done) {
-            var deferred = Q.defer();
-            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
-            deferred.reject({
-                code: 'ENOENT'
-            });
-            var twoferred = Q.defer();
-            twoferred.resolve(['target1']);
-            var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(twoferred.promise);
-            return android_sdk.list_targets().then(function (targets) {
+
+        it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with ENOENT', () => {
+            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject({ code: 'ENOENT' }));
+            const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(Promise.resolve(['target1']));
+
+            return android_sdk.list_targets().then(targets => {
                 expect(avdmanager_spy).toHaveBeenCalled();
                 expect(targets[0]).toEqual('target1');
-                done();
             });
         });
-        it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with not-recognized error (Windows)', function (done) {
-            var deferred = Q.defer();
-            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
-            deferred.reject({
+
+        it('should parse Android SDK installed target information with `android` command if list_targets_with_avdmanager fails with not-recognized error (Windows)', () => {
+            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject({
                 code: 1,
                 stderr: "'avdmanager' is not recognized as an internal or external commmand,\r\noperable program or batch file.\r\n"
-            });
-            var twoferred = Q.defer();
-            twoferred.resolve(['target1']);
-            var avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(twoferred.promise);
-            return android_sdk.list_targets().then(function (targets) {
+            }));
+
+            const avdmanager_spy = spyOn(android_sdk, 'list_targets_with_android').and.returnValue(Promise.resolve(['target1']));
+            return android_sdk.list_targets().then(targets => {
                 expect(avdmanager_spy).toHaveBeenCalled();
                 expect(targets[0]).toEqual('target1');
-                done();
             });
         });
-        it('should throw an error if no Android targets were found.', function (done) {
-            var deferred = Q.defer();
-            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(deferred.promise);
-            deferred.resolve([]);
-            return android_sdk.list_targets().then(function (targets) {
-                done.fail();
-            }).catch(function (err) {
-                expect(err).toBeDefined();
-                expect(err.message).toContain('No android targets (SDKs) installed!');
-                done();
-            });
+
+        it('should throw an error if `avdmanager` command fails with an unknown error', () => {
+            const errorMsg = 'Some random error';
+            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.reject(errorMsg));
+
+            return android_sdk.list_targets().then(
+                () => fail('Unexpectedly resolved'),
+                err => {
+                    expect(err).toBe(errorMsg);
+                }
+            );
+        });
+
+        it('should throw an error if no Android targets were found.', () => {
+            spyOn(android_sdk, 'list_targets_with_avdmanager').and.returnValue(Promise.resolve([]));
+
+            return android_sdk.list_targets().then(
+                () => fail('Unexpectedly resolved'),
+                err => {
+                    expect(err).toBeDefined();
+                    expect(err.message).toContain('No android targets (SDKs) installed!');
+                }
+            );
         });
     });
 });


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org