You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mw...@apache.org on 2013/05/15 22:35:41 UTC

[02/37] Reorganize specs into cordova-cli/ and platform-script/

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
deleted file mode 100644
index fcb3e76..0000000
--- a/spec/create.spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-var cordova = require('../cordova'),
-    path    = require('path'),
-    shell   = require('shelljs'),
-    fs      = require('fs'),
-    tempDir = path.join(__dirname, '..', 'temp');
-
-describe('create command', function () {
-    beforeEach(function() {
-        shell.rm('-rf', tempDir);
-    });
-
-    it('should print out help txt if no directory is provided', function() {
-        expect(cordova.create()).toMatch(/synopsis/i);
-    });
-    it('should create a cordova project in the specified directory if parameter is provided', function() {
-        cordova.create(tempDir);
-        var dotc = path.join(tempDir, '.cordova', 'config.json');
-        expect(fs.lstatSync(dotc).isFile()).toBe(true);
-        expect(JSON.parse(fs.readFileSync(dotc, 'utf8')).name).toBe("HelloCordova");
-        var hooks = path.join(tempDir, '.cordova', 'hooks');
-        expect(fs.existsSync(hooks)).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_platform_add'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_prepare'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_compile'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_platform_add'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_platform_rm'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_platform_rm'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_platform_ls'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_platform_ls'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_plugin_add'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_plugin_add'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_plugin_rm'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_plugin_rm'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_plugin_ls'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_plugin_ls'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_prepare'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_compile'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_build'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_build'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_emulate'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_emulate'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'before_docs'))).toBe(true);
-        expect(fs.existsSync(path.join(hooks, 'after_docs'))).toBe(true);
-    });
-    it('should throw if the directory is already a cordova project', function() {
-        shell.mkdir('-p', path.join(tempDir, '.cordova'));
-        
-        expect(function() {
-            cordova.create(tempDir);
-        }).toThrow();
-    });
-    it('should create a cordova project in the specified dir with specified name if provided', function() {
-        cordova.create(tempDir, "balls");
-
-        expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
-
-        expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/);
-    });
-    it('should create a cordova project in the specified dir with specified name and id if provided', function() {
-        cordova.create(tempDir, "birdy.nam.nam", "numnum");
-
-        expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
-
-        var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8');
-        expect(config).toMatch(/<name>numnum<\/name>/);
-        expect(config).toMatch(/id="birdy\.nam\.nam"/);
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/emulate.spec.js
----------------------------------------------------------------------
diff --git a/spec/emulate.spec.js b/spec/emulate.spec.js
deleted file mode 100644
index 3a4d1a4..0000000
--- a/spec/emulate.spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
-    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.
-*/
-var cordova = require('../cordova'),
-    et = require('elementtree'),
-    shell = require('shelljs'),
-    path = require('path'),
-    fs = require('fs'),
-    config_parser = require('../src/config_parser'),
-    android_parser = require('../src/metadata/android_parser'),
-    ios_parser = require('../src/metadata/ios_parser'),
-    blackberry_parser = require('../src/metadata/blackberry_parser'),
-    hooker = require('../src/hooker'),
-    fixtures = path.join(__dirname, 'fixtures'),
-    hooks = path.join(fixtures, 'hooks'),
-    tempDir = path.join(__dirname, '..', 'temp'),
-    cordova_project = path.join(fixtures, 'projects', 'cordova');
-
-var cwd = process.cwd();
-
-describe('emulate command', function() {
-    beforeEach(function() {
-        shell.rm('-rf', tempDir);
-        shell.mkdir('-p', tempDir);
-    });
-
-    it('should not run inside a Cordova-based project with no added platforms', function() {
-        this.after(function() {
-            process.chdir(cwd);
-        });
-
-        cordova.create(tempDir);
-        process.chdir(tempDir);
-        expect(function() {
-            cordova.emulate();
-        }).toThrow();
-    });
-    
-    it('should run inside a Cordova-based project with at least one added platform', function() {
-        shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
-        shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
-        this.after(function() {
-            process.chdir(cwd);
-            shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
-            shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
-        });
-
-        process.chdir(cordova_project);
-
-        var s = spyOn(shell, 'exec');
-        var a_spy = spyOn(android_parser.prototype, 'update_project');
-        expect(function() {
-            cordova.emulate();
-            a_spy.mostRecentCall.args[1](); // fake out android parser
-            expect(s).toHaveBeenCalled();
-        }).not.toThrow();
-    });
-    it('should not run outside of a Cordova-based project', function() {
-        this.after(function() {
-            process.chdir(cwd);
-        });
-
-        shell.mkdir('-p', tempDir);
-        process.chdir(tempDir);
-
-        expect(function() {
-            cordova.emulate();
-        }).toThrow();
-    });
-    describe('per platform', function() {
-        beforeEach(function() {
-            process.chdir(cordova_project);
-        });
-
-        afterEach(function() {
-            process.chdir(cwd);
-        });
-       
-        describe('Android', function() {
-            var s;
-            beforeEach(function() {
-                s = spyOn(require('shelljs'), 'exec');
-            });
-            it('should shell out to run command on Android', function() {
-                cordova.emulate('android');
-                expect(s.mostRecentCall.args[0].match(/\/cordova\/run/)).not.toBeNull();
-            });
-            it('should call android_parser\'s update_project', function() {
-                var spy = spyOn(android_parser.prototype, 'update_project');
-                cordova.emulate('android');
-                expect(spy).toHaveBeenCalled();
-            });
-        });
-        describe('iOS', function() {
-            it('should shell out to emulate command on iOS', function() {
-                var s = spyOn(require('shelljs'), 'exec');
-                var proj_spy = spyOn(ios_parser.prototype, 'update_project');
-                cordova.emulate('ios');
-                proj_spy.mostRecentCall.args[1]();
-                expect(s).toHaveBeenCalled();
-                expect(s.mostRecentCall.args[0].match(/\/cordova\/emulate/)).not.toBeNull();
-            });
-            it('should call ios_parser\'s update_project', function() {
-                var s = spyOn(ios_parser.prototype, 'update_project');
-                cordova.emulate('ios');
-                expect(s).toHaveBeenCalled();
-            });
-        });
-        describe('BlackBerry', function() {
-            it('should shell out to ant command on blackberry', function() {
-                var proj_spy = spyOn(blackberry_parser.prototype, 'update_project');
-                var s = spyOn(require('shelljs'), 'exec');
-                cordova.emulate('blackberry');
-                proj_spy.mostRecentCall.args[1](); // update_project fake
-                expect(s).toHaveBeenCalled();
-                expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-simulator/);
-            });
-            it('should call blackberry_parser\'s update_project', function() {
-                var s = spyOn(blackberry_parser.prototype, 'update_project');
-                cordova.emulate('blackberry');
-                expect(s).toHaveBeenCalled();
-            });
-        });
-    });
-
-    describe('hooks', function() {
-        var s, sh, ap;
-        beforeEach(function() {
-            s = spyOn(hooker.prototype, 'fire').andReturn(true);
-        });
-
-        describe('when platforms are added', function() {
-            beforeEach(function() {
-                shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
-                shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
-                sh = spyOn(shell, 'exec');
-                ap = spyOn(android_parser.prototype, 'update_project');
-                process.chdir(cordova_project);
-            });
-            afterEach(function() {
-                shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
-                shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
-                process.chdir(cwd);
-            });
-
-            it('should fire before hooks through the hooker module', function() {
-                cordova.emulate();
-                expect(s).toHaveBeenCalledWith('before_emulate');
-            });
-            it('should fire after hooks through the hooker module', function() {
-                cordova.emulate();
-                ap.mostRecentCall.args[1](); // fake parser call
-                sh.mostRecentCall.args[2](0); //fake shell call
-                expect(s).toHaveBeenCalledWith('after_emulate');
-            });
-        });
-
-        describe('with no platforms added', function() {
-            beforeEach(function() {
-                cordova.create(tempDir);
-                process.chdir(tempDir);
-            });
-            afterEach(function() {
-                process.chdir(cwd);
-            });
-            it('should not fire the hooker', function() {
-                spyOn(shell, 'exec');
-                expect(function() {
-                    cordova.emulate();
-                }).toThrow();
-                expect(s).not.toHaveBeenCalledWith('before_emulate');
-                expect(s).not.toHaveBeenCalledWith('after_emulate');
-            });
-        });
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/helper.js
----------------------------------------------------------------------
diff --git a/spec/helper.js b/spec/helper.js
deleted file mode 100644
index 2c4f331..0000000
--- a/spec/helper.js
+++ /dev/null
@@ -1,20 +0,0 @@
-
-/**
-    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.
-*/
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/hooker.spec.js b/spec/hooker.spec.js
deleted file mode 100644
index 4a0ca7d..0000000
--- a/spec/hooker.spec.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
-    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.
-*/
-var hooker = require('../src/hooker'),
-    shell  = require('shelljs'),
-    path   = require('path'),
-    fs     = require('fs'),
-    tempDir= path.join(__dirname, '..', 'temp'),
-    hooks  = path.join(__dirname, 'fixtures', 'hooks'),
-    cordova= require('../cordova');
-
-var cwd = process.cwd();
-
-describe('hooker', function() {
-    it('should throw if provided directory is not a cordova project', function() {
-        shell.rm('-rf', tempDir);
-        shell.mkdir('-p', tempDir); 
-        this.after(function() {
-            shell.rm('-rf', tempDir);
-        });
-
-        expect(function() {
-            var h = new hooker(tempDir);
-        }).toThrow();
-    });
-    it('should not throw if provided directory is a cordova project', function() {
-        cordova.create(tempDir);
-        this.after(function() {
-            shell.rm('-rf', tempDir);
-        });
-
-        expect(function() {
-            var h = new hooker(tempDir);
-        }).not.toThrow();
-    });
-
-    describe('fire method', function() {
-        var h;
-
-        beforeEach(function() {
-            cordova.create(tempDir);
-            h = new hooker(tempDir);
-        });
-        afterEach(function() {
-            shell.rm('-rf', tempDir);
-        });
-
-        describe('failure', function() {
-            it('should not throw if the hook is unrecognized', function() {
-                expect(function() {
-                    h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!');
-                }).not.toThrow();
-            });
-            it('should throw if any script exits with non-zero code', function() {
-                var script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.sh');
-                shell.cp(path.join(hooks, 'fail', 'fail.sh'), script);
-                fs.chmodSync(script, '754');
-                expect(function() {
-                    h.fire('before_build');
-                }).toThrow();
-            });
-        });
-
-        describe('success', function() {
-            it('should execute all scripts in order and return true', function() {
-                var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
-                shell.cp(path.join(hooks, 'test', '*'), path.join(hook, '.'));
-                fs.readdirSync(hook).forEach(function(script) {
-                    fs.chmodSync(path.join(hook, script), '754');
-                });
-                var returnValue;
-                var s = spyOn(shell, 'exec').andReturn({code:0});
-                expect(function() {
-                    returnValue = h.fire('before_build');
-                }).not.toThrow();
-                expect(returnValue).toBe(true);
-                expect(s.calls[0].args[0]).toMatch(/0.sh/);
-                expect(s.calls[1].args[0]).toMatch(/1.sh/);
-            });
-            it('should pass the project root folder as parameter into the project-level hooks', function() {
-                var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
-                shell.cp(path.join(hooks, 'test', '0.sh'), path.join(hook, '.'));
-                fs.readdirSync(hook).forEach(function(script) {
-                    fs.chmodSync(path.join(hook, script), '754');
-                });
-                var returnValue;
-                var s = spyOn(shell, 'exec').andReturn({code:0});
-                expect(function() {
-                    returnValue = h.fire('before_build');
-                }).not.toThrow();
-                expect(returnValue).toBe(true);
-                var paramRegex = new RegExp('0.sh "'+tempDir+'"$');
-                expect(s.calls[0].args[0]).toMatch(paramRegex);
-            });
-            describe('module-level hooks', function() {
-                var handler = jasmine.createSpy();
-                var test_event = 'before_build';
-                afterEach(function() {
-                    cordova.off(test_event, handler);
-                    handler.reset();
-                });
-
-                it('should fire handlers using cordova.on', function() {
-                    cordova.on(test_event, handler);
-                    h.fire(test_event);
-                    expect(handler).toHaveBeenCalled();
-                });
-                it('should pass the project root folder as parameter into the module-level handlers', function() {
-                    cordova.on(test_event, handler);
-                    h.fire('before_build');
-                    expect(handler).toHaveBeenCalledWith(tempDir);
-                });
-                it('should be able to stop listening to events using cordova.off', function() {
-                    cordova.on(test_event, handler);
-                    cordova.off(test_event, handler);
-                    h.fire('before_build');
-                    expect(handler).not.toHaveBeenCalled();
-                });
-            });
-        });
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/android_parser.spec.js b/spec/metadata/android_parser.spec.js
deleted file mode 100644
index d051c6f..0000000
--- a/spec/metadata/android_parser.spec.js
+++ /dev/null
@@ -1,220 +0,0 @@
-
-/**
-    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.
-*/
-var android_parser = require('../../src/metadata/android_parser'),
-    config_parser = require('../../src/config_parser'),
-    util = require('../../src/util'),
-    path = require('path'),
-    shell = require('shelljs'),
-    fs = require('fs'),
-    et = require('elementtree'),
-    cordova = require('../../cordova'),
-    projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
-    android_path = path.join(projects_path, 'native', 'android_fixture'),
-    project_path = path.join(projects_path, 'cordova'),
-    android_project_path = path.join(project_path, 'platforms', 'android');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('android project parser', function() {
-    it('should throw an exception with a path that is not a native android project', function() {
-        expect(function() {
-            var project = new android_parser(process.cwd());
-        }).toThrow();
-    });
-    it('should accept a proper native android project path as construction parameter', function() {
-        expect(function() {
-            var project = new android_parser(android_path);
-            expect(project).toBeDefined();
-        }).not.toThrow();
-    });
-
-    describe('update_from_config method', function() {
-        var project, config;
-        
-        var android_strings = path.join(android_path, 'res', 'values', 'strings.xml');
-        var android_manifest = path.join(android_path, 'AndroidManifest.xml');
-        var android_config = path.join(android_path, 'res', 'xml', 'config.xml');
-
-        var original_strings = fs.readFileSync(android_strings, 'utf-8');
-        var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
-        var original_android_config = fs.readFileSync(android_config, 'utf-8');
-
-        beforeEach(function() {
-            project = new android_parser(android_path);
-            config = new config_parser(www_config);
-        });
-        afterEach(function() {
-            fs.writeFileSync(android_strings, original_strings, 'utf-8');
-            fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
-            fs.writeFileSync(www_config, original_www_config, 'utf-8');
-            fs.writeFileSync(android_config, original_android_config, 'utf-8');
-        });
-        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 update the application name properly', function() {
-            config.name('bond. james bond.');
-            project.update_from_config(config);
-
-            var strings = new et.ElementTree(et.XML(fs.readFileSync(android_strings, 'utf-8')));
-            var app_name = strings.find('string[@name="app_name"]').text;
-
-            expect(app_name).toBe('bond. james bond.');
-        });
-        it('should update the application package name properly', function() {
-            var javs = path.join(android_path, 'src', 'ca', 'filmaj', 'dewd', 'cordovaExample.java');
-            var orig_javs = path.join(android_path, 'src', 'org', 'apache', 'cordova', 'cordovaExample', 'cordovaExample.java');
-            var orig_contents = fs.readFileSync(orig_javs, 'utf-8');
-            this.after(function() {
-                fs.writeFileSync(orig_javs, orig_contents, 'utf-8');
-                shell.rm('-rf', path.join(android_path, 'src', 'ca'));
-            });
-            config.packageName('ca.filmaj.dewd');
-            project.update_from_config(config);
-
-            var manifest = new et.ElementTree(et.XML(fs.readFileSync(android_manifest, 'utf-8')));
-            expect(manifest.getroot().attrib.package).toEqual('ca.filmaj.dewd');
-
-            expect(fs.existsSync(javs)).toBe(true);
-            expect(fs.readFileSync(javs, 'utf-8')).toMatch(/package ca.filmaj.dewd/i);
-        });
-        it('should update the whitelist properly', function() {
-            config.access.remove('*');
-            config.access.add('http://apache.org');
-            config.access.add('http://github.com');
-            project.update_from_config(config);
-
-            var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
-            var as = native_config.findall('access');
-            expect(as.length).toEqual(2);
-            expect(as[0].attrib.origin).toEqual('http://apache.org');
-            expect(as[1].attrib.origin).toEqual('http://github.com');
-        });
-        describe('preferences', function() {
-            it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
-                config.preference.add({name:'henrik',value:'sedin'});
-                project.update_from_config(config);
-
-                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
-                var ps = native_config.findall('preference');
-                expect(ps.length).toEqual(7);
-                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
-                expect(ps[0].attrib.value).toEqual('true');
-                expect(ps[6].attrib.name).toEqual('henrik');
-                expect(ps[6].attrib.value).toEqual('sedin');
-            });
-            it('should override a default project preference if applicable', function() {
-                config.preference.add({name:'useBrowserHistory',value:'false'});
-                project.update_from_config(config);
-
-                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
-                var ps = native_config.findall('preference');
-                expect(ps.length).toEqual(6);
-                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
-                expect(ps[0].attrib.value).toEqual('false');
-            });
-        });
-    });
-
-    describe('cross-platform project level methods', function() {
-        var parser, config;
-        var android_strings = path.join(android_project_path, 'res', 'values', 'strings.xml');
-        var android_manifest = path.join(android_project_path, 'AndroidManifest.xml');
-        var android_config = path.join(android_project_path, 'res', 'xml', 'config.xml');
-
-        var original_strings = fs.readFileSync(android_strings, 'utf-8');
-        var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
-        var original_android_config = fs.readFileSync(android_config, 'utf-8');
-
-        beforeEach(function() {
-            parser = new android_parser(android_project_path);
-            config = new config_parser(www_config);
-        });
-        afterEach(function() {
-            fs.writeFileSync(android_strings, original_strings, 'utf-8');
-            fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
-            fs.writeFileSync(www_config, original_www_config, 'utf-8');
-            fs.writeFileSync(android_config, original_android_config, 'utf-8');
-        });
-        describe('update_www method', function() {
-            it('should update all www assets', function() {
-                var newFile = path.join(project_path, 'www', 'somescript.js');
-                this.after(function() {
-                    shell.rm('-f', newFile);
-                });
-                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
-                parser.update_www();
-                expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'somescript.js'))).toBe(true);
-            });
-            it('should write out android js to cordova.js', function() {
-                parser.update_www();
-                expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'cordova.js'),'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'js', 'cordova.android.js'), 'utf-8'));
-            });
-        });
-
-        describe('update_overrides method',function() {
-            var mergesPath = path.join(project_path, 'merges', 'android');
-            var newFile = path.join(mergesPath, 'merge.js');
-            beforeEach(function() {
-                shell.mkdir('-p', mergesPath);
-                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
-            });
-            afterEach(function() {
-                shell.rm('-rf', mergesPath);
-            });
-            it('should copy a new file from merges into www', function() {
-                parser.update_overrides();
-                expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
-            });
-
-            it('should copy a file from merges over a file in www', function() {
-                var newFileWWW = path.join(project_path, 'www','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(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
-                expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
-            });
-        });
-
-        describe('update_project method', function() {
-            it('should invoke update_www', function() {
-                var spyWww = spyOn(parser, 'update_www');
-                parser.update_project(config);
-                expect(spyWww).toHaveBeenCalled();
-            });
-            it('should invoke update_from_config', function() {
-                var spyConfig = spyOn(parser, 'update_from_config');
-                parser.update_project(config);
-                expect(spyConfig).toHaveBeenCalled();
-            });
-            it('should call out to util.deleteSvnFolders', function() {
-                var spy = spyOn(util, 'deleteSvnFolders');
-                parser.update_project(config);
-                expect(spy).toHaveBeenCalled();
-            });
-        });
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/blackberry_parser.spec.js b/spec/metadata/blackberry_parser.spec.js
deleted file mode 100644
index 12d5294..0000000
--- a/spec/metadata/blackberry_parser.spec.js
+++ /dev/null
@@ -1,249 +0,0 @@
-
-/**
-    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.
-*/
-var blackberry_parser = require('../../src/metadata/blackberry_parser'),
-    config_parser = require('../../src/config_parser'),
-    path = require('path'),
-    util = require('../../src/util'),
-    et = require('elementtree'),
-    shell = require('shelljs'),
-    cordova = require('../../cordova'),
-    fs = require('fs'),
-    projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
-    blackberry_path = path.join(projects_path, 'native', 'blackberry_fixture'),
-    project_path = path.join(projects_path, 'cordova'),
-    blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('blackberry project parser', function() {
-    beforeEach(function() {
-        spyOn(process.stdout, 'write'); // silence console output
-    });
-
-    it('should throw an exception with a path that is not a native blackberry project', function() {
-        expect(function() {
-            var project = new blackberry_parser(process.cwd());
-        }).toThrow();
-    });
-    it('should accept a proper native blackberry project path as construction parameter', function() {
-        var project;
-        expect(function() {
-            project = new blackberry_parser(blackberry_path);
-        }).not.toThrow();
-        expect(project).toBeDefined();
-    });
-
-    describe('update_from_config method', function() {
-        var project, config;
-
-        var blackberry_config = path.join(blackberry_path, 'www', 'config.xml');
-        var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
-
-        beforeEach(function() {
-            project = new blackberry_parser(blackberry_path);
-            config = new config_parser(www_config);
-        });
-        afterEach(function() {
-            fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
-            fs.writeFileSync(www_config, original_www_config, 'utf-8');
-        });
-        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 update the application name properly', function() {
-            config.name('bond. james bond.');
-            project.update_from_config(config);
-
-            var bb_cfg = new config_parser(blackberry_config);
-
-            expect(bb_cfg.name()).toBe('bond. james bond.');
-        });
-        it('should update the application package name properly', function() {
-            config.packageName('sofa.king.awesome');
-            project.update_from_config(config);
-
-            var bb_cfg = new config_parser(blackberry_config);
-            expect(bb_cfg.packageName()).toBe('sofa.king.awesome');
-        });
-        describe('whitelist', function() {
-            it('should update the whitelist when using access elements with origin attribute', function() {
-                config.access.remove('*');
-                config.access.add('http://blackberry.com');
-                config.access.add('http://rim.com');
-                project.update_from_config(config);
-
-                var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
-                var as = bb_cfg.getroot().findall('access');
-                expect(as.length).toEqual(2);
-                expect(as[0].attrib.uri).toEqual('http://blackberry.com');
-                expect(as[1].attrib.uri).toEqual('http://rim.com');
-            });
-            it('should update the whitelist when using access elements with uri attributes', function() {
-                fs.writeFileSync(www_config, fs.readFileSync(www_config, 'utf-8').replace(/origin="\*/,'uri="http://rim.com'), 'utf-8');
-                config = new config_parser(www_config);
-                project.update_from_config(config);
-
-                var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
-                var as = bb_cfg.getroot().findall('access');
-                expect(as.length).toEqual(1);
-                expect(as[0].attrib.uri).toEqual('http://rim.com');
-            });
-        });
-    });
-
-    describe('cross-platform project level methods', function() {
-        var parser, config;
-
-        var blackberry_config = path.join(blackberry_project_path, 'www', 'config.xml');
-        var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
-
-        beforeEach(function() {
-            parser = new blackberry_parser(blackberry_project_path);
-            config = new config_parser(www_config);
-        });
-        afterEach(function() {
-            fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
-            fs.writeFileSync(www_config, original_www_config, 'utf-8');
-        });
-
-        describe('update_www method', function() {
-            it('should update all www assets', function() {
-                var newFile = path.join(project_path, 'www', 'somescript.js');
-                this.after(function() {
-                    shell.rm('-f', newFile);
-                });
-                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
-                parser.update_www();
-                expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'somescript.js'))).toBe(true);
-            });
-            it('should not overwrite the blackberry-specific config.xml', function() {
-                var www_cfg = fs.readFileSync(path.join(project_path, 'www', 'config.xml'), 'utf-8');
-                parser.update_www();
-                var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
-                expect(bb_cfg).not.toBe(www_cfg);
-            });
-        });
-
-        describe('update_overrides method',function() {
-            var mergesPath = path.join(project_path, 'merges', 'blackberry');
-            var newFile = path.join(mergesPath, 'merge.js');
-            beforeEach(function() {
-                shell.mkdir('-p', mergesPath);
-                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
-            });
-            afterEach(function() {
-                shell.rm('-rf', mergesPath);
-            });
-
-            it('should copy a new file from merges into www', function() {
-                parser.update_overrides();
-                expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
-            });
-
-            it('should copy a file from merges over a file in www', function() {
-                var newFileWWW = path.join(project_path, 'www','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(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
-                expect(fs.readFileSync(path.join(blackberry_project_path, 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
-            });
-        });
-
-        describe('update_project method', function() {
-            var cordova_config_path = path.join(project_path, '.cordova', 'config.json');
-            var original_config_json = fs.readFileSync(cordova_config_path, 'utf-8');
-
-            describe('with stubbed out config for BlackBerry SDKs', function() {
-                beforeEach(function() {
-                    fs.writeFileSync(cordova_config_path, JSON.stringify({
-                        blackberry:{
-                            qnx:{
-                            }
-                        }
-                    }), 'utf-8');
-                });
-                afterEach(function() {
-                    fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
-                });
-                it('should invoke update_www', function() {
-                    var spyWww = spyOn(parser, 'update_www');
-                    parser.update_project(config);
-                    expect(spyWww).toHaveBeenCalled();
-                });
-                it('should invoke update_from_config', function() {
-                    var spyConfig = spyOn(parser, 'update_from_config');
-                    parser.update_project(config);
-                    expect(spyConfig).toHaveBeenCalled();
-                });
-                it('should not invoke get_blackberry_environment', function() {
-                    var spyEnv = spyOn(parser, 'get_blackberry_environment');
-                    parser.update_project(config);
-                    expect(spyEnv).not.toHaveBeenCalled();
-                });
-                it('should write out project properties', function(done) {
-                    var spyProps = spyOn(parser, 'write_project_properties');
-                    parser.update_project(config, function() { 
-                        expect(spyProps).toHaveBeenCalled();
-                        done();
-                    });
-                });
-                it('should call out to util.deleteSvnFolders', function(done) {
-                    var spy = spyOn(util, 'deleteSvnFolders');
-                    parser.update_project(config, function() {
-                        expect(spy).toHaveBeenCalled();
-                        done();
-                    });
-                });
-            });
-            describe('with empty BlackBerry SDKs in config', function() {
-                afterEach(function() {
-                    fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
-                });
-                it('should invoke get_blackberry_environment', function() {
-                    var spyEnv = spyOn(parser, 'get_blackberry_environment');
-                    var promptSpy = spyOn(require('prompt'), 'get');
-                    parser.update_project(config);
-                    expect(spyEnv).toHaveBeenCalled();
-                });
-                it('should write out project properties', function(done) {
-                    var spyProps = spyOn(parser, 'write_project_properties');
-                    var promptSpy = spyOn(require('prompt'), 'get');
-                    parser.update_project(config, function() {
-                        expect(spyProps).toHaveBeenCalled();
-                        done();
-                    });
-                    promptSpy.mostRecentCall.args[1](null, {});
-                });
-            });
-        });
-    });
-
-    describe('write_project_properties method', function() {
-    });
-
-    describe('get_blackberry_environment method', function() {
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/ios_parser.spec.js b/spec/metadata/ios_parser.spec.js
deleted file mode 100644
index dbd4816..0000000
--- a/spec/metadata/ios_parser.spec.js
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- 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.
- */
-
-var ios_parser = require('../../src/metadata/ios_parser'),
-    config_parser = require('../../src/config_parser'),
-    cordova = require('../../cordova'),
-    util = require('../../src/util'),
-    path = require('path'),
-    shell = require('shelljs'),
-    fs = require('fs'),
-    et = require('elementtree'),
-    projects_path = path.join(__dirname, '..', 'fixtures', 'projects')
-ios_path = path.join(projects_path, 'native', 'ios_fixture'),
-    project_path = path.join(projects_path, 'cordova'),
-    ios_project_path = path.join(project_path, 'platforms', 'ios');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('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);
-        });
-        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');
-        });
-        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 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();
-            });
-        });
-        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/);
-                done();
-            });
-        });
-        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="\*" \/>/);
-                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');
-                    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');
-                    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);
-        });
-        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('update_www method', function () {
-            it('should update all www assets', function () {
-                var newFile = path.join(project_path, 'www', '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);
-            });
-            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.ios.js'), 'utf-8'));
-            });
-        });
-
-        describe('update_overrides method', function () {
-            var mergesPath = path.join(project_path, 'merges', 'ios');
-            var newFile = path.join(mergesPath, 'merge.js');
-            beforeEach(function() {
-                shell.mkdir('-p', mergesPath);
-                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
-            });
-            afterEach(function() {
-                shell.rm('-rf', mergesPath);
-            });
-
-            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 a file from merges over a file in www', function () {
-                var newFileWWW = path.join(project_path, 'www', '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_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();
-                });
-            });
-            it('should invoke update_from_config', function (done) {
-                var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
-                parser.update_project(config, function () {
-                    expect(spyConfig).toHaveBeenCalled();
-                    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();
-                    done();
-                });
-            });
-        });
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/android/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/android/android_parser.spec.js b/spec/platform-script/android/android_parser.spec.js
new file mode 100644
index 0000000..d051c6f
--- /dev/null
+++ b/spec/platform-script/android/android_parser.spec.js
@@ -0,0 +1,220 @@
+
+/**
+    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.
+*/
+var android_parser = require('../../src/metadata/android_parser'),
+    config_parser = require('../../src/config_parser'),
+    util = require('../../src/util'),
+    path = require('path'),
+    shell = require('shelljs'),
+    fs = require('fs'),
+    et = require('elementtree'),
+    cordova = require('../../cordova'),
+    projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+    android_path = path.join(projects_path, 'native', 'android_fixture'),
+    project_path = path.join(projects_path, 'cordova'),
+    android_project_path = path.join(project_path, 'platforms', 'android');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('android project parser', function() {
+    it('should throw an exception with a path that is not a native android project', function() {
+        expect(function() {
+            var project = new android_parser(process.cwd());
+        }).toThrow();
+    });
+    it('should accept a proper native android project path as construction parameter', function() {
+        expect(function() {
+            var project = new android_parser(android_path);
+            expect(project).toBeDefined();
+        }).not.toThrow();
+    });
+
+    describe('update_from_config method', function() {
+        var project, config;
+        
+        var android_strings = path.join(android_path, 'res', 'values', 'strings.xml');
+        var android_manifest = path.join(android_path, 'AndroidManifest.xml');
+        var android_config = path.join(android_path, 'res', 'xml', 'config.xml');
+
+        var original_strings = fs.readFileSync(android_strings, 'utf-8');
+        var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
+        var original_android_config = fs.readFileSync(android_config, 'utf-8');
+
+        beforeEach(function() {
+            project = new android_parser(android_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+            fs.writeFileSync(android_strings, original_strings, 'utf-8');
+            fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
+            fs.writeFileSync(www_config, original_www_config, 'utf-8');
+            fs.writeFileSync(android_config, original_android_config, 'utf-8');
+        });
+        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 update the application name properly', function() {
+            config.name('bond. james bond.');
+            project.update_from_config(config);
+
+            var strings = new et.ElementTree(et.XML(fs.readFileSync(android_strings, 'utf-8')));
+            var app_name = strings.find('string[@name="app_name"]').text;
+
+            expect(app_name).toBe('bond. james bond.');
+        });
+        it('should update the application package name properly', function() {
+            var javs = path.join(android_path, 'src', 'ca', 'filmaj', 'dewd', 'cordovaExample.java');
+            var orig_javs = path.join(android_path, 'src', 'org', 'apache', 'cordova', 'cordovaExample', 'cordovaExample.java');
+            var orig_contents = fs.readFileSync(orig_javs, 'utf-8');
+            this.after(function() {
+                fs.writeFileSync(orig_javs, orig_contents, 'utf-8');
+                shell.rm('-rf', path.join(android_path, 'src', 'ca'));
+            });
+            config.packageName('ca.filmaj.dewd');
+            project.update_from_config(config);
+
+            var manifest = new et.ElementTree(et.XML(fs.readFileSync(android_manifest, 'utf-8')));
+            expect(manifest.getroot().attrib.package).toEqual('ca.filmaj.dewd');
+
+            expect(fs.existsSync(javs)).toBe(true);
+            expect(fs.readFileSync(javs, 'utf-8')).toMatch(/package ca.filmaj.dewd/i);
+        });
+        it('should update the whitelist properly', function() {
+            config.access.remove('*');
+            config.access.add('http://apache.org');
+            config.access.add('http://github.com');
+            project.update_from_config(config);
+
+            var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+            var as = native_config.findall('access');
+            expect(as.length).toEqual(2);
+            expect(as[0].attrib.origin).toEqual('http://apache.org');
+            expect(as[1].attrib.origin).toEqual('http://github.com');
+        });
+        describe('preferences', function() {
+            it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
+                config.preference.add({name:'henrik',value:'sedin'});
+                project.update_from_config(config);
+
+                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+                var ps = native_config.findall('preference');
+                expect(ps.length).toEqual(7);
+                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+                expect(ps[0].attrib.value).toEqual('true');
+                expect(ps[6].attrib.name).toEqual('henrik');
+                expect(ps[6].attrib.value).toEqual('sedin');
+            });
+            it('should override a default project preference if applicable', function() {
+                config.preference.add({name:'useBrowserHistory',value:'false'});
+                project.update_from_config(config);
+
+                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+                var ps = native_config.findall('preference');
+                expect(ps.length).toEqual(6);
+                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+                expect(ps[0].attrib.value).toEqual('false');
+            });
+        });
+    });
+
+    describe('cross-platform project level methods', function() {
+        var parser, config;
+        var android_strings = path.join(android_project_path, 'res', 'values', 'strings.xml');
+        var android_manifest = path.join(android_project_path, 'AndroidManifest.xml');
+        var android_config = path.join(android_project_path, 'res', 'xml', 'config.xml');
+
+        var original_strings = fs.readFileSync(android_strings, 'utf-8');
+        var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
+        var original_android_config = fs.readFileSync(android_config, 'utf-8');
+
+        beforeEach(function() {
+            parser = new android_parser(android_project_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+            fs.writeFileSync(android_strings, original_strings, 'utf-8');
+            fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
+            fs.writeFileSync(www_config, original_www_config, 'utf-8');
+            fs.writeFileSync(android_config, original_android_config, 'utf-8');
+        });
+        describe('update_www method', function() {
+            it('should update all www assets', function() {
+                var newFile = path.join(project_path, 'www', 'somescript.js');
+                this.after(function() {
+                    shell.rm('-f', newFile);
+                });
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+                parser.update_www();
+                expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'somescript.js'))).toBe(true);
+            });
+            it('should write out android js to cordova.js', function() {
+                parser.update_www();
+                expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'cordova.js'),'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'js', 'cordova.android.js'), 'utf-8'));
+            });
+        });
+
+        describe('update_overrides method',function() {
+            var mergesPath = path.join(project_path, 'merges', 'android');
+            var newFile = path.join(mergesPath, 'merge.js');
+            beforeEach(function() {
+                shell.mkdir('-p', mergesPath);
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+            });
+            afterEach(function() {
+                shell.rm('-rf', mergesPath);
+            });
+            it('should copy a new file from merges into www', function() {
+                parser.update_overrides();
+                expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+            });
+
+            it('should copy a file from merges over a file in www', function() {
+                var newFileWWW = path.join(project_path, 'www','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(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+                expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+            });
+        });
+
+        describe('update_project method', function() {
+            it('should invoke update_www', function() {
+                var spyWww = spyOn(parser, 'update_www');
+                parser.update_project(config);
+                expect(spyWww).toHaveBeenCalled();
+            });
+            it('should invoke update_from_config', function() {
+                var spyConfig = spyOn(parser, 'update_from_config');
+                parser.update_project(config);
+                expect(spyConfig).toHaveBeenCalled();
+            });
+            it('should call out to util.deleteSvnFolders', function() {
+                var spy = spyOn(util, 'deleteSvnFolders');
+                parser.update_project(config);
+                expect(spy).toHaveBeenCalled();
+            });
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/blackberry/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/blackberry/blackberry_parser.spec.js b/spec/platform-script/blackberry/blackberry_parser.spec.js
new file mode 100644
index 0000000..12d5294
--- /dev/null
+++ b/spec/platform-script/blackberry/blackberry_parser.spec.js
@@ -0,0 +1,249 @@
+
+/**
+    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.
+*/
+var blackberry_parser = require('../../src/metadata/blackberry_parser'),
+    config_parser = require('../../src/config_parser'),
+    path = require('path'),
+    util = require('../../src/util'),
+    et = require('elementtree'),
+    shell = require('shelljs'),
+    cordova = require('../../cordova'),
+    fs = require('fs'),
+    projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+    blackberry_path = path.join(projects_path, 'native', 'blackberry_fixture'),
+    project_path = path.join(projects_path, 'cordova'),
+    blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('blackberry project parser', function() {
+    beforeEach(function() {
+        spyOn(process.stdout, 'write'); // silence console output
+    });
+
+    it('should throw an exception with a path that is not a native blackberry project', function() {
+        expect(function() {
+            var project = new blackberry_parser(process.cwd());
+        }).toThrow();
+    });
+    it('should accept a proper native blackberry project path as construction parameter', function() {
+        var project;
+        expect(function() {
+            project = new blackberry_parser(blackberry_path);
+        }).not.toThrow();
+        expect(project).toBeDefined();
+    });
+
+    describe('update_from_config method', function() {
+        var project, config;
+
+        var blackberry_config = path.join(blackberry_path, 'www', 'config.xml');
+        var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
+
+        beforeEach(function() {
+            project = new blackberry_parser(blackberry_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+            fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
+            fs.writeFileSync(www_config, original_www_config, 'utf-8');
+        });
+        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 update the application name properly', function() {
+            config.name('bond. james bond.');
+            project.update_from_config(config);
+
+            var bb_cfg = new config_parser(blackberry_config);
+
+            expect(bb_cfg.name()).toBe('bond. james bond.');
+        });
+        it('should update the application package name properly', function() {
+            config.packageName('sofa.king.awesome');
+            project.update_from_config(config);
+
+            var bb_cfg = new config_parser(blackberry_config);
+            expect(bb_cfg.packageName()).toBe('sofa.king.awesome');
+        });
+        describe('whitelist', function() {
+            it('should update the whitelist when using access elements with origin attribute', function() {
+                config.access.remove('*');
+                config.access.add('http://blackberry.com');
+                config.access.add('http://rim.com');
+                project.update_from_config(config);
+
+                var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
+                var as = bb_cfg.getroot().findall('access');
+                expect(as.length).toEqual(2);
+                expect(as[0].attrib.uri).toEqual('http://blackberry.com');
+                expect(as[1].attrib.uri).toEqual('http://rim.com');
+            });
+            it('should update the whitelist when using access elements with uri attributes', function() {
+                fs.writeFileSync(www_config, fs.readFileSync(www_config, 'utf-8').replace(/origin="\*/,'uri="http://rim.com'), 'utf-8');
+                config = new config_parser(www_config);
+                project.update_from_config(config);
+
+                var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
+                var as = bb_cfg.getroot().findall('access');
+                expect(as.length).toEqual(1);
+                expect(as[0].attrib.uri).toEqual('http://rim.com');
+            });
+        });
+    });
+
+    describe('cross-platform project level methods', function() {
+        var parser, config;
+
+        var blackberry_config = path.join(blackberry_project_path, 'www', 'config.xml');
+        var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
+
+        beforeEach(function() {
+            parser = new blackberry_parser(blackberry_project_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+            fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
+            fs.writeFileSync(www_config, original_www_config, 'utf-8');
+        });
+
+        describe('update_www method', function() {
+            it('should update all www assets', function() {
+                var newFile = path.join(project_path, 'www', 'somescript.js');
+                this.after(function() {
+                    shell.rm('-f', newFile);
+                });
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+                parser.update_www();
+                expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'somescript.js'))).toBe(true);
+            });
+            it('should not overwrite the blackberry-specific config.xml', function() {
+                var www_cfg = fs.readFileSync(path.join(project_path, 'www', 'config.xml'), 'utf-8');
+                parser.update_www();
+                var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
+                expect(bb_cfg).not.toBe(www_cfg);
+            });
+        });
+
+        describe('update_overrides method',function() {
+            var mergesPath = path.join(project_path, 'merges', 'blackberry');
+            var newFile = path.join(mergesPath, 'merge.js');
+            beforeEach(function() {
+                shell.mkdir('-p', mergesPath);
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+            });
+            afterEach(function() {
+                shell.rm('-rf', mergesPath);
+            });
+
+            it('should copy a new file from merges into www', function() {
+                parser.update_overrides();
+                expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
+            });
+
+            it('should copy a file from merges over a file in www', function() {
+                var newFileWWW = path.join(project_path, 'www','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(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
+                expect(fs.readFileSync(path.join(blackberry_project_path, 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+            });
+        });
+
+        describe('update_project method', function() {
+            var cordova_config_path = path.join(project_path, '.cordova', 'config.json');
+            var original_config_json = fs.readFileSync(cordova_config_path, 'utf-8');
+
+            describe('with stubbed out config for BlackBerry SDKs', function() {
+                beforeEach(function() {
+                    fs.writeFileSync(cordova_config_path, JSON.stringify({
+                        blackberry:{
+                            qnx:{
+                            }
+                        }
+                    }), 'utf-8');
+                });
+                afterEach(function() {
+                    fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
+                });
+                it('should invoke update_www', function() {
+                    var spyWww = spyOn(parser, 'update_www');
+                    parser.update_project(config);
+                    expect(spyWww).toHaveBeenCalled();
+                });
+                it('should invoke update_from_config', function() {
+                    var spyConfig = spyOn(parser, 'update_from_config');
+                    parser.update_project(config);
+                    expect(spyConfig).toHaveBeenCalled();
+                });
+                it('should not invoke get_blackberry_environment', function() {
+                    var spyEnv = spyOn(parser, 'get_blackberry_environment');
+                    parser.update_project(config);
+                    expect(spyEnv).not.toHaveBeenCalled();
+                });
+                it('should write out project properties', function(done) {
+                    var spyProps = spyOn(parser, 'write_project_properties');
+                    parser.update_project(config, function() { 
+                        expect(spyProps).toHaveBeenCalled();
+                        done();
+                    });
+                });
+                it('should call out to util.deleteSvnFolders', function(done) {
+                    var spy = spyOn(util, 'deleteSvnFolders');
+                    parser.update_project(config, function() {
+                        expect(spy).toHaveBeenCalled();
+                        done();
+                    });
+                });
+            });
+            describe('with empty BlackBerry SDKs in config', function() {
+                afterEach(function() {
+                    fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
+                });
+                it('should invoke get_blackberry_environment', function() {
+                    var spyEnv = spyOn(parser, 'get_blackberry_environment');
+                    var promptSpy = spyOn(require('prompt'), 'get');
+                    parser.update_project(config);
+                    expect(spyEnv).toHaveBeenCalled();
+                });
+                it('should write out project properties', function(done) {
+                    var spyProps = spyOn(parser, 'write_project_properties');
+                    var promptSpy = spyOn(require('prompt'), 'get');
+                    parser.update_project(config, function() {
+                        expect(spyProps).toHaveBeenCalled();
+                        done();
+                    });
+                    promptSpy.mostRecentCall.args[1](null, {});
+                });
+            });
+        });
+    });
+
+    describe('write_project_properties method', function() {
+    });
+
+    describe('get_blackberry_environment method', function() {
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/ios/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/ios/ios_parser.spec.js b/spec/platform-script/ios/ios_parser.spec.js
new file mode 100644
index 0000000..dbd4816
--- /dev/null
+++ b/spec/platform-script/ios/ios_parser.spec.js
@@ -0,0 +1,218 @@
+/**
+ 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.
+ */
+
+var ios_parser = require('../../src/metadata/ios_parser'),
+    config_parser = require('../../src/config_parser'),
+    cordova = require('../../cordova'),
+    util = require('../../src/util'),
+    path = require('path'),
+    shell = require('shelljs'),
+    fs = require('fs'),
+    et = require('elementtree'),
+    projects_path = path.join(__dirname, '..', 'fixtures', 'projects')
+ios_path = path.join(projects_path, 'native', 'ios_fixture'),
+    project_path = path.join(projects_path, 'cordova'),
+    ios_project_path = path.join(project_path, 'platforms', 'ios');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('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);
+        });
+        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');
+        });
+        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 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();
+            });
+        });
+        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/);
+                done();
+            });
+        });
+        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="\*" \/>/);
+                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');
+                    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');
+                    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);
+        });
+        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('update_www method', function () {
+            it('should update all www assets', function () {
+                var newFile = path.join(project_path, 'www', '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);
+            });
+            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.ios.js'), 'utf-8'));
+            });
+        });
+
+        describe('update_overrides method', function () {
+            var mergesPath = path.join(project_path, 'merges', 'ios');
+            var newFile = path.join(mergesPath, 'merge.js');
+            beforeEach(function() {
+                shell.mkdir('-p', mergesPath);
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+            });
+            afterEach(function() {
+                shell.rm('-rf', mergesPath);
+            });
+
+            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 a file from merges over a file in www', function () {
+                var newFileWWW = path.join(project_path, 'www', '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_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();
+                });
+            });
+            it('should invoke update_from_config', function (done) {
+                var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
+                parser.update_project(config, function () {
+                    expect(spyConfig).toHaveBeenCalled();
+                    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();
+                    done();
+                });
+            });
+        });
+    });
+});