1- use std :: collections :: HashMap ;
2-
1+ use clap :: { Args , Parser , Subcommand } ;
2+ use functora_cfg :: * ;
33use serde:: { Deserialize , Serialize } ;
44use serial_test:: serial;
5+ use std:: collections:: HashMap ;
6+ use std:: fmt:: Debug ;
57use temp_env:: with_vars;
68
7- fn new_cfg ( cli : & Cli ) -> Cfg {
8- let def = Cli {
9- cfg : None ,
10- host : Some ( "127.0.0.1" . into ( ) ) ,
11- port : Some ( 8080 ) ,
12- debug : Some ( false ) ,
13- nest_val : Some ( CfgNest {
14- name : "foo" . into ( ) ,
15- value : 42 ,
16- } ) ,
17- many_val : HashMap :: new ( ) ,
18- tags : None ,
19- } ;
20- functora_cfg:: Cfg {
21- default : & def,
22- file_path : |cli : & Cli | cli. cfg . as_deref ( ) ,
23- env_prefix : "FUNCTORA" ,
24- command_line : cli,
25- }
26- . eval ( )
27- . unwrap ( )
28- }
29-
30- #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
9+ #[ derive(
10+ Eq , PartialEq , Debug , Clone , Serialize , Deserialize ,
11+ ) ]
3112struct Cfg {
3213 host : String ,
3314 port : u16 ,
34- debug : bool ,
35- nest_val : Option < CfgNest > ,
36- many_val : HashMap < usize , CfgNest > ,
37- tags : Option < Vec < String > > ,
15+ logs : bool ,
16+ main_account : Account ,
17+ sub_accounts : HashMap < String , Account > ,
18+ }
19+
20+ impl Cfg {
21+ pub fn new (
22+ cli : & Cli < IdClap < HashMap < String , Account > > > ,
23+ ) -> Self {
24+ functora_cfg:: Cfg {
25+ default : & Cli :: def ( ) ,
26+ file_path : |cli : & Cli <
27+ IdClap < HashMap < String , Account > > ,
28+ > | cli. toml . as_deref ( ) ,
29+ env_prefix : "FUNCTORA" ,
30+ command_line : cli,
31+ }
32+ . eval ( )
33+ . unwrap ( )
34+ }
3835}
3936
40- #[ derive( Debug , Serialize , Deserialize , PartialEq ) ]
41- struct CfgNest {
42- name : String ,
43- value : i32 ,
37+ #[ derive(
38+ Eq ,
39+ PartialEq ,
40+ Ord ,
41+ PartialOrd ,
42+ Debug ,
43+ Clone ,
44+ Serialize ,
45+ Deserialize ,
46+ Args ,
47+ ) ]
48+ struct Account {
49+ #[ arg( long) ]
50+ alias : String ,
51+ #[ arg( long) ]
52+ balance : i32 ,
53+ #[ arg( long) ]
54+ tags : Option < Vec < String > > ,
4455}
4556
46- #[ derive( Debug , Serialize ) ]
47- struct Cli {
48- cfg : Option < String > ,
57+ #[ derive(
58+ Eq ,
59+ PartialEq ,
60+ Debug ,
61+ Clone ,
62+ Serialize ,
63+ Deserialize ,
64+ Parser ,
65+ ) ]
66+ #[ command( version, about, long_about = None ) ]
67+ struct Cli < T >
68+ where
69+ T : Eq
70+ + PartialEq
71+ + Debug
72+ + Clone
73+ + Serialize
74+ + Subcommand ,
75+ {
76+ #[ arg( long) ]
77+ toml : Option < String > ,
78+ #[ arg( long) ]
4979 host : Option < String > ,
80+ #[ arg( long) ]
5081 port : Option < u16 > ,
51- debug : Option < bool > ,
52- nest_val : Option < CfgNest > ,
53- many_val : HashMap < usize , CfgNest > ,
54- tags : Option < Vec < String > > ,
82+ #[ arg( long) ]
83+ logs : Option < bool > ,
84+ #[ command( flatten) ]
85+ main_account : Option < Account > ,
86+ #[ command( subcommand) ]
87+ sub_accounts : T ,
88+ }
89+
90+ impl Cli < IdClap < HashMap < String , Account > > > {
91+ pub fn def ( ) -> Self {
92+ Cli {
93+ toml : None ,
94+ host : Some ( "127.0.0.1" . into ( ) ) ,
95+ port : Some ( 8080 ) ,
96+ logs : Some ( false ) ,
97+ main_account : Some ( Account {
98+ alias : "foo" . into ( ) ,
99+ balance : 42 ,
100+ tags : None ,
101+ } ) ,
102+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
103+ }
104+ }
55105}
56106
57107#[ test]
58108#[ serial]
59109fn defaults_only ( ) {
60- let def = Cfg {
61- host : "127.0.0.1" . into ( ) ,
62- port : 8080 ,
63- debug : false ,
64- nest_val : Some ( CfgNest {
65- name : "foo" . into ( ) ,
66- value : 42 ,
67- } ) ,
68- many_val : HashMap :: new ( ) ,
69- tags : None ,
70- } ;
71- let cli = Cli {
72- cfg : None ,
110+ let lhs = Cfg :: new ( & Cli {
111+ toml : None ,
73112 host : None ,
74113 port : None ,
75- debug : None ,
76- nest_val : None ,
77- many_val : HashMap :: new ( ) ,
78- tags : None ,
114+ logs : None ,
115+ main_account : None ,
116+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
117+ } ) ;
118+ let rhs = Cfg {
119+ host : "127.0.0.1" . into ( ) ,
120+ port : 8080 ,
121+ logs : false ,
122+ main_account : Account {
123+ alias : "foo" . into ( ) ,
124+ balance : 42 ,
125+ tags : None ,
126+ } ,
127+ sub_accounts : HashMap :: new ( ) ,
79128 } ;
80- let cfg: Cfg = new_cfg ( & cli) ;
81- assert_eq ! ( cfg, def) ;
129+ assert_eq ! ( lhs, rhs) ;
82130}
83131
84132#[ test]
@@ -88,35 +136,34 @@ fn with_file_override() {
88136 let file = r#"
89137 host = "192.168.1.100"
90138 port = 9090
91- debug = true
139+ logs = true
92140 tags = ["a", "b"]
93141
94- [many_val.1 ]
95- name = "hello"
96- value = 123
142+ [sub_accounts.alice ]
143+ alias = "hello"
144+ balance = 123
97145 "# ;
98146 std:: fs:: write ( & path, file) . unwrap ( ) ;
99147 let cli = Cli {
100- cfg : Some ( path. to_string_lossy ( ) . into_owned ( ) ) ,
148+ toml : Some ( path. to_string_lossy ( ) . into_owned ( ) ) ,
101149 host : None ,
102150 port : None ,
103- debug : None ,
104- nest_val : None ,
105- many_val : HashMap :: new ( ) ,
106- tags : None ,
151+ logs : None ,
152+ main_account : None ,
153+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
107154 } ;
108- let cfg: Cfg = new_cfg ( & cli) ;
155+ let cfg: Cfg = Cfg :: new ( & cli) ;
109156 assert_eq ! ( cfg. host, "192.168.1.100" ) ;
110157 assert_eq ! ( cfg. port, 9090 ) ;
111- assert_eq ! ( cfg. debug, true ) ;
112- assert_eq ! ( cfg. tags. unwrap( ) , vec![ "a" , "b" ] ) ;
158+ assert_eq ! ( cfg. logs, true ) ;
113159 assert_eq ! (
114- cfg. many_val ,
160+ cfg. sub_accounts ,
115161 HashMap :: from( [ (
116- 1 ,
117- CfgNest {
118- name: "hello" . into( ) ,
119- value: 123
162+ "alice" . into( ) ,
163+ Account {
164+ alias: "hello" . into( ) ,
165+ balance: 123 ,
166+ tags: None ,
120167 }
121168 ) ] )
122169 ) ;
@@ -126,42 +173,49 @@ fn with_file_override() {
126173#[ serial]
127174fn env_override ( ) {
128175 let cli = Cli {
129- cfg : None ,
176+ toml : None ,
130177 host : None ,
131178 port : None ,
132- debug : None ,
133- nest_val : None ,
134- many_val : HashMap :: new ( ) ,
135- tags : None ,
179+ logs : None ,
180+ main_account : None ,
181+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
136182 } ;
137183 with_vars (
138184 vec ! [
139185 ( "FUNCTORA__HOST" , Some ( "10.0.0.1" ) ) ,
140186 ( "FUNCTORA__PORT" , Some ( "7070" ) ) ,
141- ( "FUNCTORA__DEBUG" , Some ( "true" ) ) ,
142- ( "FUNCTORA__NEST_VAL__NAME" , Some ( "bar" ) ) ,
143- ( "FUNCTORA__MANY_VAL__0__NAME" , Some ( "buz" ) ) ,
144- ( "FUNCTORA__MANY_VAL__0__VALUE" , Some ( "1" ) ) ,
187+ ( "FUNCTORA__LOGS" , Some ( "true" ) ) ,
188+ ( "FUNCTORA__MAIN_ACCOUNT__ALIAS" , Some ( "bar" ) ) ,
189+ (
190+ "FUNCTORA__SUB_ACCOUNTS__BOB__ALIAS" ,
191+ Some ( "buz" ) ,
192+ ) ,
193+ (
194+ "FUNCTORA__SUB_ACCOUNTS__BOB__BALANCE" ,
195+ Some ( "1" ) ,
196+ ) ,
145197 ] ,
146198 || {
147- let cfg: Cfg = new_cfg ( & cli) ;
199+ let cfg: Cfg = Cfg :: new ( & cli) ;
148200 assert_eq ! ( cfg. host, "10.0.0.1" ) ;
149201 assert_eq ! ( cfg. port, 7070 ) ;
150- assert_eq ! ( cfg. debug , true ) ;
202+ assert_eq ! ( cfg. logs , true ) ;
151203 assert_eq ! (
152- cfg. nest_val,
153- Some ( CfgNest {
154- name: "bar" . into( ) ,
155- value: 42
156- } )
204+ cfg. main_account,
205+ Account {
206+ alias: "bar" . into( ) ,
207+ balance: 42 ,
208+ tags: None ,
209+ }
157210 ) ;
158211 assert_eq ! (
159- cfg. many_val ,
212+ cfg. sub_accounts ,
160213 HashMap :: from( [ (
161- 0 ,
162- CfgNest {
163- name: "buz" . into( ) ,
164- value: 1
214+ "bob" . into( ) ,
215+ Account {
216+ alias: "buz" . into( ) ,
217+ balance: 1 ,
218+ tags: None ,
165219 }
166220 ) ] )
167221 ) ;
@@ -173,34 +227,31 @@ fn env_override() {
173227#[ serial]
174228fn cli_override ( ) {
175229 let cli = Cli {
176- cfg : None ,
230+ toml : None ,
177231 host : Some ( "cli.host" . into ( ) ) ,
178232 port : Some ( 6060 ) ,
179- debug : Some ( true ) ,
180- nest_val : None ,
181- many_val : HashMap :: new ( ) ,
182- tags : Some ( vec ! [ "cli1" . into( ) , "cli2" . into( ) ] ) ,
233+ logs : Some ( true ) ,
234+ main_account : None ,
235+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
183236 } ;
184- let cfg: Cfg = new_cfg ( & cli) ;
237+ let cfg: Cfg = Cfg :: new ( & cli) ;
185238 assert_eq ! ( cfg. host, "cli.host" ) ;
186239 assert_eq ! ( cfg. port, 6060 ) ;
187- assert_eq ! ( cfg. debug, true ) ;
188- assert_eq ! ( cfg. tags. unwrap( ) , vec![ "cli1" , "cli2" ] ) ;
240+ assert_eq ! ( cfg. logs, true ) ;
189241}
190242
191243#[ test]
192244#[ serial]
193245fn nested_struct ( ) {
194246 let cli = Cli {
195- cfg : None ,
247+ toml : None ,
196248 host : None ,
197249 port : None ,
198- debug : None ,
199- nest_val : None ,
200- many_val : HashMap :: new ( ) ,
201- tags : None ,
250+ logs : None ,
251+ main_account : None ,
252+ sub_accounts : IdClap ( HashMap :: new ( ) ) ,
202253 } ;
203- let cfg: Cfg = new_cfg ( & cli) ;
204- assert_eq ! ( cfg. nest_val . as_ref ( ) . unwrap ( ) . name , "foo" ) ;
205- assert_eq ! ( cfg. nest_val . as_ref ( ) . unwrap ( ) . value , 42 ) ;
254+ let cfg: Cfg = Cfg :: new ( & cli) ;
255+ assert_eq ! ( cfg. main_account . alias , "foo" ) ;
256+ assert_eq ! ( cfg. main_account . balance , 42 ) ;
206257}
0 commit comments