//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Arbitrary implementations for `std::path`. use std::path::*; use crate::{ arbitrary::{SMapped, StrategyFor}, path::PathParams, prelude::{any, any_with, Arbitrary, Strategy}, std_facade::{string::ToString, Arc, Box, Rc, String, Vec}, strategy::{statics::static_map, MapInto}, }; arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); /// A private type (not actually pub) representing the output of [`PathParams`] that can't be /// referred to by API users. /// /// The goal of this type is to encapsulate the output of `PathParams`. If this layer weren't /// present, the type of `::Strategy` would be `SMapped<(bool, Vec), /// Self>`. This is a problem because it exposes the internal representation of `PathParams` as an /// API. For example, if an additional parameter of randomness (e.g. another bool) were added, the /// type of `Strategy` would change. /// /// With `PathParamsOutput`, the type of `Strategy` is `SMapped`, which is a /// type that can't be named directly---only via `::Strategy`. The internal /// representation of `PathParams` can be changed without affecting the API. #[derive(Debug)] pub struct PathParamsOutput { is_absolute: bool, components: Vec, } impl Arbitrary for PathParamsOutput { type Parameters = PathParams; type Strategy = SMapped<(bool, Vec), Self>; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { static_map( ( any::(), any_with::>(( args.components(), args.component_regex(), )), ), |(is_absolute, components)| Self { is_absolute, components, }, ) } } /// This implementation accepts as its argument a [`PathParams`] struct. It generates either a /// relative or an absolute path with equal probability. /// /// Currently, this implementation does not generate: /// /// * Paths that are not valid UTF-8 (this is unlikely to change) /// * Paths with a [`PrefixComponent`](std::path::PrefixComponent) on Windows, e.g. `C:\` (this may /// change in the future) impl Arbitrary for PathBuf { type Parameters = PathParams; type Strategy = SMapped; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { static_map( any_with::(args), |PathParamsOutput { is_absolute, components, }| { let mut out = PathBuf::new(); if is_absolute { out.push(&MAIN_SEPARATOR.to_string()); } for component in components { // If a component has an embedded / (or \ on Windows), remove it from the // string. let component = component .chars() .filter(|&c| !std::path::is_separator(c)) .collect::(); out.push(&component); } out }, ) } } macro_rules! dst_wrapped { ($($w: ident),*) => { $( /// This implementation is identical to [the `Arbitrary` implementation for /// `PathBuf`](trait.Arbitrary.html#impl-Arbitrary-for-PathBuf). impl Arbitrary for $w { type Parameters = PathParams; type Strategy = MapInto, Self>; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { any_with::(args).prop_map_into() } } )* } } dst_wrapped!(Box, Rc, Arc); #[cfg(test)] mod test { no_panic_test!( strip_prefix_error => StripPrefixError, path_buf => PathBuf, box_path => Box, rc_path => Rc, arc_path => Arc ); }