1 /* <lambda>null2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.protolog.tool 18 19 import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH 20 import com.google.common.truth.Truth 21 import java.io.ByteArrayInputStream 22 import java.io.ByteArrayOutputStream 23 import java.io.File 24 import java.io.FileNotFoundException 25 import java.io.OutputStream 26 import java.util.jar.JarInputStream 27 import java.util.regex.Pattern 28 import org.junit.Assert 29 import org.junit.Test 30 31 class EndToEndTest { 32 33 @Test 34 fun e2e_transform() { 35 val output = run( 36 srcs = mapOf("frameworks/base/org/example/Example.java" to """ 37 package org.example; 38 import com.android.internal.protolog.common.ProtoLog; 39 import static com.android.internal.protolog.ProtoLogGroup.GROUP; 40 41 class Example { 42 void method() { 43 String argString = "hello"; 44 int argInt = 123; 45 ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); 46 } 47 } 48 """.trimIndent()), 49 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), 50 commandOptions = CommandOptions(arrayOf("transform-protolog-calls", 51 "--protolog-class", "com.android.internal.protolog.common.ProtoLog", 52 "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", 53 "--loggroups-jar", "not_required.jar", 54 "--viewer-config-file-path", "not_required.pb", 55 "--output-srcjar", "out.srcjar", 56 "frameworks/base/org/example/Example.java")) 57 ) 58 val outSrcJar = assertLoadSrcJar(output, "out.srcjar") 59 Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"]) 60 .containsMatch(Pattern.compile("\\{ String protoLogParam0 = " + 61 "String\\.valueOf\\(argString\\); long protoLogParam1 = argInt; " + 62 "com\\.android\\.internal\\.protolog.ProtoLogImpl_.*\\.d\\(" + 63 "GROUP, -6872339441335321086L, 4, null, protoLogParam0, protoLogParam1" + 64 "\\); \\}")) 65 } 66 67 @Test 68 fun e2e_viewerConfig() { 69 val output = run( 70 srcs = mapOf("frameworks/base/org/example/Example.java" to """ 71 package org.example; 72 import com.android.internal.protolog.common.ProtoLog; 73 import static com.android.internal.protolog.ProtoLogGroup.GROUP; 74 75 class Example { 76 void method() { 77 String argString = "hello"; 78 int argInt = 123; 79 ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); 80 } 81 } 82 """.trimIndent()), 83 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), 84 commandOptions = CommandOptions(arrayOf("generate-viewer-config", 85 "--protolog-class", "com.android.internal.protolog.common.ProtoLog", 86 "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", 87 "--loggroups-jar", "not_required.jar", 88 "--viewer-config-type", "json", 89 "--viewer-config", "out.json", 90 "frameworks/base/org/example/Example.java")) 91 ) 92 val viewerConfigJson = assertLoadText(output, "out.json") 93 Truth.assertThat(viewerConfigJson).contains(""" 94 "messages": { 95 "-6872339441335321086": { 96 "message": "Example: %s %d", 97 "level": "DEBUG", 98 "group": "GROUP", 99 "at": "org\/example\/Example.java" 100 } 101 } 102 """.trimIndent()) 103 } 104 105 private fun assertLoadSrcJar( 106 outputs: Map<String, ByteArray>, 107 path: String 108 ): Map<String, String> { 109 val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") 110 111 val sources = mutableMapOf<String, String>() 112 JarInputStream(ByteArrayInputStream(out)).use { jarStream -> 113 var entry = jarStream.nextJarEntry 114 while (entry != null) { 115 if (entry.name.endsWith(".java")) { 116 sources[entry.name] = jarStream.reader().readText() 117 } 118 entry = jarStream.nextJarEntry 119 } 120 } 121 return sources 122 } 123 124 private fun assertLoadText(outputs: Map<String, ByteArray>, path: String): String { 125 val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})") 126 return out.toString(Charsets.UTF_8) 127 } 128 129 fun run( 130 srcs: Map<String, String>, 131 logGroup: LogGroup, 132 commandOptions: CommandOptions 133 ): Map<String, ByteArray> { 134 val outputs = mutableMapOf<String, ByteArrayOutputStream>() 135 136 val srcs = srcs.toMutableMap() 137 srcs[PROTOLOG_IMPL_SRC_PATH] = """ 138 package com.android.internal.protolog; 139 140 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH; 141 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH; 142 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH; 143 144 import com.android.internal.protolog.common.ProtoLogToolInjected; 145 146 public class ProtoLogImpl { 147 @ProtoLogToolInjected(VIEWER_CONFIG_PATH) 148 private static String sViewerConfigPath; 149 150 @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH) 151 private static String sLegacyViewerConfigPath; 152 153 @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH) 154 private static String sLegacyOutputFilePath; 155 } 156 """.trimIndent() 157 158 ProtoLogTool.injector = object : ProtoLogTool.Injector { 159 override fun fileOutputStream(file: String): OutputStream = 160 ByteArrayOutputStream().also { outputs[file] = it } 161 162 override fun readText(file: File): String { 163 for (src in srcs.entries) { 164 val filePath = src.key 165 if (file.path == filePath) { 166 return src.value 167 } 168 } 169 throw FileNotFoundException("$file not found in [${srcs.keys.joinToString()}].") 170 } 171 172 override fun readLogGroups(jarPath: String, className: String) = mapOf( 173 logGroup.name to logGroup) 174 175 override fun reportParseError(ex: ParsingException) = throw AssertionError(ex) 176 } 177 178 ProtoLogTool.invoke(commandOptions) 179 180 return outputs.mapValues { it.value.toByteArray() } 181 } 182 183 fun fail(message: String): Nothing = Assert.fail(message) as Nothing 184 } 185