volume_other_test.odin (3227B)
1 #+build !windows 2 package ntfs 3 4 import "core:fmt" 5 import "core:os" 6 import "core:slice" 7 import "core:testing" 8 9 // A volume is a block device or a file holding an image of one, and both open the 10 // same way, so a file standing in for an image exercises every path here without a 11 // device to read or the rights to read it. 12 @(private = "file") 13 image :: proc(t: ^testing.T, size: int) -> (path: string, content: []byte) { 14 content = make([]byte, size, context.temp_allocator) 15 for i in 0 ..< size { 16 content[i] = byte(i * 7 + 1) 17 } 18 dir, dir_err := os.temp_directory(context.temp_allocator) 19 testing.expect(t, dir_err == nil, "no temp directory") 20 path = fmt.tprintf("%s/sonar_volume_%d.img", dir, size) 21 testing.expect(t, os.write_entire_file(path, content) == nil, "could not write the image") 22 return 23 } 24 25 @(private = "file") 26 discard :: proc(path: string) { 27 _ = os.remove(path) 28 } 29 30 @(test) 31 test_volume_read_at_offsets :: proc(t: ^testing.T) { 32 path, content := image(t, 8192) 33 defer discard(path) 34 35 v, err := volume_open(path) 36 testing.expect_value(t, err, Error.None) 37 defer volume_close(&v) 38 39 // A whole read, a tail read, an aligned middle and a single byte: the reader 40 // works in whole clusters, so every offset it asks for is one of these shapes. 41 spans := [][2]int{{0, 8192}, {4096, 4096}, {512, 1024}, {8191, 1}} 42 for span in spans { 43 off, size := span[0], span[1] 44 buf := make([]byte, size, context.temp_allocator) 45 testing.expect_value(t, volume_read_at(&v, buf, u64(off)), Error.None) 46 testing.expectf( 47 t, 48 slice.equal(buf, content[off:off + size]), 49 "wrong bytes at %d for %d", 50 off, 51 size, 52 ) 53 } 54 } 55 56 @(test) 57 test_volume_read_past_the_end_is_short :: proc(t: ^testing.T) { 58 path, _ := image(t, 1024) 59 defer discard(path) 60 61 v, err := volume_open(path) 62 testing.expect_value(t, err, Error.None) 63 defer volume_close(&v) 64 65 // Asking for more than is there has to say so, or the tail of the buffer would 66 // parse as records that were never read. 67 buf := make([]byte, 4096, context.temp_allocator) 68 testing.expect_value(t, volume_read_at(&v, buf, 0), Error.Short_Read) 69 testing.expect_value(t, volume_read_at(&v, buf[:1], 1024), Error.Short_Read) 70 } 71 72 @(test) 73 test_volume_clone_reads_independently :: proc(t: ^testing.T) { 74 path, content := image(t, 2048) 75 defer discard(path) 76 77 v, err := volume_open(path) 78 testing.expect_value(t, err, Error.None) 79 defer volume_close(&v) 80 81 c, clone_err := volume_clone(&v) 82 testing.expect_value(t, clone_err, Error.None) 83 84 buf := make([]byte, 16, context.temp_allocator) 85 testing.expect_value(t, volume_read_at(&c, buf, 100), Error.None) 86 testing.expect_value(t, buf[0], content[100]) 87 88 // Closing a clone must leave the handle it was made from readable, or the first 89 // worker to finish would take the rest of them with it. 90 volume_close(&c) 91 testing.expect(t, c.file == nil, "a closed volume still holds a handle") 92 testing.expect_value(t, volume_read_at(&v, buf, 100), Error.None) 93 testing.expect_value(t, buf[0], content[100]) 94 } 95 96 @(test) 97 test_volume_open_missing_path :: proc(t: ^testing.T) { 98 v, err := volume_open("/nonexistent/sonar/volume.img") 99 testing.expect_value(t, err, Error.Open_Failed) 100 testing.expect(t, v.file == nil, "a failed open returned a handle") 101 }