/ tests / pretend_build_script.rs
pretend_build_script.rs
  1  // Note: This will print to stderr what look like errors but these are only from autocfg doing the
  2  // intended probing (as it runs its own rustc commands that expectedly might have compiler
  3  // errors), and this will also print the build-script instructions to stdout, and these prints
  4  // will be intermixed (and their order is randomized, due to the current internal iteration of a
  5  // HashMap).  It can be helpful to redirect these, e.g.:
  6  //   cargo test --test pretend_build_script 2> /dev/null
  7  
  8  #![allow(unknown_lints, deprecated, bare_trait_objects)]
  9  
 10  extern crate cfg_rust_features;
 11  extern crate create_temp_subdir;
 12  
 13  use std::collections::{BTreeSet, HashSet};
 14  use std::env;
 15  use std::error::Error;
 16  use std::hash::Hash;
 17  use std::iter::FromIterator;
 18  
 19  use cfg_rust_features::{emit_rerun_if_changed_file, CfgRustFeatures, FeatureCategory};
 20  use create_temp_subdir::TempSubDir;
 21  
 22  type ResultDynErr<T> = Result<T, Box<Error>>;
 23  
 24  type FeatureName = &'static str;
 25  type EnabledFeatures = cfg_rust_features::EnabledFeatures<FeatureName>;
 26  
 27  
 28  /// Like a `main` function of a build script (modulo the `Ok` type).
 29  fn pretend_build_script() -> ResultDynErr<EnabledFeatures>
 30  {
 31      emit_rerun_if_changed_file(file!());
 32  
 33      Ok(try!(try!(CfgRustFeatures::new()).emit_multiple(vec![
 34          "arbitrary_self_types",
 35          // "cfg_version",  // Omitted to exercise not giving a supported one.
 36          "inner_deref",
 37          "destructuring_assignment",
 38          "error_in_core",
 39          "iter_zip",
 40          "never_type",
 41          "question_mark",
 42          "rust1",
 43          "step_trait",
 44          "unstable_features",
 45          "unwrap_infallible",
 46      ])))
 47  }
 48  
 49  
 50  fn main()
 51  {
 52      // Setup to pretend that this program is a build script.
 53      let out_dir = TempSubDir::new("intgtest-pretend_build_script").unwrap();
 54      env::set_var("OUT_DIR", &out_dir);
 55  
 56      assert_enabled_features(&pretend_build_script().unwrap());
 57  }
 58  
 59  
 60  /// Check the `EnabledFeatures` `HashMap` value, returned by the call to
 61  /// `CfgRustFeatures::emit_multiple`, which indicates whether each of the chosen features was
 62  /// found to be enabled and its categories if so.
 63  ///
 64  /// Must correspond to what [`pretend_build_script`] emits.
 65  fn assert_enabled_features(enabled: &EnabledFeatures)
 66  {
 67      /// Element of `HashSet`s.  Similar shape as a Set iterator yields.  `BTreeSet` needed because
 68      /// it `impl`s `Hash`.
 69      type Feature = (FeatureName, BTreeSet<FeatureCategory>);
 70  
 71      macro_rules! set {
 72          [$t:ty: $($e:expr),*] => {
 73              <$t>::from_iter(vec![$($e),*])
 74          }
 75      }
 76      macro_rules! hset {
 77          [$($rest:tt)*] => {
 78              set![HashSet<_>: $($rest)*]
 79          }
 80      }
 81      macro_rules! bset {
 82          [$($rest:tt)*] => {
 83              set![BTreeSet<_>: $($rest)*]
 84          }
 85      }
 86  
 87      fn bset_from_hset<T: Clone + Hash + Ord>(hset: &HashSet<T>) -> BTreeSet<T>
 88      {
 89          hset.iter().cloned().collect()
 90      }
 91  
 92      fn from_enabled_features(enabled_features: &EnabledFeatures) -> HashSet<Feature>
 93      {
 94          enabled_features
 95              .iter()
 96              .filter_map(|(&k, v)| v.as_ref().map(|c| (k, bset_from_hset(c))))
 97              .collect()
 98      }
 99  
100      fn assert_enabled_fits_required_and_allowed<T: Hash + Eq>(
101          enabled: &HashSet<T>,
102          required: &HashSet<T>,
103          allowed: &HashSet<T>,
104      )
105      {
106          assert!(enabled.is_superset(required));
107          assert!(enabled.is_subset(allowed));
108      }
109  
110  
111      let required = hset![("rust1", bset!["comp", "lang", "lib"])];
112      let optional = hset![
113          ("unstable_features", bset!["comp"]),
114          ("arbitrary_self_types", bset!["lang"]),
115          ("destructuring_assignment", bset!["lang"]),
116          ("never_type", bset!["lang"]),
117          ("question_mark", bset!["lang"]),
118          ("error_in_core", bset!["lib"]),
119          ("inner_deref", bset!["lib"]),
120          ("iter_zip", bset!["lib"]),
121          ("step_trait", bset!["lib"]),
122          ("unwrap_infallible", bset!["lib"])
123      ];
124      let allowed = &required | &optional;
125  
126      let enabled = from_enabled_features(enabled);
127      assert_enabled_fits_required_and_allowed(&enabled, &required, &allowed);
128  }