aopt/parser/
policy_fwd.rs

1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4
5use super::FailManager;
6use super::OptStyleManager;
7use super::Policy;
8use super::PolicySettings;
9use super::Return;
10use super::UserStyle;
11use crate::args;
12use crate::args::ArgInfo;
13use crate::args::Args;
14use crate::ctx::Ctx;
15use crate::ctx::Invoker;
16use crate::guess::InvokeGuess;
17use crate::opt::Opt;
18use crate::opt::OptParser;
19use crate::parser::Action;
20use crate::set::OptValidator;
21use crate::set::SetChecker;
22use crate::set::SetOpt;
23use crate::trace;
24use crate::Error;
25
26/// [`FwdPolicy`] matching the command line arguments with [`Opt`] in the [`Set`](crate::set::Set).
27/// The option would match failed if any special [`Error`] raised during option processing.
28/// [`FwdPolicy`] will return Some([`Return`]) if match successful.
29/// [`FwdPolicy`] process the option before any
30/// NOA([`Cmd`](crate::opt::Style::Cmd), [`Pos`](crate::opt::Style::Pos) and [`Main`](crate::opt::Style::Main)).
31/// During parsing, you can get the value of any option in the handler of NOA.
32///
33/// # Examples
34/// ```rust
35/// # use aopt::prelude::*;
36/// # use aopt::Error;
37/// #
38/// # fn main() -> Result<(), Error> {
39/// let mut policy = AFwdPolicy::default();
40/// let mut set = AHCSet::default();
41/// let mut inv = AInvoker::default();
42/// let filter_id = set.add_opt("--/filter=b")?.run()?;
43/// let pos_id = set.add_opt("pos=p@*")?
44///                 .set_pos_type::<String>()
45///                 .set_values(vec![])
46///                 .run()?;
47///
48/// inv.entry(pos_id).on(
49///     move |set, ctx| {
50///         let filter = set.app_data::<Vec<&str>>()?;
51///         let value = ctx.value::<String>()?;
52///         let not_filter = set[filter_id].val::<bool>()?;
53///         let valid = if !*not_filter {
54///             !filter.iter().any(|&v| v == value.as_str())
55///         } else {
56///             true
57///         };
58///
59///         Ok(valid.then(|| value))
60///     },
61/// );
62///
63/// let args = Args::from(["app", "set", "42", "foo", "bar"]);
64///
65/// for opt in set.iter_mut() {
66///     opt.init()?;
67/// }
68/// set.set_app_data(vec!["foo", "bar"]);
69/// policy.parse(&mut set, &mut inv, args)?;
70///
71/// let values = set[pos_id].vals::<String>()?;
72///
73/// assert_eq!(values[0], "set");
74/// assert_eq!(values[1], "42");
75///
76/// let args = Args::from(["app", "--/filter", "set", "42", "foo", "bar"]);
77///
78/// for opt in set.iter_mut() {
79///     opt.init()?;
80/// }
81///
82/// policy.parse(&mut set, &mut inv, args)?;
83/// let values = set[pos_id].vals::<String>()?;
84///
85/// assert_eq!(values[0], "set");
86/// assert_eq!(values[1], "42");
87/// assert_eq!(values[2], "foo");
88/// assert_eq!(values[3], "bar");
89/// #
90/// # Ok(())
91/// # }
92/// ```
93///
94/// When [`prepolicy`](PolicySettings::prepolicy) is enabled,
95/// [`FwdPolicy`] will skip any special [`Error`] during [`parse`](Policy::parse) process.
96///
97/// # Example
98/// ```rust
99/// # use aopt::getopt;
100/// # use aopt::prelude::*;
101/// # use aopt::Error;
102/// #
103/// # fn main() -> Result<(), Error> {
104/// let mut parser = AFwdParser::default();
105/// let mut cfg_loader = AFwdParser::default();
106///
107/// cfg_loader.set_prepolicy(true);
108/// parser
109///     .add_opt("-check=s")?
110///     .on(|set, ctx| {
111///         let ext = ctx.value::<String>()?;
112///         let mut found = false;
113///
114///         for name in ["-c", "-cxx"] {
115///             if let Ok(opt) = set.find(name) {
116///                 if let Ok(file) = opt.vals::<String>() {
117///                     if file.contains(&ext) {
118///                         found = true;
119///                     }
120///                 }
121///             }
122///         }
123///         Ok(Some(found))
124///     })?;
125/// cfg_loader.set_app_data(parser);
126/// cfg_loader.add_opt("--load=s")?.on(
127///     |set, ctx| {
128///         let cfg = ctx.value::<String>()?;
129///         let parser = set.app_data_mut::<AFwdParser>()?;
130///
131///         match cfg.as_str() {
132///             "cxx" => {
133///                 parser.add_opt("-cxx".infer::<String>())?.set_values(
134///                     ["cxx", "cpp", "c++", "cc", "hpp", "hxx", "h"]
135///                         .map(|v| v.to_owned())
136///                         .to_vec(),
137///                 );
138///             }
139///             "c" => {
140///                 parser
141///                     .add_opt("-c=s")?
142///                     .set_values_t(["c", "h"].map(|v| v.to_owned()).to_vec());
143///             }
144///             _ => {
145///                 panic!("Unknow configuration name")
146///             }
147///         }
148///
149///         Ok(Some(cfg))
150///     },
151/// )?;
152///
153/// let ret = getopt!(
154///     Args::from(["--load", "cxx", "-check", "cc"]),
155///     &mut cfg_loader
156/// )?;
157/// let next_args = ret.ret.clone_args();
158/// let mut parser = cfg_loader.take_app_data::<AFwdParser>()?;
159///
160/// getopt!(Args::from(next_args), &mut parser)?;
161///
162/// assert!(*parser.find_val::<bool>("-check")?);
163///
164/// // pass the parser to AppService
165/// cfg_loader.set_app_data(parser);
166///
167/// let ret = getopt!(
168///     Args::from(["--load", "c", "-check", "c"]),
169///     &mut cfg_loader
170/// )?;
171/// let next_args = ret.ret.clone_args();
172/// let mut parser = cfg_loader.service_mut().take_app_data::<AFwdParser>()?;
173///
174/// getopt!(Args::from(next_args), &mut parser)?;
175///
176/// assert!(*parser.find_val::<bool>("-check")?);
177/// #
178/// # Ok(())
179/// # }
180/// ```
181pub struct FwdPolicy<S, Chk> {
182    strict: bool,
183
184    overload: bool,
185
186    prepolicy: bool,
187
188    checker: Chk,
189
190    style_manager: OptStyleManager,
191
192    marker_s: PhantomData<S>,
193}
194
195impl<S, Chk> Clone for FwdPolicy<S, Chk>
196where
197    Chk: Clone,
198{
199    fn clone(&self) -> Self {
200        Self {
201            strict: self.strict,
202            overload: self.overload,
203            prepolicy: self.prepolicy,
204            checker: self.checker.clone(),
205            style_manager: self.style_manager.clone(),
206            marker_s: self.marker_s,
207        }
208    }
209}
210
211impl<S, Chk> Debug for FwdPolicy<S, Chk>
212where
213    Chk: Debug,
214{
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        f.debug_struct("FwdPolicy")
217            .field("strict", &self.strict)
218            .field("overload", &self.overload)
219            .field("prepolicy", &self.prepolicy)
220            .field("checker", &self.checker)
221            .field("style_manager", &self.style_manager)
222            .finish()
223    }
224}
225
226impl<S, Chk> Default for FwdPolicy<S, Chk>
227where
228    Chk: Default,
229{
230    fn default() -> Self {
231        Self {
232            strict: true,
233            overload: false,
234            prepolicy: false,
235            style_manager: OptStyleManager::default(),
236            checker: Chk::default(),
237            marker_s: PhantomData,
238        }
239    }
240}
241
242impl<S, Chk> FwdPolicy<S, Chk>
243where
244    Chk: Default,
245{
246    pub fn new(strict: bool, style: OptStyleManager) -> Self {
247        Self {
248            strict,
249            style_manager: style,
250            ..Default::default()
251        }
252    }
253}
254
255impl<S, Chk> FwdPolicy<S, Chk> {
256    /// In strict mode, if an argument looks like an option (it matched any option prefix),
257    /// then it must matched.
258    pub fn with_strict(mut self, strict: bool) -> Self {
259        self.strict = strict;
260        self
261    }
262
263    pub fn with_styles(mut self, styles: Vec<UserStyle>) -> Self {
264        self.style_manager.set(styles);
265        self
266    }
267
268    pub fn with_checker(mut self, checker: Chk) -> Self {
269        self.checker = checker;
270        self
271    }
272
273    pub fn with_overload(mut self, overload: bool) -> Self {
274        self.overload = overload;
275        self
276    }
277
278    pub fn with_prepolicy(mut self, prepolicy: bool) -> Self {
279        self.prepolicy = prepolicy;
280        self
281    }
282
283    pub fn set_checker(&mut self, checker: Chk) -> &mut Self {
284        self.checker = checker;
285        self
286    }
287
288    pub fn checker(&self) -> &Chk {
289        &self.checker
290    }
291
292    pub fn checker_mut(&mut self) -> &mut Chk {
293        &mut self.checker
294    }
295
296    pub(crate) fn noa_cmd() -> usize {
297        1
298    }
299
300    pub(crate) fn noa_main() -> usize {
301        0
302    }
303
304    pub(crate) fn noa_pos(idx: usize) -> usize {
305        idx
306    }
307
308    pub(crate) fn filter<T, E: Into<Error>>(
309        prepolicy: bool,
310        res: Result<T, E>,
311    ) -> Result<Option<T>, Error> {
312        let res = res.map_err(Into::into);
313
314        if !prepolicy {
315            res.map(|v| Some(v))
316        } else {
317            match res {
318                Ok(val) => Ok(Some(val)),
319                Err(e) => {
320                    if e.is_failure() {
321                        Ok(None)
322                    } else {
323                        Err(e)
324                    }
325                }
326            }
327        }
328    }
329}
330
331impl<Set, Chk> PolicySettings for FwdPolicy<Set, Chk> {
332    fn style_manager(&self) -> &OptStyleManager {
333        &self.style_manager
334    }
335
336    fn style_manager_mut(&mut self) -> &mut OptStyleManager {
337        &mut self.style_manager
338    }
339
340    fn strict(&self) -> bool {
341        self.strict
342    }
343
344    fn styles(&self) -> &[UserStyle] {
345        &self.style_manager
346    }
347
348    fn no_delay(&self) -> Option<&[String]> {
349        None
350    }
351
352    fn overload(&self) -> bool {
353        self.overload
354    }
355
356    fn prepolicy(&self) -> bool {
357        self.prepolicy
358    }
359
360    fn set_strict(&mut self, strict: bool) -> &mut Self {
361        self.strict = strict;
362        self
363    }
364
365    fn set_styles(&mut self, styles: Vec<UserStyle>) -> &mut Self {
366        self.style_manager.set(styles);
367        self
368    }
369
370    fn set_no_delay(&mut self, _: impl Into<String>) -> &mut Self {
371        self
372    }
373
374    fn set_overload(&mut self, overload: bool) -> &mut Self {
375        self.overload = overload;
376        self
377    }
378
379    fn set_prepolicy(&mut self, prepolicy: bool) -> &mut Self {
380        self.prepolicy = prepolicy;
381        self
382    }
383}
384
385impl<S, Chk> FwdPolicy<S, Chk>
386where
387    SetOpt<S>: Opt,
388    Chk: SetChecker<S>,
389    S: crate::set::Set + OptParser + OptValidator,
390{
391    pub(crate) fn parse_impl<'a>(
392        &mut self,
393        set: &mut <Self as Policy>::Set,
394        inv: &mut <Self as Policy>::Inv<'_>,
395        orig: &'a Args,
396        ctx: &mut Ctx<'a>,
397    ) -> Result<(), <Self as Policy>::Error> {
398        self.checker().pre_check(set).map_err(Into::into)?;
399
400        let overload = self.overload();
401        let pre = self.prepolicy();
402        let opt_styles = &self.style_manager;
403        let args: Vec<_> = orig.iter().map(|v| v.as_os_str()).collect();
404        let total = args.len();
405        let mut lefts = vec![];
406        let mut opt_fail = FailManager::default();
407        let mut iter2 = args::iter2(&args).enumerate();
408
409        trace!("parsing {ctx:?} using fwd policy");
410        ctx.set_args(args.clone());
411        while let Some((idx, (opt, next))) = iter2.next() {
412            let mut matched = false;
413            let mut consume = false;
414            let mut stopped = false;
415            let mut like_opt = false;
416
417            if let Ok(ArgInfo { name, value }) = ArgInfo::parse(opt) {
418                trace!(
419                    "guess name: {:?} value: {:?} & next: {:?}",
420                    name,
421                    value,
422                    next
423                );
424                if let Some(true) = Self::filter(pre, set.check(&name))? {
425                    let arg = value.clone();
426                    let next = next.map(|v| Cow::Borrowed(*v));
427                    let mut guess = InvokeGuess {
428                        idx,
429                        arg,
430                        set,
431                        inv,
432                        total,
433                        ctx,
434                        next,
435                        fail: &mut opt_fail,
436                        name: Some(name.clone()),
437                    };
438
439                    like_opt = true;
440                    for style in opt_styles.iter() {
441                        if let Some(Some(ret)) =
442                            Self::filter(pre, guess.guess_and_invoke(style, overload))?
443                        {
444                            (matched, consume) = (ret.matched, ret.consume);
445                        }
446                        if matched {
447                            match guess.ctx.policy_act() {
448                                Action::Stop => {
449                                    stopped = true;
450                                    guess.ctx.reset_policy_act();
451                                    break;
452                                }
453                                Action::Quit => return Ok(()),
454                                Action::Null => {}
455                            }
456                            break;
457                        }
458                    }
459                    // if not a prepolicy
460                    // and not stopped at current option
461                    // and not matched
462                    // and in strict mode
463                    // raise an Error::sp_not_found
464                    if !pre && !stopped && !matched && self.strict() {
465                        return Err(opt_fail.cause(Error::sp_not_found(name)));
466                    }
467                }
468                if !like_opt {
469                    trace!("`{:?}` not like option", opt);
470                }
471            }
472            if stopped {
473                // skip current, put left argument to noa args
474                lefts.extend(iter2.map(|(_, (a, _))| *a));
475                break;
476            }
477            // if consume the argument, skip next argument
478            if matched && consume {
479                iter2.next();
480            } else if !matched {
481                // add it to NOA if current argument not matched
482                lefts.push(*opt);
483            }
484        }
485
486        opt_fail.process_check(self.checker().opt_check(set))?;
487
488        let args = lefts;
489        let total = args.len();
490        let mut pos_fail = FailManager::default();
491        let mut cmd_fail = FailManager::default();
492
493        ctx.set_args(args.clone());
494        // when style is pos, noa index is [1..=len]
495        if total > 0 {
496            let name = crate::str::osstr_to_str_i(&args, Self::noa_cmd());
497            let mut guess = InvokeGuess {
498                set,
499                inv,
500                total,
501                name,
502                ctx,
503                arg: None,
504                next: None,
505                fail: &mut cmd_fail,
506                idx: Self::noa_cmd(),
507            };
508
509            trace!("guess Cmd = {:?}", guess.name);
510            Self::filter(pre, guess.guess_and_invoke(&UserStyle::Cmd, overload))?;
511            if let Action::Quit = ctx.policy_act() {
512                return Ok(());
513            }
514            cmd_fail.process_check(self.checker().cmd_check(set))?;
515
516            let mut guess = InvokeGuess {
517                set,
518                inv,
519                total,
520                ctx,
521                name: None,
522                arg: None,
523                next: None,
524                fail: &mut pos_fail,
525                idx: Self::noa_cmd(),
526            };
527
528            for idx in 1..total {
529                guess.idx = Self::noa_pos(idx);
530                guess.name = crate::str::osstr_to_str_i(&args, Self::noa_pos(idx));
531                trace!("guess Pos argument = {:?} @ {}", guess.name, guess.idx);
532                Self::filter(pre, guess.guess_and_invoke(&UserStyle::Pos, overload))?;
533                match guess.ctx.policy_act() {
534                    Action::Stop => {
535                        guess.ctx.reset_policy_act();
536                        break;
537                    }
538                    Action::Quit => return Ok(()),
539                    Action::Null => {}
540                }
541            }
542        } else {
543            cmd_fail.process_check(self.checker().cmd_check(set))?;
544        }
545
546        pos_fail.process_check(self.checker().pos_check(set))?;
547
548        let name = crate::str::osstr_to_str_i(&ctx.args, Self::noa_main());
549        let mut main_fail = FailManager::default();
550        let mut guess = InvokeGuess {
551            set,
552            inv,
553            total,
554            name,
555            ctx,
556            arg: None,
557            next: None,
558            fail: &mut main_fail,
559            idx: Self::noa_main(),
560        };
561
562        trace!("guess Main {:?}", guess.name);
563        Self::filter(pre, guess.guess_and_invoke(&UserStyle::Main, overload))?;
564        main_fail.process_check(self.checker().post_check(set))?;
565        Ok(())
566    }
567}
568
569impl<S, Chk> Policy for FwdPolicy<S, Chk>
570where
571    SetOpt<S>: Opt,
572    Chk: SetChecker<S>,
573    S: crate::set::Set + OptParser + OptValidator,
574{
575    type Ret = Return;
576
577    type Set = S;
578
579    type Inv<'a> = Invoker<'a, S>;
580
581    type Error = Error;
582
583    fn parse(
584        &mut self,
585        set: &mut Self::Set,
586        inv: &mut Self::Inv<'_>,
587
588        orig: Args,
589    ) -> Result<Self::Ret, Self::Error> {
590        let mut ctx = Ctx::default().with_orig(orig.clone());
591
592        match self.parse_impl(set, inv, &orig, &mut ctx) {
593            Ok(_) => Ok(Return::new(ctx)),
594            Err(e) => {
595                if e.is_failure() {
596                    Ok(Return::new(ctx).with_failure(e))
597                } else {
598                    Err(e)
599                }
600            }
601        }
602    }
603}
604
605#[cfg(test)]
606mod test {
607
608    use std::any::TypeId;
609    use std::ffi::OsStr;
610
611    use crate::opt::Cmd;
612    use crate::opt::ConfigBuildInfer;
613    use crate::opt::Pos;
614    use crate::prelude::*;
615    use crate::Error;
616
617    #[test]
618    fn testing() {
619        assert!(testing_prepolicy().is_ok());
620        assert!(testing_non_prepolicy().is_ok());
621    }
622
623    #[allow(clippy::too_many_arguments)]
624    fn check_opt_val<T: std::fmt::Debug + PartialEq + ErasedTy + 'static>(
625        opt: &AOpt,
626        uid: Uid,
627        name: &str,
628        vals: Option<Vec<T>>,
629        force: bool,
630        action: &Action,
631        type_id: &TypeId,
632        index: Option<&Index>,
633        alias: Option<Vec<&str>>,
634    ) -> Result<(), Error> {
635        let opt_uid = opt.uid();
636
637        assert_eq!(opt_uid, uid);
638        assert_eq!(opt.name(), name, "name not equal -{}({})-", opt_uid, name);
639        assert_eq!(
640            opt.force(),
641            force,
642            "option force required not equal -{}({})-: {}",
643            opt_uid,
644            name,
645            force
646        );
647        assert_eq!(opt.action(), action, "action not equal for {}", opt_uid);
648        assert_eq!(
649            opt.r#type(),
650            type_id,
651            "type_id not equal for {}({})",
652            opt_uid,
653            opt.name(),
654        );
655        assert_eq!(opt.index(), index, "option index not equal: {:?}", index);
656        if let Ok(opt_vals) = opt.vals::<T>() {
657            if let Some(vals) = vals {
658                assert_eq!(
659                    opt_vals.len(),
660                    vals.len(),
661                    "value length not equal for {}",
662                    opt_uid
663                );
664                for (l, r) in opt_vals.iter().zip(vals.iter()) {
665                    assert_eq!(
666                        l, r,
667                        "option value not equal -{}- : {:?} != {:?}",
668                        opt_uid, l, r
669                    );
670                }
671            }
672        } else {
673            assert!(
674                vals.is_none(),
675                "found none, option value not equal: {:?}",
676                vals
677            );
678        }
679        if let Some(opt_alias) = opt.alias() {
680            if let Some(alias) = alias {
681                assert_eq!(opt_alias.len(), alias.len());
682                for name in alias {
683                    assert!(
684                        opt_alias.iter().any(|n| n == name),
685                        "alias => {:?} <--> {}",
686                        &opt_alias,
687                        name,
688                    );
689                }
690            }
691        } else {
692            assert!(alias.is_none());
693        }
694        Ok(())
695    }
696
697    fn testing_non_prepolicy() -> Result<(), Error> {
698        let mut policy = AFwdPolicy::default();
699        let mut set = AHCSet::default();
700        let mut inv = AInvoker::default();
701        let args = Args::from([
702            "app",
703            "--copt",
704            "--iopt=63",
705            "--/dopt",
706            "set", // 1
707            "--iopt",
708            "-42",
709            "+eopt",
710            "-/fopt",
711            "8",       // 2
712            "16",      // 3
713            "average", // 4
714            "--りょう",
715            "88",
716            "--jopt",
717            "2",
718            "--iopt-alias1",
719            "0",
720            "--nopt=8.99",
721            "--hopt",
722            "48",
723            "--qopt=cpp",
724            "--alias-k=4",
725            "-l2.79",
726            "--nopt",
727            "3.12",
728            "--开关",
729            "-olily",
730            "program",  // 5
731            "software", // 6
732            "反转",     //7
733            "--值=恍恍惚惚",
734            "--qopt",
735            "rust",
736            "翻转", // 8
737        ]);
738
739        // add '+' to the prefix validator
740        set.validator_mut().add_prefix("+");
741        // 5
742        set.add_opt("--aopt=b")?;
743        set.add_opt("--/bopt=b")?.run()?;
744        set.add_opt("--copt=b!")?.set_action(Action::Cnt);
745        set.add_opt("--/dopt=b!")?.run()?;
746        set.add_opt("--eopt=b")?.add_alias("+eopt").run()?;
747        set.add_opt("--/fopt=b")?.add_alias("-/fopt").run()?;
748
749        // 8
750        set.add_opt("--gopt=i")?.run()?;
751        set.add_opt("--hopt=i!")?.run()?;
752        inv.entry(set.add_opt("--iopt=i")?.add_alias("--iopt-alias1").run()?)
753            .on(|set, ctx| {
754                assert_eq!(
755                    set["--hopt"].val::<i64>().ok(),
756                    None,
757                    "Option can set in any order, not access it in option"
758                );
759                Ok(Some(ctx.value::<i64>()? + 21))
760            });
761
762        // 10
763        set.add_opt("--jopt=u")?.set_force(false).run()?;
764        set.add_opt("--kopt=u")?
765            .set_action(Action::Set)
766            .add_alias("--alias-k")
767            .run()?;
768
769        // 13
770        set.add_opt("--lopt=f!")?.add_alias("-l").run()?;
771        set.add_opt("--mopt=f")?.set_value_t(1.02f64).run()?;
772        set.add_opt("--nopt=f")?.set_action(Action::Set).run()?;
773
774        // 16
775        set.add_opt("--oopt=s!")?.add_alias("-o");
776        set.add_opt("--popt=s")?.run()?;
777        inv.entry(set.add_opt("--qopt=s")?.run()?)
778            .on(|_, ctx| Ok(Some(ctx.value::<String>()?)))
779            .then(
780                |uid: Uid, set: &mut AHCSet, raw: Option<&OsStr>, val: Option<String>| {
781                    if let Some(val) = val {
782                        // let's put the value to `popt`
783                        set["--popt"].accessor_mut().push(val);
784                        if let Some(raw) = raw {
785                            set[uid].rawvals_mut()?.push(raw.to_os_string());
786                        }
787                        Ok(true)
788                    } else {
789                        Ok(false)
790                    }
791                },
792            );
793
794        // 19
795        set.add_opt("--开关=b")?;
796        set.add_opt("--值=s")?;
797        set.add_opt("--りょう=i")?;
798        set.add_opt("test_cmd=c")?;
799
800        let set_uid = set.add_opt("set=c")?.run()?;
801        let bpos_uid = set
802            .add_opt("bpos=p@[2,3]")?
803            .set_pos_type_only::<u64>()
804            .run()?;
805        let cpos_uid = set
806            .add_opt("cpos@4..5".infer::<Pos<String>>())?
807            .set_validator(ValValidator::contains2(vec!["average", "plus"]))
808            .run()?;
809        let dpos_uid = set.add_opt("dpos=p@5..7")?.set_action(Action::Set).run()?;
810        let epos_uid = set.add_opt("epos=p@7..")?.run()?;
811
812        inv.entry(set.add_opt("main=m")?.run()?)
813            .on(move |set, ctx| {
814                let copt = &set["--copt"];
815                let dopt = &set["--/dopt"];
816                let bpos = &set["bpos"];
817                let cpos = &set[cpos_uid];
818                let dpos = &set[dpos_uid];
819                let epos = &set["epos"];
820                let idx = ctx.idx()?;
821                let name = ctx.name()?;
822
823                assert_eq!(idx, 0);
824                assert_eq!(name.map(|v| v.as_ref()), Some("app"));
825                check_opt_val::<String>(
826                    epos,
827                    epos_uid,
828                    "epos",
829                    Some(vec!["反转".to_owned(), "翻转".to_owned()]),
830                    false,
831                    &Action::App,
832                    &TypeId::of::<Pos>(),
833                    Some(&Index::Range(7, None)),
834                    None,
835                )?;
836                check_opt_val::<String>(
837                    dpos,
838                    dpos_uid,
839                    "dpos",
840                    Some(vec!["program -- software".to_owned()]),
841                    false,
842                    &Action::Set,
843                    &TypeId::of::<Pos>(),
844                    Some(&Index::Range(5, Some(7))),
845                    None,
846                )?;
847                check_opt_val(
848                    cpos,
849                    cpos_uid,
850                    "cpos",
851                    Some(vec![2.31]),
852                    false,
853                    &Action::App,
854                    &TypeId::of::<Pos<String>>(),
855                    Some(&Index::Range(4, Some(5))),
856                    None,
857                )?;
858                check_opt_val::<u64>(
859                    bpos,
860                    bpos_uid,
861                    "bpos",
862                    Some(vec![32, 64]),
863                    false,
864                    &Action::App,
865                    &TypeId::of::<Pos<u64>>(),
866                    Some(&Index::list(vec![2, 3])),
867                    None,
868                )?;
869                check_opt_val::<u64>(
870                    copt,
871                    2,
872                    "--copt",
873                    Some(vec![1]),
874                    true,
875                    &Action::Cnt,
876                    &TypeId::of::<bool>(),
877                    None,
878                    None,
879                )?;
880                check_opt_val(
881                    dopt,
882                    3,
883                    "--/dopt",
884                    Some(vec![true]),
885                    true,
886                    &Action::Set,
887                    &TypeId::of::<bool>(),
888                    None,
889                    None,
890                )?;
891                Ok(Some(true))
892            });
893        inv.entry(epos_uid).on(|set, ctx| {
894            let ropt = &set["--开关"];
895            let sopt = &set["--值"];
896            let topt = &set["--りょう"];
897            let idx = ctx.idx()?;
898            let val = ctx.value::<String>()?;
899
900            check_opt_val::<i64>(
901                topt,
902                19,
903                "--りょう",
904                Some(vec![88]),
905                false,
906                &Action::App,
907                &TypeId::of::<i64>(),
908                None,
909                None,
910            )?;
911            check_opt_val::<String>(
912                sopt,
913                18,
914                "--值",
915                Some(vec![String::from("恍恍惚惚")]),
916                false,
917                &Action::App,
918                &TypeId::of::<String>(),
919                None,
920                None,
921            )?;
922            check_opt_val(
923                ropt,
924                17,
925                "--开关",
926                Some(vec![true]),
927                false,
928                &Action::Set,
929                &TypeId::of::<bool>(),
930                None,
931                None,
932            )?;
933            assert!(idx == 7 || idx == 8);
934            Ok(Some(val))
935        });
936        inv.entry(dpos_uid).on(|set, ctx| {
937            let oopt = &set["--oopt"];
938            let popt = &set["--popt"];
939            let qopt = &set["--qopt"];
940            let idx = ctx.idx()?;
941            let val = ctx.value::<String>()?;
942
943            check_opt_val::<String>(
944                qopt,
945                16,
946                "--qopt",
947                None,
948                false,
949                &Action::App,
950                &TypeId::of::<String>(),
951                None,
952                None,
953            )?;
954            check_opt_val(
955                popt,
956                15,
957                "--popt",
958                Some(vec![String::from("cpp"), String::from("rust")]),
959                false,
960                &Action::App,
961                &TypeId::of::<String>(),
962                None,
963                None,
964            )?;
965            check_opt_val(
966                oopt,
967                14,
968                "--oopt",
969                Some(vec![String::from("lily")]),
970                true,
971                &Action::App,
972                &TypeId::of::<String>(),
973                None,
974                Some(vec![("-o")]),
975            )?;
976            assert!(idx == 5 || idx == 6);
977            match set["dpos"].val::<String>() {
978                Ok(last_val) => Ok(Some(format!("{} -- {}", last_val, val))),
979                Err(_) => Ok(Some(val)),
980            }
981        });
982        inv.entry(cpos_uid).on(|set, ctx| {
983            let lopt = &set["--lopt"];
984            let mopt = &set["--mopt"];
985            let nopt = &set["--nopt"];
986            let idx = ctx.idx()?;
987            let val = ctx.value::<String>()?;
988
989            check_opt_val(
990                nopt,
991                13,
992                "--nopt",
993                Some(vec![3.12]),
994                false,
995                &Action::Set,
996                &TypeId::of::<f64>(),
997                None,
998                None,
999            )?;
1000            check_opt_val::<f64>(
1001                mopt,
1002                12,
1003                "--mopt",
1004                Some(vec![1.02]),
1005                false,
1006                &Action::App,
1007                &TypeId::of::<f64>(),
1008                None,
1009                None,
1010            )?;
1011            check_opt_val::<f64>(
1012                lopt,
1013                11,
1014                "--lopt",
1015                Some(vec![2.79]),
1016                true,
1017                &Action::App,
1018                &TypeId::of::<f64>(),
1019                None,
1020                Some(vec![("-l")]),
1021            )?;
1022            assert!(idx == 4);
1023
1024            let mut sum = 0.0;
1025
1026            for uid in [lopt, mopt, nopt].iter().map(|v| v.uid()) {
1027                sum += set[uid].val::<f64>()?;
1028            }
1029
1030            match val.as_str() {
1031                "average" => Ok(Some(sum / 3.0)),
1032                "plus" => Ok(Some(sum)),
1033                _ => Ok(None),
1034            }
1035        });
1036        inv.entry(bpos_uid).on(|set, ctx| {
1037            let jopt = &set["--jopt"];
1038            let kopt = &set["--kopt"];
1039            let idx = ctx.idx()?;
1040            let val = ctx.value::<u64>()?;
1041
1042            check_opt_val::<u64>(
1043                jopt,
1044                9,
1045                "--jopt",
1046                Some(vec![2]),
1047                false,
1048                &Action::App,
1049                &TypeId::of::<u64>(),
1050                None,
1051                None,
1052            )?;
1053            check_opt_val::<u64>(
1054                kopt,
1055                10,
1056                "--kopt",
1057                Some(vec![4]),
1058                false,
1059                &Action::Set,
1060                &TypeId::of::<u64>(),
1061                None,
1062                None,
1063            )?;
1064            assert!(idx == 2 || idx == 3);
1065            Ok(Some(val * set["--alias-k"].val::<u64>()?))
1066        });
1067        inv.entry(set_uid).on(move |set, ctx| {
1068            let uid = ctx.uid()?;
1069            let aopt = &set[0];
1070            let bopt = &set["--/bopt"];
1071            let apos = &set[uid];
1072            let eopt = &set["+eopt"];
1073            let fopt = &set["--/fopt=b"];
1074            let gopt = &set["--gopt"];
1075            let hopt = &set["--hopt"];
1076            let iopt = &set["--iopt"];
1077            let name = ctx.name()?;
1078            let value = ctx.value::<String>()?;
1079
1080            assert_eq!(name.map(|v| v.as_ref()), Some("set"));
1081            check_opt_val::<i64>(
1082                iopt,
1083                8,
1084                "--iopt",
1085                Some(vec![84, -21, 21]),
1086                false,
1087                &Action::App,
1088                &TypeId::of::<i64>(),
1089                None,
1090                Some(vec![("--iopt-alias1")]),
1091            )?;
1092            check_opt_val::<i64>(
1093                hopt,
1094                7,
1095                "--hopt",
1096                Some(vec![48]),
1097                true,
1098                &Action::App,
1099                &TypeId::of::<i64>(),
1100                None,
1101                None,
1102            )?;
1103            check_opt_val::<i64>(
1104                gopt,
1105                6,
1106                "--gopt",
1107                None,
1108                false,
1109                &Action::App,
1110                &TypeId::of::<i64>(),
1111                None,
1112                None,
1113            )?;
1114
1115            check_opt_val(
1116                fopt,
1117                5,
1118                "--/fopt",
1119                Some(vec![true]),
1120                false,
1121                &Action::Set,
1122                &TypeId::of::<bool>(),
1123                None,
1124                Some(vec![("-/fopt")]),
1125            )?;
1126            check_opt_val(
1127                eopt,
1128                4,
1129                "--eopt",
1130                Some(vec![true]),
1131                false,
1132                &Action::Set,
1133                &TypeId::of::<bool>(),
1134                None,
1135                Some(vec![("+eopt")]),
1136            )?;
1137            check_opt_val(
1138                bopt,
1139                1,
1140                "--/bopt",
1141                Some(vec![false]),
1142                false,
1143                &Action::Set,
1144                &TypeId::of::<bool>(),
1145                None,
1146                None,
1147            )?;
1148            check_opt_val(
1149                aopt,
1150                0,
1151                "--aopt",
1152                Some(vec![false]),
1153                false,
1154                &Action::Set,
1155                &TypeId::of::<bool>(),
1156                None,
1157                None,
1158            )?;
1159            check_opt_val::<String>(
1160                apos,
1161                set_uid,
1162                "set",
1163                None,
1164                true,
1165                &Action::Set,
1166                &TypeId::of::<Cmd>(),
1167                Some(&Index::forward(1)),
1168                None,
1169            )?;
1170            Ok(Some(value))
1171        });
1172        for opt in set.iter_mut() {
1173            opt.init()?;
1174        }
1175        policy.parse(&mut set, &mut inv, args)?;
1176        Ok(())
1177    }
1178
1179    fn testing_prepolicy() -> Result<(), Error> {
1180        let mut policy = AFwdPolicy::default().with_prepolicy(true);
1181        let mut set = AHCSet::default();
1182        let mut inv = AInvoker::default();
1183        let args = Args::from([
1184            "app", // 0
1185            "--copt",
1186            "--iopt=63",
1187            "--/dopt",
1188            "set", // 1
1189            "--iopt",
1190            "-42",
1191            "+eopt",
1192            "-/fopt",
1193            "8",       // 2
1194            "16",      // 3
1195            "average", // 4
1196            "--りょう",
1197            "88",
1198            "--jopt",
1199            "2",
1200            "--iopt-alias1",
1201            "0",
1202            "--nopt=8.99",
1203            "--hopt",
1204            "48",
1205            "--qopt=cpp",
1206            "--alias-k=4",
1207            "-l2.79",
1208            "--nopt",
1209            "3.12",
1210            "--开关",
1211            "-olily",
1212            "program",  // 5
1213            "software", // 6
1214            "反转",     //7
1215            "--值=恍恍惚惚",
1216            "--qopt",
1217            "rust",
1218            "翻转", // 8
1219            "left",
1220            "--wopt=98",
1221            "剩余的",
1222            "--ropt=23",
1223            "-r",
1224            "--s我的",
1225        ]);
1226
1227        // add '+' to the prefix validator
1228        set.validator_mut().add_prefix("+");
1229        // 5
1230        set.add_opt("--aopt=b")?;
1231        set.add_opt("--/bopt=b")?.run()?;
1232        set.add_opt("--copt=b!")?.set_action(Action::Cnt);
1233        set.add_opt("--/dopt=b!")?.run()?;
1234        set.add_opt("--eopt=b")?.add_alias("+eopt").run()?;
1235        set.add_opt("--/fopt=b")?.add_alias("-/fopt").run()?;
1236
1237        // 8
1238        set.add_opt("--gopt=i")?.run()?;
1239        set.add_opt("--hopt=i!")?.run()?;
1240        inv.entry(set.add_opt("--iopt=i")?.add_alias("--iopt-alias1").run()?)
1241            .on(|set, ctx| {
1242                assert_eq!(
1243                    set["--hopt"].val::<i64>().ok(),
1244                    None,
1245                    "Option can set in any order, not access it in option"
1246                );
1247                Ok(Some(ctx.value::<i64>()? + 21))
1248            });
1249
1250        // 10
1251        set.add_opt("--jopt=u")?.set_force(false).run()?;
1252        set.add_opt("--kopt=u")?
1253            .set_action(Action::Set)
1254            .add_alias("--alias-k")
1255            .run()?;
1256
1257        // 13
1258        set.add_opt("--lopt=f!")?.add_alias("-l").run()?;
1259        set.add_opt("--mopt=f")?.set_value_t(1.02f64).run()?;
1260        set.add_opt("--nopt=f")?.set_action(Action::Set).run()?;
1261
1262        // 16
1263        set.add_opt("--oopt=s!")?.add_alias("-o");
1264        set.add_opt("--popt=s")?.run()?;
1265        inv.entry(set.add_opt("--qopt=s")?.run()?)
1266            .on(|_, ctx| Ok(Some(ctx.value::<String>()?)))
1267            .then(
1268                |uid: Uid, set: &mut AHCSet, raw: Option<&OsStr>, val: Option<String>| {
1269                    if let Some(val) = val {
1270                        // let's put the value to `popt`
1271                        set["--popt"].accessor_mut().push(val);
1272                        if let Some(raw) = raw {
1273                            set[uid].rawvals_mut()?.push(raw.to_os_string());
1274                        }
1275                        Ok(true)
1276                    } else {
1277                        Ok(false)
1278                    }
1279                },
1280            );
1281
1282        // 19
1283        set.add_opt("--开关=b")?;
1284        set.add_opt("--值=s")?;
1285        set.add_opt("--りょう=i")?;
1286        set.add_opt("test_cmd=c")?;
1287
1288        let set_uid = set.add_opt("set=c")?.run()?;
1289        let bpos_uid = set
1290            .add_opt("bpos=p@[2,3]")?
1291            .set_pos_type_only::<u64>()
1292            .run()?;
1293        let cpos_uid = set
1294            .add_opt("cpos@4..5".infer::<Pos<String>>())?
1295            .set_validator(ValValidator::contains2(vec!["average", "plus"]))
1296            .run()?;
1297        let dpos_uid = set.add_opt("dpos=p@5..7")?.set_action(Action::Set).run()?;
1298        let epos_uid = set.add_opt("epos=p@7..9")?.run()?;
1299
1300        inv.entry(set.add_opt("main=m")?.run()?)
1301            .on(move |set, ctx| {
1302                let copt = &set["--copt"];
1303                let dopt = &set["--/dopt"];
1304                let bpos = &set["bpos"];
1305                let cpos = &set[cpos_uid];
1306                let dpos = &set[dpos_uid];
1307                let epos = &set["epos"];
1308                let idx = ctx.idx()?;
1309                let name = ctx.name()?;
1310
1311                assert_eq!(idx, 0);
1312                assert_eq!(name.map(|v| v.as_ref()), Some("app"));
1313                check_opt_val::<String>(
1314                    epos,
1315                    epos_uid,
1316                    "epos",
1317                    Some(vec!["反转".to_owned(), "翻转".to_owned()]),
1318                    false,
1319                    &Action::App,
1320                    &TypeId::of::<Pos>(),
1321                    Some(&Index::Range(7, Some(9))),
1322                    None,
1323                )?;
1324                check_opt_val::<String>(
1325                    dpos,
1326                    dpos_uid,
1327                    "dpos",
1328                    Some(vec!["program -- software".to_owned()]),
1329                    false,
1330                    &Action::Set,
1331                    &TypeId::of::<Pos>(),
1332                    Some(&Index::Range(5, Some(7))),
1333                    None,
1334                )?;
1335                check_opt_val(
1336                    cpos,
1337                    cpos_uid,
1338                    "cpos",
1339                    Some(vec![2.31]),
1340                    false,
1341                    &Action::App,
1342                    &TypeId::of::<Pos<String>>(),
1343                    Some(&Index::Range(4, Some(5))),
1344                    None,
1345                )?;
1346                check_opt_val::<u64>(
1347                    bpos,
1348                    bpos_uid,
1349                    "bpos",
1350                    Some(vec![32, 64]),
1351                    false,
1352                    &Action::App,
1353                    &TypeId::of::<Pos<u64>>(),
1354                    Some(&Index::list(vec![2, 3])),
1355                    None,
1356                )?;
1357                check_opt_val::<u64>(
1358                    copt,
1359                    2,
1360                    "--copt",
1361                    Some(vec![1]),
1362                    true,
1363                    &Action::Cnt,
1364                    &TypeId::of::<bool>(),
1365                    None,
1366                    None,
1367                )?;
1368                check_opt_val(
1369                    dopt,
1370                    3,
1371                    "--/dopt",
1372                    Some(vec![true]),
1373                    true,
1374                    &Action::Set,
1375                    &TypeId::of::<bool>(),
1376                    None,
1377                    None,
1378                )?;
1379                Ok(Some(true))
1380            });
1381        inv.entry(epos_uid).on(|set, ctx| {
1382            let ropt = &set["--开关"];
1383            let sopt = &set["--值"];
1384            let topt = &set["--りょう"];
1385            let idx = ctx.idx()?;
1386            let val = ctx.value::<String>()?;
1387
1388            check_opt_val::<i64>(
1389                topt,
1390                19,
1391                "--りょう",
1392                Some(vec![88]),
1393                false,
1394                &Action::App,
1395                &TypeId::of::<i64>(),
1396                None,
1397                None,
1398            )?;
1399            check_opt_val::<String>(
1400                sopt,
1401                18,
1402                "--值",
1403                Some(vec![String::from("恍恍惚惚")]),
1404                false,
1405                &Action::App,
1406                &TypeId::of::<String>(),
1407                None,
1408                None,
1409            )?;
1410            check_opt_val(
1411                ropt,
1412                17,
1413                "--开关",
1414                Some(vec![true]),
1415                false,
1416                &Action::Set,
1417                &TypeId::of::<bool>(),
1418                None,
1419                None,
1420            )?;
1421            assert!(idx == 7 || idx == 8);
1422            Ok(Some(val))
1423        });
1424        inv.entry(dpos_uid).on(|set, ctx| {
1425            let oopt = &set["--oopt"];
1426            let popt = &set["--popt"];
1427            let qopt = &set["--qopt"];
1428            let idx = ctx.idx()?;
1429            let val = ctx.value::<String>()?;
1430
1431            check_opt_val::<String>(
1432                qopt,
1433                16,
1434                "--qopt",
1435                None,
1436                false,
1437                &Action::App,
1438                &TypeId::of::<String>(),
1439                None,
1440                None,
1441            )?;
1442            check_opt_val(
1443                popt,
1444                15,
1445                "--popt",
1446                Some(vec![String::from("cpp"), String::from("rust")]),
1447                false,
1448                &Action::App,
1449                &TypeId::of::<String>(),
1450                None,
1451                None,
1452            )?;
1453            check_opt_val(
1454                oopt,
1455                14,
1456                "--oopt",
1457                Some(vec![String::from("lily")]),
1458                true,
1459                &Action::App,
1460                &TypeId::of::<String>(),
1461                None,
1462                Some(vec![("-o")]),
1463            )?;
1464            assert!(idx == 5 || idx == 6);
1465            match set["dpos"].val::<String>() {
1466                Ok(last_val) => Ok(Some(format!("{} -- {}", last_val, val))),
1467                Err(_) => Ok(Some(val)),
1468            }
1469        });
1470        inv.entry(cpos_uid).on(|set, ctx| {
1471            let lopt = &set["--lopt"];
1472            let mopt = &set["--mopt"];
1473            let nopt = &set["--nopt"];
1474            let idx = ctx.idx()?;
1475            let val = ctx.value::<String>()?;
1476
1477            check_opt_val(
1478                nopt,
1479                13,
1480                "--nopt",
1481                Some(vec![3.12]),
1482                false,
1483                &Action::Set,
1484                &TypeId::of::<f64>(),
1485                None,
1486                None,
1487            )?;
1488            check_opt_val::<f64>(
1489                mopt,
1490                12,
1491                "--mopt",
1492                Some(vec![1.02]),
1493                false,
1494                &Action::App,
1495                &TypeId::of::<f64>(),
1496                None,
1497                None,
1498            )?;
1499            check_opt_val::<f64>(
1500                lopt,
1501                11,
1502                "--lopt",
1503                Some(vec![2.79]),
1504                true,
1505                &Action::App,
1506                &TypeId::of::<f64>(),
1507                None,
1508                Some(vec![("-l")]),
1509            )?;
1510            assert!(idx == 4);
1511
1512            let mut sum = 0.0;
1513
1514            for uid in [lopt, mopt, nopt].iter().map(|v| v.uid()) {
1515                sum += set[uid].val::<f64>()?;
1516            }
1517
1518            match val.as_str() {
1519                "average" => Ok(Some(sum / 3.0)),
1520                "plus" => Ok(Some(sum)),
1521                _ => Ok(None),
1522            }
1523        });
1524        inv.entry(bpos_uid).on(|set, ctx| {
1525            let jopt = &set["--jopt"];
1526            let kopt = &set["--kopt"];
1527            let idx = ctx.idx()?;
1528            let val = ctx.value::<u64>()?;
1529
1530            check_opt_val::<u64>(
1531                jopt,
1532                9,
1533                "--jopt",
1534                Some(vec![2]),
1535                false,
1536                &Action::App,
1537                &TypeId::of::<u64>(),
1538                None,
1539                None,
1540            )?;
1541            check_opt_val::<u64>(
1542                kopt,
1543                10,
1544                "--kopt",
1545                Some(vec![4]),
1546                false,
1547                &Action::Set,
1548                &TypeId::of::<u64>(),
1549                None,
1550                None,
1551            )?;
1552            assert!(idx == 2 || idx == 3);
1553            Ok(Some(val * set["--alias-k"].val::<u64>()?))
1554        });
1555        inv.entry(set_uid).on(move |set, ctx| {
1556            let uid = ctx.uid()?;
1557            let aopt = &set[0];
1558            let bopt = &set["--/bopt"];
1559            let apos = &set[uid];
1560            let eopt = &set["+eopt"];
1561            let fopt = &set["--/fopt=b"];
1562            let gopt = &set["--gopt"];
1563            let hopt = &set["--hopt"];
1564            let iopt = &set["--iopt"];
1565            let name = ctx.name()?;
1566            let value = ctx.value::<String>()?;
1567
1568            assert_eq!(name.map(|v| v.as_ref()), Some("set"));
1569            check_opt_val::<i64>(
1570                iopt,
1571                8,
1572                "--iopt",
1573                Some(vec![84, -21, 21]),
1574                false,
1575                &Action::App,
1576                &TypeId::of::<i64>(),
1577                None,
1578                Some(vec![("--iopt-alias1")]),
1579            )?;
1580            check_opt_val::<i64>(
1581                hopt,
1582                7,
1583                "--hopt",
1584                Some(vec![48]),
1585                true,
1586                &Action::App,
1587                &TypeId::of::<i64>(),
1588                None,
1589                None,
1590            )?;
1591            check_opt_val::<i64>(
1592                gopt,
1593                6,
1594                "--gopt",
1595                None,
1596                false,
1597                &Action::App,
1598                &TypeId::of::<i64>(),
1599                None,
1600                None,
1601            )?;
1602
1603            check_opt_val(
1604                fopt,
1605                5,
1606                "--/fopt",
1607                Some(vec![true]),
1608                false,
1609                &Action::Set,
1610                &TypeId::of::<bool>(),
1611                None,
1612                Some(vec![("-/fopt")]),
1613            )?;
1614            check_opt_val(
1615                eopt,
1616                4,
1617                "--eopt",
1618                Some(vec![true]),
1619                false,
1620                &Action::Set,
1621                &TypeId::of::<bool>(),
1622                None,
1623                Some(vec![("+eopt")]),
1624            )?;
1625            check_opt_val(
1626                bopt,
1627                1,
1628                "--/bopt",
1629                Some(vec![false]),
1630                false,
1631                &Action::Set,
1632                &TypeId::of::<bool>(),
1633                None,
1634                None,
1635            )?;
1636            check_opt_val(
1637                aopt,
1638                0,
1639                "--aopt",
1640                Some(vec![false]),
1641                false,
1642                &Action::Set,
1643                &TypeId::of::<bool>(),
1644                None,
1645                None,
1646            )?;
1647            check_opt_val::<bool>(
1648                apos,
1649                set_uid,
1650                "set",
1651                None,
1652                true,
1653                &Action::Set,
1654                &TypeId::of::<Cmd>(),
1655                Some(&Index::forward(1)),
1656                None,
1657            )?;
1658            Ok(Some(value))
1659        });
1660        for opt in set.iter_mut() {
1661            opt.init()?;
1662        }
1663        let ret = policy.parse(&mut set, &mut inv, args.clone());
1664
1665        assert!(ret.is_ok());
1666        let ret = ret.unwrap();
1667        let args = ret.args();
1668
1669        for (idx, arg) in [
1670            "app",
1671            "set",
1672            "8",
1673            "16",
1674            "average",
1675            "program",
1676            "software",
1677            "反转",
1678            "翻转",
1679            "left",
1680            "--wopt=98",
1681            "剩余的",
1682            "--ropt=23",
1683            "-r",
1684            "--s我的",
1685        ]
1686        .iter()
1687        .enumerate()
1688        {
1689            assert_eq!(args[idx], OsStr::new(arg));
1690        }
1691        Ok(())
1692    }
1693}