1use crate::common::output;
25use crate::common::report::merge_reports;
26use crate::common::report::report_error;
27use crate::common::report::report_failure;
28use crate::common::syntax::Mode;
29use crate::common::syntax::parse_arguments;
30use yash_env::Env;
31use yash_env::builtin::Result;
32use yash_env::semantics::Field;
33use yash_env::system::{Fcntl, Isatty, Write};
34
35#[derive(Clone, Debug, Eq, PartialEq)]
37#[non_exhaustive]
38pub struct Command {
39 pub operands: Vec<Field>,
41}
42
43pub mod semantics;
44
45pub async fn main<S>(env: &mut Env<S>, args: Vec<Field>) -> Result
47where
48 S: Isatty + Fcntl + Write,
49{
50 let mode = Mode::with_env(env);
51 match parse_arguments(&[], mode, args) {
53 Ok((_options, operands)) => {
54 let command = Command { operands };
55 let (result, errors) = command.execute(env).await;
56 let mut result = output(env, &result).await;
57 if let Some(report) = merge_reports(&errors) {
58 result = result.max(report_failure(env, report).await);
59 }
60 result
61 }
62
63 Err(e) => report_error(env, &e).await,
64 }
65}
66
67#[allow(clippy::bool_assert_comparison)]
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use futures_util::FutureExt as _;
72 use yash_env::semantics::ExitStatus;
73 use yash_env::source::Source;
74
75 #[test]
76 fn builtin_defines_alias() {
77 let mut env = Env::new_virtual();
78 let args = Field::dummies(["foo=bar baz"]);
79
80 let result = main(&mut env, args).now_or_never().unwrap();
81 assert_eq!(result, Result::new(ExitStatus::SUCCESS));
82
83 assert_eq!(env.aliases.len(), 1);
84
85 let alias = env.aliases.get("foo").unwrap().0.as_ref();
86 assert_eq!(alias.name, "foo");
87 assert_eq!(alias.replacement, "bar baz");
88 assert_eq!(alias.global, false);
89 assert_eq!(*alias.origin.code.value.borrow(), "foo=bar baz");
90 assert_eq!(alias.origin.code.start_line_number.get(), 1);
91 assert_eq!(*alias.origin.code.source, Source::Unknown);
92 assert_eq!(alias.origin.range, 0..11);
93 }
94
95 #[test]
96 fn builtin_defines_many_aliases() {
97 let mut env = Env::new_virtual();
98 let args = Field::dummies(["abc=xyz", "yes=no", "ls=ls --color"]);
99
100 let result = main(&mut env, args).now_or_never().unwrap();
101 assert_eq!(result, Result::new(ExitStatus::SUCCESS));
102
103 assert_eq!(env.aliases.len(), 3);
104
105 let abc = env.aliases.get("abc").unwrap().0.as_ref();
106 assert_eq!(abc.name, "abc");
107 assert_eq!(abc.replacement, "xyz");
108 assert_eq!(abc.global, false);
109 assert_eq!(*abc.origin.code.value.borrow(), "abc=xyz");
110 assert_eq!(abc.origin.code.start_line_number.get(), 1);
111 assert_eq!(*abc.origin.code.source, Source::Unknown);
112 assert_eq!(abc.origin.range, 0..7);
113
114 let yes = env.aliases.get("yes").unwrap().0.as_ref();
115 assert_eq!(yes.name, "yes");
116 assert_eq!(yes.replacement, "no");
117 assert_eq!(yes.global, false);
118 assert_eq!(*yes.origin.code.value.borrow(), "yes=no");
119 assert_eq!(yes.origin.code.start_line_number.get(), 1);
120 assert_eq!(*yes.origin.code.source, Source::Unknown);
121 assert_eq!(yes.origin.range, 0..6);
122
123 let ls = env.aliases.get("ls").unwrap().0.as_ref();
124 assert_eq!(ls.name, "ls");
125 assert_eq!(ls.replacement, "ls --color");
126 assert_eq!(ls.global, false);
127 assert_eq!(*ls.origin.code.value.borrow(), "ls=ls --color");
128 assert_eq!(ls.origin.code.start_line_number.get(), 1);
129 assert_eq!(*ls.origin.code.source, Source::Unknown);
130 assert_eq!(ls.origin.range, 0..13);
131 }
132
133 #[test]
134 fn builtin_replaces_alias() {
135 let mut env = Env::new_virtual();
136 let args = Field::dummies(["foo=1"]);
137
138 let result = main(&mut env, args).now_or_never().unwrap();
139 assert_eq!(result, Result::new(ExitStatus::SUCCESS));
140
141 let args = Field::dummies(["foo=2"]);
142
143 let result = main(&mut env, args).now_or_never().unwrap();
144 assert_eq!(result, Result::new(ExitStatus::SUCCESS));
145
146 assert_eq!(env.aliases.len(), 1);
147
148 let alias = env.aliases.get("foo").unwrap().0.as_ref();
149 assert_eq!(alias.name, "foo");
150 assert_eq!(alias.replacement, "2");
151 assert_eq!(alias.global, false);
152 }
155
156 }