From 3dd1360bf1319391087cef0a37d69941b5685462 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sun, 12 Jan 2025 17:17:20 +0000 Subject: [PATCH] stash from hp --- DNX.Extensions.sln | 29 ++-- .../DNX.Extensions.Generators.csproj | 25 ++++ .../Extensions/ResourceExtensions.cs | 28 ++++ .../Generators/ConversionGenerator.cs | 86 ++++++++++++ .../ConversionGenerator.Template.txt | 91 ++++++++++++ .../Assemblies/AssemblyExtensions.cs | 12 +- .../Conversion/ConvertExtensions.cs | 26 ---- src/DNX.Extensions/DNX.Extensions.csproj | 6 + .../Exceptions/ConversionException.cs | 47 +++++++ .../Exceptions/EnumTypeException.cs | 43 ++++++ .../Exceptions/EnumValueException.cs | 49 +++++++ .../Exceptions/ExceptionExtensions.cs | 51 +++++++ .../Exceptions/ParameterException.cs | 73 ++++++++++ .../Exceptions/ParameterInvalidException.cs | 55 ++++++++ .../Exceptions/ReadOnlyListException.cs | 28 ++++ .../Conversion/ConvertExtensionsTest.cs | 130 +++++++++--------- .../Conversion/ConvertInt32ExtensionsTests.cs | 79 +++++++++++ .../DNX.Extensions.Benchmarks.csproj | 0 .../DevelopmentConfig.cs | 0 .../DNX.Extensions.Benchmarks/Program.cs | 0 .../Strings/StringExtensionBenchmarks.cs | 0 21 files changed, 748 insertions(+), 110 deletions(-) create mode 100644 src/DNX.Extensions.Generators/DNX.Extensions.Generators.csproj create mode 100644 src/DNX.Extensions.Generators/Extensions/ResourceExtensions.cs create mode 100644 src/DNX.Extensions.Generators/Generators/ConversionGenerator.cs create mode 100644 src/DNX.Extensions.Generators/Templates/ConversionGenerator.Template.txt create mode 100644 src/DNX.Extensions/Exceptions/ConversionException.cs create mode 100644 src/DNX.Extensions/Exceptions/EnumTypeException.cs create mode 100644 src/DNX.Extensions/Exceptions/EnumValueException.cs create mode 100644 src/DNX.Extensions/Exceptions/ExceptionExtensions.cs create mode 100644 src/DNX.Extensions/Exceptions/ParameterException.cs create mode 100644 src/DNX.Extensions/Exceptions/ParameterInvalidException.cs create mode 100644 src/DNX.Extensions/Exceptions/ReadOnlyListException.cs create mode 100644 tests/DNX.Extensions.Tests/Conversion/ConvertInt32ExtensionsTests.cs rename {tests => verification}/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj (100%) rename {tests => verification}/DNX.Extensions.Benchmarks/DevelopmentConfig.cs (100%) rename {tests => verification}/DNX.Extensions.Benchmarks/Program.cs (100%) rename {tests => verification}/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs (100%) diff --git a/DNX.Extensions.sln b/DNX.Extensions.sln index 476873c..40784d2 100644 --- a/DNX.Extensions.sln +++ b/DNX.Extensions.sln @@ -3,19 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32825.248 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E832563B-3DD6-4CCD-B5DA-91F89AE3B98A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{27BBD260-1C33-4F57-925A-12AB922D6AB5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions", "src\DNX.Extensions\DNX.Extensions.csproj", "{E2B8F640-BCFE-4BD7-B158-E7FE957A38CB}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{9E70C755-0A39-46EA-8063-0A3B594B7271}" ProjectSection(SolutionItems) = preProject .github\workflows\ci-build.yml = .github\workflows\ci-build.yml EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions.Tests", "tests\DNX.Extensions.Tests\DNX.Extensions.Tests.csproj", "{B14EFA70-CA77-4439-9C08-357061B97E4D}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".code", ".code", "{5936EA03-F95A-4407-9149-A23F4A378E4E}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -28,7 +20,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".docs", ".docs", "{8700E3D9 To Do.md = To Do.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions.Benchmarks", "tests\DNX.Extensions.Benchmarks\DNX.Extensions.Benchmarks.csproj", "{D9664527-B415-498F-B8A9-9AF016D7D91F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E832563B-3DD6-4CCD-B5DA-91F89AE3B98A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{27BBD260-1C33-4F57-925A-12AB922D6AB5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "verification", "verification", "{A4EAD2B7-21AC-48E8-ADE3-6AE0B5D80A6B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions", "src\DNX.Extensions\DNX.Extensions.csproj", "{E2B8F640-BCFE-4BD7-B158-E7FE957A38CB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions.Tests", "tests\DNX.Extensions.Tests\DNX.Extensions.Tests.csproj", "{B14EFA70-CA77-4439-9C08-357061B97E4D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DNX.Extensions.Benchmarks", "verification\DNX.Extensions.Benchmarks\DNX.Extensions.Benchmarks.csproj", "{D9664527-B415-498F-B8A9-9AF016D7D91F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DNX.Extensions.Generators", "src\DNX.Extensions.Generators\DNX.Extensions.Generators.csproj", "{2D817A1A-E754-45F0-9187-A9F1FE7B7630}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -48,6 +52,10 @@ Global {D9664527-B415-498F-B8A9-9AF016D7D91F}.Debug|Any CPU.Build.0 = Debug|Any CPU {D9664527-B415-498F-B8A9-9AF016D7D91F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D9664527-B415-498F-B8A9-9AF016D7D91F}.Release|Any CPU.Build.0 = Release|Any CPU + {2D817A1A-E754-45F0-9187-A9F1FE7B7630}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D817A1A-E754-45F0-9187-A9F1FE7B7630}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D817A1A-E754-45F0-9187-A9F1FE7B7630}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D817A1A-E754-45F0-9187-A9F1FE7B7630}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -55,7 +63,8 @@ Global GlobalSection(NestedProjects) = preSolution {E2B8F640-BCFE-4BD7-B158-E7FE957A38CB} = {E832563B-3DD6-4CCD-B5DA-91F89AE3B98A} {B14EFA70-CA77-4439-9C08-357061B97E4D} = {27BBD260-1C33-4F57-925A-12AB922D6AB5} - {D9664527-B415-498F-B8A9-9AF016D7D91F} = {27BBD260-1C33-4F57-925A-12AB922D6AB5} + {D9664527-B415-498F-B8A9-9AF016D7D91F} = {A4EAD2B7-21AC-48E8-ADE3-6AE0B5D80A6B} + {2D817A1A-E754-45F0-9187-A9F1FE7B7630} = {E832563B-3DD6-4CCD-B5DA-91F89AE3B98A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A971C3D4-3729-43C6-88E7-16371F03161F} diff --git a/src/DNX.Extensions.Generators/DNX.Extensions.Generators.csproj b/src/DNX.Extensions.Generators/DNX.Extensions.Generators.csproj new file mode 100644 index 0000000..1e29f8b --- /dev/null +++ b/src/DNX.Extensions.Generators/DNX.Extensions.Generators.csproj @@ -0,0 +1,25 @@ + + + + Latest + netstandard2.0 + true + true + true + true + Generated + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/src/DNX.Extensions.Generators/Extensions/ResourceExtensions.cs b/src/DNX.Extensions.Generators/Extensions/ResourceExtensions.cs new file mode 100644 index 0000000..32401c0 --- /dev/null +++ b/src/DNX.Extensions.Generators/Extensions/ResourceExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace DNX.Extensions.Generators.Extensions; + +[ExcludeFromCodeCoverage] +internal static class ResourceExtensions +{ + internal static string GetEmbeddedResourceText(this object obj, string resourceName) + { + var type = obj.GetType(); + + var assembly = type.Assembly; + + var manifestFileInfo = assembly.GetManifestResourceNames() + .SingleOrDefault(x => x.EndsWith(resourceName)); + + if (string.IsNullOrWhiteSpace(manifestFileInfo)) + throw new Exception($"Unable to locate resource : {resourceName}"); + + var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(manifestFileInfo); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } +} diff --git a/src/DNX.Extensions.Generators/Generators/ConversionGenerator.cs b/src/DNX.Extensions.Generators/Generators/ConversionGenerator.cs new file mode 100644 index 0000000..60e81b4 --- /dev/null +++ b/src/DNX.Extensions.Generators/Generators/ConversionGenerator.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using DNX.Extensions.Generators.Extensions; +using Microsoft.CodeAnalysis; + +namespace DNX.Extensions.Generators.Generators; + +[ExcludeFromCodeCoverage] +[Generator] +public class ConversionGenerator : ISourceGenerator +{ + private static readonly Dictionary TypesForGeneration = new() + { + { "short", nameof(Int16) }, + { "int", nameof(Int32) }, + { "long", nameof(Int64) }, + { "bool", nameof(Boolean) }, + }; + + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + context.ReportDiagnostic( + Diagnostic.Create( + new DiagnosticDescriptor( + "DNX0001", + $"{nameof(ConversionGenerator)} Executing", + nameof(ConversionGenerator) + " Executing for {0} types", + "Build", + DiagnosticSeverity.Info, + true + ), + Location.None, + TypesForGeneration.Count.ToString() + ) + ); + + var targetNamespace = GetType().Name.Replace("Generator", ""); + + var nameSpace = GetType().Namespace.Replace(".Generators", "") + .Trim('.') + + $".{targetNamespace}"; + + var templateFileName = $"{GetType().Name}.Template.txt"; + + var templateText = this.GetEmbeddedResourceText(templateFileName); + + if (string.IsNullOrWhiteSpace(templateText)) + throw new Exception($"{nameof(templateText)} is empty"); + + foreach (var kvp in TypesForGeneration) + { + var typeName = kvp.Key; + var typeDescription = kvp.Value; + + context.ReportDiagnostic( + Diagnostic.Create( + new DiagnosticDescriptor( + "DNX0002", + $"{nameof(ConversionGenerator)} Generating: {typeName}", + nameof(ConversionGenerator) + " Generating: {0} as {1}, under {2}", + "", + DiagnosticSeverity.Info, + true + ), + Location.None, + typeName, + typeDescription, + nameSpace + ) + ); + + var sourceText = templateText + .Replace("#namespace#", nameSpace) + .Replace("#type#", typeName) + .Replace("#name#", typeDescription) + ; + + context.AddSource($"Convert{kvp.Value}.generated.cs", sourceText); + } + } +} diff --git a/src/DNX.Extensions.Generators/Templates/ConversionGenerator.Template.txt b/src/DNX.Extensions.Generators/Templates/ConversionGenerator.Template.txt new file mode 100644 index 0000000..365e6a4 --- /dev/null +++ b/src/DNX.Extensions.Generators/Templates/ConversionGenerator.Template.txt @@ -0,0 +1,91 @@ +using System; +using DNX.Extensions.Exceptions; + +namespace #namespace#; + +/// +/// Class Convert#Name#Extensions. +/// +/// +/// Extensions for converting #type# values +/// +public static class Convert#name#Extensions +{ + /// + /// Converts the string to a #type# + /// + /// The text. + /// #type# + /// Unable to convert value to Type + public static #type# To#name#(this string text) + { + #type# result; + + if (!#type#.TryParse(text, out result)) + { + throw new ConversionException(text, "Unable to convert value to Type", typeof(#type#)); + } + + return result; + } + + /// + /// Converts the string to a #type#, or returns the default value if the conversion fails + /// + /// The text. + /// The default value. + /// #type# + public static #type# To#name#(this string text, #type# defaultValue) + { + try + { + var result = text.To#name#(); + + return result; + } + catch (ConversionException) + { + return defaultValue; + } + } + + /// + /// Determines if the string can be converted to a #type# or not + /// + /// The text. + /// true if the specified text is a #type; otherwise, false. + public static bool Is#name#(this string text) + { + try + { + text.To#name#(); + + return true; + } + catch (ConversionException) + { + return false; + } + } + + /// + /// Determines if the string can be converted to a #type# or not + /// + /// The text. + /// true if the specified text is a #type; otherwise, false. + public static bool Is#name#(this string text, out #type# value) + { + value = default; + + try + { + value = text.To#name#(); + + return true; + } + catch (ConversionException) + { + return false; + } + } +} diff --git a/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs b/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs index 17c3c06..ee6ae6a 100644 --- a/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs +++ b/src/DNX.Extensions/Assemblies/AssemblyExtensions.cs @@ -30,15 +30,9 @@ public static string GetEmbeddedResourceText(this Assembly assembly, string rela var resourceName = $"{nameSpace}.{relativeResourceName}"; - using (var stream = assembly.GetManifestResourceStream(resourceName)) - { - using (var reader = new StreamReader(stream)) - { - var result = reader.ReadToEnd(); - - return result; - } - } + using var stream = assembly.GetManifestResourceStream(resourceName); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); } catch (Exception e) { diff --git a/src/DNX.Extensions/Conversion/ConvertExtensions.cs b/src/DNX.Extensions/Conversion/ConvertExtensions.cs index 04f8112..78832da 100644 --- a/src/DNX.Extensions/Conversion/ConvertExtensions.cs +++ b/src/DNX.Extensions/Conversion/ConvertExtensions.cs @@ -18,32 +18,6 @@ public static string ToStringOrDefault(this object obj, string defaultValue = "" return obj?.ToString() ?? defaultValue; } - /// - /// Converts to boolean. - /// - /// The text. - /// The default value. - /// true/false if can be converted, defaultValue otherwise. - public static bool ToBoolean(this string text, bool defaultValue = default) - { - return bool.TryParse(text, out var value) - ? value - : defaultValue; - } - - /// - /// Converts to int32. - /// - /// The text. - /// The default value. - /// System.Int32. - public static int ToInt32(this string text, int defaultValue = default) - { - return int.TryParse(text, out var value) - ? value - : defaultValue; - } - /// /// Converts to enum. /// diff --git a/src/DNX.Extensions/DNX.Extensions.csproj b/src/DNX.Extensions/DNX.Extensions.csproj index 244a8f3..ce9c352 100644 --- a/src/DNX.Extensions/DNX.Extensions.csproj +++ b/src/DNX.Extensions/DNX.Extensions.csproj @@ -38,4 +38,10 @@ + + + + diff --git a/src/DNX.Extensions/Exceptions/ConversionException.cs b/src/DNX.Extensions/Exceptions/ConversionException.cs new file mode 100644 index 0000000..99ce7ce --- /dev/null +++ b/src/DNX.Extensions/Exceptions/ConversionException.cs @@ -0,0 +1,47 @@ +using System; + +namespace DNX.Extensions.Exceptions +{ + /// + /// Conversion Exception. + /// + /// + /// Thrown when a conversion to a specified type fails + public class ConversionException : Exception + { + /// + /// Gets the value. + /// + /// The value. + public string Value { get; private set; } + + /// + /// Gets the type of the convert. + /// + /// The type of the convert. + public Type ConvertType { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// The message. + public ConversionException(string value, string message) + : this(value, message, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// The message. + /// The type. + public ConversionException(string value, string message, Type type) + : base(message) + { + Value = value; + ConvertType = type; + } + } +} diff --git a/src/DNX.Extensions/Exceptions/EnumTypeException.cs b/src/DNX.Extensions/Exceptions/EnumTypeException.cs new file mode 100644 index 0000000..5b50f06 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/EnumTypeException.cs @@ -0,0 +1,43 @@ +using System; + +namespace DNX.Extensions.Exceptions +{ + /// + /// EnumTypeException. + /// + /// + public class EnumTypeException : Exception + { + /// + /// The message template + /// + private const string MessageTemplate = "{0} is not an enumeration type"; + + /// + /// The type the exception was thrown for + /// + /// The type. + public Type Type { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The type. + /// Uses the default message template + public EnumTypeException(Type type) + : this(type, MessageTemplate) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The type. + /// The message template. + public EnumTypeException(Type type, string messageTemplate) + : base(string.Format(messageTemplate, type.Name)) + { + Type = type; + } + } +} diff --git a/src/DNX.Extensions/Exceptions/EnumValueException.cs b/src/DNX.Extensions/Exceptions/EnumValueException.cs new file mode 100644 index 0000000..24adc14 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/EnumValueException.cs @@ -0,0 +1,49 @@ +using System; + +namespace DNX.Extensions.Exceptions +{ + /// + /// Class EnumValueException. + /// + /// + public class EnumValueException : Exception + { + /// + /// The message template + /// + private const string MessageTemplate = "{0} is not a valid {1} value"; + + /// + /// Gets the type. + /// + /// The type. + public Type Type { get; private set; } + + /// + /// Gets the value. + /// + /// The value. + public T Value { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + public EnumValueException(T value) + : this(value, MessageTemplate) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// The message template. + public EnumValueException(T value, string messageTemplate) + : base(string.Format(messageTemplate, value, typeof(T).Name)) + { + Type = typeof(T); + Value = value; + } + } +} diff --git a/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs b/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs new file mode 100644 index 0000000..3971178 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/ExceptionExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; + +namespace DNX.Extensions.Exceptions +{ + /// + /// Exception Extensions. + /// + public static class ExceptionExtensions + { + /// + /// Gets the list of messages from an Exception and inner exceptions + /// + /// The ex. + /// IList<System.String>. + /// Also available as an extension method + public static IList GetMessageList(this Exception ex) + { + var list = new List(); + + while (ex != null) + { + list.Add(ex.Message); + + ex = ex.InnerException; + } + + return list; + } + + /// + /// Gets the list of messages from an Exception and inner exceptions + /// + /// The ex. + /// IList<System.String>. + /// Also available as an extension method + public static IList GetExceptionList(this Exception ex) + { + var list = new List(); + + while (ex != null) + { + list.Add(ex); + + ex = ex.InnerException; + } + + return list; + } + } +} diff --git a/src/DNX.Extensions/Exceptions/ParameterException.cs b/src/DNX.Extensions/Exceptions/ParameterException.cs new file mode 100644 index 0000000..9be2a63 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/ParameterException.cs @@ -0,0 +1,73 @@ +using System; + +namespace DNX.Extensions.Exceptions +{ + /// + /// An exception for idenifying issues with expected parameters + /// + /// + public class ParameterException : Exception + { + /// + /// The Parameter Name + /// + /// The name of the parameter. + public string ParamName { get; private set; } + + /// + /// The value specified for the Parameter + /// + /// The parameter value. + public object ParamValue { get; private set; } + + /// + /// Create a ParameterException with a parameter name and a message + /// + /// Name of the parameter. + /// The message. + public ParameterException(string paramName, string message) + : base(message) + { + ParamName = paramName; + } + + /// + /// Create a ParameterException with a parameter name and value, and a message + /// + /// Name of the parameter. + /// The parameter value. + /// The message. + public ParameterException(string paramName, object paramValue, string message) + : base(message) + { + ParamName = paramName; + ParamValue = paramValue; + } + + /// + /// Create a ParameterException with a parameter name, message and inner Exception + /// + /// Name of the parameter. + /// The message. + /// The inner exception. + public ParameterException(string paramName, string message, Exception innerException) + : base(message, innerException) + { + ParamName = paramName; + } + + /// + /// Create a ParameterException with a parameter name and value, message and inner Exception + /// + /// Name of the parameter. + /// The parameter value. + /// The message. + /// The inner exception. + public ParameterException(string paramName, object paramValue, string message, Exception innerException) + : base(message, innerException) + { + ParamName = paramName; + ParamValue = paramValue; + } + } +} diff --git a/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs b/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs new file mode 100644 index 0000000..3ca67a5 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/ParameterInvalidException.cs @@ -0,0 +1,55 @@ +using System; + +namespace DNX.Extensions.Exceptions +{ + /// + /// An exception for idenifying an invalid value issue with expected parameters + /// + /// + public class ParameterInvalidException : ParameterException + { + /// + /// Create a ParameterInvalidException with a parameter name and a message + /// + /// Name of the parameter. + /// The message. + public ParameterInvalidException(string paramName, string message) + : base(paramName, message) + { + } + + /// + /// Create a ParameterInvalidException with a parameter name and value, and a message + /// + /// Name of the parameter. + /// The parameter value. + /// The message. + public ParameterInvalidException(string paramName, object paramValue, string message) + : base(paramName, paramValue, message) + { + } + + /// + /// Create a ParameterInvalidException with a parameter name, message and inner Exception + /// + /// Name of the parameter. + /// The message. + /// The inner exception. + public ParameterInvalidException(string paramName, string message, Exception innerException) + : base(paramName, message, innerException) + { + } + + /// + /// Create a ParameterInvalidException with a parameter name and value, message and inner Exception + /// + /// Name of the parameter. + /// The parameter value. + /// The message. + /// The inner exception. + public ParameterInvalidException(string paramName, object paramValue, string message, Exception innerException) + : base(paramName, paramValue, message, innerException) + { + } + } +} diff --git a/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs b/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs new file mode 100644 index 0000000..8634f32 --- /dev/null +++ b/src/DNX.Extensions/Exceptions/ReadOnlyListException.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace DNX.Extensions.Exceptions +{ + /// + /// Class ReadOnlyListException. + /// + /// + /// + public class ReadOnlyListException : Exception + { + /// + /// Gets the list. + /// + /// The list. + public IList List { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The list. + public ReadOnlyListException(IList list) + { + List = list; + } + } +} diff --git a/tests/DNX.Extensions.Tests/Conversion/ConvertExtensionsTest.cs b/tests/DNX.Extensions.Tests/Conversion/ConvertExtensionsTest.cs index aa5600c..d68dbdc 100644 --- a/tests/DNX.Extensions.Tests/Conversion/ConvertExtensionsTest.cs +++ b/tests/DNX.Extensions.Tests/Conversion/ConvertExtensionsTest.cs @@ -47,71 +47,71 @@ public void ToStringOrDefault_with_override_can_convert_successfully(object inst } } - public class ToBoolean - { - [Theory] - [InlineData("true", true)] - [InlineData("TRUE", true)] - [InlineData("TrUe", true)] - [InlineData("false", false)] - [InlineData("FALSE", false)] - [InlineData("FaLsE", false)] - [InlineData("NotABoolean", false)] - public void ToBoolean_without_override_can_convert_successfully(string text, bool expected) - { - var result = text.ToBoolean(); - - result.Should().Be(expected); - } - - [Theory] - [InlineData("true", false, true)] - [InlineData("TRUE", false, true)] - [InlineData("TrUe", false, true)] - [InlineData("false", true, false)] - [InlineData("FALSE", true, false)] - [InlineData("FaLsE", true, false)] - [InlineData("NotABoolean", false, false)] - [InlineData("NotABoolean", true, true)] - public void ToBoolean_with_override_can_convert_successfully(string text, bool defaultValue, bool expected) - { - var result = text.ToBoolean(defaultValue); - - result.Should().Be(expected); - } - } - - public class ToInt32 - { - [Theory] - [InlineData("160", 160)] - [InlineData("0", 0)] - [InlineData("-1", -1)] - [InlineData("2147483647", 2147483647)] - [InlineData("2147483648", 0)] - [InlineData("NotAnInt32", 0)] - public void ToInt32_without_override_can_convert_successfully(string text, int expected) - { - var result = text.ToInt32(); - - result.Should().Be(expected); - } - - [Theory] - [InlineData("160", 42, 160)] - [InlineData("0", 57, 0)] - [InlineData("-1", 5, -1)] - [InlineData("2147483647", 12345, 2147483647)] - [InlineData("2147483648", 12345, 12345)] - [InlineData("NotAnInt32", 0, 0)] - [InlineData("NotAnInt32", 222, 222)] - public void ToInt32_with_override_can_convert_successfully(string text, int defaultValue, int expected) - { - var result = text.ToInt32(defaultValue); - - result.Should().Be(expected); - } - } + //public class ToBoolean + //{ + // [Theory] + // [InlineData("true", true)] + // [InlineData("TRUE", true)] + // [InlineData("TrUe", true)] + // [InlineData("false", false)] + // [InlineData("FALSE", false)] + // [InlineData("FaLsE", false)] + // [InlineData("NotABoolean", false)] + // public void ToBoolean_without_override_can_convert_successfully(string text, bool expected) + // { + // var result = text.ToBoolean(); + // + // result.Should().Be(expected); + // } + // + // [Theory] + // [InlineData("true", false, true)] + // [InlineData("TRUE", false, true)] + // [InlineData("TrUe", false, true)] + // [InlineData("false", true, false)] + // [InlineData("FALSE", true, false)] + // [InlineData("FaLsE", true, false)] + // [InlineData("NotABoolean", false, false)] + // [InlineData("NotABoolean", true, true)] + // public void ToBoolean_with_override_can_convert_successfully(string text, bool defaultValue, bool expected) + // { + // var result = text.ToBoolean(defaultValue); + // + // result.Should().Be(expected); + // } + //} + + //public class ToInt32 + //{ + // [Theory] + // [InlineData("160", 160)] + // [InlineData("0", 0)] + // [InlineData("-1", -1)] + // [InlineData("2147483647", 2147483647)] + // [InlineData("2147483648", 0)] + // [InlineData("NotAnInt32", 0)] + // public void ToInt32_without_override_can_convert_successfully(string text, int expected) + // { + // var result = text.ToInt32(); + // + // result.Should().Be(expected); + // } + // + // [Theory] + // [InlineData("160", 42, 160)] + // [InlineData("0", 57, 0)] + // [InlineData("-1", 5, -1)] + // [InlineData("2147483647", 12345, 2147483647)] + // [InlineData("2147483648", 12345, 12345)] + // [InlineData("NotAnInt32", 0, 0)] + // [InlineData("NotAnInt32", 222, 222)] + // public void ToInt32_with_override_can_convert_successfully(string text, int defaultValue, int expected) + // { + // var result = text.ToInt32(defaultValue); + // + // result.Should().Be(expected); + // } + //} public class ToEnum { diff --git a/tests/DNX.Extensions.Tests/Conversion/ConvertInt32ExtensionsTests.cs b/tests/DNX.Extensions.Tests/Conversion/ConvertInt32ExtensionsTests.cs new file mode 100644 index 0000000..ff99e56 --- /dev/null +++ b/tests/DNX.Extensions.Tests/Conversion/ConvertInt32ExtensionsTests.cs @@ -0,0 +1,79 @@ +using Xunit; +using DNX.Extensions.Conversion; +using DNX.Extensions.Exceptions; +using FluentAssertions; + +namespace DNX.Extensions.Tests.Conversion; + +public class ConvertInt32ExtensionsTests +{ + [Theory] + [InlineData("160", 160)] + [InlineData("0", 0)] + [InlineData("-1", -1)] + [InlineData("2147483647", 2147483647)] + public void ToInt32_without_override_can_convert_successfully(string text, int expected) + { + var result = text.ToInt32(); + + result.Should().Be(expected); + } + + [Theory] + [InlineData("2147483648")] + [InlineData("NotAnInt32")] + public void ToInt32_for_invalid_value_without_override_fails_as_expected(string text) + { + Action action = () => text.ToInt32(); + + // Act / Assert + var q = action.Should() + .Throw() + .Where(e => e.Value == text) + .Where(e => e.ConvertType == typeof(int)) + ; + } + + [Theory] + [InlineData("160", 42, 160)] + [InlineData("0", 57, 0)] + [InlineData("-1", 5, -1)] + [InlineData("2147483647", 12345, 2147483647)] + [InlineData("2147483648", 12345, 12345)] + [InlineData("NotAnInt32", 0, 0)] + [InlineData("NotAnInt32", 222, 222)] + public void ToInt32_with_override_can_convert_successfully(string text, int defaultValue, int expected) + { + var result = text.ToInt32(defaultValue); + + result.Should().Be(expected); + } + + [Theory] + [InlineData("Bob", false)] + [InlineData("12345", true)] + [InlineData("12,345", false)] + public void IsInt32(string text, bool expectedResult) + { + // Act + var result = text.IsInt32(); + + // Assert + result.Should().Be(expectedResult); + } + + [Theory] + [InlineData("Bob", false)] + [InlineData("12345", true)] + [InlineData("12,345", false)] + public void IsInt32_with_output_value(string text, bool expectedResult) + { + // Act + var result = text.IsInt32(out var value); + + // Assert + result.Should().Be(expectedResult); + if (result) + value.Should().Be(text.ToInt32()); + } +} diff --git a/tests/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj b/verification/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj similarity index 100% rename from tests/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj rename to verification/DNX.Extensions.Benchmarks/DNX.Extensions.Benchmarks.csproj diff --git a/tests/DNX.Extensions.Benchmarks/DevelopmentConfig.cs b/verification/DNX.Extensions.Benchmarks/DevelopmentConfig.cs similarity index 100% rename from tests/DNX.Extensions.Benchmarks/DevelopmentConfig.cs rename to verification/DNX.Extensions.Benchmarks/DevelopmentConfig.cs diff --git a/tests/DNX.Extensions.Benchmarks/Program.cs b/verification/DNX.Extensions.Benchmarks/Program.cs similarity index 100% rename from tests/DNX.Extensions.Benchmarks/Program.cs rename to verification/DNX.Extensions.Benchmarks/Program.cs diff --git a/tests/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs b/verification/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs similarity index 100% rename from tests/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs rename to verification/DNX.Extensions.Benchmarks/Strings/StringExtensionBenchmarks.cs