From 03ea822ae3a57fec2c45797cd350836ec183dd7e Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 22 Jan 2020 10:37:37 +0200 Subject: [PATCH 1/2] feat: add support for metadata filtering The new versions of runtimes (6.4.x and newer) will support filtering of metadata generation. To achieve this they need input from CLI - two files in `/platforms/` directory. Add new service in CLI to generate the required files. Whenever the service is called, the old files (from previous execution) will be cleaned and full generation will be triggered. --- lib/bootstrap.ts | 1 + lib/constants.ts | 5 + lib/definitions/metadata-filtering-service.ts | 42 ++++ lib/services/metadata-filtering-service.ts | 83 ++++++++ .../prepare-native-platform-service.ts | 4 +- test/services/metadata-filtering-service.ts | 186 ++++++++++++++++++ test/stubs.ts | 3 + 7 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 lib/definitions/metadata-filtering-service.ts create mode 100644 lib/services/metadata-filtering-service.ts create mode 100644 test/services/metadata-filtering-service.ts diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index e24cc7a529..fe32ed475b 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -234,3 +234,4 @@ $injector.require("npmConfigService", "./services/npm-config-service"); $injector.require("ipService", "./services/ip-service"); $injector.require("jsonFileSettingsService", "./common/services/json-file-settings-service"); $injector.require("markingModeService", "./services/marking-mode-service"); +$injector.require("metadataFilteringService", "./services/metadata-filtering-service"); diff --git a/lib/constants.ts b/lib/constants.ts index ae5279593e..45009ec50c 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -64,6 +64,11 @@ export const APPLICATION_RESPONSE_TIMEOUT_SECONDS = 60; export const NATIVE_EXTENSION_FOLDER = "extensions"; export const IOS_WATCHAPP_FOLDER = "watchapp"; export const IOS_WATCHAPP_EXTENSION_FOLDER = "watchextension"; +export class MetadataFilteringConstants { + static NATIVE_API_USAGE_FILE_NAME = "native-api-usage.json"; + static WHITELIST_FILE_NAME = "whitelist.mdg"; + static BLACKLIST_FILE_NAME = "blacklist.mdg"; +} export class PackageVersion { static NEXT = "next"; diff --git a/lib/definitions/metadata-filtering-service.ts b/lib/definitions/metadata-filtering-service.ts new file mode 100644 index 0000000000..269ba87578 --- /dev/null +++ b/lib/definitions/metadata-filtering-service.ts @@ -0,0 +1,42 @@ +/** + * Describes the content of the native-api-usage.json file located in `/ directory. + */ +interface INativeApiUsageConfiguartion { + /** + * Defines if the content of plugins' native-api-usage files will be used and included in the whitelist content. + */ + ["whitelist-plugins-usages"]: boolean; + + /** + * Defines APIs which will be inlcuded in the metadata. + */ + whitelist: string[]; + + /** + * Defines APIs which will be excluded from the metadata. + */ + blacklist: string[]; +} + +/** + * Describes the content of plugin's native-api-usage.json file located in `/platforms/ directory. + */ +interface INativeApiUsagePluginConfiguration { + /** + * Defines APIs which are used by the plugin and which should be whitelisted by the application using this plugin. + */ + uses: string[]; +} + +/** + * Describes service used to generate neccesary files to filter the metadata generation. + */ +interface IMetadataFilteringService { + /** + * Cleans old metadata filters and creates new ones for the current project and platform. + * @param {IProjectData} projectData Information about the current project. + * @param {string} platform The platform for which metadata should be generated. + * @returns {void} + */ + generateMetadataFilters(projectData: IProjectData, platform: string): void; +} diff --git a/lib/services/metadata-filtering-service.ts b/lib/services/metadata-filtering-service.ts new file mode 100644 index 0000000000..2de2dfb6c0 --- /dev/null +++ b/lib/services/metadata-filtering-service.ts @@ -0,0 +1,83 @@ +import * as path from "path"; +import * as os from "os"; +import { MetadataFilteringConstants } from "../constants"; + +export class MetadataFilteringService implements IMetadataFilteringService { + constructor(private $fs: IFileSystem, + private $pluginsService: IPluginsService, + private $mobileHelper: Mobile.IMobileHelper, + private $platformsDataService: IPlatformsDataService, + private $logger: ILogger) { } + + public generateMetadataFilters(projectData: IProjectData, platform: string): void { + this.generateWhitelist(projectData, platform); + this.generateBlacklist(projectData, platform); + } + + private generateWhitelist(projectData: IProjectData, platform: string): void { + const platformsDirPath = this.getPlatformsDirPath(projectData, platform); + const pathToWhitelistFile = path.join(platformsDirPath, MetadataFilteringConstants.WHITELIST_FILE_NAME); + this.$fs.deleteFile(pathToWhitelistFile); + + const nativeApiConfiguration = this.getNativeApiConfigurationForPlatform(projectData, platform); + if (nativeApiConfiguration) { + const whitelistedItems: string[] = []; + if (nativeApiConfiguration["whitelist-plugins-usages"]) { + const plugins = this.$pluginsService.getAllProductionPlugins(projectData); + for (const pluginData of plugins) { + const pathToPlatformsDir = pluginData.pluginPlatformsFolderPath(platform); + const pathToPluginsMetadataConfig = path.join(pathToPlatformsDir, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); + if (this.$fs.exists(pathToPluginsMetadataConfig)) { + const pluginConfig: INativeApiUsagePluginConfiguration = this.$fs.readJson(pathToPluginsMetadataConfig) || {}; + this.$logger.trace(`Adding content of ${pathToPluginsMetadataConfig} to whitelisted items of metadata filtering.`); + whitelistedItems.push(...(pluginConfig.uses || [])); + } + } + } + + whitelistedItems.push(...(nativeApiConfiguration.whitelist || [])); + + if (whitelistedItems.length) { + this.$fs.writeFile(pathToWhitelistFile, _.uniq(whitelistedItems).sort().join(os.EOL)); + } + } + } + + private generateBlacklist(projectData: IProjectData, platform: string): void { + const platformsDirPath = this.getPlatformsDirPath(projectData, platform); + const pathToBlacklistFile = path.join(platformsDirPath, MetadataFilteringConstants.BLACKLIST_FILE_NAME); + this.$fs.deleteFile(pathToBlacklistFile); + + const nativeApiConfiguration = this.getNativeApiConfigurationForPlatform(projectData, platform); + if (nativeApiConfiguration) { + const blacklistedItems: string[] = nativeApiConfiguration.blacklist || []; + + if (blacklistedItems.length) { + this.$fs.writeFile(pathToBlacklistFile, _.uniq(blacklistedItems).sort().join(os.EOL)); + } + } else { + this.$logger.trace(`There's no application configuration for metadata filtering for platform ${platform}. Full metadata will be generated.`); + } + } + + private getNativeApiConfigurationForPlatform(projectData: IProjectData, platform: string): INativeApiUsageConfiguartion { + let config: INativeApiUsageConfiguartion = null; + const pathToApplicationConfigurationFile = this.getPathToApplicationConfigurationForPlatform(projectData, platform); + if (this.$fs.exists(pathToApplicationConfigurationFile)) { + config = this.$fs.readJson(pathToApplicationConfigurationFile); + } + + return config; + } + + private getPlatformsDirPath(projectData: IProjectData, platform: string): string { + const platformData = this.$platformsDataService.getPlatformData(platform, projectData); + return platformData.projectRoot; + } + + private getPathToApplicationConfigurationForPlatform(projectData: IProjectData, platform: string): string { + return path.join(projectData.appResourcesDirectoryPath, this.$mobileHelper.normalizePlatformName(platform), MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); + } +} + +$injector.register("metadataFilteringService", MetadataFilteringService); diff --git a/lib/services/platform/prepare-native-platform-service.ts b/lib/services/platform/prepare-native-platform-service.ts index c70a93cd1b..c4af534f17 100644 --- a/lib/services/platform/prepare-native-platform-service.ts +++ b/lib/services/platform/prepare-native-platform-service.ts @@ -9,6 +9,7 @@ export class PrepareNativePlatformService implements IPrepareNativePlatformServi public $hooksService: IHooksService, private $nodeModulesBuilder: INodeModulesBuilder, private $projectChangesService: IProjectChangesService, + private $metadataFilteringService: IMetadataFilteringService ) { } @performanceLog() @@ -37,12 +38,13 @@ export class PrepareNativePlatformService implements IPrepareNativePlatformServi } if (hasNativeModulesChange) { - await this.$nodeModulesBuilder.prepareNodeModules({platformData, projectData}); + await this.$nodeModulesBuilder.prepareNodeModules({ platformData, projectData }); } if (hasNativeModulesChange || hasConfigChange) { await platformData.platformProjectService.processConfigurationFilesFromAppResources(projectData, { release }); await platformData.platformProjectService.handleNativeDependenciesChange(projectData, { release }); + this.$metadataFilteringService.generateMetadataFilters(projectData, platformData.platformNameLowerCase); } platformData.platformProjectService.interpolateConfigurationFile(projectData); diff --git a/test/services/metadata-filtering-service.ts b/test/services/metadata-filtering-service.ts new file mode 100644 index 0000000000..05e8a3cf47 --- /dev/null +++ b/test/services/metadata-filtering-service.ts @@ -0,0 +1,186 @@ +import { MetadataFilteringService } from "../../lib/services/metadata-filtering-service"; +import { Yok } from "../../lib/common/yok"; +import { LoggerStub, FileSystemStub } from "../stubs"; +import { assert } from "chai"; +import * as path from "path"; +import { MetadataFilteringConstants } from "../../lib/constants"; +import { EOL } from "os"; + +describe("metadataFilteringService", () => { + const platform = "platform"; + const projectDir = "projectDir"; + const projectRoot = path.join(projectDir, "platforms", platform); + const projectData: any = { + appResourcesDirectoryPath: path.join(projectDir, "App_Resources") + }; + const blacklistArray: string[] = ["blacklisted1", "blacklisted2"]; + const whitelistArray: string[] = ["whitelisted1", "whitelisted2"]; + const appResourcesNativeApiUsageFilePath = path.join(projectData.appResourcesDirectoryPath, platform, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); + const pluginPlatformsDir = path.join("pluginDir", platform); + const pluginNativeApiUsageFilePath = path.join(pluginPlatformsDir, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); + const pluginsUses: string[] = ["whitelisted1", "pluginUses1", "pluginUses2"]; + + const createTestInjector = (input?: { hasPlugins: boolean }): IInjector => { + const testInjector = new Yok(); + testInjector.register("logger", LoggerStub); + testInjector.register("fs", FileSystemStub); + testInjector.register("pluginsService", { + getAllProductionPlugins: (prjData: IProjectData, dependencies?: IDependencyData[]): IPluginData[] => { + const plugins = !!(input && input.hasPlugins) ? [ + { + pluginPlatformsFolderPath: (pl: string) => pluginPlatformsDir + } + ] : []; + + return plugins; + } + }); + testInjector.register("mobileHelper", { + normalizePlatformName: (pl: string) => pl + }); + testInjector.register("platformsDataService", { + getPlatformData: (pl: string, prjData: IProjectData): IPlatformData => ({ projectRoot }) + }); + return testInjector; + }; + + describe("generateMetadataFilters", () => { + const mockFs = (input: { testInjector: IInjector, readJsonData?: any, writeFileAction?: (filePath: string, data: string) => void, existingFiles?: any[] }): { fs: FileSystemStub, dataWritten: IDictionary } => { + const fs = input.testInjector.resolve("fs"); + const dataWritten: IDictionary = {}; + + if (input.writeFileAction) { + fs.writeFile = (filePath: string, data: string) => input.writeFileAction(filePath, data); + } else { + fs.writeFile = (filePath: string, data: string) => dataWritten[filePath] = data; + } + + if (input.readJsonData) { + fs.readJson = (filePath: string) => input.readJsonData[filePath]; + } + + if (input.existingFiles) { + fs.exists = (filePath: string) => input.existingFiles.indexOf(filePath) !== -1; + } + + return { fs, dataWritten }; + }; + + it("deletes previously generated files for metadata filtering", () => { + const testInjector = createTestInjector(); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { fs } = mockFs({ + testInjector, writeFileAction: (filePath: string, data: string) => { + throw new Error(`No data should be written when the ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} does not exist in App_Resource/`); + } + }); + + metadataFilteringService.generateMetadataFilters(projectData, platform); + + const expectedDeletedFiles = [ + path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME), + path.join(projectRoot, MetadataFilteringConstants.BLACKLIST_FILE_NAME) + ]; + assert.deepEqual(fs.deletedFiles, expectedDeletedFiles); + }); + + it(`generates ${MetadataFilteringConstants.BLACKLIST_FILE_NAME} when the file ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} exists in App_Resources/`, () => { + const testInjector = createTestInjector(); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { dataWritten } = mockFs({ + testInjector, + existingFiles: [appResourcesNativeApiUsageFilePath], + readJsonData: { [`${appResourcesNativeApiUsageFilePath}`]: { blacklist: blacklistArray } } + }); + + metadataFilteringService.generateMetadataFilters(projectData, platform); + + assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.BLACKLIST_FILE_NAME)]: blacklistArray.join(EOL) }); + }); + + it(`generates ${MetadataFilteringConstants.WHITELIST_FILE_NAME} when the file ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} exists in App_Resources/`, () => { + const testInjector = createTestInjector(); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { dataWritten } = mockFs({ + testInjector, + existingFiles: [appResourcesNativeApiUsageFilePath], + readJsonData: { [`${appResourcesNativeApiUsageFilePath}`]: { whitelist: whitelistArray } }, + }); + + metadataFilteringService.generateMetadataFilters(projectData, platform); + assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: whitelistArray.join(EOL) }); + }); + + it(`generates ${MetadataFilteringConstants.WHITELIST_FILE_NAME} with content from plugins when the file ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} exists in App_Resources/ and whitelist-plugins-usages is true`, () => { + const testInjector = createTestInjector({ hasPlugins: true }); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { dataWritten } = mockFs({ + testInjector, + existingFiles: [appResourcesNativeApiUsageFilePath, pluginNativeApiUsageFilePath], + readJsonData: { + [`${appResourcesNativeApiUsageFilePath}`]: { ["whitelist-plugins-usages"]: true }, + [`${pluginNativeApiUsageFilePath}`]: { uses: whitelistArray } + }, + }); + + metadataFilteringService.generateMetadataFilters(projectData, platform); + assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: whitelistArray.join(EOL) }); + }); + + it(`generates all files when both plugins and applications filters are included`, () => { + const testInjector = createTestInjector({ hasPlugins: true }); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { dataWritten } = mockFs({ + testInjector, + existingFiles: [appResourcesNativeApiUsageFilePath, pluginNativeApiUsageFilePath], + readJsonData: { + [`${appResourcesNativeApiUsageFilePath}`]: { + whitelist: whitelistArray, + blacklist: blacklistArray, + ["whitelist-plugins-usages"]: true + }, + [`${pluginNativeApiUsageFilePath}`]: { uses: pluginsUses } + }, + }); + + metadataFilteringService.generateMetadataFilters(projectData, platform); + const expectedWhitelist = [ + "pluginUses1", + "pluginUses2", + ...whitelistArray + ].join(EOL); + + assert.deepEqual(dataWritten, { + [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: expectedWhitelist, + [path.join(projectRoot, MetadataFilteringConstants.BLACKLIST_FILE_NAME)]: blacklistArray.join(EOL) + }); + }); + + it(`skips plugins ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} files when whitelist-plugins-usages in App_Resources is false`, () => { + const testInjector = createTestInjector({ hasPlugins: true }); + const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); + const { dataWritten } = mockFs({ + testInjector, + existingFiles: [appResourcesNativeApiUsageFilePath, pluginNativeApiUsageFilePath], + readJsonData: { + [`${appResourcesNativeApiUsageFilePath}`]: { + whitelist: whitelistArray, + blacklist: blacklistArray, + ["whitelist-plugins-usages"]: false + }, + [`${pluginNativeApiUsageFilePath}`]: { uses: pluginsUses } + }, + }); + + metadataFilteringService.generateMetadataFilters(projectData, "platform"); + const expectedWhitelist = [ + ...whitelistArray + ].join(EOL); + + assert.deepEqual(dataWritten, { + [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: expectedWhitelist, + [path.join(projectRoot, MetadataFilteringConstants.BLACKLIST_FILE_NAME)]: blacklistArray.join(EOL) + }); + }); + }); +}); diff --git a/test/stubs.ts b/test/stubs.ts index af3d18a719..9dc2649398 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -46,6 +46,7 @@ export class LoggerStub implements ILogger { export class FileSystemStub implements IFileSystem { public fsStatCache: IDictionary = {}; + public deletedFiles: string[] = []; deleteDirectorySafe(directory: string): void { return this.deleteDirectory(directory); } @@ -62,10 +63,12 @@ export class FileSystemStub implements IFileSystem { } deleteFile(path: string): void { + this.deletedFiles.push(path); return undefined; } deleteDirectory(directory: string): void { + this.deletedFiles.push(directory); return undefined; } From 46f5b91b9c48d4994c19cd3f622610a6148c6064 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 22 Jan 2020 16:29:20 +0200 Subject: [PATCH 2/2] chore: add comments when generating whitelist.mdg Add comments from where is each line in whitelist.mdg file. --- lib/definitions/metadata-filtering-service.ts | 2 +- lib/services/metadata-filtering-service.ts | 22 ++++++++++--- test/services/metadata-filtering-service.ts | 33 ++++++++++++------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/definitions/metadata-filtering-service.ts b/lib/definitions/metadata-filtering-service.ts index 269ba87578..bacc7d38f1 100644 --- a/lib/definitions/metadata-filtering-service.ts +++ b/lib/definitions/metadata-filtering-service.ts @@ -1,5 +1,5 @@ /** - * Describes the content of the native-api-usage.json file located in `/ directory. + * Describes service used to generate necessary files to filter the native metadata generation. */ interface INativeApiUsageConfiguartion { /** diff --git a/lib/services/metadata-filtering-service.ts b/lib/services/metadata-filtering-service.ts index 2de2dfb6c0..dbc3fb2a61 100644 --- a/lib/services/metadata-filtering-service.ts +++ b/lib/services/metadata-filtering-service.ts @@ -29,16 +29,28 @@ export class MetadataFilteringService implements IMetadataFilteringService { const pathToPluginsMetadataConfig = path.join(pathToPlatformsDir, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); if (this.$fs.exists(pathToPluginsMetadataConfig)) { const pluginConfig: INativeApiUsagePluginConfiguration = this.$fs.readJson(pathToPluginsMetadataConfig) || {}; - this.$logger.trace(`Adding content of ${pathToPluginsMetadataConfig} to whitelisted items of metadata filtering.`); - whitelistedItems.push(...(pluginConfig.uses || [])); + this.$logger.trace(`Adding content of ${pathToPluginsMetadataConfig} to whitelisted items of metadata filtering: ${JSON.stringify(pluginConfig, null, 2)}`); + const itemsToAdd = pluginConfig.uses || []; + if (itemsToAdd.length) { + whitelistedItems.push(`// Added from: ${pathToPluginsMetadataConfig}`); + whitelistedItems.push(...itemsToAdd); + whitelistedItems.push(`// Finished part from ${pathToPluginsMetadataConfig}${os.EOL}`); + } } } } - whitelistedItems.push(...(nativeApiConfiguration.whitelist || [])); + const applicationWhitelistedItems = nativeApiConfiguration.whitelist || []; + if (applicationWhitelistedItems.length) { + this.$logger.trace(`Adding content from application to whitelisted items of metadata filtering: ${JSON.stringify(applicationWhitelistedItems, null, 2)}`); + + whitelistedItems.push(`// Added from application`); + whitelistedItems.push(...applicationWhitelistedItems); + whitelistedItems.push(`// Finished part from application${os.EOL}`); + } if (whitelistedItems.length) { - this.$fs.writeFile(pathToWhitelistFile, _.uniq(whitelistedItems).sort().join(os.EOL)); + this.$fs.writeFile(pathToWhitelistFile, whitelistedItems.join(os.EOL)); } } } @@ -53,7 +65,7 @@ export class MetadataFilteringService implements IMetadataFilteringService { const blacklistedItems: string[] = nativeApiConfiguration.blacklist || []; if (blacklistedItems.length) { - this.$fs.writeFile(pathToBlacklistFile, _.uniq(blacklistedItems).sort().join(os.EOL)); + this.$fs.writeFile(pathToBlacklistFile, blacklistedItems.join(os.EOL)); } } else { this.$logger.trace(`There's no application configuration for metadata filtering for platform ${platform}. Full metadata will be generated.`); diff --git a/test/services/metadata-filtering-service.ts b/test/services/metadata-filtering-service.ts index 05e8a3cf47..191594ffb9 100644 --- a/test/services/metadata-filtering-service.ts +++ b/test/services/metadata-filtering-service.ts @@ -18,7 +18,7 @@ describe("metadataFilteringService", () => { const appResourcesNativeApiUsageFilePath = path.join(projectData.appResourcesDirectoryPath, platform, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); const pluginPlatformsDir = path.join("pluginDir", platform); const pluginNativeApiUsageFilePath = path.join(pluginPlatformsDir, MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME); - const pluginsUses: string[] = ["whitelisted1", "pluginUses1", "pluginUses2"]; + const pluginsUses: string[] = ["pluginUses1", "pluginUses2"]; const createTestInjector = (input?: { hasPlugins: boolean }): IInjector => { const testInjector = new Yok(); @@ -98,6 +98,23 @@ describe("metadataFilteringService", () => { assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.BLACKLIST_FILE_NAME)]: blacklistArray.join(EOL) }); }); + const getExpectedWhitelistContent = (input: { applicationWhitelist?: string[], pluginWhitelist?: string[] }): string => { + let finalContent = ""; + if (input.pluginWhitelist) { + finalContent += `// Added from: ${pluginNativeApiUsageFilePath}${EOL}${input.pluginWhitelist.join(EOL)}${EOL}// Finished part from ${pluginNativeApiUsageFilePath}${EOL}`; + } + + if (input.applicationWhitelist) { + if (finalContent !== "") { + finalContent += EOL; + } + + finalContent += `// Added from application${EOL}${input.applicationWhitelist.join(EOL)}${EOL}// Finished part from application${EOL}`; + } + + return finalContent; + }; + it(`generates ${MetadataFilteringConstants.WHITELIST_FILE_NAME} when the file ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} exists in App_Resources/`, () => { const testInjector = createTestInjector(); const metadataFilteringService: IMetadataFilteringService = testInjector.resolve(MetadataFilteringService); @@ -108,7 +125,7 @@ describe("metadataFilteringService", () => { }); metadataFilteringService.generateMetadataFilters(projectData, platform); - assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: whitelistArray.join(EOL) }); + assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: getExpectedWhitelistContent({ applicationWhitelist: whitelistArray }) }); }); it(`generates ${MetadataFilteringConstants.WHITELIST_FILE_NAME} with content from plugins when the file ${MetadataFilteringConstants.NATIVE_API_USAGE_FILE_NAME} exists in App_Resources/ and whitelist-plugins-usages is true`, () => { @@ -124,7 +141,7 @@ describe("metadataFilteringService", () => { }); metadataFilteringService.generateMetadataFilters(projectData, platform); - assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: whitelistArray.join(EOL) }); + assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: getExpectedWhitelistContent({ pluginWhitelist: whitelistArray }) }); }); it(`generates all files when both plugins and applications filters are included`, () => { @@ -144,11 +161,7 @@ describe("metadataFilteringService", () => { }); metadataFilteringService.generateMetadataFilters(projectData, platform); - const expectedWhitelist = [ - "pluginUses1", - "pluginUses2", - ...whitelistArray - ].join(EOL); + const expectedWhitelist = getExpectedWhitelistContent({ pluginWhitelist: pluginsUses, applicationWhitelist: whitelistArray }); assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: expectedWhitelist, @@ -173,9 +186,7 @@ describe("metadataFilteringService", () => { }); metadataFilteringService.generateMetadataFilters(projectData, "platform"); - const expectedWhitelist = [ - ...whitelistArray - ].join(EOL); + const expectedWhitelist = getExpectedWhitelistContent({ applicationWhitelist: whitelistArray }); assert.deepEqual(dataWritten, { [path.join(projectRoot, MetadataFilteringConstants.WHITELIST_FILE_NAME)]: expectedWhitelist,