1 /* 2 * Copyright 2017 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.tools.build.jetifier.processor.transform.resource 18 19 import com.android.tools.build.jetifier.core.PackageMap 20 import com.android.tools.build.jetifier.core.config.Config 21 import com.android.tools.build.jetifier.core.rule.RewriteRule 22 import com.android.tools.build.jetifier.core.rule.RewriteRulesMap 23 import com.android.tools.build.jetifier.core.type.JavaType 24 import com.android.tools.build.jetifier.core.type.TypesMap 25 import com.android.tools.build.jetifier.processor.archive.ArchiveFile 26 import com.android.tools.build.jetifier.processor.transform.TransformationContext 27 import com.google.common.truth.Truth 28 import org.junit.Test 29 import java.nio.charset.Charset 30 import java.nio.file.Paths 31 32 class XmlResourcesTransformerTest { 33 34 @Test fun layout_noRule_noChange() { 35 testRewriteToTheSame( 36 givenAndExpectedXml = 37 "<android.support.v7.preference.Preference>\n" + 38 "</android.support.v7.preference.Preference>", 39 prefixes = setOf("android/support/v7/"), 40 map = mapOf(), 41 errorsExpected = true 42 ) 43 } 44 45 @Test fun layout_notApplicablePrefix_shouldStillWork() { 46 testRewrite( 47 givenXml = 48 "<android.support.v7.preference.Preference>\n" + 49 "</android.support.v7.preference.Preference>", 50 expectedXml = 51 "<android.test.pref.Preference>\n" + 52 "</android.test.pref.Preference>", 53 prefixes = setOf("android/support/v14/"), 54 typesMap = mapOf( 55 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 56 ) 57 ) 58 } 59 60 @Test fun layout_notApplicablePrefix2_noChange() { 61 testRewriteToTheSame( 62 givenAndExpectedXml = 63 "<my.android.support.v7.preference.Preference>\n" + 64 "</my.android.support.v7.preference.Preference>", 65 prefixes = setOf("android/support/v7/"), 66 map = mapOf( 67 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 68 ) 69 ) 70 } 71 72 @Test fun layout_notApplicableRule_noChange() { 73 testRewriteToTheSame( 74 givenAndExpectedXml = 75 "<android.support.v7.preference.Preference>\n" + 76 "</android.support.v7.preference.Preference>", 77 prefixes = setOf("android/support/"), 78 map = mapOf( 79 "android/support2/v7/preference/Preference" to "android/test/pref/Preference" 80 ), 81 errorsExpected = true 82 ) 83 } 84 85 @Test fun layout_onePrefix_oneRule_oneRewrite() { 86 testRewrite( 87 givenXml = 88 "<android.support.v7.preference.Preference/>", 89 expectedXml = 90 "<android.test.pref.Preference/>", 91 prefixes = setOf("android/support/"), 92 typesMap = mapOf( 93 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 94 ) 95 ) 96 } 97 98 @Test fun layout_onePrefix_oneRule_attribute_oneRewrite() { 99 testRewrite( 100 givenXml = 101 "<android.support.v7.preference.Preference \n" + 102 " someAttribute=\"android.support.v7.preference.Preference\"/>", 103 expectedXml = 104 "<android.test.pref.Preference \n" + 105 " someAttribute=\"android.test.pref.Preference\"/>", 106 prefixes = setOf("android/support/"), 107 typesMap = mapOf( 108 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 109 ) 110 ) 111 } 112 113 @Test fun layout_onePrefix_oneRule_twoRewrites() { 114 testRewrite( 115 givenXml = 116 "<android.support.v7.preference.Preference>\n" + 117 "</android.support.v7.preference.Preference>", 118 expectedXml = 119 "<android.test.pref.Preference>\n" + 120 "</android.test.pref.Preference>", 121 prefixes = setOf("android/support/"), 122 typesMap = mapOf( 123 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 124 ) 125 ) 126 } 127 128 @Test fun layout_onePrefix_oneRule_viewTag_simple() { 129 testRewrite( 130 givenXml = 131 "<view class=\"android.support.v7.preference.Preference\">", 132 expectedXml = 133 "<view class=\"android.test.pref.Preference\">", 134 prefixes = setOf("android/support/"), 135 typesMap = mapOf( 136 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 137 ) 138 ) 139 } 140 141 @Test fun layout_onePrefix_oneRule_viewInText() { 142 testRewriteToTheSame( 143 givenAndExpectedXml = 144 "<test attribute=\"view\" class=\"something.Else\">", 145 prefixes = setOf("android/support/"), 146 map = mapOf( 147 "android/support/v7/preference/Preference" to "android/test/pref/Preference" 148 ) 149 ) 150 } 151 152 @Test fun application_appComponentFactory() { 153 testRewrite( 154 givenXml = 155 "<application android:appComponentFactory=\"android.support.v7.Preference\" />", 156 expectedXml = 157 "<application android:appComponentFactory=\"android.test.pref.Preference\" />", 158 prefixes = setOf("android/support/"), 159 typesMap = mapOf( 160 "android/support/v7/Preference" to "android/test/pref/Preference" 161 ) 162 ) 163 } 164 165 @Test fun layout_onePrefix_oneRule_identity() { 166 testRewrite( 167 givenXml = 168 "<android.support.v7.preference.Preference>\n" + 169 "</android.support.v7.preference.Preference>", 170 expectedXml = 171 "<android.support.v7.preference.Preference>\n" + 172 "</android.support.v7.preference.Preference>", 173 prefixes = setOf("android/support/"), 174 typesMap = mapOf( 175 "android/support/v7/preference/Preference" 176 to "android/support/v7/preference/Preference" 177 ) 178 ) 179 } 180 181 @Test fun layout_twoPrefixes_threeRules_ignoreRule_multipleRewrites() { 182 testRewrite( 183 givenXml = 184 "<android.support.v7.preference.Preference>\n" + 185 " <android.support.v14.preference.DialogPreference" + 186 " someAttribute=\"someValue\"/>\n" + 187 " <android.support.v14.preference.DialogPreference" + 188 " someAttribute=\"someValue2\"/>\n" + 189 " <!-- This one should be ignored --> \n" + 190 " <android.support.v21.preference.DialogPreference" + 191 " someAttribute=\"someValue2\"/>\n" + 192 "</android.support.v7.preference.Preference>\n" + 193 "\n" + 194 "<android.support.v7.preference.ListPreference/>", 195 expectedXml = 196 "<android.test.pref.Preference>\n" + 197 " <android.test14.pref.DialogPreference" + 198 " someAttribute=\"someValue\"/>\n" + 199 " <android.test14.pref.DialogPreference" + 200 " someAttribute=\"someValue2\"/>\n" + 201 " <!-- This one should be ignored --> \n" + 202 " <android.support.v21.preference.DialogPreference" + 203 " someAttribute=\"someValue2\"/>\n" + 204 "</android.test.pref.Preference>\n" + 205 "\n" + 206 "<android.test.pref.ListPref/>", 207 prefixes = setOf( 208 "android/support/v7/", 209 "android/support/v14/" 210 ), 211 rulesMap = RewriteRulesMap( 212 RewriteRule(from = "android/support/v21/(.*)", to = "ignore")), 213 typesMap = mapOf( 214 "android/support/v7/preference/ListPreference" 215 to "android/test/pref/ListPref", 216 "android/support/v7/preference/Preference" 217 to "android/test/pref/Preference", 218 "android/support/v14/preference/DialogPreference" 219 to "android/test14/pref/DialogPreference" 220 ) 221 ) 222 } 223 224 @Test fun manifestFile_packageRewrite() { 225 testRewrite( 226 givenXml = 227 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 228 " package=\"android.support.v7.preference\">\n" + 229 " <uses-sdk android:minSdkVersion=\"14\"/>\n" + 230 "</manifest>", 231 expectedXml = 232 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 233 " package=\"androidx.preference\">\n" + 234 " <uses-sdk android:minSdkVersion=\"14\"/>\n" + 235 "</manifest>", 236 prefixes = setOf( 237 "android/support" 238 ), 239 typesMap = mapOf( 240 ), 241 packageMap = PackageMap(listOf( 242 PackageMap.PackageRule( 243 from = "android/support/v7/preference", 244 to = "androidx/preference") 245 )), 246 rewritingSupportLib = true 247 ) 248 } 249 250 @Test fun manifestFile_packageRewrite_prefixMismatchShouldNotAffectRewrite() { 251 testRewrite( 252 givenXml = 253 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 254 " package=\"android.support.v7.preference\">\n" + 255 " <uses-sdk android:minSdkVersion=\"14\"/>\n" + 256 "</manifest>", 257 expectedXml = 258 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 259 " package=\"androidx.preference\">\n" + 260 " <uses-sdk android:minSdkVersion=\"14\"/>\n" + 261 "</manifest>", 262 prefixes = setOf( 263 "android/something/else" 264 ), 265 typesMap = mapOf( 266 ), 267 packageMap = PackageMap(listOf( 268 PackageMap.PackageRule( 269 from = "android/support/v7/preference", 270 to = "androidx/preference") 271 )), 272 rewritingSupportLib = true 273 ) 274 } 275 276 @Test fun manifestFile_packageRewrite_shouldIgnore() { 277 testRewrite( 278 givenXml = 279 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 280 " package=\"android.support.test\">\n" + 281 "</manifest>", 282 expectedXml = 283 "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 284 " package=\"android.support.test\">\n" + 285 "</manifest>", 286 prefixes = setOf( 287 "android/support/" 288 ), 289 rulesMap = RewriteRulesMap( 290 RewriteRule("android/support/test/(.*)", "ignore") 291 ), 292 packageMap = PackageMap.EMPTY, 293 rewritingSupportLib = true 294 ) 295 } 296 297 @Test fun generic_sample_provider() { 298 testRewrite( 299 givenXml = 300 "<provider\n" + 301 " android:authorities=\"support.Something\"\n" + 302 " android:name=\"support.Something\">\n" + 303 " <meta-data android:name=\"support.Something\">\n" + 304 "</provider>", 305 expectedXml = 306 "<provider\n" + 307 " android:authorities=\"test.Something\"\n" + 308 " android:name=\"test.Something\">\n" + 309 " <meta-data android:name=\"test.Something\">\n" + 310 "</provider>", 311 prefixes = setOf("support/"), 312 typesMap = mapOf( 313 "support/Something" to "test/Something" 314 ) 315 ) 316 } 317 318 @Test fun generic_sample_intent() { 319 testRewrite( 320 givenXml = 321 "<activity android:name=\"some\" android:configChanges=\"orientation\">\n" + 322 " <intent-filter>\n" + 323 " <action android:name=\"support.Something\" />\n" + 324 " </intent-filter>\n" + 325 "</activity>", 326 expectedXml = 327 "<activity android:name=\"some\" android:configChanges=\"orientation\">\n" + 328 " <intent-filter>\n" + 329 " <action android:name=\"test.Something\" />\n" + 330 " </intent-filter>\n" + 331 "</activity>", 332 prefixes = setOf("support/"), 333 typesMap = mapOf( 334 "support/Something" to "test/Something" 335 ) 336 ) 337 } 338 339 @Test fun generic_sample_style() { 340 testRewrite( 341 givenXml = 342 "<style name=\"AppCompat\" parent=\"Platform.AppCompat\">\n" + 343 " <item name=\"viewInflaterClass\">support.Something</item>\n" + 344 "</style>", 345 expectedXml = 346 "<style name=\"AppCompat\" parent=\"Platform.AppCompat\">\n" + 347 " <item name=\"viewInflaterClass\">test.Something</item>\n" + 348 "</style>", 349 prefixes = setOf("support/"), 350 typesMap = mapOf( 351 "support/Something" to "test/Something" 352 ) 353 ) 354 } 355 356 @Test fun generic_sample_transition() { 357 testRewrite( 358 givenXml = 359 "<transition\n" + 360 " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 361 " xmlns:lb=\"http://schemas.android.com/apk/res-auto\"\n" + 362 " class=\"support.Something\"\n" + 363 " lb:lb_slideEdge=\"top\" >\n" + 364 "</transition>", 365 expectedXml = 366 "<transition\n" + 367 " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 368 " xmlns:lb=\"http://schemas.android.com/apk/res-auto\"\n" + 369 " class=\"test.Something\"\n" + 370 " lb:lb_slideEdge=\"top\" >\n" + 371 "</transition>", 372 prefixes = setOf("support/"), 373 typesMap = mapOf( 374 "support/Something" to "test/Something" 375 ) 376 ) 377 } 378 379 private fun testRewriteToTheSame( 380 givenAndExpectedXml: String, 381 prefixes: Set<String>, 382 map: Map<String, String>, 383 errorsExpected: Boolean = false 384 ) { 385 testRewrite(givenAndExpectedXml, givenAndExpectedXml, prefixes, map, 386 errorsExpected = errorsExpected) 387 } 388 389 private fun testRewrite( 390 givenXml: String, 391 expectedXml: String, 392 prefixes: Set<String>, 393 typesMap: Map<String, String> = emptyMap(), 394 rulesMap: RewriteRulesMap = RewriteRulesMap.EMPTY, 395 packageMap: PackageMap = PackageMap.EMPTY, 396 rewritingSupportLib: Boolean = false, 397 errorsExpected: Boolean = false 398 ) { 399 val given = 400 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 401 "$givenXml\n" 402 403 val expected = 404 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 405 "$expectedXml\n" 406 407 val typeMap = TypesMap(typesMap.map { JavaType(it.key) to JavaType(it.value) }.toMap()) 408 val config = Config.fromOptional( 409 restrictToPackagePrefixes = prefixes, 410 rulesMap = rulesMap, 411 typesMap = typeMap, 412 packageMap = packageMap 413 ) 414 val context = TransformationContext( 415 config, 416 rewritingSupportLib = rewritingSupportLib, 417 useFallbackIfTypeIsMissing = false) 418 val processor = XmlResourcesTransformer(context) 419 val fileName = Paths.get("random.xml") 420 val file = ArchiveFile(fileName, given.toByteArray()) 421 processor.runTransform(file) 422 val strResult = file.data.toString(Charset.defaultCharset()) 423 424 Truth.assertThat(strResult).isEqualTo(expected) 425 426 if (errorsExpected) { 427 Truth.assertThat(context.errorsTotal()).isAtLeast(1) 428 } else { 429 Truth.assertThat(context.errorsTotal()).isEqualTo(0) 430 } 431 } 432 } 433 434