diff --git a/lib/common b/lib/common index ca950f50d2..2464b26584 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit ca950f50d2be2f4c64b053b559effefe8a4eb406 +Subproject commit 2464b2658408c55ae7ecfd5a8a3dd95e4dfcc0c1 diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index bc9f9809b8..3221dc3002 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -125,7 +125,7 @@ interface IPlatformService extends IBuildPlatformAction, NodeJS.EventEmitter { * @param {IProjectData} projectData DTO with information about the project. * @returns {void} */ - startApplication(platform: string, runOptions: IRunPlatformOptions, projectId: string): Promise; + startApplication(platform: string, runOptions: IRunPlatformOptions, appData: Mobile.IApplicationData): Promise; cleanDestinationApp(platformInfo: IPreparePlatformInfo): Promise; validatePlatformInstalled(platform: string, projectData: IProjectData): void; diff --git a/lib/helpers/livesync-command-helper.ts b/lib/helpers/livesync-command-helper.ts index ad917887d9..a98f6d36ba 100644 --- a/lib/helpers/livesync-command-helper.ts +++ b/lib/helpers/livesync-command-helper.ts @@ -151,7 +151,7 @@ export class LiveSyncCommandHelper implements ILiveSyncCommandHelper { }; await this.$platformService.deployPlatform(deployPlatformInfo); - await this.$platformService.startApplication(currentPlatform, runPlatformOptions, this.$projectData.projectId); + await this.$platformService.startApplication(currentPlatform, runPlatformOptions, { appId: this.$projectData.projectId, projectName: this.$projectData.projectName }); this.$platformService.trackProjectType(this.$projectData); } } diff --git a/lib/services/android-debug-service.ts b/lib/services/android-debug-service.ts index a161179e93..1ce131a110 100644 --- a/lib/services/android-debug-service.ts +++ b/lib/services/android-debug-service.ts @@ -13,7 +13,8 @@ export class AndroidDebugService extends DebugServiceBase implements IPlatformDe private $logger: ILogger, private $androidDeviceDiscovery: Mobile.IDeviceDiscovery, private $androidProcessService: Mobile.IAndroidProcessService, - private $net: INet) { + private $net: INet, + private $projectDataService: IProjectDataService) { super(device, $devicesService); } @@ -26,7 +27,13 @@ export class AndroidDebugService extends DebugServiceBase implements IPlatformDe public async debugStart(debugData: IDebugData, debugOptions: IDebugOptions): Promise { await this.$devicesService.initialize({ platform: this.platform, deviceId: debugData.deviceIdentifier }); - const action = (device: Mobile.IAndroidDevice): Promise => this.debugStartCore(debugData.applicationIdentifier, debugOptions); + const projectData = this.$projectDataService.getProjectData(debugData.projectDir); + const appData: Mobile.IApplicationData = { + appId: debugData.applicationIdentifier, + projectName: projectData.projectName + }; + + const action = (device: Mobile.IAndroidDevice): Promise => this.debugStartCore(appData, debugOptions); await this.$devicesService.execute(action, this.getCanExecuteAction(debugData.deviceIdentifier)); } @@ -91,23 +98,29 @@ export class AndroidDebugService extends DebugServiceBase implements IPlatformDe await this.$devicesService.initialize({ platform: this.platform, deviceId: debugData.deviceIdentifier }); - const action = (device: Mobile.IAndroidDevice): Promise => this.debugCore(device, packageFile, debugData.applicationIdentifier, debugOptions); + const projectName = this.$projectDataService.getProjectData(debugData.projectDir).projectName; + const appData: Mobile.IApplicationData = { + appId: debugData.applicationIdentifier, + projectName + }; + + const action = (device: Mobile.IAndroidDevice): Promise => this.debugCore(device, packageFile, appData, debugOptions); const deviceActionResult = await this.$devicesService.execute(action, this.getCanExecuteAction(debugData.deviceIdentifier)); return deviceActionResult[0].result; } - private async debugCore(device: Mobile.IAndroidDevice, packageFile: string, packageName: string, debugOptions: IDebugOptions): Promise { - await this.printDebugPort(device.deviceInfo.identifier, packageName); + private async debugCore(device: Mobile.IAndroidDevice, packageFile: string, appData: Mobile.IApplicationData, debugOptions: IDebugOptions): Promise { + await this.printDebugPort(device.deviceInfo.identifier, appData.appId); if (debugOptions.start) { - return await this.attachDebugger(device.deviceInfo.identifier, packageName, debugOptions); + return await this.attachDebugger(device.deviceInfo.identifier, appData.appId, debugOptions); } else if (debugOptions.stop) { await this.removePortForwarding(); return null; } else { - await this.debugStartCore(packageName, debugOptions); - return await this.attachDebugger(device.deviceInfo.identifier, packageName, debugOptions); + await this.debugStartCore(appData, debugOptions); + return await this.attachDebugger(device.deviceInfo.identifier, appData.appId, debugOptions); } } @@ -126,22 +139,21 @@ export class AndroidDebugService extends DebugServiceBase implements IPlatformDe return this.getChromeDebugUrl(debugOptions, port); } - private async debugStartCore(packageName: string, debugOptions: IDebugOptions): Promise { + private async debugStartCore(appData: Mobile.IApplicationData, debugOptions: IDebugOptions): Promise { // Arguments passed to executeShellCommand must be in array ([]), but it turned out adb shell "arg with intervals" still works correctly. // As we need to redirect output of a command on the device, keep using only one argument. // We could rewrite this with two calls - touch and rm -f , but -f flag is not available on old Android, so rm call will fail when file does not exist. - - await this.device.applicationManager.stopApplication(packageName); + await this.device.applicationManager.stopApplication(appData); if (debugOptions.debugBrk) { - await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${packageName}-debugbreak`]); + await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${appData.appId}-debugbreak`]); } - await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${packageName}-debugger-started`]); + await this.device.adb.executeShellCommand([`cat /dev/null > /data/local/tmp/${appData.appId}-debugger-started`]); - await this.device.applicationManager.startApplication(packageName); + await this.device.applicationManager.startApplication(appData); - await this.waitForDebugger(packageName); + await this.waitForDebugger(appData.appId); } private async waitForDebugger(packageName: String): Promise { diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 28fbdc643d..c2ff8c6226 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -33,7 +33,8 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS private $iOSSocketRequestExecutor: IiOSSocketRequestExecutor, private $processService: IProcessService, private $socketProxyFactory: ISocketProxyFactory, - private $net: INet) { + private $net: INet, + private $projectDataService: IProjectDataService) { super(device, $devicesService); this.$processService.attachToProcessExitSignals(this, this.debugStop); this.$socketProxyFactory.on(CONNECTION_ERROR_EVENT_NAME, (e: Error) => this.emit(CONNECTION_ERROR_EVENT_NAME, e)); @@ -173,6 +174,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS private async deviceDebugBrk(debugData: IDebugData, debugOptions: IDebugOptions): Promise { await this.$devicesService.initialize({ platform: this.platform, deviceId: debugData.deviceIdentifier }); + const projectData = this.$projectDataService.getProjectData(debugData.projectDir); const action = async (device: iOSDevice.IOSDevice): Promise => { if (device.isEmulator) { return await this.emulatorDebugBrk(debugData, debugOptions); @@ -185,7 +187,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS }; const promisesResults = await Promise.all([ - this.$platformService.startApplication(this.platform, runOptions, debugData.applicationIdentifier), + this.$platformService.startApplication(this.platform, runOptions, { appId: debugData.applicationIdentifier, projectName: projectData.projectName }), this.debugBrkCore(device, debugData, debugOptions) ]); diff --git a/lib/services/ios-log-filter.ts b/lib/services/ios-log-filter.ts index f8f965cbbe..e9c7d77b86 100644 --- a/lib/services/ios-log-filter.ts +++ b/lib/services/ios-log-filter.ts @@ -1,65 +1,88 @@ const sourcemap = require("source-map"); import * as path from "path"; import { cache } from "../common/decorators"; -import * as iOSLogFilterBase from "../common/mobile/ios/ios-log-filter"; -export class IOSLogFilter extends iOSLogFilterBase.IOSLogFilter implements Mobile.IPlatformLogFilter { - protected infoFilterRegex = /^.*?((?::)?.*?(((?:CONSOLE|JS) (?:LOG|ERROR)).*?))$/im; +export class IOSLogFilter implements Mobile.IPlatformLogFilter { + // Used to recognize output related to the current project + // This looks for artifacts like: AppName[22432] or AppName(SomeTextHere)[23123] + private appOutputRegex: RegExp = /([^\s\(\)]+)(?:\([^\s]+\))?\[[0-9]+\]/; + + // Used to trim the passed messages to a simpler output + // Example: + // This: "May 24 15:54:52 Dragons-iPhone NativeScript250(NativeScript)[356] : CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE:" + // Becomes: CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE: + protected infoFilterRegex = new RegExp(`^.*(?::|:|:|\\(NativeScript\\)|${this.appOutputRegex.source}:){1}`); + + private filterActive: boolean = true; private partialLine: string = null; - constructor($loggingLevels: Mobile.ILoggingLevels, + constructor(private $logger: ILogger, + private $loggingLevels: Mobile.ILoggingLevels, private $fs: IFileSystem, private $projectData: IProjectData) { - super($loggingLevels); } - public filterData(data: string, logLevel: string, pid?: string): string { - data = super.filterData(data, logLevel, pid); - if (pid && data && data.indexOf(`[${pid}]`) === -1) { - return null; + public filterData(data: string, loggingOptions: Mobile.IDeviceLogOptions = {}): string { + const specifiedLogLevel = (loggingOptions.logLevel || '').toUpperCase(); + this.$logger.trace("Logging options", loggingOptions); + + if (specifiedLogLevel !== this.$loggingLevels.info || !data) { + return data; } - if (data) { - const skipLastLine = data[data.length - 1] !== "\n"; - const lines = data.split("\n"); - let result = ""; - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - if (i === 0 && this.partialLine) { - line = this.partialLine + line; - this.partialLine = null; - } - if (line.length < 1 || - line.indexOf("SecTaskCopyDebugDescription") !== -1 || - line.indexOf("NativeScript loaded bundle") !== -1 || - (line.indexOf("assertion failed:") !== -1 && data.indexOf("libxpc.dylib") !== -1)) { - continue; - } - // CONSOLE LOG messages comme in the following form: - // [pid] CONSOLE LOG file:///location:row:column: - // This code removes unnecessary information from log messages. The output looks like: - // CONSOLE LOG file:///location:row:column: - if (pid) { - if (line.indexOf(`[${pid}]: `) !== -1) { - const pidRegex = new RegExp(`^.*\\[${pid}\\]:\\s(?:\\(NativeScript\\)\\s)?`); - line = line.replace(pidRegex, "").trim(); - this.getOriginalFileLocation(line); - result += this.getOriginalFileLocation(line) + "\n"; - } + const chunkLines = data.split('\n'); + const skipLastLine = chunkLines.length > 0 ? data[data.length - 1] !== "\n" : false; + let output = ""; + for (let i = 0; i < chunkLines.length; i++) { + let currentLine = chunkLines[i]; - continue; - } - if (skipLastLine && i === lines.length - 1 && lines.length > 1) { - this.partialLine = line; - } else { - result += this.getOriginalFileLocation(line) + "\n"; - } + if (this.partialLine) { + currentLine = this.partialLine + currentLine; + this.partialLine = undefined; + } + + if (i === chunkLines.length - 1 && skipLastLine) { + this.partialLine = currentLine; + break; + } + + // Legacy filter moved to preFilter + if (this.preFilter(data, currentLine)) { + continue; + } + + const matchResult = this.appOutputRegex.exec(currentLine); + + if (matchResult && matchResult.length > 1) { + // Check if the name of the app equals the name of the CLI project and turn on the filter if not. + // We call initializeProjectData in order to obtain the current project name as the instance + // of this filter may be used accross multiple projects. + const projectName = loggingOptions && loggingOptions.projectName; + this.filterActive = matchResult[1] !== projectName; + } + + if (this.filterActive) { + continue; } - return result; + + const filteredLineInfo = currentLine.match(this.infoFilterRegex); + if (filteredLineInfo && filteredLineInfo.length > 0) { + currentLine = currentLine.replace(filteredLineInfo[0], ""); + } + + currentLine = currentLine.trim(); + output += this.getOriginalFileLocation(currentLine) + '\n'; } - return data; + return output.length === 0 ? null : output; + } + + private preFilter(data: string, currentLine: string): boolean { + return currentLine.length < 1 || + currentLine.indexOf("SecTaskCopyDebugDescription") !== -1 || + currentLine.indexOf("NativeScript loaded bundle") !== -1 || + (currentLine.indexOf("assertion failed:") !== -1 && data.indexOf("libxpc.dylib") !== -1); } private getOriginalFileLocation(data: string): string { diff --git a/lib/services/livesync/android-device-livesync-service.ts b/lib/services/livesync/android-device-livesync-service.ts index b19cc0d7ad..f78fcf38b3 100644 --- a/lib/services/livesync/android-device-livesync-service.ts +++ b/lib/services/livesync/android-device-livesync-service.ts @@ -42,7 +42,7 @@ export class AndroidDeviceLiveSyncService extends DeviceLiveSyncServiceBase impl (localToDevicePath: Mobile.ILocalToDevicePathData) => !this.canExecuteFastSync(localToDevicePath.getLocalPath(), projectData, this.device.deviceInfo.platform)); if (!canExecuteFastSync) { - return this.restartApplication(deviceAppData); + return this.restartApplication(deviceAppData, projectData.projectName); } } @@ -57,12 +57,12 @@ export class AndroidDeviceLiveSyncService extends DeviceLiveSyncServiceBase impl await this.$mobileHelper.buildDevicePath(deviceRootPath, LiveSyncPaths.REMOVEDSYNC_DIR_NAME)]); } - private async restartApplication(deviceAppData: Mobile.IDeviceAppData): Promise { + private async restartApplication(deviceAppData: Mobile.IDeviceAppData, projectName: string): Promise { const devicePathRoot = `/data/data/${deviceAppData.appIdentifier}/files`; const devicePath = this.$mobileHelper.buildDevicePath(devicePathRoot, "code_cache", "secondary_dexes", "proxyThumb"); await this.device.adb.executeShellCommand(["rm", "-rf", devicePath]); - await this.device.applicationManager.restartApplication(deviceAppData.appIdentifier); + await this.device.applicationManager.restartApplication({ appId: deviceAppData.appIdentifier, projectName }); } public async beforeLiveSyncAction(deviceAppData: Mobile.IDeviceAppData): Promise { diff --git a/lib/services/livesync/ios-device-livesync-service.ts b/lib/services/livesync/ios-device-livesync-service.ts index 7d177bee42..3626943a75 100644 --- a/lib/services/livesync/ios-device-livesync-service.ts +++ b/lib/services/livesync/ios-device-livesync-service.ts @@ -75,8 +75,8 @@ export class IOSDeviceLiveSyncService extends DeviceLiveSyncServiceBase implemen } } - private async restartApplication(deviceAppData: Mobile.IDeviceAppData, appName: string): Promise { - return this.device.applicationManager.restartApplication(deviceAppData.appIdentifier, appName); + private async restartApplication(deviceAppData: Mobile.IDeviceAppData, projectName: string): Promise { + return this.device.applicationManager.restartApplication({ appId: deviceAppData.appIdentifier, projectName }); } private async reloadPage(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise { diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index 255d6353df..cdf003f603 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -165,7 +165,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi }; try { - await deviceAppData.device.applicationManager.stopApplication(applicationId, projectData.projectName); + await deviceAppData.device.applicationManager.stopApplication({ appId: applicationId, projectName: projectData.projectName }); // Now that we've stopped the application we know it isn't started, so set debugOptions.start to false // so that it doesn't default to true in attachDebugger method debugOptions = debugOptions || {}; diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index e21c12b133..480b8cfd32 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -543,11 +543,11 @@ export class PlatformService extends EventEmitter implements IPlatformService { await this.$devicesService.execute(action, this.getCanExecuteAction(deployInfo.platform, deployInfo.deployOptions)); } - public async startApplication(platform: string, runOptions: IRunPlatformOptions, projectId: string): Promise { + public async startApplication(platform: string, runOptions: IRunPlatformOptions, appData: Mobile.IApplicationData): Promise { this.$logger.out("Starting..."); const action = async (device: Mobile.IDevice) => { - await device.applicationManager.startApplication(projectId); + await device.applicationManager.startApplication(appData); this.$logger.out(`Successfully started on device with identifier '${device.deviceInfo.identifier}'.`); }; diff --git a/test/services/android-debug-service.ts b/test/services/android-debug-service.ts index 478575b9af..7dcfc930bc 100644 --- a/test/services/android-debug-service.ts +++ b/test/services/android-debug-service.ts @@ -11,8 +11,9 @@ class AndroidDebugServiceInheritor extends AndroidDebugService { $logger: ILogger, $androidDeviceDiscovery: Mobile.IDeviceDiscovery, $androidProcessService: Mobile.IAndroidProcessService, - $net: INet) { - super({}, $devicesService, $errors, $logger, $androidDeviceDiscovery, $androidProcessService, $net); + $net: INet, + $projectDataService: IProjectDataService) { + super({}, $devicesService, $errors, $logger, $androidDeviceDiscovery, $androidProcessService, $net, $projectDataService); } public getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string { @@ -28,6 +29,7 @@ const createTestInjector = (): IInjector => { testInjector.register("androidDeviceDiscovery", {}); testInjector.register("androidProcessService", {}); testInjector.register("net", {}); + testInjector.register("projectDataService", {}); return testInjector; }; diff --git a/test/services/ios-debug-service.ts b/test/services/ios-debug-service.ts index 03408bb57b..ca0cc6efca 100644 --- a/test/services/ios-debug-service.ts +++ b/test/services/ios-debug-service.ts @@ -18,9 +18,10 @@ class IOSDebugServiceInheritor extends IOSDebugService { $iOSSocketRequestExecutor: IiOSSocketRequestExecutor, $processService: IProcessService, $socketProxyFactory: ISocketProxyFactory, - $net: INet) { + $net: INet, + $projectDataService: IProjectDataService) { super({}, $devicesService, $platformService, $iOSEmulatorServices, $childProcess, $hostInfo, $logger, $errors, - $npmInstallationManager, $iOSNotification, $iOSSocketRequestExecutor, $processService, $socketProxyFactory, $net); + $npmInstallationManager, $iOSNotification, $iOSSocketRequestExecutor, $processService, $socketProxyFactory, $net, $projectDataService); } public getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string { @@ -54,6 +55,8 @@ const createTestInjector = (): IInjector => { waitForPortToListen: async (opts: { port: number, timeout: number, interval?: number }): Promise => true }); + testInjector.register("projectDataService", {}); + return testInjector; }; diff --git a/test/services/ios-log-filter.ts b/test/services/ios-log-filter.ts index d6d5e4c77f..b091c83f17 100644 --- a/test/services/ios-log-filter.ts +++ b/test/services/ios-log-filter.ts @@ -1,9 +1,10 @@ import { IOSLogFilter } from "../../lib/services/ios-log-filter"; import { Yok } from "../../lib/common/yok"; import { LoggingLevels } from "../../lib/common/mobile/logging-levels"; +import { LoggerStub } from "../stubs"; import * as assert from "assert"; -function createTestInjector(): IInjector { +function createTestInjector(projectName: string): IInjector { const testInjector = new Yok(); testInjector.register("loggingLevels", LoggingLevels); testInjector.register("fs", { @@ -11,9 +12,12 @@ function createTestInjector(): IInjector { }); testInjector.register("projectData", { initializeProjectData: () => { /* empty */ }, - projectDir: "test" + projectDir: "test", + projectName: projectName }); + testInjector.register("logger", LoggerStub); + return testInjector; } @@ -24,6 +28,7 @@ describe("iOSLogFilter", () => { const testData = [ { version: 9, + projectName: "NativeScript250", originalDataArr: [ "May 24 15:54:38 Dragons-iPhone backboardd(BaseBoard)[62] : Unable to bootstrap_look_up port with name .gsEvents: unknown error code (1102)", "May 24 15:54:51 Dragons-iPhone locationd[67] : Client com.apple.springboard disconnected", @@ -45,9 +50,10 @@ describe("iOSLogFilter", () => { null, null, "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3472:32: EXCEPTION: Uncaught (in promise): Error: CUSTOM EXCEPTION", - "CONSOLE LOG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", + null, "" ], + simProjectName: "TestApp", simulator: [ "Aug 22 10:59:20 MCSOFAPPBLD TestApp[52946]: CONSOLE LOG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", "Aug 22 10:59:20 MCSOFAPPBLD TestApp[52946]: CONSOLE DEBUG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", @@ -60,6 +66,7 @@ describe("iOSLogFilter", () => { ] }, { version: 10, + projectName: "NativeScript250", originalDataArr: [ "May 24 15:54:52 Dragons-iPhone apsd(PersistentConnection)[90] : 2017-05-24 15:54:52 +0300 apsd[90]: performing call back", "May 24 15:54:52 Dragons-iPhone NativeScript250(NativeScript)[356] : CONSOLE LOG file:///app/modules/homeView/homeView.component.js:13:24: CUSTOM CONSOLE LOG", @@ -86,20 +93,21 @@ describe("iOSLogFilter", () => { "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3472:32: EXCEPTION: Uncaught (in promise): Error: CUSTOM EXCEPTION", "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE:", "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3478:36: resolvePromise@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:416:40", + "resolvePromise@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:401:31", + "file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:449:31", + "invokeTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:223:42", + "onInvokeTask@file:///app/tns_modules/@angular/core/bundles/core.umd.js:4382:51", + "invokeTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:222:54", + "runTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:123:57", + "drainMicroTaskQueue@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:355:42", + "promiseReactionJob@[native code]", + "UIApplicationMain@[native code]", + "start@file:///app/tns_modules/tns-core-modules/application/application.js:251:26", + "bootstrapApp@file:///app/tns_module", null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "CONSOLE LOG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", "" ], + simProjectName: "TestApp", simulator: [ "Aug 22 10:59:20 MCSOFAPPBLD TestApp[52946]: CONSOLE LOG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", "Aug 22 10:59:20 MCSOFAPPBLD TestApp[52946]: CONSOLE DEBUG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", @@ -113,6 +121,7 @@ describe("iOSLogFilter", () => { }, { version: 11, + projectName: "NativeScript250", originalDataArr: [ "May 24 15:54:52 Dragons-iPhone apsd(PersistentConnection)[90] : 2017-05-24 15:54:52 +0300 apsd[90]: performing call back", "May 24 15:54:52 Dragons-iPhone NativeScript250(NativeScript)[356] : CONSOLE LOG file:///app/modules/homeView/homeView.component.js:13:24: CUSTOM CONSOLE LOG", @@ -139,20 +148,21 @@ describe("iOSLogFilter", () => { "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3472:32: EXCEPTION: Uncaught (in promise): Error: CUSTOM EXCEPTION", "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3477:36: ORIGINAL STACKTRACE:", "CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3478:36: resolvePromise@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:416:40", + "resolvePromise@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:401:31", + "file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:449:31", + "invokeTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:223:42", + "onInvokeTask@file:///app/tns_modules/@angular/core/bundles/core.umd.js:4382:51", + "invokeTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:222:54", + "runTask@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:123:57", + "drainMicroTaskQueue@file:///app/tns_modules/nativescript-angular/zone-js/dist/zone-nativescript.js:355:42", + "promiseReactionJob@[native code]", + "UIApplicationMain@[native code]", + "start@file:///app/tns_modules/tns-core-modules/application/application.js:251:26", + "bootstrapApp@file:///app/tns_module", null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - "CONSOLE LOG file:///app/home/home-view-model.js:6:20: CUSTOM CONSOLE LOG", "" ], + simProjectName: "cliapp", simulator: [ "2017-10-09 13:34:38.527844+0300 localhost cliapp[52946]: (NativeScript) CONSOLE LOG file:///app/main-view-model.js:18:20: Test Console", "2017-10-09 13:34:38.527844+0300 localhost cliapp[52946]: (NativeScript) CONSOLE DEBUG file:///app/main-view-model.js:18:20: Test Console", @@ -168,45 +178,79 @@ describe("iOSLogFilter", () => { const infoLogLevel = "INFO"; const fullLogLevel = "FULL"; - beforeEach(() => { - testInjector = createTestInjector(); - logFilter = testInjector.resolve(IOSLogFilter); - }); - describe("filterData", () => { testData.forEach(data => { + + it(`returns correct data on iOS ${data.version} when data comes in chunks`, () => { + testInjector = createTestInjector(data.projectName); + logFilter = testInjector.resolve(IOSLogFilter); + + let currentStart = 0; + const maxRange = 50; + let output = ""; + const input = data.originalDataArr.join("\n"); + while (true) { + const currentRange = Math.floor(Math.random() * maxRange); + const currentFilterInput = input.substr(currentStart, currentRange); + const tempOutput = logFilter.filterData(currentFilterInput, { logLevel: infoLogLevel, projectName: data.projectName }); + if (tempOutput !== null) { + output += tempOutput; + } + currentStart += currentRange; + if (currentStart === input.length) { + break; + } + currentStart = Math.min(currentStart, input.length); + } + + assert.deepEqual(output, data.infoExpectedArr.filter(item => item !== null).join("\n")); + }); + it(`returns correct data when logLevel is ${fullLogLevel} on iOS ${data.version} and all data is passed at once`, () => { - const actualData = logFilter.filterData(data.originalDataArr.join("\n"), fullLogLevel, null); + testInjector = createTestInjector(data.projectName); + logFilter = testInjector.resolve(IOSLogFilter); + const actualData = logFilter.filterData(data.originalDataArr.join("\n"), { logLevel: fullLogLevel, projectName: data.projectName }); const actualArr = actualData.split("\n").map(line => line.trim()); - const expectedArr = data.originalDataArr.map(line => line.trim()); + const expectedArr = data.originalDataArr.map(line => line.trim()).filter(item => item !== null); assert.deepEqual(actualArr, expectedArr); }); it(`returns correct data when logLevel is ${fullLogLevel} on iOS ${data.version} and data is passed one line at a time`, () => { data.originalDataArr.forEach(line => { - const actualData = logFilter.filterData(line, fullLogLevel, null); + testInjector = createTestInjector(data.projectName); + logFilter = testInjector.resolve(IOSLogFilter); + const actualData = logFilter.filterData(line, { logLevel: fullLogLevel, projectName: data.projectName }); assert.deepEqual(actualData.trim(), line.trim()); }); }); it(`parses data incorrectly when logLevel is ${infoLogLevel} on iOS ${data.version} and all data is passed at once with pid(simulator)`, () => { - const actualData = logFilter.filterData(data.simulator.join("\n"), infoLogLevel, pid); + testInjector = createTestInjector(data.simProjectName); + logFilter = testInjector.resolve(IOSLogFilter); + const actualData = logFilter.filterData(data.simulator.join("\n"), { logLevel: infoLogLevel, projectName: data.simProjectName, applicationPid: pid }); const actualArr = actualData.split("\n").map(line => line.trim()); - assert.deepEqual(actualArr, data.simulatorExpectedArr); + assert.deepEqual(actualArr, data.simulatorExpectedArr.filter(item => item !== null)); }); it(`parses data incorrectly when logLevel is ${infoLogLevel} on iOS ${data.version} and all data is passed at once and pid is available`, () => { - const actualData = logFilter.filterData(data.originalDataArr.join("\n"), infoLogLevel, null); + testInjector = createTestInjector(data.projectName); + logFilter = testInjector.resolve(IOSLogFilter); + const actualData = logFilter.filterData(data.originalDataArr.join("\n"), { logLevel: infoLogLevel, projectName: data.projectName }); const actualArr = actualData.split("\n").map(line => line.trim()); - const expectedArr = ["CONSOLE LOG file:///app/modules/homeView/homeView.component.js:13:24: CUSTOM CONSOLE LOG", ""]; + const expectedArr = data.infoExpectedArr.filter(item => item !== null); assert.deepEqual(actualArr, expectedArr); }); it(`returns correct data when logLevel is ${infoLogLevel} on iOS ${data.version} and data is passed one line at a time`, () => { + testInjector = createTestInjector(data.projectName); + logFilter = testInjector.resolve(IOSLogFilter); data.originalDataArr.forEach((line, index) => { - const actualData = logFilter.filterData(line, infoLogLevel, null); + if (line.length > 0) { + line += "\n"; + } + const actualData = logFilter.filterData(line, { logLevel: infoLogLevel, projectName: data.projectName }); const expectedData = data.infoExpectedArr[index]; - assert.deepEqual(actualData && actualData.trim(), expectedData && expectedData); + assert.equal(actualData && actualData.trim(), expectedData); }); }); });