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