summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tokio/tests/io_read_to_end.rs
blob: 29b60becec474bb2fc2f8a73c07c402c97a86c73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]

use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf};
use tokio_test::assert_ok;
use tokio_test::io::Builder;

#[tokio::test]
async fn read_to_end() {
    let mut buf = vec![];
    let mut rd: &[u8] = b"hello world";

    let n = assert_ok!(rd.read_to_end(&mut buf).await);
    assert_eq!(n, 11);
    assert_eq!(buf[..], b"hello world"[..]);
}

#[derive(Copy, Clone, Debug)]
enum State {
    Initializing,
    JustFilling,
    Done,
}

struct UninitTest {
    num_init: usize,
    state: State,
}

impl AsyncRead for UninitTest {
    fn poll_read(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<std::io::Result<()>> {
        let me = Pin::into_inner(self);
        let real_num_init = buf.initialized().len() - buf.filled().len();
        assert_eq!(real_num_init, me.num_init, "{:?}", me.state);

        match me.state {
            State::Initializing => {
                buf.initialize_unfilled_to(me.num_init + 2);
                buf.advance(1);
                me.num_init += 1;

                if me.num_init == 24 {
                    me.state = State::JustFilling;
                }
            }
            State::JustFilling => {
                buf.advance(1);
                me.num_init -= 1;

                if me.num_init == 15 {
                    // The buffer is resized on next call.
                    me.num_init = 0;
                    me.state = State::Done;
                }
            }
            State::Done => { /* .. do nothing .. */ }
        }

        Poll::Ready(Ok(()))
    }
}

#[tokio::test]
async fn read_to_end_uninit() {
    let mut buf = Vec::with_capacity(64);
    let mut test = UninitTest {
        num_init: 0,
        state: State::Initializing,
    };

    test.read_to_end(&mut buf).await.unwrap();
    assert_eq!(buf.len(), 33);
}

#[tokio::test]
async fn read_to_end_doesnt_grow_with_capacity() {
    let arr: Vec<u8> = (0..100).collect();

    // We only test from 32 since we allocate at least 32 bytes each time
    for len in 32..100 {
        let bytes = &arr[..len];
        for split in 0..len {
            for cap in 0..101 {
                let mut mock = if split == 0 {
                    Builder::new().read(bytes).build()
                } else {
                    Builder::new()
                        .read(&bytes[..split])
                        .read(&bytes[split..])
                        .build()
                };
                let mut buf = Vec::with_capacity(cap);
                AsyncReadExt::read_to_end(&mut mock, &mut buf)
                    .await
                    .unwrap();
                // It has the right data.
                assert_eq!(buf.as_slice(), bytes);
                // Unless cap was smaller than length, then we did not reallocate.
                if cap >= len {
                    assert_eq!(buf.capacity(), cap);
                }
            }
        }
    }
}

#[tokio::test]
async fn read_to_end_grows_capacity_if_unfit() {
    let bytes = b"the_vector_startingcap_will_be_smaller";
    let mut mock = Builder::new().read(bytes).build();
    let initial_capacity = bytes.len() - 4;
    let mut buf = Vec::with_capacity(initial_capacity);
    AsyncReadExt::read_to_end(&mut mock, &mut buf)
        .await
        .unwrap();
    // *4 since it doubles when it doesn't fit and again when reaching EOF
    assert_eq!(buf.capacity(), initial_capacity * 4);
}