proptest_arbitrary/_std/
env.rs

1//! Arbitrary implementations for `std::env`.
2
3use super::*;
4use std::env::*;
5use std::iter::once;
6use std::ffi::OsString;
7
8// FIXME: SplitPaths when lifetimes in strategies are possible.
9
10generator!(
11    Args, args;
12    ArgsOs, args_os;
13    Vars, vars;
14    VarsOs, vars_os;
15    JoinPathsError, jpe
16);
17
18#[cfg(not(target_os = "windows"))]
19fn jpe() -> JoinPathsError {
20    join_paths(once(":")).unwrap_err()
21}
22
23#[cfg(target_os = "windows")]
24fn jpe() -> JoinPathsError {
25    join_paths(once("\"")).unwrap_err()
26}
27
28// Algorithm from: https://stackoverflow.com/questions/47749164
29#[cfg(target_os = "windows")]
30fn make_utf16_invalid(buf: &mut Vec<u16>, p: usize) {
31    // Verify that length is non-empty.
32    // An empty string is always valid UTF-16.
33    let len = buf.len();
34    assert!(len > 0);
35
36    // If first elem or previous entry is not a leading surrogate.
37    let gen_trail = (0 == p) || (0xd800 != buf[p - 1] & 0xfc00);
38    // If last element or succeeding entry is not a traililng surrogate.
39    let gen_lead = (p == buf.len() - 1) || (0xdc00 != buf[p + 1] & 0xfc00);
40    let (force_bits_mask, force_bits_value) = if gen_trail {
41        if gen_lead {
42            // Trailing or leading surrogate.
43            (0xf800, 0xd800)
44        } else {
45            // Trailing surrogate.
46            (0xfc00, 0xdc00)
47        }
48    } else {
49        // Leading surrogate.
50        debug_assert!(gen_lead);
51        (0xfc00, 0xd800)
52    };
53    debug_assert_eq!(0, (force_bits_value & !force_bits_mask));
54    buf[p] = (buf[p] & !force_bits_mask) | force_bits_value;
55}
56
57/// Generates the set of `WTF-16 \ UTF-16` and makes
58/// an `OsString` that is not a valid String from it.
59#[cfg(target_os = "windows")]
60fn osstring_invalid_string() -> BoxedStrategy<OsString> {
61    use std::os::windows::ffi::OsStringExt;
62    use proptest::collection::vec;
63
64    any::<u16>().prop_flat_map(|vlen| {
65        let len = vlen as usize;
66        let sbuf = vec(..std::u16::MAX, len..len + 1);
67        static_map((sbuf, 0..len - 1), |(mut buf, p)| {
68            make_utf16_invalid(&mut buf, p);
69            OsString::from_wide(buf.as_slice()).into_string().unwrap_err()
70        })
71    }).boxed()
72}
73
74#[cfg(not(target_os = "windows"))]
75fn osstring_invalid_string() -> BoxedStrategy<OsString> {
76    use std::os::unix::ffi::OsStringExt;
77    static_map(not_utf8_bytes(true), OsString::from_vec).boxed()
78}
79
80arbitrary!(VarError,
81    TupleUnion<(
82        W<Just<Self>>,
83        W<SFnPtrMap<BoxedStrategy<OsString>, Self>>
84    )>;
85    prop_oneof![
86        Just(VarError::NotPresent),
87        static_map(osstring_invalid_string(), VarError::NotUnicode)
88    ]
89);
90
91#[cfg(test)]
92mod test {
93    no_panic_test!(
94        args => Args,
95        args_os => ArgsOs,
96        vars => Vars,
97        vars_os => VarsOs,
98        join_paths_error => JoinPathsError,
99        var_error => VarError
100    );
101}