| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/tests/test_file_io.h" | 5 #include "ppapi/tests/test_file_io.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 | 9 |
| 10 #include "ppapi/c/pp_errors.h" | 10 #include "ppapi/c/pp_errors.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 std::string ReportMismatch(const std::string& method_name, | 25 std::string ReportMismatch(const std::string& method_name, |
| 26 const std::string& returned_result, | 26 const std::string& returned_result, |
| 27 const std::string& expected_result) { | 27 const std::string& expected_result) { |
| 28 return method_name + " returned '" + returned_result + "'; '" + | 28 return method_name + " returned '" + returned_result + "'; '" + |
| 29 expected_result + "' expected."; | 29 expected_result + "' expected."; |
| 30 } | 30 } |
| 31 | 31 |
| 32 int32_t ReadEntireFile(pp::FileIO_Dev* file_io, | 32 int32_t ReadEntireFile(PP_Instance instance, |
| 33 pp::FileIO_Dev* file_io, |
| 33 int32_t offset, | 34 int32_t offset, |
| 34 std::string* data) { | 35 std::string* data) { |
| 35 TestCompletionCallback callback; | 36 TestCompletionCallback callback(instance); |
| 36 char buf[256]; | 37 char buf[256]; |
| 37 int32_t read_offset = offset; | 38 int32_t read_offset = offset; |
| 38 | 39 |
| 39 for (;;) { | 40 for (;;) { |
| 40 int32_t rv = file_io->Read(read_offset, buf, sizeof(buf), callback); | 41 int32_t rv = file_io->Read(read_offset, buf, sizeof(buf), callback); |
| 41 if (rv == PP_ERROR_WOULDBLOCK) | 42 if (rv == PP_ERROR_WOULDBLOCK) |
| 42 rv = callback.WaitForResult(); | 43 rv = callback.WaitForResult(); |
| 43 if (rv < 0) | 44 if (rv < 0) |
| 44 return rv; | 45 return rv; |
| 45 if (rv == 0) | 46 if (rv == 0) |
| 46 break; | 47 break; |
| 47 read_offset += rv; | 48 read_offset += rv; |
| 48 data->append(buf, rv); | 49 data->append(buf, rv); |
| 49 } | 50 } |
| 50 | 51 |
| 51 return PP_OK; | 52 return PP_OK; |
| 52 } | 53 } |
| 53 | 54 |
| 54 int32_t WriteEntireBuffer(pp::FileIO_Dev* file_io, | 55 int32_t WriteEntireBuffer(PP_Instance instance, |
| 56 pp::FileIO_Dev* file_io, |
| 55 int32_t offset, | 57 int32_t offset, |
| 56 const std::string& data) { | 58 const std::string& data) { |
| 57 TestCompletionCallback callback; | 59 TestCompletionCallback callback(instance); |
| 58 int32_t write_offset = offset; | 60 int32_t write_offset = offset; |
| 59 const char* buf = data.c_str(); | 61 const char* buf = data.c_str(); |
| 60 int32_t size = data.size(); | 62 int32_t size = data.size(); |
| 61 | 63 |
| 62 while (write_offset < offset + size) { | 64 while (write_offset < offset + size) { |
| 63 int32_t rv = file_io->Write(write_offset, &buf[write_offset - offset], | 65 int32_t rv = file_io->Write(write_offset, &buf[write_offset - offset], |
| 64 size - write_offset + offset, callback); | 66 size - write_offset + offset, callback); |
| 65 if (rv == PP_ERROR_WOULDBLOCK) | 67 if (rv == PP_ERROR_WOULDBLOCK) |
| 66 rv = callback.WaitForResult(); | 68 rv = callback.WaitForResult(); |
| 67 if (rv < 0) | 69 if (rv < 0) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 84 RUN_TEST(Open); | 86 RUN_TEST(Open); |
| 85 RUN_TEST(ReadWriteSetLength); | 87 RUN_TEST(ReadWriteSetLength); |
| 86 RUN_TEST(TouchQuery); | 88 RUN_TEST(TouchQuery); |
| 87 RUN_TEST(AbortCalls); | 89 RUN_TEST(AbortCalls); |
| 88 // TODO(viettrungluu): add tests: | 90 // TODO(viettrungluu): add tests: |
| 89 // - that PP_ERROR_PENDING is correctly returned | 91 // - that PP_ERROR_PENDING is correctly returned |
| 90 // - that operations respect the file open modes (flags) | 92 // - that operations respect the file open modes (flags) |
| 91 } | 93 } |
| 92 | 94 |
| 93 std::string TestFileIO::TestOpen() { | 95 std::string TestFileIO::TestOpen() { |
| 94 TestCompletionCallback callback; | 96 TestCompletionCallback callback(instance_->pp_instance()); |
| 95 | 97 |
| 96 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); | 98 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); |
| 97 pp::FileRef_Dev file_ref(file_system, "/file_open"); | 99 pp::FileRef_Dev file_ref(file_system, "/file_open"); |
| 98 int32_t rv = file_system.Open(1024, callback); | 100 int32_t rv = file_system.Open(1024, callback); |
| 99 if (rv == PP_ERROR_WOULDBLOCK) | 101 if (rv == PP_ERROR_WOULDBLOCK) |
| 100 rv = callback.WaitForResult(); | 102 rv = callback.WaitForResult(); |
| 101 if (rv != PP_OK) | 103 if (rv != PP_OK) |
| 102 return ReportError("FileSystem::Open", rv); | 104 return ReportError("FileSystem::Open", rv); |
| 103 | 105 |
| 104 pp::FileIO_Dev file_io(instance_); | 106 pp::FileIO_Dev file_io(instance_); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 115 nonexistent_file_ref, PP_FILEOPENFLAG_READ, callback); | 117 nonexistent_file_ref, PP_FILEOPENFLAG_READ, callback); |
| 116 if (rv == PP_ERROR_WOULDBLOCK) | 118 if (rv == PP_ERROR_WOULDBLOCK) |
| 117 rv = callback.WaitForResult(); | 119 rv = callback.WaitForResult(); |
| 118 if (rv != PP_ERROR_FILENOTFOUND) | 120 if (rv != PP_ERROR_FILENOTFOUND) |
| 119 return ReportError("FileIO::Open", rv); | 121 return ReportError("FileIO::Open", rv); |
| 120 | 122 |
| 121 PASS(); | 123 PASS(); |
| 122 } | 124 } |
| 123 | 125 |
| 124 std::string TestFileIO::TestReadWriteSetLength() { | 126 std::string TestFileIO::TestReadWriteSetLength() { |
| 125 TestCompletionCallback callback; | 127 TestCompletionCallback callback(instance_->pp_instance()); |
| 126 | 128 |
| 127 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); | 129 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); |
| 128 pp::FileRef_Dev file_ref(file_system, "/file_read_write_setlength"); | 130 pp::FileRef_Dev file_ref(file_system, "/file_read_write_setlength"); |
| 129 int32_t rv = file_system.Open(1024, callback); | 131 int32_t rv = file_system.Open(1024, callback); |
| 130 if (rv == PP_ERROR_WOULDBLOCK) | 132 if (rv == PP_ERROR_WOULDBLOCK) |
| 131 rv = callback.WaitForResult(); | 133 rv = callback.WaitForResult(); |
| 132 if (rv != PP_OK) | 134 if (rv != PP_OK) |
| 133 return ReportError("FileSystem::Open", rv); | 135 return ReportError("FileSystem::Open", rv); |
| 134 | 136 |
| 135 pp::FileIO_Dev file_io(instance_); | 137 pp::FileIO_Dev file_io(instance_); |
| 136 rv = file_io.Open(file_ref, | 138 rv = file_io.Open(file_ref, |
| 137 PP_FILEOPENFLAG_CREATE | | 139 PP_FILEOPENFLAG_CREATE | |
| 138 PP_FILEOPENFLAG_READ | | 140 PP_FILEOPENFLAG_READ | |
| 139 PP_FILEOPENFLAG_WRITE, | 141 PP_FILEOPENFLAG_WRITE, |
| 140 callback); | 142 callback); |
| 141 if (rv == PP_ERROR_WOULDBLOCK) | 143 if (rv == PP_ERROR_WOULDBLOCK) |
| 142 rv = callback.WaitForResult(); | 144 rv = callback.WaitForResult(); |
| 143 if (rv != PP_OK) | 145 if (rv != PP_OK) |
| 144 return ReportError("FileIO::Open", rv); | 146 return ReportError("FileIO::Open", rv); |
| 145 | 147 |
| 146 // Write something to the file. | 148 // Write something to the file. |
| 147 rv = WriteEntireBuffer(&file_io, 0, "test_test"); | 149 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, "test_test"); |
| 148 if (rv != PP_OK) | 150 if (rv != PP_OK) |
| 149 return ReportError("FileIO::Write", rv); | 151 return ReportError("FileIO::Write", rv); |
| 150 | 152 |
| 151 // Read the entire file. | 153 // Read the entire file. |
| 152 std::string read_buffer; | 154 std::string read_buffer; |
| 153 rv = ReadEntireFile(&file_io, 0, &read_buffer); | 155 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer); |
| 154 if (rv != PP_OK) | 156 if (rv != PP_OK) |
| 155 return ReportError("FileIO::Read", rv); | 157 return ReportError("FileIO::Read", rv); |
| 156 if (read_buffer != "test_test") | 158 if (read_buffer != "test_test") |
| 157 return ReportMismatch("FileIO::Read", read_buffer, "test_test"); | 159 return ReportMismatch("FileIO::Read", read_buffer, "test_test"); |
| 158 | 160 |
| 159 // Truncate the file. | 161 // Truncate the file. |
| 160 rv = file_io.SetLength(4, callback); | 162 rv = file_io.SetLength(4, callback); |
| 161 if (rv == PP_ERROR_WOULDBLOCK) | 163 if (rv == PP_ERROR_WOULDBLOCK) |
| 162 rv = callback.WaitForResult(); | 164 rv = callback.WaitForResult(); |
| 163 if (rv != PP_OK) | 165 if (rv != PP_OK) |
| 164 return ReportError("FileIO::SetLength", rv); | 166 return ReportError("FileIO::SetLength", rv); |
| 165 | 167 |
| 166 // Check the file contents. | 168 // Check the file contents. |
| 167 read_buffer.clear(); | 169 read_buffer.clear(); |
| 168 rv = ReadEntireFile(&file_io, 0, &read_buffer); | 170 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer); |
| 169 if (rv != PP_OK) | 171 if (rv != PP_OK) |
| 170 return ReportError("FileIO::Read", rv); | 172 return ReportError("FileIO::Read", rv); |
| 171 if (read_buffer != "test") | 173 if (read_buffer != "test") |
| 172 return ReportMismatch("FileIO::Read", read_buffer, "test"); | 174 return ReportMismatch("FileIO::Read", read_buffer, "test"); |
| 173 | 175 |
| 174 // Try to read past the end of the file. | 176 // Try to read past the end of the file. |
| 175 read_buffer.clear(); | 177 read_buffer.clear(); |
| 176 rv = ReadEntireFile(&file_io, 100, &read_buffer); | 178 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 100, &read_buffer); |
| 177 if (rv != PP_OK) | 179 if (rv != PP_OK) |
| 178 return ReportError("FileIO::Read", rv); | 180 return ReportError("FileIO::Read", rv); |
| 179 if (!read_buffer.empty()) | 181 if (!read_buffer.empty()) |
| 180 return ReportMismatch("FileIO::Read", read_buffer, "<empty string>"); | 182 return ReportMismatch("FileIO::Read", read_buffer, "<empty string>"); |
| 181 | 183 |
| 182 // Write past the end of the file. The file should be zero-padded. | 184 // Write past the end of the file. The file should be zero-padded. |
| 183 rv = WriteEntireBuffer(&file_io, 8, "test"); | 185 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test"); |
| 184 if (rv != PP_OK) | 186 if (rv != PP_OK) |
| 185 return ReportError("FileIO::Write", rv); | 187 return ReportError("FileIO::Write", rv); |
| 186 | 188 |
| 187 // Check the contents of the file. | 189 // Check the contents of the file. |
| 188 read_buffer.clear(); | 190 read_buffer.clear(); |
| 189 rv = ReadEntireFile(&file_io, 0, &read_buffer); | 191 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer); |
| 190 if (rv != PP_OK) | 192 if (rv != PP_OK) |
| 191 return ReportError("FileIO::Read", rv); | 193 return ReportError("FileIO::Read", rv); |
| 192 if (read_buffer != std::string("test\0\0\0\0test", 12)) | 194 if (read_buffer != std::string("test\0\0\0\0test", 12)) |
| 193 return ReportMismatch("FileIO::Read", read_buffer, | 195 return ReportMismatch("FileIO::Read", read_buffer, |
| 194 std::string("test\0\0\0\0test", 12)); | 196 std::string("test\0\0\0\0test", 12)); |
| 195 | 197 |
| 196 // Extend the file. | 198 // Extend the file. |
| 197 rv = file_io.SetLength(16, callback); | 199 rv = file_io.SetLength(16, callback); |
| 198 if (rv == PP_ERROR_WOULDBLOCK) | 200 if (rv == PP_ERROR_WOULDBLOCK) |
| 199 rv = callback.WaitForResult(); | 201 rv = callback.WaitForResult(); |
| 200 if (rv != PP_OK) | 202 if (rv != PP_OK) |
| 201 return ReportError("FileIO::SetLength", rv); | 203 return ReportError("FileIO::SetLength", rv); |
| 202 | 204 |
| 203 // Check the contents of the file. | 205 // Check the contents of the file. |
| 204 read_buffer.clear(); | 206 read_buffer.clear(); |
| 205 rv = ReadEntireFile(&file_io, 0, &read_buffer); | 207 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer); |
| 206 if (rv != PP_OK) | 208 if (rv != PP_OK) |
| 207 return ReportError("FileIO::Read", rv); | 209 return ReportError("FileIO::Read", rv); |
| 208 if (read_buffer != std::string("test\0\0\0\0test\0\0\0\0", 16)) | 210 if (read_buffer != std::string("test\0\0\0\0test\0\0\0\0", 16)) |
| 209 return ReportMismatch("FileIO::Read", read_buffer, | 211 return ReportMismatch("FileIO::Read", read_buffer, |
| 210 std::string("test\0\0\0\0test\0\0\0\0", 16)); | 212 std::string("test\0\0\0\0test\0\0\0\0", 16)); |
| 211 | 213 |
| 212 // Write in the middle of the file. | 214 // Write in the middle of the file. |
| 213 rv = WriteEntireBuffer(&file_io, 4, "test"); | 215 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test"); |
| 214 if (rv != PP_OK) | 216 if (rv != PP_OK) |
| 215 return ReportError("FileIO::Write", rv); | 217 return ReportError("FileIO::Write", rv); |
| 216 | 218 |
| 217 // Check the contents of the file. | 219 // Check the contents of the file. |
| 218 read_buffer.clear(); | 220 read_buffer.clear(); |
| 219 rv = ReadEntireFile(&file_io, 0, &read_buffer); | 221 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer); |
| 220 if (rv != PP_OK) | 222 if (rv != PP_OK) |
| 221 return ReportError("FileIO::Read", rv); | 223 return ReportError("FileIO::Read", rv); |
| 222 if (read_buffer != std::string("testtesttest\0\0\0\0", 16)) | 224 if (read_buffer != std::string("testtesttest\0\0\0\0", 16)) |
| 223 return ReportMismatch("FileIO::Read", read_buffer, | 225 return ReportMismatch("FileIO::Read", read_buffer, |
| 224 std::string("testtesttest\0\0\0\0", 16)); | 226 std::string("testtesttest\0\0\0\0", 16)); |
| 225 | 227 |
| 226 // Read from the middle of the file. | 228 // Read from the middle of the file. |
| 227 read_buffer.clear(); | 229 read_buffer.clear(); |
| 228 rv = ReadEntireFile(&file_io, 4, &read_buffer); | 230 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 4, &read_buffer); |
| 229 if (rv != PP_OK) | 231 if (rv != PP_OK) |
| 230 return ReportError("FileIO::Read", rv); | 232 return ReportError("FileIO::Read", rv); |
| 231 if (read_buffer != std::string("testtest\0\0\0\0", 12)) | 233 if (read_buffer != std::string("testtest\0\0\0\0", 12)) |
| 232 return ReportMismatch("FileIO::Read", read_buffer, | 234 return ReportMismatch("FileIO::Read", read_buffer, |
| 233 std::string("testtest\0\0\0\0", 12)); | 235 std::string("testtest\0\0\0\0", 12)); |
| 234 | 236 |
| 235 PASS(); | 237 PASS(); |
| 236 } | 238 } |
| 237 | 239 |
| 238 std::string TestFileIO::TestTouchQuery() { | 240 std::string TestFileIO::TestTouchQuery() { |
| 239 TestCompletionCallback callback; | 241 TestCompletionCallback callback(instance_->pp_instance()); |
| 240 | 242 |
| 241 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); | 243 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); |
| 242 int32_t rv = file_system.Open(1024, callback); | 244 int32_t rv = file_system.Open(1024, callback); |
| 243 if (rv == PP_ERROR_WOULDBLOCK) | 245 if (rv == PP_ERROR_WOULDBLOCK) |
| 244 rv = callback.WaitForResult(); | 246 rv = callback.WaitForResult(); |
| 245 if (rv != PP_OK) | 247 if (rv != PP_OK) |
| 246 return ReportError("FileSystem::Open", rv); | 248 return ReportError("FileSystem::Open", rv); |
| 247 | 249 |
| 248 pp::FileRef_Dev file_ref(file_system, "/file_touch"); | 250 pp::FileRef_Dev file_ref(file_system, "/file_touch"); |
| 249 pp::FileIO_Dev file_io(instance_); | 251 pp::FileIO_Dev file_io(instance_); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 rv = file_io.Query(&info, callback); | 292 rv = file_io.Query(&info, callback); |
| 291 if (rv == PP_ERROR_WOULDBLOCK) | 293 if (rv == PP_ERROR_WOULDBLOCK) |
| 292 rv = callback.WaitForResult(); | 294 rv = callback.WaitForResult(); |
| 293 if (rv != PP_OK) | 295 if (rv != PP_OK) |
| 294 return ReportError("FileSystem::Query", rv); | 296 return ReportError("FileSystem::Query", rv); |
| 295 | 297 |
| 296 PASS(); | 298 PASS(); |
| 297 } | 299 } |
| 298 | 300 |
| 299 std::string TestFileIO::TestAbortCalls() { | 301 std::string TestFileIO::TestAbortCalls() { |
| 300 TestCompletionCallback callback; | 302 TestCompletionCallback callback(instance_->pp_instance()); |
| 301 | 303 |
| 302 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); | 304 pp::FileSystem_Dev file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); |
| 303 pp::FileRef_Dev file_ref(file_system, "/file_abort_calls"); | 305 pp::FileRef_Dev file_ref(file_system, "/file_abort_calls"); |
| 304 int32_t rv = file_system.Open(1024, callback); | 306 int32_t rv = file_system.Open(1024, callback); |
| 305 if (rv == PP_ERROR_WOULDBLOCK) | 307 if (rv == PP_ERROR_WOULDBLOCK) |
| 306 rv = callback.WaitForResult(); | 308 rv = callback.WaitForResult(); |
| 307 if (rv != PP_OK) | 309 if (rv != PP_OK) |
| 308 return ReportError("FileSystem::Open", rv); | 310 return ReportError("FileSystem::Open", rv); |
| 309 | 311 |
| 310 // First, create a file which to do ops on. | 312 // First, create a file which to do ops on. |
| 311 { | 313 { |
| 312 pp::FileIO_Dev file_io(instance_); | 314 pp::FileIO_Dev file_io(instance_); |
| 313 rv = file_io.Open(file_ref, | 315 rv = file_io.Open(file_ref, |
| 314 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, | 316 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, |
| 315 callback); | 317 callback); |
| 316 if (rv == PP_ERROR_WOULDBLOCK) | 318 if (rv == PP_ERROR_WOULDBLOCK) |
| 317 rv = callback.WaitForResult(); | 319 rv = callback.WaitForResult(); |
| 318 if (rv != PP_OK) | 320 if (rv != PP_OK) |
| 319 return ReportError("FileIO::Open", rv); | 321 return ReportError("FileIO::Open", rv); |
| 320 | 322 |
| 321 // N.B.: Should write at least 3 bytes. | 323 // N.B.: Should write at least 3 bytes. |
| 322 rv = WriteEntireBuffer(&file_io, 0, "foobarbazquux"); | 324 rv = WriteEntireBuffer(instance_->pp_instance(), |
| 325 &file_io, |
| 326 0, |
| 327 "foobarbazquux"); |
| 323 if (rv != PP_OK) | 328 if (rv != PP_OK) |
| 324 return ReportError("FileIO::Write", rv); | 329 return ReportError("FileIO::Write", rv); |
| 325 } | 330 } |
| 326 | 331 |
| 327 // Abort |Open()|. | 332 // Abort |Open()|. |
| 328 { | 333 { |
| 329 callback.reset_run_count(); | 334 callback.reset_run_count(); |
| 330 rv = pp::FileIO_Dev(instance_) | 335 rv = pp::FileIO_Dev(instance_) |
| 331 .Open(file_ref, PP_FILEOPENFLAG_READ,callback); | 336 .Open(file_ref, PP_FILEOPENFLAG_READ,callback); |
| 332 if (callback.run_count() > 0) | 337 if (callback.run_count() > 0) |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 } | 490 } |
| 486 } | 491 } |
| 487 | 492 |
| 488 // TODO(viettrungluu): Also test that Close() aborts callbacks. | 493 // TODO(viettrungluu): Also test that Close() aborts callbacks. |
| 489 // crbug.com/69457 | 494 // crbug.com/69457 |
| 490 | 495 |
| 491 PASS(); | 496 PASS(); |
| 492 } | 497 } |
| 493 | 498 |
| 494 // TODO(viettrungluu): Test Close(). crbug.com/69457 | 499 // TODO(viettrungluu): Test Close(). crbug.com/69457 |
| OLD | NEW |