| //- |
| // Copyright 2017, 2018 The proptest developers |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| //! Arbitrary implementations for `std::env`. |
| |
| use std::env::*; |
| use std::iter::once; |
| use std::ffi::OsString; |
| |
| use crate::strategy::*; |
| use crate::strategy::statics::static_map; |
| use crate::arbitrary::*; |
| |
| // FIXME: SplitPaths when lifetimes in strategies are possible. |
| |
| lazy_just!( |
| Args, args; |
| ArgsOs, args_os; |
| Vars, vars; |
| VarsOs, vars_os; |
| JoinPathsError, jpe |
| ); |
| |
| #[cfg(not(target_os = "windows"))] |
| fn jpe() -> JoinPathsError { |
| join_paths(once(":")).unwrap_err() |
| } |
| |
| #[cfg(target_os = "windows")] |
| fn jpe() -> JoinPathsError { |
| join_paths(once("\"")).unwrap_err() |
| } |
| |
| // Algorithm from: https://stackoverflow.com/questions/47749164 |
| #[cfg(any(target_os = "windows", test))] |
| fn make_utf16_invalid(buf: &mut [u16], p: usize) { |
| // Verify that length is non-empty. |
| // An empty string is always valid UTF-16. |
| assert!(buf.len() > 0); |
| |
| // If first elem or previous entry is not a leading surrogate. |
| let gen_trail = 0 == p || 0xd800 != (buf[p - 1] & 0xfc00); |
| // If last element or succeeding entry is not a traililng surrogate. |
| let gen_lead = p == buf.len() - 1 || 0xdc00 != (buf[p + 1] & 0xfc00); |
| let (force_bits_mask, force_bits_value) = if gen_trail { |
| if gen_lead { |
| // Trailing or leading surrogate. |
| (0xf800, 0xd800) |
| } else { |
| // Trailing surrogate. |
| (0xfc00, 0xdc00) |
| } |
| } else { |
| // Leading surrogate. |
| // Note that `gen_lead` and `gen_trail` could both be false here if `p` |
| // lies exactly between a leading and a trailing surrogate. In this |
| // case, it doesn't matter what we do because the UTF-16 will be |
| // invalid regardless, so just always force a leading surrogate. |
| (0xfc00, 0xd800) |
| }; |
| debug_assert_eq!(0, (force_bits_value & !force_bits_mask)); |
| buf[p] = (buf[p] & !force_bits_mask) | force_bits_value; |
| } |
| |
| #[cfg(not(target_arch = "wasm32"))] |
| mod var_error { |
| use super::*; |
| |
| /// Generates the set of `WTF-16 \ UTF-16` and makes |
| /// an `OsString` that is not a valid String from it. |
| #[cfg(target_os = "windows")] |
| fn osstring_invalid_string() -> impl Strategy<Value = OsString> { |
| use std::os::windows::ffi::OsStringExt; |
| let size = 1..::std::u16::MAX as usize; |
| let vec_gen = crate::collection::vec(..::std::u16::MAX, size.clone()); |
| (size, vec_gen).prop_map(|(p, mut sbuf)| { |
| // Not quite a uniform distribution due to clamping, |
| // but probably good enough |
| let p = ::std::cmp::min(p, sbuf.len() - 1); |
| make_utf16_invalid(&mut sbuf, p); |
| OsString::from_wide(sbuf.as_slice()).into_string().unwrap_err() |
| }) |
| } |
| |
| #[cfg(not(target_os = "windows"))] |
| fn osstring_invalid_string() -> impl Strategy<Value = OsString> { |
| use std::os::unix::ffi::OsStringExt; |
| use crate::arbitrary::_std::string::not_utf8_bytes; |
| static_map(not_utf8_bytes(true), OsString::from_vec) |
| } |
| |
| arbitrary!(VarError, |
| TupleUnion<( |
| W<Just<Self>>, |
| W<SFnPtrMap<BoxedStrategy<OsString>, Self>> |
| )>; |
| prop_oneof![ |
| Just(VarError::NotPresent), |
| static_map(osstring_invalid_string().boxed(), VarError::NotUnicode) |
| ] |
| ); |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| use crate::num; |
| use crate::test_runner::Config; |
| |
| no_panic_test!( |
| args => Args, |
| args_os => ArgsOs, |
| vars => Vars, |
| vars_os => VarsOs, |
| join_paths_error => JoinPathsError, |
| var_error => VarError |
| ); |
| |
| proptest! { |
| #![proptest_config(Config { |
| cases: 65536, |
| .. Config::default() |
| })] |
| |
| #[test] |
| fn make_utf16_invalid_doesnt_panic( |
| mut buf in [num::u16::ANY; 3], |
| p in 0usize..3 |
| ) { |
| make_utf16_invalid(&mut buf, p); |
| } |
| } |
| } |