Home | History | Annotate | Download | only in bytecode
      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.bytecode
     18 
     19 import com.android.tools.build.jetifier.core.config.Config
     20 import com.android.tools.build.jetifier.core.rule.RewriteRule
     21 import com.android.tools.build.jetifier.core.rule.RewriteRulesMap
     22 import com.android.tools.build.jetifier.core.type.JavaType
     23 import com.android.tools.build.jetifier.core.type.TypesMap
     24 import com.android.tools.build.jetifier.processor.FileMapping
     25 import com.android.tools.build.jetifier.processor.Processor
     26 import com.android.tools.build.jetifier.processor.archive.Archive
     27 import com.android.tools.build.jetifier.processor.archive.ArchiveFile
     28 import com.android.tools.build.jetifier.processor.archive.ArchiveItemVisitor
     29 import com.google.common.truth.Truth
     30 import org.junit.Test
     31 import java.io.File
     32 
     33 /**
     34  * Tests that individual files were moved properly due to their owner types rewrites.
     35  */
     36 class ClassFilesMoveTest {
     37 
     38     companion object {
     39         private val TEST_CONFIG = Config.fromOptional(
     40             restrictToPackagePrefixes = setOf("android/support"),
     41             reversedRestrictToPackagesPrefixes = setOf("androidx"),
     42             rulesMap = RewriteRulesMap(
     43                 RewriteRule("android/support/annotation/(.*)", "ignore"),
     44                 RewriteRule("android/support/v7/preference/R(.*)", "ignore"),
     45                 RewriteRule("android/support/v4/(.*)", "ignore")
     46             ),
     47             slRules = listOf(
     48                 RewriteRule("android/support/annotation/(.*)", "ignore"),
     49                 RewriteRule("android/support/v7/preference/R(.*)", "ignore"),
     50                 RewriteRule("android/support/v4/(.*)", "ignore")
     51             ),
     52             typesMap = TypesMap(mapOf(
     53                 "android/support/v7/preference/Preference"
     54                         to "androidx/support/preference/Preference",
     55                 "android/support/v7/preference/TwoStatePreference"
     56                         to "androidx/support/preference/TwoStatePreference",
     57                 "android/support/v7/preference/PreferenceGroup"
     58                         to "androidx/support/preference/PreferenceGroup",
     59                 "android/support/v7/preference/PreferenceViewHolder"
     60                         to "androidx/support/preference/PreferenceViewHolder",
     61                 "android/support/v7/preference/PreferenceManager"
     62                         to "androidx/support/preference/PreferenceManager",
     63                 "android/support/v14/preference/SwitchPreference"
     64                         to "androidx/support/preference/SwitchPreference",
     65                 "android/support/v7/preference/PreferenceDataStore"
     66                         to "androidx/support/preference/PreferenceDataStore"
     67             ).map { JavaType(it.key) to JavaType(it.value) }.toMap())
     68         )
     69     }
     70 
     71     /**
     72      * Tests that after rewrite of a input archive the internal classes are properly moved to new
     73      * locations (based on the rewrite rules) which is compared with the expected archive.
     74      *
     75      * Note: The expected archive does not contain rewritten classes - they were only manually
     76      * moved. Which is fine because this test validates only files locations.
     77      */
     78     @Test fun fileMove_forwardRewrite_shouldMoveFilesProperly() {
     79         val inputZipPath = "/fileRenameTest/inputTestLib.zip"
     80         val expectedZipPath = "/fileRenameTest/expectedTestLib.zip"
     81 
     82         val processor = Processor.createProcessor(TEST_CONFIG)
     83         val inputFile = File(javaClass.getResource(inputZipPath).file)
     84 
     85         val tempDir = createTempDir()
     86         val expectedFile = File(createTempDir(), "test.zip")
     87 
     88         val resultFiles = processor.transform(setOf(FileMapping(inputFile, expectedFile)))
     89 
     90         Truth.assertThat(resultFiles).hasSize(1)
     91         testArchivesAreSame(resultFiles.first(), File(javaClass.getResource(expectedZipPath).file))
     92 
     93         tempDir.delete()
     94     }
     95 
     96     /**
     97      * Does exactly the same as [fileMove_forwardRewrite_nestedArchive_shouldMoveFilesProperly] but
     98      * the files are in a nested archive e.g. archive.zip/classes.jar/some files.
     99      */
    100     @Test fun fileMove_forwardRewrite_nestedArchive_shouldMoveFilesProperly() {
    101         val inputZipPath = "/fileRenameTest/inputTestLibNested.zip"
    102         val expectedZipPath = "/fileRenameTest/expectedTestLibNested.zip"
    103 
    104         val processor = Processor.createProcessor(TEST_CONFIG)
    105         val inputFile = File(javaClass.getResource(inputZipPath).file)
    106 
    107         val tempDir = createTempDir()
    108         val expectedFile = File(createTempDir(), "test.zip")
    109 
    110         val resultFiles = processor.transform(setOf(FileMapping(inputFile, expectedFile)))
    111 
    112         Truth.assertThat(resultFiles).hasSize(1)
    113         testArchivesAreSame(resultFiles.first(), File(javaClass.getResource(expectedZipPath).file))
    114 
    115         tempDir.delete()
    116     }
    117 
    118     /**
    119      * Rewrites the input archive and then applies reversed mode to rewrite it back. The final
    120      * produced archive has to have the same directory structure as the input one.
    121      */
    122     @Test fun fileMove_forwardRewrite_backwardsRewrite_shouldKeepFilesProperly() {
    123         val inputZipPath = "/fileRenameTest/inputTestLib.zip"
    124 
    125         // Transform forward
    126         val processor = Processor.createProcessor(TEST_CONFIG)
    127         val inputFile = File(javaClass.getResource(inputZipPath).file)
    128 
    129         val tempDir = createTempDir()
    130         val expectedFile = File(createTempDir(), "test.zip")
    131 
    132         val resultFiles = processor.transform(setOf(FileMapping(inputFile, expectedFile)))
    133 
    134         // Take previous result & reverse it
    135         val processor2 = Processor.createProcessor(
    136             TEST_CONFIG,
    137             rewritingSupportLib = true,
    138             reversedMode = true)
    139         val expectedFile2 = File(createTempDir(), "test2.zip")
    140         val resultFiles2 = processor2.transform(setOf(
    141             FileMapping(resultFiles.first(), expectedFile2)))
    142 
    143         testArchivesAreSame(resultFiles2.first(), File(javaClass.getResource(inputZipPath).file))
    144 
    145         tempDir.delete()
    146     }
    147 
    148     fun testArchivesAreSame(givenZip: File, expectedZip: File) {
    149         testArchivesAreSame(Archive.Builder.extract(givenZip), Archive.Builder.extract(expectedZip))
    150     }
    151 
    152     fun testArchivesAreSame(givenZip: Archive, expectedZip: Archive) {
    153         val givenFiles = ArchiveBrowser.grabAllPathsIn(givenZip)
    154         val expectedFiles = ArchiveBrowser.grabAllPathsIn(expectedZip)
    155         Truth.assertThat(givenFiles).containsExactlyElementsIn(expectedFiles)
    156     }
    157 
    158     /**
    159      * Just a helper utility to get all file paths in the archive.
    160      */
    161     class ArchiveBrowser : ArchiveItemVisitor {
    162 
    163         companion object {
    164             fun grabAllPathsIn(archive: Archive): MutableSet<String> {
    165                 val grabber = ArchiveBrowser()
    166                 archive.accept(grabber)
    167                 return grabber.allPaths
    168             }
    169         }
    170 
    171         val allPaths = mutableSetOf<String>()
    172 
    173         override fun visit(archiveFile: ArchiveFile) {
    174             allPaths.add(archiveFile.relativePath.toString())
    175             println("Visited ${archiveFile.relativePath}")
    176         }
    177 
    178         override fun visit(archive: Archive) {
    179             archive.files.forEach { it.accept(this) }
    180         }
    181     }
    182 }
    183