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