You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/06/20 00:36:44 UTC
git commit: Further work on [CB-3737]. ios parser specs should be in
order.
Updated Branches:
refs/heads/master2 0a98697e4 -> a84fbbf89
Further work on [CB-3737]. ios parser specs should be in order.
Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/a84fbbf8
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/a84fbbf8
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/a84fbbf8
Branch: refs/heads/master2
Commit: a84fbbf893e830b9b83eb9ab97049bb686629c48
Parents: 0a98697
Author: Fil Maj <ma...@gmail.com>
Authored: Wed Jun 19 15:36:39 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Wed Jun 19 15:36:39 2013 -0700
----------------------------------------------------------------------
spec/metadata/ios_parser.spec.js | 412 +++++++++++++++++++++-------------
src/metadata/ios_parser.js | 6 +-
2 files changed, 263 insertions(+), 155 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a84fbbf8/spec/metadata/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/ios_parser.spec.js b/spec/metadata/ios_parser.spec.js
index d941179..e3cdfe4 100644
--- a/spec/metadata/ios_parser.spec.js
+++ b/spec/metadata/ios_parser.spec.js
@@ -16,195 +16,303 @@
specific language governing permissions and limitations
under the License.
*/
+var platforms = require('../../platforms'),
+ util = require('../../src/util'),
+ path = require('path'),
+ shell = require('shelljs'),
+ plist = require('plist'),
+ xcode = require('xcode'),
+ ET = require('elementtree'),
+ fs = require('fs'),
+ config = require('../../src/config'),
+ config_parser = require('../../src/config_parser'),
+ cordova = require('../../cordova');
-xdescribe('ios project parser', function () {
- it('should throw an exception with a path that is not a native ios project', function () {
- expect(function () {
- var project = new ios_parser(process.cwd());
- }).toThrow();
- });
- it('should accept a proper native ios project path as construction parameter', function () {
- var project;
- expect(function () {
- project = new ios_parser(ios_path);
- }).not.toThrow();
- expect(project).toBeDefined();
- });
-
- describe('update_from_config method', function () {
- var project, config;
-
- var ios_plist = path.join(ios_path, 'cordovaExample', 'cordovaExample-Info.plist'),
- ios_pbx = path.join(ios_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
- ios_config_xml = path.join(ios_path, 'cordovaExample', 'config.xml');
-
- var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
- var original_plist = fs.readFileSync(ios_plist, 'utf-8');
- var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
-
- beforeEach(function () {
- project = new ios_parser(ios_path);
- config = new config_parser(www_config);
+describe('ios project parser', function () {
+ var proj = '/some/path';
+ var exec, custom, readdir, cfg_parser;
+ beforeEach(function() {
+ exec = spyOn(shell, 'exec').andCallFake(function(cmd, opts, cb) {
+ cb(0, '');
});
- afterEach(function () {
- fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
- fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
- fs.writeFileSync(ios_plist, original_plist, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ custom = spyOn(config, 'has_custom_path').andReturn(false);
+ readdir = spyOn(fs, 'readdirSync').andReturn(['test.xcodeproj']);
+ cfg_parser = spyOn(util, 'config_parser');
+ });
+ describe('constructions', function() {
+ it('should throw if provided directory does not contain an xcodeproj file', function() {
+ readdir.andReturn(['noxcodehere']);
+ expect(function() {
+ new platforms.ios.parser(proj);
+ }).toThrow('The provided path is not a Cordova iOS project.');
});
- it('should throw an exception if a non config_parser object is passed into it', function () {
- expect(function () {
- project.update_from_config({});
- }).toThrow();
+ it('should create an instance with path, pbxproj, xcodeproj, originalName and cordovaproj properties', function() {
+ expect(function() {
+ var p = new platforms.ios.parser(proj);
+ expect(p.path).toEqual(proj);
+ expect(p.pbxproj).toEqual(path.join(proj, 'test.xcodeproj', 'project.pbxproj'));
+ expect(p.xcodeproj).toEqual(path.join(proj, 'test.xcodeproj'));
+ expect(p.originalName).toEqual('/test');
+ }).not.toThrow();
});
- it('should update the application name properly', function (done) {
- config.name('bond. james bond.');
- project.update_from_config(config, function () {
- var pbx_contents = fs.readFileSync(ios_pbx, 'utf-8');
- expect(pbx_contents.match(/PRODUCT_NAME\s*=\s*"bond. james bond."/)[0]).toBe('PRODUCT_NAME = "bond. james bond."');
- done();
+ });
+ describe('check_requirements', function() {
+ it('should fire a callback if there is an error during shelling out', function(done) {
+ exec.andCallFake(function(cmd, opts, cb) {
+ cb(50, 'there was an errorz!');
});
- });
- it('should update the application package name (bundle identifier) properly', function (done) {
- config.packageName('ca.filmaj.dewd');
- project.update_from_config(config, function () {
- var plist_contents = fs.readFileSync(ios_plist, 'utf-8');
- expect(plist_contents).toMatch(/<string>ca.filmaj.dewd/);
+ platforms.ios.parser.check_requirements(proj, function(err) {
+ expect(err).toContain('there was an errorz!');
done();
});
});
- it('should update the application version (CFBundleVersion) properly', function (done) {
- config.version('2.0.1');
- project.update_from_config(config, function () {
- var plist_contents = fs.readFileSync(ios_plist, 'utf-8');
- expect(plist_contents).toMatch(/<string>2.0.1/);
- done();
+ it('should fire a callback if the xcodebuild version is less than 4.5.x', function(done) {
+ exec.andCallFake(function(cmd, opts, cb) {
+ cb(0, 'version 4.4.9');
});
- });
- it('should update the whitelist in the project config.xml', function (done) {
- project.update_from_config(config, function () {
- var config_contents = fs.readFileSync(ios_config_xml, 'utf-8');
- expect(config_contents).toMatch(/<access origin="\*" \/>/);
+ platforms.ios.parser.check_requirements(proj, function(err) {
+ expect(err).toEqual('Xcode version installed is too old. Minimum: >=4.5.x, yours: 4.4.9');
done();
});
});
- describe('preferences', function () {
- it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function (done) {
- config.preference.add({name:'henrik', value:'sedin'});
- project.update_from_config(config, function () {
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(17);
- expect(ps[0].attrib.name).toEqual('KeyboardDisplayRequiresUserAction');
- expect(ps[0].attrib.value).toEqual('true');
- expect(ps[16].attrib.name).toEqual('henrik');
- expect(ps[16].attrib.value).toEqual('sedin');
+ });
+
+ describe('instance', function() {
+ var p, cp, rm, is_cordova, write, read;
+ var ios_proj = path.join(proj, 'platforms', 'ios');
+ beforeEach(function() {
+ p = new platforms.ios.parser(ios_proj);
+ cp = spyOn(shell, 'cp');
+ rm = spyOn(shell, 'rm');
+ is_cordova = spyOn(util, 'isCordova').andReturn(proj);
+ write = spyOn(fs, 'writeFileSync');
+ read = spyOn(fs, 'readFileSync');
+ });
+
+ describe('update_from_config method', function() {
+ var et, xml, find, write_xml, root;
+ var cfg, find_obj, root_obj, cfg_access_add, cfg_access_rm, cfg_pref_add, cfg_pref_rm;
+ var plist_parse, plist_build, xc;
+ var update_name, xc_write;
+ beforeEach(function() {
+ find_obj = {
+ text:'hi'
+ };
+ root_obj = {
+ attrib:{
+ package:'android_pkg'
+ }
+ };
+ find = jasmine.createSpy('ElementTree find').andReturn(find_obj);
+ write_xml = jasmine.createSpy('ElementTree write');
+ root = jasmine.createSpy('ElementTree getroot').andReturn(root_obj);
+ et = spyOn(ET, 'ElementTree').andReturn({
+ find:find,
+ write:write_xml,
+ getroot:root
+ });
+ xml = spyOn(ET, 'XML');
+ plist_parse = spyOn(plist, 'parseFileSync').andReturn({
+ });
+ plist_build = spyOn(plist, 'build').andReturn('');
+ update_name = jasmine.createSpy('update_name');
+ xc_write = jasmine.createSpy('xcode writeSync');
+ xc = spyOn(xcode, 'project').andReturn({
+ parse:function(cb) {cb();},
+ updateProductName:update_name,
+ writeSync:xc_write
+ });
+ cfg = new config_parser();
+ cfg.name = function() { return 'testname' };
+ cfg.packageName = function() { return 'testpkg' };
+ cfg.version = function() { return 'one point oh' };
+ cfg.access.get = function() { return [] };
+ cfg.preference.get = function() { return [] };
+ cfg_access_add = jasmine.createSpy('config_parser access add');
+ cfg_access_rm = jasmine.createSpy('config_parser access rm');
+ cfg_pref_rm = jasmine.createSpy('config_parser pref rm');
+ cfg_pref_add = jasmine.createSpy('config_parser pref add');
+ cfg_parser.andReturn({
+ access:{
+ remove:cfg_access_rm,
+ get:function(){},
+ add:cfg_access_add
+ },
+ preference:{
+ remove:cfg_pref_rm,
+ get:function(){},
+ add:cfg_pref_add
+ }
+ });
+ p = new platforms.ios.parser(ios_proj);
+ });
+
+ it('should write out the app name to pbxproj by calling xcode.updateProductName', function(done) {
+ p.update_from_config(cfg, function() {
+ expect(update_name).toHaveBeenCalledWith('testname');
+ done();
+ });
+ });
+ it('should write out the app id to info plist as CFBundleIdentifier', function(done) {
+ p.update_from_config(cfg, function() {
+ expect(plist_build.mostRecentCall.args[0].CFBundleIdentifier).toEqual('testpkg');
+ done();
+ });
+ });
+ it('should write out the app version to info plist as CFBundleVersion', function(done) {
+ p.update_from_config(cfg, function() {
+ expect(plist_build.mostRecentCall.args[0].CFBundleVersion).toEqual('one point oh');
+ done();
+ });
+ });
+ it('should wipe out the ios whitelist every time', function(done) {
+ p.update_from_config(cfg, function() {
+ expect(cfg_access_rm).toHaveBeenCalled();
+ done();
+ });
+ });
+ it('should update the whitelist', function(done) {
+ cfg.access.get = function() { return ['one'] };
+ p.update_from_config(cfg, function() {
+ expect(cfg_access_add).toHaveBeenCalledWith('one');
done();
});
});
- it('should override a default project preference if applicable', function (done) {
- config.preference.add({name:'UIWebViewBounce', value:'false'});
- project.update_from_config(config, function () {
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(16);
- expect(ps[2].attrib.name).toEqual('UIWebViewBounce');
- expect(ps[2].attrib.value).toEqual('false');
+ it('should update preferences', function(done) {
+ var sample_pref = {name:'pref',value:'yes'};
+ cfg.preference.get = function() { return [sample_pref] };
+ p.update_from_config(cfg, function() {
+ expect(cfg_pref_add).toHaveBeenCalledWith(sample_pref);
+ done();
+ });
+ });
+ it('should wipe out the ios preferences every time', function(done) {
+ p.update_from_config(cfg, function() {
+ expect(cfg_pref_rm).toHaveBeenCalled();
+ done();
+ });
+ });
+ it('should write out default preferences every time', function(done) {
+ var sample_pref = {name:'preftwo',value:'false'};
+ cfg.preference.get = function() { return [sample_pref] };
+ p.update_from_config(cfg, function() {
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"KeyboardDisplayRequiresUserAction",value:"true"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"SuppressesIncrementalRendering",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"UIWebViewBounce",value:"true"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"TopActivityIndicator",value:"gray"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"EnableLocation",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"EnableViewportScale",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"AutoHideSplashScreen",value:"true"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"ShowSplashScreenSpinner",value:"true"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"MediaPlaybackRequiresUserAction",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"AllowInlineMediaPlayback",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"OpenAllWhitelistURLsInWebView",value:"false"});
+ expect(cfg_pref_add).toHaveBeenCalledWith({name:"BackupWebStorage",value:"cloud"});
done();
});
});
});
- });
-
- describe('cross-platform project level methods', function () {
- var parser, config;
- var ios_plist = path.join(ios_project_path, 'cordovaExample', 'cordovaExample-Info.plist'),
- ios_pbx = path.join(ios_project_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
- ios_config_xml = path.join(ios_project_path, 'cordovaExample', 'config.xml');
-
- var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
- var original_plist = fs.readFileSync(ios_plist, 'utf-8');
- var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
-
- beforeEach(function () {
- parser = new ios_parser(ios_project_path);
- config = new config_parser(www_config);
+ describe('www_dir method', function() {
+ it('should return /www', function() {
+ expect(p.www_dir()).toEqual(path.join(ios_proj, 'www'));
+ });
});
- afterEach(function () {
- fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
- fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
- fs.writeFileSync(ios_plist, original_plist, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ describe('staging_dir method', function() {
+ it('should return .staging/www', function() {
+ expect(p.staging_dir()).toEqual(path.join(ios_proj, '.staging', 'www'));
+ });
});
-
- describe('update_www method', function () {
- it('should update all www assets', function () {
- var newFile = path.join(util.projectWww(project_path), 'somescript.js');
- this.after(function () {
- shell.rm('-f', newFile);
- });
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- parser.update_www();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'somescript.js'))).toBe(true);
+ describe('config_xml method', function() {
+ it('should return the location of the config.xml', function() {
+ expect(p.config_xml()).toEqual(path.join(ios_proj, 'test', 'config.xml'));
+ });
+ });
+ describe('update_www method', function() {
+ it('should rm project-level www and cp in platform agnostic www', function() {
+ p.update_www();
+ expect(rm).toHaveBeenCalled();
+ expect(cp).toHaveBeenCalled();
+ });
+ it('should copy in a fresh cordova.js from stock cordova lib if no custom lib is specified', function() {
+ p.update_www();
+ expect(cp.mostRecentCall.args[1]).toMatch(util.libDirectory);
});
- it('should write out ios js to cordova.js', function () {
- parser.update_www();
- expect(fs.readFileSync(path.join(ios_project_path, 'www', 'cordova.js'), 'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-ios', 'CordovaLib', 'cordova.js'), 'utf-8'));
+ it('should copy in a fresh cordova.js from custom cordova lib if custom lib is specified', function() {
+ var custom_path = '/custom/path';
+ custom.andReturn(custom_path);
+ p.update_www();
+ expect(cp.mostRecentCall.args[1]).toMatch(custom_path);
});
});
-
- describe('update_overrides method', function () {
- var mergesPath = path.join(util.appDir(project_path), 'merges', 'ios');
- var newFile = path.join(mergesPath, 'merge.js');
+ describe('update_overrides method', function() {
+ var exists;
beforeEach(function() {
- shell.mkdir('-p', mergesPath);
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ exists = spyOn(fs, 'existsSync').andReturn(true);
});
- afterEach(function() {
- shell.rm('-rf', mergesPath);
+ it('should do nothing if merges directory does not exist', function() {
+ exists.andReturn(false);
+ p.update_overrides();
+ expect(cp).not.toHaveBeenCalled();
});
-
- it('should copy a new file from merges into www', function () {
- parser.update_overrides();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
+ it('should copy merges path into www', function() {
+ p.update_overrides();
+ expect(cp).toHaveBeenCalled();
});
-
- it('should copy a file from merges over a file in www', function () {
- var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
- fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
- this.after(function () {
- shell.rm('-rf', newFileWWW);
- });
-
- parser.update_overrides();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
- expect(fs.readFileSync(path.join(ios_project_path, 'www', 'merge.js'), 'utf-8')).toEqual('alert("sup");');
+ });
+ describe('update_staging method', function() {
+ var exists;
+ beforeEach(function() {
+ exists = spyOn(fs, 'existsSync').andReturn(true);
+ });
+ it('should do nothing if staging dir does not exist', function() {
+ exists.andReturn(false);
+ p.update_staging();
+ expect(cp).not.toHaveBeenCalled();
+ });
+ it('should copy the staging dir into www if staging dir exists', function() {
+ p.update_staging();
+ expect(cp).toHaveBeenCalled();
});
});
-
- describe('update_project method', function () {
- it('should invoke update_www', function (done) {
- var spyWww = spyOn(parser, 'update_www');
- parser.update_project(config, function () {
- expect(spyWww).toHaveBeenCalled();
- done();
- });
+ describe('update_project method', function() {
+ var config, www, overrides, staging, svn;
+ beforeEach(function() {
+ config = spyOn(p, 'update_from_config').andCallFake(function(cfg, cb) { cb() });
+ www = spyOn(p, 'update_www');
+ overrides = spyOn(p, 'update_overrides');
+ staging = spyOn(p, 'update_staging');
+ svn = spyOn(util, 'deleteSvnFolders');
});
- it('should invoke update_from_config', function (done) {
- var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
- parser.update_project(config, function () {
- expect(spyConfig).toHaveBeenCalled();
+ it('should call update_from_config', function() {
+ p.update_project();
+ expect(config).toHaveBeenCalled();
+ });
+ it('should throw if update_from_config errors', function(done) {
+ var err = new Error('uh oh!');
+ config.andCallFake(function(cfg, cb) { cb(err); });
+ p.update_project({}, function(err) {
+ expect(err).toEqual(err);
done();
});
});
- it('should call out to util.deleteSvnFolders', function(done) {
- var spy = spyOn(util, 'deleteSvnFolders');
- var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
- parser.update_project(config, function () {
- expect(spy).toHaveBeenCalled();
+ it('should call update_www', function(done) {
+ p.update_project({}, function() {
+ expect(www).toHaveBeenCalled();
done();
});
});
+ it('should call update_overrides', function() {
+ p.update_project();
+ expect(overrides).toHaveBeenCalled();
+ });
+ it('should call update_staging', function() {
+ p.update_project();
+ expect(staging).toHaveBeenCalled();
+ });
+ it('should call deleteSvnFolders', function() {
+ p.update_project();
+ expect(svn).toHaveBeenCalled();
+ });
});
});
});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a84fbbf8/src/metadata/ios_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/ios_parser.js b/src/metadata/ios_parser.js
index 2853b98..343a72b 100644
--- a/src/metadata/ios_parser.js
+++ b/src/metadata/ios_parser.js
@@ -28,7 +28,7 @@ var fs = require('fs'),
config_parser = require('../config_parser'),
config = require('../config');
-var MIN_XCODE_VERSION = '4.5.x';
+var MIN_XCODE_VERSION = '>=4.5.x';
var default_prefs = {
"KeyboardDisplayRequiresUserAction":"true",
@@ -58,7 +58,7 @@ module.exports = function ios_parser(project) {
this.path = project;
this.pbxproj = path.join(this.xcodeproj, 'project.pbxproj');
this.config_path = path.join(this.cordovaproj, 'config.xml');
- this.config = new config_parser(this.config_path);
+ this.config = new util.config_parser(this.config_path);
};
module.exports.check_requirements = function(project_root, callback) {
@@ -72,7 +72,7 @@ module.exports.check_requirements = function(project_root, callback) {
callback('Xcode is (probably) not installed, specifically the command `xcodebuild` is unavailable or erroring out. Output of `'+command+'` is: ' + output);
} else {
var xc_version = output.split('\n')[0].split(' ')[1];
- if (semver.lt(xc_version, MIN_XCODE_VERSION)) {
+ if (!semver.satisfies(xc_version, MIN_XCODE_VERSION)) {
callback('Xcode version installed is too old. Minimum: ' + MIN_XCODE_VERSION + ', yours: ' + xc_version);
} else callback(false);
}