1 /* <lambda>null2 * Copyright 2021 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 androidx.benchmark 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SdkSuppress 21 import androidx.test.filters.SmallTest 22 import java.io.File 23 import java.util.Date 24 import kotlin.test.assertEquals 25 import kotlin.test.assertFailsWith 26 import kotlin.test.assertFalse 27 import kotlin.test.assertTrue 28 import org.junit.Assert 29 import org.junit.Assume.assumeTrue 30 import org.junit.Before 31 import org.junit.Test 32 import org.junit.runner.RunWith 33 34 @SmallTest 35 @RunWith(AndroidJUnit4::class) 36 public class OutputsTest { 37 private val outputs: MutableList<String> = mutableListOf() 38 39 @Before 40 public fun setUp() { 41 outputs.addAll( 42 // Don't add the / prefix. 43 listOf( 44 "foo/a.txt", 45 "foo/b.txt", 46 "foo/bar/a.txt", 47 "foo/bar/baz/a.txt", 48 ) 49 ) 50 } 51 52 @Test 53 public fun testRelativePaths_usesIntendedOutputDirectory() { 54 assertRelativePaths(Outputs.outputDirectory, outputs) 55 } 56 57 @Test 58 @SdkSuppress(minSdkVersion = 30, maxSdkVersion = 30) 59 public fun testRelativePaths_usesDirectoryUsableByAppAndShell() { 60 assertRelativePaths(Outputs.dirUsableByAppAndShell, outputs) 61 } 62 63 /** 64 * This test validates the strings searched for by BPGP aren't broken by filename sanitization. 65 */ 66 @Test 67 public fun sanitizeFilename_baselineProfileGradlePlugin() { 68 val baselineSanitized = Outputs.sanitizeFilename("foo[a=b]-baseline-prof-001.txt") 69 val startupSanitized = Outputs.sanitizeFilename("foo[a=b]-startup-prof-001.txt") 70 71 assertEquals("foo_a_b_-baseline-prof-001.txt", baselineSanitized) 72 assertEquals("foo_a_b_-startup-prof-001.txt", startupSanitized) 73 baselineSanitized.apply { 74 // NOTE: behavior MUST MATCH baseline profile gradle plugin check, see b/303034735 75 assertTrue(contains("-baseline-prof-") && endsWith(".txt")) 76 } 77 startupSanitized.apply { 78 // NOTE: behavior MUST MATCH baseline profile gradle plugin check, see b/303034735 79 assertTrue(contains("-startup-prof-") && endsWith(".txt")) 80 } 81 } 82 83 @Test 84 public fun sanitizeFilename() { 85 assertEquals( 86 "testFilename_one_Thing_two_other_", 87 Outputs.sanitizeFilename("testFilename[one=Thing( ),two:other]") 88 ) 89 } 90 91 @Test 92 public fun sanitizeFilename_tooLong() { 93 assertEquals("a".repeat(199), Outputs.sanitizeFilename("a".repeat(199))) 94 assertFailsWith<IllegalArgumentException> { Outputs.sanitizeFilename("a".repeat(200)) } 95 } 96 97 @Test 98 public fun sanitizeFilename_withExtension() { 99 assertEquals( 100 "testFilename_one_Thing_two_other_.trace", 101 Outputs.sanitizeFilename("testFilename[one=Thing( ),two:other].trace") 102 ) 103 } 104 105 @Test 106 public fun testDateToFileName() { 107 val date = Date(0) 108 val expected = "1970-01-01-00-00-00" 109 assertEquals(Outputs.dateToFileName(date), expected) 110 } 111 112 private fun assertRelativePaths(base: File, paths: List<String>) { 113 val basePath = base.absolutePath 114 val relativePaths = paths.map { Outputs.relativePathFor(File(base, it).absolutePath) } 115 relativePaths.forEach { path -> 116 assertFalse(path.startsWith("/"), "$path cannot start with a `/`.") 117 assertFalse( 118 path.startsWith(basePath), 119 "Invalid relative path ($path), Base ($basePath)." 120 ) 121 } 122 123 for ((path, relativePath) in paths.zip(relativePaths)) { 124 assertEquals(path, relativePath, "$path != $relativePath") 125 } 126 } 127 128 @Test 129 public fun dirUsableByAppAndShell_writeAppReadApp() { 130 val dir = Outputs.dirUsableByAppAndShell 131 val file = File.createTempFile("testFile", null, dir) 132 try { 133 file.writeText(file.name) // use name, as it's fairly unique 134 Assert.assertEquals(file.name, file.readText()) 135 } finally { 136 file.delete() 137 } 138 } 139 140 @Test 141 @SdkSuppress(minSdkVersion = 21) 142 public fun dirUsableByAppAndShell_writeAppReadShell() { 143 val dir = Outputs.dirUsableByAppAndShell 144 val file = File.createTempFile("testFile", null, dir) 145 file.setReadable(true, false) 146 try { 147 file.writeText(file.name) // use name, as it's fairly unique 148 Assert.assertEquals( 149 file.name, 150 Shell.executeScriptCaptureStdout("cat ${file.absolutePath}") 151 ) 152 } finally { 153 file.delete() 154 } 155 } 156 157 @Test 158 @SdkSuppress(minSdkVersion = 21) 159 public fun dirUsableByAppAndShell_writeShellReadShell() { 160 val dir = Outputs.dirUsableByAppAndShell 161 162 // simple way to get a unique path, not shared across runs 163 val file = File.createTempFile("shellwrite", null, dir) 164 val path = file.absolutePath 165 file.delete() 166 167 Shell.executeScriptSilent("rm -f $path") 168 try { 169 Shell.executeScriptSilent("echo test > $path") 170 assertEquals("test\n", Shell.executeScriptCaptureStdout("cat $path")) 171 file.appendBytes("extra".toByteArray()) 172 } finally { 173 Shell.executeScriptSilent("rm -f $path") 174 } 175 } 176 177 @Test 178 @SdkSuppress(minSdkVersion = 21) 179 public fun dirUsableByAppAndShell_writeShellReadApp() { 180 val dir = Outputs.dirUsableByAppAndShell 181 182 // simple way to get a unique path, not shared across runs 183 val file = File.createTempFile("shellwrite", null, dir) 184 val path = file.absolutePath 185 file.delete() 186 187 Shell.executeScriptSilent("rm -f $path") 188 try { 189 Shell.executeScriptSilent("echo test > $path") 190 assertEquals("test\n", File(path).readText()) 191 file.appendBytes("extra".toByteArray()) 192 } finally { 193 Shell.executeScriptSilent("rm -f $path") 194 } 195 } 196 197 /** 198 * NOTE: this test checks that the instrumentation argument additionalTestOutputDir isn't set to 199 * an invalid / unusable location. 200 * 201 * Running through Studio/Gradle, this isn't defined by the library, it's defined by AGP. 202 * 203 * If this test fails, we need to handle the directory differently. 204 */ 205 @Test 206 fun additionalTestOutputDir_appWrite() { 207 val additionalTestOutputDir = Arguments.additionalTestOutputDir 208 assumeTrue(additionalTestOutputDir != null) 209 val file = File.createTempFile("testFile", null, File(additionalTestOutputDir!!)) 210 try { 211 file.writeText("testString") 212 } finally { 213 file.delete() 214 } 215 } 216 } 217