From 87461db24e60213653867fdb259f5977390696e6 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 28 Jul 2026 14:24:59 -0700 Subject: [PATCH] Align C# styling with EncDotNet.S100 Adopt the shared editor configuration, coding guide, warnings policy, and CI format gates. Reformat existing code, resolve naming violations, and update vulnerable dependencies exposed by NuGet audit enforcement. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 821b7e94-3874-446d-8f4d-8c616c6f009f --- .editorconfig | 273 +++++++++++++++++ .github/copilot-instructions.md | 6 + .github/workflows/ci.yml | 30 +- Directory.Build.props | 5 + Directory.Packages.props | 18 +- docs/coding-style.md | 108 +++++++ docs/index.md | 1 + docs/toc.yml | 2 + src/EncDotNet.ChartViewer/App.axaml.cs | 3 +- .../Baking/ChartBaker.cs | 3 - .../ChartViewerDiagnostics.cs | 1 - .../Charts/AppDataPaths.cs | 3 - .../Charts/CachedChartSource.cs | 2 - .../Charts/FileSystemChartCatalogSource.cs | 4 - .../Charts/IChartCatalogSource.cs | 2 - .../Charts/IChartPackageManager.cs | 5 - .../Charts/IChartSource.cs | 2 - .../Charts/NoaaChartPackageManager.cs | 9 +- .../DiagnosticOptions.cs | 1 - .../Models/LayerUpdate.cs | 1 - .../Models/S57FeatureCategory.cs | 2 +- src/EncDotNet.ChartViewer/Program.cs | 7 +- .../ProjectedEdgeCache.cs | 1 - .../S57AreaGeometryBuilder.cs | 2 - .../S57CoverageHelper.cs | 1 - src/EncDotNet.ChartViewer/S57LayerFactory.cs | 13 +- src/EncDotNet.ChartViewer/S57LayerTemplate.cs | 4 +- .../S57LayerTemplates.cs | 13 +- .../S57LineGeometryBuilder.cs | 2 - src/EncDotNet.ChartViewer/ViewLocator.cs | 3 +- .../ViewModels/ChartFeatureItemViewModel.cs | 1 - .../ViewModels/ChartFeatureViewModel.cs | 2 - .../ViewModels/ChartViewModel.cs | 6 - .../ViewModels/MainWindowViewModel.cs | 7 +- .../ViewModels/ManageChartsViewModel.cs | 5 - .../ViewModels/SetupWizardViewModel.cs | 5 - .../ViewModels/ViewModelBase.cs | 4 +- .../Views/FeatureInfoWindow.axaml.cs | 2 - .../Views/MainWindow.axaml.cs | 12 +- .../Views/ManageChartsWindow.axaml.cs | 1 - .../Views/SetupWizardWindow.axaml.cs | 1 - .../Iso8211DataDescriptiveRecord.cs | 2 - .../Iso8211DataDescriptiveRecordReader.cs | 5 +- src/EncDotNet.Iso8211/Iso8211Document.cs | 2 - .../Iso8211DocumentReader.cs | 2 - .../Iso8211FieldDefinition.cs | 2 - src/EncDotNet.Iso8211/Iso8211FieldReader.cs | 8 +- src/EncDotNet.Iso8211/Iso8211Reader.cs | 6 +- src/EncDotNet.Iso8211/Iso8211Record.cs | 2 - .../Iso8211SubfieldEncoder.cs | 28 +- src/EncDotNet.Noaa/EncProductCatalogClient.cs | 4 +- src/EncDotNet.S57/Charts/S57AreaFeature.cs | 1 - src/EncDotNet.S57/Charts/S57Edge.cs | 2 - src/EncDotNet.S57/Charts/S57EdgeReference.cs | 2 +- src/EncDotNet.S57/Charts/S57IsolatedNode.cs | 2 - src/EncDotNet.S57/Charts/S57LineFeature.cs | 2 - src/EncDotNet.S57/Charts/S57PointFeature.cs | 2 - src/EncDotNet.S57/Charts/S57SpatialRecord.cs | 2 - src/EncDotNet.S57/Charts/S57TypedFeature.cs | 2 - src/EncDotNet.S57/ExchangeSets/S57Catalog.cs | 2 - src/EncDotNet.S57/S57Document.cs | 10 +- src/EncDotNet.S57/S57DocumentReader.cs | 34 +-- src/EncDotNet.S57/S57FeatureRecord.cs | 2 - src/EncDotNet.S57/S57VectorRecord.cs | 2 - .../ParsingLayerBenchmarks.cs | 2 +- tests/EncDotNet.Benchmarks/Program.cs | 1 - .../Iso8211DocumentReaderTests.cs | 3 +- .../Iso8211FieldReaderTests.cs | 2 +- .../S57AreaGeometryBuilderTests.cs | 12 +- .../S57ChartDirectoryTests.cs | 1 - tests/EndDotNet.UnitTests/S57ChartTests.cs | 14 +- .../S57DocumentReaderTests.cs | 274 +++++++++--------- 72 files changed, 658 insertions(+), 350 deletions(-) create mode 100644 .editorconfig create mode 100644 docs/coding-style.md diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9428002 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,273 @@ +# EncDotNet - editorconfig +# +# Machine-readable encoding of the C# coding style guide +# (docs/coding-style.md). CI enforces whitespace and using-directive rules; +# broader style and naming rules are surfaced by IDE analyzers and followed by +# hand. + +root = true + +########################################## +# All files +########################################## +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{json,yml,yaml,csproj,props,targets,slnx,xml,axaml,xaml,resx}] +indent_size = 2 + +[*.{cmd,bat}] +end_of_line = crlf + +[*.md] +# Trailing double-space is a hard line break in Markdown. +trim_trailing_whitespace = false + +########################################## +# C# files +########################################## +[*.cs] +indent_size = 4 +insert_final_newline = true + +#### Language / usings #### + +# File-scoped namespaces only (guide section 2). +csharp_style_namespace_declarations = file_scoped:warning + +# using directives outside the namespace, System.* first (guide section 2). +csharp_using_directive_placement = outside_namespace:warning +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +# Unused usings (build already treats warnings as errors). +dotnet_diagnostic.IDE0005.severity = warning + +#### Formatting: newlines (Allman braces, guide section 3) #### + +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 + +#### Formatting: indentation #### + +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +#### Formatting: spacing #### + +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_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_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +#### Formatting: wrapping #### + +csharp_preserve_single_line_blocks = true +# Keep terse single-line statements (for example, `if (x) return false;`) intact +# rather than force-splitting them onto multiple lines (guide section 3). +csharp_preserve_single_line_statements = true + +#### 'this.' qualification - not used (guide section 4) #### + +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_event = false:warning + +#### Language keywords over framework type names #### + +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + +#### var preferences (guide section 5) #### +# `var` is the default; explicit types remain acceptable where clearer, so +# these are suggestions rather than warnings. + +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +#### Expression-bodied members (guide section 3) #### + +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_constructors = when_on_single_line:suggestion +csharp_style_expression_bodied_operators = when_on_single_line:suggestion +csharp_style_expression_bodied_properties = when_on_single_line:suggestion +csharp_style_expression_bodied_indexers = when_on_single_line:suggestion +csharp_style_expression_bodied_accessors = when_on_single_line:suggestion +csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion +csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion + +#### Modern language idioms (guide section 5) #### + +csharp_style_namespace_declarations = file_scoped:warning +csharp_prefer_braces = when_multiline:suggestion +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_static_local_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +dotnet_style_collection_initializer = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +#### Modifiers #### + +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +dotnet_style_readonly_field = true:suggestion + +#### Parentheses clarity #### + +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent + +########################################## +# Naming conventions (guide section 4) +########################################## + +# --- Symbol groups --- +dotnet_naming_symbols.types.applicable_kinds = class, struct, enum, delegate +dotnet_naming_symbols.types.applicable_accessibilities = * + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = * + +dotnet_naming_symbols.type_parameters.applicable_kinds = type_parameter +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * + +dotnet_naming_symbols.members.applicable_kinds = property, method, event, namespace +dotnet_naming_symbols.members.applicable_accessibilities = * + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.applicable_accessibilities = * +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = * +dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, protected, protected_internal + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, internal, private_protected + +dotnet_naming_symbols.parameters_locals.applicable_kinds = parameter, local +dotnet_naming_symbols.parameters_locals.applicable_accessibilities = * + +# --- Naming styles --- +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.camel_case.capitalization = camel_case + +dotnet_naming_style.interface_prefix.capitalization = pascal_case +dotnet_naming_style.interface_prefix.required_prefix = I + +dotnet_naming_style.type_parameter_prefix.capitalization = pascal_case +dotnet_naming_style.type_parameter_prefix.required_prefix = T + +dotnet_naming_style.underscore_camel_case.capitalization = camel_case +dotnet_naming_style.underscore_camel_case.required_prefix = _ + +# --- Rules (ordered specific -> general) --- +dotnet_naming_rule.interfaces_prefixed_i.symbols = interfaces +dotnet_naming_rule.interfaces_prefixed_i.style = interface_prefix +dotnet_naming_rule.interfaces_prefixed_i.severity = warning + +dotnet_naming_rule.type_parameters_prefixed_t.symbols = type_parameters +dotnet_naming_rule.type_parameters_prefixed_t.style = type_parameter_prefix +dotnet_naming_rule.type_parameters_prefixed_t.severity = warning + +dotnet_naming_rule.types_pascal.symbols = types +dotnet_naming_rule.types_pascal.style = pascal_case +dotnet_naming_rule.types_pascal.severity = warning + +dotnet_naming_rule.members_pascal.symbols = members +dotnet_naming_rule.members_pascal.style = pascal_case +dotnet_naming_rule.members_pascal.severity = warning + +dotnet_naming_rule.constants_pascal.symbols = constants +dotnet_naming_rule.constants_pascal.style = pascal_case +dotnet_naming_rule.constants_pascal.severity = warning + +dotnet_naming_rule.static_readonly_pascal.symbols = static_readonly_fields +dotnet_naming_rule.static_readonly_pascal.style = pascal_case +dotnet_naming_rule.static_readonly_pascal.severity = warning + +dotnet_naming_rule.public_fields_pascal.symbols = public_fields +dotnet_naming_rule.public_fields_pascal.style = pascal_case +dotnet_naming_rule.public_fields_pascal.severity = warning + +dotnet_naming_rule.private_fields_underscore.symbols = private_fields +dotnet_naming_rule.private_fields_underscore.style = underscore_camel_case +dotnet_naming_rule.private_fields_underscore.severity = warning + +dotnet_naming_rule.parameters_locals_camel.symbols = parameters_locals +dotnet_naming_rule.parameters_locals_camel.style = camel_case +dotnet_naming_rule.parameters_locals_camel.severity = suggestion + +########################################## +# Test projects - relax naming so xUnit +# `Method_State_Expected` style is allowed. +########################################## +[tests/**.cs] +dotnet_naming_rule.members_pascal.severity = none +dotnet_diagnostic.IDE0005.severity = warning diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 568cb57..5475d34 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -105,6 +105,12 @@ S-57 uses **chain-node topology**: ## Coding Conventions +- The normative C# rules are in [`docs/coding-style.md`](../docs/coding-style.md) + and encoded in [`.editorconfig`](../.editorconfig). Follow both when changing + code. +- Before finishing, run `dotnet format whitespace EncDotNet.slnx` and + `dotnet format style EncDotNet.slnx --diagnostics IDE0005`; CI verifies both + with `--verify-no-changes`. - Target framework: **.NET 10** with nullable reference types and implicit usings enabled. - Use `ReadOnlySpan` for parsing hot paths where possible. - Use `ImmutableArray` and `ImmutableDictionary` for parsed record data — records are immutable after construction. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4da271a..a72248b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET uses: actions/setup-dotnet@v4 @@ -49,6 +49,32 @@ jobs: name: nupkgs path: nupkgs/*.nupkg + format: + name: Format check + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Restore + run: dotnet restore + + - name: Verify formatting (whitespace) + # Fix locally with: dotnet format whitespace EncDotNet.slnx + run: dotnet format whitespace EncDotNet.slnx --no-restore --verify-no-changes + + - name: Verify usings (ordering + unused) + # Fix locally with: + # dotnet format style EncDotNet.slnx --diagnostics IDE0005 + run: dotnet format style EncDotNet.slnx --diagnostics IDE0005 --severity warn --no-restore --verify-no-changes + publish: needs: build strategy: @@ -74,7 +100,7 @@ jobs: MACOS_SIGNING_ENABLED: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12 != '' && github.event_name != 'pull_request' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup .NET uses: actions/setup-dotnet@v4 diff --git a/Directory.Build.props b/Directory.Build.props index 918776b..26982e6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,6 +6,11 @@ enable true true + + true + true + all diff --git a/Directory.Packages.props b/Directory.Packages.props index b492568..6c55d20 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,23 +3,23 @@ true - - - - + + + + - + - + - - - + + + diff --git a/docs/coding-style.md b/docs/coding-style.md new file mode 100644 index 0000000..033eec1 --- /dev/null +++ b/docs/coding-style.md @@ -0,0 +1,108 @@ +# C# coding style guide + +This is the **normative** coding style guide for the C#/.NET code in +EncDotNet. It makes the repository's style explicit rather than requiring +contributors to infer it from surrounding code. + +> **Enforcement.** Mechanically checkable rules are encoded in +> [`.editorconfig`](../.editorconfig). CI gates whitespace with `dotnet format +> whitespace --verify-no-changes` and using directives with `dotnet format +> style --diagnostics IDE0005 --verify-no-changes`. Broader style and naming +> rules remain hand-followed because `dotnet format` cannot safely Fix-All +> naming. When this guide and `.editorconfig` disagree, `.editorconfig` wins. + +## 1. Guiding principles + +1. Prefer consistency over personal preference. +2. Treat compiler and analyzer warnings as failures; fix causes rather than + suppressing warnings. +3. Model nullability honestly instead of defeating the analyzer. +4. Use `dotnet format` rather than hand-formatting against the rules. + +## 2. Files, namespaces, and usings + +- Use one top-level type per file and match the file name to the type. Small, + tightly coupled helpers and partial types are exceptions. +- Use file-scoped namespaces. +- Keep `using` directives outside the namespace, order `System.*` first, and + remove unused directives. +- Use UTF-8, LF line endings, a trailing newline, and no trailing whitespace. + +## 3. Formatting + +- Indent C# with four spaces and never tabs. +- Use Allman braces. +- Brace multi-line blocks. Terse, same-line guards may remain unbraced. +- Keep one statement and one declaration per line. +- Keep lines reasonably short, generally 100-120 columns. +- Use expression-bodied members for readable one-liners. + +## 4. Naming + +| Element | Convention | Example | +|---|---|---| +| Namespace, type, method, property, event, enum member | `PascalCase` | `S57Document`, `TryParse` | +| Interface | `PascalCase` prefixed with `I` | `IRecordReader` | +| Type parameter | `PascalCase` prefixed with `T` | `TRecord`, `TKey` | +| Local variable, parameter | `camelCase` | `recordLength`, `field` | +| Private/internal instance field | `_camelCase` | `_recordReader` | +| Constant, `static readonly` | `PascalCase` | `FieldTerminator` | +| Async method | `PascalCase` suffixed `Async` | `ReadCatalogAsync` | + +Do not prefix member access with `this.`. Prefer descriptive names, while +retaining well-known S-57, S-52, and ISO/IEC 8211 domain abbreviations. + +## 5. Language features and idioms + +- Prefer `var` for locals unless an explicit type materially improves clarity. +- Prefer target-typed `new`, collection expressions, and range/index operators. +- Prefer pattern matching and switch expressions where they read clearly. +- Prefer string interpolation and use an explicit `StringComparison` where + culture affects semantics. +- Use `is null` and `is not null` for reference equality checks. + +## 6. Nullability and argument validation + +- Do not use the null-forgiving operator merely to silence the analyzer. +- Validate public entry-point arguments with the standard + `ArgumentException` helpers. +- Use `Parse`/`TryParse` pairs for parsing and throw the most specific standard + exception with a useful message. + +## 7. Documentation comments + +- Public and protected APIs require XML documentation, including parameters, + return values, and exceptions where applicable. +- Use `` and `...` for references and inline code. +- Comments explain non-obvious rationale or standards-derived invariants; they + do not narrate self-explanatory implementation. + +## 8. Standards-derived code + +For constants, enums, attributes, field tags, subfields, and encodings derived +from IHO S-57, IHO S-52, or ISO/IEC 8211, cite the relevant standard and section +in XML documentation when practical. + +## 9. Async + +- Suffix async methods with `Async` and return `Task`, `Task`, or + `ValueTask`. +- Accept and honor `CancellationToken` for asynchronous I/O APIs. +- Do not expose `async void` except for event handlers. +- Avoid `.Result`, `.Wait()`, and `.GetAwaiter().GetResult()`. + +## 10. Dependencies and build + +- Manage NuGet versions centrally in `Directory.Packages.props`. +- Do not use `#pragma warning disable` or `` without a specific, + documented justification. +- Keep code cross-platform and gate platform-specific APIs appropriately. + +Before pushing, apply and verify the CI-enforced subsets: + +```bash +dotnet format whitespace EncDotNet.slnx +dotnet format style EncDotNet.slnx --diagnostics IDE0005 +dotnet format whitespace EncDotNet.slnx --verify-no-changes +dotnet format style EncDotNet.slnx --diagnostics IDE0005 --verify-no-changes +``` diff --git a/docs/index.md b/docs/index.md index 022a68d..0c34415 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,3 +7,4 @@ Conceptual guides and reference material for EncDotNet. - [Getting Started](getting-started.md) — Install the libraries and learn the reader APIs - [Architecture](architecture.md) — How ENC standards map to the library layers - [S-57 Glossary](glossary.md) — Key abbreviations and terminology from the IHO S-57 and ISO 8211 standards +- [C# Coding Style](coding-style.md) — Normative style and formatting rules for contributors diff --git a/docs/toc.yml b/docs/toc.yml index 6571706..30c1a3a 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -7,3 +7,5 @@ href: architecture.md - name: S-57 Glossary href: glossary.md + - name: C# Coding Style + href: coding-style.md diff --git a/src/EncDotNet.ChartViewer/App.axaml.cs b/src/EncDotNet.ChartViewer/App.axaml.cs index 1aac9b3..62b4e98 100644 --- a/src/EncDotNet.ChartViewer/App.axaml.cs +++ b/src/EncDotNet.ChartViewer/App.axaml.cs @@ -1,4 +1,3 @@ -using System; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; @@ -90,4 +89,4 @@ private static void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddTransient(); } -} \ No newline at end of file +} diff --git a/src/EncDotNet.ChartViewer/Baking/ChartBaker.cs b/src/EncDotNet.ChartViewer/Baking/ChartBaker.cs index f48bafa..cfb3eb6 100644 --- a/src/EncDotNet.ChartViewer/Baking/ChartBaker.cs +++ b/src/EncDotNet.ChartViewer/Baking/ChartBaker.cs @@ -1,7 +1,4 @@ using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Threading.Tasks; using EncDotNet.S57; using MessagePack; using MessagePack.Resolvers; diff --git a/src/EncDotNet.ChartViewer/ChartViewerDiagnostics.cs b/src/EncDotNet.ChartViewer/ChartViewerDiagnostics.cs index ca9c10e..fc3c588 100644 --- a/src/EncDotNet.ChartViewer/ChartViewerDiagnostics.cs +++ b/src/EncDotNet.ChartViewer/ChartViewerDiagnostics.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using System.Diagnostics.Metrics; using System.Reflection; diff --git a/src/EncDotNet.ChartViewer/Charts/AppDataPaths.cs b/src/EncDotNet.ChartViewer/Charts/AppDataPaths.cs index 5e6905c..11afb26 100644 --- a/src/EncDotNet.ChartViewer/Charts/AppDataPaths.cs +++ b/src/EncDotNet.ChartViewer/Charts/AppDataPaths.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.IO; using System.Text.Json; using System.Text.Json.Serialization.Metadata; using EncDotNet.ChartViewer.Models; diff --git a/src/EncDotNet.ChartViewer/Charts/CachedChartSource.cs b/src/EncDotNet.ChartViewer/Charts/CachedChartSource.cs index 6c291ad..d1b7778 100644 --- a/src/EncDotNet.ChartViewer/Charts/CachedChartSource.cs +++ b/src/EncDotNet.ChartViewer/Charts/CachedChartSource.cs @@ -1,6 +1,4 @@ using System.Collections.Concurrent; -using System.Threading; -using System.Threading.Tasks; using EncDotNet.ChartViewer.Models; using EncDotNet.S57.Charts; diff --git a/src/EncDotNet.ChartViewer/Charts/FileSystemChartCatalogSource.cs b/src/EncDotNet.ChartViewer/Charts/FileSystemChartCatalogSource.cs index ffdc70e..be253a2 100644 --- a/src/EncDotNet.ChartViewer/Charts/FileSystemChartCatalogSource.cs +++ b/src/EncDotNet.ChartViewer/Charts/FileSystemChartCatalogSource.cs @@ -1,11 +1,7 @@ -using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization.Metadata; -using System.Threading; -using System.Threading.Tasks; using EncDotNet.ChartViewer.Baking; using EncDotNet.ChartViewer.Models; using EncDotNet.S57.Charts; diff --git a/src/EncDotNet.ChartViewer/Charts/IChartCatalogSource.cs b/src/EncDotNet.ChartViewer/Charts/IChartCatalogSource.cs index 399608a..22dc5d7 100644 --- a/src/EncDotNet.ChartViewer/Charts/IChartCatalogSource.cs +++ b/src/EncDotNet.ChartViewer/Charts/IChartCatalogSource.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Threading; using EncDotNet.ChartViewer.Models; namespace EncDotNet.ChartViewer.Charts; diff --git a/src/EncDotNet.ChartViewer/Charts/IChartPackageManager.cs b/src/EncDotNet.ChartViewer/Charts/IChartPackageManager.cs index 6bbd69f..355ed54 100644 --- a/src/EncDotNet.ChartViewer/Charts/IChartPackageManager.cs +++ b/src/EncDotNet.ChartViewer/Charts/IChartPackageManager.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - namespace EncDotNet.ChartViewer.Charts; public sealed record ChartPackage diff --git a/src/EncDotNet.ChartViewer/Charts/IChartSource.cs b/src/EncDotNet.ChartViewer/Charts/IChartSource.cs index 286f3fa..ab17edd 100644 --- a/src/EncDotNet.ChartViewer/Charts/IChartSource.cs +++ b/src/EncDotNet.ChartViewer/Charts/IChartSource.cs @@ -1,5 +1,3 @@ -using System.Threading; -using System.Threading.Tasks; using EncDotNet.ChartViewer.Models; using EncDotNet.S57.Charts; diff --git a/src/EncDotNet.ChartViewer/Charts/NoaaChartPackageManager.cs b/src/EncDotNet.ChartViewer/Charts/NoaaChartPackageManager.cs index 14fb2c8..918b5b7 100644 --- a/src/EncDotNet.ChartViewer/Charts/NoaaChartPackageManager.cs +++ b/src/EncDotNet.ChartViewer/Charts/NoaaChartPackageManager.cs @@ -1,17 +1,10 @@ -using System; -using System.Collections.Generic; -using System.IO; using System.IO.Compression; -using System.Linq; -using System.Net.Http; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization.Metadata; -using System.Threading; -using System.Threading.Tasks; using EncDotNet.ChartViewer.Models; -using EncDotNet.S57.ExchangeSets; using EncDotNet.Noaa; +using EncDotNet.S57.ExchangeSets; namespace EncDotNet.ChartViewer.Charts; diff --git a/src/EncDotNet.ChartViewer/DiagnosticOptions.cs b/src/EncDotNet.ChartViewer/DiagnosticOptions.cs index 192e165..ad70f0b 100644 --- a/src/EncDotNet.ChartViewer/DiagnosticOptions.cs +++ b/src/EncDotNet.ChartViewer/DiagnosticOptions.cs @@ -1,4 +1,3 @@ -using System; using System.Globalization; namespace EncDotNet.ChartViewer; diff --git a/src/EncDotNet.ChartViewer/Models/LayerUpdate.cs b/src/EncDotNet.ChartViewer/Models/LayerUpdate.cs index 09bba66..752dde6 100644 --- a/src/EncDotNet.ChartViewer/Models/LayerUpdate.cs +++ b/src/EncDotNet.ChartViewer/Models/LayerUpdate.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using Mapsui.Layers; namespace EncDotNet.ChartViewer.Models; diff --git a/src/EncDotNet.ChartViewer/Models/S57FeatureCategory.cs b/src/EncDotNet.ChartViewer/Models/S57FeatureCategory.cs index 4ab9a16..bff2ff0 100644 --- a/src/EncDotNet.ChartViewer/Models/S57FeatureCategory.cs +++ b/src/EncDotNet.ChartViewer/Models/S57FeatureCategory.cs @@ -21,7 +21,7 @@ private S57FeatureCategory(string name, bool defaultEnabled, params S57ObjectCod { Name = name; DefaultEnabled = defaultEnabled; - ObjectCodes = [..objectCodes]; + ObjectCodes = [.. objectCodes]; } // S-57 object class codes diff --git a/src/EncDotNet.ChartViewer/Program.cs b/src/EncDotNet.ChartViewer/Program.cs index 3d93a39..6930a7b 100644 --- a/src/EncDotNet.ChartViewer/Program.cs +++ b/src/EncDotNet.ChartViewer/Program.cs @@ -1,10 +1,9 @@ -using Avalonia; +using Avalonia; using ReactiveUI.Avalonia; -using System; namespace EncDotNet.ChartViewer; -sealed class Program +internal sealed class Program { [STAThread] public static void Main(string[] args) @@ -19,4 +18,4 @@ public static AppBuilder BuildAvaloniaApp() .WithInterFont() .LogToTrace() .UseReactiveUI(); -} \ No newline at end of file +} diff --git a/src/EncDotNet.ChartViewer/ProjectedEdgeCache.cs b/src/EncDotNet.ChartViewer/ProjectedEdgeCache.cs index 8f92a8f..df9fb8a 100644 --- a/src/EncDotNet.ChartViewer/ProjectedEdgeCache.cs +++ b/src/EncDotNet.ChartViewer/ProjectedEdgeCache.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Runtime.CompilerServices; using EncDotNet.S57; using EncDotNet.S57.Charts; diff --git a/src/EncDotNet.ChartViewer/S57AreaGeometryBuilder.cs b/src/EncDotNet.ChartViewer/S57AreaGeometryBuilder.cs index 38b1902..b0c796c 100644 --- a/src/EncDotNet.ChartViewer/S57AreaGeometryBuilder.cs +++ b/src/EncDotNet.ChartViewer/S57AreaGeometryBuilder.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using EncDotNet.S57; using EncDotNet.S57.Charts; using NetTopologySuite.Geometries; diff --git a/src/EncDotNet.ChartViewer/S57CoverageHelper.cs b/src/EncDotNet.ChartViewer/S57CoverageHelper.cs index d5f8ae2..851916a 100644 --- a/src/EncDotNet.ChartViewer/S57CoverageHelper.cs +++ b/src/EncDotNet.ChartViewer/S57CoverageHelper.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using EncDotNet.S57.Charts; using NetTopologySuite.Geometries; using NetTopologySuite.Geometries.Prepared; diff --git a/src/EncDotNet.ChartViewer/S57LayerFactory.cs b/src/EncDotNet.ChartViewer/S57LayerFactory.cs index 101582c..428e173 100644 --- a/src/EncDotNet.ChartViewer/S57LayerFactory.cs +++ b/src/EncDotNet.ChartViewer/S57LayerFactory.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.Metrics; -using EncDotNet.S57; -using EncDotNet.S57.Charts; using EncDotNet.ChartViewer.Models; using EncDotNet.ChartViewer.ViewModels; +using EncDotNet.S57; +using EncDotNet.S57.Charts; using Mapsui; using Mapsui.Layers; @@ -195,14 +192,14 @@ internal static void RecalculateMinVisible(IReadOnlyCollection l // simplified geometry could cause visual artifacts. Three levels balances coverage // completeness against overscale artifact risk; fewer levels can leave gaps where // no chart covers the viewport. - const int overlapLevels = 3; + const int OverlapLevels = 3; var scales = new List>(scaleMaxVisible); var scaleMinVisible = new Dictionary(); for (int i = 0; i < scales.Count; i++) { - // The finest N scales (i < overlapLevels) keep MinVisible = 0. + // The finest N scales (i < OverlapLevels) keep MinVisible = 0. // Coarser scales reference the chart N levels finer. - double minVis = i >= overlapLevels ? scales[i - overlapLevels].Value : 0; + double minVis = i >= OverlapLevels ? scales[i - OverlapLevels].Value : 0; scaleMinVisible[scales[i].Key] = minVis; } diff --git a/src/EncDotNet.ChartViewer/S57LayerTemplate.cs b/src/EncDotNet.ChartViewer/S57LayerTemplate.cs index 3291cd2..4a8ee42 100644 --- a/src/EncDotNet.ChartViewer/S57LayerTemplate.cs +++ b/src/EncDotNet.ChartViewer/S57LayerTemplate.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; using System.Globalization; -using EncDotNet.S57.Charts; using EncDotNet.ChartViewer.Models; +using EncDotNet.S57.Charts; using Mapsui; using Mapsui.Nts; using Mapsui.Projections; diff --git a/src/EncDotNet.ChartViewer/S57LayerTemplates.cs b/src/EncDotNet.ChartViewer/S57LayerTemplates.cs index 7f4b5f4..e078d72 100644 --- a/src/EncDotNet.ChartViewer/S57LayerTemplates.cs +++ b/src/EncDotNet.ChartViewer/S57LayerTemplates.cs @@ -1,9 +1,8 @@ using System.Collections.Frozen; -using System.Collections.Generic; using System.Globalization; +using EncDotNet.ChartViewer.Models; using EncDotNet.S57; using EncDotNet.S57.Charts; -using EncDotNet.ChartViewer.Models; using Mapsui; using Mapsui.Nts; using Mapsui.Projections; @@ -423,9 +422,9 @@ private static IEnumerable CreateDepcntFeatures(S57Chart chart, S57Lin // Default depth zone boundaries (metres). S-52 allows the mariner to // adjust these; the values below are the S-52 recommended defaults. private const double DepthDryingLine = 0.0; // boundary between DEPIT and DEPVS - private const double DepthShallow = 2.0; // boundary between DEPVS and DEPMS - private const double DepthSafety = 5.0; // boundary between DEPMS and DEPMD (default safety contour) - private const double DepthDeep = 30.0; // boundary between DEPMD and DEPDW + private const double DepthShallow = 2.0; // boundary between DEPVS and DEPMS + private const double DepthSafety = 5.0; // boundary between DEPMS and DEPMD (default safety contour) + private const double DepthDeep = 30.0; // boundary between DEPMD and DEPDW /// /// Returns the colour and line width for a depth contour feature. @@ -560,11 +559,11 @@ private static string FormatFathoms(double totalFeet) int fathoms = wholeFeet / 6; int remainingFeet = wholeFeet % 6; - const string subscriptDigits = "₀₁₂₃₄₅"; + const string SubscriptDigits = "₀₁₂₃₄₅"; return remainingFeet == 0 ? fathoms.ToString() - : $"{fathoms}{subscriptDigits[remainingFeet]}"; + : $"{fathoms}{SubscriptDigits[remainingFeet]}"; } // --- Buoy icon selection --- diff --git a/src/EncDotNet.ChartViewer/S57LineGeometryBuilder.cs b/src/EncDotNet.ChartViewer/S57LineGeometryBuilder.cs index 6806f35..22fbdb4 100644 --- a/src/EncDotNet.ChartViewer/S57LineGeometryBuilder.cs +++ b/src/EncDotNet.ChartViewer/S57LineGeometryBuilder.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using EncDotNet.S57; using EncDotNet.S57.Charts; using NetTopologySuite.Geometries; diff --git a/src/EncDotNet.ChartViewer/ViewLocator.cs b/src/EncDotNet.ChartViewer/ViewLocator.cs index a1a5a97..fe0f4db 100644 --- a/src/EncDotNet.ChartViewer/ViewLocator.cs +++ b/src/EncDotNet.ChartViewer/ViewLocator.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics.CodeAnalysis; using Avalonia.Controls; using Avalonia.Controls.Templates; @@ -34,4 +33,4 @@ public bool Match(object? data) { return data is ViewModelBase; } -} \ No newline at end of file +} diff --git a/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureItemViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureItemViewModel.cs index c9b0e81..7b4bb5e 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureItemViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureItemViewModel.cs @@ -1,4 +1,3 @@ -using System; using EncDotNet.S57; using ReactiveUI; diff --git a/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureViewModel.cs index b177c73..ffdb10e 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/ChartFeatureViewModel.cs @@ -1,6 +1,4 @@ -using System; using System.Collections.Immutable; -using System.Linq; using EncDotNet.ChartViewer.Models; using EncDotNet.S57; using ReactiveUI; diff --git a/src/EncDotNet.ChartViewer/ViewModels/ChartViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/ChartViewModel.cs index d02a1ec..13298a7 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/ChartViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/ChartViewModel.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.Metrics; -using System.IO; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Input; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; diff --git a/src/EncDotNet.ChartViewer/ViewModels/MainWindowViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/MainWindowViewModel.cs index 2e67be1..a968606 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/MainWindowViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/MainWindowViewModel.cs @@ -1,14 +1,9 @@ -using System; using System.Collections.ObjectModel; -using System.Reactive; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Input; using EncDotNet.ChartViewer.Charts; using EncDotNet.ChartViewer.Models; using EncDotNet.S57.Charts; using ReactiveUI; -using System.Linq; namespace EncDotNet.ChartViewer.ViewModels; @@ -222,4 +217,4 @@ private void ApplyChartFilter() } } } -} \ No newline at end of file +} diff --git a/src/EncDotNet.ChartViewer/ViewModels/ManageChartsViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/ManageChartsViewModel.cs index 650abc1..8249707 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/ManageChartsViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/ManageChartsViewModel.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Input; using EncDotNet.ChartViewer.Charts; using ReactiveUI; diff --git a/src/EncDotNet.ChartViewer/ViewModels/SetupWizardViewModel.cs b/src/EncDotNet.ChartViewer/ViewModels/SetupWizardViewModel.cs index e4f7c4f..1ce7aaa 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/SetupWizardViewModel.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/SetupWizardViewModel.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Input; using EncDotNet.ChartViewer.Charts; using ReactiveUI; diff --git a/src/EncDotNet.ChartViewer/ViewModels/ViewModelBase.cs b/src/EncDotNet.ChartViewer/ViewModels/ViewModelBase.cs index bc493b8..8d0756a 100644 --- a/src/EncDotNet.ChartViewer/ViewModels/ViewModelBase.cs +++ b/src/EncDotNet.ChartViewer/ViewModels/ViewModelBase.cs @@ -1,7 +1,7 @@ -using ReactiveUI; +using ReactiveUI; namespace EncDotNet.ChartViewer.ViewModels; public abstract class ViewModelBase : ReactiveObject { -} \ No newline at end of file +} diff --git a/src/EncDotNet.ChartViewer/Views/FeatureInfoWindow.axaml.cs b/src/EncDotNet.ChartViewer/Views/FeatureInfoWindow.axaml.cs index 3d9421d..5de9748 100644 --- a/src/EncDotNet.ChartViewer/Views/FeatureInfoWindow.axaml.cs +++ b/src/EncDotNet.ChartViewer/Views/FeatureInfoWindow.axaml.cs @@ -1,7 +1,5 @@ -using System.Collections.Generic; using System.Text; using Avalonia.Controls; -using Avalonia.Input; using Avalonia.Interactivity; using EncDotNet.S57; diff --git a/src/EncDotNet.ChartViewer/Views/MainWindow.axaml.cs b/src/EncDotNet.ChartViewer/Views/MainWindow.axaml.cs index 15f315c..67cf364 100644 --- a/src/EncDotNet.ChartViewer/Views/MainWindow.axaml.cs +++ b/src/EncDotNet.ChartViewer/Views/MainWindow.axaml.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; -using System.IO; -using System.Linq; using System.Text; -using System.Threading; -using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; @@ -17,18 +12,17 @@ using EncDotNet.ChartViewer.ViewModels; using EncDotNet.S57; using Mapsui; -using Microsoft.Extensions.DependencyInjection; using Mapsui.Extensions; using Mapsui.Layers; -using System.Collections.Immutable; using Mapsui.Manipulations; using Mapsui.Nts; using Mapsui.Projections; using Mapsui.Styles; using Mapsui.Styles.Thematics; using Mapsui.Tiling; -using NetTopologySuite.Geometries; using Mapsui.Widgets.ScaleBar; +using Microsoft.Extensions.DependencyInjection; +using NetTopologySuite.Geometries; namespace EncDotNet.ChartViewer.Views; diff --git a/src/EncDotNet.ChartViewer/Views/ManageChartsWindow.axaml.cs b/src/EncDotNet.ChartViewer/Views/ManageChartsWindow.axaml.cs index 42d259c..b81731a 100644 --- a/src/EncDotNet.ChartViewer/Views/ManageChartsWindow.axaml.cs +++ b/src/EncDotNet.ChartViewer/Views/ManageChartsWindow.axaml.cs @@ -1,4 +1,3 @@ -using System; using Avalonia.Controls; using EncDotNet.ChartViewer.ViewModels; diff --git a/src/EncDotNet.ChartViewer/Views/SetupWizardWindow.axaml.cs b/src/EncDotNet.ChartViewer/Views/SetupWizardWindow.axaml.cs index 2bec5bb..0f6c4cf 100644 --- a/src/EncDotNet.ChartViewer/Views/SetupWizardWindow.axaml.cs +++ b/src/EncDotNet.ChartViewer/Views/SetupWizardWindow.axaml.cs @@ -1,4 +1,3 @@ -using System; using Avalonia.Controls; using EncDotNet.ChartViewer.ViewModels; diff --git a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecord.cs b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecord.cs index 87c4f7b..8f4666b 100644 --- a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecord.cs +++ b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecord.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.Iso8211; /// diff --git a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs index 78966f6..0481042 100644 --- a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs +++ b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs @@ -1,6 +1,5 @@ using System.Collections.Concurrent; using System.Collections.Immutable; -using System.Text; namespace EncDotNet.Iso8211; @@ -40,7 +39,7 @@ public static class Iso8211DataDescriptiveRecordReader /// Since every DDR field shares the same internal layout for a given field control length, /// we avoid repeated allocations by caching the definition. /// - private static readonly ConcurrentDictionary s_ddrFieldDefinitionCache = new(); + private static readonly ConcurrentDictionary DdrFieldDefinitionCache = new(); /// /// Parses an that represents a DDR and returns a @@ -108,7 +107,7 @@ public static Iso8211DataDescriptiveRecord Read(Iso8211Record record) /// An describing the DDR's own field structure. public static Iso8211FieldDefinition GetDdrFieldDefinition(int fieldControlLength) { - return s_ddrFieldDefinitionCache.GetOrAdd(fieldControlLength, static fcl => + return DdrFieldDefinitionCache.GetOrAdd(fieldControlLength, static fcl => { var subfieldDefinitions = CreateDdrSubfieldDefinitions(fcl); diff --git a/src/EncDotNet.Iso8211/Iso8211Document.cs b/src/EncDotNet.Iso8211/Iso8211Document.cs index 070416c..337070b 100644 --- a/src/EncDotNet.Iso8211/Iso8211Document.cs +++ b/src/EncDotNet.Iso8211/Iso8211Document.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.Iso8211; /// diff --git a/src/EncDotNet.Iso8211/Iso8211DocumentReader.cs b/src/EncDotNet.Iso8211/Iso8211DocumentReader.cs index 6a4606a..e7b4e16 100644 --- a/src/EncDotNet.Iso8211/Iso8211DocumentReader.cs +++ b/src/EncDotNet.Iso8211/Iso8211DocumentReader.cs @@ -1,5 +1,3 @@ -using System.Text; - namespace EncDotNet.Iso8211; /// diff --git a/src/EncDotNet.Iso8211/Iso8211FieldDefinition.cs b/src/EncDotNet.Iso8211/Iso8211FieldDefinition.cs index 2e1d2b1..8d04968 100644 --- a/src/EncDotNet.Iso8211/Iso8211FieldDefinition.cs +++ b/src/EncDotNet.Iso8211/Iso8211FieldDefinition.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.Iso8211; /// diff --git a/src/EncDotNet.Iso8211/Iso8211FieldReader.cs b/src/EncDotNet.Iso8211/Iso8211FieldReader.cs index 496bf7a..ac1a3bd 100644 --- a/src/EncDotNet.Iso8211/Iso8211FieldReader.cs +++ b/src/EncDotNet.Iso8211/Iso8211FieldReader.cs @@ -370,7 +370,7 @@ public IEnumerable GetSubfieldGroups() { break; } - + // For fixed-width subfields in repeating groups, check if we've hit the end: // If the remaining data is just the field terminator, we're done. if (format.IsFixedWidth && _fieldDefinition.HasRepeatingGroup) @@ -688,7 +688,7 @@ private static object ConvertUnsignedBinary(ReadOnlySpan data, int widt { // Use actual data length if shorter than expected width int actualWidth = Math.Min(width, data.Length); - + ulong value = actualWidth switch { 1 => data[0], @@ -753,7 +753,7 @@ private static object ConvertSignedBinary(ReadOnlySpan data, int width) { // Use actual data length if shorter than expected width int actualWidth = Math.Min(width, data.Length); - + long value = actualWidth switch { 1 => (sbyte)data[0], @@ -896,7 +896,7 @@ private static ulong ReadUnsignedLittleEndian(ReadOnlySpan data, int width private static long ReadSignedLittleEndian(ReadOnlySpan data, int width) { var unsigned = ReadUnsignedLittleEndian(data, width); - + // Sign extend if the high bit is set var signBit = 1UL << (width * 8 - 1); if ((unsigned & signBit) != 0) diff --git a/src/EncDotNet.Iso8211/Iso8211Reader.cs b/src/EncDotNet.Iso8211/Iso8211Reader.cs index 7a69d2c..a2406d8 100644 --- a/src/EncDotNet.Iso8211/Iso8211Reader.cs +++ b/src/EncDotNet.Iso8211/Iso8211Reader.cs @@ -358,7 +358,7 @@ public bool TrySkipRecord() // Move past the current record var recordEnd = _fieldAreaOffset + (_leader.RecordLength - _leader.BaseAddressOfFieldArea); - + // Check if we have enough data if (recordEnd > _buffer.Length) { @@ -370,7 +370,7 @@ public bool TrySkipRecord() // Need more data return false; } - + var bytesToSkip = recordEnd - _consumed; if (bytesToSkip > 0) { @@ -498,7 +498,7 @@ private bool TryReadRecordStart() // Parse leader var recordLength = ParseNumeric(leaderSpan, 0, 5); - + // Check if we have the entire record if (_buffer.Length - _consumed < recordLength) { diff --git a/src/EncDotNet.Iso8211/Iso8211Record.cs b/src/EncDotNet.Iso8211/Iso8211Record.cs index 6649467..b88bf4a 100644 --- a/src/EncDotNet.Iso8211/Iso8211Record.cs +++ b/src/EncDotNet.Iso8211/Iso8211Record.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.Iso8211; /// diff --git a/src/EncDotNet.Iso8211/Iso8211SubfieldEncoder.cs b/src/EncDotNet.Iso8211/Iso8211SubfieldEncoder.cs index 60a6ea5..b166c5f 100644 --- a/src/EncDotNet.Iso8211/Iso8211SubfieldEncoder.cs +++ b/src/EncDotNet.Iso8211/Iso8211SubfieldEncoder.cs @@ -151,17 +151,17 @@ private static byte[] EncodeFloatingBinary(object? value, int width) switch (width) { case 4: - { - var bytes = new byte[4]; - BinaryPrimitives.WriteSingleLittleEndian(bytes, (float)d); - return bytes; - } + { + var bytes = new byte[4]; + BinaryPrimitives.WriteSingleLittleEndian(bytes, (float)d); + return bytes; + } case 8: - { - var bytes = new byte[8]; - BinaryPrimitives.WriteDoubleLittleEndian(bytes, d); - return bytes; - } + { + var bytes = new byte[8]; + BinaryPrimitives.WriteDoubleLittleEndian(bytes, d); + return bytes; + } default: throw new InvalidOperationException($"Unsupported floating-point binary width: {width} byte(s)."); } @@ -178,10 +178,10 @@ private static byte[] EncodeBitString(object? value, int width) } return FitToWidth(raw, width, 0); case string hex: - { - var raw = Convert.FromHexString(hex); - return width <= 0 ? raw : FitToWidth(raw, width, 0); - } + { + var raw = Convert.FromHexString(hex); + return width <= 0 ? raw : FitToWidth(raw, width, 0); + } case null: return width <= 0 ? Array.Empty() : new byte[width]; default: diff --git a/src/EncDotNet.Noaa/EncProductCatalogClient.cs b/src/EncDotNet.Noaa/EncProductCatalogClient.cs index 5c0b033..16d677a 100644 --- a/src/EncDotNet.Noaa/EncProductCatalogClient.cs +++ b/src/EncDotNet.Noaa/EncProductCatalogClient.cs @@ -45,8 +45,8 @@ public async Task GetCatalogAsync(string url, CancellationTok /// The deserialized . public async Task GetNoaaCatalogAsync(CancellationToken cancellationToken = default) { - const string noaaUrl = "https://www.charts.noaa.gov/ENCs/ENCProdCat.xml"; - return await GetCatalogAsync(noaaUrl, cancellationToken); + const string NoaaUrl = "https://www.charts.noaa.gov/ENCs/ENCProdCat.xml"; + return await GetCatalogAsync(NoaaUrl, cancellationToken); } /// diff --git a/src/EncDotNet.S57/Charts/S57AreaFeature.cs b/src/EncDotNet.S57/Charts/S57AreaFeature.cs index 74ae463..10e2969 100644 --- a/src/EncDotNet.S57/Charts/S57AreaFeature.cs +++ b/src/EncDotNet.S57/Charts/S57AreaFeature.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using System.Linq; namespace EncDotNet.S57.Charts; diff --git a/src/EncDotNet.S57/Charts/S57Edge.cs b/src/EncDotNet.S57/Charts/S57Edge.cs index 7c0638e..04252c5 100644 --- a/src/EncDotNet.S57/Charts/S57Edge.cs +++ b/src/EncDotNet.S57/Charts/S57Edge.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/Charts/S57EdgeReference.cs b/src/EncDotNet.S57/Charts/S57EdgeReference.cs index 24e2ddd..f6e50b6 100644 --- a/src/EncDotNet.S57/Charts/S57EdgeReference.cs +++ b/src/EncDotNet.S57/Charts/S57EdgeReference.cs @@ -37,6 +37,6 @@ public S57EdgeReference( } /// - public override string ToString() => + public override string ToString() => $"Edge {EdgeName}, Orientation={Orientation}, Usage={Usage}"; } diff --git a/src/EncDotNet.S57/Charts/S57IsolatedNode.cs b/src/EncDotNet.S57/Charts/S57IsolatedNode.cs index d6f13c6..73a64bc 100644 --- a/src/EncDotNet.S57/Charts/S57IsolatedNode.cs +++ b/src/EncDotNet.S57/Charts/S57IsolatedNode.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/Charts/S57LineFeature.cs b/src/EncDotNet.S57/Charts/S57LineFeature.cs index 632f679..d545c39 100644 --- a/src/EncDotNet.S57/Charts/S57LineFeature.cs +++ b/src/EncDotNet.S57/Charts/S57LineFeature.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/Charts/S57PointFeature.cs b/src/EncDotNet.S57/Charts/S57PointFeature.cs index 7f24143..d5cd42a 100644 --- a/src/EncDotNet.S57/Charts/S57PointFeature.cs +++ b/src/EncDotNet.S57/Charts/S57PointFeature.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/Charts/S57SpatialRecord.cs b/src/EncDotNet.S57/Charts/S57SpatialRecord.cs index ec1eb37..f4a96a7 100644 --- a/src/EncDotNet.S57/Charts/S57SpatialRecord.cs +++ b/src/EncDotNet.S57/Charts/S57SpatialRecord.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/Charts/S57TypedFeature.cs b/src/EncDotNet.S57/Charts/S57TypedFeature.cs index 3459231..14c6040 100644 --- a/src/EncDotNet.S57/Charts/S57TypedFeature.cs +++ b/src/EncDotNet.S57/Charts/S57TypedFeature.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.Charts; /// diff --git a/src/EncDotNet.S57/ExchangeSets/S57Catalog.cs b/src/EncDotNet.S57/ExchangeSets/S57Catalog.cs index 706c7d1..3dcc780 100644 --- a/src/EncDotNet.S57/ExchangeSets/S57Catalog.cs +++ b/src/EncDotNet.S57/ExchangeSets/S57Catalog.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57.ExchangeSets; /// diff --git a/src/EncDotNet.S57/S57Document.cs b/src/EncDotNet.S57/S57Document.cs index 53a3cbf..69bb4f3 100644 --- a/src/EncDotNet.S57/S57Document.cs +++ b/src/EncDotNet.S57/S57Document.cs @@ -186,8 +186,8 @@ private static S57FeatureRecord ApplyFeatureModify(S57FeatureRecord baseRecord, UpdateInstruction = updateRecord.UpdateInstruction, Attributes = MergeAttributes(baseRecord.Attributes, updateRecord.Attributes), NationalAttributes = MergeAttributes(baseRecord.NationalAttributes, updateRecord.NationalAttributes), - SpatialPointers = ApplyArrayUpdate([..baseRecord.SpatialPointers], [..updateRecord.SpatialPointers], updateRecord.SpatialPointerControl), - FeaturePointers = ApplyArrayUpdate([..baseRecord.FeaturePointers], [..updateRecord.FeaturePointers], updateRecord.FeaturePointerControl), + SpatialPointers = ApplyArrayUpdate([.. baseRecord.SpatialPointers], [.. updateRecord.SpatialPointers], updateRecord.SpatialPointerControl), + FeaturePointers = ApplyArrayUpdate([.. baseRecord.FeaturePointers], [.. updateRecord.FeaturePointers], updateRecord.FeaturePointerControl), }; } @@ -199,9 +199,9 @@ private static S57VectorRecord ApplyVectorModify(S57VectorRecord baseRecord, S57 RecordVersion = updateRecord.RecordVersion, UpdateInstruction = updateRecord.UpdateInstruction, Attributes = MergeAttributes(baseRecord.Attributes, updateRecord.Attributes), - VectorPointers = ApplyArrayUpdate([..baseRecord.VectorPointers], [..updateRecord.VectorPointers], updateRecord.VectorPointerControl), - Coordinates2D = ApplyArrayUpdate([..baseRecord.Coordinates2D], [..updateRecord.Coordinates2D], updateRecord.CoordinateControl), - Soundings = ApplyArrayUpdate([..baseRecord.Soundings], [..updateRecord.Soundings], updateRecord.CoordinateControl), + VectorPointers = ApplyArrayUpdate([.. baseRecord.VectorPointers], [.. updateRecord.VectorPointers], updateRecord.VectorPointerControl), + Coordinates2D = ApplyArrayUpdate([.. baseRecord.Coordinates2D], [.. updateRecord.Coordinates2D], updateRecord.CoordinateControl), + Soundings = ApplyArrayUpdate([.. baseRecord.Soundings], [.. updateRecord.Soundings], updateRecord.CoordinateControl), }; } diff --git a/src/EncDotNet.S57/S57DocumentReader.cs b/src/EncDotNet.S57/S57DocumentReader.cs index a1f6aef..7c2bb6b 100644 --- a/src/EncDotNet.S57/S57DocumentReader.cs +++ b/src/EncDotNet.S57/S57DocumentReader.cs @@ -456,7 +456,7 @@ private static ImmutableArray ParseAttributes(Iso8211Record r { var attributes = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(fieldTag); - + foreach (var field in record.GetFieldsByTag(fieldTag)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -466,7 +466,7 @@ private static ImmutableArray ParseAttributes(Iso8211Record r // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data, lexicalLevel); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -495,7 +495,7 @@ private static ImmutableArray ParseSpatialPointers(Iso8211Rec { var pointers = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(S57FieldTags.FSPT); - + foreach (var field in record.GetFieldsByTag(S57FieldTags.FSPT)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -505,7 +505,7 @@ private static ImmutableArray ParseSpatialPointers(Iso8211Rec // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -514,7 +514,7 @@ private static ImmutableArray ParseSpatialPointers(Iso8211Rec // Read it as raw bytes and decompose var nameBytes = group.GetSubfieldBytes(S57SubfieldNames.NAME); var name = DecomposeNameField(nameBytes); - + var ornt = group.GetSubfield(S57SubfieldNames.ORNT); var usag = group.GetSubfield(S57SubfieldNames.USAG); var mask = group.GetSubfield(S57SubfieldNames.MASK); @@ -545,7 +545,7 @@ private static ImmutableArray ParseFeaturePointers(Iso8211Rec { var pointers = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(S57FieldTags.FFPT); - + foreach (var field in record.GetFieldsByTag(S57FieldTags.FFPT)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -555,7 +555,7 @@ private static ImmutableArray ParseFeaturePointers(Iso8211Rec // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -563,7 +563,7 @@ private static ImmutableArray ParseFeaturePointers(Iso8211Rec // LNAM is a composite subfield (8 bytes: AGEN(2) + FIDN(4) + FIDS(2)) var lnamBytes = group.GetSubfieldBytes(S57SubfieldNames.LNAM); var lnam = DecomposeLongNameField(lnamBytes); - + var rind = group.GetSubfield(S57SubfieldNames.RIND); var comt = group.GetSubfield(S57SubfieldNames.COMT); @@ -592,7 +592,7 @@ private static ImmutableArray ParseVectorPointers(Iso8211Recor { var pointers = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(S57FieldTags.VRPT); - + foreach (var field in record.GetFieldsByTag(S57FieldTags.VRPT)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -602,7 +602,7 @@ private static ImmutableArray ParseVectorPointers(Iso8211Recor // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -610,7 +610,7 @@ private static ImmutableArray ParseVectorPointers(Iso8211Recor // NAME is a composite subfield (5 bytes: RCNM(1) + RCID(4)) var nameBytes = group.GetSubfieldBytes(S57SubfieldNames.NAME); var name = DecomposeNameField(nameBytes); - + var ornt = group.GetSubfield(S57SubfieldNames.ORNT); var usag = group.GetSubfield(S57SubfieldNames.USAG); var topi = group.GetSubfield(S57SubfieldNames.TOPI); @@ -643,7 +643,7 @@ private static ImmutableArray ParseCoordinates2D(Iso8211Record { var coordinates = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(S57FieldTags.SG2D); - + foreach (var field in record.GetFieldsByTag(S57FieldTags.SG2D)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -653,7 +653,7 @@ private static ImmutableArray ParseCoordinates2D(Iso8211Record // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -685,7 +685,7 @@ private static ImmutableArray ParseSoundings(Iso8211Record record, { var soundings = ImmutableArray.CreateBuilder(); var fieldDef = ddr?.GetFieldDefinition(S57FieldTags.SG3D); - + foreach (var field in record.GetFieldsByTag(S57FieldTags.SG3D)) { if (fieldDef == null || !fieldDef.HasRepeatingGroup) @@ -695,7 +695,7 @@ private static ImmutableArray ParseSoundings(Iso8211Record record, // Use DDR-based field reader with repeating groups var reader = new Iso8211FieldReader(fieldDef, field.Data); - + foreach (var group in reader.GetSubfieldGroups()) { try @@ -731,7 +731,7 @@ private static S57RecordName DecomposeNameField(ReadOnlySpan data) { return default; } - + var rcnm = data[0]; var rcid = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(1, 4)); return S57RecordName.FromRcnmRcid(rcnm, (int)rcid); @@ -746,7 +746,7 @@ private static S57RecordName DecomposeLongNameField(ReadOnlySpan data) { return default; } - + var agen = BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(0, 2)); var fidn = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(2, 4)); var fids = BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)); diff --git a/src/EncDotNet.S57/S57FeatureRecord.cs b/src/EncDotNet.S57/S57FeatureRecord.cs index d1a16ad..99d7628 100644 --- a/src/EncDotNet.S57/S57FeatureRecord.cs +++ b/src/EncDotNet.S57/S57FeatureRecord.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57; /// diff --git a/src/EncDotNet.S57/S57VectorRecord.cs b/src/EncDotNet.S57/S57VectorRecord.cs index 05c7d7b..29fb0ad 100644 --- a/src/EncDotNet.S57/S57VectorRecord.cs +++ b/src/EncDotNet.S57/S57VectorRecord.cs @@ -1,5 +1,3 @@ -using System.Collections.Immutable; - namespace EncDotNet.S57; /// diff --git a/tests/EncDotNet.Benchmarks/ParsingLayerBenchmarks.cs b/tests/EncDotNet.Benchmarks/ParsingLayerBenchmarks.cs index 4da3db0..1560d0c 100644 --- a/tests/EncDotNet.Benchmarks/ParsingLayerBenchmarks.cs +++ b/tests/EncDotNet.Benchmarks/ParsingLayerBenchmarks.cs @@ -1,6 +1,6 @@ using BenchmarkDotNet.Attributes; -using EncDotNet.S57; using EncDotNet.Iso8211; +using EncDotNet.S57; namespace EncDotNet.Benchmarks; diff --git a/tests/EncDotNet.Benchmarks/Program.cs b/tests/EncDotNet.Benchmarks/Program.cs index 6017b3f..1a73212 100644 --- a/tests/EncDotNet.Benchmarks/Program.cs +++ b/tests/EncDotNet.Benchmarks/Program.cs @@ -1,4 +1,3 @@ -using BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; namespace EncDotNet.Benchmarks; diff --git a/tests/EndDotNet.UnitTests/Iso8211DocumentReaderTests.cs b/tests/EndDotNet.UnitTests/Iso8211DocumentReaderTests.cs index 1214e32..77862e0 100644 --- a/tests/EndDotNet.UnitTests/Iso8211DocumentReaderTests.cs +++ b/tests/EndDotNet.UnitTests/Iso8211DocumentReaderTests.cs @@ -1,4 +1,3 @@ -using System.Collections.Immutable; using System.Text; using EncDotNet.Iso8211; @@ -82,7 +81,7 @@ private static byte[] CreateMinimalRecord(bool isDataDescriptiveRecord = true) private static byte[] CreateMultiFieldRecord(bool isDataDescriptiveRecord = false) { var leaderIdentifier = isDataDescriptiveRecord ? 'L' : 'D'; - + // Fields: 0001 -> "HELLO", 0002 -> "WORLD" var field1Tag = "0001"; var field1Data = "HELLO"u8.ToArray(); diff --git a/tests/EndDotNet.UnitTests/Iso8211FieldReaderTests.cs b/tests/EndDotNet.UnitTests/Iso8211FieldReaderTests.cs index e4e7eb6..300fe43 100644 --- a/tests/EndDotNet.UnitTests/Iso8211FieldReaderTests.cs +++ b/tests/EndDotNet.UnitTests/Iso8211FieldReaderTests.cs @@ -351,7 +351,7 @@ public void GetSubfield_VariableLengthString_StopsAtUnitTerminator() var fieldDef = CreateFieldDefinition("TEST", ("DSNM", Iso8211SubfieldFormatType.CharacterData, 0, false), ("EDTN", Iso8211SubfieldFormatType.CharacterData, 0, false)); - + // Use \u001F instead of \x1F to avoid hex digit consumption (\x1FE would be wrong) var data = Encoding.ASCII.GetBytes("FILE1\u001FEDITION1\u001E"); var reader = new Iso8211FieldReader(fieldDef, data); diff --git a/tests/EndDotNet.UnitTests/S57AreaGeometryBuilderTests.cs b/tests/EndDotNet.UnitTests/S57AreaGeometryBuilderTests.cs index 27c2330..b5be2d4 100644 --- a/tests/EndDotNet.UnitTests/S57AreaGeometryBuilderTests.cs +++ b/tests/EndDotNet.UnitTests/S57AreaGeometryBuilderTests.cs @@ -73,12 +73,12 @@ private static S57VectorPointer FaceEdgePointer( int edgeId, S57Orientation orientation, S57UsageIndicator usage) => new() - { - Name = EdgeName(edgeId), - Orientation = orientation, - Usage = usage, - Mask = S57MaskingIndicator.Show - }; + { + Name = EdgeName(edgeId), + Orientation = orientation, + Usage = usage, + Mask = S57MaskingIndicator.Show + }; private static S57SpatialPointer ExteriorEdgeRef(int edgeId, S57Orientation orientation = S57Orientation.Forward) => new() { diff --git a/tests/EndDotNet.UnitTests/S57ChartDirectoryTests.cs b/tests/EndDotNet.UnitTests/S57ChartDirectoryTests.cs index 120bd08..acb1be0 100644 --- a/tests/EndDotNet.UnitTests/S57ChartDirectoryTests.cs +++ b/tests/EndDotNet.UnitTests/S57ChartDirectoryTests.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.Text; using EncDotNet.S57; -using EncDotNet.S57.Charts; using EncDotNet.S57.ExchangeSets; namespace EndDotNet.UnitTests; diff --git a/tests/EndDotNet.UnitTests/S57ChartTests.cs b/tests/EndDotNet.UnitTests/S57ChartTests.cs index bca4e9d..414e0cb 100644 --- a/tests/EndDotNet.UnitTests/S57ChartTests.cs +++ b/tests/EndDotNet.UnitTests/S57ChartTests.cs @@ -43,8 +43,8 @@ private static S57VectorRecord CreateIsolatedNodeRecord( RecordName = S57RecordName.FromRcnmRcid(S57RecordNameCodes.IsolatedNode, rcid), RecordVersion = 1, UpdateInstruction = S57UpdateInstruction.Insert, - Coordinates2D = position.HasValue - ? ImmutableArray.Create(position.Value) + Coordinates2D = position.HasValue + ? ImmutableArray.Create(position.Value) : ImmutableArray.Empty, Soundings = soundings?.ToImmutableArray() ?? ImmutableArray.Empty, Attributes = attributes?.ToImmutableArray() ?? ImmutableArray.Empty, @@ -481,7 +481,7 @@ public void ConnectedNode_MultiplNodes_IndexedByRecordName() // Assert Assert.Equal(3, chart.ConnectedNodes.Count); - + var retrieved1 = chart.GetConnectedNode(S57RecordName.FromRcnmRcid(S57RecordNameCodes.ConnectedNode, 1)); Assert.NotNull(retrieved1); Assert.Equal(100, retrieved1.Position.X); @@ -600,10 +600,10 @@ public void Face_WithExteriorBoundary_HasCorrectEdgeReferences() var face = chart.Faces.Values.First(); Assert.True(face.HasExteriorBoundary); Assert.Equal(3, face.ExteriorBoundary.Count); - + Assert.Equal(1, face.ExteriorBoundary[0].EdgeName.RecordId); Assert.Equal(S57Orientation.Forward, face.ExteriorBoundary[0].Orientation); - + Assert.Equal(2, face.ExteriorBoundary[1].EdgeName.RecordId); Assert.Equal(S57Orientation.Reverse, face.ExteriorBoundary[1].Orientation); } @@ -735,12 +735,12 @@ public void PointFeature_WithAttributes_PreservesAttributesAndHasHelperMethods() var pointFeature = chart.PointFeatures[0]; Assert.True(pointFeature.HasAttributes); Assert.Equal(3, pointFeature.Attributes.Count); - + // Single value lookup Assert.Equal("RED", pointFeature.GetAttributeValue(116)); Assert.Equal("1", pointFeature.GetAttributeValue(117)); Assert.Null(pointFeature.GetAttributeValue(999)); - + // Multiple value lookup var values = pointFeature.GetAttributeValues(116).ToList(); Assert.Equal(2, values.Count); diff --git a/tests/EndDotNet.UnitTests/S57DocumentReaderTests.cs b/tests/EndDotNet.UnitTests/S57DocumentReaderTests.cs index 723a0c1..78061a5 100644 --- a/tests/EndDotNet.UnitTests/S57DocumentReaderTests.cs +++ b/tests/EndDotNet.UnitTests/S57DocumentReaderTests.cs @@ -20,27 +20,27 @@ private static byte[] CreateS57Document(params byte[][] dataRecords) { // Create DDR (Data Descriptive Record) with proper S-57 field definitions var ddr = CreateS57Ddr(); - + // Calculate total size var totalSize = ddr.Length; foreach (var record in dataRecords) { totalSize += record.Length; } - + // Combine all records var result = new byte[totalSize]; var offset = 0; - + Array.Copy(ddr, 0, result, offset, ddr.Length); offset += ddr.Length; - + foreach (var record in dataRecords) { Array.Copy(record, 0, result, offset, record.Length); offset += record.Length; } - + return result; } @@ -206,10 +206,10 @@ private static byte[] CreateDdrFieldData(string fieldName, string subfieldDescri ms.WriteByte((byte)('0' + dataType)); // Field name and subfield descriptors - var descriptors = string.IsNullOrEmpty(fieldName) - ? subfieldDescriptors + var descriptors = string.IsNullOrEmpty(fieldName) + ? subfieldDescriptors : (string.IsNullOrEmpty(subfieldDescriptors) ? fieldName : $"{fieldName}!{subfieldDescriptors}"); - + if (!string.IsNullOrEmpty(descriptors)) { ms.Write(Encoding.ASCII.GetBytes(descriptors)); @@ -231,48 +231,48 @@ private static byte[] CreateDdrRecord((string tag, byte[] data)[] fields) // Calculate directory entries var directoryEntries = new List(); var currentPosition = 0; - + foreach (var (tag, data) in fields) { var entry = Encoding.ASCII.GetBytes($"{tag}{data.Length:D3}{currentPosition:D3}"); directoryEntries.Add(entry); currentPosition += data.Length; } - + var directorySize = directoryEntries.Sum(e => e.Length); var baseAddress = 24 + directorySize + 1; var totalFieldSize = fields.Sum(f => f.data.Length); var recordLength = baseAddress + totalFieldSize; - + // DDR leader: 'L' for leader identifier, field control length = 2 var leader = Encoding.ASCII.GetBytes( $"{recordLength:D5}3LE1 02{baseAddress:D5} 3304" ); - + var record = new byte[recordLength]; var offset = 0; - + // Copy leader Array.Copy(leader, 0, record, offset, leader.Length); offset += leader.Length; - + // Copy directory entries foreach (var entry in directoryEntries) { Array.Copy(entry, 0, record, offset, entry.Length); offset += entry.Length; } - + // Directory terminator record[offset++] = FieldTerminator; - + // Copy field data foreach (var (_, data) in fields) { Array.Copy(data, 0, record, offset, data.Length); offset += data.Length; } - + return record; } @@ -294,7 +294,7 @@ private static byte[] CreateDsidRecord( // Build DSID field data using var ms = new MemoryStream(); using var writer = new BinaryWriter(ms); - + writer.Write(rcnm); // RCNM writer.Write(rcid); // RCID writer.Write((byte)1); // EXPP @@ -312,9 +312,9 @@ private static byte[] CreateDsidRecord( writer.Write(agen); // AGEN WriteString(writer, ""); // COMT writer.Write((byte)0x1E); // Field terminator - + var dsidData = ms.ToArray(); - + return CreateDataRecord("DSID", dsidData); } @@ -337,7 +337,7 @@ private static byte[] CreateDspmRecord( { using var ms = new MemoryStream(); using var writer = new BinaryWriter(ms); - + writer.Write(rcnm); // RCNM writer.Write(rcid); // RCID writer.Write(hdat); // HDAT @@ -352,9 +352,9 @@ private static byte[] CreateDspmRecord( writer.Write(somf); // SOMF WriteString(writer, ""); // COMT writer.Write((byte)0x1E); // Field terminator - + var dspmData = ms.ToArray(); - + return CreateDataRecord("DSPM", dspmData); } @@ -377,7 +377,7 @@ private static byte[] CreateFeatureRecord( { using var ms = new MemoryStream(); using var writer = new BinaryWriter(ms); - + // FRID field writer.Write(rcnm); // RCNM writer.Write(rcid); // RCID @@ -387,42 +387,42 @@ private static byte[] CreateFeatureRecord( writer.Write(rver); // RVER writer.Write(ruin); // RUIN writer.Write((byte)0x1E); // Field terminator - + var fridData = ms.ToArray(); - + // Build fields dictionary var fields = new List<(string tag, byte[] data)> { ("FRID", fridData) }; - + // Add ATTF field if attributes provided if (attributes != null && attributes.Length > 0) { using var attfMs = new MemoryStream(); using var attfWriter = new BinaryWriter(attfMs); - + foreach (var attr in attributes) { attfWriter.Write((ushort)attr.AttributeCode); WriteString(attfWriter, attr.Value); } attfWriter.Write((byte)0x1E); - + fields.Add(("ATTF", attfMs.ToArray())); } - + // Add FSPC field if spatial pointer control provided if (spatialPointerControl.HasValue) { using var fspcMs = new MemoryStream(); using var fspcWriter = new BinaryWriter(fspcMs); - + fspcWriter.Write((byte)spatialPointerControl.Value.UpdateInstruction); fspcWriter.Write((ushort)spatialPointerControl.Value.Index); fspcWriter.Write((ushort)spatialPointerControl.Value.Count); fspcWriter.Write((byte)0x1E); - + fields.Add(("FSPC", fspcMs.ToArray())); } @@ -431,7 +431,7 @@ private static byte[] CreateFeatureRecord( { using var fsptMs = new MemoryStream(); using var fsptWriter = new BinaryWriter(fsptMs); - + foreach (var ptr in spatialPointers) { fsptWriter.Write((byte)ptr.Name.RecordNameCode); @@ -441,7 +441,7 @@ private static byte[] CreateFeatureRecord( fsptWriter.Write((byte)ptr.Mask); } fsptWriter.Write((byte)0x1E); - + fields.Add(("FSPT", fsptMs.ToArray())); } @@ -450,12 +450,12 @@ private static byte[] CreateFeatureRecord( { using var ffpcMs = new MemoryStream(); using var ffpcWriter = new BinaryWriter(ffpcMs); - + ffpcWriter.Write((byte)featurePointerControl.Value.UpdateInstruction); ffpcWriter.Write((ushort)featurePointerControl.Value.Index); ffpcWriter.Write((ushort)featurePointerControl.Value.Count); ffpcWriter.Write((byte)0x1E); - + fields.Add(("FFPC", ffpcMs.ToArray())); } @@ -464,7 +464,7 @@ private static byte[] CreateFeatureRecord( { using var ffptMs = new MemoryStream(); using var ffptWriter = new BinaryWriter(ffptMs); - + foreach (var ptr in featurePointers) { // LNAM: AGEN(2) + FIDN(4) + FIDS(2) @@ -475,10 +475,10 @@ private static byte[] CreateFeatureRecord( WriteString(ffptWriter, ptr.Comment); } ffptWriter.Write((byte)0x1E); - + fields.Add(("FFPT", ffptMs.ToArray())); } - + return CreateDataRecordMultiField(fields.ToArray()); } @@ -498,33 +498,33 @@ private static byte[] CreateVectorRecord( { using var ms = new MemoryStream(); using var writer = new BinaryWriter(ms); - + // VRID field writer.Write(rcnm); // RCNM writer.Write(rcid); // RCID writer.Write(rver); // RVER writer.Write(ruin); // RUIN writer.Write((byte)0x1E); // Field terminator - + var vridData = ms.ToArray(); - + // Build fields dictionary var fields = new List<(string tag, byte[] data)> { ("VRID", vridData) }; - + // Add VRPC field if vector pointer control provided if (vectorPointerControl.HasValue) { using var vrpcMs = new MemoryStream(); using var vrpcWriter = new BinaryWriter(vrpcMs); - + vrpcWriter.Write((byte)vectorPointerControl.Value.UpdateInstruction); vrpcWriter.Write((ushort)vectorPointerControl.Value.Index); vrpcWriter.Write((ushort)vectorPointerControl.Value.Count); vrpcWriter.Write((byte)0x1E); - + fields.Add(("VRPC", vrpcMs.ToArray())); } @@ -533,7 +533,7 @@ private static byte[] CreateVectorRecord( { using var vrptMs = new MemoryStream(); using var vrptWriter = new BinaryWriter(vrptMs); - + foreach (var ptr in vectorPointers) { vrptWriter.Write((byte)ptr.Name.RecordNameCode); @@ -544,7 +544,7 @@ private static byte[] CreateVectorRecord( vrptWriter.Write((byte)ptr.Mask); } vrptWriter.Write((byte)0x1E); - + fields.Add(("VRPT", vrptMs.ToArray())); } @@ -553,12 +553,12 @@ private static byte[] CreateVectorRecord( { using var sgccMs = new MemoryStream(); using var sgccWriter = new BinaryWriter(sgccMs); - + sgccWriter.Write((byte)coordinateControl.Value.UpdateInstruction); sgccWriter.Write((ushort)coordinateControl.Value.Index); sgccWriter.Write((ushort)coordinateControl.Value.Count); sgccWriter.Write((byte)0x1E); - + fields.Add(("SGCC", sgccMs.ToArray())); } @@ -567,23 +567,23 @@ private static byte[] CreateVectorRecord( { using var sg2dMs = new MemoryStream(); using var sg2dWriter = new BinaryWriter(sg2dMs); - + foreach (var coord in coordinates) { sg2dWriter.Write(coord.Y); sg2dWriter.Write(coord.X); } sg2dWriter.Write((byte)0x1E); - + fields.Add(("SG2D", sg2dMs.ToArray())); } - + // Add SG3D field if soundings provided if (soundings != null && soundings.Length > 0) { using var sg3dMs = new MemoryStream(); using var sg3dWriter = new BinaryWriter(sg3dMs); - + foreach (var snd in soundings) { sg3dWriter.Write(snd.Y); @@ -591,10 +591,10 @@ private static byte[] CreateVectorRecord( sg3dWriter.Write(snd.Depth); } sg3dWriter.Write((byte)0x1E); - + fields.Add(("SG3D", sg3dMs.ToArray())); } - + return CreateDataRecordMultiField(fields.ToArray()); } @@ -612,51 +612,51 @@ private static byte[] CreateDataRecord(string tag, byte[] fieldData) private static byte[] CreateDataRecordMultiField(params (string tag, byte[] data)[] fields) { var fieldTerminator = (byte)0x1E; - + // Calculate directory entries var directoryEntries = new List(); var currentPosition = 0; - + foreach (var (tag, data) in fields) { var entry = Encoding.ASCII.GetBytes($"{tag}{data.Length:D3}{currentPosition:D3}"); directoryEntries.Add(entry); currentPosition += data.Length; } - + var directorySize = directoryEntries.Sum(e => e.Length); var baseAddress = 24 + directorySize + 1; // +1 for directory terminator var totalFieldSize = fields.Sum(f => f.data.Length); var recordLength = baseAddress + totalFieldSize; - + var leader = Encoding.ASCII.GetBytes( $"{recordLength:D5}3DE1 00{baseAddress:D5} 3304" ); - + var record = new byte[recordLength]; var offset = 0; - + // Copy leader Array.Copy(leader, 0, record, offset, leader.Length); offset += leader.Length; - + // Copy directory entries foreach (var entry in directoryEntries) { Array.Copy(entry, 0, record, offset, entry.Length); offset += entry.Length; } - + // Directory terminator record[offset++] = fieldTerminator; - + // Copy field data foreach (var (_, data) in fields) { Array.Copy(data, 0, record, offset, data.Length); offset += data.Length; } - + return record; } @@ -678,10 +678,10 @@ public void Read_EmptyDocument_ReturnsDocumentWithNoRecords() { // Arrange var data = CreateS57Document(); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.NotNull(document); Assert.Null(document.DataSetIdentification); @@ -707,10 +707,10 @@ public void Read_DocumentWithDsid_ParsesDataSetIdentification() agen: 540 ); var data = CreateS57Document(dsidRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal(10, document.DataSetIdentification.RecordName.RecordNameCode); @@ -744,10 +744,10 @@ public void Read_DocumentWithDspm_ParsesDataSetParameters() somf: 10 ); var data = CreateS57Document(dspmRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.NotNull(document.DataSetParameters); Assert.Equal(20, document.DataSetParameters.RecordName.RecordNameCode); @@ -778,10 +778,10 @@ public void Read_DocumentWithFeatureRecord_ParsesFeatureRecord() ruin: (byte)S57UpdateInstruction.Insert ); var data = CreateS57Document(featureRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.FeatureRecords); var feature = document.FeatureRecords[0]; @@ -815,10 +815,10 @@ public void Read_DocumentWithFeatureRecordAndAttributes_ParsesAttributes() attributes: attributes ); var data = CreateS57Document(featureRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.FeatureRecords); var feature = document.FeatureRecords[0]; @@ -842,10 +842,10 @@ public void Read_DocumentWithVectorRecord_ParsesVectorRecord() ruin: (byte)S57UpdateInstruction.Insert ); var data = CreateS57Document(vectorRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.VectorRecords); var vector = document.VectorRecords[0]; @@ -872,10 +872,10 @@ public void Read_DocumentWithVectorRecordAnd2DCoordinates_ParsesCoordinates() coordinates: coordinates ); var data = CreateS57Document(vectorRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.VectorRecords); var vector = document.VectorRecords[0]; @@ -903,10 +903,10 @@ public void Read_DocumentWithVectorRecordAndSoundings_ParsesSoundings() soundings: soundings ); var data = CreateS57Document(vectorRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.VectorRecords); var vector = document.VectorRecords[0]; @@ -929,16 +929,16 @@ public void Read_DocumentWithMultipleRecords_ParsesAllRecords() var featureRecord2 = CreateFeatureRecord(rcid: 2, objl: 159); var vectorRecord1 = CreateVectorRecord(rcnm: S57RecordNameCodes.IsolatedNode, rcid: 1); var vectorRecord2 = CreateVectorRecord(rcnm: S57RecordNameCodes.Edge, rcid: 2); - + var data = CreateS57Document( - dsidRecord, dspmRecord, + dsidRecord, dspmRecord, featureRecord1, featureRecord2, vectorRecord1, vectorRecord2 ); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("TESTDATA", document.DataSetIdentification.DataSetName); @@ -960,11 +960,11 @@ public void GetFeatureRecord_ByRecordName_ReturnsMatchingRecord() var featureRecord2 = CreateFeatureRecord(rcnm: 100, rcid: 2, objl: 159); var data = CreateS57Document(featureRecord1, featureRecord2); var document = S57DocumentReader.Read(data); - + // Act var targetName = S57RecordName.FromRcnmRcid(100, 2); var result = document.GetFeatureRecord(targetName); - + // Assert Assert.NotNull(result); Assert.Equal(2, result.RecordName.RecordId); @@ -978,11 +978,11 @@ public void GetFeatureRecord_NonExistentName_ReturnsNull() var featureRecord = CreateFeatureRecord(rcnm: 100, rcid: 1, objl: 75); var data = CreateS57Document(featureRecord); var document = S57DocumentReader.Read(data); - + // Act var targetName = S57RecordName.FromRcnmRcid(100, 999); var result = document.GetFeatureRecord(targetName); - + // Assert Assert.Null(result); } @@ -995,11 +995,11 @@ public void GetVectorRecord_ByRecordName_ReturnsMatchingRecord() var vectorRecord2 = CreateVectorRecord(rcnm: S57RecordNameCodes.Edge, rcid: 2); var data = CreateS57Document(vectorRecord1, vectorRecord2); var document = S57DocumentReader.Read(data); - + // Act var targetName = S57RecordName.FromRcnmRcid(S57RecordNameCodes.Edge, 2); var result = document.GetVectorRecord(targetName); - + // Assert Assert.NotNull(result); Assert.Equal(S57RecordNameCodes.Edge, result.RecordName.RecordNameCode); @@ -1015,10 +1015,10 @@ public void GetFeaturesByObjectCode_ReturnsMatchingRecords() var featureRecord3 = CreateFeatureRecord(rcnm: 100, rcid: 3, objl: 75); var data = CreateS57Document(featureRecord1, featureRecord2, featureRecord3); var document = S57DocumentReader.Read(data); - + // Act var results = document.GetFeaturesByObjectCode(S57ObjectCode.LIGHTS).ToArray(); - + // Assert Assert.Equal(2, results.Length); Assert.All(results, r => Assert.Equal(S57ObjectCode.LIGHTS, r.ObjectCode)); @@ -1031,10 +1031,10 @@ public void CoordinateMultiplicationFactor_WithDspm_ReturnsValue() var dspmRecord = CreateDspmRecord(comf: 10000000); var data = CreateS57Document(dspmRecord); var document = S57DocumentReader.Read(data); - + // Act var result = document.CoordinateMultiplicationFactor; - + // Assert Assert.Equal(10000000, result); } @@ -1045,10 +1045,10 @@ public void CoordinateMultiplicationFactor_WithoutDspm_ReturnsDefault() // Arrange var data = CreateS57Document(); var document = S57DocumentReader.Read(data); - + // Act var result = document.CoordinateMultiplicationFactor; - + // Assert Assert.Equal(10000000, result); // Default value } @@ -1060,10 +1060,10 @@ public void SoundingMultiplicationFactor_WithDspm_ReturnsValue() var dspmRecord = CreateDspmRecord(somf: 100); var data = CreateS57Document(dspmRecord); var document = S57DocumentReader.Read(data); - + // Act var result = document.SoundingMultiplicationFactor; - + // Assert Assert.Equal(100, result); } @@ -1074,10 +1074,10 @@ public void SoundingMultiplicationFactor_WithoutDspm_ReturnsDefault() // Arrange var data = CreateS57Document(); var document = S57DocumentReader.Read(data); - + // Act var result = document.SoundingMultiplicationFactor; - + // Assert Assert.Equal(10, result); // Default value } @@ -1091,7 +1091,7 @@ public void S57RecordName_FromRcnmRcid_CreatesCorrectly() { // Act var name = S57RecordName.FromRcnmRcid(100, 42); - + // Assert Assert.Equal(100, name.RecordNameCode); Assert.Equal(42, name.RecordId); @@ -1105,7 +1105,7 @@ public void S57RecordName_FromLongName_CreatesCorrectly() { // Act var name = S57RecordName.FromLongName(540, 12345, 1); - + // Assert Assert.Equal(540, name.AgencyCode); Assert.Equal(12345, name.FeatureId); @@ -1118,7 +1118,7 @@ public void S57RecordName_Equality_SameValues_ReturnsTrue() // Arrange var name1 = S57RecordName.FromRcnmRcid(100, 42); var name2 = S57RecordName.FromRcnmRcid(100, 42); - + // Assert Assert.Equal(name1, name2); Assert.True(name1 == name2); @@ -1131,7 +1131,7 @@ public void S57RecordName_Equality_DifferentValues_ReturnsFalse() // Arrange var name1 = S57RecordName.FromRcnmRcid(100, 42); var name2 = S57RecordName.FromRcnmRcid(100, 43); - + // Assert Assert.NotEqual(name1, name2); Assert.False(name1 == name2); @@ -1144,7 +1144,7 @@ public void S57RecordName_GetHashCode_SameValues_ReturnsSameHash() // Arrange var name1 = S57RecordName.FromRcnmRcid(100, 42); var name2 = S57RecordName.FromRcnmRcid(100, 42); - + // Assert Assert.Equal(name1.GetHashCode(), name2.GetHashCode()); } @@ -1154,10 +1154,10 @@ public void S57RecordName_ToString_ReturnsExpectedFormat() { // Arrange var name = S57RecordName.FromRcnmRcid(100, 42); - + // Act var result = name.ToString(); - + // Assert Assert.Equal("RCNM=100, RCID=42", result); } @@ -1171,7 +1171,7 @@ public void S57AttributeValue_Constructor_SetsProperties() { // Act var attr = new S57AttributeValue(116, "RED"); - + // Assert Assert.Equal(116, attr.AttributeCode); Assert.Equal("RED", attr.Value); @@ -1182,10 +1182,10 @@ public void S57AttributeValue_ToString_ReturnsExpectedFormat() { // Arrange var attr = new S57AttributeValue(116, "RED"); - + // Act var result = attr.ToString(); - + // Assert Assert.Equal("ATTL=116, ATVL=RED", result); } @@ -1200,10 +1200,10 @@ public void S57Coordinate2D_ToDecimalDegrees_ConvertsCorrectly() // Arrange var coord = new S57Coordinate2D { X = -1225000000, Y = 475000000 }; var multiplicationFactor = 10000000; - + // Act var (longitude, latitude) = coord.ToDecimalDegrees(multiplicationFactor); - + // Assert Assert.Equal(-122.5, longitude, 6); Assert.Equal(47.5, latitude, 6); @@ -1220,10 +1220,10 @@ public void S57Sounding_ToDecimalValues_ConvertsCorrectly() var sounding = new S57Sounding { X = -1225000000, Y = 475000000, Depth = 150 }; var coordFactor = 10000000; var soundingFactor = 10; - + // Act var (longitude, latitude, depth) = sounding.ToDecimalValues(coordFactor, soundingFactor); - + // Assert Assert.Equal(-122.5, longitude, 6); Assert.Equal(47.5, latitude, 6); @@ -1281,10 +1281,10 @@ public void Read_ByteArray_ReturnsDocument() // Arrange var dsidRecord = CreateDsidRecord(dsnm: "BYTEARRAY"); var data = CreateS57Document(dsidRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("BYTEARRAY", document.DataSetIdentification.DataSetName); @@ -1296,10 +1296,10 @@ public void Read_ReadOnlySpan_ReturnsDocument() // Arrange var dsidRecord = CreateDsidRecord(dsnm: "SPANTEST"); var data = CreateS57Document(dsidRecord); - + // Act var document = S57DocumentReader.Read(data.AsSpan()); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("SPANTEST", document.DataSetIdentification.DataSetName); @@ -1311,14 +1311,14 @@ public void Read_Stream_ReturnsDocument() // Arrange var dsidRecord = CreateDsidRecord(dsnm: "STREAMTEST"); var data = CreateS57Document(dsidRecord); - + // Act S57Document document; using (var stream = new MemoryStream(data)) { document = S57DocumentReader.Read(stream); } - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("STREAMTEST", document.DataSetIdentification.DataSetName); @@ -1330,14 +1330,14 @@ public async Task ReadAsync_Stream_ReturnsDocument() // Arrange var dsidRecord = CreateDsidRecord(dsnm: "ASYNCSTREAM"); var data = CreateS57Document(dsidRecord); - + // Act S57Document document; using (var stream = new MemoryStream(data)) { document = await S57DocumentReader.ReadAsync(stream); } - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("ASYNCSTREAM", document.DataSetIdentification.DataSetName); @@ -1350,14 +1350,14 @@ public void ReadFromFile_ValidFile_ReturnsDocument() var dsidRecord = CreateDsidRecord(dsnm: "FILETEST"); var data = CreateS57Document(dsidRecord); var tempFile = Path.GetTempFileName(); - + try { File.WriteAllBytes(tempFile, data); - + // Act var document = S57DocumentReader.ReadFromFile(tempFile); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("FILETEST", document.DataSetIdentification.DataSetName); @@ -1375,14 +1375,14 @@ public async Task ReadFromFileAsync_ValidFile_ReturnsDocument() var dsidRecord = CreateDsidRecord(dsnm: "ASYNCFILE"); var data = CreateS57Document(dsidRecord); var tempFile = Path.GetTempFileName(); - + try { await File.WriteAllBytesAsync(tempFile, data); - + // Act var document = await S57DocumentReader.ReadFromFileAsync(tempFile); - + // Assert Assert.NotNull(document.DataSetIdentification); Assert.Equal("ASYNCFILE", document.DataSetIdentification.DataSetName); @@ -1759,10 +1759,10 @@ public void Read_FeatureRecordWithEmptyAttributes_ReturnsEmptyAttributeArray() attributes: null ); var data = CreateS57Document(featureRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.FeatureRecords); Assert.Empty(document.FeatureRecords[0].Attributes); @@ -1778,10 +1778,10 @@ public void Read_VectorRecordWithNoCoordinates_ReturnsEmptyCoordinateArray() coordinates: null ); var data = CreateS57Document(vectorRecord); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Single(document.VectorRecords); Assert.Empty(document.VectorRecords[0].Coordinates2D); @@ -1796,10 +1796,10 @@ public void Read_MultipleFeatureRecords_PreservesOrder() var featureRecord2 = CreateFeatureRecord(rcnm: 100, rcid: 2, objl: 20); var featureRecord3 = CreateFeatureRecord(rcnm: 100, rcid: 3, objl: 30); var data = CreateS57Document(featureRecord1, featureRecord2, featureRecord3); - + // Act - Call S57Reader.Read FIRST var document = S57DocumentReader.Read(data); - + // Assert Assert.Equal(3, document.FeatureRecords.Count); Assert.Equal(1, document.FeatureRecords[0].RecordName.RecordId); @@ -1816,10 +1816,10 @@ public void Read_DifferentVectorTypes_ParsesCorrectly() var edge = CreateVectorRecord(rcnm: S57RecordNameCodes.Edge, rcid: 3); var face = CreateVectorRecord(rcnm: S57RecordNameCodes.Face, rcid: 4); var data = CreateS57Document(isolatedNode, connectedNode, edge, face); - + // Act var document = S57DocumentReader.Read(data); - + // Assert Assert.Equal(4, document.VectorRecords.Count); Assert.Equal(S57RecordNameCodes.IsolatedNode, document.VectorRecords[0].RecordName.RecordNameCode);