dynamic_cli/plugin/builtin/
help.rs1use crate::config::schema::CommandsConfig;
11use crate::executor::CommandHandler;
12use crate::plugin::system::SystemHelpHandler;
13use crate::plugin::Plugin;
14
15pub struct HelpPlugin {
47 config: Option<CommandsConfig>,
49}
50
51impl HelpPlugin {
52 pub fn new() -> Self {
63 Self { config: None }
64 }
65
66 pub fn with_config(mut self, config: CommandsConfig) -> Self {
92 self.config = Some(config);
93 self
94 }
95}
96
97impl Default for HelpPlugin {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl Plugin for HelpPlugin {
104 fn name(&self) -> &str {
105 "help"
106 }
107
108 fn version(&self) -> &str {
109 env!("CARGO_PKG_VERSION")
110 }
111
112 fn description(&self) -> &str {
113 "Standalone help command (split out of SystemPlugin, #44)"
114 }
115
116 fn handlers(&self) -> Vec<(String, Box<dyn CommandHandler>)> {
117 vec![(
118 "system_help".to_string(),
119 Box::new(SystemHelpHandler::new(self.config.clone())),
120 )]
121 }
122}
123
124#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::config::schema::{CommandsConfig, Metadata};
132 use crate::context::ExecutionContext;
133 use crate::parser::ParsedArgs;
134 use std::any::Any;
135 use std::collections::HashMap;
136
137 #[derive(Default)]
138 struct TestContext;
139
140 impl ExecutionContext for TestContext {
141 fn as_any(&self) -> &dyn Any {
142 self
143 }
144 fn as_any_mut(&mut self) -> &mut dyn Any {
145 self
146 }
147 }
148
149 fn test_config() -> CommandsConfig {
150 CommandsConfig {
151 metadata: Metadata {
152 version: "2.0.0".to_string(),
153 prompt: "testapp".to_string(),
154 prompt_suffix: " > ".to_string(),
155 },
156 commands: vec![],
157 global_options: vec![],
158 }
159 }
160
161 #[test]
162 fn test_help_plugin_metadata() {
163 let p = HelpPlugin::new();
164 assert_eq!(p.name(), "help");
165 assert!(!p.version().is_empty());
166 assert!(!p.description().is_empty());
167 }
168
169 #[test]
170 fn test_help_plugin_default() {
171 let p = HelpPlugin::default();
172 assert_eq!(p.name(), "help");
173 }
174
175 #[test]
176 fn test_help_plugin_handler_name() {
177 let handlers = HelpPlugin::new().handlers();
178 assert_eq!(handlers.len(), 1);
179 assert_eq!(handlers[0].0, "system_help");
180 }
181
182 #[test]
183 fn test_help_plugin_with_config() {
184 let plugin = HelpPlugin::new().with_config(test_config());
185 assert!(plugin.config.is_some());
186 assert_eq!(plugin.config.unwrap().metadata.version, "2.0.0");
187 }
188
189 #[test]
190 fn test_help_handler_executes_with_config() {
191 let plugin = HelpPlugin::new().with_config(test_config());
192 let handlers = plugin.handlers();
193 let (_, handler) = &handlers[0];
194 let mut ctx = TestContext;
195 assert!(handler
196 .execute(&mut ctx, &ParsedArgs::from_scalars(HashMap::new()))
197 .is_ok());
198 }
199
200 #[test]
201 fn test_help_handler_executes_without_config() {
202 let handlers = HelpPlugin::new().handlers();
203 let (_, handler) = &handlers[0];
204 let mut ctx = TestContext;
205 assert!(handler
206 .execute(&mut ctx, &ParsedArgs::from_scalars(HashMap::new()))
207 .is_ok());
208 }
209
210 #[test]
211 fn test_help_plugin_is_send_sync() {
212 fn assert_send_sync<T: Send + Sync>(_: T) {}
213 assert_send_sync(HelpPlugin::new());
214 }
215}