From 667c4061bd4c817e435d3b5a4cf57622c9c6b91f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:07:02 +0100 Subject: [PATCH 1/8] understand nullables and have netstandard2 as net8 --- .editorconfig | 570 ++++++++++++++++++ .github/dependabot.yml | 6 + .github/workflows/dotnetcore.yml | 22 + Directory.Build.props | 16 + Directory.Packages.props | 11 + Narochno.Primitives.sln | 8 + NuGet.config | 9 + build/Program.cs | 88 +++ build/build.csproj | 14 + build/packages.lock.json | 25 + global copy.json | 6 + .../EnumStringConverter.cs | 14 +- .../Narochno.Primitives.Json.csproj | 4 +- .../OptionalJsonConverter.cs | 35 -- .../packages.lock.json | 30 + .../DictionaryExtensions.cs | 15 +- .../EnumerableExtensions.cs | 16 +- src/Narochno.Primitives/IOptional.cs | 9 - .../Narochno.Primitives.csproj | 2 +- src/Narochno.Primitives/NotNullExtensions.cs | 103 ++++ src/Narochno.Primitives/Optional.cs | 53 -- src/Narochno.Primitives/OptionalExtensions.cs | 29 - .../Parsing/DefaultParserLibrary.cs | 18 +- src/Narochno.Primitives/Parsing/IParser.cs | 2 +- src/Narochno.Primitives/Parsing/Parser.cs | 4 +- .../Parsing/Parsers/EnumParser.cs | 27 +- .../Parsing/Parsers/GuidParser.cs | 2 +- .../Parsing/StringExtensions.cs | 6 +- src/Narochno.Primitives/TypeExtensions.cs | 4 +- src/Narochno.Primitives/packages.lock.json | 22 + .../EnumStringConverterTests.cs | 6 +- .../Narochno.Primitives.Json.Tests.csproj | 8 +- .../OptionalJsonConverterTests.cs | 57 -- .../packages.lock.json | 117 ++++ .../DictionaryExtensionsTests.cs | 20 +- .../EnumParserTests.cs | 16 +- .../EnumerableExtensionsTests.cs | 39 +- .../Narochno.Primitives.Tests.csproj | 8 +- .../OptionalEqualityTests.cs | 53 -- .../OptionalExtensionsTests.cs | 75 --- .../OptionalTests.cs | 76 --- .../ParsingBenchmarks.cs | 6 +- .../PrimitiveParserTests.cs | 4 +- .../packages.lock.json | 110 ++++ 44 files changed, 1226 insertions(+), 539 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/dotnetcore.yml create mode 100644 Directory.Build.props create mode 100644 Directory.Packages.props create mode 100644 NuGet.config create mode 100644 build/Program.cs create mode 100644 build/build.csproj create mode 100644 build/packages.lock.json create mode 100644 global copy.json delete mode 100644 src/Narochno.Primitives.Json/OptionalJsonConverter.cs create mode 100644 src/Narochno.Primitives.Json/packages.lock.json delete mode 100644 src/Narochno.Primitives/IOptional.cs create mode 100644 src/Narochno.Primitives/NotNullExtensions.cs delete mode 100644 src/Narochno.Primitives/Optional.cs delete mode 100644 src/Narochno.Primitives/OptionalExtensions.cs create mode 100644 src/Narochno.Primitives/packages.lock.json delete mode 100644 test/Narochno.Primitives.Json.Tests/OptionalJsonConverterTests.cs create mode 100644 test/Narochno.Primitives.Json.Tests/packages.lock.json delete mode 100644 test/Narochno.Primitives.Tests/OptionalEqualityTests.cs delete mode 100644 test/Narochno.Primitives.Tests/OptionalExtensionsTests.cs delete mode 100644 test/Narochno.Primitives.Tests/OptionalTests.cs create mode 100644 test/Narochno.Primitives.Tests/packages.lock.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1953cba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,570 @@ +# Version: 2.0.1 (Using https://semver.org/) +# Updated: 2020-12-11 +# See https://github.com/RehanSaeed/EditorConfig/releases for release notes. +# See https://github.com/RehanSaeed/EditorConfig for updates to this file. +# See http://EditorConfig.org for more information about .editorconfig files. + +########################################## +# Common Settings +########################################## + +# This file is the top-most EditorConfig file +root = true + +# All Files +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +########################################## +# File Extension Settings +########################################## + +# Visual Studio Solution Files +[*.sln] +indent_style = tab + +# Visual Studio XML Project Files +[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML Configuration Files +[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] +indent_size = 2 + +# JSON Files +[*.{json,json5,webmanifest}] +indent_size = 2 + +# YAML Files +[*.{yml,yaml}] +indent_size = 2 + +# Markdown Files +[*.md] +trim_trailing_whitespace = false + +# Web Files +[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}] +indent_size = 2 + +# Batch Files +[*.{cmd,bat}] +end_of_line = crlf + +# Bash Files +[*.sh] +end_of_line = lf + +# Makefiles +[Makefile] +indent_style = tab + +########################################## +# Default .NET Code Style Severities +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope +########################################## + +[*.{cs,csx,cake,vb,vbx}] +# Default Severity for all .NET Code Style rules below +dotnet_analyzer_diagnostic.severity = none + +########################################## +# File Header (Uncomment to support file headers) +# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header +########################################## + +# [*.{cs,csx,cake,vb,vbx}] +# file_header_template = \n© PROJECT-AUTHOR\n + +# SA1636: File header copyright text should match +# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project. +# dotnet_diagnostic.SA1636.severity = none + +########################################## +# .NET Language Conventions +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions +########################################## + +# .NET Code Style Settings +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings +[*.{cs,csx,cake,vb,vbx}] +# "this." and "Me." qualifiers +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me +#dotnet_style_qualification_for_field = true:warning +#dotnet_style_qualification_for_property = true:warning +#dotnet_style_qualification_for_method = true:warning +#dotnet_style_qualification_for_event = true:warning +# Language keywords instead of framework type names for type references +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning +# Modifier preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers +dotnet_style_require_accessibility_modifiers = always:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning +dotnet_style_readonly_field = true:warning +# Parentheses preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion +# Expression-level preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion +dotnet_diagnostic.IDE0045.severity = suggestion +dotnet_style_prefer_conditional_expression_over_return = false:suggestion +dotnet_diagnostic.IDE0046.severity = suggestion +dotnet_style_prefer_compound_assignment = true:warning +# Null-checking preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences +dotnet_style_coalesce_expression = true:warning +dotnet_style_null_propagation = true:warning +# Parameter preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences +dotnet_code_quality_unused_parameters = all:warning +# More style options (Undocumented) +# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641 +dotnet_style_operator_placement_when_wrapping = end_of_line +# https://github.com/dotnet/roslyn/pull/40070 +dotnet_style_prefer_simplified_interpolation = true:warning + +# C# Code Style Settings +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings +[*.{cs,csx,cake}] +# Implicit and explicit types +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning +# Expression-bodied members +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_operators = true:warning +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = true:warning +# Pattern matching +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning +# Inlined variable declarations +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations +csharp_style_inlined_variable_declaration = true:warning +# Expression-level preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences +csharp_prefer_simple_default_expression = true:warning +# "Null" checking preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences +csharp_style_throw_expression = true:warning +csharp_style_conditional_delegate_call = true:warning +# Code block preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences +csharp_prefer_braces = true:warning +# Unused value preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences +csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion +dotnet_diagnostic.IDE0058.severity = suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +dotnet_diagnostic.IDE0059.severity = suggestion +# Index and range preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_range_operator = true:warning +# Miscellaneous preferences +# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_using_directive_placement = outside_namespace:warning +csharp_prefer_static_local_function = true:warning +csharp_prefer_simple_using_statement = true:suggestion +dotnet_diagnostic.IDE0063.severity = suggestion + +########################################## +# .NET Formatting Conventions +# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions +########################################## + +# Organize usings +# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives +dotnet_sort_system_directives_first = true +# Newline options +# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation options +# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = no_change +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents_when_block = false +# Spacing options +# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_after_comma = true +csharp_space_before_comma = false +csharp_space_after_dot = false +csharp_space_before_dot = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_before_semicolon_in_for_statement = false +csharp_space_around_declaration_statements = false +csharp_space_before_open_square_brackets = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_square_brackets = false +# Wrapping options +# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true + +csharp_style_namespace_declarations = file_scoped + +########################################## +# .NET Naming Conventions +# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions +########################################## + +[*.{cs,csx,cake,vb,vbx}] +dotnet_diagnostic.CA1000.severity = suggestion +dotnet_diagnostic.CA1001.severity = error +dotnet_diagnostic.CA1018.severity = error +dotnet_diagnostic.CA1036.severity = silent +dotnet_diagnostic.CA1051.severity = suggestion +dotnet_diagnostic.CA1068.severity = error +dotnet_diagnostic.CA1069.severity = error +dotnet_diagnostic.CA1304.severity = error +dotnet_diagnostic.CA1305.severity = suggestion +dotnet_diagnostic.CA1307.severity = suggestion +dotnet_diagnostic.CA1309.severity = suggestion +dotnet_diagnostic.CA1310.severity = error +dotnet_diagnostic.CA1507.severity = suggestion +dotnet_diagnostic.CA1510.severity = suggestion +dotnet_diagnostic.CA1513.severity = suggestion +dotnet_diagnostic.CA1707.severity = suggestion +dotnet_diagnostic.CA1708.severity = suggestion +dotnet_diagnostic.CA1711.severity = suggestion +dotnet_diagnostic.CA1716.severity = suggestion +dotnet_diagnostic.CA1720.severity = suggestion +dotnet_diagnostic.CA1725.severity = suggestion +dotnet_diagnostic.CA1805.severity = suggestion +dotnet_diagnostic.CA1816.severity = suggestion +dotnet_diagnostic.CA1822.severity = suggestion +dotnet_diagnostic.CA1825.severity = error +dotnet_diagnostic.CA1826.severity = silent +dotnet_diagnostic.CA1827.severity = error +dotnet_diagnostic.CA1829.severity = suggestion +dotnet_diagnostic.CA1834.severity = error +dotnet_diagnostic.CA1845.severity = suggestion +dotnet_diagnostic.CA1848.severity = suggestion +dotnet_diagnostic.CA1852.severity = suggestion +dotnet_diagnostic.CA1859.severity = suggestion +dotnet_diagnostic.CA1860.severity = suggestion +dotnet_diagnostic.CA1861.severity = suggestion +dotnet_diagnostic.CA2016.severity = suggestion +dotnet_diagnostic.CA2201.severity = error +dotnet_diagnostic.CA2206.severity = error +dotnet_diagnostic.CA2208.severity = error +dotnet_diagnostic.CA2211.severity = error +dotnet_diagnostic.CA2249.severity = error +dotnet_diagnostic.CA2251.severity = error +dotnet_diagnostic.CA2252.severity = none +dotnet_diagnostic.CA2254.severity = suggestion + +dotnet_diagnostic.CS0169.severity = error +dotnet_diagnostic.CS0219.severity = error +dotnet_diagnostic.CS1998.severity = error +dotnet_diagnostic.CS8602.severity = error +dotnet_diagnostic.CS8604.severity = error +dotnet_diagnostic.CS8618.severity = error +dotnet_diagnostic.CS0618.severity = error +dotnet_diagnostic.CS1998.severity = error +dotnet_diagnostic.CS4014.severity = error +dotnet_diagnostic.CS8600.severity = error +dotnet_diagnostic.CS8603.severity = error +dotnet_diagnostic.CS8625.severity = error + +dotnet_diagnostic.BL0005.severity = suggestion + +dotnet_diagnostic.MVC1000.severity = suggestion + +dotnet_diagnostic.RZ10012.severity = error + +dotnet_diagnostic.IDE0004.severity = error # redundant cast +dotnet_diagnostic.IDE0005.severity = suggestion +dotnet_diagnostic.IDE0007.severity = error # Use var +dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements +dotnet_diagnostic.IDE0010.severity = silent # populate switch +dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified +dotnet_diagnostic.IDE0021.severity = silent # expression body for constructors +dotnet_diagnostic.IDE0022.severity = silent # expression body for methods +dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators +dotnet_diagnostic.IDE0024.severity = silent # expression body for operators +dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties +dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors +dotnet_diagnostic.IDE0028.severity = silent +dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property +dotnet_diagnostic.IDE0033.severity = error # prefer tuple name +dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type +dotnet_diagnostic.IDE0040.severity = error # modifiers required +dotnet_diagnostic.IDE0041.severity = error # simplify null +dotnet_diagnostic.IDE0042.severity = error # deconstruct variable +dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible +dotnet_diagnostic.IDE0047.severity = suggestion # paratemeter name +dotnet_diagnostic.IDE0051.severity = error # unused field +dotnet_diagnostic.IDE0052.severity = error # unused member +dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed +dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting +dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified +dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters +dotnet_diagnostic.IDE0061.severity = suggestion # local expression body +dotnet_diagnostic.IDE0062.severity = suggestion # local to static +dotnet_diagnostic.IDE0063.severity = error # simplify using +dotnet_diagnostic.IDE0066.severity = suggestion # switch expression +dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified +dotnet_diagnostic.IDE0078.severity = suggestion # use pattern matching +dotnet_diagnostic.IDE0090.severity = suggestion # new can be simplified +dotnet_diagnostic.IDE0130.severity = suggestion # namespace folder structure +dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required +dotnet_diagnostic.IDE0161.severity = error # Please use file namespaces +dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed +dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters +dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching +dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation +dotnet_diagnostic.IDE0290.severity = suggestion # Primary Constructor +dotnet_diagnostic.IDE0300.severity = suggestion # Collection +dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList + +dotnet_diagnostic.NX0001.severity = error +dotnet_diagnostic.NX0002.severity = silent +dotnet_diagnostic.NX0003.severity = silent + +########################################## +# Styles +########################################## + +# camel_case_style - Define the camelCase style +dotnet_naming_style.camel_case_style.capitalization = camel_case +# pascal_case_style - Define the PascalCase style +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# constant_case - Define the CONSTANT_CASE style +dotnet_naming_style.constant_case.capitalization = all_upper +dotnet_naming_style.constant_case.word_separator = _ +# first_upper_style - The first character must start with an upper-case character +dotnet_naming_style.first_upper_style.capitalization = first_word_upper +# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' +dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case +dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I +# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T' +dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case +dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T +# disallowed_style - Anything that has this style applied is marked as disallowed +dotnet_naming_style.disallowed_style.capitalization = pascal_case +dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____ +dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____ +# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file +dotnet_naming_style.internal_error_style.capitalization = pascal_case +dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____ +dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____ + +# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' +dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case +dotnet_naming_style.underscore_camel_case_style.required_prefix = _ + +########################################## +# .NET Design Guideline Field Naming Rules +# Naming rules for fields follow the .NET Framework design guidelines +# https://docs.microsoft.com/dotnet/standard/design-guidelines/index +########################################## + +# All public/protected/protected_internal constant fields must be constant_case +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = constant_case +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning + +# All public/protected/protected_internal static readonly fields must be constant_case +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = constant_case +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No other public/protected/protected_internal fields are allowed +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error + +########################################## +# StyleCop Field Naming Rules +# Naming rules for fields follow the StyleCop analyzers +# This does not override any rules using disallowed_style above +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers +########################################## + +# All constant fields must be constant_case +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = constant_case +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning + +# All static readonly fields must be constant_case +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = constant_case +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No non-private instance fields are allowed +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error + +# Private fields must be camelCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md +dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private +dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = underscore_camel_case_style +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning + +# Local variables must be camelCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md +dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local +dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = warning + +# This rule should never fire. However, it's included for at least two purposes: +# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers. +# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#). +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = * +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error + + +########################################## +# Other Naming Rules +########################################## + +# All of the following must be PascalCase: +# - Namespaces +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Classes and Enumerations +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Delegates +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types +# - Constructors, Properties, Events, Methods +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members +dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property +dotnet_naming_rule.element_rule.symbols = element_group +dotnet_naming_rule.element_rule.style = pascal_case_style +dotnet_naming_rule.element_rule.severity = warning + +# Interfaces use PascalCase and are prefixed with uppercase 'I' +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.interface_group.applicable_kinds = interface +dotnet_naming_rule.interface_rule.symbols = interface_group +dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style +dotnet_naming_rule.interface_rule.severity = warning + +# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T' +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter +dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group +dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style +dotnet_naming_rule.type_parameter_rule.severity = warning + +# Function parameters use camelCase +# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters +dotnet_naming_symbols.parameters_group.applicable_kinds = parameter +dotnet_naming_rule.parameters_rule.symbols = parameters_group +dotnet_naming_rule.parameters_rule.style = camel_case_style +dotnet_naming_rule.parameters_rule.severity = warning + +########################################## +# License +########################################## +# The following applies as to the .editorconfig file ONLY, and is +# included below for reference, per the requirements of the license +# corresponding to this .editorconfig file. +# See: https://github.com/RehanSaeed/EditorConfig +# +# MIT License +# +# Copyright (c) 2017-2019 Muhammad Rehan Saeed +# Copyright (c) 2019 Henry Gabryjelski +# +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, +# sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +########################################## diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6753405 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" # search for actions - there are other options available + directory: "/" # search in .github/workflows under root `/` + schedule: + interval: "weekly" # check for action update every week diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 0000000..0f9b4a0 --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,22 @@ +name: Narochno.EnvFile +on: + push: + branches: + - 'master' + pull_request: + types: [ opened, synchronize, reopened, ready_for_review ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + - run: dotnet run --project build/build.csproj + - uses: actions/upload-artifact@v4 + with: + name: narochno.envfile.nupkg + path: artifacts/* diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..b3d0b59 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,16 @@ + + + latest + enable + Recommended + true + true + true + true + true + False + False + true + true + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..5481e2e --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Narochno.Primitives.sln b/Narochno.Primitives.sln index 0d4b984..0cb56e5 100644 --- a/Narochno.Primitives.sln +++ b/Narochno.Primitives.sln @@ -15,6 +15,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Narochno.Primitives.Tests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Narochno.Primitives.Json.Tests", "test\Narochno.Primitives.Json.Tests\Narochno.Primitives.Json.Tests.csproj", "{E04F8B42-125C-4362-93A4-0B2E57112AA6}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{ED5BB2CC-D22A-4CA3-A773-B796036EB7EA}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + global.json = global.json + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 0000000..4825921 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/build/Program.cs b/build/Program.cs new file mode 100644 index 0000000..1ca0a30 --- /dev/null +++ b/build/Program.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.IO; +using GlobExpressions; +using static Bullseye.Targets; +using static SimpleExec.Command; + +const string Clean = "clean"; +const string Restore = "restore"; +const string Build = "build"; +const string Test = "test"; +const string Format = "format"; +const string Publish = "publish"; + +Target( + Clean, + ForEach("**/bin", "**/obj"), + dir => + { + IEnumerable GetDirectories(string d) + { + return Glob.Directories(".", d); + } + + void RemoveDirectory(string d) + { + if (Directory.Exists(d)) + { + Console.WriteLine(d); + Directory.Delete(d, true); + } + } + + foreach (var d in GetDirectories(dir)) + { + RemoveDirectory(d); + } + } +); + +Target( + Format, + () => + { + Run("dotnet", "tool restore"); + Run("dotnet", "csharpier --check ."); + } +); +Target(Restore, DependsOn(Format), () => Run("dotnet", "restore")); + +Target( + Build, + DependsOn(Restore), + () => + { + Run("dotnet", "build src/Narochno.EnvFile/Narochno.EnvFile.csproj -c Release --no-restore"); + } +); + +Target( + Test, + DependsOn(Build), + () => + { + IEnumerable GetFiles(string d) + { + return Glob.Files(".", d); + } + + foreach (var file in GetFiles("**/*.Test.csproj")) + { + Run("dotnet", $"test {file} -c Release -f net8.0 --no-restore --verbosity=normal"); + } + } +); + +Target( + Publish, + DependsOn(Test), + () => + { + Run("dotnet", "pack src/Narochno.EnvFile/Narochno.EnvFile.csproj -c Release -o artifacts/"); + } +); + +Target("default", DependsOn(Publish), () => Console.WriteLine("Done!")); + +await RunTargetsAndExitAsync(args); diff --git a/build/build.csproj b/build/build.csproj new file mode 100644 index 0000000..e0dffc7 --- /dev/null +++ b/build/build.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + + + + + + + + + diff --git a/build/packages.lock.json b/build/packages.lock.json new file mode 100644 index 0000000..8a8fa2c --- /dev/null +++ b/build/packages.lock.json @@ -0,0 +1,25 @@ +{ + "version": 2, + "dependencies": { + "net8.0": { + "Bullseye": { + "type": "Direct", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "bqyt+m17ym+5aN45C5oZRAjuLDt8jKiCm/ys1XfymIXSkrTFwvI/QsbY3ucPSHDz7SF7uON7B57kXFv5H2k1ew==" + }, + "Glob": { + "type": "Direct", + "requested": "[1.1.9, )", + "resolved": "1.1.9", + "contentHash": "AfK5+ECWYTP7G3AAdnU8IfVj+QpGjrh9GC2mpdcJzCvtQ4pnerAGwHsxJ9D4/RnhDUz2DSzd951O/lQjQby2Sw==" + }, + "SimpleExec": { + "type": "Direct", + "requested": "[12.0.0, )", + "resolved": "12.0.0", + "contentHash": "ptxlWtxC8vM6Y6e3h9ZTxBBkOWnWrm/Sa1HT+2i1xcXY3Hx2hmKDZP5RShPf8Xr9D+ivlrXNy57ktzyH8kyt+Q==" + } + } + } +} \ No newline at end of file diff --git a/global copy.json b/global copy.json new file mode 100644 index 0000000..391ba3c --- /dev/null +++ b/global copy.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestFeature" + } +} diff --git a/src/Narochno.Primitives.Json/EnumStringConverter.cs b/src/Narochno.Primitives.Json/EnumStringConverter.cs index c5a4aa9..a5f7efb 100644 --- a/src/Narochno.Primitives.Json/EnumStringConverter.cs +++ b/src/Narochno.Primitives.Json/EnumStringConverter.cs @@ -20,26 +20,22 @@ public EnumStringConverter(IParserLibrary parserLibrary) public override bool CanConvert(Type objectType) { -#if PORTABLE40 - return objectType.GetNullableUnderlyingType().IsEnum; -#else return objectType.GetNullableUnderlyingType().GetTypeInfo().IsEnum; -#endif } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (objectType.IsNullable() && reader.Value == null) { return existingValue; } - return parserLibrary.GetParser(objectType.GetNullableUnderlyingType()).Parse(reader.Value?.ToString()); + return parserLibrary.GetParser(objectType.GetNullableUnderlyingType().NotNull()).Parse(reader.Value.NotNull().ToString()); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - var parser = parserLibrary.GetParser(value.GetType()); - writer.WriteValue(parser.ToString(value)); } + var parser = parserLibrary.GetParser(value.NotNull().GetType().NotNull()); + writer.WriteValue(parser.ToString(value.NotNull())); } } } diff --git a/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj b/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj index bbbfced..e8d622d 100644 --- a/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj +++ b/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj @@ -15,8 +15,8 @@ - + - + diff --git a/src/Narochno.Primitives.Json/OptionalJsonConverter.cs b/src/Narochno.Primitives.Json/OptionalJsonConverter.cs deleted file mode 100644 index 45bb976..0000000 --- a/src/Narochno.Primitives.Json/OptionalJsonConverter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Newtonsoft.Json; -using System.Reflection; - -namespace Narochno.Primitives.Json -{ - public class OptionalJsonConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { -#if PORTABLE40 - return typeof(IOptional).IsAssignableFrom(objectType); -#else - return typeof(IOptional).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); -#endif - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { -#if PORTABLE40 - var type = objectType.GetGenericArguments()[0]; -#else - var type = objectType.GetTypeInfo().GenericTypeArguments[0]; -#endif - var optionalType = typeof(Optional<>).MakeGenericType(type); - return Activator.CreateInstance(optionalType, Convert.ChangeType(reader.Value, type, null)); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var optional = value as IOptional; - serializer.Serialize(writer, optional.HasValue ? optional.Value : null); - } - } -} diff --git a/src/Narochno.Primitives.Json/packages.lock.json b/src/Narochno.Primitives.Json/packages.lock.json new file mode 100644 index 0000000..090ea04 --- /dev/null +++ b/src/Narochno.Primitives.Json/packages.lock.json @@ -0,0 +1,30 @@ +{ + "version": 2, + "dependencies": { + ".NETStandard,Version=v2.0": { + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Newtonsoft.Json": { + "type": "Direct", + "requested": "[13.0.2, )", + "resolved": "13.0.2", + "contentHash": "R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "narochno.primitives": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/src/Narochno.Primitives/DictionaryExtensions.cs b/src/Narochno.Primitives/DictionaryExtensions.cs index bceceba..651f62c 100644 --- a/src/Narochno.Primitives/DictionaryExtensions.cs +++ b/src/Narochno.Primitives/DictionaryExtensions.cs @@ -4,26 +4,15 @@ namespace Narochno.Primitives { public static class DictionaryExtensions { - public static Optional GetObject(this IDictionary dictionary, TKey key) - where TValue : class - { - if (!dictionary.ContainsKey(key)) - { - return new Optional(); - } - - return dictionary[key]; - } - public static TValue? GetValue(this IDictionary dictionary, TKey key) where TValue : struct { - if (!dictionary.ContainsKey(key)) + if (!dictionary.TryGetValue(key, out var value)) { return null; } - return dictionary[key]; + return value; } } } diff --git a/src/Narochno.Primitives/EnumerableExtensions.cs b/src/Narochno.Primitives/EnumerableExtensions.cs index 5448eab..f52db1b 100644 --- a/src/Narochno.Primitives/EnumerableExtensions.cs +++ b/src/Narochno.Primitives/EnumerableExtensions.cs @@ -5,18 +5,6 @@ namespace Narochno.Primitives { public static class EnumerableExtensions { - public static Optional SingleOrOptional(this IEnumerable items) - where T : class - { - return new Optional(items.SingleOrDefault()); - } - - public static Optional FirstOrOptional(this IEnumerable items) - where T : class - { - return new Optional(items.FirstOrDefault()); - } - public static IEnumerable AsEnumerable(this T item) { if (item != null) @@ -28,7 +16,7 @@ public static IEnumerable AsEnumerable(this T item) public static IEnumerable> Batch( this IEnumerable source, int size) { - TSource[] bucket = null; + TSource[]? bucket = null; var count = 0; foreach (var item in source) @@ -56,4 +44,4 @@ public static IEnumerable> Batch( } } } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/IOptional.cs b/src/Narochno.Primitives/IOptional.cs deleted file mode 100644 index 5914b0d..0000000 --- a/src/Narochno.Primitives/IOptional.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Narochno.Primitives -{ - public interface IOptional - { - bool HasValue { get; } - bool HasNoValue { get; } - object Value { get; } - } -} \ No newline at end of file diff --git a/src/Narochno.Primitives/Narochno.Primitives.csproj b/src/Narochno.Primitives/Narochno.Primitives.csproj index 78aa08d..d24fe21 100644 --- a/src/Narochno.Primitives/Narochno.Primitives.csproj +++ b/src/Narochno.Primitives/Narochno.Primitives.csproj @@ -4,7 +4,7 @@ Classes designed to make working with C# code easier. 3.0.1 alanedwardes;adamhathcock - netstandard2.0 + net8.0;netstandard2.0 Narochno.Primitives Narochno.Primitives csharp;primitives;netcore diff --git a/src/Narochno.Primitives/NotNullExtensions.cs b/src/Narochno.Primitives/NotNullExtensions.cs new file mode 100644 index 0000000..85dda67 --- /dev/null +++ b/src/Narochno.Primitives/NotNullExtensions.cs @@ -0,0 +1,103 @@ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Narochno.Primitives; + +public static class NotNullExtensions +{ + public static IEnumerable Empty(this IEnumerable? source) => source ?? Enumerable.Empty(); +#if NET8_0 + public static async Task NotNull(this Task task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + where T : class + { + var x = await task; + ArgumentNullException.ThrowIfNull(x, paramName); + return x; + } + public static async ValueTask NotNull(this ValueTask task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + where T : class + { + var x = await task; + ArgumentNullException.ThrowIfNull(x, paramName); + return x; + } + + public static async Task NotNull(this Task task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + where T : struct + { + var x = await task; + ArgumentNullException.ThrowIfNull(x, paramName); + return x.Value; + } + public static async ValueTask NotNull(this ValueTask task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + where T : struct + { + var x = await task; + ArgumentNullException.ThrowIfNull(x, paramName); + return x.Value; + } + + public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) + where T : class + { + ArgumentNullException.ThrowIfNull(obj, paramName); + return obj; + } + + public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) + where T : struct + { + ArgumentNullException.ThrowIfNull(obj, paramName); + return obj.Value; + } + #else + + public static async Task NotNull(this Task task, string? message = null) + where T : class + { + var x = await task; + if (x is null) + { + throw new ArgumentNullException(message ?? "Value is null"); + } + return x; + } + + public static async Task NotNull(this Task task, string? message = null) + where T : struct + { + var x = await task; + if (x is null) + { + throw new ArgumentNullException(message ?? "Value is null"); + } + return x.Value; + } + + public static T NotNull(this T? obj, string? message = null) + where T : class + { + if (obj is null) + { + throw new ArgumentNullException(message ?? "Value is null"); + } + return obj; + } + + public static T NotNull(this T? obj, string? message = null) + where T : struct + { + if (obj is null) + { + throw new ArgumentNullException(message ?? "Value is null"); + } + return obj.Value; + } + +#endif +} diff --git a/src/Narochno.Primitives/Optional.cs b/src/Narochno.Primitives/Optional.cs deleted file mode 100644 index cd9c91a..0000000 --- a/src/Narochno.Primitives/Optional.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; - -namespace Narochno.Primitives -{ - public struct Optional : IOptional - where TValue : class - { - private readonly TValue value; - - public Optional(TValue value) - { - HasValue = value != null; - this.value = value; - } - - public TValue Value - { - get - { - if (HasNoValue) - { - throw new InvalidOperationException($"Optional<{typeof(TValue).Name}> is not set"); - } - - return value; - } - } - - public bool HasNoValue => !HasValue; - public bool HasValue { get; } - object IOptional.Value => Value; - - public override string ToString() => value?.ToString() ?? "Not Set"; - public override int GetHashCode() => value?.GetHashCode() ?? 0; - public static implicit operator Optional(TValue value) => new Optional(value); - - public override bool Equals(object obj) - { - if ((obj is TValue)) - { - return Equals(value, obj); - } - - if (!(obj is Optional)) - { - return false; - } - - var other = (Optional)obj; - return Equals(value, other.value); - } - } -} diff --git a/src/Narochno.Primitives/OptionalExtensions.cs b/src/Narochno.Primitives/OptionalExtensions.cs deleted file mode 100644 index d94eeb4..0000000 --- a/src/Narochno.Primitives/OptionalExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Narochno.Primitives -{ - public static class OptionalExtensions - { - public static Optional Optional(this TType value) - where TType : class - { - return new Optional(value); - } - - public static Optional Fallback(this Optional value, Optional fallback) - where TType : class - { - return value.HasValue ? value.Value : fallback; - } - - public static TType Fallback(this Optional value, TType fallback) - where TType : class - { - return value.HasValue ? value.Value : fallback; - } - - public static TType Unwrap(this Optional value) - where TType : class - { - return value.HasValue ? value.Value : default(TType); - } - } -} diff --git a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs index 46aff4d..271e54f 100644 --- a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs +++ b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs @@ -7,8 +7,8 @@ namespace Narochno.Primitives.Parsing { public class DefaultParserLibrary : IParserLibrary { - private static object lockObject = new object(); - public static IParserLibrary Instance { get; set; } = new DefaultParserLibrary(); + private static object lockObject = new(); + public static IParserLibrary Instance { get; } = new DefaultParserLibrary(); public IDictionary Parsers { get; } = new Dictionary { @@ -29,27 +29,23 @@ public class DefaultParserLibrary : IParserLibrary public IParser GetParser(Type type) { - if (Parsers.ContainsKey(type)) + if (Parsers.TryGetValue(type, out var parser1)) { - return Parsers[type]; + return parser1; } lock (lockObject) { - if (Parsers.ContainsKey(type)) + if (Parsers.TryGetValue(type, value: out var parser)) { - return Parsers[type]; + return parser; } // Enums need type information, // so each one gets a parser -#if PORTABLE40 - if (type.IsEnum) -#else if (type.GetTypeInfo().IsEnum) -#endif { - Parsers.Add(type, (IParser) Activator.CreateInstance(typeof(EnumParser<>).MakeGenericType(type))); + Parsers.Add(type, (IParser) Activator.CreateInstance(typeof(EnumParser<>).MakeGenericType(type)).NotNull()); return Parsers[type]; } diff --git a/src/Narochno.Primitives/Parsing/IParser.cs b/src/Narochno.Primitives/Parsing/IParser.cs index 5a4519c..a7294ad 100644 --- a/src/Narochno.Primitives/Parsing/IParser.cs +++ b/src/Narochno.Primitives/Parsing/IParser.cs @@ -12,7 +12,7 @@ public interface IParser /// /// The input string to convert from /// A converted object - object TryParse(string input); + object? TryParse(string input); /// /// Convert from to the type diff --git a/src/Narochno.Primitives/Parsing/Parser.cs b/src/Narochno.Primitives/Parsing/Parser.cs index 89f0e6a..351ccc9 100644 --- a/src/Narochno.Primitives/Parsing/Parser.cs +++ b/src/Narochno.Primitives/Parsing/Parser.cs @@ -8,7 +8,7 @@ public abstract class Parser : IParser, IParser where TType : struct { object IParser.Parse(string input) => Parse(input); - object IParser.TryParse(string input) => TryParse(input); + object? IParser.TryParse(string input) => TryParse(input); string IParser.ToString(object input) => ToString((TType)input); /// @@ -29,4 +29,4 @@ public abstract class Parser : IParser, IParser public abstract string ToString(TType value); } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs index 7349834..4cb6e6a 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Narochno.Primitives.Parsing.Parsers { public class EnumParser: Parser - where T : struct + where T : struct { public Type Type { get; } - public List Values { get; } = new List(); + public List Values { get; } = new(); public IDictionary EnumStrings { get; } = new Dictionary(); public IDictionary EnumStringsReverse { get; } = new Dictionary(); @@ -24,7 +23,7 @@ public EnumParser() // Cache this as it's expensive to fetch foreach (var value in Values) { - foreach (var attribute in Type.GetField(Enum.GetName(Type, value)) + foreach (var attribute in Type.GetField(Enum.GetName(Type, value).NotNull()).NotNull() .GetCustomAttributes(false).OfType()) { EnumStrings.Add(attribute.Value, (T)value); @@ -33,31 +32,31 @@ public EnumParser() } } - public override T Parse(string input) + public override T Parse(string? input) { // First try to get the fields with EnumMemberAttribute - if (input != null && EnumStrings.ContainsKey(input)) + if (input != null && EnumStrings.TryGetValue(input, out var s)) { - return EnumStrings[input]; + return s; } // Fallback to the real Enum.Parse - return (T)Enum.Parse(Type, input, true); + return (T)Enum.Parse(Type, input.NotNull(), true); } - public override T? TryParse(string input) + public override T? TryParse(string? input) { // First try to get the fields with EnumMemberAttribute - if (input != null && EnumStrings.ContainsKey(input)) + if (input != null && EnumStrings.TryGetValue(input, out var s)) { - return EnumStrings[input]; + return s; } // Fallback to a try parse (we can't use the // real TryParse here as it has type parameters) foreach (var value in Values) { - if (Enum.GetName(Type, value).Equals(input)) + if (Enum.GetName(Type, value).NotNull().Equals(input)) { return value; } @@ -68,12 +67,12 @@ public override T Parse(string input) public override string ToString(T value) { - string s; + string? s; if (EnumStringsReverse.TryGetValue(value, out s)) { return s; } - return value.ToString(); + return value.ToString().NotNull(); } } } diff --git a/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs b/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs index 7e2cebb..30d36a8 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs @@ -19,7 +19,7 @@ public class GuidParser : Parser public override string ToString(Guid value) { - return Convert.ToString(value); + return Convert.ToString(value).NotNull(); } } } diff --git a/src/Narochno.Primitives/Parsing/StringExtensions.cs b/src/Narochno.Primitives/Parsing/StringExtensions.cs index d707148..7a437b6 100644 --- a/src/Narochno.Primitives/Parsing/StringExtensions.cs +++ b/src/Narochno.Primitives/Parsing/StringExtensions.cs @@ -11,7 +11,7 @@ public static class StringExtensions /// The input string /// The Optional parsed from the string public static TType? TryParse(this string input) - where TType : struct + where TType : struct { return DefaultParserLibrary.Instance.GetParser() .TryParse(input); @@ -23,7 +23,7 @@ public static class StringExtensions /// The input string /// The type to convert to /// The IOptional parsed from the string - public static object TryParse(this string input, Type type) + public static object? TryParse(this string input, Type type) { return DefaultParserLibrary.Instance.GetParser(type) .TryParse(input); @@ -36,7 +36,7 @@ public static object TryParse(this string input, Type type) /// The input string /// The type parsed from the string public static TType Parse(this string input) - where TType : struct + where TType : struct { return DefaultParserLibrary.Instance.GetParser() .Parse(input); diff --git a/src/Narochno.Primitives/TypeExtensions.cs b/src/Narochno.Primitives/TypeExtensions.cs index b42a88e..49aa33c 100644 --- a/src/Narochno.Primitives/TypeExtensions.cs +++ b/src/Narochno.Primitives/TypeExtensions.cs @@ -17,7 +17,7 @@ public static bool IsNullable(this Type type) } #endif - public static Type GetNullableUnderlyingType(this Type type) + public static Type? GetNullableUnderlyingType(this Type type) { if (type.IsNullable()) { @@ -27,4 +27,4 @@ public static Type GetNullableUnderlyingType(this Type type) return type; } } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/packages.lock.json b/src/Narochno.Primitives/packages.lock.json new file mode 100644 index 0000000..7e76f72 --- /dev/null +++ b/src/Narochno.Primitives/packages.lock.json @@ -0,0 +1,22 @@ +{ + "version": 2, + "dependencies": { + ".NETStandard,Version=v2.0": { + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + } + }, + "net8.0": {} + } +} \ No newline at end of file diff --git a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs index b08a8ab..3557c53 100644 --- a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs +++ b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs @@ -54,7 +54,7 @@ public void ExpectDeserialiseEnum() { var result = JsonConvert.DeserializeObject("{\"Test\":\"Second\"}", serializerSettings); - Assert.Equal(TestEnum.Two, result.Test); + Assert.Equal(TestEnum.Two, result?.Test); } [Fact] @@ -62,7 +62,7 @@ public void ExpectDeserialiseUnknownEnumString() { var result = JsonConvert.DeserializeObject("{\"Test\":\"Three\"}", serializerSettings); - Assert.Equal(TestEnum.Three, result.Test); + Assert.Equal(TestEnum.Three, result?.Test); } [Fact] @@ -87,7 +87,7 @@ public void ExpectDeserialiseNullableEnum() { var result = JsonConvert.DeserializeObject("{\"Test\":\"Second\"}", serializerSettings); - Assert.Equal(TestEnum.Two, result.Test); + Assert.Equal(TestEnum.Two, result?.Test); } [Fact] diff --git a/test/Narochno.Primitives.Json.Tests/Narochno.Primitives.Json.Tests.csproj b/test/Narochno.Primitives.Json.Tests/Narochno.Primitives.Json.Tests.csproj index 9de61d9..3fa8380 100644 --- a/test/Narochno.Primitives.Json.Tests/Narochno.Primitives.Json.Tests.csproj +++ b/test/Narochno.Primitives.Json.Tests/Narochno.Primitives.Json.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + net8.0 Narochno.Primitives.Json.Tests Narochno.Primitives.Json.Tests true @@ -12,9 +12,9 @@ - - - + + + diff --git a/test/Narochno.Primitives.Json.Tests/OptionalJsonConverterTests.cs b/test/Narochno.Primitives.Json.Tests/OptionalJsonConverterTests.cs deleted file mode 100644 index f2d9f1e..0000000 --- a/test/Narochno.Primitives.Json.Tests/OptionalJsonConverterTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Newtonsoft.Json; -using Xunit; - -namespace Narochno.Primitives.Json.Tests -{ - public class OptionalJsonConverterTests - { - class TestClass - { - public Optional String { get; set; } - public int? Integer { get; set; } - } - - class TestClassComplex - { - public Optional Test { get; set; } - } - - [Fact] - public void TestSerialisingWithValue() - { - var test = new TestClass { String = "test", Integer = 42 }; - - var serialised = JsonConvert.SerializeObject(test, new OptionalJsonConverter()); - - Assert.Equal("{\"String\":\"test\",\"Integer\":42}", serialised); - } - - [Fact] - public void TestSerialisingWithoutValue() - { - var test = new TestClass(); - - var serialised = JsonConvert.SerializeObject(test, new OptionalJsonConverter()); - - Assert.Equal("{\"String\":null,\"Integer\":null}", serialised); - } - - [Fact] - public void TestDeserialising() - { - var deserialised = JsonConvert.DeserializeObject("{\"String\":\"test\",\"Integer\":42}", new OptionalJsonConverter()); - - Assert.Equal("test", deserialised.String); - Assert.Equal(42, deserialised.Integer); - } - - [Fact(Skip = "Skipping, this needs work")] - public void TestComplexDeserialising() - { - var deserialised = JsonConvert.DeserializeObject("{\"Test\":{\"String\":\"test\",\"Integer\":42}}", new OptionalJsonConverter()); - - Assert.Equal("test", deserialised.Test.Value.String); - Assert.Equal(42, deserialised.Test.Value.Integer); - } - } -} diff --git a/test/Narochno.Primitives.Json.Tests/packages.lock.json b/test/Narochno.Primitives.Json.Tests/packages.lock.json new file mode 100644 index 0000000..83e7824 --- /dev/null +++ b/test/Narochno.Primitives.Json.Tests/packages.lock.json @@ -0,0 +1,117 @@ +{ + "version": 2, + "dependencies": { + "net8.0": { + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[17.9.0, )", + "resolved": "17.9.0", + "contentHash": "7GUNAUbJYn644jzwLm5BD3a2p9C1dmP8Hr6fDPDxgItQk9hBs1Svdxzz07KQ/UphMSmgza9AbijBJGmw5D658A==", + "dependencies": { + "Microsoft.CodeCoverage": "17.9.0", + "Microsoft.TestPlatform.TestHost": "17.9.0" + } + }, + "xunit": { + "type": "Direct", + "requested": "[2.8.0, )", + "resolved": "2.8.0", + "contentHash": "US3a3twJziAif1kFPGdk9fALwILHxV0n1roX5j67bN/d3o4DGNLHnV3tr5ZX+uinVrzfkf0avH3zGX8JPBC0qA==", + "dependencies": { + "xunit.analyzers": "1.13.0", + "xunit.assert": "2.8.0", + "xunit.core": "[2.8.0]" + } + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[2.8.0, )", + "resolved": "2.8.0", + "contentHash": "mqQbS2zr8dfgSWxkNOC6UTzO8JoqpTmM5+FFn2XR/2nVmx2JvEY0YbM5pt2FmXVg9YVe+jKUPHd6KrroyCl67w==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "RGD37ZSrratfScYXm7M0HjvxMxZyWZL4jm+XgMZbkIY1UPgjUpbNA/t+WTGj/rC/0Hm9A3IrH3ywbKZkOCnoZA==" + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "1ilw/8vgmjLyKU+2SKXKXaOqpYFJCQfGqGz+x0cosl981VzjrY74Sv6qAJv+neZMZ9ZMxF3ArN6kotaQ4uvEBw==", + "dependencies": { + "System.Reflection.Metadata": "1.6.0" + } + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "Spmg7Wx49Ya3SxBjyeAR+nQpjMTKZwTwpZ7KyeOTIqI/WHNPnBU4HUvl5kuHPQAwGWqMy4FGZja1HvEwvoaDiA==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.9.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.13.0", + "contentHash": "Pai9YnDV71/Ox14nBHB6/f62iyPyLbmUG/YYMiA4dfdFZvr0gIYE9yGxSr0i5Tr3INK75wgL2MCUNEKpeiZ2Fw==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "lwf7Dy5/5HbDkaPx1YrGXCByytCEEcIn+KPI74jh2BD/RU/7RhO8c+S3k0Ph+Mr7+cLf338fl+o6UcgPCLa6PA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "McSTFGTETCxLpmJKE9TWi9FtFthrRbpRrjz2V2g8sK2wRt1+JHs15vwi+B+nfftFkV9aFWIXZfzZM95TIGZNIA==", + "dependencies": { + "xunit.extensibility.core": "[2.8.0]", + "xunit.extensibility.execution": "[2.8.0]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "eBJv9xQeY0p5z+C/L1tFjUFYqtl5pQqIEYCGTMl+MbRzA7sOlgYKwJE//vEePBp+mgBh7NjD0Qhz0liZBYM27w==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "TyyrZesHB9ODZMS9c73OqiBz4x0vL944JCkSPBWW5w6PF2LlUfdfXRjjOhoIOuY6lTmEgl07rS4/Jot9mCYnpg==", + "dependencies": { + "xunit.extensibility.core": "[2.8.0]" + } + }, + "narochno.primitives": { + "type": "Project" + }, + "narochno.primitives.json": { + "type": "Project", + "dependencies": { + "Narochno.Primitives": "[3.0.1, )", + "Newtonsoft.Json": "[13.0.2, )" + } + }, + "Newtonsoft.Json": { + "type": "CentralTransitive", + "requested": "[13.0.2, )", + "resolved": "13.0.2", + "contentHash": "R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg==" + } + } + } +} \ No newline at end of file diff --git a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs index 71058f7..40cc0ff 100644 --- a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs @@ -5,24 +5,6 @@ namespace Narochno.Primitives.Tests { public class DictionaryExtensionsTests { - [Fact] - public void TestGetOptionalExists() - { - var dict = new Dictionary - { - { "test", "testing" } - }; - - Assert.Equal("testing", dict.GetObject("test").Value); - } - - [Fact] - public void TestGetOptionalNotExists() - { - var dict = new Dictionary(); - - Assert.False(dict.GetObject("test").HasValue); - } [Fact] public void TestGetNullableExists() @@ -32,7 +14,7 @@ public void TestGetNullableExists() { "test", 1 } }; - Assert.Equal(1, dict.GetValue("test").Value); + Assert.Equal(1, dict.GetValue("test").NotNull()); } [Fact] diff --git a/test/Narochno.Primitives.Tests/EnumParserTests.cs b/test/Narochno.Primitives.Tests/EnumParserTests.cs index a6ae67b..885deea 100644 --- a/test/Narochno.Primitives.Tests/EnumParserTests.cs +++ b/test/Narochno.Primitives.Tests/EnumParserTests.cs @@ -34,17 +34,17 @@ public void TestParseNoAttribute() [Fact] public void TestParseAttributeToOptional() { - Assert.Equal(TestEnum.One, "test_one".TryParse().Value); - Assert.Equal(TestEnum.Two, "test_two".TryParse().Value); - Assert.Equal(TestEnum.Three, "test_three".TryParse().Value); + Assert.Equal(TestEnum.One, "test_one".TryParse().NotNull()); + Assert.Equal(TestEnum.Two, "test_two".TryParse().NotNull()); + Assert.Equal(TestEnum.Three, "test_three".TryParse().NotNull()); } [Fact] public void TestParseNoAttributeToOptional() { - Assert.Equal(TestEnum.One, "One".TryParse().Value); - Assert.Equal(TestEnum.Two, "Two".TryParse().Value); - Assert.Equal(TestEnum.Three, "Three".TryParse().Value); + Assert.Equal(TestEnum.One, "One".TryParse().NotNull()); + Assert.Equal(TestEnum.Two, "Two".TryParse().NotNull()); + Assert.Equal(TestEnum.Three, "Three".TryParse().NotNull()); } [Fact] @@ -52,7 +52,7 @@ public void TestParseInvalid() { Assert.Throws(() => "lol".Parse()); Assert.Throws(() => string.Empty.Parse()); - Assert.Throws(() => ((string)null).Parse()); + Assert.Throws(() => ((string)null!).Parse()); } [Fact] @@ -60,7 +60,7 @@ public void TestParseInvalidToOptional() { Assert.False("lol".TryParse().HasValue); Assert.False(string.Empty.TryParse().HasValue); - Assert.False(((string)null).TryParse().HasValue); + Assert.False(((string)null!).TryParse().HasValue); } } } diff --git a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs index 0f729e9..59593f9 100644 --- a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs @@ -8,7 +8,7 @@ public class EnumerableExtensionsTests [Fact] public void TestAsEnumerable() { - string x = null; + string? x = null; Assert.Empty( x.AsEnumerable()); int y = 0; @@ -21,45 +21,12 @@ public void TestAsEnumerable() Assert.Empty(z.AsEnumerable()); } - [Fact] - public void TestFirstOrOptional() - { - var optional = "test".AsEnumerable().FirstOrOptional(); - - Assert.True(optional.HasValue); - Assert.Equal("test", optional.Value); - } - - [Fact] - public void TestFirstOrOptionalNoValue() - { - var optional = new string[0].FirstOrOptional(); - - Assert.False(optional.HasValue); - } - - [Fact] - public void TestSingleOrOptional() - { - var optional = "test".AsEnumerable().SingleOrOptional(); - - Assert.True(optional.HasValue); - Assert.Equal("test", optional.Value); - } - - [Fact] - public void TestSingleOrOptionalNoValue() - { - var optional = new string[0].SingleOrOptional(); - - Assert.False(optional.HasValue); - } [Fact] public void TestBatch() { - var items = new string[] {"a", "b", "c"}; + var items = new[] {"a", "b", "c"}; var batches = items.Batch(2).ToList(); @@ -73,4 +40,4 @@ public void TestBatch() Assert.Equal("c", b[0]); } } -} \ No newline at end of file +} diff --git a/test/Narochno.Primitives.Tests/Narochno.Primitives.Tests.csproj b/test/Narochno.Primitives.Tests/Narochno.Primitives.Tests.csproj index 6e5f07b..62d465b 100644 --- a/test/Narochno.Primitives.Tests/Narochno.Primitives.Tests.csproj +++ b/test/Narochno.Primitives.Tests/Narochno.Primitives.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + net8.0 Narochno.Primitives.Tests Narochno.Primitives.Tests true @@ -12,9 +12,9 @@ - - - + + + diff --git a/test/Narochno.Primitives.Tests/OptionalEqualityTests.cs b/test/Narochno.Primitives.Tests/OptionalEqualityTests.cs deleted file mode 100644 index ee48841..0000000 --- a/test/Narochno.Primitives.Tests/OptionalEqualityTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Xunit; - -namespace Narochno.Primitives.Tests -{ - public class OptionalEqualityTests - { - [Fact] - public void TestClassNotSetAndSetEquality() - { - var one = new Optional(); - var two = "test".Optional(); - - Assert.False(one.Equals(two)); - } - - [Fact] - public void TestClassNotSetEquality() - { - var one = new Optional(); - var two = new Optional(); - - Assert.True(one.Equals(two)); - } - - [Fact] - public void TestClassEquality() - { - var one = "one".Optional(); - var two = "one".Optional(); - - Assert.True(one.Equals(two)); - } - - [Fact] - public void TestClassNonEquality() - { - var one = "one".Optional(); - var two = "two".Optional(); - - Assert.False(one.Equals(two)); - } - - [Fact] - public void TestClassEqualityNonOptional() - { - var one = "one".Optional(); - var two = "one"; - - Assert.True(one.Equals(two)); - Assert.False(two.Equals(one)); - } - } -} diff --git a/test/Narochno.Primitives.Tests/OptionalExtensionsTests.cs b/test/Narochno.Primitives.Tests/OptionalExtensionsTests.cs deleted file mode 100644 index 7bfe1ec..0000000 --- a/test/Narochno.Primitives.Tests/OptionalExtensionsTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using Xunit; - -namespace Narochno.Primitives.Tests -{ - public class OptionalExtensionsTests - { - [Fact] - public void TestClassToOptional() - { - var optional = "test".Optional(); - - Assert.True(optional.HasValue); - Assert.Equal("test", optional.Value); - } - - [Fact] - public void TestFallbackOptional() - { - var missing = new Optional(); - - var result = missing.Fallback("fallback".Optional()); - Assert.True(result.HasValue); - Assert.Equal("fallback", result.Value); - } - - [Fact] - public void TestFallback() - { - var missing = new Optional(); - - var result = missing.Fallback("fallback"); - Assert.NotNull(result); - Assert.Equal("fallback", result); - } - - [Fact] - public void TestNoFallbackOptional() - { - var existing = "test".Optional(); - - var result = existing.Fallback("fallback".Optional()); - Assert.True(result.HasValue); - Assert.Equal("test", result.Value); - } - - [Fact] - public void TestNoFallback() - { - var existing = "test".Optional(); - - var result = existing.Fallback("fallback"); - Assert.NotNull(result); - Assert.Equal("test", result); - } - - [Fact] - public void TestUnwrapClass() - { - var original = "test"; - - var result = original.Optional(); - - Assert.Same(original, result.Unwrap()); - } - - [Fact] - public void TestUnwrapMissingClass() - { - var result = new Optional(); - - Assert.Null(result.Unwrap()); - } - } -} diff --git a/test/Narochno.Primitives.Tests/OptionalTests.cs b/test/Narochno.Primitives.Tests/OptionalTests.cs deleted file mode 100644 index c864525..0000000 --- a/test/Narochno.Primitives.Tests/OptionalTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using Xunit; - -namespace Narochno.Primitives.Tests -{ - public class OptionalTests - { - class TestClass { public override string ToString() => "test class"; } - - [Fact] - public void TestOptionalClassHasValue() - { - var test = new TestClass().Optional(); - Assert.True(test.HasValue); - Assert.False(test.HasNoValue); - } - - [Fact] - public void TestOptionalClassSetToString() - { - var test = new TestClass().Optional(); - Assert.Equal("test class", test.ToString()); - } - - [Fact] - public void TestOptionalHasNoValueToString() - { - var test = new Optional(); - Assert.Equal("Not Set", test.ToString()); - } - - [Fact] - public void TestOptionalHasNoValue() - { - var test = new Optional(); - Assert.False(test.HasValue); - Assert.True(test.HasNoValue); - } - - [Fact] - public void TestOptionalHasNoValueValueException() - { - var test = new Optional(); - Assert.Throws(() => test.Value); - } - - [Fact] - public void TestTypeToOptionalConversion() - { - var test = new TestClass(); - // A method that accepts an optional - new Action>(x => - { - Assert.True(x.HasValue); - Assert.False(x.HasNoValue); - Assert.Same(test, x.Value); - })(test); - } - - [Fact] - public void TestOptionalCastToValue() - { - var test = (Optional)new TestClass(); - Assert.True(test.HasValue); - Assert.False(test.HasNoValue); - } - - [Fact] - public void TestOptionalCastToNoValue() - { - var test = (Optional)null; - Assert.False(test.HasValue); - Assert.True(test.HasNoValue); - } - } -} diff --git a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs index ed237ef..82b2288 100644 --- a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs +++ b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs @@ -7,7 +7,7 @@ namespace Narochno.Primitives.Tests /// /// Test class to compare the timings of each /// parse method using a large number of iterations. - /// + /// /// A good way to use this class is to test before changes /// and afterwards, to see if/how the time to parse has changed. /// @@ -41,7 +41,7 @@ public void GenericBoolTryParse() { for (var i = 0; i < Iterations; i++) { - Assert.True("true".TryParse().Value); + Assert.True("true".TryParse().NotNull()); } } @@ -79,7 +79,7 @@ public void GenericEnumTryParse() { for (var i = 0; i < Iterations; i++) { - Assert.Equal(DateTimeKind.Utc, "Utc".TryParse().Value); + Assert.Equal(DateTimeKind.Utc, "Utc".TryParse().NotNull()); } } diff --git a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs index 4a4e073..0d9aae5 100644 --- a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs +++ b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs @@ -7,7 +7,7 @@ public class PrimitiveParserTests { public struct MyStruct { - + } [Theory] [InlineData(typeof(bool), "true", true)] @@ -42,7 +42,7 @@ public void Parse(Type type, string input, object expected) public void GuidToType() { Assert.Equal(new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), "433158F7-7B46-4E6D-8980-B5492D46F0DE".Parse()); - Assert.Equal(new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().Value); + Assert.Equal(new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().NotNull()); } [Fact] diff --git a/test/Narochno.Primitives.Tests/packages.lock.json b/test/Narochno.Primitives.Tests/packages.lock.json new file mode 100644 index 0000000..8cb7c63 --- /dev/null +++ b/test/Narochno.Primitives.Tests/packages.lock.json @@ -0,0 +1,110 @@ +{ + "version": 2, + "dependencies": { + "net8.0": { + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[17.9.0, )", + "resolved": "17.9.0", + "contentHash": "7GUNAUbJYn644jzwLm5BD3a2p9C1dmP8Hr6fDPDxgItQk9hBs1Svdxzz07KQ/UphMSmgza9AbijBJGmw5D658A==", + "dependencies": { + "Microsoft.CodeCoverage": "17.9.0", + "Microsoft.TestPlatform.TestHost": "17.9.0" + } + }, + "xunit": { + "type": "Direct", + "requested": "[2.8.0, )", + "resolved": "2.8.0", + "contentHash": "US3a3twJziAif1kFPGdk9fALwILHxV0n1roX5j67bN/d3o4DGNLHnV3tr5ZX+uinVrzfkf0avH3zGX8JPBC0qA==", + "dependencies": { + "xunit.analyzers": "1.13.0", + "xunit.assert": "2.8.0", + "xunit.core": "[2.8.0]" + } + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[2.8.0, )", + "resolved": "2.8.0", + "contentHash": "mqQbS2zr8dfgSWxkNOC6UTzO8JoqpTmM5+FFn2XR/2nVmx2JvEY0YbM5pt2FmXVg9YVe+jKUPHd6KrroyCl67w==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "RGD37ZSrratfScYXm7M0HjvxMxZyWZL4jm+XgMZbkIY1UPgjUpbNA/t+WTGj/rC/0Hm9A3IrH3ywbKZkOCnoZA==" + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "1ilw/8vgmjLyKU+2SKXKXaOqpYFJCQfGqGz+x0cosl981VzjrY74Sv6qAJv+neZMZ9ZMxF3ArN6kotaQ4uvEBw==", + "dependencies": { + "System.Reflection.Metadata": "1.6.0" + } + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "17.9.0", + "contentHash": "Spmg7Wx49Ya3SxBjyeAR+nQpjMTKZwTwpZ7KyeOTIqI/WHNPnBU4HUvl5kuHPQAwGWqMy4FGZja1HvEwvoaDiA==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.9.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.13.0", + "contentHash": "Pai9YnDV71/Ox14nBHB6/f62iyPyLbmUG/YYMiA4dfdFZvr0gIYE9yGxSr0i5Tr3INK75wgL2MCUNEKpeiZ2Fw==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "lwf7Dy5/5HbDkaPx1YrGXCByytCEEcIn+KPI74jh2BD/RU/7RhO8c+S3k0Ph+Mr7+cLf338fl+o6UcgPCLa6PA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "McSTFGTETCxLpmJKE9TWi9FtFthrRbpRrjz2V2g8sK2wRt1+JHs15vwi+B+nfftFkV9aFWIXZfzZM95TIGZNIA==", + "dependencies": { + "xunit.extensibility.core": "[2.8.0]", + "xunit.extensibility.execution": "[2.8.0]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "eBJv9xQeY0p5z+C/L1tFjUFYqtl5pQqIEYCGTMl+MbRzA7sOlgYKwJE//vEePBp+mgBh7NjD0Qhz0liZBYM27w==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "TyyrZesHB9ODZMS9c73OqiBz4x0vL944JCkSPBWW5w6PF2LlUfdfXRjjOhoIOuY6lTmEgl07rS4/Jot9mCYnpg==", + "dependencies": { + "xunit.extensibility.core": "[2.8.0]" + } + }, + "narochno.primitives": { + "type": "Project" + }, + "Newtonsoft.Json": { + "type": "CentralTransitive", + "requested": "[13.0.2, )", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + } + } + } +} \ No newline at end of file From a75411a30d6f3bd29ad01fc169be06600aa3068a Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:07:44 +0100 Subject: [PATCH 2/8] csharpier --- .config/dotnet-tools.json | 12 ++++ .../EnumStringConverter.cs | 20 ++++--- .../DictionaryExtensions.cs | 5 +- .../EnumerableExtensions.cs | 4 +- src/Narochno.Primitives/HexExtensions.cs | 2 +- src/Narochno.Primitives/NotNullExtensions.cs | 43 ++++++++++---- src/Narochno.Primitives/Parsing/Convert.cs | 2 +- .../Parsing/DefaultParserLibrary.cs | 45 ++++++++------ .../Parsing/IParserLibrary.cs | 2 +- src/Narochno.Primitives/Parsing/Parser.cs | 2 + .../Parsing/ParserExtensions.cs | 2 +- .../Parsing/Parsers/EnumParser.cs | 10 +++- .../Parsing/StringExtensions.cs | 12 ++-- src/Narochno.Primitives/TypeExtensions.cs | 5 +- .../EnumStringConverterTests.cs | 58 ++++++++++++++----- .../Narochno.Primitives.Tests/ConvertTests.cs | 2 +- .../DictionaryExtensionsTests.cs | 6 +- .../EnumParserTests.cs | 2 + .../EnumerableExtensionsTests.cs | 6 +- .../ParsingBenchmarks.cs | 9 ++- .../PrimitiveParserTests.cs | 14 +++-- 21 files changed, 173 insertions(+), 90 deletions(-) create mode 100644 .config/dotnet-tools.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..a271784 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "csharpier": { + "version": "0.28.2", + "commands": [ + "dotnet-csharpier" + ] + } + } +} \ No newline at end of file diff --git a/src/Narochno.Primitives.Json/EnumStringConverter.cs b/src/Narochno.Primitives.Json/EnumStringConverter.cs index a5f7efb..a6d3468 100644 --- a/src/Narochno.Primitives.Json/EnumStringConverter.cs +++ b/src/Narochno.Primitives.Json/EnumStringConverter.cs @@ -1,7 +1,7 @@ using System; -using Newtonsoft.Json; using System.Reflection; using Narochno.Primitives.Parsing; +using Newtonsoft.Json; namespace Narochno.Primitives.Json { @@ -9,9 +9,7 @@ public class EnumStringConverter : JsonConverter { private IParserLibrary parserLibrary = DefaultParserLibrary.Instance; - public EnumStringConverter() - { - } + public EnumStringConverter() { } public EnumStringConverter(IParserLibrary parserLibrary) { @@ -23,19 +21,27 @@ public override bool CanConvert(Type objectType) return objectType.GetNullableUnderlyingType().GetTypeInfo().IsEnum; } - public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer + ) { if (objectType.IsNullable() && reader.Value == null) { return existingValue; } - return parserLibrary.GetParser(objectType.GetNullableUnderlyingType().NotNull()).Parse(reader.Value.NotNull().ToString()); + return parserLibrary + .GetParser(objectType.GetNullableUnderlyingType().NotNull()) + .Parse(reader.Value.NotNull().ToString()); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { var parser = parserLibrary.GetParser(value.NotNull().GetType().NotNull()); - writer.WriteValue(parser.ToString(value.NotNull())); } + writer.WriteValue(parser.ToString(value.NotNull())); + } } } diff --git a/src/Narochno.Primitives/DictionaryExtensions.cs b/src/Narochno.Primitives/DictionaryExtensions.cs index 651f62c..9fba40a 100644 --- a/src/Narochno.Primitives/DictionaryExtensions.cs +++ b/src/Narochno.Primitives/DictionaryExtensions.cs @@ -4,7 +4,10 @@ namespace Narochno.Primitives { public static class DictionaryExtensions { - public static TValue? GetValue(this IDictionary dictionary, TKey key) + public static TValue? GetValue( + this IDictionary dictionary, + TKey key + ) where TValue : struct { if (!dictionary.TryGetValue(key, out var value)) diff --git a/src/Narochno.Primitives/EnumerableExtensions.cs b/src/Narochno.Primitives/EnumerableExtensions.cs index f52db1b..145bf4f 100644 --- a/src/Narochno.Primitives/EnumerableExtensions.cs +++ b/src/Narochno.Primitives/EnumerableExtensions.cs @@ -14,7 +14,9 @@ public static IEnumerable AsEnumerable(this T item) } public static IEnumerable> Batch( - this IEnumerable source, int size) + this IEnumerable source, + int size + ) { TSource[]? bucket = null; var count = 0; diff --git a/src/Narochno.Primitives/HexExtensions.cs b/src/Narochno.Primitives/HexExtensions.cs index 92024ca..ca1b893 100644 --- a/src/Narochno.Primitives/HexExtensions.cs +++ b/src/Narochno.Primitives/HexExtensions.cs @@ -10,4 +10,4 @@ public static string ToHexString(this byte[] ba) return hex.Replace("-", ""); } } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/NotNullExtensions.cs b/src/Narochno.Primitives/NotNullExtensions.cs index 85dda67..7c9d1dc 100644 --- a/src/Narochno.Primitives/NotNullExtensions.cs +++ b/src/Narochno.Primitives/NotNullExtensions.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -10,16 +9,25 @@ namespace Narochno.Primitives; public static class NotNullExtensions { - public static IEnumerable Empty(this IEnumerable? source) => source ?? Enumerable.Empty(); + public static IEnumerable Empty(this IEnumerable? source) => + source ?? Enumerable.Empty(); + #if NET8_0 - public static async Task NotNull(this Task task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + public static async Task NotNull( + this Task task, + [CallerArgumentExpression(nameof(task))] string? paramName = null + ) where T : class { var x = await task; ArgumentNullException.ThrowIfNull(x, paramName); return x; } - public static async ValueTask NotNull(this ValueTask task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + + public static async ValueTask NotNull( + this ValueTask task, + [CallerArgumentExpression(nameof(task))] string? paramName = null + ) where T : class { var x = await task; @@ -27,14 +35,21 @@ public static async ValueTask NotNull(this ValueTask task, [CallerArgu return x; } - public static async Task NotNull(this Task task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + public static async Task NotNull( + this Task task, + [CallerArgumentExpression(nameof(task))] string? paramName = null + ) where T : struct { var x = await task; ArgumentNullException.ThrowIfNull(x, paramName); return x.Value; } - public static async ValueTask NotNull(this ValueTask task, [CallerArgumentExpression(nameof(task))] string? paramName = null) + + public static async ValueTask NotNull( + this ValueTask task, + [CallerArgumentExpression(nameof(task))] string? paramName = null + ) where T : struct { var x = await task; @@ -42,20 +57,26 @@ public static async ValueTask NotNull(this ValueTask task, [CallerArgu return x.Value; } - public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) + public static T NotNull( + [NotNull] this T? obj, + [CallerArgumentExpression(nameof(obj))] string? paramName = null + ) where T : class { ArgumentNullException.ThrowIfNull(obj, paramName); return obj; } - public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) + public static T NotNull( + [NotNull] this T? obj, + [CallerArgumentExpression(nameof(obj))] string? paramName = null + ) where T : struct { ArgumentNullException.ThrowIfNull(obj, paramName); return obj.Value; } - #else +#else public static async Task NotNull(this Task task, string? message = null) where T : class @@ -79,7 +100,7 @@ public static async Task NotNull(this Task task, string? message = nul return x.Value; } - public static T NotNull(this T? obj, string? message = null) + public static T NotNull(this T? obj, string? message = null) where T : class { if (obj is null) @@ -89,7 +110,7 @@ public static T NotNull(this T? obj, string? message = null) return obj; } - public static T NotNull(this T? obj, string? message = null) + public static T NotNull(this T? obj, string? message = null) where T : struct { if (obj is null) diff --git a/src/Narochno.Primitives/Parsing/Convert.cs b/src/Narochno.Primitives/Parsing/Convert.cs index 1d93a78..d96ae02 100644 --- a/src/Narochno.Primitives/Parsing/Convert.cs +++ b/src/Narochno.Primitives/Parsing/Convert.cs @@ -38,4 +38,4 @@ public static string ToString(TType type) return DefaultParserLibrary.Instance.GetParser().ToString(type); } } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs index 271e54f..e54a31b 100644 --- a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs +++ b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs @@ -1,7 +1,7 @@ -using Narochno.Primitives.Parsing.Parsers; -using System; +using System; using System.Collections.Generic; using System.Reflection; +using Narochno.Primitives.Parsing.Parsers; namespace Narochno.Primitives.Parsing { @@ -10,22 +10,23 @@ public class DefaultParserLibrary : IParserLibrary private static object lockObject = new(); public static IParserLibrary Instance { get; } = new DefaultParserLibrary(); - public IDictionary Parsers { get; } = new Dictionary - { - { typeof(bool), new BoolParser() }, - { typeof(char), new CharParser() }, - { typeof(decimal), new DecimalParser() }, - { typeof(double), new DoubleParser() }, - { typeof(float), new FloatParser() }, - { typeof(Guid), new GuidParser() }, - { typeof(int), new IntParser() }, - { typeof(long), new LongParser() }, - { typeof(sbyte), new SByteParser() }, - { typeof(short), new ShortParser() }, - { typeof(uint), new UIntParser() }, - { typeof(ulong), new ULongParser() }, - { typeof(ushort), new UShortParser() } - }; + public IDictionary Parsers { get; } = + new Dictionary + { + { typeof(bool), new BoolParser() }, + { typeof(char), new CharParser() }, + { typeof(decimal), new DecimalParser() }, + { typeof(double), new DoubleParser() }, + { typeof(float), new FloatParser() }, + { typeof(Guid), new GuidParser() }, + { typeof(int), new IntParser() }, + { typeof(long), new LongParser() }, + { typeof(sbyte), new SByteParser() }, + { typeof(short), new ShortParser() }, + { typeof(uint), new UIntParser() }, + { typeof(ulong), new ULongParser() }, + { typeof(ushort), new UShortParser() } + }; public IParser GetParser(Type type) { @@ -45,7 +46,13 @@ public IParser GetParser(Type type) // so each one gets a parser if (type.GetTypeInfo().IsEnum) { - Parsers.Add(type, (IParser) Activator.CreateInstance(typeof(EnumParser<>).MakeGenericType(type)).NotNull()); + Parsers.Add( + type, + (IParser) + Activator + .CreateInstance(typeof(EnumParser<>).MakeGenericType(type)) + .NotNull() + ); return Parsers[type]; } diff --git a/src/Narochno.Primitives/Parsing/IParserLibrary.cs b/src/Narochno.Primitives/Parsing/IParserLibrary.cs index ae2a327..155f231 100644 --- a/src/Narochno.Primitives/Parsing/IParserLibrary.cs +++ b/src/Narochno.Primitives/Parsing/IParserLibrary.cs @@ -6,4 +6,4 @@ public interface IParserLibrary { IParser GetParser(Type type); } -} \ No newline at end of file +} diff --git a/src/Narochno.Primitives/Parsing/Parser.cs b/src/Narochno.Primitives/Parsing/Parser.cs index 351ccc9..0c7afb8 100644 --- a/src/Narochno.Primitives/Parsing/Parser.cs +++ b/src/Narochno.Primitives/Parsing/Parser.cs @@ -8,7 +8,9 @@ public abstract class Parser : IParser, IParser where TType : struct { object IParser.Parse(string input) => Parse(input); + object? IParser.TryParse(string input) => TryParse(input); + string IParser.ToString(object input) => ToString((TType)input); /// diff --git a/src/Narochno.Primitives/Parsing/ParserExtensions.cs b/src/Narochno.Primitives/Parsing/ParserExtensions.cs index d25b452..ae194c4 100644 --- a/src/Narochno.Primitives/Parsing/ParserExtensions.cs +++ b/src/Narochno.Primitives/Parsing/ParserExtensions.cs @@ -3,7 +3,7 @@ public static class ParserExtensions { public static TType? TryParse(this IParser parser, string input) - where TType : struct + where TType : struct { return (TType?)parser.TryParse(input); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs index 4cb6e6a..be39e9d 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs @@ -4,7 +4,7 @@ namespace Narochno.Primitives.Parsing.Parsers { - public class EnumParser: Parser + public class EnumParser : Parser where T : struct { public Type Type { get; } @@ -23,8 +23,12 @@ public EnumParser() // Cache this as it's expensive to fetch foreach (var value in Values) { - foreach (var attribute in Type.GetField(Enum.GetName(Type, value).NotNull()).NotNull() - .GetCustomAttributes(false).OfType()) + foreach ( + var attribute in Type.GetField(Enum.GetName(Type, value).NotNull()) + .NotNull() + .GetCustomAttributes(false) + .OfType() + ) { EnumStrings.Add(attribute.Value, (T)value); EnumStringsReverse.Add((T)value, attribute.Value); diff --git a/src/Narochno.Primitives/Parsing/StringExtensions.cs b/src/Narochno.Primitives/Parsing/StringExtensions.cs index 7a437b6..19c0466 100644 --- a/src/Narochno.Primitives/Parsing/StringExtensions.cs +++ b/src/Narochno.Primitives/Parsing/StringExtensions.cs @@ -13,8 +13,7 @@ public static class StringExtensions public static TType? TryParse(this string input) where TType : struct { - return DefaultParserLibrary.Instance.GetParser() - .TryParse(input); + return DefaultParserLibrary.Instance.GetParser().TryParse(input); } /// @@ -25,8 +24,7 @@ public static class StringExtensions /// The IOptional parsed from the string public static object? TryParse(this string input, Type type) { - return DefaultParserLibrary.Instance.GetParser(type) - .TryParse(input); + return DefaultParserLibrary.Instance.GetParser(type).TryParse(input); } /// @@ -38,8 +36,7 @@ public static class StringExtensions public static TType Parse(this string input) where TType : struct { - return DefaultParserLibrary.Instance.GetParser() - .Parse(input); + return DefaultParserLibrary.Instance.GetParser().Parse(input); } /// @@ -50,8 +47,7 @@ public static TType Parse(this string input) /// The type parsed from the string public static object Parse(this string input, Type type) { - return DefaultParserLibrary.Instance.GetParser(type) - .Parse(input); + return DefaultParserLibrary.Instance.GetParser(type).Parse(input); } } } diff --git a/src/Narochno.Primitives/TypeExtensions.cs b/src/Narochno.Primitives/TypeExtensions.cs index 49aa33c..f223382 100644 --- a/src/Narochno.Primitives/TypeExtensions.cs +++ b/src/Narochno.Primitives/TypeExtensions.cs @@ -13,9 +13,10 @@ public static bool IsNullable(this Type type) #else public static bool IsNullable(this Type type) { - return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + return type.GetTypeInfo().IsGenericType + && type.GetGenericTypeDefinition() == typeof(Nullable<>); } - #endif +#endif public static Type? GetNullableUnderlyingType(this Type type) { diff --git a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs index 3557c53..c8fdf6c 100644 --- a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs +++ b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs @@ -1,6 +1,6 @@ -using Narochno.Primitives.Parsing; +using System; +using Narochno.Primitives.Parsing; using Newtonsoft.Json; -using System; using Xunit; namespace Narochno.Primitives.Json.Tests @@ -10,8 +10,10 @@ public class EnumStringConverterTests enum TestEnum { Undefined, + [EnumString("First")] One, + [EnumString("Second")] Two, Three @@ -30,10 +32,10 @@ class TestObject [Fact] public void ExpectSerialiseEnumNoValue() { - var result = JsonConvert.SerializeObject(new TestObject - { - Test = TestEnum.Three - }, serializerSettings); + var result = JsonConvert.SerializeObject( + new TestObject { Test = TestEnum.Three }, + serializerSettings + ); Assert.Equal("{\"Test\":\"Three\"}", result); } @@ -41,10 +43,10 @@ public void ExpectSerialiseEnumNoValue() [Fact] public void ExpectSerialiseEnum() { - var result = JsonConvert.SerializeObject(new TestObject - { - Test = TestEnum.Two - }, serializerSettings); + var result = JsonConvert.SerializeObject( + new TestObject { Test = TestEnum.Two }, + serializerSettings + ); Assert.Equal("{\"Test\":\"Second\"}", result); } @@ -52,7 +54,10 @@ public void ExpectSerialiseEnum() [Fact] public void ExpectDeserialiseEnum() { - var result = JsonConvert.DeserializeObject("{\"Test\":\"Second\"}", serializerSettings); + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Second\"}", + serializerSettings + ); Assert.Equal(TestEnum.Two, result?.Test); } @@ -60,7 +65,10 @@ public void ExpectDeserialiseEnum() [Fact] public void ExpectDeserialiseUnknownEnumString() { - var result = JsonConvert.DeserializeObject("{\"Test\":\"Three\"}", serializerSettings); + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Three\"}", + serializerSettings + ); Assert.Equal(TestEnum.Three, result?.Test); } @@ -68,13 +76,25 @@ public void ExpectDeserialiseUnknownEnumString() [Fact] public void ExpectNotDeserialiseUnknownEnum() { - Assert.Throws(() => JsonConvert.DeserializeObject("{\"Test\":\"ok\"}", serializerSettings)); + Assert.Throws( + () => + JsonConvert.DeserializeObject( + "{\"Test\":\"ok\"}", + serializerSettings + ) + ); } [Fact] public void ExpectNotDeserialiseNullEnum() { - Assert.Throws(() => JsonConvert.DeserializeObject("{\"Test\": null}", serializerSettings)); + Assert.Throws( + () => + JsonConvert.DeserializeObject( + "{\"Test\": null}", + serializerSettings + ) + ); } class TestObjectNullable @@ -85,7 +105,10 @@ class TestObjectNullable [Fact] public void ExpectDeserialiseNullableEnum() { - var result = JsonConvert.DeserializeObject("{\"Test\":\"Second\"}", serializerSettings); + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Second\"}", + serializerSettings + ); Assert.Equal(TestEnum.Two, result?.Test); } @@ -93,7 +116,10 @@ public void ExpectDeserialiseNullableEnum() [Fact] public void ExpectNotDeserialiseNullableEnum() { - var result = JsonConvert.DeserializeObject("{\"Test\": null}", serializerSettings); + var result = JsonConvert.DeserializeObject( + "{\"Test\": null}", + serializerSettings + ); } } } diff --git a/test/Narochno.Primitives.Tests/ConvertTests.cs b/test/Narochno.Primitives.Tests/ConvertTests.cs index 23af4e5..23cd1df 100644 --- a/test/Narochno.Primitives.Tests/ConvertTests.cs +++ b/test/Narochno.Primitives.Tests/ConvertTests.cs @@ -12,4 +12,4 @@ public void Parse() Assert.Equal(long.MaxValue, Convert.Parse("9223372036854775807")); } } -} \ No newline at end of file +} diff --git a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs index 40cc0ff..5e02eda 100644 --- a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs @@ -5,14 +5,10 @@ namespace Narochno.Primitives.Tests { public class DictionaryExtensionsTests { - [Fact] public void TestGetNullableExists() { - var dict = new Dictionary - { - { "test", 1 } - }; + var dict = new Dictionary { { "test", 1 } }; Assert.Equal(1, dict.GetValue("test").NotNull()); } diff --git a/test/Narochno.Primitives.Tests/EnumParserTests.cs b/test/Narochno.Primitives.Tests/EnumParserTests.cs index 885deea..750c3c9 100644 --- a/test/Narochno.Primitives.Tests/EnumParserTests.cs +++ b/test/Narochno.Primitives.Tests/EnumParserTests.cs @@ -9,8 +9,10 @@ public enum TestEnum { [EnumString("test_one")] One, + [EnumString("test_two")] Two, + [EnumString("test_three")] Three } diff --git a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs index 59593f9..17e1e01 100644 --- a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs @@ -9,7 +9,7 @@ public class EnumerableExtensionsTests public void TestAsEnumerable() { string? x = null; - Assert.Empty( x.AsEnumerable()); + Assert.Empty(x.AsEnumerable()); int y = 0; Assert.Single(y.AsEnumerable()); @@ -21,12 +21,10 @@ public void TestAsEnumerable() Assert.Empty(z.AsEnumerable()); } - - [Fact] public void TestBatch() { - var items = new[] {"a", "b", "c"}; + var items = new[] { "a", "b", "c" }; var batches = items.Batch(2).ToList(); diff --git a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs index 82b2288..9ced42b 100644 --- a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs +++ b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs @@ -1,5 +1,5 @@ -using Narochno.Primitives.Parsing; -using System; +using System; +using Narochno.Primitives.Parsing; using Xunit; namespace Narochno.Primitives.Tests @@ -70,7 +70,10 @@ public void TypedEnumParse() { for (var i = 0; i < Iterations; i++) { - Assert.Equal(DateTimeKind.Utc, (DateTimeKind)Enum.Parse(typeof(DateTimeKind), "Utc")); + Assert.Equal( + DateTimeKind.Utc, + (DateTimeKind)Enum.Parse(typeof(DateTimeKind), "Utc") + ); } } diff --git a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs index 0d9aae5..682c07e 100644 --- a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs +++ b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs @@ -5,10 +5,8 @@ namespace Narochno.Primitives.Parsing.Tests { public class PrimitiveParserTests { - public struct MyStruct - { + public struct MyStruct { } - } [Theory] [InlineData(typeof(bool), "true", true)] [InlineData(typeof(bool), "false", false)] @@ -41,8 +39,14 @@ public void Parse(Type type, string input, object expected) [Fact] public void GuidToType() { - Assert.Equal(new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), "433158F7-7B46-4E6D-8980-B5492D46F0DE".Parse()); - Assert.Equal(new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().NotNull()); + Assert.Equal( + new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), + "433158F7-7B46-4E6D-8980-B5492D46F0DE".Parse() + ); + Assert.Equal( + new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), + "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().NotNull() + ); } [Fact] From 7aaeaad14f3d9263ef263f43b78f2014eaa4332c Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:10:19 +0100 Subject: [PATCH 3/8] fmt --- .../EnumStringConverter.cs | 58 +++-- .../Narochno.Primitives.Json.csproj | 2 +- .../DictionaryExtensions.cs | 25 +- .../EnumerableExtensions.cs | 63 +++-- src/Narochno.Primitives/HexExtensions.cs | 13 +- .../Narochno.Primitives.csproj | 2 +- src/Narochno.Primitives/Parsing/Convert.cs | 63 +++-- .../Parsing/DefaultParserLibrary.cs | 91 ++++---- .../Parsing/EnumStringAttribute.cs | 16 +- src/Narochno.Primitives/Parsing/IParser.cs | 79 ++++--- .../Parsing/IParserLibrary.cs | 9 +- src/Narochno.Primitives/Parsing/Parser.cs | 53 +++-- .../Parsing/ParserExtensions.cs | 21 +- .../Parsing/ParserLibraryExtensions.cs | 14 +- .../Parsing/Parsers/BoolParser.cs | 28 +-- .../Parsing/Parsers/CharParser.cs | 38 ++- .../Parsing/Parsers/DecimalParser.cs | 28 +-- .../Parsing/Parsers/DoubleParser.cs | 28 +-- .../Parsing/Parsers/EnumParser.cs | 113 +++++---- .../Parsing/Parsers/FloatParser.cs | 28 +-- .../Parsing/Parsers/GuidParser.cs | 28 +-- .../Parsing/Parsers/IntParser.cs | 28 +-- .../Parsing/Parsers/LongParser.cs | 28 +-- .../Parsing/Parsers/SByteParser.cs | 28 +-- .../Parsing/Parsers/ShortParser.cs | 28 +-- .../Parsing/Parsers/UIntParser.cs | 28 +-- .../Parsing/Parsers/ULongParser.cs | 28 +-- .../Parsing/Parsers/UShortParser.cs | 28 +-- .../Parsing/StringExtensions.cs | 81 +++---- src/Narochno.Primitives/TypeExtensions.cs | 31 +-- .../EnumStringConverterTests.cs | 219 ++++++++---------- .../Narochno.Primitives.Tests/ConvertTests.cs | 17 +- .../DictionaryExtensionsTests.cs | 27 ++- .../EnumParserTests.cs | 105 +++++---- .../EnumerableExtensionsTests.cs | 67 +++--- .../ParsingBenchmarks.cs | 130 +++++------ .../PrimitiveParserTests.cs | 99 ++++---- 37 files changed, 820 insertions(+), 952 deletions(-) diff --git a/src/Narochno.Primitives.Json/EnumStringConverter.cs b/src/Narochno.Primitives.Json/EnumStringConverter.cs index a6d3468..d773808 100644 --- a/src/Narochno.Primitives.Json/EnumStringConverter.cs +++ b/src/Narochno.Primitives.Json/EnumStringConverter.cs @@ -3,45 +3,39 @@ using Narochno.Primitives.Parsing; using Newtonsoft.Json; -namespace Narochno.Primitives.Json +namespace Narochno.Primitives.Json; + +public class EnumStringConverter : JsonConverter { - public class EnumStringConverter : JsonConverter - { - private IParserLibrary parserLibrary = DefaultParserLibrary.Instance; + private IParserLibrary parserLibrary = DefaultParserLibrary.Instance; - public EnumStringConverter() { } + public EnumStringConverter() { } - public EnumStringConverter(IParserLibrary parserLibrary) - { - this.parserLibrary = parserLibrary; - } + public EnumStringConverter(IParserLibrary parserLibrary) => this.parserLibrary = parserLibrary; - public override bool CanConvert(Type objectType) - { - return objectType.GetNullableUnderlyingType().GetTypeInfo().IsEnum; - } + public override bool CanConvert(Type objectType) => + objectType.GetNullableUnderlyingType().GetTypeInfo().IsEnum; - public override object? ReadJson( - JsonReader reader, - Type objectType, - object? existingValue, - JsonSerializer serializer - ) + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer + ) + { + if (objectType.IsNullable() && reader.Value == null) { - if (objectType.IsNullable() && reader.Value == null) - { - return existingValue; - } - - return parserLibrary - .GetParser(objectType.GetNullableUnderlyingType().NotNull()) - .Parse(reader.Value.NotNull().ToString()); + return existingValue; } - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) - { - var parser = parserLibrary.GetParser(value.NotNull().GetType().NotNull()); - writer.WriteValue(parser.ToString(value.NotNull())); - } + return parserLibrary + .GetParser(objectType.GetNullableUnderlyingType().NotNull()) + .Parse(reader.Value.NotNull().ToString()); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + var parser = parserLibrary.GetParser(value.NotNull().GetType().NotNull()); + writer.WriteValue(parser.ToString(value.NotNull())); } } diff --git a/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj b/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj index e8d622d..3e946d1 100644 --- a/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj +++ b/src/Narochno.Primitives.Json/Narochno.Primitives.Json.csproj @@ -2,7 +2,7 @@ Classes designed to make working with C# code easier. - 3.0.1 + 4.0.0 alanedwardes;adamhathcock netstandard2.0 Narochno.Primitives.Json diff --git a/src/Narochno.Primitives/DictionaryExtensions.cs b/src/Narochno.Primitives/DictionaryExtensions.cs index 9fba40a..70c943a 100644 --- a/src/Narochno.Primitives/DictionaryExtensions.cs +++ b/src/Narochno.Primitives/DictionaryExtensions.cs @@ -1,21 +1,20 @@ using System.Collections.Generic; -namespace Narochno.Primitives +namespace Narochno.Primitives; + +public static class DictionaryExtensions { - public static class DictionaryExtensions + public static TValue? GetValue( + this IDictionary dictionary, + TKey key + ) + where TValue : struct { - public static TValue? GetValue( - this IDictionary dictionary, - TKey key - ) - where TValue : struct + if (!dictionary.TryGetValue(key, out var value)) { - if (!dictionary.TryGetValue(key, out var value)) - { - return null; - } - - return value; + return null; } + + return value; } } diff --git a/src/Narochno.Primitives/EnumerableExtensions.cs b/src/Narochno.Primitives/EnumerableExtensions.cs index 145bf4f..3096831 100644 --- a/src/Narochno.Primitives/EnumerableExtensions.cs +++ b/src/Narochno.Primitives/EnumerableExtensions.cs @@ -1,49 +1,48 @@ using System.Collections.Generic; using System.Linq; -namespace Narochno.Primitives +namespace Narochno.Primitives; + +public static class EnumerableExtensions { - public static class EnumerableExtensions + public static IEnumerable AsEnumerable(this T item) { - public static IEnumerable AsEnumerable(this T item) + if (item != null) { - if (item != null) - { - yield return item; - } + yield return item; } + } - public static IEnumerable> Batch( - this IEnumerable source, - int size - ) - { - TSource[]? bucket = null; - var count = 0; + public static IEnumerable> Batch( + this IEnumerable source, + int size + ) + { + TSource[]? bucket = null; + var count = 0; - foreach (var item in source) + foreach (var item in source) + { + if (bucket == null) { - if (bucket == null) - { - bucket = new TSource[size]; - } - - bucket[count++] = item; - if (count != size) - { - continue; - } - - yield return bucket; - - bucket = null; - count = 0; + bucket = new TSource[size]; } - if (bucket != null && count > 0) + bucket[count++] = item; + if (count != size) { - yield return bucket.Take(count); + continue; } + + yield return bucket; + + bucket = null; + count = 0; + } + + if (bucket != null && count > 0) + { + yield return bucket.Take(count); } } } diff --git a/src/Narochno.Primitives/HexExtensions.cs b/src/Narochno.Primitives/HexExtensions.cs index ca1b893..b4f6a29 100644 --- a/src/Narochno.Primitives/HexExtensions.cs +++ b/src/Narochno.Primitives/HexExtensions.cs @@ -1,13 +1,12 @@ using System; -namespace Narochno.Primitives +namespace Narochno.Primitives; + +public static class HexExtensions { - public static class HexExtensions + public static string ToHexString(this byte[] ba) { - public static string ToHexString(this byte[] ba) - { - string hex = BitConverter.ToString(ba).ToLowerInvariant(); - return hex.Replace("-", ""); - } + string hex = BitConverter.ToString(ba).ToLowerInvariant(); + return hex.Replace("-", ""); } } diff --git a/src/Narochno.Primitives/Narochno.Primitives.csproj b/src/Narochno.Primitives/Narochno.Primitives.csproj index d24fe21..3e77522 100644 --- a/src/Narochno.Primitives/Narochno.Primitives.csproj +++ b/src/Narochno.Primitives/Narochno.Primitives.csproj @@ -2,7 +2,7 @@ Classes designed to make working with C# code easier. - 3.0.1 + 4.0.0 alanedwardes;adamhathcock net8.0;netstandard2.0 Narochno.Primitives diff --git a/src/Narochno.Primitives/Parsing/Convert.cs b/src/Narochno.Primitives/Parsing/Convert.cs index d96ae02..704a079 100644 --- a/src/Narochno.Primitives/Parsing/Convert.cs +++ b/src/Narochno.Primitives/Parsing/Convert.cs @@ -1,41 +1,34 @@ using System; -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public static class Convert + where TType : struct { - public static class Convert - where TType : struct - { - /// - /// Convert given string to Nullable - /// - /// The type to convert to - /// The input string - /// The Nullable parsed from the string - public static TType? TryParse(string input) - { - return DefaultParserLibrary.Instance.GetParser().TryParse(input); - } + /// + /// Convert given string to Nullable + /// + /// The type to convert to + /// The input string + /// The Nullable parsed from the string + public static TType? TryParse(string input) => + DefaultParserLibrary.Instance.GetParser().TryParse(input); - /// - /// Convert given string to type - /// - /// The type to convert to - /// The input string - /// The type parsed from the string - public static TType Parse(string input) - { - return DefaultParserLibrary.Instance.GetParser().Parse(input); - } + /// + /// Convert given string to type + /// + /// The type to convert to + /// The input string + /// The type parsed from the string + public static TType Parse(string input) => + DefaultParserLibrary.Instance.GetParser().Parse(input); - /// - /// Convert given string to object - /// - /// The input string - /// The type to convert to - /// The type parsed from the string - public static string ToString(TType type) - { - return DefaultParserLibrary.Instance.GetParser().ToString(type); - } - } + /// + /// Convert given string to object + /// + /// The input string + /// The type to convert to + /// The type parsed from the string + public static string ToString(TType type) => + DefaultParserLibrary.Instance.GetParser().ToString(type); } diff --git a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs index e54a31b..c4adf96 100644 --- a/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs +++ b/src/Narochno.Primitives/Parsing/DefaultParserLibrary.cs @@ -3,61 +3,60 @@ using System.Reflection; using Narochno.Primitives.Parsing.Parsers; -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public class DefaultParserLibrary : IParserLibrary { - public class DefaultParserLibrary : IParserLibrary - { - private static object lockObject = new(); - public static IParserLibrary Instance { get; } = new DefaultParserLibrary(); + private static object lockObject = new(); + public static IParserLibrary Instance { get; } = new DefaultParserLibrary(); - public IDictionary Parsers { get; } = - new Dictionary - { - { typeof(bool), new BoolParser() }, - { typeof(char), new CharParser() }, - { typeof(decimal), new DecimalParser() }, - { typeof(double), new DoubleParser() }, - { typeof(float), new FloatParser() }, - { typeof(Guid), new GuidParser() }, - { typeof(int), new IntParser() }, - { typeof(long), new LongParser() }, - { typeof(sbyte), new SByteParser() }, - { typeof(short), new ShortParser() }, - { typeof(uint), new UIntParser() }, - { typeof(ulong), new ULongParser() }, - { typeof(ushort), new UShortParser() } - }; + public IDictionary Parsers { get; } = + new Dictionary + { + { typeof(bool), new BoolParser() }, + { typeof(char), new CharParser() }, + { typeof(decimal), new DecimalParser() }, + { typeof(double), new DoubleParser() }, + { typeof(float), new FloatParser() }, + { typeof(Guid), new GuidParser() }, + { typeof(int), new IntParser() }, + { typeof(long), new LongParser() }, + { typeof(sbyte), new SByteParser() }, + { typeof(short), new ShortParser() }, + { typeof(uint), new UIntParser() }, + { typeof(ulong), new ULongParser() }, + { typeof(ushort), new UShortParser() } + }; - public IParser GetParser(Type type) + public IParser GetParser(Type type) + { + if (Parsers.TryGetValue(type, out var parser1)) { - if (Parsers.TryGetValue(type, out var parser1)) + return parser1; + } + + lock (lockObject) + { + if (Parsers.TryGetValue(type, value: out var parser)) { - return parser1; + return parser; } - lock (lockObject) + // Enums need type information, + // so each one gets a parser + if (type.GetTypeInfo().IsEnum) { - if (Parsers.TryGetValue(type, value: out var parser)) - { - return parser; - } - - // Enums need type information, - // so each one gets a parser - if (type.GetTypeInfo().IsEnum) - { - Parsers.Add( - type, - (IParser) - Activator - .CreateInstance(typeof(EnumParser<>).MakeGenericType(type)) - .NotNull() - ); - return Parsers[type]; - } - - throw new ArgumentException($"Unable to find parser for {type.FullName}"); + Parsers.Add( + type, + (IParser) + Activator + .CreateInstance(typeof(EnumParser<>).MakeGenericType(type)) + .NotNull() + ); + return Parsers[type]; } + + throw new ArgumentException($"Unable to find parser for {type.FullName}"); } } } diff --git a/src/Narochno.Primitives/Parsing/EnumStringAttribute.cs b/src/Narochno.Primitives/Parsing/EnumStringAttribute.cs index 6b3e0ca..5eb9661 100644 --- a/src/Narochno.Primitives/Parsing/EnumStringAttribute.cs +++ b/src/Narochno.Primitives/Parsing/EnumStringAttribute.cs @@ -1,15 +1,11 @@ using System; -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] +public class EnumStringAttribute : Attribute { - [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] - public class EnumStringAttribute : Attribute - { - public EnumStringAttribute(string value) - { - Value = value; - } + public EnumStringAttribute(string value) => Value = value; - public string Value { get; set; } - } + public string Value { get; set; } } diff --git a/src/Narochno.Primitives/Parsing/IParser.cs b/src/Narochno.Primitives/Parsing/IParser.cs index a7294ad..5ed6a64 100644 --- a/src/Narochno.Primitives/Parsing/IParser.cs +++ b/src/Narochno.Primitives/Parsing/IParser.cs @@ -1,49 +1,48 @@ -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +/// +/// Do not implement this, it offers no type safety! +/// Instead inherit from +/// +public interface IParser { /// - /// Do not implement this, it offers no type safety! - /// Instead inherit from + /// Convert from to the type + /// Should throw if invalid. /// - public interface IParser - { - /// - /// Convert from to the type - /// Should throw if invalid. - /// - /// The input string to convert from - /// A converted object - object? TryParse(string input); + /// The input string to convert from + /// A converted object + object? TryParse(string input); - /// - /// Convert from to the type - /// Should not throw, instead return an unset . - /// - /// The input string to convert from - /// An - object Parse(string input); + /// + /// Convert from to the type + /// Should not throw, instead return an unset . + /// + /// The input string to convert from + /// An + object Parse(string input); - string ToString(object input); - } + string ToString(object input); +} - public interface IParser - where TType : struct - { - /// - /// Convert from to the type - /// Should throw if invalid. - /// - /// The input string to convert from - /// A converted object - TType? TryParse(string input); +public interface IParser + where TType : struct +{ + /// + /// Convert from to the type + /// Should throw if invalid. + /// + /// The input string to convert from + /// A converted object + TType? TryParse(string input); - /// - /// Convert from to the type - /// Should not throw, instead return an unset . - /// - /// The input string to convert from - /// An - TType Parse(string input); + /// + /// Convert from to the type + /// Should not throw, instead return an unset . + /// + /// The input string to convert from + /// An + TType Parse(string input); - string ToString(TType input); - } + string ToString(TType input); } diff --git a/src/Narochno.Primitives/Parsing/IParserLibrary.cs b/src/Narochno.Primitives/Parsing/IParserLibrary.cs index 155f231..fa2f3b1 100644 --- a/src/Narochno.Primitives/Parsing/IParserLibrary.cs +++ b/src/Narochno.Primitives/Parsing/IParserLibrary.cs @@ -1,9 +1,8 @@ using System; -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public interface IParserLibrary { - public interface IParserLibrary - { - IParser GetParser(Type type); - } + IParser GetParser(Type type); } diff --git a/src/Narochno.Primitives/Parsing/Parser.cs b/src/Narochno.Primitives/Parsing/Parser.cs index 0c7afb8..9817c96 100644 --- a/src/Narochno.Primitives/Parsing/Parser.cs +++ b/src/Narochno.Primitives/Parsing/Parser.cs @@ -1,34 +1,33 @@ -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +/// +/// The base class for all parsers +/// +/// The type this class will parse +public abstract class Parser : IParser, IParser + where TType : struct { - /// - /// The base class for all parsers - /// - /// The type this class will parse - public abstract class Parser : IParser, IParser - where TType : struct - { - object IParser.Parse(string input) => Parse(input); + object IParser.Parse(string input) => Parse(input); - object? IParser.TryParse(string input) => TryParse(input); + object? IParser.TryParse(string input) => TryParse(input); - string IParser.ToString(object input) => ToString((TType)input); + string IParser.ToString(object input) => ToString((TType)input); - /// - /// Convert from to the type - /// Should throw if invalid. - /// - /// The input string to convert from - /// A converted object - public abstract TType Parse(string input); + /// + /// Convert from to the type + /// Should throw if invalid. + /// + /// The input string to convert from + /// A converted object + public abstract TType Parse(string input); - /// - /// Convert from to the type - /// Should not throw, instead return an unset . - /// - /// The input string to convert from - /// An - public abstract TType? TryParse(string input); + /// + /// Convert from to the type + /// Should not throw, instead return an unset . + /// + /// The input string to convert from + /// An + public abstract TType? TryParse(string input); - public abstract string ToString(TType value); - } + public abstract string ToString(TType value); } diff --git a/src/Narochno.Primitives/Parsing/ParserExtensions.cs b/src/Narochno.Primitives/Parsing/ParserExtensions.cs index ae194c4..cfbe381 100644 --- a/src/Narochno.Primitives/Parsing/ParserExtensions.cs +++ b/src/Narochno.Primitives/Parsing/ParserExtensions.cs @@ -1,17 +1,10 @@ -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public static class ParserExtensions { - public static class ParserExtensions - { - public static TType? TryParse(this IParser parser, string input) - where TType : struct - { - return (TType?)parser.TryParse(input); - } + public static TType? TryParse(this IParser parser, string input) + where TType : struct => (TType?)parser.TryParse(input); - public static TType Parse(this IParser parser, string input) - where TType : struct - { - return (TType)parser.Parse(input); - } - } + public static TType Parse(this IParser parser, string input) + where TType : struct => (TType)parser.Parse(input); } diff --git a/src/Narochno.Primitives/Parsing/ParserLibraryExtensions.cs b/src/Narochno.Primitives/Parsing/ParserLibraryExtensions.cs index b3e0543..ecc5361 100644 --- a/src/Narochno.Primitives/Parsing/ParserLibraryExtensions.cs +++ b/src/Narochno.Primitives/Parsing/ParserLibraryExtensions.cs @@ -1,11 +1,7 @@ -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public static class ParserLibraryExtensions { - public static class ParserLibraryExtensions - { - public static IParser GetParser(this IParserLibrary parserLibrary) - where TType : struct - { - return (IParser)parserLibrary.GetParser(typeof(TType)); - } - } + public static IParser GetParser(this IParserLibrary parserLibrary) + where TType : struct => (IParser)parserLibrary.GetParser(typeof(TType)); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/BoolParser.cs b/src/Narochno.Primitives/Parsing/Parsers/BoolParser.cs index 79921b7..328a03c 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/BoolParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/BoolParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class BoolParser : Parser { - public class BoolParser : Parser - { - public override bool Parse(string input) => bool.Parse(input); + public override bool Parse(string input) => bool.Parse(input); - public override bool? TryParse(string input) + public override bool? TryParse(string input) + { + bool result; + if (bool.TryParse(input, out result)) { - bool result; - if (bool.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(bool value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(bool value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/CharParser.cs b/src/Narochno.Primitives/Parsing/Parsers/CharParser.cs index ef06552..a2c44b9 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/CharParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/CharParser.cs @@ -1,33 +1,29 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class CharParser : Parser { - public class CharParser : Parser + public override char Parse(string input) { - public override char Parse(string input) + var c = TryParse(input); + if (c.HasValue) { - var c = TryParse(input); - if (c.HasValue) - { - return c.Value; - } - throw new InvalidOperationException("Cannot parse: " + input); + return c.Value; } + throw new InvalidOperationException("Cannot parse: " + input); + } - public override char? TryParse(string input) + public override char? TryParse(string input) + { + char result; + if (char.TryParse(input, out result)) { - char result; - if (char.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(char value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(char value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/DecimalParser.cs b/src/Narochno.Primitives/Parsing/Parsers/DecimalParser.cs index 65d81ec..bd0c528 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/DecimalParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/DecimalParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class DecimalParser : Parser { - public class DecimalParser : Parser - { - public override decimal Parse(string input) => decimal.Parse(input); + public override decimal Parse(string input) => decimal.Parse(input); - public override decimal? TryParse(string input) + public override decimal? TryParse(string input) + { + decimal result; + if (decimal.TryParse(input, out result)) { - decimal result; - if (decimal.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(decimal value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(decimal value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/DoubleParser.cs b/src/Narochno.Primitives/Parsing/Parsers/DoubleParser.cs index ceef89e..8f716db 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/DoubleParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/DoubleParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class DoubleParser : Parser { - public class DoubleParser : Parser - { - public override double Parse(string input) => double.Parse(input); + public override double Parse(string input) => double.Parse(input); - public override double? TryParse(string input) + public override double? TryParse(string input) + { + double result; + if (double.TryParse(input, out result)) { - double result; - if (double.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(double value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(double value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs index be39e9d..89a9bc7 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/EnumParser.cs @@ -2,81 +2,80 @@ using System.Collections.Generic; using System.Linq; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class EnumParser : Parser + where T : struct { - public class EnumParser : Parser - where T : struct - { - public Type Type { get; } - public List Values { get; } = new(); - public IDictionary EnumStrings { get; } = new Dictionary(); - public IDictionary EnumStringsReverse { get; } = new Dictionary(); + public Type Type { get; } + public List Values { get; } = new(); + public IDictionary EnumStrings { get; } = new Dictionary(); + public IDictionary EnumStringsReverse { get; } = new Dictionary(); - public EnumParser() + public EnumParser() + { + Type = typeof(T); + foreach (var value in Enum.GetValues(Type)) { - Type = typeof(T); - foreach (var value in Enum.GetValues(Type)) - { - Values.Add((T)value); - } - - // Cache this as it's expensive to fetch - foreach (var value in Values) - { - foreach ( - var attribute in Type.GetField(Enum.GetName(Type, value).NotNull()) - .NotNull() - .GetCustomAttributes(false) - .OfType() - ) - { - EnumStrings.Add(attribute.Value, (T)value); - EnumStringsReverse.Add((T)value, attribute.Value); - } - } + Values.Add((T)value); } - public override T Parse(string? input) + // Cache this as it's expensive to fetch + foreach (var value in Values) { - // First try to get the fields with EnumMemberAttribute - if (input != null && EnumStrings.TryGetValue(input, out var s)) + foreach ( + var attribute in Type.GetField(Enum.GetName(Type, value).NotNull()) + .NotNull() + .GetCustomAttributes(false) + .OfType() + ) { - return s; + EnumStrings.Add(attribute.Value, (T)value); + EnumStringsReverse.Add((T)value, attribute.Value); } - - // Fallback to the real Enum.Parse - return (T)Enum.Parse(Type, input.NotNull(), true); } + } - public override T? TryParse(string? input) + public override T Parse(string? input) + { + // First try to get the fields with EnumMemberAttribute + if (input != null && EnumStrings.TryGetValue(input, out var s)) { - // First try to get the fields with EnumMemberAttribute - if (input != null && EnumStrings.TryGetValue(input, out var s)) - { - return s; - } + return s; + } - // Fallback to a try parse (we can't use the - // real TryParse here as it has type parameters) - foreach (var value in Values) - { - if (Enum.GetName(Type, value).NotNull().Equals(input)) - { - return value; - } - } + // Fallback to the real Enum.Parse + return (T)Enum.Parse(Type, input.NotNull(), true); + } - return null; + public override T? TryParse(string? input) + { + // First try to get the fields with EnumMemberAttribute + if (input != null && EnumStrings.TryGetValue(input, out var s)) + { + return s; } - public override string ToString(T value) + // Fallback to a try parse (we can't use the + // real TryParse here as it has type parameters) + foreach (var value in Values) { - string? s; - if (EnumStringsReverse.TryGetValue(value, out s)) + if (Enum.GetName(Type, value).NotNull().Equals(input)) { - return s; + return value; } - return value.ToString().NotNull(); } + + return null; + } + + public override string ToString(T value) + { + string? s; + if (EnumStringsReverse.TryGetValue(value, out s)) + { + return s; + } + return value.ToString().NotNull(); } } diff --git a/src/Narochno.Primitives/Parsing/Parsers/FloatParser.cs b/src/Narochno.Primitives/Parsing/Parsers/FloatParser.cs index 385901f..eaf89ef 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/FloatParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/FloatParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class FloatParser : Parser { - public class FloatParser : Parser - { - public override float Parse(string input) => float.Parse(input); + public override float Parse(string input) => float.Parse(input); - public override float? TryParse(string input) + public override float? TryParse(string input) + { + float result; + if (float.TryParse(input, out result)) { - float result; - if (float.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(float value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(float value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs b/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs index 30d36a8..7d5c6d5 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/GuidParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class GuidParser : Parser { - public class GuidParser : Parser - { - public override Guid Parse(string input) => Guid.Parse(input); + public override Guid Parse(string input) => Guid.Parse(input); - public override Guid? TryParse(string input) + public override Guid? TryParse(string input) + { + Guid result; + if (Guid.TryParse(input, out result)) { - Guid result; - if (Guid.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(Guid value) - { - return Convert.ToString(value).NotNull(); - } + return null; } + + public override string ToString(Guid value) => Convert.ToString(value).NotNull(); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/IntParser.cs b/src/Narochno.Primitives/Parsing/Parsers/IntParser.cs index e73bc65..f010d4d 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/IntParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/IntParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class IntParser : Parser { - public class IntParser : Parser - { - public override int Parse(string input) => int.Parse(input); + public override int Parse(string input) => int.Parse(input); - public override int? TryParse(string input) + public override int? TryParse(string input) + { + int result; + if (int.TryParse(input, out result)) { - int result; - if (int.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(int value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(int value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/LongParser.cs b/src/Narochno.Primitives/Parsing/Parsers/LongParser.cs index 4a57b50..17e0d1a 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/LongParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/LongParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class LongParser : Parser { - public class LongParser : Parser - { - public override long Parse(string input) => long.Parse(input); + public override long Parse(string input) => long.Parse(input); - public override long? TryParse(string input) + public override long? TryParse(string input) + { + long result; + if (long.TryParse(input, out result)) { - long result; - if (long.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(long value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(long value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/SByteParser.cs b/src/Narochno.Primitives/Parsing/Parsers/SByteParser.cs index 9425b55..cc545c0 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/SByteParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/SByteParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class SByteParser : Parser { - public class SByteParser : Parser - { - public override sbyte Parse(string input) => sbyte.Parse(input); + public override sbyte Parse(string input) => sbyte.Parse(input); - public override sbyte? TryParse(string input) + public override sbyte? TryParse(string input) + { + sbyte result; + if (sbyte.TryParse(input, out result)) { - sbyte result; - if (sbyte.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(sbyte value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(sbyte value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/ShortParser.cs b/src/Narochno.Primitives/Parsing/Parsers/ShortParser.cs index f69ec2f..ca5d66f 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/ShortParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/ShortParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class ShortParser : Parser { - public class ShortParser : Parser - { - public override short Parse(string input) => short.Parse(input); + public override short Parse(string input) => short.Parse(input); - public override short? TryParse(string input) + public override short? TryParse(string input) + { + short result; + if (short.TryParse(input, out result)) { - short result; - if (short.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(short value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(short value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/UIntParser.cs b/src/Narochno.Primitives/Parsing/Parsers/UIntParser.cs index 2242f08..7956ccf 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/UIntParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/UIntParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class UIntParser : Parser { - public class UIntParser : Parser - { - public override uint Parse(string input) => uint.Parse(input); + public override uint Parse(string input) => uint.Parse(input); - public override uint? TryParse(string input) + public override uint? TryParse(string input) + { + uint result; + if (uint.TryParse(input, out result)) { - uint result; - if (uint.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(uint value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(uint value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/ULongParser.cs b/src/Narochno.Primitives/Parsing/Parsers/ULongParser.cs index 59b0c39..84bf55f 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/ULongParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/ULongParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class ULongParser : Parser { - public class ULongParser : Parser - { - public override ulong Parse(string input) => ulong.Parse(input); + public override ulong Parse(string input) => ulong.Parse(input); - public override ulong? TryParse(string input) + public override ulong? TryParse(string input) + { + ulong result; + if (ulong.TryParse(input, out result)) { - ulong result; - if (ulong.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(ulong value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(ulong value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/Parsers/UShortParser.cs b/src/Narochno.Primitives/Parsing/Parsers/UShortParser.cs index 0aaf286..2b7978a 100644 --- a/src/Narochno.Primitives/Parsing/Parsers/UShortParser.cs +++ b/src/Narochno.Primitives/Parsing/Parsers/UShortParser.cs @@ -1,25 +1,21 @@ using System; -namespace Narochno.Primitives.Parsing.Parsers +namespace Narochno.Primitives.Parsing.Parsers; + +public class UShortParser : Parser { - public class UShortParser : Parser - { - public override ushort Parse(string input) => ushort.Parse(input); + public override ushort Parse(string input) => ushort.Parse(input); - public override ushort? TryParse(string input) + public override ushort? TryParse(string input) + { + ushort result; + if (ushort.TryParse(input, out result)) { - ushort result; - if (ushort.TryParse(input, out result)) - { - return result; - } - - return null; + return result; } - public override string ToString(ushort value) - { - return Convert.ToString(value); - } + return null; } + + public override string ToString(ushort value) => Convert.ToString(value); } diff --git a/src/Narochno.Primitives/Parsing/StringExtensions.cs b/src/Narochno.Primitives/Parsing/StringExtensions.cs index 19c0466..9e1ed3f 100644 --- a/src/Narochno.Primitives/Parsing/StringExtensions.cs +++ b/src/Narochno.Primitives/Parsing/StringExtensions.cs @@ -1,53 +1,42 @@ using System; -namespace Narochno.Primitives.Parsing +namespace Narochno.Primitives.Parsing; + +public static class StringExtensions { - public static class StringExtensions - { - /// - /// Convert given string to Optional - /// - /// The type to convert to - /// The input string - /// The Optional parsed from the string - public static TType? TryParse(this string input) - where TType : struct - { - return DefaultParserLibrary.Instance.GetParser().TryParse(input); - } + /// + /// Convert given string to Optional + /// + /// The type to convert to + /// The input string + /// The Optional parsed from the string + public static TType? TryParse(this string input) + where TType : struct => DefaultParserLibrary.Instance.GetParser().TryParse(input); - /// - /// Convert given string to IOptional - /// - /// The input string - /// The type to convert to - /// The IOptional parsed from the string - public static object? TryParse(this string input, Type type) - { - return DefaultParserLibrary.Instance.GetParser(type).TryParse(input); - } + /// + /// Convert given string to IOptional + /// + /// The input string + /// The type to convert to + /// The IOptional parsed from the string + public static object? TryParse(this string input, Type type) => + DefaultParserLibrary.Instance.GetParser(type).TryParse(input); - /// - /// Convert given string to type - /// - /// The type to convert to - /// The input string - /// The type parsed from the string - public static TType Parse(this string input) - where TType : struct - { - return DefaultParserLibrary.Instance.GetParser().Parse(input); - } + /// + /// Convert given string to type + /// + /// The type to convert to + /// The input string + /// The type parsed from the string + public static TType Parse(this string input) + where TType : struct => DefaultParserLibrary.Instance.GetParser().Parse(input); - /// - /// Convert given string to object - /// - /// The input string - /// The type to convert to - /// The type parsed from the string - public static object Parse(this string input, Type type) - { - return DefaultParserLibrary.Instance.GetParser(type).Parse(input); - } - } + /// + /// Convert given string to object + /// + /// The input string + /// The type to convert to + /// The type parsed from the string + public static object Parse(this string input, Type type) => + DefaultParserLibrary.Instance.GetParser(type).Parse(input); } diff --git a/src/Narochno.Primitives/TypeExtensions.cs b/src/Narochno.Primitives/TypeExtensions.cs index f223382..6c49e7f 100644 --- a/src/Narochno.Primitives/TypeExtensions.cs +++ b/src/Narochno.Primitives/TypeExtensions.cs @@ -1,31 +1,20 @@ using System; using System.Reflection; -namespace Narochno.Primitives +namespace Narochno.Primitives; + +public static class TypeExtensions { - public static class TypeExtensions + public static bool IsNullable(this Type type) => + type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + + public static Type? GetNullableUnderlyingType(this Type type) { -#if PORTABLE40 - public static bool IsNullable(this Type type) - { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } -#else - public static bool IsNullable(this Type type) + if (type.IsNullable()) { - return type.GetTypeInfo().IsGenericType - && type.GetGenericTypeDefinition() == typeof(Nullable<>); + return Nullable.GetUnderlyingType(type); } -#endif - public static Type? GetNullableUnderlyingType(this Type type) - { - if (type.IsNullable()) - { - return Nullable.GetUnderlyingType(type); - } - - return type; - } + return type; } } diff --git a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs index c8fdf6c..cc49caa 100644 --- a/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs +++ b/test/Narochno.Primitives.Json.Tests/EnumStringConverterTests.cs @@ -3,123 +3,110 @@ using Newtonsoft.Json; using Xunit; -namespace Narochno.Primitives.Json.Tests +namespace Narochno.Primitives.Json.Tests; + +public class EnumStringConverterTests { - public class EnumStringConverterTests + enum TestEnum + { + Undefined, + + [EnumString("First")] + One, + + [EnumString("Second")] + Two, + Three + } + + class TestObject + { + public TestEnum Test { get; set; } + } + + private JsonSerializerSettings serializerSettings = new JsonSerializerSettings + { + Converters = new[] { new EnumStringConverter() } + }; + + [Fact] + public void ExpectSerialiseEnumNoValue() + { + var result = JsonConvert.SerializeObject( + new TestObject { Test = TestEnum.Three }, + serializerSettings + ); + + Assert.Equal("{\"Test\":\"Three\"}", result); + } + + [Fact] + public void ExpectSerialiseEnum() + { + var result = JsonConvert.SerializeObject( + new TestObject { Test = TestEnum.Two }, + serializerSettings + ); + + Assert.Equal("{\"Test\":\"Second\"}", result); + } + + [Fact] + public void ExpectDeserialiseEnum() + { + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Second\"}", + serializerSettings + ); + + Assert.Equal(TestEnum.Two, result?.Test); + } + + [Fact] + public void ExpectDeserialiseUnknownEnumString() + { + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Three\"}", + serializerSettings + ); + + Assert.Equal(TestEnum.Three, result?.Test); + } + + [Fact] + public void ExpectNotDeserialiseUnknownEnum() => + Assert.Throws( + () => JsonConvert.DeserializeObject("{\"Test\":\"ok\"}", serializerSettings) + ); + + [Fact] + public void ExpectNotDeserialiseNullEnum() => + Assert.Throws( + () => JsonConvert.DeserializeObject("{\"Test\": null}", serializerSettings) + ); + + class TestObjectNullable + { + public TestEnum? Test { get; set; } + } + + [Fact] + public void ExpectDeserialiseNullableEnum() + { + var result = JsonConvert.DeserializeObject( + "{\"Test\":\"Second\"}", + serializerSettings + ); + + Assert.Equal(TestEnum.Two, result?.Test); + } + + [Fact] + public void ExpectNotDeserialiseNullableEnum() { - enum TestEnum - { - Undefined, - - [EnumString("First")] - One, - - [EnumString("Second")] - Two, - Three - } - - class TestObject - { - public TestEnum Test { get; set; } - } - - private JsonSerializerSettings serializerSettings = new JsonSerializerSettings - { - Converters = new[] { new EnumStringConverter() } - }; - - [Fact] - public void ExpectSerialiseEnumNoValue() - { - var result = JsonConvert.SerializeObject( - new TestObject { Test = TestEnum.Three }, - serializerSettings - ); - - Assert.Equal("{\"Test\":\"Three\"}", result); - } - - [Fact] - public void ExpectSerialiseEnum() - { - var result = JsonConvert.SerializeObject( - new TestObject { Test = TestEnum.Two }, - serializerSettings - ); - - Assert.Equal("{\"Test\":\"Second\"}", result); - } - - [Fact] - public void ExpectDeserialiseEnum() - { - var result = JsonConvert.DeserializeObject( - "{\"Test\":\"Second\"}", - serializerSettings - ); - - Assert.Equal(TestEnum.Two, result?.Test); - } - - [Fact] - public void ExpectDeserialiseUnknownEnumString() - { - var result = JsonConvert.DeserializeObject( - "{\"Test\":\"Three\"}", - serializerSettings - ); - - Assert.Equal(TestEnum.Three, result?.Test); - } - - [Fact] - public void ExpectNotDeserialiseUnknownEnum() - { - Assert.Throws( - () => - JsonConvert.DeserializeObject( - "{\"Test\":\"ok\"}", - serializerSettings - ) - ); - } - - [Fact] - public void ExpectNotDeserialiseNullEnum() - { - Assert.Throws( - () => - JsonConvert.DeserializeObject( - "{\"Test\": null}", - serializerSettings - ) - ); - } - - class TestObjectNullable - { - public TestEnum? Test { get; set; } - } - - [Fact] - public void ExpectDeserialiseNullableEnum() - { - var result = JsonConvert.DeserializeObject( - "{\"Test\":\"Second\"}", - serializerSettings - ); - - Assert.Equal(TestEnum.Two, result?.Test); - } - - [Fact] - public void ExpectNotDeserialiseNullableEnum() - { - var result = JsonConvert.DeserializeObject( - "{\"Test\": null}", - serializerSettings - ); - } + var result = JsonConvert.DeserializeObject( + "{\"Test\": null}", + serializerSettings + ); } } diff --git a/test/Narochno.Primitives.Tests/ConvertTests.cs b/test/Narochno.Primitives.Tests/ConvertTests.cs index 23cd1df..9778acc 100644 --- a/test/Narochno.Primitives.Tests/ConvertTests.cs +++ b/test/Narochno.Primitives.Tests/ConvertTests.cs @@ -1,15 +1,14 @@ using Xunit; -namespace Narochno.Primitives.Parsing.Tests +namespace Narochno.Primitives.Parsing.Tests; + +public class ConvertTests { - public class ConvertTests + [Fact] + public void Parse() { - [Fact] - public void Parse() - { - Assert.Equal(ushort.MaxValue, Convert.Parse("65535")); - Assert.Equal(float.MinValue, Convert.Parse("-3.40282347E+38")); - Assert.Equal(long.MaxValue, Convert.Parse("9223372036854775807")); - } + Assert.Equal(ushort.MaxValue, Convert.Parse("65535")); + Assert.Equal(float.MinValue, Convert.Parse("-3.40282347E+38")); + Assert.Equal(long.MaxValue, Convert.Parse("9223372036854775807")); } } diff --git a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs index 5e02eda..1c2f3bc 100644 --- a/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/DictionaryExtensionsTests.cs @@ -1,24 +1,23 @@ using System.Collections.Generic; using Xunit; -namespace Narochno.Primitives.Tests +namespace Narochno.Primitives.Tests; + +public class DictionaryExtensionsTests { - public class DictionaryExtensionsTests + [Fact] + public void TestGetNullableExists() { - [Fact] - public void TestGetNullableExists() - { - var dict = new Dictionary { { "test", 1 } }; + var dict = new Dictionary { { "test", 1 } }; - Assert.Equal(1, dict.GetValue("test").NotNull()); - } + Assert.Equal(1, dict.GetValue("test").NotNull()); + } - [Fact] - public void TestGetNullableNotExists() - { - var dict = new Dictionary(); + [Fact] + public void TestGetNullableNotExists() + { + var dict = new Dictionary(); - Assert.False(dict.GetValue("test").HasValue); - } + Assert.False(dict.GetValue("test").HasValue); } } diff --git a/test/Narochno.Primitives.Tests/EnumParserTests.cs b/test/Narochno.Primitives.Tests/EnumParserTests.cs index 750c3c9..43dcd4c 100644 --- a/test/Narochno.Primitives.Tests/EnumParserTests.cs +++ b/test/Narochno.Primitives.Tests/EnumParserTests.cs @@ -1,68 +1,67 @@ using System; using Xunit; -namespace Narochno.Primitives.Parsing.Tests +namespace Narochno.Primitives.Parsing.Tests; + +public class EnumParserTests { - public class EnumParserTests + public enum TestEnum { - public enum TestEnum - { - [EnumString("test_one")] - One, + [EnumString("test_one")] + One, - [EnumString("test_two")] - Two, + [EnumString("test_two")] + Two, - [EnumString("test_three")] - Three - } + [EnumString("test_three")] + Three + } - [Fact] - public void TestParseAttribute() - { - Assert.Equal(TestEnum.One, "test_one".Parse()); - Assert.Equal(TestEnum.Two, "test_two".Parse()); - Assert.Equal(TestEnum.Three, "test_three".Parse()); - } + [Fact] + public void TestParseAttribute() + { + Assert.Equal(TestEnum.One, "test_one".Parse()); + Assert.Equal(TestEnum.Two, "test_two".Parse()); + Assert.Equal(TestEnum.Three, "test_three".Parse()); + } - [Fact] - public void TestParseNoAttribute() - { - Assert.Equal(TestEnum.One, "One".Parse()); - Assert.Equal(TestEnum.Two, "Two".Parse()); - Assert.Equal(TestEnum.Three, "Three".Parse()); - } + [Fact] + public void TestParseNoAttribute() + { + Assert.Equal(TestEnum.One, "One".Parse()); + Assert.Equal(TestEnum.Two, "Two".Parse()); + Assert.Equal(TestEnum.Three, "Three".Parse()); + } - [Fact] - public void TestParseAttributeToOptional() - { - Assert.Equal(TestEnum.One, "test_one".TryParse().NotNull()); - Assert.Equal(TestEnum.Two, "test_two".TryParse().NotNull()); - Assert.Equal(TestEnum.Three, "test_three".TryParse().NotNull()); - } + [Fact] + public void TestParseAttributeToOptional() + { + Assert.Equal(TestEnum.One, "test_one".TryParse().NotNull()); + Assert.Equal(TestEnum.Two, "test_two".TryParse().NotNull()); + Assert.Equal(TestEnum.Three, "test_three".TryParse().NotNull()); + } - [Fact] - public void TestParseNoAttributeToOptional() - { - Assert.Equal(TestEnum.One, "One".TryParse().NotNull()); - Assert.Equal(TestEnum.Two, "Two".TryParse().NotNull()); - Assert.Equal(TestEnum.Three, "Three".TryParse().NotNull()); - } + [Fact] + public void TestParseNoAttributeToOptional() + { + Assert.Equal(TestEnum.One, "One".TryParse().NotNull()); + Assert.Equal(TestEnum.Two, "Two".TryParse().NotNull()); + Assert.Equal(TestEnum.Three, "Three".TryParse().NotNull()); + } - [Fact] - public void TestParseInvalid() - { - Assert.Throws(() => "lol".Parse()); - Assert.Throws(() => string.Empty.Parse()); - Assert.Throws(() => ((string)null!).Parse()); - } + [Fact] + public void TestParseInvalid() + { + Assert.Throws(() => "lol".Parse()); + Assert.Throws(() => string.Empty.Parse()); + Assert.Throws(() => ((string)null!).Parse()); + } - [Fact] - public void TestParseInvalidToOptional() - { - Assert.False("lol".TryParse().HasValue); - Assert.False(string.Empty.TryParse().HasValue); - Assert.False(((string)null!).TryParse().HasValue); - } + [Fact] + public void TestParseInvalidToOptional() + { + Assert.False("lol".TryParse().HasValue); + Assert.False(string.Empty.TryParse().HasValue); + Assert.False(((string)null!).TryParse().HasValue); } } diff --git a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs index 17e1e01..9cfbce0 100644 --- a/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs +++ b/test/Narochno.Primitives.Tests/EnumerableExtensionsTests.cs @@ -1,41 +1,40 @@ using System.Linq; using Xunit; -namespace Narochno.Primitives.Tests +namespace Narochno.Primitives.Tests; + +public class EnumerableExtensionsTests { - public class EnumerableExtensionsTests + [Fact] + public void TestAsEnumerable() { - [Fact] - public void TestAsEnumerable() - { - string? x = null; - Assert.Empty(x.AsEnumerable()); - - int y = 0; - Assert.Single(y.AsEnumerable()); - - y = 1; - Assert.Single(y.AsEnumerable()); - - int? z = null; - Assert.Empty(z.AsEnumerable()); - } - - [Fact] - public void TestBatch() - { - var items = new[] { "a", "b", "c" }; - - var batches = items.Batch(2).ToList(); - - Assert.Equal(2, batches.Count); - var b = batches[0].ToList(); - Assert.Equal(2, b.Count); - Assert.Equal("a", b[0]); - Assert.Equal("b", b[1]); - b = batches[1].ToList(); - Assert.Equal(1, b.Count); - Assert.Equal("c", b[0]); - } + string? x = null; + Assert.Empty(x.AsEnumerable()); + + int y = 0; + Assert.Single(y.AsEnumerable()); + + y = 1; + Assert.Single(y.AsEnumerable()); + + int? z = null; + Assert.Empty(z.AsEnumerable()); + } + + [Fact] + public void TestBatch() + { + var items = new[] { "a", "b", "c" }; + + var batches = items.Batch(2).ToList(); + + Assert.Equal(2, batches.Count); + var b = batches[0].ToList(); + Assert.Equal(2, b.Count); + Assert.Equal("a", b[0]); + Assert.Equal("b", b[1]); + b = batches[1].ToList(); + Assert.Equal(1, b.Count); + Assert.Equal("c", b[0]); } } diff --git a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs index 9ced42b..60b666b 100644 --- a/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs +++ b/test/Narochno.Primitives.Tests/ParsingBenchmarks.cs @@ -2,99 +2,95 @@ using Narochno.Primitives.Parsing; using Xunit; -namespace Narochno.Primitives.Tests +namespace Narochno.Primitives.Tests; + +/// +/// Test class to compare the timings of each +/// parse method using a large number of iterations. +/// +/// A good way to use this class is to test before changes +/// and afterwards, to see if/how the time to parse has changed. +/// +public class ParsingBenchmarks { /// - /// Test class to compare the timings of each - /// parse method using a large number of iterations. - /// - /// A good way to use this class is to test before changes - /// and afterwards, to see if/how the time to parse has changed. + /// 10 million /// - public class ParsingBenchmarks - { - /// - /// 10 million - /// - private const int Iterations = 10000000; + private const int Iterations = 10000000; - [Fact(Skip = "Skipping Benchmarks")] - public void GenericBoolParse() + [Fact(Skip = "Skipping Benchmarks")] + public void GenericBoolParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.True("true".Parse()); - } + Assert.True("true".Parse()); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void TypedBoolParse() + [Fact(Skip = "Skipping Benchmarks")] + public void TypedBoolParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.True(bool.Parse("true")); - } + Assert.True(bool.Parse("true")); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void GenericBoolTryParse() + [Fact(Skip = "Skipping Benchmarks")] + public void GenericBoolTryParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.True("true".TryParse().NotNull()); - } + Assert.True("true".TryParse().NotNull()); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void TypedBoolTryParse() + [Fact(Skip = "Skipping Benchmarks")] + public void TypedBoolTryParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - bool result = false; - bool.TryParse("true", out result); - Assert.True(result); - } + bool result = false; + bool.TryParse("true", out result); + Assert.True(result); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void GenericEnumParse() + [Fact(Skip = "Skipping Benchmarks")] + public void GenericEnumParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.Equal(DateTimeKind.Utc, "Utc".Parse()); - } + Assert.Equal(DateTimeKind.Utc, "Utc".Parse()); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void TypedEnumParse() + [Fact(Skip = "Skipping Benchmarks")] + public void TypedEnumParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.Equal( - DateTimeKind.Utc, - (DateTimeKind)Enum.Parse(typeof(DateTimeKind), "Utc") - ); - } + Assert.Equal(DateTimeKind.Utc, (DateTimeKind)Enum.Parse(typeof(DateTimeKind), "Utc")); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void GenericEnumTryParse() + [Fact(Skip = "Skipping Benchmarks")] + public void GenericEnumTryParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - Assert.Equal(DateTimeKind.Utc, "Utc".TryParse().NotNull()); - } + Assert.Equal(DateTimeKind.Utc, "Utc".TryParse().NotNull()); } + } - [Fact(Skip = "Skipping Benchmarks")] - public void TypedEnumTryParse() + [Fact(Skip = "Skipping Benchmarks")] + public void TypedEnumTryParse() + { + for (var i = 0; i < Iterations; i++) { - for (var i = 0; i < Iterations; i++) - { - DateTimeKind result; - Enum.TryParse("Utc", out result); - Assert.Equal(DateTimeKind.Utc, result); - } + DateTimeKind result; + Enum.TryParse("Utc", out result); + Assert.Equal(DateTimeKind.Utc, result); } } } diff --git a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs index 682c07e..9429765 100644 --- a/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs +++ b/test/Narochno.Primitives.Tests/PrimitiveParserTests.cs @@ -1,59 +1,58 @@ using System; using Xunit; -namespace Narochno.Primitives.Parsing.Tests +namespace Narochno.Primitives.Parsing.Tests; + +public class PrimitiveParserTests { - public class PrimitiveParserTests - { - public struct MyStruct { } + public struct MyStruct { } - [Theory] - [InlineData(typeof(bool), "true", true)] - [InlineData(typeof(bool), "false", false)] - [InlineData(typeof(char), "\0", char.MinValue)] - [InlineData(typeof(char), "\uffff", char.MaxValue)] - [InlineData(typeof(double), "-1.7976931348623157E+308", double.MinValue)] - [InlineData(typeof(double), "1.7976931348623157E+308", double.MaxValue)] - [InlineData(typeof(float), "-3.40282347E+38", float.MinValue)] - [InlineData(typeof(float), "3.40282347E+38", float.MaxValue)] - [InlineData(typeof(int), "2147483647", int.MaxValue)] - [InlineData(typeof(int), "-2147483648", int.MinValue)] - [InlineData(typeof(long), "-9223372036854775808", long.MinValue)] - [InlineData(typeof(long), "9223372036854775807", long.MaxValue)] - [InlineData(typeof(sbyte), "-128", sbyte.MinValue)] - [InlineData(typeof(sbyte), "127", sbyte.MaxValue)] - [InlineData(typeof(short), "-32768", short.MinValue)] - [InlineData(typeof(short), "32767", short.MaxValue)] - [InlineData(typeof(uint), "0", uint.MinValue)] - [InlineData(typeof(uint), "4294967295", uint.MaxValue)] - [InlineData(typeof(ulong), "0", ulong.MinValue)] - [InlineData(typeof(ulong), "18446744073709551615", ulong.MaxValue)] - [InlineData(typeof(ushort), "0", ushort.MinValue)] - [InlineData(typeof(ushort), "65535", ushort.MaxValue)] - public void Parse(Type type, string input, object expected) - { - Assert.Equal(expected, input.Parse(type)); - Assert.Equal(expected, input.TryParse(type)); - } + [Theory] + [InlineData(typeof(bool), "true", true)] + [InlineData(typeof(bool), "false", false)] + [InlineData(typeof(char), "\0", char.MinValue)] + [InlineData(typeof(char), "\uffff", char.MaxValue)] + [InlineData(typeof(double), "-1.7976931348623157E+308", double.MinValue)] + [InlineData(typeof(double), "1.7976931348623157E+308", double.MaxValue)] + [InlineData(typeof(float), "-3.40282347E+38", float.MinValue)] + [InlineData(typeof(float), "3.40282347E+38", float.MaxValue)] + [InlineData(typeof(int), "2147483647", int.MaxValue)] + [InlineData(typeof(int), "-2147483648", int.MinValue)] + [InlineData(typeof(long), "-9223372036854775808", long.MinValue)] + [InlineData(typeof(long), "9223372036854775807", long.MaxValue)] + [InlineData(typeof(sbyte), "-128", sbyte.MinValue)] + [InlineData(typeof(sbyte), "127", sbyte.MaxValue)] + [InlineData(typeof(short), "-32768", short.MinValue)] + [InlineData(typeof(short), "32767", short.MaxValue)] + [InlineData(typeof(uint), "0", uint.MinValue)] + [InlineData(typeof(uint), "4294967295", uint.MaxValue)] + [InlineData(typeof(ulong), "0", ulong.MinValue)] + [InlineData(typeof(ulong), "18446744073709551615", ulong.MaxValue)] + [InlineData(typeof(ushort), "0", ushort.MinValue)] + [InlineData(typeof(ushort), "65535", ushort.MaxValue)] + public void Parse(Type type, string input, object expected) + { + Assert.Equal(expected, input.Parse(type)); + Assert.Equal(expected, input.TryParse(type)); + } - [Fact] - public void GuidToType() - { - Assert.Equal( - new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), - "433158F7-7B46-4E6D-8980-B5492D46F0DE".Parse() - ); - Assert.Equal( - new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), - "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().NotNull() - ); - } + [Fact] + public void GuidToType() + { + Assert.Equal( + new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), + "433158F7-7B46-4E6D-8980-B5492D46F0DE".Parse() + ); + Assert.Equal( + new Guid("433158F7-7B46-4E6D-8980-B5492D46F0DE"), + "433158F7-7B46-4E6D-8980-B5492D46F0DE".TryParse().NotNull() + ); + } - [Fact] - public void UnknownType() - { - Assert.Throws(() => "test".Parse()); - Assert.Throws(() => "test".TryParse()); - } + [Fact] + public void UnknownType() + { + Assert.Throws(() => "test".Parse()); + Assert.Throws(() => "test".TryParse()); } } From e51137863e5830b4ad3eb5d91d82d7abb58c9760 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:11:23 +0100 Subject: [PATCH 4/8] fix name --- .github/workflows/dotnetcore.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 0f9b4a0..7486843 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -1,4 +1,4 @@ -name: Narochno.EnvFile +name: Narochno.Primitives on: push: branches: @@ -18,5 +18,5 @@ jobs: - run: dotnet run --project build/build.csproj - uses: actions/upload-artifact@v4 with: - name: narochno.envfile.nupkg + name: narochno.primitives.nupkg path: artifacts/* From 7f6c150dbbd9957f21ba43267228c1797201afbf Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:13:48 +0100 Subject: [PATCH 5/8] fix build name --- Narochno.Primitives.sln | 6 ++++++ build/Program.cs | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Narochno.Primitives.sln b/Narochno.Primitives.sln index 0cb56e5..d6d29ce 100644 --- a/Narochno.Primitives.sln +++ b/Narochno.Primitives.sln @@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{ED5BB2 global.json = global.json EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "build", "build\build.csproj", "{7126AFE3-188B-4785-8C01-A565303B3757}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {E04F8B42-125C-4362-93A4-0B2E57112AA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {E04F8B42-125C-4362-93A4-0B2E57112AA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {E04F8B42-125C-4362-93A4-0B2E57112AA6}.Release|Any CPU.Build.0 = Release|Any CPU + {7126AFE3-188B-4785-8C01-A565303B3757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7126AFE3-188B-4785-8C01-A565303B3757}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7126AFE3-188B-4785-8C01-A565303B3757}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7126AFE3-188B-4785-8C01-A565303B3757}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/build/Program.cs b/build/Program.cs index 1ca0a30..ad732dd 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -53,7 +53,10 @@ void RemoveDirectory(string d) DependsOn(Restore), () => { - Run("dotnet", "build src/Narochno.EnvFile/Narochno.EnvFile.csproj -c Release --no-restore"); + Run( + "dotnet", + "build src/Narochno.Primitives/Narochno.Primitives.csproj -c Release --no-restore" + ); } ); @@ -79,7 +82,10 @@ IEnumerable GetFiles(string d) DependsOn(Test), () => { - Run("dotnet", "pack src/Narochno.EnvFile/Narochno.EnvFile.csproj -c Release -o artifacts/"); + Run( + "dotnet", + "pack src/Narochno.Primitives/Narochno.Primitives.csproj -c Release -o artifacts/" + ); } ); From 868047dc75d6c905925f5946fb4fa69e8da976dd Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:15:42 +0100 Subject: [PATCH 6/8] fix packaging --- src/Narochno.Primitives/Narochno.Primitives.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Narochno.Primitives/Narochno.Primitives.csproj b/src/Narochno.Primitives/Narochno.Primitives.csproj index 3e77522..6041af0 100644 --- a/src/Narochno.Primitives/Narochno.Primitives.csproj +++ b/src/Narochno.Primitives/Narochno.Primitives.csproj @@ -7,8 +7,7 @@ net8.0;netstandard2.0 Narochno.Primitives Narochno.Primitives - csharp;primitives;netcore - https://avatars.githubusercontent.com/u/24652538 + https://avatars.githubusercontent.com/u/24652538 https://github.com/Narochno/Narochno.Primitives From df33a2073e6bcfddaae6856e14a18d40fdba0e99 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Mon, 29 Apr 2024 15:58:41 +0100 Subject: [PATCH 7/8] remove package icon --- src/Narochno.Primitives/Narochno.Primitives.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Narochno.Primitives/Narochno.Primitives.csproj b/src/Narochno.Primitives/Narochno.Primitives.csproj index 6041af0..3a3bc6f 100644 --- a/src/Narochno.Primitives/Narochno.Primitives.csproj +++ b/src/Narochno.Primitives/Narochno.Primitives.csproj @@ -7,7 +7,6 @@ net8.0;netstandard2.0 Narochno.Primitives Narochno.Primitives - https://avatars.githubusercontent.com/u/24652538 https://github.com/Narochno/Narochno.Primitives From 58dcb398db547bcebf4fe9351fb193d6fe9a2e5a Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 30 Apr 2024 09:04:59 +0100 Subject: [PATCH 8/8] Update readme --- README.md | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 2524692..e049df1 100644 --- a/README.md +++ b/README.md @@ -2,33 +2,9 @@ Classes designed to make working with C# code easier. -## Optional<T> +## NotNull and Empty -A generic struct to allow for optional reference values. It allows you to write code that assumes all variables except those wrapped with `Optional` are specified, avoiding the need for null checks and possible null reference exceptions. - -It is the same concept as `Nullable`, but can be used for reference types instead of value types. - -### Example Usage - -```csharp -public async Task RecordInformation(Information information, Optional location) -{ - var document = new Document(); - document["name"] = information.Name; - document["email"] = information.Email; - - if (location.HasValue) - { - document["country"] = location.Value.Country; - document["city"] = location.Value.City; - } - - await Table.LoadTable(dynamoClient, "Information") - .PutItemAsync(document); -} -``` - -The use of `Optional` in the code above to wrap the `Location` object is an explicit way to show that it may not be set, without a null check. Anyone calling and editing the code can see the intent of the parameter from a glance. +Helpers that remove of the constant issues around checking `null` on all types and collections. If you find yourself doing "if not then throw" or "null or empty collection" then these help you out. ## Generic Parsing