|
@@ -0,0 +1,549 @@
|
|
|
+package test_core_io
|
|
|
+
|
|
|
+import "core:bytes"
|
|
|
+import "core:io"
|
|
|
+import "core:log"
|
|
|
+import "core:os"
|
|
|
+import "core:strings"
|
|
|
+import "core:testing"
|
|
|
+
|
|
|
+Passed_Tests :: distinct io.Stream_Mode_Set
|
|
|
+
|
|
|
+_test_stream :: proc(
|
|
|
+ t: ^testing.T,
|
|
|
+ stream: io.Stream,
|
|
|
+ buffer: []u8,
|
|
|
+
|
|
|
+ reading_consumes: bool = false,
|
|
|
+ resets_on_empty: bool = false,
|
|
|
+ do_destroy: bool = true,
|
|
|
+
|
|
|
+ loc := #caller_location
|
|
|
+) -> (passed: Passed_Tests, ok: bool) {
|
|
|
+ // We only test what the stream reports to support.
|
|
|
+
|
|
|
+ mode_set := io.query(stream)
|
|
|
+
|
|
|
+ // Can't feature-test anything if Query isn't supported.
|
|
|
+ testing.expectf(t, .Query in mode_set, "stream does not support .Query: %v", mode_set, loc = loc) or_return
|
|
|
+
|
|
|
+ passed += { .Query }
|
|
|
+
|
|
|
+ size := i64(len(buffer))
|
|
|
+
|
|
|
+ // Do some basic Seek sanity testing.
|
|
|
+ if .Seek in mode_set {
|
|
|
+ pos, err := io.seek(stream, 0, io.Seek_From(-1))
|
|
|
+ testing.expectf(t, pos == 0 && err == .Invalid_Whence,
|
|
|
+ "Seek(-1) didn't fail with Invalid_Whence: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, 0, .Start)
|
|
|
+ testing.expectf(t, pos == 0 && err == nil,
|
|
|
+ "Seek Start isn't 0: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, 0, .Current)
|
|
|
+ testing.expectf(t, pos == 0 && err == nil,
|
|
|
+ "Seek Current isn't 0 at the start: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, -1, .Start)
|
|
|
+ testing.expectf(t, pos == 0 && err == .Invalid_Offset,
|
|
|
+ "Seek Start-1 wasn't Invalid_Offset: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, -1, .Current)
|
|
|
+ testing.expectf(t, pos == 0 && err == .Invalid_Offset,
|
|
|
+ "Seek Current-1 wasn't Invalid_Offset: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, 0, .End)
|
|
|
+ testing.expectf(t, pos == size && err == nil,
|
|
|
+ "Seek End+0 failed: %v != size<%i>, %v", pos, size, err, loc = loc) or_return
|
|
|
+
|
|
|
+ pos, err = io.seek(stream, 0, .Current)
|
|
|
+ testing.expectf(t, pos == size && err == nil,
|
|
|
+ "Seek Current isn't size<%v> at the End: %v, %v", size, pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Seeking past the End is accepted throughout the API.
|
|
|
+ //
|
|
|
+ // It's _reading_ past the End which is erroneous.
|
|
|
+ pos, err = io.seek(stream, 1, .End)
|
|
|
+ testing.expectf(t, pos == size+1 && err == nil,
|
|
|
+ "Seek End+1 failed: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Reset our position for future tests.
|
|
|
+ pos, err = io.seek(stream, 0, .Start)
|
|
|
+ testing.expectf(t, pos == 0 && err == nil,
|
|
|
+ "Seek Start reset failed: %v, %v", pos, err, loc = loc) or_return
|
|
|
+
|
|
|
+ passed += { .Seek }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test Size.
|
|
|
+ if .Size in mode_set {
|
|
|
+ api_size, size_err := io.size(stream)
|
|
|
+ testing.expectf(t, api_size == size,
|
|
|
+ "Size reports %v for its size; expected %v", api_size, size, loc = loc) or_return
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Size expected no error: %v", size_err, loc = loc) or_return
|
|
|
+
|
|
|
+ passed += { .Size }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test Read_At.
|
|
|
+ if .Read_At in mode_set {
|
|
|
+ read_buf, alloc_err := make([]u8, size)
|
|
|
+ testing.expect_value(t, alloc_err, nil, loc = loc) or_return
|
|
|
+ defer delete(read_buf)
|
|
|
+
|
|
|
+ for start in 0..<size {
|
|
|
+ for end in 1+start..<size {
|
|
|
+ subsize := end - start
|
|
|
+ bytes_read, err := io.read_at(stream, read_buf[:subsize], start)
|
|
|
+ testing.expectf(t, i64(bytes_read) == subsize && err == nil,
|
|
|
+ "Read_At(%i) of %v bytes failed: %v, %v", start, subsize, bytes_read, err, loc = loc) or_return
|
|
|
+ testing.expectf(t, bytes.compare(read_buf[:subsize], buffer[start:end]) == 0,
|
|
|
+ "Read_At buffer compare failed: read_buf<%v> != buffer<%v>", read_buf, buffer, loc = loc) or_return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test empty streams and EOF.
|
|
|
+ one_buf: [1]u8
|
|
|
+ bytes_read, err := io.read_at(stream, one_buf[:], size)
|
|
|
+ testing.expectf(t, bytes_read == 0 && err == .EOF,
|
|
|
+ "Read_At at end of stream failed: %v, %v", bytes_read, err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Make sure size is still sane.
|
|
|
+ if .Size in mode_set {
|
|
|
+ api_size, size_err := io.size(stream)
|
|
|
+ testing.expectf(t, api_size == size,
|
|
|
+ "Read_At+Size reports %v for its size after Read_At tests; expected %v", api_size, size, loc = loc) or_return
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Read_At+Size expected no error: %v", size_err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ passed += { .Read_At }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test Read.
|
|
|
+ if .Read in mode_set {
|
|
|
+ if size > 0 {
|
|
|
+ read_buf, alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(read_buf)
|
|
|
+
|
|
|
+ bytes_read, err := io.read(stream, read_buf[:1])
|
|
|
+ testing.expectf(t, bytes_read == 1 && err == nil,
|
|
|
+ "Read 1 byte at start failed: %v, %v", bytes_read, err, loc = loc) or_return
|
|
|
+ testing.expectf(t, read_buf[0] == buffer[0],
|
|
|
+ "Read of first byte failed: read_buf[0]<%v> != buffer[0]<%v>", read_buf[0], buffer[0], loc = loc) or_return
|
|
|
+
|
|
|
+ // Test rolling back the stream one byte then reading it again.
|
|
|
+ if .Seek in mode_set {
|
|
|
+ pos, seek_err := io.seek(stream, -1, .Current)
|
|
|
+ testing.expectf(t, pos == 0 && err == nil,
|
|
|
+ "Read+Seek Current-1 reset to 0 failed: %v, %v", pos, seek_err, loc = loc) or_return
|
|
|
+
|
|
|
+ bytes_read, err = io.read(stream, read_buf[:1])
|
|
|
+ testing.expectf(t, bytes_read == 1 && err == nil,
|
|
|
+ "Read 1 byte at start after Seek reset failed: %v, %v", bytes_read, err, loc = loc) or_return
|
|
|
+ testing.expectf(t, read_buf[0] == buffer[0] ,
|
|
|
+ "re-Read of first byte failed: read_buf[0]<%v> != buffer[0]<%v>", read_buf[0], buffer[0], loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Make sure size is still sane.
|
|
|
+ if .Size in mode_set {
|
|
|
+ api_size, size_err := io.size(stream)
|
|
|
+ expected_api_size := size - 1 if reading_consumes else size
|
|
|
+
|
|
|
+ testing.expectf(t, api_size == expected_api_size,
|
|
|
+ "Read+Size reports %v for its size after Read tests; expected %v", api_size, expected_api_size, loc = loc) or_return
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Read+Size expected no error: %v", size_err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read the rest.
|
|
|
+ if size > 1 {
|
|
|
+ bytes_read, err = io.read(stream, read_buf[1:])
|
|
|
+ testing.expectf(t, i64(bytes_read) == size - 1 && err == nil,
|
|
|
+ "Read rest of stream failed: %v != %v, %v", bytes_read, size-1, err, loc = loc) or_return
|
|
|
+ testing.expectf(t, bytes.compare(read_buf, buffer) == 0,
|
|
|
+ "Read buffer compare failed: read_buf<%v> != buffer<%v>", read_buf, buffer, loc = loc) or_return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test empty streams and EOF.
|
|
|
+ one_buf: [1]u8
|
|
|
+ bytes_read, err := io.read(stream, one_buf[:])
|
|
|
+ testing.expectf(t, bytes_read == 0 && err == .EOF,
|
|
|
+ "Read at end of stream failed: %v, %v", bytes_read, err, loc = loc) or_return
|
|
|
+
|
|
|
+ if !resets_on_empty && .Size in mode_set {
|
|
|
+ // Make sure size is still sane.
|
|
|
+ api_size, size_err := io.size(stream)
|
|
|
+ testing.expectf(t, api_size == size,
|
|
|
+ "Read+Size reports %v for its size after Read tests; expected %v", api_size, size, loc = loc) or_return
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Read+Size expected no error: %v", size_err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ passed += { .Read }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test Write_At.
|
|
|
+ if .Write_At in mode_set {
|
|
|
+ if size > 0 {
|
|
|
+ write_buf, write_buf_alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, write_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(write_buf)
|
|
|
+
|
|
|
+ for i in 0..<size {
|
|
|
+ write_buf[i] = buffer[i] ~ 0xAA
|
|
|
+ }
|
|
|
+
|
|
|
+ bytes_written, write_err := io.write_at(stream, write_buf[:], 0)
|
|
|
+ testing.expectf(t, i64(bytes_written) == size && write_err == nil,
|
|
|
+ "Write_At failed: bytes_written<%v> != size<%v>: %v", bytes_written, size, write_err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Test reading what we've written.
|
|
|
+ if .Read_At in mode_set {
|
|
|
+ read_buf, read_buf_alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(read_buf)
|
|
|
+ bytes_read, read_err := io.read_at(stream, read_buf[:], 0)
|
|
|
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
|
|
|
+ "Write_At+Read_At failed: bytes_read<%i> != size<%i>, %v", bytes_read, size, read_err, loc = loc) or_return
|
|
|
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
|
|
|
+ "Write_At+Read_At buffer compare failed: write_buf<%v> != read_buf<%v>", write_buf, read_buf, loc = loc) or_return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Expect that it should be okay to write a single byte to an empty stream.
|
|
|
+ x_buf: [1]u8 = { 'Z' }
|
|
|
+
|
|
|
+ bytes_written, write_err := io.write_at(stream, x_buf[:], 0)
|
|
|
+ testing.expectf(t, i64(bytes_written) == 1 && write_err == nil,
|
|
|
+ "Write_At(0) with 'Z' on empty stream failed: bytes_written<%v>, %v", bytes_written, write_err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Test reading what we've written.
|
|
|
+ if .Read_At in mode_set {
|
|
|
+ x_buf[0] = 0
|
|
|
+ bytes_read, read_err := io.read_at(stream, x_buf[:], 0)
|
|
|
+ testing.expectf(t, i64(bytes_read) == 1 && read_err == nil,
|
|
|
+ "Write_At(0)+Read_At(0) failed expectation: bytes_read<%v> != 1, %q != 'Z', %v", bytes_read, x_buf[0], read_err, loc = loc) or_return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ passed += { .Write_At }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test Write.
|
|
|
+ if .Write in mode_set {
|
|
|
+ write_buf, write_buf_alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, write_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(write_buf)
|
|
|
+
|
|
|
+ for i in 0..<size {
|
|
|
+ write_buf[i] = buffer[i] ~ 0xAA
|
|
|
+ }
|
|
|
+
|
|
|
+ pos: i64 = -1
|
|
|
+ before_write_size: i64 = -1
|
|
|
+
|
|
|
+ // Do a Seek sanity check after past tests.
|
|
|
+ if .Seek in mode_set {
|
|
|
+ seek_err: io.Error
|
|
|
+ pos, seek_err = io.seek(stream, 0, .Current)
|
|
|
+ testing.expectf(t, seek_err == nil,
|
|
|
+ "Write+Seek(Current) failed: pos<%i>, %v", pos, seek_err) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get the Size before writing.
|
|
|
+ if .Size in mode_set {
|
|
|
+ size_err: io.Error
|
|
|
+ before_write_size, size_err = io.size(stream)
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Write+Size failed: %v", size_err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ bytes_written, write_err := io.write(stream, write_buf[:])
|
|
|
+ testing.expectf(t, i64(bytes_written) == size && write_err == nil,
|
|
|
+ "Write %i bytes failed: %i, %v", size, bytes_written, write_err, loc = loc) or_return
|
|
|
+
|
|
|
+ // Size sanity check, part 2.
|
|
|
+ if before_write_size >= 0 && .Size in mode_set {
|
|
|
+ after_write_size, size_err := io.size(stream)
|
|
|
+ testing.expectf(t, size_err == nil,
|
|
|
+ "Write+Size.part_2 failed: %v", size_err, loc = loc) or_return
|
|
|
+ testing.expectf(t, after_write_size == before_write_size + size,
|
|
|
+ "Write+Size.part_2 failed: %v != %v + %v", after_write_size, before_write_size, size, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test reading what we've written directly with Read_At.
|
|
|
+ if pos >= 0 && .Read_At in mode_set {
|
|
|
+ read_buf, read_buf_alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(read_buf)
|
|
|
+
|
|
|
+ bytes_read, read_err := io.read_at(stream, read_buf[:], pos)
|
|
|
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
|
|
|
+ "Write+Read_At(%i) failed: bytes_read<%i> != size<%i>, %v", pos, bytes_read, size, read_err, loc = loc) or_return
|
|
|
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
|
|
|
+ "Write+Read_At buffer compare failed: read_buf<%v> != write_buf<%v>", read_buf, write_buf, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test resetting the pointer and reading what we've written with Read.
|
|
|
+ if .Read in mode_set && .Seek in mode_set {
|
|
|
+ seek_err: io.Error
|
|
|
+ pos, seek_err = io.seek(stream, 0, .Start)
|
|
|
+ testing.expectf(t, pos == 0 && seek_err == nil,
|
|
|
+ "Write+Read+Seek(Start) failed: pos<%i>, %v", pos, seek_err) or_return
|
|
|
+
|
|
|
+ read_buf, read_buf_alloc_err := make([]u8, size)
|
|
|
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
|
|
|
+ defer delete(read_buf)
|
|
|
+
|
|
|
+ bytes_read, read_err := io.read(stream, read_buf[:])
|
|
|
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
|
|
|
+ "Write+Read failed: bytes_read<%i> != size<%i>, %v", bytes_read, size, read_err, loc = loc) or_return
|
|
|
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
|
|
|
+ "Write+Readbuffer compare failed: read_buf<%v> != write_buf<%v>", read_buf, write_buf, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ passed += { .Write }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test the other modes.
|
|
|
+ if .Flush in mode_set {
|
|
|
+ err := io.flush(stream)
|
|
|
+ testing.expectf(t, err == nil, "stream failed to Flush: %v", err, loc = loc) or_return
|
|
|
+ passed += { .Flush }
|
|
|
+ }
|
|
|
+
|
|
|
+ if .Close in mode_set {
|
|
|
+ close_err := io.close(stream)
|
|
|
+ testing.expectf(t, close_err == nil, "stream failed to Close: %v", close_err, loc = loc) or_return
|
|
|
+ passed += { .Close }
|
|
|
+
|
|
|
+ // TODO(Feoramund): The OS<->IO interface will need updating for more
|
|
|
+ // specific error messages.
|
|
|
+ //
|
|
|
+ // This test will catch it when they start using them, but so long as
|
|
|
+ // they actually error, it should be okay for now.
|
|
|
+ //
|
|
|
+ // .EOF would be a better message for all of these.
|
|
|
+
|
|
|
+ if .Seek in mode_set {
|
|
|
+ pos, err := io.seek(stream, 0, .Start)
|
|
|
+
|
|
|
+ testing.expectf(t, pos == 0 && err == .Invalid_Offset,
|
|
|
+ "Seek after Close unexpected output: pos<%v>, %v", pos, err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ if .Read in mode_set {
|
|
|
+ eof_buf: [1]u8
|
|
|
+ bytes_read, err := io.read(stream, eof_buf[:])
|
|
|
+ testing.expectf(t, bytes_read == 0 && err == .Unknown,
|
|
|
+ "Read after Close unexpected output: bytes_read<%v>, %v", bytes_read, err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ if size > 0 && .Read_At in mode_set {
|
|
|
+ eof_buf: [1]u8
|
|
|
+ bytes_read, err := io.read_at(stream, eof_buf[:], 0)
|
|
|
+ testing.expectf(t, bytes_read == 0 && err == .Unknown,
|
|
|
+ "Read_At after Close unexpected output: bytes_read<%v>, %v", bytes_read, err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ if .Write in mode_set {
|
|
|
+ eof_buf: [1]u8 = {'Z'}
|
|
|
+ bytes_written, err := io.write(stream, eof_buf[:])
|
|
|
+ testing.expectf(t, bytes_written == 0 && err == .Unknown,
|
|
|
+ "Write after Close unexpected output: bytes_written<%v>, %v", bytes_written, err, loc = loc) or_return
|
|
|
+ }
|
|
|
+
|
|
|
+ if .Write_At in mode_set {
|
|
|
+ eof_buf: [1]u8 = {'Z'}
|
|
|
+ bytes_written, err := io.write_at(stream, eof_buf[:], 0)
|
|
|
+ testing.expectf(t, bytes_written == 0 && err == .Unknown,
|
|
|
+ "Write after Close unexpected output: bytes_written<%v>, %v", bytes_written, err, loc = loc) or_return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if do_destroy && .Destroy in mode_set {
|
|
|
+ err := io.destroy(stream)
|
|
|
+ testing.expectf(t, err == nil, "stream failed to Destroy: %v", err, loc = loc) or_return
|
|
|
+ passed += { .Destroy }
|
|
|
+ }
|
|
|
+
|
|
|
+ ok = true
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+@test
|
|
|
+test_bytes_reader :: proc(t: ^testing.T) {
|
|
|
+ buf: [32]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ }
|
|
|
+
|
|
|
+ br: bytes.Reader
|
|
|
+
|
|
|
+ results: Passed_Tests
|
|
|
+ ok: bool
|
|
|
+
|
|
|
+ for end in 0..<i64(len(buf)) {
|
|
|
+ results, ok =_test_stream(t, bytes.reader_init(&br, buf[:end]), buf[:end])
|
|
|
+ if !ok {
|
|
|
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|
|
|
+
|
|
|
+@test
|
|
|
+test_bytes_buffer_stream :: proc(t: ^testing.T) {
|
|
|
+ buf: [32]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ }
|
|
|
+
|
|
|
+ results: Passed_Tests
|
|
|
+ ok: bool
|
|
|
+
|
|
|
+ for end in 0..<i64(len(buf)) {
|
|
|
+ bb: bytes.Buffer
|
|
|
+ // Mind that `bytes.buffer_init` copies the entire underlying slice.
|
|
|
+ bytes.buffer_init(&bb, buf[:end])
|
|
|
+
|
|
|
+ // `bytes.Buffer` has a behavior of decreasing its size with each read
|
|
|
+ // until it eventually clears the underlying buffer when it runs out of
|
|
|
+ // data to read.
|
|
|
+ results, ok = _test_stream(t, bytes.buffer_to_stream(&bb), buf[:end],
|
|
|
+ reading_consumes = true, resets_on_empty = true)
|
|
|
+ if !ok {
|
|
|
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|
|
|
+
|
|
|
+@test
|
|
|
+test_limited_reader :: proc(t: ^testing.T) {
|
|
|
+ buf: [32]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ }
|
|
|
+
|
|
|
+ br: bytes.Reader
|
|
|
+ bs := bytes.reader_init(&br, buf[:])
|
|
|
+
|
|
|
+ lr: io.Limited_Reader
|
|
|
+
|
|
|
+ results: Passed_Tests
|
|
|
+ ok: bool
|
|
|
+
|
|
|
+ for end in 0..<i64(len(buf)) {
|
|
|
+ io.seek(bs, 0, .Start)
|
|
|
+ results, ok = _test_stream(t, io.limited_reader_init(&lr, bs, end), buf[:end])
|
|
|
+ if !ok {
|
|
|
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|
|
|
+
|
|
|
+@test
|
|
|
+test_section_reader :: proc(t: ^testing.T) {
|
|
|
+ buf: [32]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ }
|
|
|
+
|
|
|
+ br: bytes.Reader
|
|
|
+ bs := bytes.reader_init(&br, buf[:])
|
|
|
+
|
|
|
+ sr: io.Section_Reader
|
|
|
+
|
|
|
+ results: Passed_Tests
|
|
|
+ ok: bool
|
|
|
+
|
|
|
+ for start in 0..<i64(len(buf)) {
|
|
|
+ for end in start..<i64(len(buf)) {
|
|
|
+ results, ok = _test_stream(t, io.section_reader_init(&sr, bs, start, end-start), buf[start:end])
|
|
|
+ if !ok {
|
|
|
+ log.debugf("buffer[%i:%i] := %v", start, end, buf[start:end])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|
|
|
+
|
|
|
+@test
|
|
|
+test_string_builder_stream :: proc(t: ^testing.T) {
|
|
|
+ sb := strings.builder_make()
|
|
|
+ defer strings.builder_destroy(&sb)
|
|
|
+
|
|
|
+ // String builders do not support reading, so we'll have to set up a few
|
|
|
+ // things outside the main test.
|
|
|
+
|
|
|
+ buf: [32]u8
|
|
|
+ expected_buf: [64]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ expected_buf[i] = 'A' + i
|
|
|
+ strings.write_byte(&sb, 'A' + i)
|
|
|
+ }
|
|
|
+ for i in 32..<u8(len(expected_buf)) {
|
|
|
+ expected_buf[i] = ('A' + i-len(buf)) ~ 0xAA
|
|
|
+ }
|
|
|
+
|
|
|
+ results, _ := _test_stream(t, strings.to_stream(&sb), buf[:],
|
|
|
+ do_destroy = false)
|
|
|
+
|
|
|
+ testing.expectf(t, bytes.compare(sb.buf[:], expected_buf[:]) == 0, "string builder stream failed:\nbuilder<%q>\n!=\nbuffer <%q>", sb.buf[:], expected_buf[:])
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|
|
|
+
|
|
|
+@test
|
|
|
+test_os_file_stream :: proc(t: ^testing.T) {
|
|
|
+ defer if !testing.failed(t) {
|
|
|
+ testing.expect_value(t, os.remove(TEMPORARY_FILENAME), nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ buf: [32]u8
|
|
|
+ for i in 0..<u8(len(buf)) {
|
|
|
+ buf[i] = 'A' + i
|
|
|
+ }
|
|
|
+
|
|
|
+ TEMPORARY_FILENAME :: "test_core_io_os_file_stream"
|
|
|
+
|
|
|
+ fd, open_err := os.open(TEMPORARY_FILENAME, os.O_RDWR | os.O_CREATE | os.O_TRUNC, 0o644)
|
|
|
+ if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ stream := os.stream_from_handle(fd)
|
|
|
+
|
|
|
+ bytes_written, write_err := io.write(stream, buf[:])
|
|
|
+ if !testing.expectf(t, bytes_written == len(buf) && write_err == nil,
|
|
|
+ "failed to Write initial buffer: bytes_written<%v> != len_buf<%v>, %v", bytes_written, len(buf), write_err) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ flush_err := io.flush(stream)
|
|
|
+ if !testing.expectf(t, flush_err == nil,
|
|
|
+ "failed to Flush initial buffer: %v", write_err) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ results, _ := _test_stream(t, stream, buf[:])
|
|
|
+
|
|
|
+ log.debugf("%#v", results)
|
|
|
+}
|