blob: 8489f05eacda4c481e879fe0b151f43631d118c9 [file] [log] [blame]
/**
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 { events } = require('cordova-common');
const cordovaUtil = require('../../../src/cordova/util');
const pluginUtil = require('../../../src/cordova/plugin/util');
const pluginAdd = require('../../../src/cordova/plugin/add');
const cordovaVersion = '3.4.2';
// Used to extract the constraint, the installed version, and the required
// semver range from a warning message
const UNMET_REQ_REGEX = /\s+([^\s]+)[^\d]+(\d+\.\d+\.\d+) in project, (.+) required\)/;
function unmetRequirementsCollector (warning) {
const match = UNMET_REQ_REGEX.exec(warning);
if (!match) return;
unmetRequirementsCollector.store.push({
dependency: match[1],
installed: match[2],
required: match[3]
});
}
// Checks the warnings that were printed by the CLI to ensure that the code is
// listing the correct reasons for failure. Checks against the global warnings
// object which is reset before each test
function expectUnmetRequirements (expected) {
const actual = unmetRequirementsCollector.store;
expect(actual).toEqual(jasmine.arrayWithExactContents(expected));
}
// Helper functions for creating the requirements objects taken by
// expectUnmetRequirements()
function getPlatformRequirement (requirement) {
return {
dependency: 'cordova-android',
installed: '3.1.0',
required: requirement
};
}
function getCordovaRequirement (requirement) {
return {
dependency: 'cordova',
installed: cordovaVersion,
required: requirement
};
}
function getPluginRequirement (requirement) {
return {
dependency: 'ca.filmaj.AndroidPlugin',
installed: '4.2.0',
required: requirement
};
}
describe('plugin fetching version selection', () => {
let project, testPlugin;
beforeEach(() => {
unmetRequirementsCollector.store = [];
// We generate warnings when we don't fetch latest. Collect them to make sure we
// are making the correct warnings
events.on('warn', unmetRequirementsCollector);
testPlugin = {
version: '2.3.0',
name: 'test-plugin',
engines: { cordovaDependencies: {} },
versions: [
'0.0.2',
'0.7.0',
'1.0.0',
'1.1.0',
'1.1.3',
'1.3.0',
'1.7.0',
'1.7.1',
'2.0.0-rc.1',
'2.0.0-rc.2',
'2.0.0',
'2.3.0'
]
};
spyOn(pluginUtil, 'getInstalledPlugins').and.returnValue([
{ id: 'ca.filmaj.AndroidPlugin', version: '4.2.0' }
]);
spyOn(cordovaUtil, 'getInstalledPlatformsWithVersions').and.returnValue(
Promise.resolve({ android: '3.1.0' })
);
});
afterEach(() => {
events.removeListener('warn', unmetRequirementsCollector);
});
function getFetchVersion (plugin) {
return pluginAdd.getFetchVersion(project, plugin, cordovaVersion);
}
it('Test 001 : should handle a mix of upper bounds and single versions', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': { 'cordova-android': '1.0.0' },
'0.0.2': { 'cordova-android': '>1.0.0' },
'<1.0.0': { 'cordova-android': '<2.0.0' },
'1.0.0': { 'cordova-android': '>2.0.0' },
'1.7.0': { 'cordova-android': '>4.0.0' },
'<2.3.0': { 'cordova-android': '<6.1.1' },
'2.3.0': { 'cordova-android': '6.1.1' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.3.0');
expectUnmetRequirements([getPlatformRequirement('6.1.1')]);
});
});
it('Test 002 : should apply upper bound engine constraints when there are no unspecified constraints above the upper bound', () => {
testPlugin.engines.cordovaDependencies = {
'1.0.0': { 'cordova-android': '>2.0.0' },
'1.7.0': { 'cordova-android': '>4.0.0' },
'<2.3.0': {
'cordova-android': '<6.1.1',
'ca.filmaj.AndroidPlugin': '<1.0.0'
},
'2.3.0': { 'cordova-android': '6.1.1' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([getPlatformRequirement('6.1.1')]);
});
});
it('Test 003 : should apply upper bound engine constraints when there are unspecified constraints above the upper bound', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': {},
'2.0.0': { 'cordova-android': '~5.0.0' },
'<1.0.0': { 'cordova-android': '>5.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.7.1');
expectUnmetRequirements([getPlatformRequirement('~5.0.0')]);
});
});
it('Test 004 : should handle the case where there are no constraints for earliest releases', () => {
testPlugin.engines.cordovaDependencies = {
'1.0.0': { 'cordova-android': '~5.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('0.7.0');
expectUnmetRequirements([getPlatformRequirement('~5.0.0')]);
});
});
it('Test 005 : should handle the case where the lowest version is unsatisfied', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.2': { 'cordova-android': '~5.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([getPlatformRequirement('~5.0.0')]);
});
});
it('Test 006 : should handle upperbounds if no single version constraints are given', () => {
testPlugin.engines.cordovaDependencies = {
'<1.0.0': { 'cordova-android': '<2.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('2.3.0');
expectUnmetRequirements([]);
});
});
it('Test 007 : should apply upper bounds greater than highest version', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': {},
'<5.0.0': { 'cordova-android': '<2.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([getPlatformRequirement('<2.0.0')]);
});
});
it('Test 008 : should treat empty constraints as satisfied', () => {
testPlugin.engines.cordovaDependencies = {
'1.0.0': {},
'1.1.0': { 'cordova-android': '>5.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.0.0');
expectUnmetRequirements([getPlatformRequirement('>5.0.0')]);
});
});
it('Test 009 : should ignore an empty cordovaDependencies entry', () => {
testPlugin.engines.cordovaDependencies = {};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([]);
});
});
it('Test 010 : should ignore a badly formatted semver range', () => {
testPlugin.engines.cordovaDependencies = {
'1.1.3': { 'cordova-android': 'badSemverRange' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('2.3.0');
expectUnmetRequirements([]);
});
});
it('Test 011 : should respect unreleased versions in constraints', () => {
testPlugin.engines.cordovaDependencies = {
'1.0.0': { 'cordova-android': '3.1.0' },
'1.1.2': { 'cordova-android': '6.1.1' },
'1.3.0': { 'cordova-android': '6.1.1' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.1.0');
expectUnmetRequirements([getPlatformRequirement('6.1.1')]);
});
});
it('Test 012 : should respect plugin constraints', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': { 'ca.filmaj.AndroidPlugin': '1.2.0' },
'1.1.3': { 'ca.filmaj.AndroidPlugin': '<5.0.0 || >2.3.0' },
'2.3.0': { 'ca.filmaj.AndroidPlugin': '6.1.1' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('2.0.0');
expectUnmetRequirements([getPluginRequirement('6.1.1')]);
});
});
it('Test 013 : should respect cordova constraints', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': { cordova: '>1.0.0' },
'1.1.3': { cordova: '<3.0.0 || >4.0.0' },
'2.3.0': { cordova: '6.1.1' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.1.0');
expectUnmetRequirements([getCordovaRequirement('6.1.1')]);
});
});
it('Test 014 : should not include pre-release versions', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': {},
'2.0.0': { 'cordova-android': '>5.0.0' }
};
// Should not return 2.0.0-rc.2
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.7.1');
expectUnmetRequirements([getPlatformRequirement('>5.0.0')]);
});
});
it('Test 015 : should not fail if there is no engine in the npm info', () => {
delete testPlugin.engines;
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([]);
});
});
it('Test 016 : should not fail if there is no cordovaDependencies in the engines', () => {
testPlugin.engines = {
node: '>7.0.0',
npm: '~2.0.0'
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([]);
});
});
it('Test 017 : should handle extra whitespace', () => {
testPlugin.engines.cordovaDependencies = {
' 1.0.0 ': {},
'2.0.0 ': { ' cordova-android': '~5.0.0 ' },
' < 1.0.0\t': { ' cordova-android ': ' > 5.0.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.7.1');
expectUnmetRequirements([getPlatformRequirement('~5.0.0')]);
});
});
it('Test 018 : should ignore badly typed version requirement entries', () => {
testPlugin.engines.cordovaDependencies = {
'1.1.0': ['cordova', '5.0.0'],
'1.3.0': undefined,
'1.7.0': null
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('2.3.0');
expectUnmetRequirements([]);
});
});
it('Test 019 : should ignore badly typed constraint entries', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.2': { cordova: 1 },
'0.7.0': { cordova: {} },
'1.0.0': { cordova: undefined },
'1.1.3': { 8: '5.0.0' },
'1.3.0': { cordova: [] },
'1.7.1': { cordova: null }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('2.3.0');
expectUnmetRequirements([]);
});
});
it('Test 020 : should ignore bad semver versions', () => {
testPlugin.engines.cordovaDependencies = {
'0.0.0': { 'cordova-android': '5.0.0' },
notAVersion: { 'cordova-android': '3.1.0' },
'^1.1.2': { 'cordova-android': '3.1.0' },
'<=1.3.0': { 'cordova-android': '3.1.0' },
'1.0': { 'cordova-android': '3.1.0' },
2: { 'cordova-android': '3.1.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([getPlatformRequirement('5.0.0')]);
});
});
it('Test 021 : should not fail if there are bad semver versions', () => {
testPlugin.engines.cordovaDependencies = {
notAVersion: { 'cordova-android': '3.1.0' },
'^1.1.2': { 'cordova-android': '3.1.0' },
'<=1.3.0': { 'cordova-android': '3.1.0' },
'1.0.0': { 'cordova-android': '~3' }, // Good semver
'2.0.0': { 'cordova-android': '5.1.0' }, // Good semver
'1.0': { 'cordova-android': '3.1.0' },
2: { 'cordova-android': '3.1.0' }
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.7.1');
expectUnmetRequirements([getPlatformRequirement('5.1.0')]);
});
});
it('Test 022 : should properly warn about multiple unmet requirements', () => {
testPlugin.engines.cordovaDependencies = {
'1.7.0': {
'cordova-android': '>5.1.0',
'ca.filmaj.AndroidPlugin': '3.1.0',
cordova: '3.4.2'
}
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.3.0');
expectUnmetRequirements([
getPlatformRequirement('>5.1.0'),
getPluginRequirement('3.1.0')
]);
});
});
it('Test 023 : should properly warn about both unmet latest and upper bound requirements', () => {
testPlugin.engines.cordovaDependencies = {
'1.7.0': { 'cordova-android': '>5.1.0' },
'<5.0.0': {
'cordova-android': '>7.1.0',
'ca.filmaj.AndroidPlugin': '3.1.0'
}
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe(null);
expectUnmetRequirements([
getPlatformRequirement('>5.1.0 AND >7.1.0'),
getPluginRequirement('3.1.0')
]);
});
});
it('Test 024 : should not warn about versions past latest', () => {
testPlugin.engines.cordovaDependencies = {
'1.7.0': { 'cordova-android': '>5.1.0' },
'7.0.0': {
'cordova-android': '>7.1.0',
'ca.filmaj.AndroidPlugin': '3.1.0'
}
};
return getFetchVersion(testPlugin).then(version => {
expect(version).toBe('1.3.0');
expectUnmetRequirements([getPlatformRequirement('>5.1.0')]);
});
});
});