From 8ab75e710980703d6b4427ea8ca3a4ea1b87e307 Mon Sep 17 00:00:00 2001 From: Vladimir Kotikov Date: Mon, 29 Feb 2016 18:49:17 +0300 Subject: [PATCH] CB-10729 Move plugin handlers tests for into platform's repo --- .gitignore | 4 + .jshintignore | 1 + bin/templates/cordova/lib/pluginHandlers.js | 30 +- node_modules/.bin/istanbul | 15 + node_modules/.bin/istanbul.cmd | 7 + package.json | 2 + .../android_project/AndroidManifest.xml | 69 +++++ .../android_project/assets/www/.gitkeep | 0 .../android_project/res/xml/config.xml | 54 ++++ spec/fixtures/android_project/src/.gitkeep | 0 .../android-resource.xml | 1 + .../org.test.plugins.dummyplugin/extra.gradle | 1 + .../plugin-lib/AndroidManifest.xml | 5 + .../plugin-lib/libFile | 1 + .../plugin-lib/project.properties | 1 + .../plugin-lib2/AndroidManifest.xml | 5 + .../plugin-lib2/libFile | 1 + .../plugin-lib2/project.properties | 1 + .../org.test.plugins.dummyplugin/plugin.xml | 75 +++++ .../src/android/DummyPlugin.java | 1 + .../src/android/TestLib.jar | Bin 0 -> 55 bytes .../www/dummyplugin.js | 1 + .../www/dummyplugin/image.jpg | Bin 0 -> 57 bytes .../org.test.plugins.faultyplugin/plugin.xml | 63 +++++ .../src/android/FaultyPlugin.java | 1 + spec/unit/AndroidProject.spec.js | 31 +++ spec/unit/{plugin.spec.js => Api.spec.js} | 0 spec/unit/pluginHandlers/common.spec.js | 170 ++++++++++++ spec/unit/pluginHandlers/handlers.spec.js | 258 ++++++++++++++++++ 29 files changed, 784 insertions(+), 14 deletions(-) create mode 100644 node_modules/.bin/istanbul create mode 100644 node_modules/.bin/istanbul.cmd create mode 100644 spec/fixtures/android_project/AndroidManifest.xml create mode 100644 spec/fixtures/android_project/assets/www/.gitkeep create mode 100644 spec/fixtures/android_project/res/xml/config.xml create mode 100644 spec/fixtures/android_project/src/.gitkeep create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/android-resource.xml create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/extra.gradle create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/AndroidManifest.xml create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/libFile create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/project.properties create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/AndroidManifest.xml create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/libFile create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/project.properties create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/plugin.xml create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/src/android/DummyPlugin.java create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin.js create mode 100644 spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin/image.jpg create mode 100644 spec/fixtures/org.test.plugins.faultyplugin/plugin.xml create mode 100644 spec/fixtures/org.test.plugins.faultyplugin/src/android/FaultyPlugin.java create mode 100644 spec/unit/AndroidProject.spec.js rename spec/unit/{plugin.spec.js => Api.spec.js} (100%) create mode 100644 spec/unit/pluginHandlers/common.spec.js create mode 100644 spec/unit/pluginHandlers/handlers.spec.js diff --git a/.gitignore b/.gitignore index 23195f35..65636c01 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ Desktop.ini *.swp *.class *.jar +!/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar # IntelliJ IDEA files *.iml .idea @@ -43,3 +44,6 @@ npm-debug.log node_modules/jshint node_modules/promise-matchers node_modules/jasmine-node +node_modules/rewire +node_modules/istanbul +/coverage diff --git a/.jshintignore b/.jshintignore index e87aa4bc..dc77ccc1 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,2 +1,3 @@ bin/node_modules/* bin/templates/project/* +spec/fixtures/* diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index efbeda88..1ee6b1f3 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -31,7 +31,7 @@ var handlers = { if (!obj.src) throw new CordovaError(' element is missing "src" attribute for plugin: ' + plugin.id); if (!obj.targetDir) throw new CordovaError(' element is missing "target-dir" attribute for plugin: ' + plugin.id); var dest = path.join(obj.targetDir, path.basename(obj.src)); - copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link); + copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall:function(obj, plugin, project, options) { var dest = path.join(obj.targetDir, path.basename(obj.src)); @@ -41,7 +41,7 @@ var handlers = { 'lib-file':{ install:function(obj, plugin, project, options) { var dest = path.join('libs', path.basename(obj.src)); - copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link); + copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall:function(obj, plugin, project, options) { var dest = path.join('libs', path.basename(obj.src)); @@ -50,7 +50,7 @@ var handlers = { }, 'resource-file':{ install:function(obj, plugin, project, options) { - copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link); + copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link)); }, uninstall:function(obj, plugin, project, options) { removeFile(project.projectDir, path.normalize(obj.target)); @@ -65,22 +65,24 @@ var handlers = { var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir; var subDir; - if (obj.custom) { - var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src); - copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link); - subDir = path.resolve(project.projectDir, subRelativeDir); - } else { - obj.type = 'sys'; - subDir = src; + if (obj.custom) { + var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src); + copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link)); + subDir = path.resolve(project.projectDir, subRelativeDir); + } else { + obj.type = 'sys'; + subDir = src; } if (obj.type == 'gradleReference') { project.addGradleReference(parentDir, subDir); - } else if (obj.type == 'sys') { - project.addSystemLibrary(parentDir, subDir); - } else { - project.addSubProject(parentDir, subDir); + } else if (obj.type == 'sys') { + project.addSystemLibrary(parentDir, subDir); + } else { + project.addSubProject(parentDir, subDir); } + + project.addSubProject(parentDir, subDir); }, uninstall:function(obj, plugin, project, options) { var src = obj.src; diff --git a/node_modules/.bin/istanbul b/node_modules/.bin/istanbul new file mode 100644 index 00000000..6d0d6148 --- /dev/null +++ b/node_modules/.bin/istanbul @@ -0,0 +1,15 @@ +#!/bin/sh +basedir=`dirname "$0"` + +case `uname` in + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -x "$basedir/node" ]; then + "$basedir/node" "$basedir/../istanbul/lib/cli.js" "$@" + ret=$? +else + node "$basedir/../istanbul/lib/cli.js" "$@" + ret=$? +fi +exit $ret diff --git a/node_modules/.bin/istanbul.cmd b/node_modules/.bin/istanbul.cmd new file mode 100644 index 00000000..6635d194 --- /dev/null +++ b/node_modules/.bin/istanbul.cmd @@ -0,0 +1,7 @@ +@IF EXIST "%~dp0\node.exe" ( + "%~dp0\node.exe" "%~dp0\..\istanbul\lib\cli.js" %* +) ELSE ( + @SETLOCAL + @SET PATHEXT=%PATHEXT:;.JS;=;% + node "%~dp0\..\istanbul\lib\cli.js" %* +) \ No newline at end of file diff --git a/package.json b/package.json index c9cc19cd..f9f57ffe 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ ], "scripts": { "test": "npm run jshint && jasmine-node --color spec/unit", + "cover": "istanbul cover --root bin/templates/cordova --print detail node_modules/jasmine-node/bin/jasmine-node -- spec/unit", "test-build": "jasmine-node --captureExceptions --color spec/e2e", "jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint spec" }, @@ -39,6 +40,7 @@ "shelljs" ], "devDependencies": { + "istanbul": "^0.4.2", "jasmine-node": "^1.14.5", "jshint": "^2.6.0", "promise-matchers": "~0", diff --git a/spec/fixtures/android_project/AndroidManifest.xml b/spec/fixtures/android_project/AndroidManifest.xml new file mode 100644 index 00000000..17489caf --- /dev/null +++ b/spec/fixtures/android_project/AndroidManifest.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/fixtures/android_project/assets/www/.gitkeep b/spec/fixtures/android_project/assets/www/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/android_project/res/xml/config.xml b/spec/fixtures/android_project/res/xml/config.xml new file mode 100644 index 00000000..4f087a9d --- /dev/null +++ b/spec/fixtures/android_project/res/xml/config.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/fixtures/android_project/src/.gitkeep b/spec/fixtures/android_project/src/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/org.test.plugins.dummyplugin/android-resource.xml b/spec/fixtures/org.test.plugins.dummyplugin/android-resource.xml new file mode 100644 index 00000000..9046e6e6 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/android-resource.xml @@ -0,0 +1 @@ +./org.test.plugins.dummyplugin/android-resource.xml diff --git a/spec/fixtures/org.test.plugins.dummyplugin/extra.gradle b/spec/fixtures/org.test.plugins.dummyplugin/extra.gradle new file mode 100644 index 00000000..5b828a9d --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/extra.gradle @@ -0,0 +1 @@ +extra.gradle diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/AndroidManifest.xml b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/AndroidManifest.xml new file mode 100644 index 00000000..3c9499c1 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/libFile b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/libFile new file mode 100644 index 00000000..c79df8ef --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/libFile @@ -0,0 +1 @@ +libFile contents diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/project.properties b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/project.properties new file mode 100644 index 00000000..c4a5b638 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib/project.properties @@ -0,0 +1 @@ +target=android-11 diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/AndroidManifest.xml b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/AndroidManifest.xml new file mode 100644 index 00000000..3c9499c1 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/libFile b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/libFile new file mode 100644 index 00000000..c79df8ef --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/libFile @@ -0,0 +1 @@ +libFile contents diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/project.properties b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/project.properties new file mode 100644 index 00000000..c4a5b638 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin-lib2/project.properties @@ -0,0 +1 @@ +target=android-11 diff --git a/spec/fixtures/org.test.plugins.dummyplugin/plugin.xml b/spec/fixtures/org.test.plugins.dummyplugin/plugin.xml new file mode 100644 index 00000000..a40df2b2 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/plugin.xml @@ -0,0 +1,75 @@ + + + + + + + dummyplugin + + my description + Jackson Badman + dummy,plugin + BSD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/fixtures/org.test.plugins.dummyplugin/src/android/DummyPlugin.java b/spec/fixtures/org.test.plugins.dummyplugin/src/android/DummyPlugin.java new file mode 100644 index 00000000..90e4f5a2 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/src/android/DummyPlugin.java @@ -0,0 +1 @@ +./org.test.plugins.dummyplugin/src/android/DummyPlugin.java diff --git a/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar b/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar new file mode 100644 index 0000000000000000000000000000000000000000..089ae3bec291c8c51c25a6ee57cfe16efd92bc45 GIT binary patch literal 55 zcmdPX&o4^XD@iRb(JRO)P0!3L)=MeP&8>uR^oxs<^%L__it;m4^h1D(d@_^tvJ#89 E07c{!j{pDw literal 0 HcmV?d00001 diff --git a/spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin.js b/spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin.js new file mode 100644 index 00000000..631d6da9 --- /dev/null +++ b/spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin.js @@ -0,0 +1 @@ +./org.test.plugins.dummyplugin/www/dummyplugin.js diff --git a/spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin/image.jpg b/spec/fixtures/org.test.plugins.dummyplugin/www/dummyplugin/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..219c78a1c74afe1a2ce1f0f0420b09a670ad95b0 GIT binary patch literal 57 xcmdPX&o4^XD@iRb(JRO)P0!3L)=MeP&8>uR^vlc3^^y6RxrynidRYbOTmX7o71jU% literal 0 HcmV?d00001 diff --git a/spec/fixtures/org.test.plugins.faultyplugin/plugin.xml b/spec/fixtures/org.test.plugins.faultyplugin/plugin.xml new file mode 100644 index 00000000..7d2a2d2a --- /dev/null +++ b/spec/fixtures/org.test.plugins.faultyplugin/plugin.xml @@ -0,0 +1,63 @@ + + + + + + Faulty Plugin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec/fixtures/org.test.plugins.faultyplugin/src/android/FaultyPlugin.java b/spec/fixtures/org.test.plugins.faultyplugin/src/android/FaultyPlugin.java new file mode 100644 index 00000000..dba5492f --- /dev/null +++ b/spec/fixtures/org.test.plugins.faultyplugin/src/android/FaultyPlugin.java @@ -0,0 +1 @@ +./org.test.plugins.faultyplugin/src/android/org.test.plugins.faultyplugin.java diff --git a/spec/unit/AndroidProject.spec.js b/spec/unit/AndroidProject.spec.js new file mode 100644 index 00000000..8aec35a7 --- /dev/null +++ b/spec/unit/AndroidProject.spec.js @@ -0,0 +1,31 @@ +/** + 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 path = require('path'); +var AndroidProject = require('../../bin/templates/cordova/lib/AndroidProject'); +var android_project = path.join(__dirname, '../fixtures/android_project'); + +describe('AndroidProject class', function() { + describe('getPackageName method', function() { + it('should return an android project\'s proper package name', function() { + expect(AndroidProject.getProjectFile(android_project).getPackageName()) + .toEqual('com.alunny.childapp'); + }); + }); +}); diff --git a/spec/unit/plugin.spec.js b/spec/unit/Api.spec.js similarity index 100% rename from spec/unit/plugin.spec.js rename to spec/unit/Api.spec.js diff --git a/spec/unit/pluginHandlers/common.spec.js b/spec/unit/pluginHandlers/common.spec.js new file mode 100644 index 00000000..7280ffb9 --- /dev/null +++ b/spec/unit/pluginHandlers/common.spec.js @@ -0,0 +1,170 @@ +/* + * + * + * 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. + * +*/ + +var rewire = require('rewire'); +var common = rewire('../../../bin/templates/cordova/lib/pluginHandlers'); +var path = require('path'); +var fs = require('fs'); +var osenv = require('os'); +var shell = require('shelljs'); +var test_dir = path.join(osenv.tmpdir(), 'test_plugman'); +var project_dir = path.join(test_dir, 'project'); +var src = path.join(project_dir, 'src'); +var dest = path.join(project_dir, 'dest'); +var java_dir = path.join(src, 'one', 'two', 'three'); +var java_file = path.join(java_dir, 'test.java'); +var symlink_file = path.join(java_dir, 'symlink'); +var non_plugin_file = path.join(osenv.tmpdir(), 'non_plugin_file'); + +var copyFile = common.__get__('copyFile'); +var deleteJava = common.__get__('deleteJava'); +var copyNewFile = common.__get__('copyNewFile'); + +describe('common platform handler', function() { + + describe('copyFile', function() { + it('should throw if source path not found', function(){ + shell.rm('-rf', src); + expect(function(){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(){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; + } + + 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(){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(){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 = path.resolve(project_dir, dest); + + 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 = path.resolve(project_dir, dest); + + 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(){copyNewFile(test_dir, src, project_dir, dest);}). + toThrow(new Error('"' + dest + '" already exists!')); + shell.rm('-rf', dest); + }); + }); + + describe('deleteJava', function() { + beforeEach(function() { + shell.mkdir('-p', java_dir); + fs.writeFileSync(java_file, 'contents', 'utf-8'); + }); + + afterEach(function() { + shell.rm('-rf', java_dir); + }); + + it('should call fs.unlinkSync on the provided paths', function(){ + var s = spyOn(fs, 'unlinkSync').andCallThrough(); + deleteJava(project_dir, java_file); + expect(s).toHaveBeenCalled(); + expect(s).toHaveBeenCalledWith(path.resolve(project_dir, java_file)); + }); + + it('should delete empty directories after removing source code in a java src path hierarchy', function(){ + 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); + }); + + it('should never delete the top-level src directory, even if all plugins added were removed', function(){ + deleteJava(project_dir, java_file); + expect(fs.existsSync(src)).toBe(true); + }); + }); +}); + +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; +} diff --git a/spec/unit/pluginHandlers/handlers.spec.js b/spec/unit/pluginHandlers/handlers.spec.js new file mode 100644 index 00000000..abeb48b9 --- /dev/null +++ b/spec/unit/pluginHandlers/handlers.spec.js @@ -0,0 +1,258 @@ +/** + 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 rewire = require('rewire'); +var common = rewire('../../../bin/templates/cordova/lib/pluginHandlers'); +var android = common.__get__('handlers'); +var path = require('path'); +var fs = require('fs'); +var shell = require('shelljs'); +var os = require('os'); +var temp = path.join(os.tmpdir(), 'plugman'); +var plugins_dir = path.join(temp, 'cordova/plugins'); +var dummyplugin = path.join(__dirname, '../../fixtures/org.test.plugins.dummyplugin'); +var faultyplugin = path.join(__dirname, '../../fixtures/org.test.plugins.faultyplugin'); +var android_project = path.join(__dirname, '../../fixtures/android_project/*'); + +var PluginInfo = require('cordova-common').PluginInfo; +var AndroidProject = require('../../../bin/templates/cordova/lib/AndroidProject'); + +var dummyPluginInfo = new PluginInfo(dummyplugin); +var valid_source = dummyPluginInfo.getSourceFiles('android'), + valid_resources = dummyPluginInfo.getResourceFiles('android'), + valid_libs = dummyPluginInfo.getLibFiles('android'); + +var faultyPluginInfo = new PluginInfo(faultyplugin); +var invalid_source = faultyPluginInfo.getSourceFiles('android'); + +describe('android project handler', function() { + describe('installation', function() { + var copyFileOrig = common.__get__('copyFile'); + var copyFileSpy = jasmine.createSpy('copyFile'); + var dummyProject; + + beforeEach(function() { + shell.mkdir('-p', temp); + dummyProject = AndroidProject.getProjectFile(temp); + common.__set__('copyFile', copyFileSpy); + }); + + afterEach(function() { + shell.rm('-rf', temp); + common.__set__('copyFile', copyFileOrig); + }); + + describe('of elements', function() { + it('should copy files', function () { + android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject); + expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin, 'src/android/TestLib.jar', temp, path.join('libs', 'TestLib.jar'), false); + }); + }); + + describe('of elements', function() { + it('should copy files', function () { + android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject); + expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin, 'android-resource.xml', temp, path.join('res', 'xml', 'dummy.xml'), false); + }); + }); + + describe('of elements', function() { + beforeEach(function() { + shell.cp('-rf', android_project, temp); + }); + + it('should copy stuff from one location to another by calling common.copyFile', function() { + android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject); + expect(copyFileSpy) + .toHaveBeenCalledWith(dummyplugin, 'src/android/DummyPlugin.java', temp, path.join('src/com/phonegap/plugins/dummyplugin/DummyPlugin.java'), false); + }); + + it('should throw if source file cannot be found', function() { + common.__set__('copyFile', copyFileOrig); + expect(function() { + android['source-file'].install(invalid_source[0], faultyPluginInfo, dummyProject); + }).toThrow('"' + path.resolve(faultyplugin, 'src/android/NotHere.java') + '" not found!'); + }); + + it('should throw if target file already exists', function() { + // write out a file + var target = path.resolve(temp, 'src/com/phonegap/plugins/dummyplugin'); + shell.mkdir('-p', target); + target = path.join(target, 'DummyPlugin.java'); + fs.writeFileSync(target, 'some bs', 'utf-8'); + + expect(function() { + android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject); + }).toThrow('"' + target + '" already exists!'); + }); + }); + + describe('of elements', function() { + + var someString = jasmine.any(String); + + var copyNewFileOrig = common.__get__('copyNewFile'); + var copyNewFileSpy = jasmine.createSpy('copyNewFile'); + + beforeEach(function() { + shell.cp('-rf', android_project, temp); + + spyOn(dummyProject, 'addSystemLibrary'); + spyOn(dummyProject, 'addSubProject'); + spyOn(dummyProject, 'addGradleReference'); + common.__set__('copyNewFile', copyNewFileSpy); + }); + + afterEach(function() { + common.__set__('copyNewFile', copyNewFileOrig); + }); + + it('should throw if framework doesn\'t have "src" attribute', function() { + expect(function() { android.framework.install({}, dummyPluginInfo, dummyProject); }).toThrow(); + }); + + it('should install framework without "parent" attribute into project root', function() { + var framework = {src: 'plugin-lib'}; + android.framework.install(framework, dummyPluginInfo, dummyProject); + expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(dummyProject.projectDir, someString); + }); + + it('should install framework with "parent" attribute into parent framework dir', function() { + var childFramework = {src: 'plugin-lib2', parent: 'plugin-lib'}; + android.framework.install(childFramework, dummyPluginInfo, dummyProject); + expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(path.resolve(dummyProject.projectDir, childFramework.parent), someString); + }); + + it('should not copy anything if "custom" attribute is not set', function() { + var framework = {src: 'plugin-lib'}; + var cpSpy = spyOn(shell, 'cp'); + android.framework.install(framework, dummyPluginInfo, dummyProject); + expect(dummyProject.addSystemLibrary).toHaveBeenCalledWith(someString, framework.src); + expect(cpSpy).not.toHaveBeenCalled(); + }); + + it('should copy framework sources if "custom" attribute is set', function() { + var framework = {src: 'plugin-lib', custom: true}; + android.framework.install(framework, dummyPluginInfo, dummyProject); + expect(dummyProject.addSubProject).toHaveBeenCalledWith(dummyProject.projectDir, someString); + expect(copyNewFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, framework.src, dummyProject.projectDir, someString, false); + }); + + it('should install gradleReference using project.addGradleReference', function() { + var framework = {src: 'plugin-lib', custom: true, type: 'gradleReference'}; + android.framework.install(framework, dummyPluginInfo, dummyProject); + expect(copyNewFileSpy).toHaveBeenCalledWith(dummyPluginInfo.dir, framework.src, dummyProject.projectDir, someString, false); + expect(dummyProject.addGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString); + }); + }); + }); + + describe('uninstallation', function() { + + var removeFileOrig = common.__get__('removeFile'); + var deleteJavaOrig = common.__get__('deleteJava'); + + var removeFileSpy = jasmine.createSpy('removeFile'); + var deleteJavaSpy = jasmine.createSpy('deleteJava'); + var dummyProject; + + beforeEach(function() { + shell.mkdir('-p', temp); + shell.mkdir('-p', plugins_dir); + shell.cp('-rf', android_project, temp); + AndroidProject.purgeCache(); + dummyProject = AndroidProject.getProjectFile(temp); + common.__set__('removeFile', removeFileSpy); + common.__set__('deleteJava', deleteJavaSpy); + }); + + afterEach(function() { + shell.rm('-rf', temp); + common.__set__('removeFile', removeFileOrig); + common.__set__('deleteJava', deleteJavaOrig); + }); + + describe('of elements', function(done) { + it('should remove jar files', function () { + android['lib-file'].install(valid_libs[0], dummyPluginInfo, dummyProject); + android['lib-file'].uninstall(valid_libs[0], dummyPluginInfo, dummyProject); + expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('libs/TestLib.jar')); + }); + }); + + describe('of elements', function(done) { + it('should remove files', function () { + android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject); + android['resource-file'].uninstall(valid_resources[0], dummyPluginInfo, dummyProject); + expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('res/xml/dummy.xml')); + }); + }); + + describe('of elements', function() { + it('should remove stuff by calling common.deleteJava', function() { + android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject); + android['source-file'].uninstall(valid_source[0], dummyPluginInfo, dummyProject); + expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('src/com/phonegap/plugins/dummyplugin/DummyPlugin.java')); + }); + }); + + describe('of elements', function() { + + var someString = jasmine.any(String); + + beforeEach(function() { + shell.mkdir(path.join(dummyProject.projectDir, dummyPluginInfo.id)); + + spyOn(dummyProject, 'removeSystemLibrary'); + spyOn(dummyProject, 'removeSubProject'); + spyOn(dummyProject, 'removeGradleReference'); + }); + + it('should throw if framework doesn\'t have "src" attribute', function() { + expect(function() { android.framework.uninstall({}, dummyPluginInfo, dummyProject); }).toThrow(); + }); + + it('should uninstall framework without "parent" attribute into project root', function() { + var framework = {src: 'plugin-lib'}; + android.framework.uninstall(framework, dummyPluginInfo, dummyProject); + expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(dummyProject.projectDir, someString); + }); + + it('should uninstall framework with "parent" attribute into parent framework dir', function() { + var childFramework = {src: 'plugin-lib2', parent: 'plugin-lib'}; + android.framework.uninstall(childFramework, dummyPluginInfo, dummyProject); + expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(path.resolve(dummyProject.projectDir, childFramework.parent), someString); + }); + + it('should remove framework sources if "custom" attribute is set', function() { + var framework = {src: 'plugin-lib', custom: true}; + android.framework.uninstall(framework, dummyPluginInfo, dummyProject); + expect(dummyProject.removeSubProject).toHaveBeenCalledWith(dummyProject.projectDir, someString); + expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString); + }); + + it('should install gradleReference using project.removeGradleReference', function() { + var framework = {src: 'plugin-lib', custom: true, type: 'gradleReference'}; + android.framework.uninstall(framework, dummyPluginInfo, dummyProject); + expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString); + expect(dummyProject.removeGradleReference).toHaveBeenCalledWith(dummyProject.projectDir, someString); + }); + }); + }); +});