Skip to content

Commit

Permalink
Sun azimuth CLI option.
Browse files Browse the repository at this point in the history
  • Loading branch information
breki committed May 25, 2024
1 parent 0ffc88e commit a7a828b
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 144 deletions.
233 changes: 129 additions & 104 deletions Demeton.Tests/Command line parsing/Parsing a sequence of parameters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,170 +7,195 @@ open Xunit
open Swensen.Unquote
open TestHelp

let someArg argName =
Arg.build argName |> Arg.asFloat 10. |> Arg.toPar
let someArg argName =
Arg.build argName |> Arg.asFloatWithMin 10. |> Arg.toPar

let someOptionalArg argName =
Arg.build argName |> Arg.asFloat 10. |> Arg.optional |> Arg.toPar
let someOptionalArg argName =
Arg.build argName |> Arg.asFloatWithMin 10. |> Arg.optional |> Arg.toPar

let supportedParameters: CommandParameter[] = [|
Switch.build "switch1" |> Switch.toPar
Option.build "option1" |> Option.asInt |> Option.toPar
|]
let supportedParameters: CommandParameter[] =
[| Switch.build "switch1" |> Switch.toPar
Option.build "option1" |> Option.asInt |> Option.toPar |]

[<Fact>]
let ``All command arguments need to be specified before any options and switches``() =
let supportedParameters: CommandParameter[] = [|
Switch.build "switch1" |> Switch.toPar
someArg "arg1"
Option.build "option1" |> Option.toPar
|]

let ``All command arguments need to be specified before any options and switches``
()
=
let supportedParameters: CommandParameter[] =
[| Switch.build "switch1" |> Switch.toPar
someArg "arg1"
Option.build "option1" |> Option.toPar |]

let result = parseParameters [] supportedParameters
test <@ result |> isErrorData
"All command arguments need to be specified before any options and switches."

test
<@
result
|> isErrorData
"All command arguments need to be specified before any options and switches."
@>

[<Fact>]
let ``All mandatory command arguments need to be specified before any non-mandatory ones``() =
let supportedParameters: CommandParameter[] = [|
someOptionalArg "arg1"
someArg "arg2"
|]
let ``All mandatory command arguments need to be specified before any non-mandatory ones``
()
=
let supportedParameters: CommandParameter[] =
[| someOptionalArg "arg1"; someArg "arg2" |]

let result = parseParameters [] supportedParameters
test <@ result |> isErrorData
"All mandatory command arguments need to be specified before any non-mandatory ones."

test
<@
result
|> isErrorData
"All mandatory command arguments need to be specified before any non-mandatory ones."
@>

[<Fact>]
let ``Reports an error if some of the mandatory command arguments are missing and there is a switch after it``() =
let supportedParameters: CommandParameter[] = [|
someArg "arg1"
someArg "arg2"
Switch.build "switch1" |> Switch.toPar
|]

let ``Reports an error if some of the mandatory command arguments are missing and there is a switch after it``
()
=
let supportedParameters: CommandParameter[] =
[| someArg "arg1"
someArg "arg2"
Switch.build "switch1" |> Switch.toPar |]

let args = [ "123."; "--switch1" ]
let result = parseParameters args supportedParameters
test <@ result |> isErrorData
"<arg2> argument's value is missing."
@>
test <@ result |> isErrorData "<arg2> argument's value is missing." @>

[<Fact>]
let ``Reports an error if some of the mandatory command arguments are missing and there are no more args``() =
let supportedParameters: CommandParameter[] = [|
someArg "arg1"
someArg "arg2"
Switch.build "switch1" |> Switch.toPar
|]

let ``Reports an error if some of the mandatory command arguments are missing and there are no more args``
()
=
let supportedParameters: CommandParameter[] =
[| someArg "arg1"
someArg "arg2"
Switch.build "switch1" |> Switch.toPar |]

let args = [ "123." ]
let result = parseParameters args supportedParameters
test <@ result |> isErrorData
"<arg2> argument's value is missing."
@>
test <@ result |> isErrorData "<arg2> argument's value is missing." @>

[<Fact>]
let ``Allows an optional command argument to not be specified (case when there are no parameters left)``() =
let supportedParameters: CommandParameter[] = [|
someArg "arg1"
someOptionalArg "arg2"
|]
let ``Allows an optional command argument to not be specified (case when there are no parameters left)``
()
=
let supportedParameters: CommandParameter[] =
[| someArg "arg1"; someOptionalArg "arg2" |]

