1 /* <lambda>null2 * Copyright (C) 2023 Square, Inc. 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 package okio.assetfilesystem 17 18 import androidx.test.platform.app.InstrumentationRegistry 19 import assertk.assertThat 20 import assertk.assertions.containsAll 21 import assertk.assertions.containsExactly 22 import assertk.assertions.hasMessage 23 import assertk.assertions.isEmpty 24 import assertk.assertions.isEqualTo 25 import assertk.assertions.isFalse 26 import assertk.assertions.isNotNull 27 import assertk.assertions.isNull 28 import assertk.assertions.isTrue 29 import kotlin.test.assertFailsWith 30 import okio.Buffer 31 import okio.BufferedSource 32 import okio.FileHandle 33 import okio.FileNotFoundException 34 import okio.IOException 35 import okio.Path.Companion.toPath 36 import okio.buffer 37 import org.junit.Test 38 39 class AssetFileSystemTest { 40 private val context = InstrumentationRegistry.getInstrumentation().context 41 private val fs = context.assets.asFileSystem() 42 43 @Test fun canonicalizeValid() { 44 assertThat(fs.canonicalize("/".toPath())).isEqualTo("/".toPath()) 45 assertThat(fs.canonicalize(".".toPath())).isEqualTo("/".toPath()) 46 assertThat(fs.canonicalize("not/a/path/../../..".toPath())).isEqualTo("/".toPath()) 47 assertThat(fs.canonicalize("file.txt".toPath())).isEqualTo("/file.txt".toPath()) 48 assertThat(fs.canonicalize("stuff/../file.txt".toPath())).isEqualTo("/file.txt".toPath()) 49 assertThat(fs.canonicalize("dir".toPath())).isEqualTo("/dir".toPath()) 50 assertThat(fs.canonicalize("dir/whevs/..".toPath())).isEqualTo("/dir".toPath()) 51 assertThat(fs.canonicalize("dir/nested.txt".toPath())).isEqualTo("/dir/nested.txt".toPath()) 52 assertThat(fs.canonicalize("dir/whevs/../nested.txt".toPath())).isEqualTo("/dir/nested.txt".toPath()) 53 } 54 55 @Test fun canonicalizeInvalidThrows() { 56 assertFailsWith<FileNotFoundException> { 57 fs.canonicalize("not/a/path".toPath()) 58 } 59 } 60 61 @Test fun listRoot() { 62 val list = fs.list("/".toPath()) 63 assertThat(list).containsAll( 64 "dir".toPath(), 65 "file.txt".toPath(), 66 "moby10b.txt".toPath(), 67 ) 68 } 69 70 @Test fun listRootCanonicalizes() { 71 val list = fs.list("foo/bar/../..".toPath()) 72 assertThat(list).containsAll( 73 "dir".toPath(), 74 "file.txt".toPath(), 75 "moby10b.txt".toPath(), 76 ) 77 } 78 79 @Test fun listDirectory() { 80 val list = fs.list("dir".toPath()) 81 assertThat(list).containsExactly("nested.txt".toPath()) 82 } 83 84 @Test fun listDirectoryCanonicalizes() { 85 val list = fs.list("dir/not/real/../..".toPath()) 86 assertThat(list).containsExactly("nested.txt".toPath()) 87 } 88 89 @Test fun listNonExistentDirectoryThrows() { 90 assertFailsWith<FileNotFoundException> { 91 fs.list("nope/".toPath()) 92 } 93 } 94 95 @Test fun listFileThrows() { 96 assertFailsWith<FileNotFoundException> { 97 fs.list("dir/nested.txt".toPath()) 98 } 99 } 100 101 @Test fun listOrNullDirectory() { 102 val list = fs.listOrNull("dir".toPath()) 103 assertThat(list).isNotNull().containsExactly("nested.txt".toPath()) 104 } 105 106 @Test fun listOrNullDirectoryCanonicalizes() { 107 val list = fs.listOrNull("dir/not/real/../..".toPath()) 108 assertThat(list).isNotNull().containsExactly("nested.txt".toPath()) 109 } 110 111 @Test fun listOrNullNonExistentDirectory() { 112 val list = fs.listOrNull("nope".toPath()) 113 assertThat(list).isNull() 114 } 115 116 @Test fun listOrNullFile() { 117 val list = fs.listOrNull("dir/nested.txt".toPath()) 118 assertThat(list).isNull() 119 } 120 121 @Test fun metadataFile() { 122 val metadata = fs.metadataOrNull("file.txt".toPath())!! 123 124 // Data we can get: 125 assertThat(metadata.isRegularFile).isTrue() 126 assertThat(metadata.isDirectory).isFalse() 127 128 // Data we cannot get or is impossible: 129 assertThat(metadata.size).isNull() 130 assertThat(metadata.symlinkTarget).isNull() 131 assertThat(metadata.createdAtMillis).isNull() 132 assertThat(metadata.lastModifiedAtMillis).isNull() 133 assertThat(metadata.lastAccessedAtMillis).isNull() 134 assertThat(metadata.extras).isEmpty() 135 } 136 137 @Test fun metadataDirectory() { 138 val metadata = fs.metadataOrNull("dir".toPath())!! 139 140 // Data we can get: 141 assertThat(metadata.isRegularFile).isFalse() 142 assertThat(metadata.isDirectory).isTrue() 143 144 // Data we cannot get or is impossible: 145 assertThat(metadata.symlinkTarget).isNull() 146 assertThat(metadata.size).isNull() 147 assertThat(metadata.createdAtMillis).isNull() 148 assertThat(metadata.lastModifiedAtMillis).isNull() 149 assertThat(metadata.lastAccessedAtMillis).isNull() 150 assertThat(metadata.extras).isEmpty() 151 } 152 153 @Test fun metadataDirectoryCanonicalizes() { 154 val metadata = fs.metadataOrNull("dir/not/real/../..".toPath())!! 155 assertThat(metadata.isDirectory).isTrue() 156 } 157 158 @Test fun metadataNonExistentPath() { 159 val metadata = fs.metadataOrNull("not/a/path".toPath()) 160 assertThat(metadata).isNull() 161 } 162 163 @Test fun sourceFile() { 164 val file = fs.source("file.txt".toPath()).buffer().use(BufferedSource::readUtf8) 165 assertThat(file).isEqualTo("File!\n") 166 val nested = fs.source("dir/nested.txt".toPath()).buffer().use(BufferedSource::readUtf8) 167 assertThat(nested).isEqualTo("Nested!\n") 168 } 169 170 @Test fun sourceDirectory() { 171 assertFailsWith<FileNotFoundException> { 172 fs.source("dir".toPath()) 173 } 174 } 175 176 @Test fun sourceNonExistent() { 177 assertFailsWith<FileNotFoundException> { 178 fs.source("not/a/path".toPath()) 179 } 180 } 181 182 @Test fun openReadOnlyInvalidThrows() { 183 assertFailsWith<FileNotFoundException> { 184 fs.openReadOnly("not/a/path".toPath()) 185 } 186 } 187 188 @Test fun openReadOnlyDirectoryThrows() { 189 assertFailsWith<FileNotFoundException> { 190 fs.openReadOnly("dir".toPath()) 191 } 192 } 193 194 @Test fun openReadOnlySize() { 195 val smallSize = fs.openReadOnly("file.txt".toPath()).use(FileHandle::size) 196 assertThat(smallSize).isEqualTo(6) 197 198 val mobySize = fs.openReadOnly("moby10b.txt".toPath()).use(FileHandle::size) 199 assertThat(mobySize).isEqualTo(1232923) 200 } 201 202 @Test fun openReadOnlyRandomAccessForward() { 203 fs.openReadOnly("moby10b.txt".toPath()).use { handle -> 204 val buffer = Buffer() 205 handle.read(34251, buffer, 16) 206 assertThat(buffer.readUtf8()).isEqualTo("Call me Ishmael.") 207 handle.read(148605, buffer, 49) 208 assertThat(buffer.readUtf8()).isEqualTo("It is not down in any map; true places never are.") 209 handle.read(1051694, buffer, 50) 210 assertThat(buffer.readUtf8()).isEqualTo("his forehead's veins swelled like overladen brooks") 211 handle.read(148605, buffer, 49) 212 assertThat(buffer.readUtf8()).isEqualTo("It is not down in any map; true places never are.") 213 handle.read(34251, buffer, 16) 214 assertThat(buffer.readUtf8()).isEqualTo("Call me Ishmael.") 215 } 216 } 217 218 @Test fun openReadOnlyRandomAccessThenSize() { 219 fs.openReadOnly("moby10b.txt".toPath()).use { handle -> 220 val buffer = Buffer() 221 handle.read(34251, buffer, 16) 222 assertThat(buffer.readUtf8()).isEqualTo("Call me Ishmael.") 223 224 assertThat(handle.size()).isEqualTo(1232923) 225 } 226 } 227 228 @Test fun openReadOnlyFlushThrows() { 229 fs.openReadOnly("file.txt".toPath()).use { handle -> 230 val t = assertFailsWith<IllegalStateException> { 231 handle.flush() 232 } 233 assertThat(t).hasMessage("file handle is read-only") 234 } 235 } 236 237 @Test fun openReadOnlyResizeThrows() { 238 fs.openReadOnly("file.txt".toPath()).use { handle -> 239 val t = assertFailsWith<IllegalStateException> { 240 handle.resize(10L) 241 } 242 assertThat(t).hasMessage("file handle is read-only") 243 } 244 } 245 246 @Test fun openReadOnlyWriteThrows() { 247 fs.openReadOnly("file.txt".toPath()).use { handle -> 248 val t = assertFailsWith<IllegalStateException> { 249 handle.write(0, Buffer().writeUtf8("Sup"), 3) 250 } 251 assertThat(t).hasMessage("file handle is read-only") 252 } 253 } 254 255 @Test fun sinkThrows() { 256 val t = assertFailsWith<IOException> { 257 fs.sink("file.txt".toPath()) 258 } 259 assertThat(t).hasMessage("asset file systems are read-only") 260 } 261 262 @Test fun appendingSinkThrows() { 263 val t = assertFailsWith<IOException> { 264 fs.appendingSink("file.txt".toPath()) 265 } 266 assertThat(t).hasMessage("asset file systems are read-only") 267 } 268 269 @Test fun createDirectoryThrows() { 270 val t = assertFailsWith<IOException> { 271 fs.createDirectory("new-dir".toPath(), mustCreate = true) 272 } 273 assertThat(t).hasMessage("asset file systems are read-only") 274 } 275 276 @Test fun atomicMoveThrows() { 277 val t = assertFailsWith<IOException> { 278 fs.atomicMove("file.txt".toPath(), "new-file.txt".toPath()) 279 } 280 assertThat(t).hasMessage("asset file systems are read-only") 281 } 282 283 @Test fun deleteThrows() { 284 val t = assertFailsWith<IOException> { 285 fs.delete("file.txt".toPath()) 286 } 287 assertThat(t).hasMessage("asset file systems are read-only") 288 } 289 290 @Test fun createSymlinkThrows() { 291 val t = assertFailsWith<IOException> { 292 fs.createSymlink("file.txt".toPath(), "new-file.txt".toPath()) 293 } 294 assertThat(t).hasMessage("asset file systems are read-only") 295 } 296 297 @Test fun openReadWriteThrows() { 298 val t = assertFailsWith<IOException> { 299 fs.openReadWrite("file.txt".toPath()) 300 } 301 assertThat(t).hasMessage("asset file systems are read-only") 302 } 303 } 304