@@ -16,6 +16,8 @@ import ErrorsLib = require("../lib/common/errors");
1616import ProjectHelperLib = require( "../lib/common/project-helper" ) ;
1717import PlatformsDataLib = require( "../lib/platforms-data" ) ;
1818import ProjectDataServiceLib = require( "../lib/services/project-data-service" ) ;
19+ import helpers = require( "../lib/common/helpers" ) ;
20+ import os = require( "os" ) ;
1921
2022import PluginsServiceLib = require( "../lib/services/plugins-service" ) ;
2123import AddPluginCommandLib = require( "../lib/commands/plugin/add-plugin" ) ;
@@ -124,6 +126,30 @@ function addPluginWhenExpectingToFail(testInjector: IInjector, plugin: string, e
124126 assert . isTrue ( isErrorThrown ) ;
125127}
126128
129+ function createAndroidManifestFile ( projectFolder : string , fs :IFileSystem ) : void {
130+ let manifest = '<?xml version="1.0" encoding="UTF-8"?>' +
131+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >' +
132+ '<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>' +
133+ '<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>' +
134+ '<uses-permission android:name="android.permission.INTERNET"/>' +
135+ '<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.Sample" >' +
136+ '<activity android:name="com.example.android.basiccontactables.MainActivity" android:label="@string/app_name" android:launchMode="singleTop">' +
137+ '<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />' +
138+ '<intent-filter>' +
139+ '<action android:name="android.intent.action.SEARCH" />' +
140+ '</intent-filter>' +
141+ '<intent-filter>' +
142+ '<action android:name="android.intent.action.MAIN" />' +
143+ '</intent-filter>' +
144+ '</activity>' +
145+ '</application>' +
146+ '</manifest>' ;
147+
148+ fs . createDirectory ( path . join ( projectFolder , "platforms" ) ) . wait ( ) ;
149+ fs . createDirectory ( path . join ( projectFolder , "platforms" , "android" ) ) . wait ( ) ;
150+ fs . writeFile ( path . join ( projectFolder , "platforms" , "android" , "AndroidManifest.xml" ) , manifest ) . wait ( ) ;
151+ }
152+
127153describe ( "Plugins service" , ( ) => {
128154 let testInjector : IInjector ;
129155 beforeEach ( ( ) => {
@@ -256,7 +282,7 @@ describe("Plugins service", () => {
256282 let packageJsonContent = fs . readJson ( path . join ( projectFolder , "package.json" ) ) . wait ( ) ;
257283 let actualDependencies = packageJsonContent . dependencies ;
258284 let expectedDependencies = {
259- "plugin1" : "^1.0.0 "
285+ "plugin1" : "^1.0.3 "
260286 } ;
261287 assert . deepEqual ( actualDependencies , expectedDependencies ) ;
262288 } ) ;
@@ -419,4 +445,141 @@ describe("Plugins service", () => {
419445 commandsService . tryExecuteCommand ( "plugin|add" , [ pluginFolderPath ] ) . wait ( ) ;
420446 } ) ;
421447 } ) ;
448+
449+ describe ( "merge xmls tests" , ( ) => {
450+ let testInjector : IInjector ;
451+ beforeEach ( ( ) => {
452+ testInjector = createTestInjector ( ) ;
453+ testInjector . registerCommand ( "plugin|add" , AddPluginCommandLib . AddPluginCommand ) ;
454+ } ) ;
455+ it ( "fails if the plugin contains incorrect xml" , ( ) => {
456+ let pluginName = "mySamplePlugin" ;
457+ let projectFolder = createProjectFile ( testInjector ) ;
458+ let pluginFolderPath = path . join ( projectFolder , pluginName ) ;
459+ let pluginJsonData = {
460+ "name" : pluginName ,
461+ "version" : "0.0.1" ,
462+ "nativescript" : {
463+ "platforms" : {
464+ "android" : "0.10.0"
465+ }
466+ }
467+ } ;
468+ let fs = testInjector . resolve ( "fs" ) ;
469+ fs . writeJson ( path . join ( pluginFolderPath , "package.json" ) , pluginJsonData ) . wait ( ) ;
470+
471+ // Adds AndroidManifest.xml file in platforms/android folder
472+ createAndroidManifestFile ( projectFolder , fs ) ;
473+
474+ // Mock plugins service
475+ let pluginsService = testInjector . resolve ( "pluginsService" ) ;
476+ pluginsService . getAllInstalledPlugins = ( ) => {
477+ return ( ( ) => {
478+ return [ {
479+ name : ""
480+ } ] ;
481+ } ) . future < IPluginData [ ] > ( ) ( ) ;
482+ }
483+
484+ let appDestinationDirectoryPath = path . join ( projectFolder , "platforms" , "android" ) ;
485+
486+ // Mock platformsData
487+ let platformsData = testInjector . resolve ( "platformsData" ) ;
488+ platformsData . getPlatformData = ( platform : string ) => {
489+ return {
490+ appDestinationDirectoryPath : appDestinationDirectoryPath ,
491+ frameworkPackageName : "tns-android" ,
492+ configurationFileName : "AndroidManifest.xml"
493+ }
494+ }
495+
496+ // Ensure the pluginDestinationPath folder exists
497+ let pluginPlatformsDirPath = path . join ( appDestinationDirectoryPath , "app" , "tns_modules" , pluginName , "platforms" , "android" ) ;
498+ fs . ensureDirectoryExists ( pluginPlatformsDirPath ) . wait ( ) ;
499+
500+ // Creates invalid plugin's AndroidManifest.xml file
501+ let xml = '<?xml version="1.0" encoding="UTF-8"?>' +
502+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >' +
503+ '<uses-permission android:name="android.permission.READ_CONTACTS"/>' ;
504+ let pluginConfigurationFilePath = path . join ( pluginPlatformsDirPath , "AndroidManifest.xml" ) ;
505+ fs . writeFile ( pluginConfigurationFilePath , xml ) . wait ( ) ;
506+
507+ // Expected error message. The assertion happens in mockBeginCommand
508+ let expectedErrorMessage = `Exception: Invalid xml file ${ pluginConfigurationFilePath } . Additional technical information: element parse error: Exception: Invalid xml file ` +
509+ `${ pluginConfigurationFilePath } . Additional technical information: unclosed xml attribute` +
510+ `\n@#[line:1,col:39].` +
511+ `\n@#[line:1,col:39].` ;
512+ mockBeginCommand ( testInjector , expectedErrorMessage ) ;
513+
514+ let commandsService = testInjector . resolve ( CommandsServiceLib . CommandsService ) ;
515+ commandsService . tryExecuteCommand ( "plugin|add" , [ pluginFolderPath ] ) . wait ( ) ;
516+ } ) ;
517+ it ( "merges AndroidManifest.xml and produces correct xml" , ( ) => {
518+ let pluginName = "mySamplePlugin" ;
519+ let projectFolder = createProjectFile ( testInjector ) ;
520+ let pluginFolderPath = path . join ( projectFolder , pluginName ) ;
521+ let pluginJsonData = {
522+ "name" : pluginName ,
523+ "version" : "0.0.1" ,
524+ "nativescript" : {
525+ "platforms" : {
526+ "android" : "0.10.0"
527+ }
528+ }
529+ } ;
530+ let fs = testInjector . resolve ( "fs" ) ;
531+ fs . writeJson ( path . join ( pluginFolderPath , "package.json" ) , pluginJsonData ) . wait ( ) ;
532+
533+ // Adds AndroidManifest.xml file in platforms/android folder
534+ createAndroidManifestFile ( projectFolder , fs ) ;
535+
536+ // Mock plugins service
537+ let pluginsService = testInjector . resolve ( "pluginsService" ) ;
538+ pluginsService . getAllInstalledPlugins = ( ) => {
539+ return ( ( ) => {
540+ return [ {
541+ name : ""
542+ } ] ;
543+ } ) . future < IPluginData [ ] > ( ) ( ) ;
544+ }
545+
546+ let appDestinationDirectoryPath = path . join ( projectFolder , "platforms" , "android" ) ;
547+
548+ // Mock platformsData
549+ let platformsData = testInjector . resolve ( "platformsData" ) ;
550+ platformsData . getPlatformData = ( platform : string ) => {
551+ return {
552+ appDestinationDirectoryPath : appDestinationDirectoryPath ,
553+ frameworkPackageName : "tns-android" ,
554+ configurationFileName : "AndroidManifest.xml" ,
555+ configurationFilePath : path . join ( appDestinationDirectoryPath , "AndroidManifest.xml" ) ,
556+ mergeXmlConfig : [ { "nodename" : "manifest" , "attrname" : "*" } ]
557+ }
558+ }
559+
560+ // Ensure the pluginDestinationPath folder exists
561+ let pluginPlatformsDirPath = path . join ( appDestinationDirectoryPath , "app" , "tns_modules" , pluginName , "platforms" , "android" ) ;
562+ fs . ensureDirectoryExists ( pluginPlatformsDirPath ) . wait ( ) ;
563+
564+ // Creates valid plugin's AndroidManifest.xml file
565+ let xml = '<?xml version="1.0" encoding="UTF-8"?>' +
566+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.basiccontactables" android:versionCode="1" android:versionName="1.0" >' +
567+ '<uses-permission android:name="android.permission.READ_CONTACTS"/>' +
568+ '</manifest>' ;
569+ let pluginConfigurationFilePath = path . join ( pluginPlatformsDirPath , "AndroidManifest.xml" ) ;
570+ fs . writeFile ( pluginConfigurationFilePath , xml ) . wait ( ) ;
571+
572+ pluginsService . add ( pluginFolderPath ) . wait ( ) ;
573+
574+ let expectedXml = '<?xmlversion="1.0"encoding="UTF-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.example.android.basiccontactables"android:versionCode="1"android:versionName="1.0"><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.INTERNET"/><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/Theme.Sample"><activityandroid:name="com.example.android.basiccontactables.MainActivity"android:label="@string/app_name"android:launchMode="singleTop"><meta-dataandroid:name="android.app.searchable"android:resource="@xml/searchable"/><intent-filter><actionandroid:name="android.intent.action.SEARCH"/></intent-filter><intent-filter><actionandroid:name="android.intent.action.MAIN"/></intent-filter></activity></application><uses-permissionandroid:name="android.permission.READ_CONTACTS"/></manifest>' ;
575+ expectedXml = helpers . stringReplaceAll ( expectedXml , os . EOL , "" ) ;
576+ expectedXml = helpers . stringReplaceAll ( expectedXml , " " , "" ) ;
577+
578+ let actualXml = fs . readText ( path . join ( appDestinationDirectoryPath , "AndroidManifest.xml" ) ) . wait ( ) ;
579+ actualXml = helpers . stringReplaceAll ( actualXml , "\n" , "" ) ;
580+ actualXml = helpers . stringReplaceAll ( actualXml , " " , "" ) ;
581+
582+ assert . equal ( expectedXml , actualXml ) ;
583+ } ) ;
584+ } ) ;
422585} ) ;
0 commit comments