proptest_http/
uri.rs

1use super::*;
2
3/// Wrapper that generates random-ish `Uri` instances.
4/// Not that URI generation is rather basic. There probably
5/// a lot of tricky cases that are not considered
6#[derive(Debug, PartialEq, Eq, Clone)]
7pub struct ArbitraryUri(pub http::Uri);
8#[derive(Debug, Clone, Copy)]
9pub struct UriStrategy;
10#[derive(Debug, Clone)]
11pub struct UriValueTree {
12    pub with_schema_and_host: BoolValueTree,
13    pub schema: IndexValueTree,
14    pub authority: IndexValueTree,
15    pub host: IndexValueTree,
16    pub path: IndexValueTree,
17    pub query: IndexValueTree,
18
19    pub whose_turn: usize,
20}
21
22const SCHEMAS: [&str; 2] = ["http://", "https://"];
23
24const AUTHS : [&str;16] = [
25    "",
26    "a@",
27    "a:a@",
28    "a:@",
29    ":a@",
30    ":@",
31    "%C3%BC:a@",
32    "%20:%20@",
33    "0:4@",
34    "1:%20@",
35    "2:%C5%81@",
36    "3:%F3%A0%80%A0@",
37    "4:%20a%20@",
38    "5:%20%09%F3%A0%80%A0%D1%89%F3%A0%80%A0%09%20@",
39    "6:%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20@",
40    "7:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@",
41];
42
43const HOSTS: [&str; 10] = [
44    "localhost",
45    "127.0.0.1",
46    "localhost:8080",
47    "127.0.0.1:8080",
48    "example.com",
49    "example.com:8080",
50    "[::1]",
51    "[::1]:8080",
52    "[0000:0000:0000:0000:0000:0000:0000:0001]:8080",
53    "longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong.example:8080",
54];
55
56const PATHS : [&str;9] = [
57    "/",
58    "/foo",
59    "/foo/",
60    "/foo/bar/",
61    "/%20",
62    "/%D0%B9%D1%86%D1%83%D0%BA%D0%B5%D0%BD%D0%B3%D1%88%D1%89",
63    "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z",
64    "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/",
65    "/%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20?%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20#%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20",
66];
67
68const QUERIES : [&str; 9] = [
69    "",
70    "?",
71    "?q",
72    "?q=w",
73    "?q=%20bar%20",
74    "?q=w&",
75    "?q=%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20?%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20#%5B%5D%3F%2F%3C%7E%23%6D%21%40%24%25%5E%26%2A%28%29%2B%3D%7D%7C%3A%22%3B%27%2C%3E%7B%20&",
76    "?q=http%3A%2F%2F%5B%3A%3A1%5D%3A123%2F%3Fqw%3D3%26q%3D1%231v&",
77    "?q=http%253A%252F%252F%255B%253A%253A1%255D%253A123%252F%253Fqw%253D3%2526q%253D1%25231v&",
78];
79
80impl Arbitrary for ArbitraryUri {
81    type Parameters = ();
82    type Strategy = UriStrategy;
83
84    fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
85        UriStrategy
86    }
87}
88
89impl Strategy for UriStrategy {
90    type Value = ArbitraryUri;
91    type Tree = UriValueTree;
92
93    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
94        Ok(UriValueTree {
95            with_schema_and_host: weighted(0.95).new_tree(runner)?,
96            schema: Index::arbitrary().new_tree(runner)?,
97            authority: Index::arbitrary().new_tree(runner)?,
98            host: Index::arbitrary().new_tree(runner)?,
99            path: Index::arbitrary().new_tree(runner)?,
100            query: Index::arbitrary().new_tree(runner)?,
101            whose_turn: 1,
102        })
103    }
104}
105
106impl ValueTree for UriValueTree {
107    type Value = ArbitraryUri;
108
109    fn current(&self) -> Self::Value {
110        //let uri : http::uri::Uri = "/test".parse().unwrap();
111        let mut s = String::with_capacity(50);
112
113        if self.with_schema_and_host.current() {
114            s += *self.schema.current().get(&SCHEMAS[..]);
115            s += *self.authority.current().get(&AUTHS[..]);
116            s += *self.host.current().get(&HOSTS[..]);
117        }
118        s += *self.path.current().get(&PATHS[..]);
119        s += *self.query.current().get(&QUERIES[..]);
120
121        //eprintln!("Q: {}", s);
122        let uri: http::uri::Uri = s.parse().unwrap();
123        ArbitraryUri(uri)
124    }
125
126    fn simplify(&mut self) -> bool {
127        let mut ctr = 0;
128        loop {
129            if self.simplify1() {
130                self.advance_turn();
131                return true;
132            } else {
133                self.advance_turn();
134                ctr += 1;
135            }
136            if ctr == 5 {
137                return false;
138            }
139        }
140    }
141
142    fn complicate(&mut self) -> bool {
143        self.unadvance_turn();
144        let ret = self.complicate1();
145        self.advance_turn(); // to prevent looping on one field
146        ret
147    }
148}
149
150impl UriValueTree {
151    fn simplify1(&mut self) -> bool {
152        match self.whose_turn {
153            0 => self.with_schema_and_host.simplify(),
154            1 => self.schema.simplify(),
155            2 => self.authority.simplify(),
156            3 => self.path.simplify(),
157            4 => self.query.simplify(),
158            _ => unreachable!(),
159        }
160    }
161    fn complicate1(&mut self) -> bool {
162        match self.whose_turn {
163            0 => self.with_schema_and_host.complicate(),
164            1 => self.schema.complicate(),
165            2 => self.authority.complicate(),
166            3 => self.path.complicate(),
167            4 => self.query.complicate(),
168            _ => unreachable!(),
169        }
170    }
171
172    fn advance_turn(&mut self) {
173        self.whose_turn += 1;
174        if self.whose_turn > 4 {
175            self.whose_turn = 0;
176        }
177    }
178
179    fn unadvance_turn(&mut self) {
180        if self.whose_turn == 0 {
181            self.whose_turn = 5;
182        }
183        self.whose_turn -= 1;
184    }
185}