@@ -50,11 +50,61 @@ enum Subcommand {
5050 Convert ( convert:: ConvertSubcommandArgs ) ,
5151}
5252
53- pub fn run_splashsurf ( args : & [ std:: ffi:: OsString ] ) -> Result < ( ) , anyhow:: Error > {
53+ /// A simple on/off switch for command line arguments.
54+ ///
55+ /// For example an argument defined as:
56+ /// ```rust ignore
57+ /// /// Enable the use of double precision for all computations
58+ /// #[arg(
59+ /// long,
60+ /// default_value = "off",
61+ /// value_name = "off|on",
62+ /// ignore_case = true,
63+ /// require_equals = true
64+ /// )]
65+ /// pub double_precision: Switch,
66+ /// ```
67+ /// can be used in the CLI as `--double-precision=on` or `--double-precision=off`.
68+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , clap:: ValueEnum ) ]
69+ pub ( crate ) enum Switch {
70+ Off ,
71+ On ,
72+ }
73+
74+ impl Switch {
75+ pub ( crate ) fn into_bool ( self ) -> bool {
76+ match self {
77+ Switch :: Off => false ,
78+ Switch :: On => true ,
79+ }
80+ }
81+ }
82+
83+ /// Runs the splashsurf CLI with the provided command line arguments.
84+ ///
85+ /// This function behaves like the binary `splashsurf` command line tool including output to stdout and stderr.
86+ /// Note that the first argument is always ignored as it is the binary name when called using `std::env::args()`
87+ /// from the command line:
88+ /// ```
89+ /// splashsurf::cli::run_splashsurf([".", "--version"]);
90+ /// ```
91+ /// If no placeholder for the binary name is provided it will return an error (and print a help message):
92+ /// ```should_panic
93+ /// splashsurf::cli::run_splashsurf(["--version"]);
94+ /// ```
95+ pub fn run_splashsurf < I , T > ( args : I ) -> Result < ( ) , anyhow:: Error >
96+ where
97+ I : IntoIterator < Item = T > ,
98+ T : Into < std:: ffi:: OsString > + Clone ,
99+ {
54100 run_splashsurf_impl ( args) . inspect_err ( logging:: log_error)
55101}
56102
57- fn run_splashsurf_impl ( args : & [ std:: ffi:: OsString ] ) -> Result < ( ) , anyhow:: Error > {
103+ fn run_splashsurf_impl < I , T > ( args : I ) -> Result < ( ) , anyhow:: Error >
104+ where
105+ I : IntoIterator < Item = T > ,
106+ T : Into < std:: ffi:: OsString > + Clone ,
107+ {
58108 let cmd_args = CommandlineArgs :: parse_from ( args) ;
59109
60110 let verbosity = VerbosityLevel :: from ( cmd_args. verbosity ) ;
@@ -125,3 +175,152 @@ impl VerbosityLevel {
125175 }
126176 }
127177}
178+
179+ #[ cfg( test) ]
180+ mod cli_args_tests {
181+ use super :: * ;
182+
183+ #[ test]
184+ fn verify_main_cli ( ) {
185+ use clap:: CommandFactory ;
186+ CommandlineArgs :: command ( ) . debug_assert ( )
187+ }
188+
189+ #[ test]
190+ fn verify_reconstruct_cli ( ) {
191+ use clap:: CommandFactory ;
192+ crate :: reconstruction:: ReconstructSubcommandArgs :: command ( ) . debug_assert ( )
193+ }
194+
195+ #[ test]
196+ fn verify_convert_cli ( ) {
197+ use clap:: CommandFactory ;
198+ crate :: convert:: ConvertSubcommandArgs :: command ( ) . debug_assert ( )
199+ }
200+
201+ #[ test]
202+ fn test_main_cli ( ) {
203+ use clap:: Parser ;
204+
205+ // Display help
206+ assert_eq ! (
207+ CommandlineArgs :: try_parse_from( [ "splashsurf" , "--help" , ] )
208+ . expect_err( "this command is supposed to fail" )
209+ . kind( ) ,
210+ clap:: error:: ErrorKind :: DisplayHelp
211+ ) ;
212+
213+ // Display help, reconstruct
214+ assert_eq ! (
215+ CommandlineArgs :: try_parse_from( [ "splashsurf" , "reconstruct" , "--help" , ] )
216+ . expect_err( "this command is supposed to fail" )
217+ . kind( ) ,
218+ clap:: error:: ErrorKind :: DisplayHelp
219+ ) ;
220+
221+ // Display help, convert
222+ assert_eq ! (
223+ CommandlineArgs :: try_parse_from( [ "splashsurf" , "convert" , "--help" , ] )
224+ . expect_err( "this command is supposed to fail" )
225+ . kind( ) ,
226+ clap:: error:: ErrorKind :: DisplayHelp
227+ ) ;
228+
229+ // Minimum arguments: input file
230+ if let Subcommand :: Reconstruct ( rec_args) = CommandlineArgs :: try_parse_from ( [
231+ "splashsurf" ,
232+ "reconstruct" ,
233+ "test.vtk" ,
234+ "--particle-radius=0.05" ,
235+ "--smoothing-length=3.0" ,
236+ "--cube-size=0.75" ,
237+ ] )
238+ . expect ( "this command is supposed to work" )
239+ . subcommand
240+ {
241+ assert_eq ! (
242+ rec_args. input_file_or_sequence,
243+ std:: path:: PathBuf :: from( "test.vtk" )
244+ ) ;
245+ } ;
246+
247+ // Test on/off switch
248+ if let Subcommand :: Reconstruct ( rec_args) = CommandlineArgs :: try_parse_from ( [
249+ "splashsurf" ,
250+ "reconstruct" ,
251+ "test.vtk" ,
252+ "--particle-radius=0.05" ,
253+ "--smoothing-length=3.0" ,
254+ "--cube-size=0.75" ,
255+ "--normals=on" ,
256+ ] )
257+ . expect ( "this command is supposed to work" )
258+ . subcommand
259+ {
260+ assert_eq ! ( rec_args. normals, Switch :: On ) ;
261+ } ;
262+
263+ if let Subcommand :: Reconstruct ( rec_args) = CommandlineArgs :: try_parse_from ( [
264+ "splashsurf" ,
265+ "reconstruct" ,
266+ "test.vtk" ,
267+ "--particle-radius=0.05" ,
268+ "--smoothing-length=3.0" ,
269+ "--cube-size=0.75" ,
270+ "--normals=off" ,
271+ ] )
272+ . expect ( "this command is supposed to work" )
273+ . subcommand
274+ {
275+ assert_eq ! ( rec_args. normals, Switch :: Off ) ;
276+ } ;
277+
278+ // Test domain min/max: correct values
279+ if let Subcommand :: Reconstruct ( rec_args) = CommandlineArgs :: try_parse_from ( [
280+ "splashsurf" ,
281+ "reconstruct" ,
282+ "test.vtk" ,
283+ "--particle-radius=0.05" ,
284+ "--smoothing-length=3.0" ,
285+ "--cube-size=0.75" ,
286+ "--particle-aabb-min" ,
287+ "-1.0" ,
288+ "1.0" ,
289+ "-1.0" ,
290+ "--particle-aabb-max" ,
291+ "-2.0" ,
292+ "2.0" ,
293+ "-2.0" ,
294+ ] )
295+ . expect ( "this command is supposed to work" )
296+ . subcommand
297+ {
298+ assert_eq ! ( rec_args. particle_aabb_min, Some ( vec![ -1.0 , 1.0 , -1.0 ] ) ) ;
299+ assert_eq ! ( rec_args. particle_aabb_max, Some ( vec![ -2.0 , 2.0 , -2.0 ] ) ) ;
300+ } ;
301+
302+ // Test domain min/max: too many values
303+ assert_eq ! (
304+ CommandlineArgs :: try_parse_from( [
305+ "splashsurf" ,
306+ "reconstruct" ,
307+ "test.vtk" ,
308+ "--particle-radius=0.05" ,
309+ "--smoothing-length=3.0" ,
310+ "--cube-size=0.75" ,
311+ "--particle-aabb-min" ,
312+ "-1.0" ,
313+ "1.0" ,
314+ "-1.0" ,
315+ "2.0" ,
316+ "--particle-aabb-max" ,
317+ "-2.0" ,
318+ "2.0" ,
319+ "-2.0" ,
320+ ] )
321+ . expect_err( "this command is supposed to fail" )
322+ . kind( ) ,
323+ clap:: error:: ErrorKind :: UnknownArgument
324+ ) ;
325+ }
326+ }
0 commit comments