1#![forbid(unsafe_code)]
48
49extern crate self as usage_rs;
52
53pub use usage_argv as argv;
54pub use usage_argv::*;
55#[cfg(feature = "config")]
56pub use usage_config as config;
57#[cfg(feature = "config")]
58pub use usage_derive::Config;
59#[cfg(feature = "spec")]
60pub use usage_derive::{ArgGroup, Args, Cli, Subcommands, ValueEnum};
61#[cfg(feature = "test")]
62pub use usage_test as test;
63#[cfg(feature = "validation")]
64pub use usage_validation as validation;
65#[cfg(feature = "response-files")]
66pub mod response;
67
68#[cfg(all(test, feature = "spec"))]
69mod tests {
70 #[derive(crate::Cli)]
71 #[usage(bin = "internal")]
72 struct Internal {}
73
74 #[cfg(feature = "validation")]
75 #[derive(Debug, crate::Cli)]
76 #[usage(bin = "validated")]
77 struct Validated {
78 #[usage(
79 long,
80 validate = "int(value) >= 1 && int(value) <= 65535",
81 validate_error = "must be a valid port"
82 )]
83 port: Option<u16>,
84 }
85
86 #[cfg(feature = "validation")]
87 #[derive(Debug, crate::Args)]
88 struct ValidatedArgs {
89 #[usage(long, validate = "value == 'ok'", validate_error = "must be ok")]
90 token: Option<String>,
91 }
92
93 #[cfg(feature = "validation")]
94 #[derive(Debug, crate::Cli)]
95 #[usage(bin = "validated-args")]
96 struct ValidatedArgsCli {
97 #[usage(flatten)]
98 args: ValidatedArgs,
99 }
100
101 #[test]
102 fn derives_resolve_the_facade_from_inside_the_facade() {
103 assert_eq!(Internal::spec().bin, Some("internal"));
104 }
105
106 #[cfg(feature = "config")]
107 #[derive(crate::Config)]
108 struct InternalSettings {
109 #[usage(env = "INTERNAL_JOBS", default = 4)]
111 jobs: u64,
112 }
113
114 #[cfg(feature = "config")]
115 #[test]
116 fn the_config_derive_resolves_the_facade_from_inside_the_facade() {
117 let resolved = crate::config::resolve(
118 InternalSettings::SETTINGS_REGISTRY,
119 crate::config::Layers::new(),
120 )
121 .expect("resolves");
122 let settings = InternalSettings::read(&resolved).expect("reads");
123 assert_eq!(settings.jobs, 4);
124 assert!(InternalSettings::spec_kdl().contains(r#"prop "jobs""#));
125 }
126
127 #[cfg(feature = "validation")]
128 #[test]
129 fn derives_evaluate_portable_validation_expressions() {
130 let valid = [
131 ::std::ffi::OsStr::new("--port"),
132 ::std::ffi::OsStr::new("9229"),
133 ];
134 assert_eq!(Validated::parse_from(&valid).unwrap().port, Some(9229));
135
136 let invalid = [
137 ::std::ffi::OsStr::new("--port"),
138 ::std::ffi::OsStr::new("0"),
139 ];
140 let crate::Error::InvalidValue(error) = Validated::parse_from(&invalid).unwrap_err() else {
141 panic!("expected invalid value");
142 };
143 assert_eq!(error.reason, "must be a valid port");
144
145 let invalid_args = [
146 ::std::ffi::OsStr::new("--token"),
147 ::std::ffi::OsStr::new("bad"),
148 ];
149 let crate::Error::InvalidValue(error) =
150 ValidatedArgsCli::parse_from(&invalid_args).unwrap_err()
151 else {
152 panic!("expected invalid value from flattened Args");
153 };
154 assert_eq!(error.reason, "must be ok");
155
156 let valid_args = [
157 ::std::ffi::OsStr::new("--token"),
158 ::std::ffi::OsStr::new("ok"),
159 ];
160 assert_eq!(
161 ValidatedArgsCli::parse_from(&valid_args)
162 .unwrap()
163 .args
164 .token
165 .as_deref(),
166 Some("ok")
167 );
168
169 let kdl = Validated::to_kdl();
170 assert!(
171 kdl.contains(r#"validate="int(value) >= 1 && int(value) <= 65535""#),
172 "{kdl}"
173 );
174 }
175}