|
| 1 | +// Based on: |
| 2 | +// * https://users.rust-lang.org/t/existing-tests-for-read-write-and-seek-traits/72991/2 |
| 3 | +// * https://github.com/rust-lang/rust/blob/a2ebd5a1f12f4242edf66cbbd471c421bec62753/library/std/src/io/cursor/tests.rs |
| 4 | + |
| 5 | +#![feature(io_slice_advance)] |
| 6 | +#![feature(write_all_vectored)] |
| 7 | + |
| 8 | +use ic_cdk_macros::{init, query, update}; |
| 9 | +use std::io::{IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; |
| 10 | + |
| 11 | +thread_local! { |
| 12 | + static STABLE_MEMORY: std::cell::RefCell<icfs::StableMemory> |
| 13 | + = std::cell::RefCell::new(icfs::StableMemory::default()); |
| 14 | +} |
| 15 | + |
| 16 | +fn setup() { |
| 17 | + STABLE_MEMORY.with(|stable_memory| { |
| 18 | + let mut stable_memory = *stable_memory.borrow(); |
| 19 | + let capacity = icfs::StableMemory::capacity(); |
| 20 | + let b: &[_] = &vec![0; capacity]; |
| 21 | + |
| 22 | + ic_cdk::api::stable::stable64_write(0, &b); |
| 23 | + assert_eq!(&icfs::StableMemory::bytes()[..], b); |
| 24 | + |
| 25 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 26 | + assert_eq!(stable_memory.stream_position().unwrap(), 0); |
| 27 | + }) |
| 28 | +} |
| 29 | + |
| 30 | +#[update] |
| 31 | +fn test_writer() { |
| 32 | + setup(); |
| 33 | + STABLE_MEMORY.with(|stable_memory| { |
| 34 | + let mut stable_memory = *stable_memory.borrow(); |
| 35 | + assert_eq!(stable_memory.write(&[0]).unwrap(), 1); |
| 36 | + assert_eq!(stable_memory.write(&[1, 2, 3]).unwrap(), 3); |
| 37 | + assert_eq!(stable_memory.write(&[4, 5, 6, 7]).unwrap(), 4); |
| 38 | + stable_memory |
| 39 | + .write_all_vectored(&mut [ |
| 40 | + IoSlice::new(&[]), |
| 41 | + IoSlice::new(&[8, 9]), |
| 42 | + IoSlice::new(&[10]), |
| 43 | + ]) |
| 44 | + .unwrap(); |
| 45 | + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
| 46 | + assert_eq!(&icfs::StableMemory::bytes()[0..11], b); |
| 47 | + }) |
| 48 | +} |
| 49 | + |
| 50 | +#[update] |
| 51 | +fn test_writer_vectored() { |
| 52 | + setup(); |
| 53 | + STABLE_MEMORY.with(|stable_memory| { |
| 54 | + let mut stable_memory = *stable_memory.borrow(); |
| 55 | + assert_eq!(stable_memory.stream_position().unwrap(), 0); |
| 56 | + |
| 57 | + stable_memory.write_all_vectored(&mut [IoSlice::new(&[0])]).unwrap(); |
| 58 | + assert_eq!(stable_memory.stream_position().unwrap(), 1); |
| 59 | + |
| 60 | + stable_memory.write_all_vectored(&mut [IoSlice::new(&mut [1, 2, 3]), IoSlice::new(&mut [4, 5, 6, 7]),]).unwrap(); |
| 61 | + assert_eq!(stable_memory.stream_position().unwrap(), 8); |
| 62 | + |
| 63 | + stable_memory.write_all_vectored(&mut []).unwrap(); |
| 64 | + assert_eq!(stable_memory.stream_position().unwrap(), 8); |
| 65 | + |
| 66 | + stable_memory.write_all_vectored(&mut [IoSlice::new(&[8, 9])]).unwrap(); |
| 67 | + stable_memory.write_all_vectored(&mut [IoSlice::new(&[10])]).unwrap(); |
| 68 | + |
| 69 | + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; |
| 70 | + assert_eq!(&icfs::StableMemory::bytes()[0..9], b); |
| 71 | + }) |
| 72 | +} |
| 73 | + |
| 74 | +#[update] |
| 75 | +fn test_writer_seek() { |
| 76 | + setup(); |
| 77 | + STABLE_MEMORY.with(|stable_memory| { |
| 78 | + let mut stable_memory = *stable_memory.borrow(); |
| 79 | + |
| 80 | + assert_eq!(stable_memory.stream_position().unwrap(), 0); |
| 81 | + assert_eq!(stable_memory.write(&[1]).unwrap(), 1); |
| 82 | + assert_eq!(stable_memory.stream_position().unwrap(), 1); |
| 83 | + |
| 84 | + assert_eq!(stable_memory.seek(SeekFrom::Start(2)).unwrap(), 2); |
| 85 | + assert_eq!(stable_memory.stream_position().unwrap(), 2); |
| 86 | + assert_eq!(stable_memory.write(&[2]).unwrap(), 1); |
| 87 | + assert_eq!(stable_memory.stream_position().unwrap(), 3); |
| 88 | + |
| 89 | + assert_eq!(stable_memory.seek(SeekFrom::Current(-2)).unwrap(), 1); |
| 90 | + assert_eq!(stable_memory.stream_position().unwrap(), 1); |
| 91 | + assert_eq!(stable_memory.write(&[3]).unwrap(), 1); |
| 92 | + assert_eq!(stable_memory.stream_position().unwrap(), 2); |
| 93 | + |
| 94 | + let capacity = icfs::StableMemory::capacity(); |
| 95 | + |
| 96 | + assert_eq!(stable_memory.seek(SeekFrom::End(-1)).unwrap(), capacity as u64 - 1); |
| 97 | + assert_eq!(stable_memory.stream_position().unwrap(), capacity as u64 - 1); |
| 98 | + assert_eq!(stable_memory.write(&[4]).unwrap(), 1); |
| 99 | + assert_eq!(stable_memory.stream_position().unwrap(), capacity as u64); |
| 100 | + |
| 101 | + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 0]; |
| 102 | + assert_eq!(&icfs::StableMemory::bytes()[0..8], b); |
| 103 | + |
| 104 | + let b: &[_] = &[0, 0, 0, 0, 0, 0, 0, 4]; |
| 105 | + assert_eq!(&icfs::StableMemory::bytes()[(capacity - 8)..], b); |
| 106 | + }) |
| 107 | +} |
| 108 | + |
| 109 | +#[update] |
| 110 | +fn test_reader() { |
| 111 | + setup(); |
| 112 | + STABLE_MEMORY.with(|stable_memory| { |
| 113 | + let mut stable_memory = *stable_memory.borrow(); |
| 114 | + stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); |
| 115 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 116 | + |
| 117 | + let mut buf = []; |
| 118 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 0); |
| 119 | + assert_eq!(stable_memory.stream_position().unwrap(), 0); |
| 120 | + |
| 121 | + let mut buf = [0]; |
| 122 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); |
| 123 | + assert_eq!(stable_memory.stream_position().unwrap(), 1); |
| 124 | + |
| 125 | + let b: &[_] = &[0]; |
| 126 | + assert_eq!(buf, b); |
| 127 | + |
| 128 | + let mut buf = [0; 4]; |
| 129 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); |
| 130 | + assert_eq!(stable_memory.stream_position().unwrap(), 5); |
| 131 | + |
| 132 | + let b: &[_] = &[1, 2, 3, 4]; |
| 133 | + assert_eq!(buf, b); |
| 134 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); |
| 135 | + |
| 136 | + let b: &[_] = &[5, 6, 7, 0]; |
| 137 | + assert_eq!(buf, b); |
| 138 | + |
| 139 | + let b: &[_] = &[5, 6, 7]; |
| 140 | + assert_eq!(&buf[..3], b); |
| 141 | + |
| 142 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 4); |
| 143 | + let b: &[_] = &[0, 0, 0, 0]; |
| 144 | + assert_eq!(buf, b); |
| 145 | + }) |
| 146 | +} |
| 147 | + |
| 148 | +// Based on https://github.com/rust-lang/rust/blob/a2af9cf1cf6ccb195eae40cdd793939bc77e7e73/library/std/src/io/mod.rs#L1578 |
| 149 | +fn read_all_vectored(stable_memory: &mut icfs::StableMemory, mut bufs: &mut [IoSliceMut<'_>]) -> std::io::Result<()> { |
| 150 | + // Guarantee that bufs is empty if it contains no data, |
| 151 | + // to avoid calling write_vectored if there is no data to be written. |
| 152 | + IoSliceMut::advance_slices(&mut bufs, 0); |
| 153 | + while !bufs.is_empty() { |
| 154 | + match stable_memory.read_vectored(bufs) { |
| 155 | + Ok(0) => { |
| 156 | + return Err(std::io::Error::new( |
| 157 | + std::io::ErrorKind::Other, |
| 158 | + "failed to read whole buffer", |
| 159 | + )); |
| 160 | + } |
| 161 | + Ok(n) => IoSliceMut::advance_slices(&mut bufs, n), |
| 162 | + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} |
| 163 | + Err(e) => return Err(e), |
| 164 | + } |
| 165 | + } |
| 166 | + Ok(()) |
| 167 | +} |
| 168 | + |
| 169 | +#[update] |
| 170 | +fn test_reader_vectored() { |
| 171 | + setup(); |
| 172 | + STABLE_MEMORY.with(|stable_memory| { |
| 173 | + let mut stable_memory = *stable_memory.borrow(); |
| 174 | + stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); |
| 175 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 176 | + |
| 177 | + let mut buf = []; |
| 178 | + read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut buf)]).unwrap(); |
| 179 | + assert_eq!(stable_memory.stream_position().unwrap(), 0); |
| 180 | + |
| 181 | + let mut buf = [0]; |
| 182 | + read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(); |
| 183 | + assert_eq!(stable_memory.stream_position().unwrap(), 1); |
| 184 | + |
| 185 | + let b: &[_] = &[0]; |
| 186 | + assert_eq!(buf, b); |
| 187 | + |
| 188 | + let mut buf1 = [0; 4]; |
| 189 | + let mut buf2 = [0; 4]; |
| 190 | + read_all_vectored(&mut stable_memory, &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]).unwrap(); |
| 191 | + |
| 192 | + let b1: &[_] = &[1, 2, 3, 4]; |
| 193 | + let b2: &[_] = &[5, 6, 7]; |
| 194 | + assert_eq!(buf1, b1); |
| 195 | + assert_eq!(&buf2[..3], b2); |
| 196 | + |
| 197 | + assert_eq!(stable_memory.read(&mut buf).unwrap(), 1); |
| 198 | + }) |
| 199 | +} |
| 200 | + |
| 201 | +#[update] |
| 202 | +fn test_read_to_end() { |
| 203 | + setup(); |
| 204 | + STABLE_MEMORY.with(|stable_memory| { |
| 205 | + let mut stable_memory = *stable_memory.borrow(); |
| 206 | + stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); |
| 207 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 208 | + |
| 209 | + let mut v = Vec::new(); |
| 210 | + stable_memory.read_to_end(&mut v).unwrap(); |
| 211 | + |
| 212 | + assert_eq!(v, icfs::StableMemory::bytes()); |
| 213 | + }) |
| 214 | +} |
| 215 | + |
| 216 | +#[update] |
| 217 | +fn test_read_exact() { |
| 218 | + setup(); |
| 219 | + STABLE_MEMORY.with(|stable_memory| { |
| 220 | + let mut stable_memory = *stable_memory.borrow(); |
| 221 | + stable_memory.write(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); |
| 222 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 223 | + |
| 224 | + let mut buf = []; |
| 225 | + assert!(stable_memory.read_exact(&mut buf).is_ok()); |
| 226 | + |
| 227 | + let mut buf = [8]; |
| 228 | + assert!(stable_memory.read_exact(&mut buf).is_ok()); |
| 229 | + assert_eq!(buf[0], 0); |
| 230 | + |
| 231 | + let mut buf = [0, 0, 0, 0, 0, 0, 0]; |
| 232 | + assert!(stable_memory.read_exact(&mut buf).is_ok()); |
| 233 | + assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); |
| 234 | + }) |
| 235 | +} |
| 236 | + |
| 237 | +#[update] |
| 238 | +fn test_seek_past_end() { |
| 239 | + setup(); |
| 240 | + STABLE_MEMORY.with(|stable_memory| { |
| 241 | + let mut stable_memory = *stable_memory.borrow(); |
| 242 | + let capacity = icfs::StableMemory::capacity(); |
| 243 | + let offset = capacity as u64 + 1; |
| 244 | + assert_eq!(stable_memory.seek(SeekFrom::Start(offset)).unwrap(), offset); |
| 245 | + assert_eq!(stable_memory.read(&mut [0]).unwrap(), 0); |
| 246 | + }) |
| 247 | +} |
| 248 | + |
| 249 | +#[update] |
| 250 | +fn test_seek_before_0() { |
| 251 | + setup(); |
| 252 | + STABLE_MEMORY.with(|stable_memory| { |
| 253 | + let mut stable_memory = *stable_memory.borrow(); |
| 254 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 255 | + assert!(stable_memory.seek(SeekFrom::Current(-1)).is_err()); |
| 256 | + |
| 257 | + stable_memory.seek(SeekFrom::Start(0)).unwrap(); |
| 258 | + let capacity = icfs::StableMemory::capacity(); |
| 259 | + let offset = 0 - capacity as i64 - 1; |
| 260 | + assert!(stable_memory.seek(SeekFrom::End(offset)).is_err()); |
| 261 | + }) |
| 262 | +} |
0 commit comments