1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, 2// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and 3// Ana Hobden (@hoverbear) <operator@hoverbear.org> 4// 5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 8// option. This file may not be copied, modified, or distributed 9// except according to those terms. 10// 11// This work was derived from Structopt (https://github.com/TeXitoi/structopt) 12// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the 13// MIT/Apache 2.0 license. 14 15use clap::error::ErrorKind; 16use clap::Parser; 17use std::num::ParseIntError; 18 19pub const DISPLAY_ORDER: usize = 2; 20 21// Check if the global settings compile 22#[derive(Parser, Debug, PartialEq, Eq)] 23#[command(group = clap::ArgGroup::new("foo"))] 24struct Opt { 25 #[arg( 26 long = "x", 27 display_order = DISPLAY_ORDER, 28 next_line_help = true, 29 default_value = "0", 30 require_equals = true, 31 )] 32 x: i32, 33 34 #[arg(short = 'l', long = "level", aliases = ["set-level", "lvl"])] 35 level: String, 36 37 #[arg(long("values"))] 38 values: Vec<i32>, 39 40 #[arg(id = "FILE", requires_if("FILE", "values"))] 41 files: Vec<String>, 42} 43 44#[test] 45fn test_slice() { 46 assert_eq!( 47 Opt { 48 x: 0, 49 level: "1".to_string(), 50 files: Vec::new(), 51 values: vec![], 52 }, 53 Opt::try_parse_from(["test", "-l", "1"]).unwrap() 54 ); 55 assert_eq!( 56 Opt { 57 x: 0, 58 level: "1".to_string(), 59 files: Vec::new(), 60 values: vec![], 61 }, 62 Opt::try_parse_from(["test", "--level", "1"]).unwrap() 63 ); 64 assert_eq!( 65 Opt { 66 x: 0, 67 level: "1".to_string(), 68 files: Vec::new(), 69 values: vec![], 70 }, 71 Opt::try_parse_from(["test", "--set-level", "1"]).unwrap() 72 ); 73 assert_eq!( 74 Opt { 75 x: 0, 76 level: "1".to_string(), 77 files: Vec::new(), 78 values: vec![], 79 }, 80 Opt::try_parse_from(["test", "--lvl", "1"]).unwrap() 81 ); 82} 83 84#[test] 85fn test_multi_args() { 86 assert_eq!( 87 Opt { 88 x: 0, 89 level: "1".to_string(), 90 files: vec!["file".to_string()], 91 values: vec![], 92 }, 93 Opt::try_parse_from(["test", "-l", "1", "file"]).unwrap() 94 ); 95 assert_eq!( 96 Opt { 97 x: 0, 98 level: "1".to_string(), 99 files: vec!["FILE".to_string()], 100 values: vec![1], 101 }, 102 Opt::try_parse_from(["test", "-l", "1", "--values", "1", "--", "FILE"]).unwrap() 103 ); 104} 105 106#[test] 107fn test_multi_args_fail() { 108 let result = Opt::try_parse_from(["test", "-l", "1", "--", "FILE"]); 109 assert!(result.is_err()); 110} 111 112#[test] 113fn test_bool() { 114 assert_eq!( 115 Opt { 116 x: 1, 117 level: "1".to_string(), 118 files: vec![], 119 values: vec![], 120 }, 121 Opt::try_parse_from(["test", "-l", "1", "--x=1"]).unwrap() 122 ); 123 let result = Opt::try_parse_from(["test", "-l", "1", "--x", "1"]); 124 assert!(result.is_err()); 125 assert_eq!(result.unwrap_err().kind(), ErrorKind::NoEquals); 126} 127 128fn parse_hex(input: &str) -> Result<u64, ParseIntError> { 129 u64::from_str_radix(input, 16) 130} 131 132#[derive(Parser, PartialEq, Debug)] 133struct HexOpt { 134 #[arg(short, value_parser = parse_hex)] 135 number: u64, 136} 137 138#[test] 139#[cfg(feature = "error-context")] 140fn test_parse_hex_function_path() { 141 assert_eq!( 142 HexOpt { number: 5 }, 143 HexOpt::try_parse_from(["test", "-n", "5"]).unwrap() 144 ); 145 assert_eq!( 146 HexOpt { 147 number: 0x00ab_cdef 148 }, 149 HexOpt::try_parse_from(["test", "-n", "abcdef"]).unwrap() 150 ); 151 152 let err = HexOpt::try_parse_from(["test", "-n", "gg"]).unwrap_err(); 153 assert!( 154 err.to_string().contains("invalid digit found in string"), 155 "{}", 156 err 157 ); 158} 159