let args = [ "123" ]

let result =
parseParameters args supportedParameters
test <@ result
|> isOkValue ([ ParsedArg { Name = "arg1"; Value = 123. } ]) @>
let result = parseParameters args supportedParameters

test <@ result |> isOkValue [ ParsedArg { Name = "arg1"; Value = 123. } ] @>

[<Fact>]
let ``Allows an optional command argument to not be specified (case when there follows an option)``() =
let supportedParameters: CommandParameter[] = [|
someArg "arg1"
someOptionalArg "arg2"
Switch.build "switch1" |> Switch.toPar
|]
let ``Allows an optional command argument to not be specified (case when there follows an option)``
()
=
let supportedParameters: CommandParameter[] =
[| someArg "arg1"
someOptionalArg "arg2"
Switch.build "switch1" |> Switch.toPar |]

let args = [ "123"; "--switch1" ]

let result = parseParameters args supportedParameters
test <@ result
|> isOkValue ([
ParsedArg { Name = "arg1"; Value = 123. }
ParsedSwitch { Name = "switch1" }
]) @>

test
<@
result
|> isOkValue
[ ParsedArg { Name = "arg1"; Value = 123. }
ParsedSwitch { Name = "switch1" } ]
@>

[<Fact>]
let ``Reports an error if command argument's value is invalid``() =
let supportedParameters: CommandParameter[] = [|
someArg "arg1"
|]

let ``Reports an error if command argument's value is invalid`` () =
let supportedParameters: CommandParameter[] = [| someArg "arg1" |]

let args = [ "dsd" ]
let result = parseParameters args supportedParameters
test <@ result |> isErrorData
"<arg1> argument's value is invalid, it has to be a numeric value >= 10."

test
<@
result
|> isErrorData
"<arg1> argument's value is invalid, it has to be a numeric value >= 10."
@>

[<Fact>]
let ``If option or switch name does not start with prefix, returns an error``() =
let ``If option or switch name does not start with prefix, returns an error``
()
=
let args = [ "weird" ]

let result = parseParameters args supportedParameters
test <@ result |> isErrorData "Unrecognized parameter 'weird'." @>

[<Fact>]
let ``If option or switch is not among supported ones, returns an error``() =
let ``If option or switch is not among supported ones, returns an error`` () =
let args = [ "--par3" ]

let result = parseParameters args supportedParameters
test <@ result |> isErrorData "Unrecognized parameter 'par3'." @>

[<Fact>]
let ``If parameter is a supported switch, record it in parsed parameters list``() =
let ``If parameter is a supported switch, record it in parsed parameters list``
()
=
let args = [ "--switch1" ]

let result = parseParameters args supportedParameters
test <@ result
|> isOkValue ([ ParsedSwitch { Name = "switch1" } ]) @>

test <@ result |> isOkValue [ ParsedSwitch { Name = "switch1" } ] @>

[<Fact>]
let ``If parameter is a supported option, record it and its value in parsed parameters list``() =
let ``If parameter is a supported option, record it and its value in parsed parameters list``
()
=
let args = [ "--option1"; "123" ]

let result = parseParameters args supportedParameters
test <@ result
|> isOkValue ([ ParsedOption { Name = "option1"; Value = 123 } ]) @>


test
<@
result
|> isOkValue [ ParsedOption { Name = "option1"; Value = 123 } ]
@>

[<Fact>]
let ``Supports parsing of series of parameters (case 1)``() =
let pars = [|
someArg "arg1"
someOptionalArg "arg2"
Switch.build "switch1" |> Switch.toPar
Option.build "option1" |> Option.asInt |> Option.toPar
|]
let ``Supports parsing of series of parameters (case 1)`` () =
let pars =
[| someArg "arg1"
someOptionalArg "arg2"
Switch.build "switch1" |> Switch.toPar
Option.build "option1" |> Option.asInt |> Option.toPar |]

let args = [ "123"; "234"; "--switch1"; "--option1"; "123" ]

let result = parseParameters args pars
test <@ result
|> isOkValue ([
ParsedArg { Name = "arg1"; Value = 123. }
ParsedArg { Name = "arg2"; Value = 234. }
ParsedSwitch { Name = "switch1" }
ParsedOption { Name = "option1"; Value = 123 }
]) @>


test
<@
result
|> isOkValue
[ ParsedArg { Name = "arg1"; Value = 123. }
ParsedArg { Name = "arg2"; Value = 234. }
ParsedSwitch { Name = "switch1" }
ParsedOption { Name = "option1"; Value = 123 } ]
@>

