Bytesrw adapter for Eio
ocaml codec
at main 7.1 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(* Test reading from a mock flow *) 7let test_reader_basic () = 8 Eio_main.run @@ fun _env -> 9 let test_data = "Hello, World!" in 10 let flow = Eio.Flow.string_source test_data in 11 let reader = Bytesrw_eio.bytes_reader_of_flow flow in 12 13 (* Read first slice *) 14 let slice1 = Bytesrw.Bytes.Reader.read reader in 15 Alcotest.(check bool) "slice is not eod" false (Bytesrw.Bytes.Slice.is_eod slice1); 16 17 let read_data = Bytes.sub_string 18 (Bytesrw.Bytes.Slice.bytes slice1) 19 (Bytesrw.Bytes.Slice.first slice1) 20 (Bytesrw.Bytes.Slice.length slice1) in 21 Alcotest.(check string) "data matches" test_data read_data; 22 23 (* Next read should be eod *) 24 let slice2 = Bytesrw.Bytes.Reader.read reader in 25 Alcotest.(check bool) "second read is eod" true (Bytesrw.Bytes.Slice.is_eod slice2) 26 27(* Test reading with custom slice length *) 28let test_reader_custom_slice_length () = 29 Eio_main.run @@ fun _env -> 30 let test_data = "Hello, World!" in 31 let flow = Eio.Flow.string_source test_data in 32 let slice_length = 5 in 33 let reader = Bytesrw_eio.bytes_reader_of_flow ~slice_length flow in 34 35 (* Read should respect slice_length as maximum *) 36 let slice = Bytesrw.Bytes.Reader.read reader in 37 Alcotest.(check bool) "slice length <= custom size" true 38 (Bytesrw.Bytes.Slice.length slice <= slice_length) 39 40(* Test reading empty flow *) 41let test_reader_empty () = 42 Eio_main.run @@ fun _env -> 43 let flow = Eio.Flow.string_source "" in 44 let reader = Bytesrw_eio.bytes_reader_of_flow flow in 45 46 let slice = Bytesrw.Bytes.Reader.read reader in 47 Alcotest.(check bool) "empty flow returns eod" true (Bytesrw.Bytes.Slice.is_eod slice) 48 49(* Test writing to a mock flow *) 50let test_writer_basic () = 51 Eio_main.run @@ fun _env -> 52 let buf = Buffer.create 100 in 53 let flow = Eio.Flow.buffer_sink buf in 54 let writer = Bytesrw_eio.bytes_writer_of_flow flow in 55 56 let test_data = "Hello, World!" in 57 let bytes = Bytes.of_string test_data in 58 let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 59 60 Bytesrw.Bytes.Writer.write writer slice; 61 62 let written = Buffer.contents buf in 63 Alcotest.(check string) "written data matches" test_data written 64 65(* Test writing with custom slice length *) 66let test_writer_custom_slice_length () = 67 Eio_main.run @@ fun _env -> 68 let buf = Buffer.create 100 in 69 let flow = Eio.Flow.buffer_sink buf in 70 let slice_length = 8 in 71 let writer = Bytesrw_eio.bytes_writer_of_flow ~slice_length flow in 72 73 let test_data = "Hello, World!" in 74 let bytes = Bytes.of_string test_data in 75 let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 76 77 Bytesrw.Bytes.Writer.write writer slice; 78 79 let written = Buffer.contents buf in 80 Alcotest.(check string) "written data matches regardless of slice_length" test_data written 81 82(* Test writing eod slice (should be no-op) *) 83let test_writer_eod () = 84 Eio_main.run @@ fun _env -> 85 let buf = Buffer.create 100 in 86 let flow = Eio.Flow.buffer_sink buf in 87 let writer = Bytesrw_eio.bytes_writer_of_flow flow in 88 89 Bytesrw.Bytes.Writer.write writer Bytesrw.Bytes.Slice.eod; 90 91 let written = Buffer.contents buf in 92 Alcotest.(check string) "eod writes nothing" "" written 93 94(* Test writing partial slice *) 95let test_writer_partial_slice () = 96 Eio_main.run @@ fun _env -> 97 let buf = Buffer.create 100 in 98 let flow = Eio.Flow.buffer_sink buf in 99 let writer = Bytesrw_eio.bytes_writer_of_flow flow in 100 101 let test_data = "Hello, World!" in 102 let bytes = Bytes.of_string test_data in 103 (* Write only "World" *) 104 let slice = Bytesrw.Bytes.Slice.make bytes ~first:7 ~length:5 in 105 106 Bytesrw.Bytes.Writer.write writer slice; 107 108 let written = Buffer.contents buf in 109 Alcotest.(check string) "partial slice written" "World" written 110 111(* Test multiple reads to ensure data isolation - buffers from previous reads 112 should not be corrupted by subsequent reads *) 113let test_reader_multiple_reads () = 114 Eio_main.run @@ fun _env -> 115 let test_data = "ABCDEFGHIJ" in (* 10 bytes *) 116 let flow = Eio.Flow.string_source test_data in 117 let reader = Bytesrw_eio.bytes_reader_of_flow ~slice_length:5 flow in 118 119 (* Read first 5 bytes *) 120 let slice1 = Bytesrw.Bytes.Reader.read reader in 121 let bytes1 = Bytesrw.Bytes.Slice.bytes slice1 in 122 let data1 = Bytes.sub_string bytes1 123 (Bytesrw.Bytes.Slice.first slice1) 124 (Bytesrw.Bytes.Slice.length slice1) in 125 126 (* Read next 5 bytes *) 127 let slice2 = Bytesrw.Bytes.Reader.read reader in 128 let data2 = Bytes.sub_string 129 (Bytesrw.Bytes.Slice.bytes slice2) 130 (Bytesrw.Bytes.Slice.first slice2) 131 (Bytesrw.Bytes.Slice.length slice2) in 132 133 (* Critical test: verify first read's data is STILL intact after second read 134 This would fail if we were reusing buffers or if Cstruct.to_bytes created a view *) 135 let data1_check = Bytes.sub_string bytes1 136 (Bytesrw.Bytes.Slice.first slice1) 137 (Bytesrw.Bytes.Slice.length slice1) in 138 139 Alcotest.(check string) "first read" "ABCDE" data1; 140 Alcotest.(check string) "second read" "FGHIJ" data2; 141 Alcotest.(check string) "first read still intact after second" "ABCDE" data1_check 142 143(* Test round-trip: write then read *) 144let test_roundtrip () = 145 Eio_main.run @@ fun _env -> 146 let test_data = "Round-trip test data" in 147 148 (* Write to buffer *) 149 let buf = Buffer.create 100 in 150 let write_flow = Eio.Flow.buffer_sink buf in 151 let writer = Bytesrw_eio.bytes_writer_of_flow write_flow in 152 153 let bytes = Bytes.of_string test_data in 154 let slice = Bytesrw.Bytes.Slice.make bytes ~first:0 ~length:(Bytes.length bytes) in 155 Bytesrw.Bytes.Writer.write writer slice; 156 157 (* Read back from buffer *) 158 let read_flow = Eio.Flow.string_source (Buffer.contents buf) in 159 let reader = Bytesrw_eio.bytes_reader_of_flow read_flow in 160 161 let read_slice = Bytesrw.Bytes.Reader.read reader in 162 let read_data = Bytes.sub_string 163 (Bytesrw.Bytes.Slice.bytes read_slice) 164 (Bytesrw.Bytes.Slice.first read_slice) 165 (Bytesrw.Bytes.Slice.length read_slice) in 166 167 Alcotest.(check string) "round-trip data matches" test_data read_data 168 169let () = 170 Alcotest.run "Bytesrw_eio" [ 171 "reader", [ 172 Alcotest.test_case "basic read" `Quick test_reader_basic; 173 Alcotest.test_case "custom slice length" `Quick test_reader_custom_slice_length; 174 Alcotest.test_case "empty flow" `Quick test_reader_empty; 175 Alcotest.test_case "multiple reads data isolation" `Quick test_reader_multiple_reads; 176 ]; 177 "writer", [ 178 Alcotest.test_case "basic write" `Quick test_writer_basic; 179 Alcotest.test_case "custom slice length" `Quick test_writer_custom_slice_length; 180 Alcotest.test_case "eod write" `Quick test_writer_eod; 181 Alcotest.test_case "partial slice" `Quick test_writer_partial_slice; 182 ]; 183 "integration", [ 184 Alcotest.test_case "round-trip" `Quick test_roundtrip; 185 ]; 186 ]