1use crate::vars::*;
6use displaydoc::Display;
7#[cfg(test)]
8use mockall::mock;
9use std::{
10 borrow::ToOwned,
11 collections::{hash_map::Iter as HashMapIter, hash_set::Iter as HashSetIter, HashMap, HashSet},
12 env::{split_paths, var, var_os, vars, VarError},
13 num::ParseIntError,
14 path::{Path, PathBuf},
15 str::FromStr,
16};
17
18#[derive(Clone, Copy, Debug)]
20pub enum TargetFamily {
21 Unix,
23 Windows,
25 Wasm,
27}
28
29#[derive(Clone, Debug, Display)]
32pub enum TargetFamilyError {
33 Unknown(String),
35}
36
37impl TryFrom<&str> for TargetFamily {
38 type Error = TargetFamilyError;
39
40 fn try_from(src: &str) -> Result<TargetFamily, Self::Error> {
41 match src {
42 "unix" => Ok(TargetFamily::Unix),
43 "windows" => Ok(TargetFamily::Windows),
44 "wasm" => Ok(TargetFamily::Wasm),
45 other => Err(TargetFamilyError::Unknown(other.to_owned())),
46 }
47 }
48}
49
50#[derive(Clone, Copy, Debug)]
52pub enum Endianness {
53 Little,
55 Big,
57}
58
59#[derive(Clone, Debug, Display)]
62pub enum EndiannessError {
63 Unknown(String),
65}
66
67impl TryFrom<&str> for Endianness {
68 type Error = EndiannessError;
69
70 fn try_from(src: &str) -> Result<Endianness, Self::Error> {
71 match src {
72 "little" => Ok(Endianness::Little),
73 "big" => Ok(Endianness::Big),
74 other => Err(EndiannessError::Unknown(other.to_owned())),
75 }
76 }
77}
78
79#[derive(Clone, Debug, Display)]
81pub enum EnvironmentError {
82 Var(String, VarError),
84 Endianness(EndiannessError),
86 TargetFamily(TargetFamilyError),
88 ParseInt(String, ParseIntError),
90 OutDir(PathBuf),
92}
93
94impl From<EndiannessError> for EnvironmentError {
95 fn from(src: EndiannessError) -> EnvironmentError {
96 EnvironmentError::Endianness(src)
97 }
98}
99
100impl From<TargetFamilyError> for EnvironmentError {
101 fn from(src: TargetFamilyError) -> EnvironmentError {
102 EnvironmentError::TargetFamily(src)
103 }
104}
105
106fn read_depvars() -> HashMap<String, String> {
107 vars()
108 .filter_map(|(mut key, value)| {
109 if key.starts_with("DEP_") {
110 key.replace_range(.."DEP_".len(), "");
111 Some((key, value))
112 } else {
113 None
114 }
115 })
116 .collect()
117}
118
119fn read_features() -> HashSet<String> {
121 vars()
122 .filter_map(|(mut key, _value)| {
123 if key.starts_with("CARGO_FEATURE_") {
124 key.replace_range(.."CARGO_FEATURE_".len(), "");
125 while let Some(pos) = key.find('_') {
126 key.replace_range(pos..=pos, "-");
127 }
128 key.make_ascii_lowercase();
129 Some(key)
130 } else {
131 None
132 }
133 })
134 .collect()
135}
136
137fn parse_int_var<T: FromStr<Err = ParseIntError>>(env_var: &str) -> Result<T, EnvironmentError> {
139 var(env_var)
140 .map_err(|e| EnvironmentError::Var(env_var.to_owned(), e))?
141 .parse::<T>()
142 .map_err(|e| EnvironmentError::ParseInt(env_var.to_owned(), e))
143}
144
145fn env_to_opt_pathbuf(name: &str) -> Option<PathBuf> {
147 var(name).ok().and_then(|v| {
148 if v.is_empty() {
149 None
150 } else {
151 Some(PathBuf::from(v))
152 }
153 })
154}
155
156#[derive(Clone, Debug)]
159pub struct Environment {
160 cargo_path: PathBuf,
161 out_path: PathBuf,
162 features: HashSet<String>,
163
164 manifest_dir: PathBuf,
166 manifest_links: Option<String>,
167
168 pkg_version: String,
170 version_major: u64,
171 version_minor: u64,
172 version_patch: u64,
173 version_pre: Option<String>,
174 authors: HashSet<String>,
175 name: String,
176 description: String,
177 homepage: String,
178 repository: String,
179
180 debug_assertions: bool,
182 proc_macro: bool,
183 target_arch: String,
184 target_endian: Endianness,
185 target_env: String,
186 target_family: TargetFamily,
187 target_has_atomic: HashSet<String>,
188 target_has_atomic_load_store: HashSet<String>,
189 target_os: String,
190 target_pointer_width: usize,
191 target_thread_local: bool,
192 target_vendor: String,
193 target_features: HashSet<String>,
194
195 depvars: HashMap<String, String>,
197
198 target: String,
200 host: String,
201 num_jobs: usize,
202 opt_level: usize,
203 debug: bool,
204 profile: String,
205 rustc: PathBuf,
206 rustdoc: PathBuf,
207 linker: PathBuf,
208 locked: bool,
209
210 target_dir: PathBuf,
212 profile_target_dir: PathBuf,
213}
214
215#[cfg(test)]
216mock! {
217 pub Environment {
218 pub fn cargo(&self) -> &Path;
219 pub fn locked(&self) -> bool;
220 pub fn profile(&self) -> &str;
221 }
222
223 impl Clone for Environment {
224 fn clone(&self) -> Self;
225 }
226}
227
228impl Default for Environment {
229 fn default() -> Environment {
230 Environment::new().expect("Could not read environment")
231 }
232}
233
234impl Environment {
235 pub fn new() -> Result<Environment, EnvironmentError> {
237 let out_dir = PathBuf::from(
238 var(ENV_OUT_DIR).map_err(|e| EnvironmentError::Var(ENV_OUT_DIR.to_owned(), e))?,
239 );
240 let cargo_target_dir = PathBuf::from(
242 var(ENV_CARGO_TARGET_DIR)
243 .map_err(|e| EnvironmentError::Var(ENV_CARGO_TARGET_DIR.to_owned(), e))?,
244 );
245 let target =
246 var(ENV_TARGET).map_err(|e| EnvironmentError::Var(ENV_TARGET.to_owned(), e))?;
247 let profile =
248 var(ENV_PROFILE).map_err(|e| EnvironmentError::Var(ENV_PROFILE.to_owned(), e))?;
249
250 let (target_dir, profile_target_dir) =
251 Self::get_target_profile_dir(&out_dir, &cargo_target_dir, target)
252 .ok_or_else(|| EnvironmentError::OutDir(out_dir.clone()))
253 .unwrap();
254
255 let target_has_atomic = var(ENV_CARGO_CFG_TARGET_HAS_ATOMIC)
256 .unwrap_or_default()
257 .split(',')
258 .map(ToOwned::to_owned)
259 .collect::<HashSet<String>>();
260
261 let target_has_atomic_load_store = var(ENV_CARGO_CFG_TARGET_HAS_ATOMIC_LOAD_STORE)
262 .unwrap_or_default()
263 .split(',')
264 .map(ToOwned::to_owned)
265 .collect::<HashSet<String>>();
266
267 let linker = env_to_opt_pathbuf(ENV_RUSTC_LINKER)
268 .or_else(|| env_to_opt_pathbuf(ENV_LD))
269 .or_else(|| {
270 Some(
271 var_os(ENV_PATH)
272 .and_then(|paths| {
273 split_paths(&paths)
274 .filter_map(|dir| {
275 let full_path = dir.join("ld");
276 if full_path.is_file() {
277 Some(full_path)
278 } else {
279 None
280 }
281 })
282 .next()
283 })
284 .expect("Could not find `ld` in path environment variable"),
285 )
286 })
287 .expect("Could not find linker to use");
288
289 let features = read_features();
290 let depvars = read_depvars();
291
292 Ok(Self {
293 cargo_path: var(ENV_CARGO)
295 .map_err(|e| EnvironmentError::Var(ENV_CARGO.to_owned(), e))?
296 .into(),
297 locked: var(ENV_CARGO_LOCKED).is_ok(),
298
299 manifest_dir: var(ENV_CARGO_MANIFEST_DIR)
301 .map_err(|e| EnvironmentError::Var(ENV_CARGO_MANIFEST_DIR.to_owned(), e))?
302 .into(),
303 manifest_links: var(ENV_CARGO_MANIFEST_LINKS).ok(),
304
305 debug: var(ENV_DEBUG).is_ok(),
307 host: var(ENV_HOST).map_err(|e| EnvironmentError::Var(ENV_HOST.to_owned(), e))?,
308 linker,
309 num_jobs: parse_int_var(ENV_NUM_JOBS)?,
310 out_path: out_dir,
311 opt_level: parse_int_var(ENV_OPT_LEVEL)?,
312 profile,
313 rustc: var(ENV_RUSTC)
314 .map_err(|e| EnvironmentError::Var(ENV_RUSTC.to_owned(), e))?
315 .into(),
316 rustdoc: var(ENV_RUSTDOC)
317 .map_err(|e| EnvironmentError::Var(ENV_RUSTDOC.to_owned(), e))?
318 .into(),
319 target: var(ENV_TARGET).map_err(|e| EnvironmentError::Var(ENV_TARGET.to_owned(), e))?,
320
321 features,
323 depvars,
325
326 pkg_version: var(ENV_CARGO_PKG_VERSION)
328 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_VERSION.to_owned(), e))?,
329 version_major: parse_int_var(ENV_CARGO_PKG_VERSION_MAJOR)?,
330 version_minor: parse_int_var(ENV_CARGO_PKG_VERSION_MINOR)?,
331 version_patch: parse_int_var(ENV_CARGO_PKG_VERSION_PATCH)?,
332 version_pre: match var(ENV_CARGO_PKG_VERSION_PRE) {
333 Ok(value) => {
334 if value.is_empty() {
335 None
336 } else {
337 Some(value)
338 }
339 }
340 Err(VarError::NotPresent) => None,
341 Err(other) => {
342 return Err(EnvironmentError::Var(
343 ENV_CARGO_PKG_VERSION_PRE.to_owned(),
344 other,
345 ))
346 }
347 },
348 authors: var(ENV_CARGO_PKG_AUTHORS)
349 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_AUTHORS.to_owned(), e))?
350 .split(':')
351 .map(ToOwned::to_owned)
352 .collect(),
353 name: var(ENV_CARGO_PKG_NAME)
354 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_NAME.to_owned(), e))?,
355 description: var(ENV_CARGO_PKG_DESCRIPTION)
356 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_DESCRIPTION.to_owned(), e))?,
357 homepage: var(ENV_CARGO_PKG_HOMEPAGE)
358 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_HOMEPAGE.to_owned(), e))?,
359 repository: var(ENV_CARGO_PKG_REPOSITORY)
360 .map_err(|e| EnvironmentError::Var(ENV_CARGO_PKG_REPOSITORY.to_owned(), e))?,
361
362 debug_assertions: var(ENV_CARGO_CFG_DEBUG_ASSERTIONS).is_ok(),
364 proc_macro: var(ENV_CARGO_CFG_PROC_MACRO).is_ok(),
365 target_arch: var(ENV_CARGO_CFG_TARGET_ARCH)
366 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_ARCH.to_owned(), e))?,
367 target_endian: Endianness::try_from(
368 var(ENV_CARGO_CFG_TARGET_ENDIAN)
369 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_ENDIAN.to_owned(), e))?
370 .as_str(),
371 )?,
372 target_env: var(ENV_CARGO_CFG_TARGET_ENV)
373 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_ENV.to_owned(), e))?,
374 target_family: TargetFamily::try_from(
375 var(ENV_CARGO_CFG_TARGET_FAMILY)
376 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_FAMILY.to_owned(), e))?
377 .as_ref(),
378 )?,
379 target_features: var(ENV_CARGO_CFG_TARGET_FEATURE)
380 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_FEATURE.to_owned(), e))?
381 .split(',')
382 .map(ToOwned::to_owned)
383 .collect(),
384 target_has_atomic,
385 target_has_atomic_load_store,
386 target_os: var(ENV_CARGO_CFG_TARGET_OS)
387 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_OS.to_owned(), e))?,
388 target_pointer_width: parse_int_var(ENV_CARGO_CFG_TARGET_POINTER_WIDTH)?,
389 target_thread_local: var(ENV_CARGO_CFG_TARGET_THREAD_LOCAL).is_ok(),
390 target_vendor: var(ENV_CARGO_CFG_TARGET_VENDOR)
391 .map_err(|e| EnvironmentError::Var(ENV_CARGO_CFG_TARGET_VENDOR.to_owned(), e))?,
392
393 target_dir,
395 profile_target_dir,
396 })
397 }
398
399 fn get_target_profile_dir(
400 out_dir: &Path,
401 target_dir: &PathBuf,
402 target: String,
403 ) -> Option<(PathBuf, PathBuf)> {
404 let mut ancestor = out_dir.ancestors().peekable();
405 while let Some(current_path) = ancestor.next() {
406 if let Some(parent_path) = ancestor.peek() {
407 if !target.is_empty() && parent_path.ends_with(&target)
408 || !target_dir.as_os_str().is_empty() && parent_path.ends_with(target_dir)
409 || parent_path.ends_with("target")
410 {
411 let tuple = (PathBuf::from(parent_path), PathBuf::from(current_path));
412
413 return Some(tuple);
414 }
415 }
416 }
417 None
418 }
419
420 pub fn cargo(&self) -> &Path {
422 &self.cargo_path
423 }
424
425 pub fn locked(&self) -> bool {
427 self.locked
428 }
429
430 pub fn features(&self) -> HashSetIter<String> {
433 self.features.iter()
434 }
435
436 pub fn feature(&self, feature: &str) -> bool {
441 self.features.contains(feature)
442 }
443
444 pub fn depvars(&self) -> HashMapIter<String, String> {
447 self.depvars.iter()
448 }
449
450 pub fn depvar(&self, var: &str) -> Option<&str> {
452 self.depvars.get(var).map(String::as_str)
453 }
454
455 pub fn dir(&self) -> &Path {
457 &self.manifest_dir
458 }
459
460 pub fn links(&self) -> Option<&str> {
462 self.manifest_links.as_deref()
463 }
464
465 pub fn debug(&self) -> bool {
467 self.debug
468 }
469
470 pub fn host(&self) -> &str {
472 &self.host
473 }
474
475 pub fn linker(&self) -> &Path {
477 &self.linker
478 }
479
480 pub fn num_jobs(&self) -> usize {
482 self.num_jobs
483 }
484
485 pub fn out_dir(&self) -> &Path {
487 &self.out_path
488 }
489
490 pub fn opt_level(&self) -> usize {
492 self.opt_level
493 }
494
495 pub fn profile(&self) -> &str {
497 &self.profile
498 }
499
500 pub fn rustc(&self) -> &Path {
502 &self.rustc
503 }
504
505 pub fn rustdoc(&self) -> &Path {
507 &self.rustdoc
508 }
509
510 pub fn target(&self) -> &str {
512 &self.target
513 }
514
515 pub fn version(&self) -> &str {
517 &self.pkg_version
518 }
519
520 pub fn version_major(&self) -> u64 {
522 self.version_major
523 }
524
525 pub fn version_minor(&self) -> u64 {
527 self.version_minor
528 }
529
530 pub fn version_patch(&self) -> u64 {
532 self.version_patch
533 }
534
535 pub fn version_pre(&self) -> Option<String> {
537 self.version_pre.clone()
538 }
539
540 pub fn authors(&self) -> &HashSet<String> {
542 &self.authors
543 }
544
545 pub fn name(&self) -> &str {
547 &self.name
548 }
549
550 pub fn description(&self) -> &str {
552 &self.description
553 }
554
555 pub fn homepage(&self) -> &str {
557 &self.homepage
558 }
559
560 pub fn repository(&self) -> &str {
562 &self.repository
563 }
564
565 pub fn debug_assertions(&self) -> bool {
567 self.debug_assertions
568 }
569
570 pub fn proc_macro(&self) -> bool {
572 self.proc_macro
573 }
574
575 pub fn target_arch(&self) -> &str {
577 &self.target_arch
578 }
579
580 pub fn target_endian(&self) -> Endianness {
582 self.target_endian
583 }
584
585 pub fn target_env(&self) -> &str {
587 &self.target_env
588 }
589
590 pub fn target_family(&self) -> TargetFamily {
592 self.target_family
593 }
594
595 pub fn target_features(&self) -> &HashSet<String> {
597 &self.target_features
598 }
599
600 pub fn target_has_atomic(&self) -> &HashSet<String> {
603 &self.target_has_atomic
604 }
605
606 pub fn target_has_atomic_load_store(&self) -> &HashSet<String> {
608 &self.target_has_atomic_load_store
609 }
610
611 pub fn target_os(&self) -> &str {
613 &self.target_os
614 }
615
616 pub fn target_pointer_width(&self) -> usize {
618 self.target_pointer_width
619 }
620
621 pub fn target_thread_local(&self) -> bool {
623 self.target_thread_local
624 }
625
626 pub fn target_vendor(&self) -> &str {
628 &self.target_vendor
629 }
630
631 pub fn target_dir(&self) -> &Path {
633 &self.target_dir
634 }
635
636 pub fn profile_target_dir(&self) -> &Path {
638 &self.profile_target_dir
639 }
640}
641
642#[cfg(test)]
643mod tests {
644 use super::*;
645 use fluent_asserter::prelude::*;
646
647 fn setup_env(env_values: HashMap<&str, Option<&str>>) -> Environment {
648 temp_env::with_vars(
649 [
650 (
651 ENV_OUT_DIR,
652 if env_values.get(ENV_OUT_DIR).is_some() {
653 env_values.get(ENV_OUT_DIR).cloned().unwrap()
654 } else {
655 Some("/path_to_out_dir")
656 },
657 ),
658 (
659 ENV_TARGET,
660 if env_values.get(ENV_TARGET).is_some() {
661 env_values.get(ENV_TARGET).cloned().unwrap()
662 } else {
663 Some("target")
664 },
665 ),
666 (
667 ENV_PROFILE,
668 if env_values.get(ENV_PROFILE).is_some() {
669 env_values.get(ENV_PROFILE).cloned().unwrap()
670 } else {
671 Some("profile")
672 },
673 ),
674 (
675 ENV_CARGO,
676 if env_values.get(ENV_CARGO).is_some() {
677 env_values.get(ENV_CARGO).cloned().unwrap()
678 } else {
679 Some("/path_to_cargo")
680 },
681 ),
682 (ENV_HOST, Some("host")),
683 (ENV_NUM_JOBS, Some("11")),
684 (ENV_OPT_LEVEL, Some("2")),
685 (ENV_RUSTC, Some("rustc")),
686 (ENV_RUSTDOC, Some("rustdoc")),
687 (
688 ENV_CARGO_TARGET_DIR,
689 if env_values.get(ENV_CARGO_TARGET_DIR).is_some() {
690 env_values.get(ENV_CARGO_TARGET_DIR).cloned().unwrap()
691 } else {
692 Some("/path_to_target_dir")
693 },
694 ),
695 (ENV_CARGO_PKG_VERSION, Some("2.1.0-pre0")),
696 (ENV_CARGO_PKG_AUTHORS, Some("MobileCoin")),
697 (ENV_CARGO_PKG_NAME, Some("mc-build-rs")),
698 (ENV_CARGO_PKG_DESCRIPTION, Some("")),
699 (ENV_CARGO_PKG_HOMEPAGE, Some("")),
700 (ENV_CARGO_PKG_REPOSITORY, Some("")),
701 (ENV_CARGO_CFG_TARGET_ARCH, Some("x86_64")),
702 (ENV_CARGO_CFG_TARGET_ENDIAN, Some("little")),
703 (ENV_CARGO_CFG_TARGET_ENV, Some("")),
704 (ENV_CARGO_CFG_TARGET_FAMILY, Some("unix")),
705 (ENV_CARGO_CFG_TARGET_FEATURE, Some("adx,aes,avx,avx2,")),
706 (ENV_CARGO_CFG_TARGET_OS, Some("linux")),
707 (ENV_CARGO_CFG_TARGET_POINTER_WIDTH, Some("64")),
708 (ENV_CARGO_CFG_TARGET_VENDOR, Some("unknown")),
709 ],
710 || {
711 return Environment::default();
712 },
713 )
714 }
715
716 #[test]
717 fn init_env() {
718 let expected_out_dir = "/x86_64-unknown-linux-gnu/path_to_out_directory";
719 let expected_target = "x86_64-unknown-linux-gnu";
720 let expected_cargo_path = "/path_to_cargo";
721 let expected_profile = "debug";
722 let expected_cargo_package_version = "2.1.0-pre0";
723
724 let mut values = HashMap::new();
725 values.insert(ENV_OUT_DIR, Some(expected_out_dir));
726 values.insert(ENV_TARGET, Some(expected_target));
727 values.insert(ENV_CARGO, Some(expected_cargo_path));
728 values.insert(ENV_PROFILE, Some(expected_profile));
729 values.insert(ENV_CARGO_PKG_VERSION, Some(expected_cargo_package_version));
730
731 let env = setup_env(values);
732
733 assert_eq!(
734 env.out_dir(),
735 PathBuf::from_str(expected_out_dir).expect("Fail")
736 );
737 assert_eq!(env.target, expected_target);
738 assert_eq!(env.profile, expected_profile);
739 assert_eq!(
740 env.cargo_path,
741 PathBuf::from_str(expected_cargo_path).expect("Fail")
742 );
743 assert_eq!(env.pkg_version, expected_cargo_package_version);
744 }
745
746 #[test]
747 fn match_target_type() {
748 let out_dir = "path_to/target/x86_64-unknown-linux-gnu/debug/path/to/out";
749 let target = "x86_64-unknown-linux-gnu";
750 let expected_target_dir = "path_to/target/x86_64-unknown-linux-gnu/";
751 let expected_profile_dir = "path_to/target/x86_64-unknown-linux-gnu/debug";
752
753 let mut values = HashMap::new();
754 values.insert(ENV_OUT_DIR, Some(out_dir));
755 values.insert(ENV_TARGET, Some(target));
756
757 let env = setup_env(values);
758
759 assert_eq!(
760 env.target_dir,
761 PathBuf::from_str(expected_target_dir).expect("Fail")
762 );
763 assert_eq!(
764 env.profile_target_dir,
765 PathBuf::from_str(expected_profile_dir).expect("Fail")
766 );
767 }
768
769 #[test]
770 fn match_target_dir() {
771 let target_dir = "path_to/target";
772 let out_dir = "path_to/target/debug/path/to/out";
773 let target = "x86_64-unknown-linux-gnu";
774 let expected_target_dir = "path_to/target";
775 let expected_profile_dir = "path_to/target/debug";
776
777 let mut values = HashMap::new();
778 values.insert(ENV_OUT_DIR, Some(out_dir));
779 values.insert(ENV_CARGO_TARGET_DIR, Some(target_dir));
780 values.insert(ENV_TARGET, Some(target));
781
782 let env = setup_env(values);
783
784 assert_eq!(
785 env.target_dir,
786 PathBuf::from_str(expected_target_dir).expect("Fail")
787 );
788 assert_eq!(
789 env.profile_target_dir,
790 PathBuf::from_str(expected_profile_dir).expect("Fail")
791 );
792 }
793
794 #[test]
795 fn match_target_string() {
796 let target_dir = "";
797 let out_dir = "path_to/target/debug/path/to/out";
798 let target = "x86_64-unknown-linux-gnu";
799 let expected_target_dir = "path_to/target/";
800 let expected_profile_dir = "path_to/target/debug";
801
802 let mut values = HashMap::new();
803 values.insert(ENV_OUT_DIR, Some(out_dir));
804 values.insert(ENV_CARGO_TARGET_DIR, Some(target_dir));
805 values.insert(ENV_TARGET, Some(target));
806
807 let env = setup_env(values);
808
809 assert_eq!(
810 env.target_dir,
811 PathBuf::from_str(expected_target_dir).expect("Fail")
812 );
813 assert_eq!(
814 env.profile_target_dir,
815 PathBuf::from_str(expected_profile_dir).expect("Fail")
816 );
817 }
818
819 #[test]
820 fn err_out_dir() {
821 let target_dir = "different/path_to_target";
822 let out_dir = "path_to/debug/path/to/out";
823 let target = "x86_64-unknown-linux-gnu";
824
825 let mut values = HashMap::new();
826 values.insert(ENV_OUT_DIR, Some(out_dir));
827 values.insert(ENV_CARGO_TARGET_DIR, Some(target_dir));
828 values.insert(ENV_TARGET, Some(target));
829
830 assert_that_code!(|| setup_env(values))
831 .panics()
832 .with_message(
833 "called `Result::unwrap()` on an `Err` value: OutDir(\"path_to/debug/path/to/out\")",
834 );
835 }
836}