namespace TweetTest.Data.CommandLineArgs open Xunit open TweetDuck.Data type _TestData = static member empty with get() = CommandLineArgs() static member flags with get() = let args = CommandLineArgs() args.AddFlag("flag1") args.AddFlag("flag2") args.AddFlag("flag3") args static member values with get() = let args = CommandLineArgs() args.SetValue("val1", "hello") args.SetValue("val2", "world") args static member mixed with get() = let args = CommandLineArgs() args.AddFlag("flag1") args.AddFlag("flag2") args.AddFlag("flag3") args.SetValue("val1", "hello") args.SetValue("val2", "world") args static member duplicate with get() = let args = CommandLineArgs() args.AddFlag("duplicate") args.SetValue("duplicate", "value") args module Count = [<Fact>] let ``counts nothing correctly`` () = Assert.Equal(0, _TestData.empty.Count) [<Fact>] let ``counts flags correctly`` () = Assert.Equal(3, _TestData.flags.Count) [<Fact>] let ``counts values correctly`` () = Assert.Equal(2, _TestData.values.Count) [<Fact>] let ``counts mixed flags and values correctly`` () = Assert.Equal(5, _TestData.mixed.Count) module Flags = [<Theory>] [<InlineData("flag1")>] [<InlineData("flag2")>] [<InlineData("flag3")>] let ``HasFlag returns false if flag is missing`` (flag: string) = Assert.False(_TestData.empty.HasFlag(flag)) Assert.False(_TestData.values.HasFlag(flag)) [<Theory>] [<InlineData("val1")>] [<InlineData("val2")>] let ``HasFlag returns false if the name only specifies a key`` (flag: string) = Assert.False(_TestData.values.HasFlag(flag)) [<Fact>] let ``HasFlag returns true if the name specifies both a flag and a value key`` () = Assert.True(_TestData.duplicate.HasFlag("duplicate")) [<Theory>] [<InlineData("flag1")>] [<InlineData("flag2")>] [<InlineData("flag3")>] let ``HasFlag returns true if flag is present`` (flag: string) = Assert.True(_TestData.flags.HasFlag(flag)) [<Theory>] [<InlineData("FLAG1")>] [<InlineData("FlAg1")>] let ``HasFlag is case-insensitive`` (flag: string) = Assert.True(_TestData.flags.HasFlag(flag)) [<Fact>] let ``AddFlag adds new flag`` () = let args = _TestData.flags args.AddFlag("flag4") Assert.Equal(4, args.Count) Assert.True(args.HasFlag("flag4")) [<Fact>] let ``AddFlag does nothing if flag is already present`` () = let args = _TestData.flags args.AddFlag("flag1") Assert.Equal(3, args.Count) [<Theory>] [<InlineData("flag1")>] [<InlineData("flag2")>] [<InlineData("flag3")>] let ``RemoveFlag removes existing flag`` (flag: string) = let args = _TestData.flags args.RemoveFlag(flag) Assert.Equal(2, args.Count) Assert.False(args.HasFlag(flag)) [<Theory>] [<InlineData("FLAG1")>] [<InlineData("FlAg1")>] let ``RemoveFlag is case-insensitive`` (flag: string) = let args = _TestData.flags args.RemoveFlag(flag) Assert.Equal(2, args.Count) Assert.False(args.HasFlag(flag)) [<Fact>] let ``RemoveFlag does nothing if flag is missing`` () = let args = _TestData.flags args.RemoveFlag("missing") Assert.Equal(3, args.Count) module Values = [<Theory>] [<InlineData("val1")>] [<InlineData("val2")>] let ``HasValue returns false if key is missing`` (key: string) = Assert.False(_TestData.empty.HasValue(key)) Assert.False(_TestData.flags.HasValue(key)) [<Theory>] [<InlineData("flag1")>] [<InlineData("flag2")>] [<InlineData("flag3")>] let ``HasValue returns false if the name specifies a flag`` (key: string) = Assert.False(_TestData.flags.HasValue(key)) [<Fact>] let ``HasValue returns true if the name specifies both a flag and a value key`` () = Assert.True(_TestData.duplicate.HasValue("duplicate")) [<Theory>] [<InlineData("val1")>] [<InlineData("val2")>] let ``HasValue returns true if key is present`` (key: string) = Assert.True(_TestData.values.HasValue(key)) [<Theory>] [<InlineData("VAL1")>] [<InlineData("VaL1")>] let ``HasValue is case-insensitive`` (key: string) = Assert.True(_TestData.values.HasValue(key)) [<Theory>] [<InlineData("val1", "hello")>] [<InlineData("val2", "world")>] let ``GetValue returns correct value if key is present`` (key: string, expectedValue: string) = Assert.Equal(expectedValue, _TestData.values.GetValue(key, "")) [<Theory>] [<InlineData("VAL1", "hello")>] [<InlineData("VaL1", "hello")>] let ``GetValue is case-insensitive`` (key: string, expectedValue: string) = Assert.Equal(expectedValue, _TestData.values.GetValue(key, "")) [<Fact>] let ``GetValue returns default value if key is missing`` () = Assert.Equal("oh no", _TestData.values.GetValue("missing", "oh no")) [<Fact>] let ``SetValue adds new value`` () = let args = _TestData.values args.SetValue("val3", "this is nice") Assert.Equal(3, args.Count) Assert.Equal("this is nice", args.GetValue("val3", "")) [<Fact>] let ``SetValue replaces existing value`` () = let args = _TestData.values args.SetValue("val2", "mom") Assert.Equal(2, args.Count) Assert.Equal("mom", args.GetValue("val2", "")) [<Theory>] [<InlineData("val1")>] [<InlineData("val2")>] let ``RemoveValue removes existing key`` (key: string) = let args = _TestData.values args.RemoveValue(key) Assert.Equal(1, args.Count) Assert.False(args.HasValue(key)) [<Theory>] [<InlineData("VAL1")>] [<InlineData("VaL1")>] let ``RemoveValue is case-insensitive`` (key: string) = let args = _TestData.values args.RemoveValue(key) Assert.Equal(1, args.Count) Assert.False(args.HasValue(key)) [<Fact>] let ``RemoveValue does nothing if key is missing`` () = let args = _TestData.values args.RemoveValue("missing") Assert.Equal(2, args.Count) module Clone = [<Fact>] let ``clones flags and values correctly`` () = let clone = _TestData.mixed.Clone() Assert.True(clone.HasFlag("flag1")) Assert.True(clone.HasFlag("flag2")) Assert.True(clone.HasFlag("flag3")) Assert.Equal("hello", clone.GetValue("val1", "")) Assert.Equal("world", clone.GetValue("val2", "")) [<Fact>] let ``cloning creates a new object`` () = let args = _TestData.mixed Assert.NotSame(args.Clone(), args) [<Fact>] let ``modifying a clone does not modify the original`` () = let original = _TestData.mixed let clone = original.Clone() clone.RemoveFlag("flag1") clone.AddFlag("flag4") clone.SetValue("val1", "goodbye") Assert.True(original.HasFlag("flag1")) Assert.False(original.HasFlag("flag4")) Assert.Equal("hello", original.GetValue("val1", "")) module ToDictionary = open System.Collections.Generic [<Fact>] let ``does nothing with empty args`` () = let dict = Dictionary<string, string>() _TestData.empty.ToDictionary(dict) Assert.Equal(0, dict.Count) [<Fact>] let ``converts flags and values correctly`` () = let dict = Dictionary<string, string>() _TestData.mixed.ToDictionary(dict) Assert.Equal(5, dict.Count) Assert.Equal("1", dict.["flag1"]) Assert.Equal("1", dict.["flag2"]) Assert.Equal("1", dict.["flag3"]) Assert.Equal("hello", dict.["val1"]) Assert.Equal("world", dict.["val2"]) [<Fact>] let ``prefers value if the same name is used for a flag and value`` () = let dict = Dictionary<string, string>() _TestData.duplicate.ToDictionary(dict) Assert.Equal(1, dict.Count) Assert.Equal("value", dict.["duplicate"]) module ToString = [<Fact>] let ``returns empty string for empty args`` () = Assert.Equal("", _TestData.empty.ToString()) [<Fact>] let ``converts flags and values correctly`` () = Assert.Equal("flag1 flag2 flag3 val1 \"hello\" val2 \"world\"", _TestData.mixed.ToString()) // not guaranteed to be in order but works for now [<Fact>] let ``handle duplicate names in a probably pretty decent way tbh`` () = Assert.Equal("duplicate duplicate \"value\"", _TestData.duplicate.ToString()) module FromStringArray = [<Fact>] let ``returns empty args if input array is empty`` () = Assert.Equal(0, CommandLineArgs.FromStringArray('-', Array.empty).Count) [<Fact>] let ``returns empty args if no entry starts with entry char`` () = Assert.Equal(0, CommandLineArgs.FromStringArray('-', [| ""; "~nope"; ":fail" |]).Count) [<Fact>] let ``reads flags and values correctly`` () = let args = CommandLineArgs.FromStringArray('-', [| "-flag1"; "-flag2"; "-flag3"; "-val1"; "first value"; "-val2"; "second value" |]) Assert.Equal(5, args.Count) Assert.True(args.HasFlag("-flag1")) Assert.True(args.HasFlag("-flag2")) Assert.True(args.HasFlag("-flag3")) Assert.Equal("first value", args.GetValue("-val1", "")) Assert.Equal("second value", args.GetValue("-val2", "")) module ReadCefArguments = [<Fact>] let ``returns empty args if input string is empty`` () = Assert.Equal(0, CommandLineArgs.ReadCefArguments("").Count) [<Fact>] let ``returns empty args if input string is whitespace`` () = Assert.Equal(0, CommandLineArgs.ReadCefArguments(" \r\n \t").Count) [<Fact>] let ``reads values correctly`` () = let args = CommandLineArgs.ReadCefArguments("--first-value=10 --second-value=\"long string with spaces\"") Assert.Equal(2, args.Count) Assert.Equal("10", args.GetValue("first-value", "")) Assert.Equal("long string with spaces", args.GetValue("second-value", "")) [<Fact>] let ``reads flags as value keys with values of 1`` () = let args = CommandLineArgs.ReadCefArguments("--first-flag-as-value --second-flag-as-value") Assert.Equal(2, args.Count) Assert.Equal("1", args.GetValue("first-flag-as-value", "")) Assert.Equal("1", args.GetValue("second-flag-as-value", "")) [<Fact>] let ``reads complex string with whitespace correctly`` () = let args = CommandLineArgs.ReadCefArguments("\t--first-value=55.5\r\n--first-flag-as-value\r\n --second-value=\"long string\"\t--second-flag-as-value ") Assert.Equal(4, args.Count) Assert.Equal("55.5", args.GetValue("first-value", "")) Assert.Equal("long string", args.GetValue("second-value", "")) Assert.Equal("1", args.GetValue("first-flag-as-value", "")) Assert.Equal("1", args.GetValue("second-flag-as-value", ""))