diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b49242c9..e1920104 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,7 @@ ### 6.2.0 * Add `ParseResults.ProgramName` [#229](https://github.com/fsprojects/Argu/pull/229) +* Add `ParseResults.GetResult(expr, 'Field -> 'R): 'R` as alias for `PostProcessResult`, `ParseResults.GetResults(expr, 'Field -> 'R): 'R list` as alias for `PostProcessResults`, `ParseResults.TryGetResult(expr, 'Field -> 'R): 'R option` as alias for `TryPostProcessResult` [#230](https://github.com/fsprojects/Argu/pull/230) +* Add `ParseResults.GetResult(expr, defThunk: unit -> 'Field, parse: 'Field -> 'R): 'R` and `ParseResults.GetResults(expr, def: 'Field, parse: 'Field -> 'R): 'R` that trap parse exceptions, mapping them to parse exit messages [#230](https://github.com/fsprojects/Argu/pull/230) ### 6.1.5 * Fix the regression of the [#127](https://github.com/fsprojects/Argu/pull/127) merged in 6.1.2 and fix Mandatory arguments in nested subcommands. [#220](https://github.com/fsprojects/Argu/issues/220) [@fpellet](https://github.com/fpellet) diff --git a/docs/index.fsx b/docs/index.fsx index 6278af4e..ae017c69 100644 --- a/docs/index.fsx +++ b/docs/index.fsx @@ -1,20 +1,20 @@ (*** hide ***) -// This block of code is omitted in the generated HTML documentation. Use +// This block of code is omitted in the generated HTML documentation. Use // it to define helpers that you do not want to show in the documentation. #I "../src/Argu/bin/Release/netstandard2.0" #r "Argu.dll" -open System open Argu type Args = - | Working_Directory of path:string - | Listener of host:string * port:int - | Log_Level of level:int + | Working_Directory of path: string + | Listener of host: string * port: int + | Log_Level of level: int | Detach with interface IArgParserTemplate with - member _.Usage = "" + member _.Usage = + "(see the Tutorial for how this should be written)" (** @@ -35,22 +35,22 @@ It can be installed using NuGet. ## Basic Concepts -The library is based on the simple observation that -configuration parameters can be naturally described using discriminated unions. +The library is based on the simple observation that +configuration parameters can be naturally described using discriminated unions. For instance: *) type Arguments = - | Working_Directory of path:string - | Listener of host:string * port:int - | Log_Level of level:int + | Working_Directory of path: string + | Listener of host: string * port: int + | Log_Level of level: int | Detach (** -Argu takes such discriminated unions and generates -a corresponding argument parsing scheme. +Argu takes such discriminated unions and generates +a corresponding argument parsing scheme. For example, a parser generated from the above template would take the following command line input @@ -60,7 +60,7 @@ take the following command line input and parse it into the list *) -[ Working_Directory "/var/run" ; Listener("localhost", 8080) ; Detach ] +[ Working_Directory "/var/run"; Listener("localhost", 8080); Detach ] (** @@ -82,36 +82,38 @@ let argv = [| "--log-level"; "3" |] let reader = EnvironmentVariableConfigurationReader() :> IConfigurationReader let parser = ArgumentParser.Create(programName = "rutta") // pass the reader to the Parse call -let results = parser.Parse(argv, configurationReader=reader) +let results = parser.Parse(argv, configurationReader = reader) (** ## Who uses Argu? * [MBrace](http://m-brace.net/) - + * [FAKE](http://fsharp.github.io/FAKE/) - + * [Paket](http://fsprojects.github.io/Paket/) - + * [Logary](https://logary.tech) + * [Equinox + Propulsion](https://github.com/jet/Equinox) + ## Documentation * [Tutorial](tutorial.html) A short walkthrough of Argu features. - * [API Reference](reference/index.html) contains automatically generated documentation for all types, + * [API Reference](reference/index.html) contains automatically generated documentation for all types, modules and functions in the library. ## Contributing and copyright -The project is hosted on [GitHub][gh] where you can [report issues][issues], fork +The project is hosted on [GitHub][gh] where you can [report issues][issues], fork the project and submit pull requests. -The library is available under the MIT License. -For more information see the [License file][license] in the GitHub repository. +The library is available under the MIT License. +For more information see the [License file][license] in the GitHub repository. [gh]: https://github.com/fsprojects/Argu [issues]: https://github.com/fsprojects/Argu/issues - [license]: https://github.com/fsprojects/Argu/blob/master/License.md + [license]: https://github.com/fsprojects/Argu/blob/master/LICENSE.md *) diff --git a/docs/perf.fsx b/docs/perf.fsx index 039b2758..c2e2b9cd 100644 --- a/docs/perf.fsx +++ b/docs/perf.fsx @@ -33,7 +33,7 @@ By default Argu checks that the discriminated union is well formed and only cont This incur both the cost of the checks themselves but also the cost of materializing the whole argument graph that could be loaded only if the corresponding arguments are used. -This check can easilly be bypassed either only in release builds : +This check can easily be bypassed either only in release builds : *) diff --git a/docs/tutorial.fsx b/docs/tutorial.fsx index 697881e1..323badba 100644 --- a/docs/tutorial.fsx +++ b/docs/tutorial.fsx @@ -19,9 +19,9 @@ For instance: *) type Arguments = - | Working_Directory of path:string - | Listener of host:string * port:int - | Log_Level of level:int + | Working_Directory of path: string + | Listener of host: string * port: int + | Log_Level of level: int | Detach (** @@ -64,11 +64,11 @@ A minimal parser based on the above example can be created as follows: open Argu type CliArguments = - | Working_Directory of path:string - | Listener of host:string * port:int - | Data of base64:byte[] - | Port of tcp_port:int - | Log_Level of level:int + | Working_Directory of path: string + | Listener of host: string * port: int + | Data of base64: byte[] + | Port of tcp_port: int + | Log_Level of level: int | Detach interface IArgParserTemplate with @@ -79,7 +79,7 @@ type CliArguments = | Data _ -> "binary data in base64 encoding." | Port _ -> "specify a primary port." | Log_Level _ -> "set the log level." - | Detach _ -> "detach daemon from console." + | Detach -> "detach daemon from console." (** We extract the argument parser from the template using the following command: *) @@ -111,11 +111,11 @@ To parse a command line input: *) -let results = parser.Parse [| "--detach" ; "--listener" ; "localhost" ; "8080" |] +let results = parser.Parse [| "--detach"; "--listener"; "localhost" ; "8080" |] (** which gives *) -let all = results.GetAllResults() // [ Detach ; Listener ("localhost", 8080) ] +let all = results.GetAllResults() // [ Detach; Listener ("localhost", 8080) ] (** @@ -132,7 +132,7 @@ let listener = results.GetResults Listener (** The following methods return the last observed result for given argument case *) let dataOpt = results.TryGetResult Data -let logLevel = results.GetResult (Log_Level, defaultValue = 0) +let logLevel = results.GetResult(Log_Level, defaultValue = 0) (** @@ -147,12 +147,12 @@ can be customized by fixing attributes to the union cases: *) type Argument = - | [] Cache_Path of path:string - | [] Connection_String of conn:string - | [] Listener of host:string * port:int - | [] Assignment of value:string - | [] AssignmentOrSpace of value:string - | [] Primary_Port of tcp_port:int + | [] Cache_Path of path: string + | [] Connection_String of conn: string + | [] Listener of host: string * port: int + | [] Assignment of value: string + | [] AssignmentOrSpace of value: string + | [] Primary_Port of tcp_port: int (** @@ -165,7 +165,7 @@ In this case, * [`AltCommandLine`](reference/argu-arguattributes-altcommandlineattribute.html): specifies an alternative command line switch. * [`EqualsAssignment`](reference/argu-arguattributes-equalsassignmentattribute.html) : enforces `--assignment=value` and `--assignment key=value` CLI syntax. - + * [`EqualsAssignmentOrSpaced`](reference/argu-arguattributes-equalsassignmentorspacedattribute.html) : enforces `--assignment=value` and `--assignment value` CLI syntax. * [`Unique`](reference/argu-arguattributes-uniqueattribute.html) : parser will fail if CLI provides this argument more than once. @@ -202,8 +202,8 @@ Additionally, it is possible to specify argument parameters that are either opti *) type VariadicParameters = - | [] Enable_Logging of path:string option - | Tcp_Ports of port:int list + | [] Enable_Logging of path: string option + | Tcp_Ports of port: int list (** @@ -261,7 +261,7 @@ These arguments can be passed without the need to specify a switch identifier. type WGetArguments = | Quiet | No_Check_Certificate - | [] Urls of url:string list + | [] Urls of url: string list (** @@ -306,7 +306,7 @@ type CleanArgs = and CommitArgs = | Amend | [] Patch - | [] Message of msg:string + | [] Message of msg: string interface IArgParserTemplate with member this.Usage = @@ -339,9 +339,8 @@ and the following console app entrypoint let main argv = try parser.ParseCommandLine(inputs = argv, raiseOnUsage = true) |> ignore - with e -> - printfn "%s" e.Message - 0 + 0 + with :? ArguParseException as e -> eprintfn "%s" e.Message; 1 (** @@ -406,7 +405,9 @@ which would make the aforementioned syntax valid. It should be noted here that arbitrary unions are not supported by the parser. Union cases can only contain fields of primitive types. This means that user-defined parsers are not supported. For configuration inputs that are non-trivial, -a post-process facility is provided. +a post-process facility is provided + +NOTE prior to version 6.2.0, these methods were called PostProcessResult, PostProcessResults, TryPostProcessResult *) let parsePort p = @@ -414,7 +415,7 @@ let parsePort p = failwith "invalid port number." else p -let ports = results.PostProcessResults (<@ Port @>, parsePort) +let ports = results.GetResults(Port, parsePort) (** @@ -427,7 +428,7 @@ Argu is convenient when it comes to automated process spawning: open System.Diagnostics -let arguments = parser.PrintCommandLineArgumentsFlat [ Port 42 ; Working_Directory "temp" ] +let arguments = parser.PrintCommandLineArgumentsFlat [ Port 42; Working_Directory "temp" ] Process.Start("foo.exe", arguments) @@ -435,7 +436,7 @@ Process.Start("foo.exe", arguments) It can also be used to auto-generate a suitable `AppSettings` configuration file: *) -let xml = parser.PrintAppSettingsArguments [ Port 42 ; Working_Directory "/tmp" ] +let xml = parser.PrintAppSettingsArguments [ Port 42; Working_Directory "/tmp" ] (** which would yield the following: diff --git a/src/Argu/ParseResults.fs b/src/Argu/ParseResults.fs index c4ebfd8f..6a900dd1 100644 --- a/src/Argu/ParseResults.fs +++ b/src/Argu/ParseResults.fs @@ -75,8 +75,8 @@ type ParseResults<[]'Template wh /// Query parse results for argument with parameters. /// The name of the parameter, expressed as quotation of DU constructor. /// Optional source restriction: AppSettings or CommandLine. - member _.GetResults ([] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields list = - expr |> getResults source |> Seq.map (fun r -> r.FieldContents :?> 'Fields) |> Seq.toList + member _.GetResults ([] expr : Expr<'Field -> 'Template>, ?source : ParseSource) : 'Field list = + expr |> getResults source |> Seq.map (fun r -> r.FieldContents :?> 'Field) |> Seq.toList /// Gets all parse results. /// Optional source restriction: AppSettings or CommandLine. @@ -94,8 +94,8 @@ type ParseResults<[]'Template wh /// Command line parameters have precedence over AppSettings parameters. /// The name of the parameter, expressed as quotation of DU constructor. /// Optional source restriction: AppSettings or CommandLine. - member _.TryGetResult ([] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields option = - expr |> tryGetResult source |> Option.map (fun r -> r.FieldContents :?> 'Fields) + member _.TryGetResult ([] expr : Expr<'Field -> 'Template>, ?source : ParseSource) : 'Field option = + expr |> tryGetResult source |> Option.map (fun r -> r.FieldContents :?> 'Field) /// Returns the *last* specified parameter of given type. /// Command line parameters have precedence over AppSettings parameters. @@ -112,12 +112,13 @@ type ParseResults<[]'Template wh /// The name of the parameter, expressed as quotation of DU constructor. /// Return this if no parameter of specific kind has been specified. /// Optional source restriction: AppSettings or CommandLine. - member s.GetResult ([] expr : Expr<'Fields -> 'Template>, ?defaultValue : 'Fields, ?source : ParseSource) : 'Fields = + member s.GetResult ([] expr : Expr<'Field -> 'Template>, ?defaultValue : 'Field, ?source : ParseSource) : 'Field = match defaultValue with - | None -> let r = getResult source expr in r.FieldContents :?> 'Fields - | Some def -> defaultArg (s.TryGetResult(expr, ?source = source)) def + | None -> let r = getResult source expr in r.FieldContents :?> 'Field + | Some def -> s.TryGetResult(expr, ?source = source) |> Option.defaultValue def - /// Returns the *last* specified parameter of given type. + /// Returns the *last* specified parameter of given type, + /// trapping exceptions from the defThunk used if no argument has been supplied. /// Command line parameters have precedence over AppSettings parameters. /// The name of the parameter, expressed as quotation of DU constructor. /// Function used to default if no parameter has been specified. @@ -125,10 +126,40 @@ type ParseResults<[]'Template wh /// Optional source restriction: AppSettings or CommandLine. /// The error code to be returned. /// Print usage together with error message. - member s.GetResult([] expr : Expr<'Fields -> 'Template>, defThunk : unit -> 'Fields, ?source : ParseSource, ?errorCode, ?showUsage) : 'Fields = - match s.TryGetResult(expr, ?source = source) with + member r.GetResult([] expr : Expr<'Field -> 'Template>, defThunk : unit -> 'Field, ?source : ParseSource, ?errorCode, ?showUsage) : 'Field = + match r.TryGetResult(expr, ?source = source) with | Some x -> x - | None -> s.Catch(defThunk, ?errorCode = errorCode, ?showUsage = showUsage) + | None -> r.Catch(defThunk, ?errorCode = errorCode, ?showUsage = showUsage) + + /// Returns the *last* specified parameter of given type, + /// trapping exceptions from the defThunk used if no argument has been supplied. + /// Results are passed to a post-processing function parse that is error handled by the parser. + /// Command line parameters have precedence over AppSettings parameters. + /// The name of the parameter, expressed as quotation of DU constructor. + /// Function used to default if no parameter has been specified. + /// Any resulting Exception will be trapped, and the Exception's .Message will be used as the Failure Message as per Raise and Catch. + /// The post-processing parser. + /// Optional source restriction: AppSettings or CommandLine. + /// The error code to be returned. + /// Print usage together with error message. Defaults to true + member r.GetResult([] expr: Expr<'Field -> 'Template>, defThunk: unit -> 'Field, parser: 'Field -> 'R, ?source: ParseSource, ?errorCode, ?showUsage) : 'R = + match expr |> tryGetResult source |> Option.map (parseResult parser) with + | Some x -> x + | None -> r.Catch(defThunk >> parser, ?errorCode = errorCode, ?showUsage = showUsage) + + /// Returns the *last* specified parameter of given type. + /// Results are passed to a post-processing function parse that is error handled by the parser. + /// Command line parameters have precedence over AppSettings parameters. + /// The name of the parameter, expressed as quotation of DU constructor. + /// Use this if no parameter of specific kind has been specified. + /// The post-processing parser. + /// Optional source restriction: AppSettings or CommandLine. + /// The error code to be returned. + /// Print usage together with error message. + member r.GetResult([] expr: Expr<'Field -> 'Template>, defaultValue: 'Field, parser: 'Field -> 'R, ?source, ?errorCode : ErrorCode, ?showUsage : bool) : 'R = + match expr |> tryGetResult source |> Option.map (parseResult parser) with + | Some x -> x + | None -> r.Catch((fun () -> parser defaultValue), ?errorCode = errorCode, ?showUsage = showUsage) /// Checks if parameter of specific kind has been specified. /// The name of the parameter, expressed as quotation of DU constructor. @@ -137,7 +168,7 @@ type ParseResults<[]'Template wh /// Checks if parameter of specific kind has been specified. /// The name of the parameter, expressed as quotation of DU constructor. /// Optional source restriction: AppSettings or CommandLine. - member _.Contains ([] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : bool = containsResult source expr + member _.Contains ([] expr : Expr<'Field -> 'Template>, ?source : ParseSource) : bool = containsResult source expr /// Raise an error through the argument parser's exiter mechanism. Display usage optionally. /// The error message to be displayed. @@ -169,6 +200,7 @@ type ParseResults<[]'Template wh /// The name of the parameter, expressed as quotation of DU constructor. /// The post-processing parser. /// Optional source restriction: AppSettings or CommandLine. + // TODO for V7 [] member r.PostProcessResult ([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R = expr |> getResult source |> parseResult parser @@ -179,6 +211,7 @@ type ParseResults<[]'Template wh /// The name of the parameter, expressed as quotation of DU constructor. /// The post-processing parser. /// Optional source restriction: AppSettings or CommandLine. + // TODO for V7 [] member r.PostProcessResults ([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R list = expr |> getResults source |> Seq.map (parseResult parser) |> Seq.toList @@ -189,9 +222,40 @@ type ParseResults<[]'Template wh /// The name of the parameter, expressed as quotation of DU constructor. /// The post-processing parser. /// Optional source restriction: AppSettings or CommandLine. + // TODO for V7 [] member r.TryPostProcessResult ([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option = expr |> tryGetResult source |> Option.map (parseResult parser) + /// Returns the *last* specified parameter of given type. + /// Command line parameters have precedence over AppSettings parameters. + /// Results are passed to a post-processing function that is error handled by the parser. + /// + /// The name of the parameter, expressed as quotation of DU constructor. + /// The post-processing parser. + /// Optional source restriction: AppSettings or CommandLine. + member r.GetResult([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R = + expr |> getResult source |> parseResult parser + + /// Query parse results for given argument kind. + /// Command line parameters have precedence over AppSettings parameters. + /// Results are passed to a post-processing function that is error handled by the parser. + /// + /// The name of the parameter, expressed as quotation of DU constructor. + /// The post-processing parser. + /// Optional source restriction: AppSettings or CommandLine. + member r.GetResults([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R list = + expr |> getResults source |> Seq.map (parseResult parser) |> Seq.toList + + /// Returns the *last* specified parameter of given type. + /// Command line parameters have precedence over AppSettings parameters. + /// Results are passed to a post-processing function that is error handled by the parser. + /// + /// The name of the parameter, expressed as quotation of DU constructor. + /// The post-processing parser. + /// Optional source restriction: AppSettings or CommandLine. + member r.TryGetResult([] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option = + expr |> tryGetResult source |> Option.map (parseResult parser) + /// /// Iterates through *all* parse results for a given argument kind. /// Command line parameters have precedence over AppSettings parameters. @@ -239,30 +303,30 @@ type ParseResults<[]'Template wh // used by StructuredFormatDisplay attribute member private r.StructuredFormatDisplay = r.ToString() - + // used by EqualityConditionalOn attribute // used by ComparisonConditionalOn attribute member val private CachedAllResults = lazy (getAllResults None) with get // used by EqualityConditionalOn attribute - override r.Equals (other : obj) = + override r.Equals (other : obj) = match other with - | :? ParseResults<'Template> as other -> - Unchecked.equals + | :? ParseResults<'Template> as other -> + Unchecked.equals r.CachedAllResults.Value other.CachedAllResults.Value | _ -> false // used by EqualityConditionalOn attribute - override r.GetHashCode () = + override r.GetHashCode () = Unchecked.hash r.CachedAllResults.Value - + // used by ComparisonConditionalOn attribute - interface System.IComparable with + interface System.IComparable with member r.CompareTo other = match other with - | :? ParseResults<'Template> as other -> - Unchecked.compare - r.CachedAllResults.Value + | :? ParseResults<'Template> as other -> + Unchecked.compare + r.CachedAllResults.Value other.CachedAllResults.Value | _ -> invalidArg "other" "cannot compare values of different types" diff --git a/tests/Argu.Tests/Tests.fs b/tests/Argu.Tests/Tests.fs index d46f729a..94b3d3df 100644 --- a/tests/Argu.Tests/Tests.fs +++ b/tests/Argu.Tests/Tests.fs @@ -187,7 +187,7 @@ module ``Argu Tests Main List`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @> test <@ results.GetResults <@ Log_Level @> = [2] @> - test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> + test <@ results.GetResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> [] let ``Simple AppSettings parsing`` () = @@ -203,7 +203,7 @@ module ``Argu Tests Main List`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @> test <@ results.GetResults <@ Log_Level @> = [2] @> - test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> + test <@ results.GetResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> [] let ``Simple AppSettings contains usage comments`` () = @@ -423,7 +423,7 @@ module ``Argu Tests Main List`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @> test <@ results.GetResults Log_Level = [2] @> - test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> + test <@ results.GetResult(Log_Level, fun x -> x + 1) = 3 @> [] let ``Fail on misplaced First parameter`` () = @@ -980,7 +980,7 @@ module ``Argu Tests Main Primitive`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @> test <@ results.GetResults <@ Log_Level @> = [2] @> - test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> + test <@ results.GetResult(<@ Log_Level @>, fun x -> x + 1) = 3 @> [] let ``Help String`` () = @@ -1005,7 +1005,7 @@ module ``Argu Tests Main Primitive`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @> test <@ results.GetResults Log_Level = [2] @> - test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @> + test <@ results.GetResult(<@ Log_Level @>, fun x -> x + 1) = 3 @> [] let ``Unrecognized CLI params`` () = @@ -1022,13 +1022,48 @@ module ``Argu Tests Main Primitive`` = test <@ results.Contains <@ Detach @> @> test <@ results.GetResult <@ Main @> = "main" @> - [] - let ``Trap defaulting function exceptions`` () = + module ``Traps for defaulting and or post-processing functions`` = let results = parser.ParseCommandLine [| "--mandatory-arg" ; "true"; "command" |] - let defThunk (): string = failwith "Defaulting Failed" - raisesWith - <@ results.GetResult(Working_Directory, defThunk, showUsage = false) @> - <| fun e -> <@ e.Message = "Defaulting Failed" && e.ErrorCode = ErrorCode.PostProcess @> - raisesWith - <@ results.GetResult(Working_Directory, defThunk) @> - (fun e -> <@ e.Message.StartsWith "Defaulting Failed" && e.Message.Contains "--working-directory" @>) + + [] + let ``Trap defaulting function exceptions`` () = + let failingDefThunk (): string = failwith "Defaulting Failed" + raisesWith + <@ results.GetResult(Working_Directory, failingDefThunk, showUsage = false) @> + <| fun e -> <@ e.Message = "Defaulting Failed" && e.ErrorCode = ErrorCode.PostProcess @> + raisesWith + <@ results.GetResult(Working_Directory, failingDefThunk) @> + (fun e -> <@ e.Message.StartsWith "Defaulting Failed" && e.Message.Contains "--working-directory" @>) + + [] + let ``Trap defaulting function exceptions (for overloads with parse functions)`` () = + let parser (_ : string): string = failwith "should not be triggered" + let failingDefThunk (): string = failwith "Defaulting Failed" + raisesWith + <@ results.GetResult(Working_Directory, failingDefThunk, parser, showUsage = false) @> + <| fun e -> <@ e.Message = "Defaulting Failed" && e.ErrorCode = ErrorCode.PostProcess @> + raisesWith + <@ results.GetResult(Working_Directory, failingDefThunk, parser) @> + (fun e -> <@ e.Message.StartsWith "Defaulting Failed" && e.Message.Contains "--working-directory" @>) + + [] + let ``Trap post processing exceptions for GetResult overloads with defaulting functions`` () = + let parser value: string = if value = "default" then failwith "Parse Failed" else failwith "unexpected" + let okDefThunk (): string = "default" + raisesWith + <@ results.GetResult(Working_Directory, okDefThunk, parser, showUsage = false) @> + <| fun e -> <@ e.Message = "Parse Failed" && e.ErrorCode = ErrorCode.PostProcess @> + raisesWith + <@ results.GetResult(Working_Directory, okDefThunk, parser) @> + (fun e -> <@ e.Message.StartsWith "Parse Failed" && e.Message.Contains "--working-directory" @>) + + [] + let ``Trap post processing exceptions for GetResult overloads with default values`` () = + let def: string = "default" + let parser value: string = if value = "default" then failwith "Parse Failed" else failwith "unexpected" + raisesWith + <@ results.GetResult(Working_Directory, def, parser, showUsage = false) @> + <| fun e -> <@ e.Message = "Parse Failed" && e.ErrorCode = ErrorCode.PostProcess @> + raisesWith + <@ results.GetResult(Working_Directory, def, parser) @> + (fun e -> <@ e.Message.StartsWith "Parse Failed" && e.Message.Contains "--working-directory" @>)