[<Fact>]
let ``Supports parsing of series of parameters (case 2)``() =
let ``Supports parsing of series of parameters (case 2)`` () =
let args = [ "--switch1"; "--option1"; "123" ]

let result = parseParameters args supportedParameters
test <@ result
|> isOkValue ([
ParsedSwitch { Name = "switch1" }
ParsedOption { Name = "option1"; Value = 123 }
]) @>

test
<@
result
|> isOkValue
[ ParsedSwitch { Name = "switch1" }
ParsedOption { Name = "option1"; Value = 123 } ]
@>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open Demeton.Commands

open Demeton.Shaders
open Xunit
open Swensen.Unquote
open TestHelp
Expand All @@ -17,6 +18,7 @@ let ``Geo area needed is calculated correctly`` () =
Dpi = 245
IgorHillshadingIntensity = 1.
SlopeShadingIntensity = 1.
SunAzimuth = IgorHillshader.DefaultSunAzimuth
WaterBodiesColor = "#49C8FF" |> Png.Rgba8Bit.parseColorHexValue
LocalCacheDir = TileShadeCommand.DefaultLocalCacheDir
OutputDir = TileShadeCommand.DefaultOutputDir }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open Demeton.Commands

open Demeton.Shaders
open Xunit

[<Fact>]
Expand All @@ -15,6 +16,7 @@ let ``Projection is created`` () =
Dpi = 245
IgorHillshadingIntensity = 1.
SlopeShadingIntensity = 1.
SunAzimuth = IgorHillshader.DefaultSunAzimuth
WaterBodiesColor = "#49C8FF" |> Png.Rgba8Bit.parseColorHexValue
LocalCacheDir = TileShadeCommand.DefaultLocalCacheDir
OutputDir = TileShadeCommand.DefaultOutputDir }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open Demeton.Commands

open Demeton.Shaders
open Xunit

[<Fact>]
Expand All @@ -16,6 +17,7 @@ let ``run command`` () =
Dpi = 245
IgorHillshadingIntensity = 1.
SlopeShadingIntensity = 1.
SunAzimuth = IgorHillshader.DefaultSunAzimuth
WaterBodiesColor = "#49C8FF" |> Png.Rgba8Bit.parseColorHexValue
LocalCacheDir = TileShadeCommand.DefaultLocalCacheDir
OutputDir = TileShadeCommand.DefaultOutputDir }
Expand Down
2 changes: 2 additions & 0 deletions Demeton.Tests/todo.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module Demeton.Tests.todo

// todo 0: option to name the output file

// todo 6: limit the command to stick to the SRTM level 0

// todo 100: update shading docs now that we have added an array of fetchers
Expand Down
8 changes: 6 additions & 2 deletions Demeton/CommandLine/Arg.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ let build name =
Example = None
Parser = fun value -> OkValue value }

let asFloat minValue (arg: CommandArg) =
let asFloat (arg: CommandArg) =
{ arg with
Parser = (ValueParsers.parseFloat minValue) }
Parser = (ValueParsers.parseFloat None) }

let asFloatWithMin minValue (arg: CommandArg) =
{ arg with
Parser = (ValueParsers.parseFloat (Some minValue)) }

let asPositiveInt (arg: CommandArg) =
{ arg with
Expand Down
12 changes: 9 additions & 3 deletions Demeton/CommandLine/Option.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ let build name : CommandOption =
let desc description (opt: CommandOption) =
{ opt with Description = description }

let asFloat minValue (opt: CommandOption) =
let asFloat (opt: CommandOption) =
{ opt with
Parser = (ValueParsers.parseFloat minValue)
Parser = (ValueParsers.parseFloat None)
ValuePlaceholder = "number"
Format = "real number" }

let asFloatWithMin minValue (opt: CommandOption) =
{ opt with
Parser = (ValueParsers.parseFloat (Some minValue))
ValuePlaceholder = "number"
Format = sprintf "real number >= %g" minValue }

Expand Down Expand Up @@ -47,7 +53,7 @@ let asPositiveFloat (opt: CommandOption) =

let asNonNegativeFloat (opt: CommandOption) =
{ opt with
Parser = (ValueParsers.parseFloat 0.)
Parser = (ValueParsers.parseFloat (Some 0.))
ValuePlaceholder = "number"
Format = "non-negative real number" }

Expand Down
Loading

0 comments on commit a7a828b

Please sign in to comment.