CB-10769 Copy raw pluginHandler tests from cordova-lib Update tests structure and npm tasks Copying related fixtures from cordova-lib
Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/c0db5e4e Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/c0db5e4e Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/c0db5e4e Branch: refs/heads/4.1.x Commit: c0db5e4ecfb4e2afa31fdb277620cc4ebcf7d7f3 Parents: 70e16ef Author: Vladimir Kotikov <[email protected]> Authored: Thu Mar 3 17:06:19 2016 +0300 Committer: Vladimir Kotikov <[email protected]> Committed: Fri Mar 11 10:12:15 2016 +0300 ---------------------------------------------------------------------- .gitignore | 1 + .jshintignore | 1 + package.json | 7 +- tests/spec/unit/Plugman/common.spec.js | 195 ++++++ tests/spec/unit/Plugman/ios.spec.js | 447 +++++++++++++ .../CordovaLib.xcodeproj/project.pbxproj | 636 +++++++++++++++++++ .../fixtures/ios-config-xml/CordovaLib/VERSION | 1 + .../SampleApp.xcodeproj/project.orig.pbxproj | 498 +++++++++++++++ .../SampleApp.xcodeproj/project.pbxproj | 496 +++++++++++++++ .../SampleApp/SampleApp-Info.plist | 86 +++ .../ios-config-xml/SampleApp/config.xml | 59 ++ .../unit/fixtures/ios-config-xml/www/.gitkeep | 0 .../org.test.plugins.dummyplugin/plugin.xml | 66 ++ .../src/ios/Custom.framework/someFheader.h | 1 + .../src/ios/Custom.framework/somebinlib | 1 + .../src/ios/DummyPlugin.bundle | 1 + .../src/ios/DummyPluginCommand.h | 1 + .../src/ios/DummyPluginCommand.m | 1 + .../src/ios/SourceWithFramework.m | 1 + .../src/ios/TargetDirTest.h | 1 + .../src/ios/TargetDirTest.m | 1 + .../src/ios/libsqlite3.dylib | 1 + .../www/dummyplugin.js | 1 + .../www/dummyplugin/image.jpg | 1 + .../org.test.plugins.faultyplugin/plugin.xml | 55 ++ .../src/ios/FaultyPlugin.h | 1 + .../src/ios/FaultyPlugin.m | 1 + .../org.test.plugins.weblessplugin/plugin.xml | 54 ++ .../src/ios/WeblessPlugin.bundle/arrow_left.png | 1 + .../ios/WeblessPlugin.bundle/[email protected] | 1 + .../ios/WeblessPlugin.bundle/arrow_right.png | 1 + .../ios/WeblessPlugin.bundle/[email protected] | 1 + .../ios/WeblessPlugin.bundle/but_refresh.png | 1 + .../ios/WeblessPlugin.bundle/[email protected] | 1 + .../src/ios/WeblessPlugin.bundle/compass.png | 1 + .../src/ios/WeblessPlugin.bundle/[email protected] | 1 + .../src/ios/WeblessPluginCommand.h | 1 + .../src/ios/WeblessPluginCommand.m | 1 + .../src/ios/WeblessPluginViewController.h | 1 + .../src/ios/WeblessPluginViewController.m | 1 + .../src/ios/WeblessPluginViewController.xib | 1 + tests/spec/unit/fixtures/test-config-2.xml | 22 + tests/spec/unit/fixtures/test-config.xml | 109 ++++ tests/spec/unit/ios_parser.spec.js | 500 +++++++++++++++ 44 files changed, 3256 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/c0db5e4e/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index aff5891..2744ab7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ tmp xcuserdata console.log node_modules/ +npm-debug.log \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/c0db5e4e/.jshintignore ---------------------------------------------------------------------- diff --git a/.jshintignore b/.jshintignore index e87aa4b..1ec4bc1 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,2 +1,3 @@ bin/node_modules/* bin/templates/project/* +tests/spec/unit/fixtures/* \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/c0db5e4e/package.json ---------------------------------------------------------------------- diff --git a/package.json b/package.json index 447a38e..5f05f17 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ "cordova:platform" ], "scripts": { - "test": "npm run jshint && npm run jasmine", - "jasmine": "npm run objc-tests && npm run jasmine-tests", + "test": "npm run jshint && npm run e2e-tests && npm run objc-tests && npm run unit-tests", + "e2e-tests": "jasmine-node --captureExceptions --color tests/spec/create.spec.js", "objc-tests": "jasmine-node --captureExceptions --color tests/spec/cordovalib.spec.js", - "jasmine-tests": "jasmine-node --captureExceptions --color tests/spec/create.spec.js", + "unit-tests": "jasmine-node --captureExceptions --color tests/spec/unit", "jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint tests" }, "author": "Apache Software Foundation", @@ -29,6 +29,7 @@ "tmp": "^0.0.26", "jasmine-node": "~1", "coffee-script": "^1.7.1", + "rewire": "^2.5.1", "nodeunit": "^0.8.7" }, "dependencies": { http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/c0db5e4e/tests/spec/unit/Plugman/common.spec.js ---------------------------------------------------------------------- diff --git a/tests/spec/unit/Plugman/common.spec.js b/tests/spec/unit/Plugman/common.spec.js new file mode 100644 index 0000000..f591193 --- /dev/null +++ b/tests/spec/unit/Plugman/common.spec.js @@ -0,0 +1,195 @@ +/* + * + * + * Licensed 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. + * +*/ + +/* jshint laxcomma:true */ + +var common = require('../../src/plugman/platforms/common') + , path = require('path') + , fs = require('fs') + , osenv = require('os') + , shell = require('shelljs') + , test_dir = path.join(osenv.tmpdir(), 'test_plugman') + , project_dir = path.join(test_dir, 'project') + , src = path.join(project_dir, 'src') + , dest = path.join(project_dir, 'dest') + , java_dir = path.join(src, 'one', 'two', 'three') + , java_file = path.join(java_dir, 'test.java') + , symlink_file = path.join(java_dir, 'symlink') + , non_plugin_file = path.join(osenv.tmpdir(), 'non_plugin_file'); + +describe('common platform handler', function() { + describe('resolveSrcPath', function() { + it('should not throw if path exists', function(){ + shell.mkdir('-p', test_dir); + var target = path.join(test_dir, 'somefile'); + fs.writeFileSync(target, '80085', 'utf-8'); + expect(function(){common.resolveSrcPath(test_dir, 'somefile');}).not.toThrow(); + shell.rm('-rf', test_dir); + }); + }); + + describe('resolveTargetPath', function() { + it('should throw if path exists', function(){ + shell.mkdir('-p', test_dir); + expect(function(){common.resolveTargetPath(test_dir);}).toThrow(); + shell.rm('-rf', test_dir); + }); + + it('should not throw if path cannot be resolved', function(){ + expect(function(){common.resolveTargetPath(test_dir, 'somefile');}).not.toThrow(); + }); + }); + + describe('copyFile', function() { + it('should throw if source path not found', function(){ + expect(function(){common.copyFile(test_dir, src, project_dir, dest);}). + toThrow(new Error('"' + src + '" not found!')); + }); + + it('should throw if src not in plugin directory', function(){ + shell.mkdir('-p', project_dir); + fs.writeFileSync(non_plugin_file, 'contents', 'utf-8'); + expect(function(){common.copyFile(test_dir, '../non_plugin_file', project_dir, dest);}). + toThrow(new Error('"' + non_plugin_file + '" not located within plugin!')); + shell.rm('-rf', test_dir); + }); + + it('should allow symlink src, if inside plugin', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + // This will fail on windows if not admin - ignore the error in that case. + if (ignoreEPERMonWin32(java_file, symlink_file)) { + return; + } + + common.copyFile(test_dir, symlink_file, project_dir, dest); + shell.rm('-rf', project_dir); + }); + + it('should throw if symlink is linked to a file outside the plugin', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(non_plugin_file, 'contents', 'utf-8'); + + // This will fail on windows if not admin - ignore the error in that case. + if (ignoreEPERMonWin32(non_plugin_file, symlink_file)) { + return; + } + + expect(function(){common.copyFile(test_dir, symlink_file, project_dir, dest);}). + toThrow(new Error('"' + symlink_file + '" not located within plugin!')); + shell.rm('-rf', project_dir); + }); + + it('should throw if dest is outside the project directory', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + expect(function(){common.copyFile(test_dir, java_file, project_dir, non_plugin_file);}). + toThrow(new Error('"' + non_plugin_file + '" not located within project!')); + shell.rm('-rf', project_dir); + }); + + it('should call mkdir -p on target path', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + var s = spyOn(shell, 'mkdir').andCallThrough(); + var resolvedDest = common.resolveTargetPath(project_dir, dest); + + common.copyFile(test_dir, java_file, project_dir, dest); + + expect(s).toHaveBeenCalled(); + expect(s).toHaveBeenCalledWith('-p', path.dirname(resolvedDest)); + shell.rm('-rf', project_dir); + }); + + it('should call cp source/dest paths', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + var s = spyOn(shell, 'cp').andCallThrough(); + var resolvedDest = common.resolveTargetPath(project_dir, dest); + + common.copyFile(test_dir, java_file, project_dir, dest); + + expect(s).toHaveBeenCalled(); + expect(s).toHaveBeenCalledWith('-f', java_file, resolvedDest); + + shell.rm('-rf', project_dir); + }); + + }); + + describe('copyNewFile', function () { + it('should throw if target path exists', function(){ + shell.mkdir('-p', dest); + expect(function(){common.copyNewFile(test_dir, src, project_dir, dest);}). + toThrow(new Error('"' + dest + '" already exists!')); + shell.rm('-rf', dest); + }); + + }); + + describe('deleteJava', function() { + it('should call fs.unlinkSync on the provided paths', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + var s = spyOn(fs, 'unlinkSync').andCallThrough(); + common.deleteJava(project_dir, java_file); + expect(s).toHaveBeenCalled(); + expect(s).toHaveBeenCalledWith(path.resolve(project_dir, java_file)); + + shell.rm('-rf', java_dir); + }); + + it('should delete empty directories after removing source code in a java src path hierarchy', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + common.deleteJava(project_dir, java_file); + expect(fs.existsSync(java_file)).not.toBe(true); + expect(fs.existsSync(java_dir)).not.toBe(true); + expect(fs.existsSync(path.join(src,'one'))).not.toBe(true); + + shell.rm('-rf', java_dir); + }); + + it('should never delete the top-level src directory, even if all plugins added were removed', function(){ + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + + common.deleteJava(project_dir, java_file); + expect(fs.existsSync(src)).toBe(true); + + shell.rm('-rf', java_dir); + }); + }); +}); + +function ignoreEPERMonWin32(symlink_src, symlink_dest) { + try { + fs.symlinkSync(symlink_src, symlink_dest); + } catch (e) { + if (process.platform === 'win32' && e.message.indexOf('Error: EPERM, operation not permitted' > -1)) { + return true; + } + throw e; + } + return false; +} http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/c0db5e4e/tests/spec/unit/Plugman/ios.spec.js ---------------------------------------------------------------------- diff --git a/tests/spec/unit/Plugman/ios.spec.js b/tests/spec/unit/Plugman/ios.spec.js new file mode 100644 index 0000000..7c245bd --- /dev/null +++ b/tests/spec/unit/Plugman/ios.spec.js @@ -0,0 +1,447 @@ +/** + 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. +*/ + +/* jshint sub:true */ + +var ios = require('../../src/plugman/platforms/ios'), + install = require('../../src/plugman/install'), + path = require('path'), + fs = require('fs'), + shell = require('shelljs'), + os = require('os'), + temp = path.join(os.tmpdir(), 'plugman'), + plugins_dir = path.join(temp, 'cordova', 'plugins'), + ios_config_xml_project = path.join(__dirname, '..', 'projects', 'ios-config-xml', '*'), + ios_project = path.join(ios_config_xml_project, '..'), + faultyplugin = path.join(__dirname, '..', 'plugins', 'org.test.plugins.faultyplugin'), + dummyplugin = path.join(__dirname, '..', 'plugins', 'org.test.plugins.dummyplugin'), + weblessplugin = path.join(__dirname, '..', 'plugins', 'org.test.plugins.weblessplugin'), + done = false; + +var PluginInfo = require('cordova-common').PluginInfo; + +var dummyPluginInfo = new PluginInfo(dummyplugin); +var dummy_id = dummyPluginInfo.id; +var valid_source = dummyPluginInfo.getSourceFiles('ios'), + valid_headers = dummyPluginInfo.getHeaderFiles('ios'), + valid_resources = dummyPluginInfo.getResourceFiles('ios'), + valid_custom_frameworks = dummyPluginInfo.getFrameworks('ios').filter(function(f) { return f.custom; }); + +var faultyPluginInfo = new PluginInfo(faultyplugin); +var faulty_id = faultyPluginInfo.id; + +var invalid_source = faultyPluginInfo.getSourceFiles('ios'); +var invalid_headers = faultyPluginInfo.getHeaderFiles('ios'); +var invalid_resources = faultyPluginInfo.getResourceFiles('ios'); +var invalid_custom_frameworks = faultyPluginInfo.getFrameworks('ios').filter(function(f) { return f.custom; }); + +shell.mkdir('-p', temp); +shell.cp('-rf', ios_config_xml_project, temp); +var proj_files = ios.parseProjectFile(temp); +shell.rm('-rf', temp); +ios.purgeProjectFileCache(temp); + +function copyArray(arr) { + return Array.prototype.slice.call(arr, 0); +} + +function installPromise(f) { + f.then(function(res) { done = true; }, function(err) { done = err; }); +} + +function slashJoin() { + // In some places we need to use forward slash instead of path.join(). + // See CB-7311. + return Array.prototype.join.call(arguments, '/'); +} + +describe('ios project handler', function() { + beforeEach(function() { + shell.mkdir('-p', temp); + shell.mkdir('-p', plugins_dir); + }); + afterEach(function() { + shell.rm('-rf', temp); + ios.purgeProjectFileCache(temp); + }); + + describe('www_dir method', function() { + it('should return cordova-ios project www location using www_dir', function() { + expect(ios.www_dir(path.sep)).toEqual(path.sep + 'www'); + }); + }); + + describe('package_name method', function() { + it('should return the CFBundleIdentifier from the project\'s Info.plist file', function() { + expect(ios.package_name(ios_project)).toEqual('com.example.friendstring'); + }); + }); + + describe('parseProjectFile method', function () { + it('should throw if project is not an xcode project', function() { + expect(function() { + ios.parseProjectFile(temp); + }).toThrow('does not appear to be an xcode project (no xcode project file)'); + }); + it('should throw if project does not contain an appropriate config.xml file', function() { + shell.cp('-rf', ios_config_xml_project, temp); + shell.rm(path.join(temp, 'SampleApp', 'config.xml')); + + expect(function() { + ios.parseProjectFile(temp); + }).toThrow('could not find -Info.plist file, or config.xml file.'); + }); + it('should throw if project does not contain an appropriate -Info.plist file', function() { + shell.cp('-rf', ios_config_xml_project, temp); + shell.rm(path.join(temp, 'SampleApp', 'SampleApp-Info.plist')); + + expect(function () { + ios.parseProjectFile(temp); + }).toThrow('could not find -Info.plist file, or config.xml file.'); + }); + it('should return right directory when multiple .plist files are present', function() { + shell.cp('-rf', ios_config_xml_project, temp); + //Create a folder named A with config.xml and .plist files in it + var pathToFolderA = path.join(temp, 'A'); + shell.mkdir(pathToFolderA); + shell.cp('-rf', path.join(temp, 'SampleApp/*'), pathToFolderA); + + var parsedProjectFile = ios.parseProjectFile(temp); + var pluginsDir = parsedProjectFile.plugins_dir, + resourcesDir = parsedProjectFile.resources_dir, + xcodePath = parsedProjectFile.xcode_path; + + var pluginsDirParent = path.dirname(pluginsDir), + resourcesDirParent = path.dirname(resourcesDir), + sampleAppDir = path.join(temp, 'SampleApp'); + + expect(pluginsDirParent).toEqual(sampleAppDir); + expect(resourcesDirParent).toEqual(sampleAppDir); + expect(xcodePath).toEqual(sampleAppDir); + }); + }); + + describe('installation', function() { + beforeEach(function() { + shell.cp('-rf', ios_config_xml_project, temp); + done = false; + }); + + describe('of <source-file> elements', function() { + it('should throw if source-file src cannot be found', function() { + var source = copyArray(invalid_source); + expect(function() { + ios['source-file'].install(source[1], faultyplugin, temp, faulty_id, null, proj_files); + }).toThrow(); + }); + it('should throw if source-file target already exists', function() { + var source = copyArray(valid_source); + var target = path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'DummyPluginCommand.m'); + shell.mkdir('-p', path.dirname(target)); + fs.writeFileSync(target, 'some bs', 'utf-8'); + expect(function() { + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + }).toThrow(); + }); + it('should call into xcodeproj\'s addSourceFile appropriately when element has no target-dir', function() { + var source = copyArray(valid_source).filter(function(s) { return s.targetDir === undefined; }); + var spy = spyOn(proj_files.xcode, 'addSourceFile'); + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'DummyPluginCommand.m'), {}); + }); + it('should call into xcodeproj\'s addSourceFile appropriately when element has a target-dir', function() { + var source = copyArray(valid_source).filter(function(s) { return s.targetDir !== undefined; }); + var spy = spyOn(proj_files.xcode, 'addSourceFile'); + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'targetDir', 'TargetDirTest.m'), {}); + }); + it('should cp the file to the right target location when element has no target-dir', function() { + var source = copyArray(valid_source).filter(function(s) { return s.targetDir === undefined; }); + var spy = spyOn(shell, 'cp'); + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-f', path.join(dummyplugin, 'src', 'ios', 'DummyPluginCommand.m'), path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'DummyPluginCommand.m')); + }); + it('should cp the file to the right target location when element has a target-dir', function() { + var source = copyArray(valid_source).filter(function(s) { return s.targetDir !== undefined; }); + var spy = spyOn(shell, 'cp'); + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-f', path.join(dummyplugin, 'src', 'ios', 'TargetDirTest.m'), path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'targetDir', 'TargetDirTest.m')); + }); + it('should call into xcodeproj\'s addFramework appropriately when element has framework=true set', function() { + var source = copyArray(valid_source).filter(function(s) { return s.framework; }); + spyOn(proj_files.xcode, 'addSourceFile'); + var spy = spyOn(proj_files.xcode, 'addFramework'); + ios['source-file'].install(source[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(path.join('SampleApp', 'Plugins', dummy_id, 'SourceWithFramework.m'), {weak:false}); + }); + }); + + describe('of <header-file> elements', function() { + it('should throw if header-file src cannot be found', function() { + var headers = copyArray(invalid_headers); + expect(function() { + ios['header-file'].install(headers[1], faultyplugin, temp, faulty_id, null, proj_files); + }).toThrow(); + }); + it('should throw if header-file target already exists', function() { + var headers = copyArray(valid_headers); + var target = path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'DummyPluginCommand.h'); + shell.mkdir('-p', path.dirname(target)); + fs.writeFileSync(target, 'some bs', 'utf-8'); + expect(function() { + ios['header-file'].install(headers[0], dummyplugin, temp, dummy_id, null, proj_files); + }).toThrow(); + }); + it('should call into xcodeproj\'s addHeaderFile appropriately when element has no target-dir', function() { + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir === undefined; }); + var spy = spyOn(proj_files.xcode, 'addHeaderFile'); + ios['header-file'].install(headers[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'DummyPluginCommand.h')); + }); + it('should call into xcodeproj\'s addHeaderFile appropriately when element a target-dir', function() { + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir !== undefined; }); + var spy = spyOn(proj_files.xcode, 'addHeaderFile'); + ios['header-file'].install(headers[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'targetDir', 'TargetDirTest.h')); + }); + it('should cp the file to the right target location when element has no target-dir', function() { + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir === undefined; }); + var spy = spyOn(shell, 'cp'); + ios['header-file'].install(headers[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-f', path.join(dummyplugin, 'src', 'ios', 'DummyPluginCommand.h'), path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'DummyPluginCommand.h')); + }); + it('should cp the file to the right target location when element has a target-dir', function() { + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir !== undefined; }); + var spy = spyOn(shell, 'cp'); + ios['header-file'].install(headers[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-f', path.join(dummyplugin, 'src', 'ios', 'TargetDirTest.h'), path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'targetDir', 'TargetDirTest.h')); + }); + }); + + describe('of <resource-file> elements', function() { + it('should throw if resource-file src cannot be found', function() { + var resources = copyArray(invalid_resources); + expect(function() { + ios['resource-file'].install(resources[0], faultyplugin, temp, 'pluginid', null, proj_files); + }).toThrow('cannot find "' + path.resolve(faultyplugin, 'src/ios/IDontExist.bundle') + '" ios <resource-file>'); + }); + it('should throw if resource-file target already exists', function() { + var resources = copyArray(valid_resources); + var target = path.join(temp, 'SampleApp', 'Resources', 'DummyPlugin.bundle'); + shell.mkdir('-p', path.dirname(target)); + fs.writeFileSync(target, 'some bs', 'utf-8'); + expect(function() { + ios['resource-file'].install(resources[0], dummyplugin, temp, 'pluginid',null, proj_files); + }).toThrow('target destination "' + target + '" already exists'); + }); + it('should call into xcodeproj\'s addResourceFile', function() { + var resources = copyArray(valid_resources); + var spy = spyOn(proj_files.xcode, 'addResourceFile'); + ios['resource-file'].install(resources[0], dummyplugin, temp, 'pluginid', null, proj_files); + expect(spy).toHaveBeenCalledWith(path.join('Resources', 'DummyPlugin.bundle')); + }); + it('should cp the file to the right target location', function() { + var resources = copyArray(valid_resources); + var spy = spyOn(shell, 'cp'); + ios['resource-file'].install(resources[0], dummyplugin, temp, 'pluginid', null, proj_files); + expect(spy).toHaveBeenCalledWith('-R', path.join(dummyplugin, 'src', 'ios', 'DummyPlugin.bundle'), path.join(temp, 'SampleApp', 'Resources')); + }); + }); + describe('of <framework> elements', function() { + + it('should call into xcodeproj\'s addFramework', function() { + var frameworks = copyArray(valid_custom_frameworks); + var spy = spyOn(proj_files.xcode, 'addFramework'); + ios['framework'].install(frameworks[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(path.normalize('SampleApp/Plugins/org.test.plugins.dummyplugin/Custom.framework'), {customFramework:true}); + }); + + // TODO: Add more tests to cover the cases: + // * framework with weak attribute + // * framework that shouldn't be added/removed + + describe('with custom="true" attribute', function () { + it('should throw if framework src cannot be found', function() { + var frameworks = copyArray(invalid_custom_frameworks); + expect(function() { + ios['framework'].install(frameworks[0], faultyplugin, temp, dummy_id, null, proj_files); + }).toThrow('cannot find "' + path.resolve(faultyplugin, 'src/ios/NonExistantCustomFramework.framework') + '" ios <framework>'); + }); + it('should throw if framework target already exists', function() { + var frameworks = copyArray(valid_custom_frameworks); + var target = path.join(temp, 'SampleApp/Plugins/org.test.plugins.dummyplugin/Custom.framework'); + shell.mkdir('-p', target); + expect(function() { + ios['framework'].install(frameworks[0], dummyplugin, temp, dummy_id, null, proj_files); + }).toThrow('target destination "' + target + '" already exists'); + }); + it('should cp the file to the right target location', function() { + var frameworks = copyArray(valid_custom_frameworks); + var spy = spyOn(shell, 'cp'); + ios['framework'].install(frameworks[0], dummyplugin, temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-R', path.join(dummyplugin, 'src', 'ios', 'Custom.framework'), + path.join(temp, 'SampleApp/Plugins/org.test.plugins.dummyplugin')); + }); + }); + }); + it('of two plugins should apply xcode file changes from both', function(){ + runs(function() { + installPromise( + install('ios', temp, dummyplugin) + .then(function () { install('ios', temp, weblessplugin); }) + ); + }); + waitsFor(function() { return done; }, 'install promise never resolved', 200); + runs(function() { + var xcode = ios.parseProjectFile(temp).xcode; + // from org.test.plugins.dummyplugin + expect(xcode.hasFile(slashJoin('Resources', 'DummyPlugin.bundle'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.dummyplugin', 'DummyPluginCommand.h'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.dummyplugin', 'DummyPluginCommand.m'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.dummyplugin','targetDir','TargetDirTest.h'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.dummyplugin','targetDir','TargetDirTest.m'))).toBe(true); + expect(xcode.hasFile('usr/lib/src/ios/libsqlite3.dylib')).toBe(true); + expect(xcode.hasFile(slashJoin('SampleApp','Plugins','org.test.plugins.dummyplugin','Custom.framework'))).toBe(true); + // from org.test.plugins.weblessplugin + expect(xcode.hasFile(slashJoin('Resources', 'WeblessPluginViewController.xib'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.weblessplugin','WeblessPluginCommand.h'))).toBe(true); + expect(xcode.hasFile(slashJoin('Plugins','org.test.plugins.weblessplugin','WeblessPluginCommand.m'))).toBe(true); + expect(xcode.hasFile('usr/lib/libsqlite3.dylib')).toBe(true); + }); + }); + }); + + describe('uninstallation', function() { + describe('of <source-file> elements', function() { + it('should call into xcodeproj\'s removeSourceFile appropriately when element has no target-dir', function(){ + var source = copyArray(valid_source).filter(function(s) { return s.targetDir === undefined; }); + shell.cp('-rf', ios_config_xml_project, temp); + var spy = spyOn(proj_files.xcode, 'removeSourceFile'); + ios['source-file'].uninstall(source[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'DummyPluginCommand.m')); + }); + it('should call into xcodeproj\'s removeSourceFile appropriately when element a target-dir', function(){ + var source = copyArray(valid_source).filter(function(s) { return s.targetDir !== undefined; }); + shell.cp('-rf', ios_config_xml_project, temp); + var spy = spyOn(proj_files.xcode, 'removeSourceFile'); + ios['source-file'].uninstall(source[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'targetDir', 'TargetDirTest.m')); + }); + it('should rm the file from the right target location when element has no target-dir', function(){ + var source = copyArray(valid_source).filter(function(s) { return s.targetDir === undefined; }); + shell.cp('-rf', ios_config_xml_project, temp); + + var spy = spyOn(shell, 'rm'); + ios['source-file'].uninstall(source[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', dummy_id)); + }); + it('should rm the file from the right target location when element has a target-dir', function(){ + var source = copyArray(valid_source).filter(function(s) { return s.targetDir !== undefined; }); + shell.cp('-rf', ios_config_xml_project, temp); + var spy = spyOn(shell, 'rm'); + + ios['source-file'].uninstall(source[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'targetDir')); + }); + it('should call into xcodeproj\'s removeFramework appropriately when element framework=true set', function(){ + var source = copyArray(valid_source).filter(function(s) { return s.framework; }); + shell.cp('-rf', ios_config_xml_project, temp); + var spy = spyOn(proj_files.xcode, 'removeFramework'); + + ios['source-file'].uninstall(source[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(path.join('SampleApp', 'Plugins', dummy_id, 'SourceWithFramework.m')); + }); + }); + + describe('of <header-file> elements', function() { + beforeEach(function() { + shell.cp('-rf', ios_config_xml_project, temp); + }); + it('should call into xcodeproj\'s removeHeaderFile appropriately when element has no target-dir', function(){ + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir === undefined; }); + var spy = spyOn(proj_files.xcode, 'removeHeaderFile'); + + ios['header-file'].uninstall(headers[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'DummyPluginCommand.h')); + }); + it('should call into xcodeproj\'s removeHeaderFile appropriately when element a target-dir', function(){ + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir !== undefined; }); + + var spy = spyOn(proj_files.xcode, 'removeHeaderFile'); + + ios['header-file'].uninstall(headers[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(slashJoin('Plugins', dummy_id, 'targetDir', 'TargetDirTest.h')); + }); + it('should rm the file from the right target location', function(){ + var headers = copyArray(valid_headers).filter(function(s) { return s.targetDir !== undefined; }); + var spy = spyOn(shell, 'rm'); + + ios['header-file'].uninstall(headers[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Plugins', dummy_id, 'targetDir')); + }); + }); + + describe('of <resource-file> elements', function() { + beforeEach(function() { + shell.cp('-rf', ios_config_xml_project, temp); + }); + it('should call into xcodeproj\'s removeResourceFile', function(){ + var resources = copyArray(valid_resources); + var spy = spyOn(proj_files.xcode, 'removeResourceFile'); + + ios['resource-file'].uninstall(resources[0], temp, 'pluginid', null, proj_files); + expect(spy).toHaveBeenCalledWith(path.join('Resources', 'DummyPlugin.bundle')); + }); + it('should rm the file from the right target location', function(){ + var resources = copyArray(valid_resources); + var spy = spyOn(shell, 'rm'); + + ios['resource-file'].uninstall(resources[0], temp, 'pluginid', null, proj_files); + expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp', 'Resources', 'DummyPlugin.bundle')); + }); + }); + describe('of <framework> elements', function() { + beforeEach(function() { + shell.cp('-rf', ios_config_xml_project, temp); + }); + + it('should call into xcodeproj\'s removeFramework', function(){ + var frameworks = copyArray(valid_custom_frameworks); + var spy = spyOn(proj_files.xcode, 'removeFramework'); + + ios['framework'].uninstall(frameworks[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith(path.join(temp, 'SampleApp/Plugins/org.test.plugins.dummyplugin/Custom.framework'), {customFramework:true}); + }); + + // TODO: Add more tests to cover the cases: + // * framework with weak attribute + // * framework that shouldn't be added/removed + + describe('with custom="true" attribute', function () { + it('should rm the file from the right target location', function(){ + var frameworks = copyArray(valid_custom_frameworks); + var spy = spyOn(shell, 'rm'); + + ios['framework'].uninstall(frameworks[0], temp, dummy_id, null, proj_files); + expect(spy).toHaveBeenCalledWith('-rf', path.join(temp, 'SampleApp/Plugins/org.test.plugins.dummyplugin/Custom.framework')); + }); + }); + }); + }); +}); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
