mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-22 00:32:55 +08:00
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.
This commit is contained in:
parent
8f2a4c7231
commit
7ab0cf123d
3
bin/templates/cordova/lib/android_sdk.js
vendored
3
bin/templates/cordova/lib/android_sdk.js
vendored
@ -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;
|
||||
});
|
||||
|
134
spec/unit/AndroidProject.spec.js
Normal file
134
spec/unit/AndroidProject.spec.js
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
@ -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');
|
||||
const superspawn = require('cordova-common').superspawn;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const rewire = require('rewire');
|
||||
|
||||
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);
|
||||
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) {
|
||||
|
||||
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!');
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user