From 8ef78b87f9c96b7f2c501acf856bf85a19152c8b Mon Sep 17 00:00:00 2001 From: Kingcean Date: Fri, 10 Jan 2025 22:21:25 +0800 Subject: [PATCH] Update JSON converter. --- Core/Maths/Boolean/Operations.cs | 21 + .../Lifecycle/ObservableProperties.cs | 2 +- Core/Text/JsonConverter/Object.cs | 76 +++- Core/Text/JsonNode/Values.cs | 61 ++- UnitTest/Tasks/EquipmentTaskUnitTest.cs | 139 ++++--- UnitTest/Tasks/InterceptorUnitTest.cs | 305 ++++++++------- UnitTest/Tasks/InterceptorVerb.cs | 365 +++++++++--------- UnitTest/Tasks/RetryUnitTest.cs | 129 +++---- UnitTest/Tasks/RetryVerb.cs | 107 +++-- UnitTest/Tasks/TaskFlowUnitTest.cs | 111 +++--- UnitTest/Text/JsonUnitTest.cs | 2 - UnitTest/Text/Models.cs | 8 +- UnitTest/Text/SchemaUnitTest.cs | 3 +- 13 files changed, 717 insertions(+), 612 deletions(-) diff --git a/Core/Maths/Boolean/Operations.cs b/Core/Maths/Boolean/Operations.cs index fc5a0241..5ff8c7d5 100644 --- a/Core/Maths/Boolean/Operations.cs +++ b/Core/Maths/Boolean/Operations.cs @@ -148,6 +148,27 @@ public static string ToString(CriteriaBooleanOperator op) public static string ToString(IEnumerable col) => string.Join(Environment.NewLine, col.Select(ele => ele?.ToString())); + /// + /// Converts a boolean to string format customized. + /// + /// A boolean value. + /// true in string. + /// false in string. + /// The customized string converted from boolean. + public static string ToString(bool value, string trueString, string falseString) + => value ? trueString : falseString; + + /// + /// Converts a boolean to string format customized. + /// + /// A boolean value. + /// true in string. + /// false in string. + /// null in string. + /// The customized string converted from boolean. + public static string ToString(bool? value, string trueString, string falseString, string nullString) + => value.HasValue ? ToString(value.Value, trueString, falseString) : nullString; + /// /// Calculates by boolean operation. /// diff --git a/Core/Reflection/Lifecycle/ObservableProperties.cs b/Core/Reflection/Lifecycle/ObservableProperties.cs index 9f5c8b3d..b5cde881 100644 --- a/Core/Reflection/Lifecycle/ObservableProperties.cs +++ b/Core/Reflection/Lifecycle/ObservableProperties.cs @@ -506,7 +506,7 @@ protected string GetPropertyJson(string key, JsonSerializerOptions options = /// Writes this instance to the specified writer as a JSON value. /// /// The writer to which to write this instance. - protected void WriteTo(Utf8JsonWriter writer) + protected virtual void WriteTo(Utf8JsonWriter writer) => JsonObjectNode.ConvertFrom(this).WriteTo(writer); /// diff --git a/Core/Text/JsonConverter/Object.cs b/Core/Text/JsonConverter/Object.cs index 8383ecff..225136d9 100644 --- a/Core/Text/JsonConverter/Object.cs +++ b/Core/Text/JsonConverter/Object.cs @@ -398,13 +398,41 @@ public override void Write(Utf8JsonWriter writer, JsonNodeSchemaDescription valu } } + /// + /// JSON object node host converter. + /// + internal sealed class HostConverter : JsonConverter where T : IJsonObjectHost + { + /// + public override bool CanConvert(Type typeToConvert) + => typeof(IJsonObjectHost).IsAssignableFrom(typeToConvert); + + /// + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => ReadHost(ref reader, typeToConvert, options); + + /// + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + var json = value?.ToJson(); + if (json is null) writer.WriteNullValue(); + json.WriteTo(writer); + } + } + /// public override bool CanConvert(Type typeToConvert) - => typeof(IJsonValueNode).IsAssignableFrom(typeToConvert) || typeToConvert == typeof(JsonNodeSchemaDescription); + => typeof(IJsonValueNode).IsAssignableFrom(typeToConvert) || typeof(IJsonObjectHost).IsAssignableFrom(typeToConvert) || typeToConvert == typeof(JsonNodeSchemaDescription); /// public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { + if (typeof(IJsonObjectHost).IsAssignableFrom(typeToConvert)) + { + var type = typeof(HostConverter<>).MakeGenericType(new[] { typeToConvert }); + return (JsonConverter)Activator.CreateInstance(type); + } + if (typeToConvert == typeof(IJsonValueNode)) return new CommonConverter(); if (typeToConvert == typeof(JsonObjectNode)) return new ObjectConverter(); if (typeToConvert == typeof(JsonArrayNode)) return new ArrayConverter(); @@ -446,22 +474,40 @@ internal static void Write(Utf8JsonWriter writer, IJsonValueNode value, JsonSeri else if (value is IJsonValueNode jDecimal) writer.WriteNumberValue(jDecimal.Value); else writer.WriteNullValue(); } + + internal static T ReadHost(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + where T : IJsonObjectHost + { + JsonValues.SkipComments(ref reader); + switch (reader.TokenType) + { + case JsonTokenType.Null: + return default; + case JsonTokenType.StartObject: + if (typeToConvert.IsInterface) throw new NotSupportedException(); + var constructor = typeToConvert.GetConstructor(new[] { typeof(JsonObjectNode), typeof(JsonSerializerOptions) }); + if (constructor != null) return (T)constructor.Invoke(new object[] { new JsonObjectNode(ref reader), options }); + constructor = typeToConvert.GetConstructor(new[] { typeof(JsonObjectNode) }); + if (constructor != null) return (T)constructor.Invoke(new[] { new JsonObjectNode(ref reader) }); + throw new JsonException("Requires a constructor with an argument of which type is JsonObjectNode.", new InvalidOperationException("Cannot deserialize the entity.")); + default: + throw new JsonException($"The token type is {reader.TokenType} but expect JSON object or null for {typeToConvert}."); + } + } } -#if NET7_0_OR_GREATER || NET462_OR_GREATER /// /// JSON object node host converter. /// -public sealed class JsonObjectHostConverter : JsonConverter +/// The type of the model. +public abstract class JsonObjectHostConverter : JsonConverter where T : IJsonObjectHost { - private readonly static JsonConverter defaultConverter = (JsonConverter)JsonSerializerOptions.Default.GetConverter(typeof(IJsonObjectHost)); - /// public override bool CanConvert(Type typeToConvert) => typeof(IJsonObjectHost).IsAssignableFrom(typeToConvert); /// - public override IJsonObjectHost Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonValues.SkipComments(ref reader); switch (reader.TokenType) @@ -469,23 +515,25 @@ public override IJsonObjectHost Read(ref Utf8JsonReader reader, Type typeToConve case JsonTokenType.Null: return default; case JsonTokenType.StartObject: - if (typeToConvert.IsInterface) throw new NotSupportedException(); - var constructor = typeToConvert.GetConstructor(new[] { typeof(JsonObjectNode), typeof(JsonSerializerOptions) }); - if (constructor != null) return (IJsonObjectHost)constructor.Invoke(new object[] { new JsonObjectNode(ref reader), options }); - constructor = typeToConvert.GetConstructor(new[] { typeof(JsonObjectNode) }); - if (constructor != null) return (IJsonObjectHost)constructor.Invoke(new[] { new JsonObjectNode(ref reader) }); - return defaultConverter.Read(ref reader, typeToConvert, options); + var json = JsonObjectNode.ParseValue(ref reader); + return json is null ? default : Create(json); default: throw new JsonException($"The token type is {reader.TokenType} but expect JSON object or null for {typeToConvert}."); } } /// - public override void Write(Utf8JsonWriter writer, IJsonObjectHost value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { var json = value?.ToJson(); if (json is null) writer.WriteNullValue(); json.WriteTo(writer); } + + /// + /// Creates the instance by JSON object. + /// + /// The JSON object. + /// The instance. + protected abstract T Create(JsonObjectNode json); } -#endif diff --git a/Core/Text/JsonNode/Values.cs b/Core/Text/JsonNode/Values.cs index e381c4d9..2f0dc8b3 100644 --- a/Core/Text/JsonNode/Values.cs +++ b/Core/Text/JsonNode/Values.cs @@ -24,6 +24,7 @@ using System.Runtime.Serialization.Json; using System.Net.Http; using Trivial.IO; +using Trivial.Maths; namespace Trivial.Text; @@ -1405,6 +1406,14 @@ public static string ToString(IJsonObjectHost value, IndentStyles indent = Inden return json.ToString(indent); } + /// + /// Converts to string format. + /// + /// A boolean value. + /// The string converted in JSON format. + public static string ToString(bool? value) + => BooleanOperations.ToString(value, JsonBooleanNode.TrueString, JsonBooleanNode.FalseString, NullString); + /// /// Converts to a specific type. /// @@ -2415,7 +2424,7 @@ internal static JsonObjectNode ToJson(Dictionary value.HasValue ? value.Value : double.NaN; + => value ?? double.NaN; internal static JsonNodeSchemaDescription CreateEnumSchema(Type type, JsonNodeSchemaDescription result = null) { @@ -2435,7 +2444,6 @@ internal static JsonNodeSchemaDescription CreateEnumSchema(Type type, JsonNodeSc return desc; } - internal static void RemoveJsonNodeSchemaDescriptionExtendedProperties(JsonObjectNode json, bool onlyBase) { json.SetRange(json); @@ -2456,13 +2464,51 @@ public static string ToTypeScriptDefinitionString(this JsonObjectSchemaDescripti { if (source == null) return string.IsNullOrWhiteSpace(name) ? string.Empty : string.Concat(name, ": null | undefined;"); var sb = new StringBuilder(); - ToTypeScriptDefinitionString("export interface ", name, source.Description, sb, 0); + ToTypeScriptDefinitionString("declare interface ", name, source.Description, sb, 0); if (!string.IsNullOrWhiteSpace(name)) sb.Append(' '); ToTypeScriptDefinitionString(source, sb, 0); sb.AppendLine(); return sb.ToString(); } + /// + /// Converts the JSON operation to Type Script definition (format of .d.ts file) content string. + /// + /// The JSON operation to convert. + /// The function name. + /// A Type Script definition format content string. + /// name was empty or consists only of white-space characters. + /// name was null. + public static string ToTypeScriptDefinitionString(this JsonOperationDescription source, string name) + { + StringExtensions.AssertNotWhiteSpace(nameof(name), name); + if (source == null) return string.Concat("declare function ", name, "(): void", Environment.NewLine); + var sb = new StringBuilder(); + ToTypeScriptDefinitionString("declare function ", name, source.Description, sb, 0); + if (source.ArgumentSchema == null) + { + sb.Append("(): "); + } + else + { + sb.Append("(args: "); + ToTypeScriptDefinitionString(source.ArgumentSchema, sb, 0); + sb.Append("): "); + } + + if (source.ResultSchema == null) + { + sb.Append("void;"); + } + else + { + ToTypeScriptDefinitionString(source.ResultSchema, sb, 0); + sb.AppendLine(";"); + } + + return sb.ToString(); + } + /// /// Converts the JSON schema to Type Script definition (format of .d.ts file) content string. /// @@ -2477,8 +2523,8 @@ private static void ToTypeScriptDefinitionString(JsonNodeSchemaDescription sourc sb.Append(str.ConstantValue ?? "string"); else if (source is JsonNumberSchemaDescription || source is JsonIntegerSchemaDescription) sb.Append("number"); - else if (source is JsonBooleanSchemaDescription) - sb.Append("boolean"); + else if (source is JsonBooleanSchemaDescription b) + sb.Append(BooleanOperations.ToString(b.ConstantValue, JsonBooleanNode.TrueString, JsonBooleanNode.FalseString, "boolean")); else if (source is JsonObjectSchemaDescription obj) ToTypeScriptDefinitionString(obj, sb, indent); else if (source is JsonArraySchemaDescription arr) @@ -2508,12 +2554,15 @@ private static void ToTypeScriptDefinitionString(JsonObjectSchemaDescription sou var indentStr = new string(' ', indent * 2); sb.AppendLine("{"); indent++; + var hasDesc = false; foreach (var prop in source.Properties) { var key = prop.Key; var v = prop.Value; if (string.IsNullOrWhiteSpace(key) || v == null) continue; + if (hasDesc) sb.AppendLine(); ToTypeScriptDefinitionString(null, key, v.Description, sb, indent); + if (!string.IsNullOrWhiteSpace(v.Description)) hasDesc = true; if (!source.RequiredPropertyNames.Contains(key)) sb.Append('?'); sb.Append(": "); ToTypeScriptDefinitionString(v, sb, indent); @@ -2522,6 +2571,7 @@ private static void ToTypeScriptDefinitionString(JsonObjectSchemaDescription sou if (!source.DisableAdditionalProperties || (source.PatternProperties != null && source.PatternProperties.Count > 0)) { + if (hasDesc) sb.AppendLine(); sb.Append(indentStr); sb.AppendLine(" [key: string]: any;"); } @@ -2557,7 +2607,6 @@ private static void ToTypeScriptDefinitionString(string prefix, string name, str var indentStr = new string(' ', indent * 2); if (!string.IsNullOrWhiteSpace(description)) { - sb.AppendLine(); sb.Append(indentStr); sb.AppendLine("/** "); sb.Append(indentStr); diff --git a/UnitTest/Tasks/EquipmentTaskUnitTest.cs b/UnitTest/Tasks/EquipmentTaskUnitTest.cs index c0a77f06..7e3b0b5f 100644 --- a/UnitTest/Tasks/EquipmentTaskUnitTest.cs +++ b/UnitTest/Tasks/EquipmentTaskUnitTest.cs @@ -8,84 +8,83 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +/// +/// Equipment task unit test. +/// +[TestClass] +public class EquipmentTaskUnitTest { /// - /// Equipment task unit test. + /// Tests equipment task. /// - [TestClass] - public class EquipmentTaskUnitTest + [TestMethod] + public void TestTask() { - /// - /// Tests equipment task. - /// - [TestMethod] - public void TestTask() - { - var tasks = new EquipartitionTaskContainer(); - var task1 = tasks.Create("a", "o", 5, "task1"); - var task2 = tasks.Create("a", "p", 1, "task2"); - var task3 = tasks.Create("b", "q", 2, "task3"); + var tasks = new EquipartitionTaskContainer(); + var task1 = tasks.Create("a", "o", 5, "task1"); + var task2 = tasks.Create("a", "p", 1, "task2"); + var task3 = tasks.Create("b", "q", 2, "task3"); - Assert.AreEqual(5, task1.Count); - Assert.AreEqual(1, task2.Count); - Assert.AreEqual(2, task3.Count); - Assert.AreEqual(5, task1.GetWaitingOrProcessingFragments().Count()); - Assert.AreEqual(1, task2.GetWaitingOrProcessingFragments().Count()); - Assert.AreEqual(2, task3.GetWaitingOrProcessingFragments().Count()); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - Assert.AreEqual(0, task2.GetProcessingFragments().Count()); - Assert.AreEqual(0, task3.GetProcessingFragments().Count()); - Assert.AreEqual(0, task1.GetDoneFragments().Count()); - Assert.AreEqual(0, task2.GetDoneFragments().Count()); - Assert.AreEqual(0, task3.GetDoneFragments().Count()); + Assert.AreEqual(5, task1.Count); + Assert.AreEqual(1, task2.Count); + Assert.AreEqual(2, task3.Count); + Assert.AreEqual(5, task1.GetWaitingOrProcessingFragments().Count()); + Assert.AreEqual(1, task2.GetWaitingOrProcessingFragments().Count()); + Assert.AreEqual(2, task3.GetWaitingOrProcessingFragments().Count()); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + Assert.AreEqual(0, task2.GetProcessingFragments().Count()); + Assert.AreEqual(0, task3.GetProcessingFragments().Count()); + Assert.AreEqual(0, task1.GetDoneFragments().Count()); + Assert.AreEqual(0, task2.GetDoneFragments().Count()); + Assert.AreEqual(0, task3.GetDoneFragments().Count()); - var f = task1.Pick(); - Assert.AreEqual(EquipartitionTask.FragmentStates.Working, f.State); - Assert.AreEqual(1, task1.GetProcessingFragments().Count()); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - Assert.AreEqual(EquipartitionTask.FragmentStates.Success, f.State); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - f = task1.Pick(); - Assert.AreEqual(EquipartitionTask.FragmentStates.Working, f.State); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Failure); - Assert.AreEqual(EquipartitionTask.FragmentStates.Failure, f.State); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - f = task1.Pick(); - Assert.AreEqual(EquipartitionTask.FragmentStates.Retrying, f.State); - Assert.AreEqual(1, task1.GetProcessingFragments().Count()); - Assert.AreEqual(0, task2.GetProcessingFragments().Count()); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Fatal); - Assert.AreEqual(EquipartitionTask.FragmentStates.Fatal, f.State); + var f = task1.Pick(); + Assert.AreEqual(EquipartitionTask.FragmentStates.Working, f.State); + Assert.AreEqual(1, task1.GetProcessingFragments().Count()); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + Assert.AreEqual(EquipartitionTask.FragmentStates.Success, f.State); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + f = task1.Pick(); + Assert.AreEqual(EquipartitionTask.FragmentStates.Working, f.State); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Failure); + Assert.AreEqual(EquipartitionTask.FragmentStates.Failure, f.State); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + f = task1.Pick(); + Assert.AreEqual(EquipartitionTask.FragmentStates.Retrying, f.State); + Assert.AreEqual(1, task1.GetProcessingFragments().Count()); + Assert.AreEqual(0, task2.GetProcessingFragments().Count()); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Fatal); + Assert.AreEqual(EquipartitionTask.FragmentStates.Fatal, f.State); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - Assert.AreEqual(0, task2.GetProcessingFragments().Count()); - Assert.AreEqual(0, task3.GetProcessingFragments().Count()); - Assert.AreEqual(2, task1.GetDoneFragments().Count()); - Assert.AreEqual(0, task2.GetDoneFragments().Count()); - Assert.AreEqual(0, task3.GetDoneFragments().Count()); - Assert.AreEqual(3, task1.GetWaitingOrProcessingFragments().Count()); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + Assert.AreEqual(0, task2.GetProcessingFragments().Count()); + Assert.AreEqual(0, task3.GetProcessingFragments().Count()); + Assert.AreEqual(2, task1.GetDoneFragments().Count()); + Assert.AreEqual(0, task2.GetDoneFragments().Count()); + Assert.AreEqual(0, task3.GetDoneFragments().Count()); + Assert.AreEqual(3, task1.GetWaitingOrProcessingFragments().Count()); - task3.Pick(); - f = task3.Pick(); - Assert.AreEqual(2, task3.GetProcessingFragments().Count()); - var fStr = f.ToJsonString(); - f = EquipartitionTask.Fragment.Parse(fStr); - fStr = f.ToQueryData().ToString(); - f = EquipartitionTask.Fragment.Parse(fStr); - var status = task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - Assert.AreEqual(2, task3.GetProcessingFragments().Count()); - Assert.AreEqual(false, status); - task3.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - Assert.AreEqual(1, task3.GetProcessingFragments().Count()); - Assert.AreEqual(EquipartitionTask.FragmentStates.Success, f.State); - f = task3.Pick(); - Assert.IsNull(f); + task3.Pick(); + f = task3.Pick(); + Assert.AreEqual(2, task3.GetProcessingFragments().Count()); + var fStr = f.ToJsonString(); + f = EquipartitionTask.Fragment.Parse(fStr); + fStr = f.ToQueryData().ToString(); + f = EquipartitionTask.Fragment.Parse(fStr); + var status = task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + Assert.AreEqual(2, task3.GetProcessingFragments().Count()); + Assert.AreEqual(false, status); + task3.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); + Assert.AreEqual(1, task3.GetProcessingFragments().Count()); + Assert.AreEqual(EquipartitionTask.FragmentStates.Success, f.State); + f = task3.Pick(); + Assert.IsNull(f); - task3.UpdateFragment(task3[0], EquipartitionTask.FragmentStates.Success); - Assert.AreEqual(0, task1.GetProcessingFragments().Count()); - } + task3.UpdateFragment(task3[0], EquipartitionTask.FragmentStates.Success); + Assert.AreEqual(0, task1.GetProcessingFragments().Count()); } } diff --git a/UnitTest/Tasks/InterceptorUnitTest.cs b/UnitTest/Tasks/InterceptorUnitTest.cs index cba3a5fd..f66ee53b 100644 --- a/UnitTest/Tasks/InterceptorUnitTest.cs +++ b/UnitTest/Tasks/InterceptorUnitTest.cs @@ -8,165 +8,164 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +/// +/// Hit task unit test. +/// +[TestClass] +public class InterceptorUnitTest { /// - /// Hit task unit test. + /// Tests debounce hit task. /// - [TestClass] - public class InterceptorUnitTest + /// The task object representing the asynchronous operation. + [TestMethod] + public async Task TestDebounceAsync() { - /// - /// Tests debounce hit task. - /// - /// The task object representing the asynchronous operation. - [TestMethod] - public async Task TestDebounceAsync() - { - var result = string.Empty; - var task = new Interceptor( - v => result = v, - InterceptorPolicy.Debounce(TimeSpan.FromMilliseconds(100)) - ); - Assert.IsFalse(task.IsWorking); - _ = task.InvokeAsync("abc"); - Assert.IsTrue(task.IsWorking); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("defg"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("hijk"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("lmn"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - await Task.Delay(90); - if (string.IsNullOrEmpty(result)) await Task.Delay(20); - Assert.AreEqual("lmn", result); - await task.WaitAsync(); - Assert.IsFalse(task.IsWorking); - } + var result = string.Empty; + var task = new Interceptor( + v => result = v, + InterceptorPolicy.Debounce(TimeSpan.FromMilliseconds(100)) + ); + Assert.IsFalse(task.IsWorking); + _ = task.InvokeAsync("abc"); + Assert.IsTrue(task.IsWorking); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("defg"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("hijk"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("lmn"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + await Task.Delay(90); + if (string.IsNullOrEmpty(result)) await Task.Delay(20); + Assert.AreEqual("lmn", result); + await task.WaitAsync(); + Assert.IsFalse(task.IsWorking); + } - /// - /// Tests throttle hit task. - /// - /// The task object representing the asynchronous operation. - [TestMethod] - public async Task TestThrottleAsync() - { - var taskTokens = new List(); - var result = string.Empty; - var task = new Interceptor( - v => result = v, - InterceptorPolicy.Throttle(TimeSpan.FromMilliseconds(100)) - ); - Assert.IsFalse(task.IsWorking); - _ = task.InvokeAsync("opq"); - await Task.Delay(10); - Assert.AreEqual("opq", result); - _ = task.InvokeAsync("rst"); - await Task.Delay(10); - Assert.AreEqual("opq", result); - _ = task.InvokeAsync("uvw"); - await Task.Delay(110); - Assert.AreEqual("opq", result); - _ = task.InvokeAsync("xyz"); - Assert.AreEqual("xyz", result); - await task.WaitAsync(); - Assert.IsFalse(task.IsWorking); - } + /// + /// Tests throttle hit task. + /// + /// The task object representing the asynchronous operation. + [TestMethod] + public async Task TestThrottleAsync() + { + var taskTokens = new List(); + var result = string.Empty; + var task = new Interceptor( + v => result = v, + InterceptorPolicy.Throttle(TimeSpan.FromMilliseconds(100)) + ); + Assert.IsFalse(task.IsWorking); + _ = task.InvokeAsync("opq"); + await Task.Delay(10); + Assert.AreEqual("opq", result); + _ = task.InvokeAsync("rst"); + await Task.Delay(10); + Assert.AreEqual("opq", result); + _ = task.InvokeAsync("uvw"); + await Task.Delay(110); + Assert.AreEqual("opq", result); + _ = task.InvokeAsync("xyz"); + Assert.AreEqual("xyz", result); + await task.WaitAsync(); + Assert.IsFalse(task.IsWorking); + } - /// - /// Tests multiple hit task. - /// - /// The task object representing the asynchronous operation. - [TestMethod] - public async Task TestMutlipleHitsAsync() - { - var taskTokens = new List(); - var result = string.Empty; - var task = new Interceptor( - v => result = v, - InterceptorPolicy.Mutliple(2, 4, TimeSpan.FromMilliseconds(100)) - ); - Assert.IsFalse(task.IsWorking); - _ = task.InvokeAsync("abc"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("defg"); - await Task.Delay(20); - Assert.AreEqual("defg", result); - _ = task.InvokeAsync("hijk"); - await Task.Delay(20); - Assert.AreEqual("hijk", result); - _ = task.InvokeAsync("lmn"); - await Task.Delay(20); - Assert.AreEqual("lmn", result); - _ = task.InvokeAsync("opq"); - await Task.Delay(110); - Assert.AreEqual("lmn", result); - _ = task.InvokeAsync("rst"); - await Task.Delay(20); - Assert.AreEqual("lmn", result); - _ = task.InvokeAsync("uvw"); - await Task.Delay(20); - Assert.AreEqual("uvw", result); - _ = task.InvokeAsync("xyz"); - await Task.Delay(20); - Assert.AreEqual("xyz", result); - await task.WaitAsync(); - Assert.IsFalse(task.IsWorking); - } + /// + /// Tests multiple hit task. + /// + /// The task object representing the asynchronous operation. + [TestMethod] + public async Task TestMutlipleHitsAsync() + { + var taskTokens = new List(); + var result = string.Empty; + var task = new Interceptor( + v => result = v, + InterceptorPolicy.Mutliple(2, 4, TimeSpan.FromMilliseconds(100)) + ); + Assert.IsFalse(task.IsWorking); + _ = task.InvokeAsync("abc"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("defg"); + await Task.Delay(20); + Assert.AreEqual("defg", result); + _ = task.InvokeAsync("hijk"); + await Task.Delay(20); + Assert.AreEqual("hijk", result); + _ = task.InvokeAsync("lmn"); + await Task.Delay(20); + Assert.AreEqual("lmn", result); + _ = task.InvokeAsync("opq"); + await Task.Delay(110); + Assert.AreEqual("lmn", result); + _ = task.InvokeAsync("rst"); + await Task.Delay(20); + Assert.AreEqual("lmn", result); + _ = task.InvokeAsync("uvw"); + await Task.Delay(20); + Assert.AreEqual("uvw", result); + _ = task.InvokeAsync("xyz"); + await Task.Delay(20); + Assert.AreEqual("xyz", result); + await task.WaitAsync(); + Assert.IsFalse(task.IsWorking); + } - /// - /// Tests times hit task. - /// - /// The task object representing the asynchronous operation. - [TestMethod] - public async Task TestTimesHitsAsync() - { - var taskTokens = new List(); - var result = string.Empty; - var task = new Interceptor( - v => result = v, - InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(100)) - ); - Assert.IsFalse(task.IsWorking); - _ = task.InvokeAsync("abc"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("defg"); - Assert.IsTrue(task.IsWorking); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("hijk"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("lmn"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - await Task.Delay(90); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("opq"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - _ = task.InvokeAsync("rst"); - await Task.Delay(20); - Assert.AreEqual(string.Empty, result); - await Task.Delay(90); - if (string.IsNullOrEmpty(result)) await Task.Delay(20); - Assert.AreEqual("rst", result); - _ = task.InvokeAsync("uvw"); - await Task.Delay(20); - Assert.AreEqual("rst", result); - _ = task.InvokeAsync("xyz"); - await Task.Delay(140); - if (result == "rst") await Task.Delay(20); - Assert.AreEqual("xyz", result); - await task.WaitAsync(); - Assert.IsFalse(task.IsWorking); - } + /// + /// Tests times hit task. + /// + /// The task object representing the asynchronous operation. + [TestMethod] + public async Task TestTimesHitsAsync() + { + var taskTokens = new List(); + var result = string.Empty; + var task = new Interceptor( + v => result = v, + InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(100)) + ); + Assert.IsFalse(task.IsWorking); + _ = task.InvokeAsync("abc"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("defg"); + Assert.IsTrue(task.IsWorking); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("hijk"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("lmn"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + await Task.Delay(90); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("opq"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + _ = task.InvokeAsync("rst"); + await Task.Delay(20); + Assert.AreEqual(string.Empty, result); + await Task.Delay(90); + if (string.IsNullOrEmpty(result)) await Task.Delay(20); + Assert.AreEqual("rst", result); + _ = task.InvokeAsync("uvw"); + await Task.Delay(20); + Assert.AreEqual("rst", result); + _ = task.InvokeAsync("xyz"); + await Task.Delay(140); + if (result == "rst") await Task.Delay(20); + Assert.AreEqual("xyz", result); + await task.WaitAsync(); + Assert.IsFalse(task.IsWorking); } } diff --git a/UnitTest/Tasks/InterceptorVerb.cs b/UnitTest/Tasks/InterceptorVerb.cs index e249ed68..1af3bea2 100644 --- a/UnitTest/Tasks/InterceptorVerb.cs +++ b/UnitTest/Tasks/InterceptorVerb.cs @@ -5,202 +5,201 @@ using System.Threading; using System.Threading.Tasks; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +class InterceptorVerb : CommandLine.BaseCommandVerb { - class InterceptorVerb : CommandLine.BaseCommandVerb - { - private int checkCount = 0; + private int checkCount = 0; - private string value = "a"; + private string value = "a"; - public static string Description => "Interceptor"; + public static string Description => "Interceptor"; - protected override async Task OnProcessAsync(CancellationToken cancellationToken = default) - { - await TestKeyFeaturesAsync(); - Console.WriteLine(); - TestEquipartitionTaskAsync(); - } + protected override async Task OnProcessAsync(CancellationToken cancellationToken = default) + { + await TestKeyFeaturesAsync(); + Console.WriteLine(); + TestEquipartitionTaskAsync(); + } - private async Task TestKeyFeaturesAsync() - { - Console.WriteLine("Interceptor testing."); - - Console.WriteLine("Debounce"); - var task = new Interceptor( - v => value = v, - InterceptorPolicy.Debounce(TimeSpan.FromMilliseconds(200)) - ); - _ = task.InvokeAsync("b"); - await Task.Delay(100); - _ = task.InvokeAsync("c"); - await Task.Delay(100); - _ = task.InvokeAsync("d"); - await Task.Delay(100); - _ = task.InvokeAsync("e"); - Check("a"); - await Task.Delay(300); - Check("e"); - await task.WaitAsync(); - Check("e"); - - Console.WriteLine("Throttle"); - task.ResetDuration(); - task.Policy = InterceptorPolicy.Throttle(TimeSpan.FromMilliseconds(800)); - _ = task.InvokeAsync("f"); - await Task.Delay(100); - _ = task.InvokeAsync("g"); - await Task.Delay(100); - _ = task.InvokeAsync("h"); - await Task.Delay(100); - _ = task.InvokeAsync("i"); - await Task.Delay(100); - Check("f"); - await task.WaitAsync(); - Check("f"); - - Console.WriteLine("Multiple"); - task.ResetDuration(); - task.Policy = InterceptorPolicy.Mutliple(2, 4, TimeSpan.FromMilliseconds(200)); - _ = task.InvokeAsync("j"); - Check("f"); - await Task.Delay(100); - _ = task.InvokeAsync("k"); - Check("k"); - await Task.Delay(100); - _ = task.InvokeAsync("l"); - await Task.Delay(100); - _ = task.InvokeAsync("m"); - await Task.Delay(100); - Check("m"); - _ = task.InvokeAsync("n"); - await Task.Delay(100); - Check("m"); - await task.WaitAsync(); - Check("m"); - - Console.WriteLine("Times 1"); - task.ResetDuration(); - task.Policy = InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(200)); - _ = task.InvokeAsync("o"); - Check("m"); - await Task.Delay(100); - _ = task.InvokeAsync("p"); - Check("m"); - await Task.Delay(100); - _ = task.InvokeAsync("q"); - await Task.Delay(100); - _ = task.InvokeAsync("r"); - await Task.Delay(100); - Check("m"); - _ = task.InvokeAsync("s"); - await Task.Delay(100); - Check("m"); - await task.WaitAsync(); - Check("m"); - - Console.WriteLine("Times 2"); - task.ResetDuration(); - task.Policy = InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(200)); - _ = task.InvokeAsync("t"); - Check("m"); - await Task.Delay(100); - _ = task.InvokeAsync("u"); - Check("m"); - await Task.Delay(100); - _ = task.InvokeAsync("v"); - await Task.Delay(100); - Check("m"); - await task.WaitAsync(); - Check("v"); - } + private async Task TestKeyFeaturesAsync() + { + Console.WriteLine("Interceptor testing."); + + Console.WriteLine("Debounce"); + var task = new Interceptor( + v => value = v, + InterceptorPolicy.Debounce(TimeSpan.FromMilliseconds(200)) + ); + _ = task.InvokeAsync("b"); + await Task.Delay(100); + _ = task.InvokeAsync("c"); + await Task.Delay(100); + _ = task.InvokeAsync("d"); + await Task.Delay(100); + _ = task.InvokeAsync("e"); + Check("a"); + await Task.Delay(300); + Check("e"); + await task.WaitAsync(); + Check("e"); + + Console.WriteLine("Throttle"); + task.ResetDuration(); + task.Policy = InterceptorPolicy.Throttle(TimeSpan.FromMilliseconds(800)); + _ = task.InvokeAsync("f"); + await Task.Delay(100); + _ = task.InvokeAsync("g"); + await Task.Delay(100); + _ = task.InvokeAsync("h"); + await Task.Delay(100); + _ = task.InvokeAsync("i"); + await Task.Delay(100); + Check("f"); + await task.WaitAsync(); + Check("f"); + + Console.WriteLine("Multiple"); + task.ResetDuration(); + task.Policy = InterceptorPolicy.Mutliple(2, 4, TimeSpan.FromMilliseconds(200)); + _ = task.InvokeAsync("j"); + Check("f"); + await Task.Delay(100); + _ = task.InvokeAsync("k"); + Check("k"); + await Task.Delay(100); + _ = task.InvokeAsync("l"); + await Task.Delay(100); + _ = task.InvokeAsync("m"); + await Task.Delay(100); + Check("m"); + _ = task.InvokeAsync("n"); + await Task.Delay(100); + Check("m"); + await task.WaitAsync(); + Check("m"); + + Console.WriteLine("Times 1"); + task.ResetDuration(); + task.Policy = InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(200)); + _ = task.InvokeAsync("o"); + Check("m"); + await Task.Delay(100); + _ = task.InvokeAsync("p"); + Check("m"); + await Task.Delay(100); + _ = task.InvokeAsync("q"); + await Task.Delay(100); + _ = task.InvokeAsync("r"); + await Task.Delay(100); + Check("m"); + _ = task.InvokeAsync("s"); + await Task.Delay(100); + Check("m"); + await task.WaitAsync(); + Check("m"); + + Console.WriteLine("Times 2"); + task.ResetDuration(); + task.Policy = InterceptorPolicy.Times(2, 3, TimeSpan.FromMilliseconds(200)); + _ = task.InvokeAsync("t"); + Check("m"); + await Task.Delay(100); + _ = task.InvokeAsync("u"); + Check("m"); + await Task.Delay(100); + _ = task.InvokeAsync("v"); + await Task.Delay(100); + Check("m"); + await task.WaitAsync(); + Check("v"); + } - private void TestEquipartitionTaskAsync() + private void TestEquipartitionTaskAsync() + { + Console.WriteLine("Equipartition task testing."); + var tasks = new EquipartitionTaskContainer(); + tasks.Created += (sender, ev) => { - Console.WriteLine("Equipartition task testing."); - var tasks = new EquipartitionTaskContainer(); - tasks.Created += (sender, ev) => - { - if (ev.NewValue == null) - { - Console.WriteLine("N/A"); - return; - } - - Console.WriteLine($"{ev.NewValue.Description ?? ev.NewValue.Id}\t{ev.Key}\tCreated"); - }; - var task1 = tasks.Create("a", "o", 5, "task1"); - WriteLine(task1); - var task2 = tasks.Create("a", "p", 1, "task2"); - WriteLine(task2); - var task3 = tasks.Create("b", "q", 2, "task3"); - WriteLine(task3); - - Console.WriteLine("Pick from " + (task1.Description ?? task1.Id)); - var f = task1.Pick(); - f = task1.Pick(); - WriteLine(task1); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - WriteLine(task1); - f = task1.Pick(); - WriteLine(task1); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Failure); - WriteLine(task1); - Console.WriteLine(f.State); - f = task1.Pick(); - Console.WriteLine(f.State); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Fatal); - Console.WriteLine(f.State); - WriteLine(task1); - WriteLine(task2); - WriteLine(task3); - - Console.WriteLine("Pick from " + (task3.Description ?? task3.Id)); - f = task3.Pick(); - f = task3.Pick(); - WriteLine(task1); - WriteLine(task2); - WriteLine(task3); - var fStr = f.ToJsonString(); - Console.WriteLine(fStr); - f = EquipartitionTask.Fragment.Parse(fStr); - fStr = f.ToQueryData().ToString(); - Console.WriteLine(fStr); - f = EquipartitionTask.Fragment.Parse(fStr); - task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - WriteLine(task1); - WriteLine(task2); - WriteLine(task3); - task3.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); - WriteLine(task1); - WriteLine(task2); - WriteLine(task3); - f = task3.Pick(); - Console.WriteLine("No more fragment in task3."); - if (f != null) + if (ev.NewValue == null) { - Console.WriteLine("Error!"); + Console.WriteLine("N/A"); return; } - task3.UpdateFragment(task3[0], EquipartitionTask.FragmentStates.Success); - WriteLine(task1); - WriteLine(task2); - WriteLine(task3); - - Console.WriteLine("Done!"); - } - - private void Check(string expect, string message = null) + Console.WriteLine($"{ev.NewValue.Description ?? ev.NewValue.Id}\t{ev.Key}\tCreated"); + }; + var task1 = tasks.Create("a", "o", 5, "task1"); + WriteLine(task1); + var task2 = tasks.Create("a", "p", 1, "task2"); + WriteLine(task2); + var task3 = tasks.Create("b", "q", 2, "task3"); + WriteLine(task3); + + Console.WriteLine("Pick from " + (task1.Description ?? task1.Id)); + var f = task1.Pick(); + f = task1.Pick(); + WriteLine(task1); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + WriteLine(task1); + f = task1.Pick(); + WriteLine(task1); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Failure); + WriteLine(task1); + Console.WriteLine(f.State); + f = task1.Pick(); + Console.WriteLine(f.State); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Fatal); + Console.WriteLine(f.State); + WriteLine(task1); + WriteLine(task2); + WriteLine(task3); + + Console.WriteLine("Pick from " + (task3.Description ?? task3.Id)); + f = task3.Pick(); + f = task3.Pick(); + WriteLine(task1); + WriteLine(task2); + WriteLine(task3); + var fStr = f.ToJsonString(); + Console.WriteLine(fStr); + f = EquipartitionTask.Fragment.Parse(fStr); + fStr = f.ToQueryData().ToString(); + Console.WriteLine(fStr); + f = EquipartitionTask.Fragment.Parse(fStr); + task1.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + WriteLine(task1); + WriteLine(task2); + WriteLine(task3); + task3.UpdateFragment(f, EquipartitionTask.FragmentStates.Success); + WriteLine(task1); + WriteLine(task2); + WriteLine(task3); + f = task3.Pick(); + Console.WriteLine("No more fragment in task3."); + if (f != null) { - checkCount++; - if (expect == value) return; - throw new InvalidOperationException("#" + checkCount + " (" + value + " != " + expect + ") " + (message ?? string.Empty)); + Console.WriteLine("Error!"); + return; } - private static void WriteLine(EquipartitionTask t) - { - Console.WriteLine($"{t.Description ?? t.Id}\t{t.JobId}\t{t.GetProcessingFragments().Count()} + {t.GetDoneFragments().Count()} / {t.Count}"); - } + task3.UpdateFragment(task3[0], EquipartitionTask.FragmentStates.Success); + WriteLine(task1); + WriteLine(task2); + WriteLine(task3); + + Console.WriteLine("Done!"); + } + + private void Check(string expect, string message = null) + { + checkCount++; + if (expect == value) return; + throw new InvalidOperationException("#" + checkCount + " (" + value + " != " + expect + ") " + (message ?? string.Empty)); + } + + private static void WriteLine(EquipartitionTask t) + { + Console.WriteLine($"{t.Description ?? t.Id}\t{t.JobId}\t{t.GetProcessingFragments().Count()} + {t.GetDoneFragments().Count()} / {t.Count}"); } } diff --git a/UnitTest/Tasks/RetryUnitTest.cs b/UnitTest/Tasks/RetryUnitTest.cs index 9412c247..f3ca0261 100644 --- a/UnitTest/Tasks/RetryUnitTest.cs +++ b/UnitTest/Tasks/RetryUnitTest.cs @@ -9,88 +9,87 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Trivial.Reflection; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +/// +/// Retry unit test. +/// +[TestClass] +public class RetryUnitTest { /// - /// Retry unit test. + /// Tests linear retry policy. /// - [TestClass] - public class RetryUnitTest + /// The task object representing the asynchronous operation. + [TestMethod] + public async Task TestLinearAsync() { - /// - /// Tests linear retry policy. - /// - /// The task object representing the asynchronous operation. - [TestMethod] - public async Task TestLinearAsync() + var count = 0; + var now = DateTime.Now; + var retry = new LinearRetryPolicy(3, TimeSpan.FromMilliseconds(20), TimeSpan.FromMilliseconds(10)); + await retry.ProcessAsync(() => + { + count++; + throw new ApplicationException(); + }, typeof(ApplicationException)); + Assert.AreEqual(4, count); + Assert.IsTrue(DateTime.Now - now >= TimeSpan.FromMilliseconds(90)); + + var isSucc = false; + try { - var count = 0; - var now = DateTime.Now; - var retry = new LinearRetryPolicy(3, TimeSpan.FromMilliseconds(20), TimeSpan.FromMilliseconds(10)); await retry.ProcessAsync(() => { count++; - throw new ApplicationException(); + throw new InvalidOperationException(); }, typeof(ApplicationException)); - Assert.AreEqual(4, count); - Assert.IsTrue(DateTime.Now - now >= TimeSpan.FromMilliseconds(90)); + } + catch (InvalidOperationException) + { + isSucc = true; + } - var isSucc = false; - try - { - await retry.ProcessAsync(() => - { - count++; - throw new InvalidOperationException(); - }, typeof(ApplicationException)); - } - catch (InvalidOperationException) - { - isSucc = true; - } + Assert.IsTrue(isSucc); + Assert.AreEqual(5, count); - Assert.IsTrue(isSucc); - Assert.AreEqual(5, count); + var h = new ExceptionHandler(); + h.Add(ex => + { + return null; + }); + h.Add(ex => + { + if (ex.Message == "name") return null; + return new ApplicationException(); + }); - var h = new ExceptionHandler(); - h.Add(ex => - { - return null; - }); - h.Add(ex => - { - if (ex.Message == "name") return null; - return new ApplicationException(); - }); + await retry.ProcessAsync(() => + { + count++; + throw new ApplicationException(); + }, h.GetException); + await retry.ProcessAsync(() => + { + count++; + throw new ArgumentException("name"); + }, h.GetException); + Assert.AreEqual(13, count); + isSucc = false; + try + { await retry.ProcessAsync(() => { count++; - throw new ApplicationException(); - }, h.GetException); - await retry.ProcessAsync(() => - { - count++; - throw new ArgumentException("name"); + throw new ArgumentException("other"); }, h.GetException); - Assert.AreEqual(13, count); - - isSucc = false; - try - { - await retry.ProcessAsync(() => - { - count++; - throw new ArgumentException("other"); - }, h.GetException); - } - catch (ApplicationException) - { - isSucc = true; - } - - Assert.AreEqual(14, count); - Assert.IsTrue(isSucc); } + catch (ApplicationException) + { + isSucc = true; + } + + Assert.AreEqual(14, count); + Assert.IsTrue(isSucc); } } diff --git a/UnitTest/Tasks/RetryVerb.cs b/UnitTest/Tasks/RetryVerb.cs index 8dcd86c7..e2d245d3 100644 --- a/UnitTest/Tasks/RetryVerb.cs +++ b/UnitTest/Tasks/RetryVerb.cs @@ -6,77 +6,76 @@ using Trivial.Reflection; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +class RetryVerb : CommandLine.BaseCommandVerb { - class RetryVerb : CommandLine.BaseCommandVerb - { - public static string Description => "Retry"; + public static string Description => "Retry"; - protected override async Task OnProcessAsync(CancellationToken cancellationToken = default) + protected override async Task OnProcessAsync(CancellationToken cancellationToken = default) + { + Console.WriteLine("Retry 1"); + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + var retry = new LinearRetryPolicy(3, TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(100)); + await retry.ProcessAsync(() => { - Console.WriteLine("Retry 1"); Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - var retry = new LinearRetryPolicy(3, TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(100)); + throw new ApplicationException(); + }, typeof(ApplicationException)); + + Console.WriteLine("Retry 2"); + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + try + { await retry.ProcessAsync(() => { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - throw new ApplicationException(); + throw new InvalidOperationException(); }, typeof(ApplicationException)); + } + catch (InvalidOperationException) + { + } - Console.WriteLine("Retry 2"); - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - try - { - await retry.ProcessAsync(() => - { - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - throw new InvalidOperationException(); - }, typeof(ApplicationException)); - } - catch (InvalidOperationException) - { - } - - var h = new ExceptionHandler(); - h.Add(ex => - { - return null; - }); - h.Add(ex => - { - if (ex.Message == "name") return null; - return new ApplicationException(); - }); + var h = new ExceptionHandler(); + h.Add(ex => + { + return null; + }); + h.Add(ex => + { + if (ex.Message == "name") return null; + return new ApplicationException(); + }); - Console.WriteLine("Retry 3"); + Console.WriteLine("Retry 3"); + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + await retry.ProcessAsync(() => + { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - await retry.ProcessAsync(() => - { - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - throw new ApplicationException(); - }, h.GetException); + throw new ApplicationException(); + }, h.GetException); - Console.WriteLine("Retry 4"); + Console.WriteLine("Retry 4"); + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + await retry.ProcessAsync(() => + { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + throw new ArgumentException("name"); + }, h.GetException); + + Console.WriteLine("Retry 5"); + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); + try + { await retry.ProcessAsync(() => { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - throw new ArgumentException("name"); + throw new ArgumentException("other"); }, h.GetException); - - Console.WriteLine("Retry 5"); - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - try - { - await retry.ProcessAsync(() => - { - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff")); - throw new ArgumentException("other"); - }, h.GetException); - } - catch (ApplicationException) - { - } + } + catch (ApplicationException) + { } } } diff --git a/UnitTest/Tasks/TaskFlowUnitTest.cs b/UnitTest/Tasks/TaskFlowUnitTest.cs index 35accd6b..282edcef 100644 --- a/UnitTest/Tasks/TaskFlowUnitTest.cs +++ b/UnitTest/Tasks/TaskFlowUnitTest.cs @@ -8,67 +8,66 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Trivial.Tasks +namespace Trivial.Tasks; + +/// +/// Task flow unit test. +/// +[TestClass] +public class TaskFlowUnitTest { /// - /// Task flow unit test. + /// Tests equipment task. /// - [TestClass] - public class TaskFlowUnitTest + [TestMethod] + public async Task TestTaskAsync() { - /// - /// Tests equipment task. - /// - [TestMethod] - public async Task TestTaskAsync() + var task = Task.Run(async () => + { + await Task.Delay(100); + return 100; + }); + var flow1 = new TaskFlow(task); + flow1.ResultTo(r => + { + Assert.AreEqual(100, r); + }); + flow1.ResultTo(r => + { + Assert.AreEqual(100, r); + }); + flow1.Catch(ex => + { + Assert.Fail("It should not throw any exception."); + }); + var flow2 = flow1.Then(r => + { + throw new InvalidOperationException("test"); + #pragma warning disable CS0162 + return string.Empty; + #pragma warning restore CS0162 + }); + flow2.Catch(ex => + { + Assert.AreEqual("test", ex.Message); + }); + flow2.ResultTo(r => + { + Assert.Fail("It should not return any result."); + }); + flow2.Catch(ex => + { + Assert.AreEqual("test", ex.Message); + }); + Assert.AreEqual(100, await flow1.ResultAsync()); + try + { + await flow2.WaitAsync(); + Assert.Fail("It should throw an exception."); + } + catch (InvalidOperationException ex) { - var task = Task.Run(async () => - { - await Task.Delay(100); - return 100; - }); - var flow1 = new TaskFlow(task); - flow1.ResultTo(r => - { - Assert.AreEqual(100, r); - }); - flow1.ResultTo(r => - { - Assert.AreEqual(100, r); - }); - flow1.Catch(ex => - { - Assert.Fail("It should not throw any exception."); - }); - var flow2 = flow1.Then(r => - { - throw new InvalidOperationException("test"); - #pragma warning disable CS0162 - return string.Empty; - #pragma warning restore CS0162 - }); - flow2.Catch(ex => - { - Assert.AreEqual("test", ex.Message); - }); - flow2.ResultTo(r => - { - Assert.Fail("It should not return any result."); - }); - flow2.Catch(ex => - { - Assert.AreEqual("test", ex.Message); - }); - Assert.AreEqual(100, await flow1.ResultAsync()); - try - { - await flow2.WaitAsync(); - Assert.Fail("It should throw an exception."); - } - catch (InvalidOperationException ex) - { - Assert.AreEqual("test", ex.Message); - } + Assert.AreEqual("test", ex.Message); } } } diff --git a/UnitTest/Text/JsonUnitTest.cs b/UnitTest/Text/JsonUnitTest.cs index e75aaaa0..99dfbb2c 100644 --- a/UnitTest/Text/JsonUnitTest.cs +++ b/UnitTest/Text/JsonUnitTest.cs @@ -378,11 +378,9 @@ public void TestJsonObject() var host = new JsonHostTestModel("Test", "JSON"); json.SetValue("host", host); Assert.AreEqual("Test", json.TryGetStringValue(new[] { "host", "n" })); -#if NET7_0_OR_GREATER host = JsonSerializer.Deserialize(JsonSerializer.Serialize(host)); json.SetValue("host", host); Assert.AreEqual("JSON", json.TryGetValue("host", "v")); -#endif var hostService = new JsonObjectHostService(json); host = hostService.TryGetValue("host"); host.Name = "Right"; diff --git a/UnitTest/Text/Models.cs b/UnitTest/Text/Models.cs index ba2a5f20..ad52e6fe 100644 --- a/UnitTest/Text/Models.cs +++ b/UnitTest/Text/Models.cs @@ -133,15 +133,9 @@ class JsonAttributeTestModel public Maths.Angle W { get; set; } } -#if NET7_0_OR_GREATER -[JsonConverter(typeof(JsonObjectHostConverter))] -#endif +[JsonConverter(typeof(JsonValueNodeConverter))] class JsonHostTestModel : IJsonObjectHost { - public JsonHostTestModel() - { - } - public JsonHostTestModel(JsonObjectNode json) { if (json == null) return; diff --git a/UnitTest/Text/SchemaUnitTest.cs b/UnitTest/Text/SchemaUnitTest.cs index c71d483b..a7d7e3ba 100644 --- a/UnitTest/Text/SchemaUnitTest.cs +++ b/UnitTest/Text/SchemaUnitTest.cs @@ -33,9 +33,10 @@ public void TestJsonSchema() Assert.IsNotNull(arrSchema?.DefaultItems); Assert.AreEqual(typeof(JsonIntegerSchemaDescription), arrSchema.DefaultItems.GetType()); var desc = JsonOperationDescription.Create(typeof(JsonModel), nameof(JsonModel.Create), new[] { typeof(JsonAttributeTestModel) }); - Assert.IsNotNull(desc); + Assert.IsNotNull(desc?.ResultSchema); Assert.AreEqual("Create a new instance.", desc.Description); Assert.AreEqual("A test model.", desc.ArgumentSchema.Description); + Assert.IsNotNull(desc.ToTypeScriptDefinitionString("testFunc")); desc = JsonOperationDescription.Create(typeof(JsonModel), nameof(JsonModel.Create), new[] { typeof(string), typeof(string) }); Assert.IsNotNull(desc); Assert.AreEqual("Create a new instance.", desc.Description);