1use crate::CompatibilityMode;
10use std::ffi::OsStr;
11use std::path::Path;
12
13pub fn resolve(
15 strict_flag: Option<bool>,
16 env_strict: Option<&OsStr>,
17 argv0: Option<&OsStr>,
18) -> CompatibilityMode {
19 if let Some(flag) = strict_flag {
20 return if flag {
21 CompatibilityMode::Strict
22 } else {
23 CompatibilityMode::Default
24 };
25 }
26 if let Some(value) = env_strict {
27 if env_var_is_truthy(value) {
28 return CompatibilityMode::Strict;
29 }
30 }
31 if let Some(arg0) = argv0 {
32 if argv0_implies_strict(arg0) {
33 return CompatibilityMode::Strict;
34 }
35 }
36 CompatibilityMode::Default
37}
38
39fn env_var_is_truthy(value: &OsStr) -> bool {
40 let Some(s) = value.to_str() else {
41 return false;
42 };
43 matches!(
44 s.trim().to_ascii_lowercase().as_str(),
45 "1" | "true" | "yes" | "on"
46 )
47}
48
49fn argv0_implies_strict(arg0: &OsStr) -> bool {
50 let Some(stem) = Path::new(arg0).file_stem() else {
51 return false;
52 };
53 stem == OsStr::new("pee")
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn explicit_strict_flag_wins() {
62 assert_eq!(resolve(Some(true), None, None), CompatibilityMode::Strict);
63 assert_eq!(
64 resolve(Some(false), Some(OsStr::new("1")), Some(OsStr::new("pee"))),
65 CompatibilityMode::Default,
66 "explicit --no-strict beats env and argv[0]"
67 );
68 }
69
70 #[test]
71 fn env_var_truthy_implies_strict() {
72 for v in ["1", "true", "yes", "on", "TRUE", " 1 ", "On"] {
73 assert_eq!(
74 resolve(None, Some(OsStr::new(v)), None),
75 CompatibilityMode::Strict,
76 "env value {v:?} should imply strict"
77 );
78 }
79 }
80
81 #[test]
82 fn env_var_falsy_does_not_imply_strict() {
83 for v in ["0", "false", "no", "off", ""] {
84 assert_eq!(
85 resolve(None, Some(OsStr::new(v)), None),
86 CompatibilityMode::Default,
87 "env value {v:?} should NOT imply strict"
88 );
89 }
90 }
91
92 #[test]
93 fn argv0_pee_implies_strict() {
94 assert_eq!(
95 resolve(None, None, Some(OsStr::new("pee"))),
96 CompatibilityMode::Strict
97 );
98 assert_eq!(
99 resolve(None, None, Some(OsStr::new("/usr/local/bin/pee"))),
100 CompatibilityMode::Strict
101 );
102 assert_eq!(
103 resolve(None, None, Some(OsStr::new("pee.exe"))),
104 CompatibilityMode::Strict,
105 "argv[0] = pee.exe must imply strict (file_stem strips .exe)"
106 );
107 }
108
109 #[test]
110 fn argv0_rusty_pee_does_not_imply_strict() {
111 assert_eq!(
112 resolve(None, None, Some(OsStr::new("rusty-pee"))),
113 CompatibilityMode::Default
114 );
115 assert_eq!(
116 resolve(None, None, Some(OsStr::new("rusty-pee.exe"))),
117 CompatibilityMode::Default
118 );
119 }
120
121 #[test]
122 fn default_when_nothing_set() {
123 assert_eq!(resolve(None, None, None), CompatibilityMode::Default);
124 }
125
126 #[test]
127 fn ladder_strict_flag_beats_env_var() {
128 assert_eq!(
129 resolve(Some(false), Some(OsStr::new("1")), None),
130 CompatibilityMode::Default
131 );
132 assert_eq!(
133 resolve(Some(true), Some(OsStr::new("0")), None),
134 CompatibilityMode::Strict
135 );
136 }
137
138 #[test]
139 fn ladder_env_var_beats_argv0() {
140 assert_eq!(
141 resolve(None, Some(OsStr::new("1")), Some(OsStr::new("rusty-pee"))),
142 CompatibilityMode::Strict
143 );
144 assert_eq!(
145 resolve(None, Some(OsStr::new("0")), Some(OsStr::new("pee"))),
146 CompatibilityMode::Strict,
147 "rung 2 falsy is no-op; rung 3 (argv0=pee) still engages Strict"
148 );
149 }
150}