Loading tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +53 −25 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import com.github.javaparser.ast.CompilationUnit import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.OutputStream import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.jar.JarOutputStream Loading @@ -42,9 +43,10 @@ object ProtoLogTool { } private fun processClasses(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val out = FileOutputStream(command.outputSourceJarArg) val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val out = injector.fileOutputStream(command.outputSourceJarArg) val outJar = JarOutputStream(out) val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, command.protoLogGroupsClassNameArg, groups) Loading @@ -56,18 +58,18 @@ object ProtoLogTool { val transformer = SourceTransformer(command.protoLogImplClassNameArg, command.protoLogCacheClassNameArg, processor) val file = File(path) val text = file.readText() val text = injector.readText(file) val outSrc = try { val code = tryParse(text, path) if (containsProtoLogText(text, command.protoLogClassNameArg)) { transformer.processClass(text, path, code) transformer.processClass(text, path, packagePath(file, code), code) } else { text } } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will fail // in a subsequent build step. println("\n${ex.message}\n") injector.reportParseError(ex) text } path to outSrc Loading Loading @@ -142,8 +144,9 @@ ${updates.replaceIndent(" ")} } private fun viewerConf(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, command.protoLogGroupsClassNameArg, groups) val builder = ViewerConfigBuilder(processor) Loading @@ -153,18 +156,15 @@ ${updates.replaceIndent(" ")} command.javaSourceArgs.map { path -> executor.submitCallable { val file = File(path) val text = file.readText() val text = injector.readText(file) if (containsProtoLogText(text, command.protoLogClassNameArg)) { try { val code = tryParse(text, path) val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val newPath = pack.replace('.', '/') + '/' + file.name builder.findLogCalls(code, newPath) builder.findLogCalls(code, path, packagePath(file, code)) } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will fail // in a subsequent build step. println("\n${ex.message}\n") injector.reportParseError(ex) null } } else { Loading @@ -177,11 +177,18 @@ ${updates.replaceIndent(" ")} executor.shutdown() val out = FileOutputStream(command.viewerConfigJsonArg) val out = injector.fileOutputStream(command.viewerConfigJsonArg) out.write(builder.build().toByteArray()) out.close() } private fun packagePath(file: File, code: CompilationUnit): String { val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val packagePath = pack.replace('.', '/') + '/' + file.name return packagePath } private fun read(command: CommandOptions) { LogParser(ViewerConfigParser()) .parse(FileInputStream(command.logProtofileArg), Loading @@ -190,26 +197,47 @@ ${updates.replaceIndent(" ")} @JvmStatic fun main(args: Array<String>) { try { val command = CommandOptions(args) invoke(command) } catch (ex: InvalidCommandException) { println("\n${ex.message}\n") showHelpAndExit() } catch (ex: CodeProcessingException) { println("\n${ex.message}\n") exitProcess(1) } } fun invoke(command: CommandOptions) { StaticJavaParser.setConfiguration(ParserConfiguration().apply { setLanguageLevel(ParserConfiguration.LanguageLevel.RAW) setAttributeComments(false) }) try { val command = CommandOptions(args) when (command.command) { CommandOptions.TRANSFORM_CALLS_CMD -> processClasses(command) CommandOptions.GENERATE_CONFIG_CMD -> viewerConf(command) CommandOptions.READ_LOG_CMD -> read(command) } } catch (ex: InvalidCommandException) { println("\n${ex.message}\n") showHelpAndExit() } catch (ex: CodeProcessingException) { } var injector = object : Injector { override fun fileOutputStream(file: String) = FileOutputStream(file) override fun readText(file: File) = file.readText() override fun readLogGroups(jarPath: String, className: String) = ProtoLogGroupReader().loadFromJar(jarPath, className) override fun reportParseError(ex: ParsingException) { println("\n${ex.message}\n") exitProcess(1) } } interface Injector { fun fileOutputStream(file: String): OutputStream fun readText(file: File): String fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup> fun reportParseError(ex: ParsingException) } } private fun <T> ExecutorService.submitCallable(f: () -> T) = submit(f) Loading tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +10 −5 Original line number Diff line number Diff line Loading @@ -72,7 +72,7 @@ class SourceTransformer( } val ifStmt: IfStmt if (group.enabled) { val hash = CodeUtils.hash(fileName, messageString, level, group) val hash = CodeUtils.hash(packagePath, messageString, level, group) val newCall = call.clone() if (!group.textEnabled) { // Remove message string if text logging is not enabled by default. Loading @@ -97,7 +97,7 @@ class SourceTransformer( if (argTypes.size != call.arguments.size - 2) { throw InvalidProtoLogCallException( "Number of arguments (${argTypes.size} does not mach format" + " string in: $call", ParsingContext(fileName, call)) " string in: $call", ParsingContext(path, call)) } val blockStmt = BlockStmt() if (argTypes.isNotEmpty()) { Loading Loading @@ -214,18 +214,23 @@ class SourceTransformer( StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName) private var processedCode: MutableList<String> = mutableListOf() private var offsets: IntArray = IntArray(0) private var fileName: String = "" /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */ private var path: String = "" /** The path of the file being processed, relative to the root package */ private var packagePath: String = "" fun processClass( code: String, path: String, packagePath: String, compilationUnit: CompilationUnit = StaticJavaParser.parse(code) ): String { fileName = path this.path = path this.packagePath = packagePath processedCode = code.split('\n').toMutableList() offsets = IntArray(processedCode.size) protoLogCallProcessor.process(compilationUnit, this, fileName) protoLogCallProcessor.process(compilationUnit, this, path) return processedCode.joinToString("\n") } } tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt +8 −4 Original line number Diff line number Diff line Loading @@ -46,7 +46,11 @@ class ViewerConfigBuilder( private val statements: MutableMap<Int, LogCall> = mutableMapOf() private val groups: MutableSet<LogGroup> = mutableSetOf() fun findLogCalls(unit: CompilationUnit, fileName: String): List<Pair<LogCall, ParsingContext>> { fun findLogCalls( unit: CompilationUnit, path: String, packagePath: String ): List<Pair<LogCall, ParsingContext>> { val calls = mutableListOf<Pair<LogCall, ParsingContext>>() val visitor = object : ProtoLogCallVisitor { override fun processCall( Loading @@ -55,12 +59,12 @@ class ViewerConfigBuilder( level: LogLevel, group: LogGroup ) { val logCall = LogCall(messageString, level, group, fileName) val context = ParsingContext(fileName, call) val logCall = LogCall(messageString, level, group, packagePath) val context = ParsingContext(path, call) calls.add(logCall to context) } } processor.process(unit, visitor, fileName) processor.process(unit, visitor, path) return calls } Loading tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * 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. */ package com.android.protolog.tool import org.junit.Assert import org.junit.Assert.assertTrue import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File import java.io.FileNotFoundException import java.io.OutputStream import java.util.jar.JarInputStream class EndToEndTest { @Test fun e2e_transform() { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.server.protolog.common.ProtoLog; import static com.android.server.wm.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", "--protolog-class", "com.android.server.protolog.common.ProtoLog", "--protolog-impl-class", "com.android.server.protolog.ProtoLogImpl", "--protolog-cache-class", "com.android.server.protolog.ProtoLog${"\$\$"}Cache", "--loggroups-class", "com.android.server.wm.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) ) val outSrcJar = assertLoadSrcJar(output, "out.srcjar") assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!) } @Test fun e2e_viewerConfig() { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.server.protolog.common.ProtoLog; import static com.android.server.wm.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", "--protolog-class", "com.android.server.protolog.common.ProtoLog", "--loggroups-class", "com.android.server.wm.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-conf", "out.json", "frameworks/base/org/example/Example.java")) ) val viewerConfigJson = assertLoadText(output, "out.json") assertTrue("\"2066303299\"" in viewerConfigJson) } private fun assertLoadSrcJar( outputs: Map<String, ByteArray>, path: String ): Map<String, String> { val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") val sources = mutableMapOf<String, String>() JarInputStream(ByteArrayInputStream(out)).use { jarStream -> var entry = jarStream.nextJarEntry while (entry != null) { if (entry.name.endsWith(".java")) { sources[entry.name] = jarStream.reader().readText() } entry = jarStream.nextJarEntry } } return sources } private fun assertLoadText(outputs: Map<String, ByteArray>, path: String): String { val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") return out.toString(Charsets.UTF_8) } fun run( src: Pair<String, String>, logGroup: LogGroup, commandOptions: CommandOptions ): Map<String, ByteArray> { val outputs = mutableMapOf<String, ByteArrayOutputStream>() ProtoLogTool.injector = object : ProtoLogTool.Injector { override fun fileOutputStream(file: String): OutputStream = ByteArrayOutputStream().also { outputs[file] = it } override fun readText(file: File): String { if (file.path == src.first) { return src.second } throw FileNotFoundException("expected: ${src.first}, but was $file") } override fun readLogGroups(jarPath: String, className: String) = mapOf( logGroup.name to logGroup) override fun reportParseError(ex: ParsingException) = throw AssertionError(ex) } ProtoLogTool.invoke(commandOptions) return outputs.mapValues { it.value.toByteArray() } } fun fail(message: String): Nothing = Assert.fail(message) as Nothing } tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +8 −8 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -228,7 +228,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -266,7 +266,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -303,7 +303,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -337,7 +337,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -375,7 +375,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -413,7 +413,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading @@ -439,7 +439,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading
tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +53 −25 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import com.github.javaparser.ast.CompilationUnit import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.OutputStream import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.jar.JarOutputStream Loading @@ -42,9 +43,10 @@ object ProtoLogTool { } private fun processClasses(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val out = FileOutputStream(command.outputSourceJarArg) val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val out = injector.fileOutputStream(command.outputSourceJarArg) val outJar = JarOutputStream(out) val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, command.protoLogGroupsClassNameArg, groups) Loading @@ -56,18 +58,18 @@ object ProtoLogTool { val transformer = SourceTransformer(command.protoLogImplClassNameArg, command.protoLogCacheClassNameArg, processor) val file = File(path) val text = file.readText() val text = injector.readText(file) val outSrc = try { val code = tryParse(text, path) if (containsProtoLogText(text, command.protoLogClassNameArg)) { transformer.processClass(text, path, code) transformer.processClass(text, path, packagePath(file, code), code) } else { text } } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will fail // in a subsequent build step. println("\n${ex.message}\n") injector.reportParseError(ex) text } path to outSrc Loading Loading @@ -142,8 +144,9 @@ ${updates.replaceIndent(" ")} } private fun viewerConf(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, command.protoLogGroupsClassNameArg, groups) val builder = ViewerConfigBuilder(processor) Loading @@ -153,18 +156,15 @@ ${updates.replaceIndent(" ")} command.javaSourceArgs.map { path -> executor.submitCallable { val file = File(path) val text = file.readText() val text = injector.readText(file) if (containsProtoLogText(text, command.protoLogClassNameArg)) { try { val code = tryParse(text, path) val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val newPath = pack.replace('.', '/') + '/' + file.name builder.findLogCalls(code, newPath) builder.findLogCalls(code, path, packagePath(file, code)) } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will fail // in a subsequent build step. println("\n${ex.message}\n") injector.reportParseError(ex) null } } else { Loading @@ -177,11 +177,18 @@ ${updates.replaceIndent(" ")} executor.shutdown() val out = FileOutputStream(command.viewerConfigJsonArg) val out = injector.fileOutputStream(command.viewerConfigJsonArg) out.write(builder.build().toByteArray()) out.close() } private fun packagePath(file: File, code: CompilationUnit): String { val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val packagePath = pack.replace('.', '/') + '/' + file.name return packagePath } private fun read(command: CommandOptions) { LogParser(ViewerConfigParser()) .parse(FileInputStream(command.logProtofileArg), Loading @@ -190,26 +197,47 @@ ${updates.replaceIndent(" ")} @JvmStatic fun main(args: Array<String>) { try { val command = CommandOptions(args) invoke(command) } catch (ex: InvalidCommandException) { println("\n${ex.message}\n") showHelpAndExit() } catch (ex: CodeProcessingException) { println("\n${ex.message}\n") exitProcess(1) } } fun invoke(command: CommandOptions) { StaticJavaParser.setConfiguration(ParserConfiguration().apply { setLanguageLevel(ParserConfiguration.LanguageLevel.RAW) setAttributeComments(false) }) try { val command = CommandOptions(args) when (command.command) { CommandOptions.TRANSFORM_CALLS_CMD -> processClasses(command) CommandOptions.GENERATE_CONFIG_CMD -> viewerConf(command) CommandOptions.READ_LOG_CMD -> read(command) } } catch (ex: InvalidCommandException) { println("\n${ex.message}\n") showHelpAndExit() } catch (ex: CodeProcessingException) { } var injector = object : Injector { override fun fileOutputStream(file: String) = FileOutputStream(file) override fun readText(file: File) = file.readText() override fun readLogGroups(jarPath: String, className: String) = ProtoLogGroupReader().loadFromJar(jarPath, className) override fun reportParseError(ex: ParsingException) { println("\n${ex.message}\n") exitProcess(1) } } interface Injector { fun fileOutputStream(file: String): OutputStream fun readText(file: File): String fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup> fun reportParseError(ex: ParsingException) } } private fun <T> ExecutorService.submitCallable(f: () -> T) = submit(f) Loading
tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +10 −5 Original line number Diff line number Diff line Loading @@ -72,7 +72,7 @@ class SourceTransformer( } val ifStmt: IfStmt if (group.enabled) { val hash = CodeUtils.hash(fileName, messageString, level, group) val hash = CodeUtils.hash(packagePath, messageString, level, group) val newCall = call.clone() if (!group.textEnabled) { // Remove message string if text logging is not enabled by default. Loading @@ -97,7 +97,7 @@ class SourceTransformer( if (argTypes.size != call.arguments.size - 2) { throw InvalidProtoLogCallException( "Number of arguments (${argTypes.size} does not mach format" + " string in: $call", ParsingContext(fileName, call)) " string in: $call", ParsingContext(path, call)) } val blockStmt = BlockStmt() if (argTypes.isNotEmpty()) { Loading Loading @@ -214,18 +214,23 @@ class SourceTransformer( StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName) private var processedCode: MutableList<String> = mutableListOf() private var offsets: IntArray = IntArray(0) private var fileName: String = "" /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */ private var path: String = "" /** The path of the file being processed, relative to the root package */ private var packagePath: String = "" fun processClass( code: String, path: String, packagePath: String, compilationUnit: CompilationUnit = StaticJavaParser.parse(code) ): String { fileName = path this.path = path this.packagePath = packagePath processedCode = code.split('\n').toMutableList() offsets = IntArray(processedCode.size) protoLogCallProcessor.process(compilationUnit, this, fileName) protoLogCallProcessor.process(compilationUnit, this, path) return processedCode.joinToString("\n") } }
tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt +8 −4 Original line number Diff line number Diff line Loading @@ -46,7 +46,11 @@ class ViewerConfigBuilder( private val statements: MutableMap<Int, LogCall> = mutableMapOf() private val groups: MutableSet<LogGroup> = mutableSetOf() fun findLogCalls(unit: CompilationUnit, fileName: String): List<Pair<LogCall, ParsingContext>> { fun findLogCalls( unit: CompilationUnit, path: String, packagePath: String ): List<Pair<LogCall, ParsingContext>> { val calls = mutableListOf<Pair<LogCall, ParsingContext>>() val visitor = object : ProtoLogCallVisitor { override fun processCall( Loading @@ -55,12 +59,12 @@ class ViewerConfigBuilder( level: LogLevel, group: LogGroup ) { val logCall = LogCall(messageString, level, group, fileName) val context = ParsingContext(fileName, call) val logCall = LogCall(messageString, level, group, packagePath) val context = ParsingContext(path, call) calls.add(logCall to context) } } processor.process(unit, visitor, fileName) processor.process(unit, visitor, path) return calls } Loading
tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt 0 → 100644 +144 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * 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. */ package com.android.protolog.tool import org.junit.Assert import org.junit.Assert.assertTrue import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File import java.io.FileNotFoundException import java.io.OutputStream import java.util.jar.JarInputStream class EndToEndTest { @Test fun e2e_transform() { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.server.protolog.common.ProtoLog; import static com.android.server.wm.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", "--protolog-class", "com.android.server.protolog.common.ProtoLog", "--protolog-impl-class", "com.android.server.protolog.ProtoLogImpl", "--protolog-cache-class", "com.android.server.protolog.ProtoLog${"\$\$"}Cache", "--loggroups-class", "com.android.server.wm.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) ) val outSrcJar = assertLoadSrcJar(output, "out.srcjar") assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!) } @Test fun e2e_viewerConfig() { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.server.protolog.common.ProtoLog; import static com.android.server.wm.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", "--protolog-class", "com.android.server.protolog.common.ProtoLog", "--loggroups-class", "com.android.server.wm.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-conf", "out.json", "frameworks/base/org/example/Example.java")) ) val viewerConfigJson = assertLoadText(output, "out.json") assertTrue("\"2066303299\"" in viewerConfigJson) } private fun assertLoadSrcJar( outputs: Map<String, ByteArray>, path: String ): Map<String, String> { val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") val sources = mutableMapOf<String, String>() JarInputStream(ByteArrayInputStream(out)).use { jarStream -> var entry = jarStream.nextJarEntry while (entry != null) { if (entry.name.endsWith(".java")) { sources[entry.name] = jarStream.reader().readText() } entry = jarStream.nextJarEntry } } return sources } private fun assertLoadText(outputs: Map<String, ByteArray>, path: String): String { val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") return out.toString(Charsets.UTF_8) } fun run( src: Pair<String, String>, logGroup: LogGroup, commandOptions: CommandOptions ): Map<String, ByteArray> { val outputs = mutableMapOf<String, ByteArrayOutputStream>() ProtoLogTool.injector = object : ProtoLogTool.Injector { override fun fileOutputStream(file: String): OutputStream = ByteArrayOutputStream().also { outputs[file] = it } override fun readText(file: File): String { if (file.path == src.first) { return src.second } throw FileNotFoundException("expected: ${src.first}, but was $file") } override fun readLogGroups(jarPath: String, className: String) = mapOf( logGroup.name to logGroup) override fun reportParseError(ex: ParsingException) = throw AssertionError(ex) } ProtoLogTool.invoke(commandOptions) return outputs.mapValues { it.value.toByteArray() } } fun fail(message: String): Nothing = Assert.fail(message) as Nothing }
tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +8 −8 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -228,7 +228,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -266,7 +266,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -303,7 +303,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -337,7 +337,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -375,7 +375,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading Loading @@ -413,7 +413,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading @@ -439,7 +439,7 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) Loading