diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj
index a7c3ce4e..70260ba9 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj
@@ -16,6 +16,7 @@
+
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
index a5295c63..e0b97c5c 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
@@ -1,103 +1,92 @@
-////
-//// Copyright © Pete Sramek. All rights reserved.
-//// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-////
-
-//namespace PolylineAlgorithm.Benchmarks;
-
-//using BenchmarkDotNet.Attributes;
-//using BenchmarkDotNet.Engines;
-//using PolylineAlgorithm.Utility;
-//using System.Collections.Generic;
-
-/////
-///// Benchmarks for .
-/////
-//public class PolylineEncoderBenchmark {
-// private readonly Consumer _consumer = new();
-
-// ///
-// /// Number of coordinates for benchmarks.
-// ///
-// [Params(1, 100, 1_000)]
-// public int CoordinatesCount { get; set; }
-
-//#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
-// ///
-// /// Coordinates as list.
-// ///
-// public List<(double Latitude, double Longitude)> List { get; private set; }
-
-// ///
-// /// Coordinates as array.
-// ///
-// public (double Latitude, double Longitude)[] Array { get; private set; }
-
-// ///
-// /// Coordinates as read-only memory.
-// ///
-// public ReadOnlyMemory<(double Latitude, double Longitude)> Memory { get; private set; }
-
-//#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
-
-// ///
-// /// Polyline encoder instance.
-// ///
-// private readonly StringPolylineEncoder _stringEncoder = new();
-
-// ///
-// /// Polyline encoder instance.
-// ///
-// private readonly CharArrayPolylineEncoder _charArrayEncoder = new();
-
-// ///
-// /// Polyline encoder instance.
-// ///
-// private readonly MemoryPolylineEncoder _memoryEncoder = new();
-
-// ///
-// /// Sets up benchmark data.
-// ///
-// [GlobalSetup]
-// public void SetupData() {
-// List = [.. RandomValueProvider.GetCoordinates(CoordinatesCount).Select(c => (c.Latitude, c.Longitude))];
-// Array = [.. List];
-// Memory = Array.AsMemory();
-// }
-
-// ///
-// /// Benchmark: encode coordinates from span.
-// ///
-// /// Encoded polyline.
-// [Benchmark]
-// public void PolylineEncoder_Encode_Span() {
-// var polyline = _encoder
-// .Encode(Memory.Span!);
-
-// _consumer.Consume(polyline);
-// }
-
-// ///
-// /// Benchmark: encode coordinates from array.
-// ///
-// /// Encoded polyline.
-// [Benchmark]
-// public void PolylineEncoder_Encode_Array() {
-// var polyline = _encoder
-// .Encode(Array!);
-
-// _consumer.Consume(polyline);
-// }
-
-// ///
-// /// Benchmark: encode coordinates from list.
-// ///
-// /// Encoded polyline.
-// [Benchmark]
-// public void PolylineEncoder_Encode_List() {
-// var polyline = _encoder
-// .Encode(List!);
-
-// _consumer.Consume(polyline);
-// }
-//}
\ No newline at end of file
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.Benchmarks;
+
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Engines;
+using PolylineAlgorithm.Abstraction;
+using PolylineAlgorithm.Extensions;
+using PolylineAlgorithm.Utility;
+using System.Collections.Generic;
+
+///
+/// Benchmarks for .
+///
+public class PolylineEncoderBenchmark {
+ private readonly Consumer _consumer = new();
+
+ ///
+ /// Number of coordinates for benchmarks.
+ ///
+ [Params(1, 100, 1_000)]
+ public int CoordinatesCount { get; set; }
+
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+ ///
+ /// Coordinates as list.
+ ///
+ public List<(double Latitude, double Longitude)> List { get; private set; }
+
+ ///
+ /// Coordinates as array.
+ ///
+ public (double Latitude, double Longitude)[] Array { get; private set; }
+
+ ///
+ /// Coordinates as read-only memory.
+ ///
+ public ReadOnlyMemory<(double Latitude, double Longitude)> Memory { get; private set; }
+
+#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+
+ ///
+ /// Polyline encoder instance.
+ ///
+ private readonly StringPolylineEncoder _encoder = new();
+
+ ///
+ /// Sets up benchmark data.
+ ///
+ [GlobalSetup]
+ public void SetupData() {
+ List = [.. RandomValueProvider.GetCoordinates(CoordinatesCount)];
+ Array = [.. List];
+ Memory = Array.AsMemory();
+ }
+
+ ///
+ /// Benchmark: encode coordinates from span.
+ ///
+ [Benchmark]
+ public void PolylineEncoder_Encode_Span() {
+ var polyline = _encoder.Encode(Memory.Span);
+ _consumer.Consume(polyline);
+ }
+
+ ///
+ /// Benchmark: encode coordinates from array.
+ ///
+ [Benchmark]
+ public void PolylineEncoder_Encode_Array() {
+ var polyline = _encoder.Encode(Array);
+ _consumer.Consume(polyline);
+ }
+
+ ///
+ /// Benchmark: encode coordinates from list.
+ ///
+ [Benchmark]
+ public void PolylineEncoder_Encode_List() {
+ var polyline = _encoder.Encode(List);
+ _consumer.Consume(polyline);
+ }
+
+ private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ }
+}
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
index c8cc1e54..7c0449b7 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
@@ -4,10 +4,8 @@
//
using Microsoft.Extensions.Logging;
-using PolylineAlgorithm.Diagnostics;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
-using PolylineAlgorithm.Internal.Diagnostics;
using System.Runtime.CompilerServices;
namespace PolylineAlgorithm.Abstraction {
@@ -54,27 +52,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
- ///
- /// Decodes an encoded into a sequence of instances.
- ///
- ///
- /// The instance containing the encoded polyline string to decode.
- ///
- ///
- /// An of representing the decoded latitude and longitude pairs.
- ///
- ///
- /// Thrown when is .
- ///
- ///
- /// Thrown when is empty.
- ///
- ///
- /// Thrown when the polyline format is invalid or malformed at a specific position.
- ///
- public IEnumerable Decode(TPolyline polyline)
- => Decode(polyline, CancellationToken.None);
-
///
/// Decodes an encoded into a sequence of instances,
/// with support for cancellation.
@@ -100,7 +77,7 @@ public IEnumerable Decode(TPolyline polyline)
///
/// Thrown when is canceled during decoding.
///
- public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken) {
+ public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) {
const string OperationName = nameof(Decode);
_logger?.LogOperationStartedDebug(OperationName);
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
index 3f68736a..801a45b3 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
@@ -9,11 +9,11 @@ namespace PolylineAlgorithm.Abstraction;
using PolylineAlgorithm;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
-using PolylineAlgorithm.Internal.Diagnostics;
using System;
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Threading;
///
/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
@@ -61,6 +61,9 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
///
/// The collection of objects to encode.
///
+ ///
+ /// A that can be used to cancel the encoding operation.
+ ///
///
/// An instance of representing the encoded coordinates.
///
@@ -74,7 +77,7 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
/// Thrown when the internal encoding buffer cannot accommodate the encoded value.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")]
- public TPolyline Encode(ReadOnlySpan coordinates) {
+ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) {
const string OperationName = nameof(Encode);
_logger
@@ -98,6 +101,7 @@ public TPolyline Encode(ReadOnlySpan coordinates) {
try {
for (var i = 0; i < coordinates.Length; i++) {
+ cancellationToken.ThrowIfCancellationRequested();
delta
.Next(
@@ -150,7 +154,7 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates,
logger
.LogEmptyArgumentWarning(nameof(coordinates));
- ExceptionGuard.ThrwoArgumentCannotBeEmptyEnumerationMessage(nameof(coordinates));
+ ExceptionGuard.ThrowArgumentCannotBeEmptyEnumerationMessage(nameof(coordinates));
}
}
}
diff --git a/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs b/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs
deleted file mode 100644
index b29c0ecd..00000000
--- a/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-namespace PolylineAlgorithm.Extensions;
-
-using PolylineAlgorithm;
-using PolylineAlgorithm.Abstraction;
-using PolylineAlgorithm.Internal.Diagnostics;
-using System;
-using System.Collections.Generic;
-
-///
-/// Provides extension methods for the interface to facilitate decoding encoded polylines.
-///
-public static class PolylineDecoderExtensions {
- ///
- /// Decodes an encoded polyline string into a sequence of geographic coordinates.
- ///
- ///
- /// The instance used to perform the decoding operation.
- ///
- ///
- /// The encoded polyline string to decode.
- ///
- ///
- /// An containing the decoded latitude and longitude pairs.
- ///
- ///
- /// Thrown when or is .
- ///
- public static IEnumerable Decode(this IPolylineDecoder decoder, string polyline) {
- if (decoder is null) {
- ExceptionGuard.ThrowArgumentNull(nameof(decoder));
- }
-
- return decoder.Decode(Polyline.FromString(polyline));
- }
-
- ///
- /// Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates.
- ///
- ///
- /// The instance used to perform the decoding operation.
- ///
- ///
- /// The encoded polyline as a character array to decode.
- ///
- ///
- /// An containing the decoded latitude and longitude pairs.
- ///
- ///
- /// Thrown when or is .
- ///
- public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) {
- if (decoder is null) {
- ExceptionGuard.ThrowArgumentNull(nameof(decoder));
- }
-
- return decoder.Decode(Polyline.FromCharArray(polyline));
- }
-
- ///
- /// Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates.
- ///
- ///
- /// The instance used to perform the decoding operation.
- ///
- ///
- /// The encoded polyline as a read-only memory of characters to decode.
- ///
- ///
- /// An containing the decoded latitude and longitude pairs.
- ///
- ///
- /// Thrown when is .
- ///
- public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) {
- if (decoder is null) {
- ExceptionGuard.ThrowArgumentNull(nameof(decoder));
- }
-
- return decoder.Decode(Polyline.FromMemory(polyline));
- }
-}
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
index 5c89ec5a..037b3a9e 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
@@ -1,39 +1,144 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.Tests.Abstraction;
+
using PolylineAlgorithm.Abstraction;
+using PolylineAlgorithm.Utility;
+using System;
+using System.Collections.Generic;
-namespace PolylineAlgorithm.Tests.Abstraction {
- [TestClass]
- public sealed class AbstractPolylineDecoderTests {
- private sealed class TestStringDecoder : AbstractPolylineDecoder {
- protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
- }
+///
+/// Tests for .
+///
+[TestClass]
+public sealed class AbstractPolylineDecoderTests {
+ private sealed class TestStringDecoder : AbstractPolylineDecoder {
+ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ }
- [TestMethod]
- public void Decode_Null_Polyline_Throws_ArgumentNullException() {
- // Arrange
- var decoder = new TestStringDecoder();
+ private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder {
+ public TestStringDecoderWithOptions(PolylineEncodingOptions options)
+ : base(options) { }
- // Act & Assert
- var ex = Assert.ThrowsExactly(() => decoder.Decode((string?)null!).ToList());
- Assert.AreEqual("polyline", ex.ParamName);
- }
+ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ }
- [TestMethod]
- public void Decode_Empty_Polyline_Throws_InvalidPolylineException() {
- // Arrange
- var decoder = new TestStringDecoder();
+ ///
+ /// Tests that Decode with a null polyline throws .
+ ///
+ [TestMethod]
+ public void Decode_With_Null_Polyline_Throws_ArgumentNullException() {
+ // Arrange
+ TestStringDecoder decoder = new();
- // Act & Assert - empty string is too short (min block length = 1)
- Assert.ThrowsExactly(() => decoder.Decode(string.Empty).ToList());
- }
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(() => decoder.Decode((string?)null!).ToList());
+ Assert.AreEqual("polyline", ex.ParamName);
+ }
+
+ ///
+ /// Tests that Decode with an empty polyline throws .
+ ///
+ [TestMethod]
+ public void Decode_With_Empty_Polyline_Throws_InvalidPolylineException() {
+ // Arrange
+ TestStringDecoder decoder = new();
+
+ // Act & Assert
+ Assert.ThrowsExactly(() => decoder.Decode(string.Empty).ToList());
+ }
+
+ ///
+ /// Tests that Decode with a polyline containing an invalid character throws .
+ ///
+ [TestMethod]
+ public void Decode_With_Invalid_Character_Polyline_Throws_InvalidPolylineException() {
+ // Arrange
+ TestStringDecoder decoder = new();
+
+ // '!' (33) is below allowed range ('?' == 63)
+ // Act & Assert
+ Assert.ThrowsExactly(() => decoder.Decode("!").ToList());
+ }
- [TestMethod]
- public void Decode_Invalid_Character_Polyline_Throws_InvalidPolylineException() {
- // Arrange
- var decoder = new TestStringDecoder();
+ ///
+ /// Tests that Decode with a valid polyline returns the expected coordinates.
+ ///
+ [TestMethod]
+ public void Decode_ValidPolyline_ReturnsExpectedCoordinates() {
+ // Arrange
+ TestStringDecoder decoder = new();
+ string polyline = StaticValueProvider.Valid.GetPolyline();
+ (double Latitude, double Longitude)[] expected = [.. StaticValueProvider.Valid.GetCoordinates()];
- // '!' (33) is below allowed range ('?' == 63) and should trigger invalid polyline character
- Assert.ThrowsExactly(() => decoder.Decode("!").ToList());
+ // Act
+ (double Latitude, double Longitude)[] result = [.. decoder.Decode(polyline)];
+
+ // Assert
+ Assert.AreEqual(expected.Length, result.Length);
+ for (int i = 0; i < expected.Length; i++) {
+ Assert.AreEqual(expected[i].Latitude, result[i].Latitude, 1e-5);
+ Assert.AreEqual(expected[i].Longitude, result[i].Longitude, 1e-5);
}
}
-}
\ No newline at end of file
+
+ ///
+ /// Tests that the options constructor with null throws .
+ ///
+ [TestMethod]
+ public void Constructor_WithNullOptions_ThrowsArgumentNullException() {
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(() => new TestStringDecoderWithOptions(null!));
+ Assert.AreEqual("options", ex.ParamName);
+ }
+
+ ///
+ /// Tests that the Options property returns the configured options.
+ ///
+ [TestMethod]
+ public void Options_Default_ReturnsDefaultOptions() {
+ // Arrange
+ TestStringDecoder decoder = new();
+
+ // Assert
+ Assert.IsNotNull(decoder.Options);
+ Assert.AreEqual(5u, decoder.Options.Precision);
+ }
+
+ ///
+ /// Tests that the options constructor stores the provided options.
+ ///
+ [TestMethod]
+ public void Constructor_WithOptions_StoresOptions() {
+ // Arrange
+ PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create()
+ .WithPrecision(7)
+ .Build();
+
+ // Act
+ TestStringDecoderWithOptions decoder = new(options);
+
+ // Assert
+ Assert.AreSame(options, decoder.Options);
+ }
+
+ ///
+ /// Tests that Decode with a pre-cancelled token throws .
+ ///
+ [TestMethod]
+ public void Decode_PreCancelledToken_ThrowsOperationCanceledException() {
+ // Arrange
+ TestStringDecoder decoder = new();
+ string polyline = StaticValueProvider.Valid.GetPolyline();
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+
+ // Act & Assert
+ Assert.ThrowsExactly(() => decoder.Decode(polyline, cts.Token).ToList());
+ }
+}
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
new file mode 100644
index 00000000..9a79fa0e
--- /dev/null
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
@@ -0,0 +1,152 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.Tests.Abstraction;
+
+using PolylineAlgorithm.Abstraction;
+using PolylineAlgorithm.Utility;
+using System;
+
+///
+/// Tests for .
+///
+[TestClass]
+public sealed class AbstractPolylineEncoderTests {
+ private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ public TestStringEncoder()
+ : base() { }
+
+ public TestStringEncoder(PolylineEncodingOptions options)
+ : base(options) { }
+
+ protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ }
+
+ ///
+ /// Tests that the default constructor creates an instance with default options.
+ ///
+ [TestMethod]
+ public void Constructor_Default_CreatesInstanceWithDefaultOptions() {
+ // Act
+ TestStringEncoder encoder = new();
+
+ // Assert
+ Assert.IsNotNull(encoder);
+ Assert.IsNotNull(encoder.Options);
+ Assert.AreEqual(5u, encoder.Options.Precision);
+ Assert.AreEqual(512, encoder.Options.StackAllocLimit);
+ }
+
+ ///
+ /// Tests that the options constructor with null throws .
+ ///
+ [TestMethod]
+ public void Constructor_WithNullOptions_ThrowsArgumentNullException() {
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(() => new TestStringEncoder(null!));
+ Assert.AreEqual("options", ex.ParamName);
+ }
+
+ ///
+ /// Tests that the options constructor stores the provided options.
+ ///
+ [TestMethod]
+ public void Constructor_WithOptions_StoresOptions() {
+ // Arrange
+ PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create()
+ .WithPrecision(7)
+ .Build();
+
+ // Act
+ TestStringEncoder encoder = new(options);
+
+ // Assert
+ Assert.AreSame(options, encoder.Options);
+ }
+
+ ///
+ /// Tests that Encode with an empty span throws .
+ ///
+ [TestMethod]
+ public void Encode_EmptySpan_ThrowsArgumentException() {
+ // Arrange
+ TestStringEncoder encoder = new();
+
+ // Act & Assert
+ Assert.ThrowsExactly(() => encoder.Encode(ReadOnlySpan<(double, double)>.Empty));
+ }
+
+ ///
+ /// Tests that Encode with a single valid coordinate returns a non-empty string.
+ ///
+ [TestMethod]
+ public void Encode_SingleCoordinate_ReturnsNonEmptyString() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ (double, double)[] coordinates = [(0.0, 0.0)];
+
+ // Act
+ string result = encoder.Encode(coordinates.AsSpan());
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.IsTrue(result.Length > 0);
+ }
+
+ ///
+ /// Tests that Encode with known coordinates returns the expected polyline string.
+ ///
+ [TestMethod]
+ public void Encode_KnownCoordinates_ReturnsExpectedPolyline() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ (double Latitude, double Longitude)[] coordinates = [.. StaticValueProvider.Valid.GetCoordinates()];
+ string expected = StaticValueProvider.Valid.GetPolyline();
+
+ // Act
+ string result = encoder.Encode(coordinates.AsSpan());
+
+ // Assert
+ Assert.AreEqual(expected, result);
+ }
+
+ ///
+ /// Tests that Encode with a pre-cancelled token throws .
+ ///
+ [TestMethod]
+ public void Encode_PreCancelledToken_ThrowsOperationCanceledException() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ using CancellationTokenSource cts = new();
+ cts.Cancel();
+ (double, double)[] coordinates = [(0.0, 0.0), (1.0, 1.0)];
+
+ // Act & Assert
+ Assert.ThrowsExactly(() => encoder.Encode(coordinates.AsSpan(), cts.Token));
+ }
+
+ ///
+ /// Tests that Encode still produces the correct result when the buffer exceeds the stack allocation
+ /// limit, forcing heap allocation via .
+ ///
+ [TestMethod]
+ public void Encode_WithSmallStackAllocLimit_UsesHeapAllocationAndProducesCorrectResult() {
+ // Arrange — force heap path by making stackAllocLimit smaller than any real encoding needs
+ PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create()
+ .WithStackAllocLimit(1)
+ .Build();
+ TestStringEncoder encoder = new(options);
+ (double Latitude, double Longitude)[] coordinates = [.. StaticValueProvider.Valid.GetCoordinates()];
+ string expected = StaticValueProvider.Valid.GetPolyline();
+
+ // Act
+ string result = encoder.Encode(coordinates.AsSpan());
+
+ // Assert
+ Assert.AreEqual(expected, result);
+ }
+}
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
new file mode 100644
index 00000000..f1439b75
--- /dev/null
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
@@ -0,0 +1,123 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.Tests.Extensions;
+
+using PolylineAlgorithm.Abstraction;
+using PolylineAlgorithm.Extensions;
+using PolylineAlgorithm.Utility;
+using System;
+using System.Collections.Generic;
+
+///
+/// Tests for .
+///
+[TestClass]
+public sealed class PolylineEncoderExtensionsTests {
+ private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ }
+
+ // ----- Encode(List) -----
+
+ ///
+ /// Tests that Encode with a null encoder throws .
+ ///
+ [TestMethod]
+ public void Encode_List_NullEncoder_ThrowsArgumentNullException() {
+ // Arrange — use interface type so the extension method is resolved
+ IPolylineEncoder<(double, double), string>? encoder = null;
+ List<(double, double)> coordinates = [(0.0, 0.0)];
+
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(
+ () => encoder!.Encode(coordinates));
+ Assert.AreEqual("encoder", ex.ParamName);
+ }
+
+ ///
+ /// Tests that Encode with a null list throws .
+ ///
+ [TestMethod]
+ public void Encode_List_NullCoordinates_ThrowsArgumentNullException() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ List<(double, double)>? coordinates = null;
+
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(
+ () => encoder.Encode(coordinates!));
+ Assert.AreEqual("coordinates", ex.ParamName);
+ }
+
+ ///
+ /// Tests that Encode with a valid list returns the expected polyline.
+ ///
+ [TestMethod]
+ public void Encode_List_ValidCoordinates_ReturnsExpectedPolyline() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ List<(double Latitude, double Longitude)> coordinates = [.. StaticValueProvider.Valid.GetCoordinates()];
+ string expected = StaticValueProvider.Valid.GetPolyline();
+
+ // Act
+ string result = encoder.Encode(coordinates);
+
+ // Assert
+ Assert.AreEqual(expected, result);
+ }
+
+ // ----- Encode(T[]) -----
+
+ ///
+ /// Tests that Encode with a null encoder throws .
+ ///
+ [TestMethod]
+ public void Encode_Array_NullEncoder_ThrowsArgumentNullException() {
+ // Arrange — call the extension method explicitly because IPolylineEncoder.Encode(ReadOnlySpan)
+ // would be preferred over the extension when calling through method syntax with an array argument.
+ IPolylineEncoder<(double, double), string>? encoder = null;
+ (double, double)[] coordinates = [(0.0, 0.0)];
+
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(
+ () => PolylineEncoderExtensions.Encode<(double, double), string>(encoder!, coordinates));
+ Assert.AreEqual("encoder", ex.ParamName);
+ }
+
+ ///
+ /// Tests that Encode with a null array throws .
+ ///
+ [TestMethod]
+ public void Encode_Array_NullCoordinates_ThrowsArgumentNullException() {
+ // Arrange — call the extension method explicitly (same reasoning as above).
+ IPolylineEncoder<(double, double), string> encoder = new TestStringEncoder();
+ (double, double)[]? coordinates = null;
+
+ // Act & Assert
+ ArgumentNullException ex = Assert.ThrowsExactly(
+ () => PolylineEncoderExtensions.Encode<(double, double), string>(encoder, coordinates!));
+ Assert.AreEqual("coordinates", ex.ParamName);
+ }
+
+ ///
+ /// Tests that Encode with a valid array returns the expected polyline.
+ ///
+ [TestMethod]
+ public void Encode_Array_ValidCoordinates_ReturnsExpectedPolyline() {
+ // Arrange
+ TestStringEncoder encoder = new();
+ (double Latitude, double Longitude)[] coordinates = [.. StaticValueProvider.Valid.GetCoordinates()];
+ string expected = StaticValueProvider.Valid.GetPolyline();
+
+ // Act
+ string result = encoder.Encode(coordinates);
+
+ // Assert
+ Assert.AreEqual(expected, result);
+ }
+}
diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
index c4fa5100..1e915fe2 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
@@ -6,6 +6,7 @@
namespace PolylineAlgorithm.Tests.Internal;
using PolylineAlgorithm.Internal;
+using System.Globalization;
///
/// Tests for .
@@ -13,10 +14,9 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class CoordinateDeltaTests {
///
- /// Tests that default constructor initializes delta values to zero.
+ /// Tests that the default constructor initializes delta values to zero.
///
[TestMethod]
-
public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
// Act
CoordinateDelta delta = new();
@@ -27,167 +27,54 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
}
///
- /// Tests that Next with positive values calculates correct delta from zero.
- ///
- [TestMethod]
-
- public void Next_With_Positive_Values_Calculates_Delta_From_Zero() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(10, 20);
-
- // Assert
- Assert.AreEqual(10, delta.Latitude);
- Assert.AreEqual(20, delta.Longitude);
- }
-
- ///
- /// Tests that Next with negative values calculates correct delta from zero.
+ /// Tests that a single call to Next computes the correct delta from the initial zero state.
///
[TestMethod]
-
- public void Next_With_Negative_Values_Calculates_Delta_From_Zero() {
+ [DataRow(10, 20, 10, 20)]
+ [DataRow(-50, -100, -50, -100)]
+ [DataRow(0, 0, 0, 0)]
+ [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)]
+ [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)]
+ public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) {
// Arrange
CoordinateDelta delta = new();
// Act
- delta.Next(-50, -100);
+ delta.Next(latitude, longitude);
// Assert
- Assert.AreEqual(-50, delta.Latitude);
- Assert.AreEqual(-100, delta.Longitude);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that Next with zero values keeps delta at zero.
+ /// Tests that two consecutive calls to Next compute the delta relative to the previous value.
///
[TestMethod]
-
- public void Next_With_Zero_Values_Keeps_Delta_At_Zero() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(0, 0);
-
- // Assert
- Assert.AreEqual(0, delta.Latitude);
- Assert.AreEqual(0, delta.Longitude);
- }
-
- ///
- /// Tests that Next called multiple times calculates delta from previous value.
- ///
- [TestMethod]
-
- public void Next_Called_Multiple_Times_Calculates_Delta_From_Previous_Value() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(10, 20);
- delta.Next(15, 30);
-
- // Assert
- Assert.AreEqual(5, delta.Latitude);
- Assert.AreEqual(10, delta.Longitude);
- }
-
- ///
- /// Tests that Next with decreasing values calculates negative delta.
- ///
- [TestMethod]
-
- public void Next_With_Decreasing_Values_Calculates_Negative_Delta() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(100, 200);
- delta.Next(50, 150);
-
- // Assert
- Assert.AreEqual(-50, delta.Latitude);
- Assert.AreEqual(-50, delta.Longitude);
- }
-
- ///
- /// Tests that Next with same values as previous calculates zero delta.
- ///
- [TestMethod]
-
- public void Next_With_Same_Values_As_Previous_Calculates_Zero_Delta() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(42, 84);
- delta.Next(42, 84);
-
- // Assert
- Assert.AreEqual(0, delta.Latitude);
- Assert.AreEqual(0, delta.Longitude);
- }
-
- ///
- /// Tests that Next with maximum integer values calculates correct delta.
- ///
- [TestMethod]
-
- public void Next_With_Maximum_Integer_Values_Calculates_Correct_Delta() {
+ [DataRow(10, 20, 15, 30, 5, 10)]
+ [DataRow(100, 200, 50, 150, -50, -50)]
+ [DataRow(42, 84, 42, 84, 0, 0)]
+ [DataRow(-50, 100, 25, -75, 75, -175)]
+ public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value(
+ int firstLatitude, int firstLongitude,
+ int secondLatitude, int secondLongitude,
+ int expectedLatitude, int expectedLongitude) {
// Arrange
CoordinateDelta delta = new();
+ delta.Next(firstLatitude, firstLongitude);
// Act
- delta.Next(int.MaxValue, int.MaxValue);
+ delta.Next(secondLatitude, secondLongitude);
// Assert
- Assert.AreEqual(int.MaxValue, delta.Latitude);
- Assert.AreEqual(int.MaxValue, delta.Longitude);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that Next with minimum integer values calculates correct delta.
+ /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value.
///
[TestMethod]
-
- public void Next_With_Minimum_Integer_Values_Calculates_Correct_Delta() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(int.MinValue, int.MinValue);
-
- // Assert
- Assert.AreEqual(int.MinValue, delta.Latitude);
- Assert.AreEqual(int.MinValue, delta.Longitude);
- }
-
- ///
- /// Tests that Next with mixed positive and negative values calculates correct delta.
- ///
- [TestMethod]
-
- public void Next_With_Mixed_Positive_And_Negative_Values_Calculates_Correct_Delta() {
- // Arrange
- CoordinateDelta delta = new();
-
- // Act
- delta.Next(-50, 100);
- delta.Next(25, -75);
-
- // Assert
- Assert.AreEqual(75, delta.Latitude);
- Assert.AreEqual(-175, delta.Longitude);
- }
-
- ///
- /// Tests that ToString with default constructor returns formatted string with zeros.
- ///
- [TestMethod]
-
public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() {
// Arrange
CoordinateDelta delta = new();
@@ -205,29 +92,31 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero
}
///
- /// Tests that ToString after Next returns formatted string with correct values.
+ /// Tests that ToString reflects the delta values computed by Next.
///
[TestMethod]
-
- public void ToString_After_Next_Returns_Formatted_String_With_Correct_Values() {
+ [DataRow(42, 84)]
+ [DataRow(-100, -200)]
+ [DataRow(int.MaxValue, int.MaxValue)]
+ [DataRow(int.MinValue, int.MinValue)]
+ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) {
// Arrange
CoordinateDelta delta = new();
- delta.Next(42, 84);
+ delta.Next(latitude, longitude);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("42", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("84", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
}
///
- /// Tests that ToString after multiple Next calls returns formatted string with latest values.
+ /// Tests that ToString after multiple Next calls reflects the most recent delta values.
///
[TestMethod]
-
public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() {
// Arrange
CoordinateDelta delta = new();
@@ -244,58 +133,4 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat
Assert.IsTrue(result.Contains("20", StringComparison.Ordinal));
}
- ///
- /// Tests that ToString with negative values returns formatted string with negative signs.
- ///
- [TestMethod]
-
- public void ToString_With_Negative_Values_Returns_Formatted_String_With_Negative_Signs() {
- // Arrange
- CoordinateDelta delta = new();
- delta.Next(-100, -200);
-
- // Act
- string result = delta.ToString();
-
- // Assert
- Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("-100", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("-200", StringComparison.Ordinal));
- }
-
- ///
- /// Tests that ToString with maximum integer values returns formatted string.
- ///
- [TestMethod]
-
- public void ToString_With_Maximum_Integer_Values_Returns_Formatted_String() {
- // Arrange
- CoordinateDelta delta = new();
- delta.Next(int.MaxValue, int.MaxValue);
-
- // Act
- string result = delta.ToString();
-
- // Assert
- Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(int.MaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
- }
-
- ///
- /// Tests that ToString with minimum integer values returns formatted string.
- ///
- [TestMethod]
-
- public void ToString_With_Minimum_Integer_Values_Returns_Formatted_String() {
- // Arrange
- CoordinateDelta delta = new();
- delta.Next(int.MinValue, int.MinValue);
-
- // Act
- string result = delta.ToString();
-
- // Assert
- Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(int.MinValue.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
- }
-}
\ No newline at end of file
+}
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs
index 9e955cca..ae62566e 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs
@@ -17,7 +17,6 @@ public sealed class ExceptionGuardTests {
/// Tests that ThrowNotFiniteNumber throws ArgumentOutOfRangeException with correct parameter name.
///
[TestMethod]
-
public void ThrowNotFiniteNumber_WithParamName_ThrowsArgumentOutOfRangeException() {
// Arrange
const string paramName = "value";
@@ -32,7 +31,6 @@ public void ThrowNotFiniteNumber_WithParamName_ThrowsArgumentOutOfRangeException
/// Tests that ThrowArgumentNull throws ArgumentNullException with correct parameter name.
///
[TestMethod]
-
public void ThrowArgumentNull_WithParamName_ThrowsArgumentNullException() {
// Arrange
const string paramName = "input";
@@ -46,7 +44,6 @@ public void ThrowArgumentNull_WithParamName_ThrowsArgumentNullException() {
/// Tests that ThrowBufferOverflow throws OverflowException with correct message.
///
[TestMethod]
-
public void ThrowBufferOverflow_WithMessage_ThrowsOverflowException() {
// Arrange
const string message = "Buffer overflow occurred.";
@@ -60,7 +57,6 @@ public void ThrowBufferOverflow_WithMessage_ThrowsOverflowException() {
/// Tests that ThrowCoordinateValueOutOfRange throws ArgumentOutOfRangeException with correct parameter name.
///
[TestMethod]
-
public void ThrowCoordinateValueOutOfRange_WithParameters_ThrowsArgumentOutOfRangeException() {
// Arrange
const double value = 100.0;
@@ -78,7 +74,6 @@ public void ThrowCoordinateValueOutOfRange_WithParameters_ThrowsArgumentOutOfRan
/// Tests that StackAllocLimitMustBeEqualOrGreaterThan throws ArgumentOutOfRangeException with correct parameter name.
///
[TestMethod]
-
public void StackAllocLimitMustBeEqualOrGreaterThan_WithParameters_ThrowsArgumentOutOfRangeException() {
// Arrange
const int minValue = 10;
@@ -94,7 +89,6 @@ public void StackAllocLimitMustBeEqualOrGreaterThan_WithParameters_ThrowsArgumen
/// Tests that ThrwoArgumentCannotBeEmptyEnumerationMessage throws ArgumentException with correct parameter name.
///
[TestMethod]
-
public void ThrwoArgumentCannotBeEmptyEnumerationMessage_WithParamName_ThrowsArgumentException() {
// Arrange
const string paramName = "collection";
@@ -109,7 +103,6 @@ public void ThrwoArgumentCannotBeEmptyEnumerationMessage_WithParamName_ThrowsArg
/// Tests that ThrowCouldNotWriteEncodedValueToBuffer throws InvalidOperationException with correct message.
///
[TestMethod]
-
public void ThrowCouldNotWriteEncodedValueToBuffer_ThrowsInvalidOperationException() {
// Act & Assert
var ex = Assert.ThrowsExactly(() => ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer());
@@ -120,7 +113,6 @@ public void ThrowCouldNotWriteEncodedValueToBuffer_ThrowsInvalidOperationExcepti
/// Tests that ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength throws ArgumentException with correct parameter name.
///
[TestMethod]
-
public void ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_WithParameters_ThrowsArgumentException() {
// Arrange
const int destinationLength = 5;
@@ -137,7 +129,6 @@ public void ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_Wi
/// Tests that ThrowInvalidPolylineLength throws InvalidPolylineException with correct message.
///
[TestMethod]
-
public void ThrowInvalidPolylineLength_WithParameters_ThrowsInvalidPolylineException() {
// Arrange
const int length = 5;
@@ -152,7 +143,6 @@ public void ThrowInvalidPolylineLength_WithParameters_ThrowsInvalidPolylineExcep
/// Tests that ThrowInvalidPolylineCharacter throws InvalidPolylineException with correct message.
///
[TestMethod]
-
public void ThrowInvalidPolylineCharacter_WithParameters_ThrowsInvalidPolylineException() {
// Arrange
const char character = '!';
@@ -167,7 +157,6 @@ public void ThrowInvalidPolylineCharacter_WithParameters_ThrowsInvalidPolylineEx
/// Tests that ThrowPolylineBlockTooLong throws InvalidPolylineException with correct message.
///
[TestMethod]
-
public void ThrowPolylineBlockTooLong_WithPosition_ThrowsInvalidPolylineException() {
// Arrange
const int position = 42;
@@ -181,7 +170,6 @@ public void ThrowPolylineBlockTooLong_WithPosition_ThrowsInvalidPolylineExceptio
/// Tests that ThrowInvalidPolylineFormat throws InvalidPolylineException with correct message.
///
[TestMethod]
-
public void ThrowInvalidPolylineFormat_WithPosition_ThrowsInvalidPolylineException() {
// Arrange
const long position = 100L;
@@ -195,7 +183,6 @@ public void ThrowInvalidPolylineFormat_WithPosition_ThrowsInvalidPolylineExcepti
/// Tests that ThrowInvalidPolylineBlockTerminator throws InvalidPolylineException with correct message.
///
[TestMethod]
-
public void ThrowInvalidPolylineBlockTerminator_ThrowsInvalidPolylineException() {
// Act & Assert
var ex = Assert.ThrowsExactly(() => ExceptionGuard.ThrowInvalidPolylineBlockTerminator());
@@ -206,7 +193,6 @@ public void ThrowInvalidPolylineBlockTerminator_ThrowsInvalidPolylineException()
/// Tests that FormatStackAllocLimitMustBeEqualOrGreaterThan returns formatted message with specified value.
///
[TestMethod]
-
public void FormatStackAllocLimitMustBeEqualOrGreaterThan_WithMinValue_ReturnsFormattedMessage() {
// Arrange
const int minValue = 10;
@@ -223,7 +209,6 @@ public void FormatStackAllocLimitMustBeEqualOrGreaterThan_WithMinValue_ReturnsFo
/// Tests that FormatPolylineCannotBeShorterThan returns formatted message with specified values.
///
[TestMethod]
-
public void FormatPolylineCannotBeShorterThan_WithLengthAndMinLength_ReturnsFormattedMessage() {
// Arrange
const int length = 5;
@@ -242,7 +227,6 @@ public void FormatPolylineCannotBeShorterThan_WithLengthAndMinLength_ReturnsForm
/// Tests that FormatMalformedPolyline returns formatted message with position.
///
[TestMethod]
-
public void FormatMalformedPolyline_WithPosition_ReturnsFormattedMessage() {
// Arrange
const long position = 42L;
@@ -259,7 +243,6 @@ public void FormatMalformedPolyline_WithPosition_ReturnsFormattedMessage() {
/// Tests that FormatMalformedPolyline with zero position returns formatted message.
///
[TestMethod]
-
public void FormatMalformedPolyline_WithZeroPosition_ReturnsFormattedMessage() {
// Arrange
const long position = 0L;
@@ -276,7 +259,6 @@ public void FormatMalformedPolyline_WithZeroPosition_ReturnsFormattedMessage() {
/// Tests that FormatMalformedPolyline with negative position returns formatted message.
///
[TestMethod]
-
public void FormatMalformedPolyline_WithNegativePosition_ReturnsFormattedMessage() {
// Arrange
const long position = -10L;
@@ -293,7 +275,6 @@ public void FormatMalformedPolyline_WithNegativePosition_ReturnsFormattedMessage
/// Tests that FormatMalformedPolyline with large position returns formatted message.
///
[TestMethod]
-
public void FormatMalformedPolyline_WithLargePosition_ReturnsFormattedMessage() {
// Arrange
const long position = long.MaxValue;
@@ -310,7 +291,6 @@ public void FormatMalformedPolyline_WithLargePosition_ReturnsFormattedMessage()
/// Tests that FormatCoordinateValueMustBeBetween returns formatted message with all parameters.
///
[TestMethod]
-
public void FormatCoordinateValueMustBeBetween_WithParameters_ReturnsFormattedMessage() {
// Arrange
const string name = "latitude";
@@ -331,7 +311,6 @@ public void FormatCoordinateValueMustBeBetween_WithParameters_ReturnsFormattedMe
/// Tests that FormatCoordinateValueMustBeBetween with positive values returns formatted message.
///
[TestMethod]
-
public void FormatCoordinateValueMustBeBetween_WithPositiveValues_ReturnsFormattedMessage() {
// Arrange
const string name = "longitude";
@@ -352,7 +331,6 @@ public void FormatCoordinateValueMustBeBetween_WithPositiveValues_ReturnsFormatt
/// Tests that FormatCoordinateValueMustBeBetween with fractional values returns formatted message.
///
[TestMethod]
-
public void FormatCoordinateValueMustBeBetween_WithFractionalValues_ReturnsFormattedMessage() {
// Arrange
const string name = "value";
@@ -371,7 +349,6 @@ public void FormatCoordinateValueMustBeBetween_WithFractionalValues_ReturnsForma
/// Tests that FormatPolylineBlockTooLong returns formatted message with position.
///
[TestMethod]
-
public void FormatPolylineBlockTooLong_WithPosition_ReturnsFormattedMessage() {
// Arrange
const int position = 15;
@@ -388,7 +365,6 @@ public void FormatPolylineBlockTooLong_WithPosition_ReturnsFormattedMessage() {
/// Tests that FormatPolylineBlockTooLong with zero position returns formatted message.
///
[TestMethod]
-
public void FormatPolylineBlockTooLong_WithZeroPosition_ReturnsFormattedMessage() {
// Arrange
const int position = 0;
@@ -405,7 +381,6 @@ public void FormatPolylineBlockTooLong_WithZeroPosition_ReturnsFormattedMessage(
/// Tests that FormatPolylineBlockTooLong with large position returns formatted message.
///
[TestMethod]
-
public void FormatPolylineBlockTooLong_WithLargePosition_ReturnsFormattedMessage() {
// Arrange
const int position = int.MaxValue;
@@ -422,7 +397,6 @@ public void FormatPolylineBlockTooLong_WithLargePosition_ReturnsFormattedMessage
/// Tests that FormatInvalidPolylineCharacter returns formatted message with character and position.
///
[TestMethod]
-
public void FormatInvalidPolylineCharacter_WithCharacterAndPosition_ReturnsFormattedMessage() {
// Arrange
const char character = '!';
@@ -441,7 +415,6 @@ public void FormatInvalidPolylineCharacter_WithCharacterAndPosition_ReturnsForma
/// Tests that FormatInvalidPolylineCharacter with letter character returns formatted message.
///
[TestMethod]
-
public void FormatInvalidPolylineCharacter_WithLetterCharacter_ReturnsFormattedMessage() {
// Arrange
const char character = 'Z';
@@ -460,7 +433,6 @@ public void FormatInvalidPolylineCharacter_WithLetterCharacter_ReturnsFormattedM
/// Tests that FormatInvalidPolylineCharacter with special character returns formatted message.
///
[TestMethod]
-
public void FormatInvalidPolylineCharacter_WithSpecialCharacter_ReturnsFormattedMessage() {
// Arrange
const char character = '@';
@@ -479,7 +451,6 @@ public void FormatInvalidPolylineCharacter_WithSpecialCharacter_ReturnsFormatted
/// Tests that FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength returns formatted message.
///
[TestMethod]
-
public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_WithLengths_ReturnsFormattedMessage() {
// Arrange
const int destinationLength = 5;
@@ -498,7 +469,6 @@ public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_W
/// Tests that FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength with zero destination length returns formatted message.
///
[TestMethod]
-
public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_WithZeroDestinationLength_ReturnsFormattedMessage() {
// Arrange
const int destinationLength = 0;
@@ -517,7 +487,6 @@ public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_W
/// Tests that FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength with large values returns formatted message.
///
[TestMethod]
-
public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_WithLargeValues_ReturnsFormattedMessage() {
// Arrange
const int destinationLength = 1000;
@@ -536,7 +505,6 @@ public void FormatDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_W
/// Tests that FormatInvalidPolylineLength returns formatted message with length and min values.
///
[TestMethod]
-
public void FormatInvalidPolylineLength_WithLengthAndMin_ReturnsFormattedMessage() {
// Arrange
const int length = 5;
@@ -555,7 +523,6 @@ public void FormatInvalidPolylineLength_WithLengthAndMin_ReturnsFormattedMessage
/// Tests that FormatInvalidPolylineLength with zero length returns formatted message.
///
[TestMethod]
-
public void FormatInvalidPolylineLength_WithZeroLength_ReturnsFormattedMessage() {
// Arrange
const int length = 0;
@@ -574,7 +541,6 @@ public void FormatInvalidPolylineLength_WithZeroLength_ReturnsFormattedMessage()
/// Tests that FormatInvalidPolylineLength with negative values returns formatted message.
///
[TestMethod]
-
public void FormatInvalidPolylineLength_WithNegativeValues_ReturnsFormattedMessage() {
// Arrange
const int length = -5;
@@ -593,7 +559,6 @@ public void FormatInvalidPolylineLength_WithNegativeValues_ReturnsFormattedMessa
/// Tests that GetArgumentValueMustBeFiniteNumber returns non-null message.
///
[TestMethod]
-
public void GetArgumentValueMustBeFiniteNumber_ReturnsNonNullMessage() {
// Act
string result = ExceptionGuard.ExceptionMessage.GetArgumentValueMustBeFiniteNumber();
@@ -607,7 +572,6 @@ public void GetArgumentValueMustBeFiniteNumber_ReturnsNonNullMessage() {
/// Tests that GetCouldNotWriteEncodedValueToTheBuffer returns non-null message.
///
[TestMethod]
-
public void GetCouldNotWriteEncodedValueToTheBuffer_ReturnsNonNullMessage() {
// Act
string result = ExceptionGuard.ExceptionMessage.GetCouldNotWriteEncodedValueToTheBuffer();
@@ -621,7 +585,6 @@ public void GetCouldNotWriteEncodedValueToTheBuffer_ReturnsNonNullMessage() {
/// Tests that GetArgumentCannotBeEmpty returns non-null message.
///
[TestMethod]
-
public void GetArgumentCannotBeEmpty_ReturnsNonNullMessage() {
// Act
string result = ExceptionGuard.ExceptionMessage.GetArgumentCannotBeEmpty();
@@ -635,7 +598,6 @@ public void GetArgumentCannotBeEmpty_ReturnsNonNullMessage() {
/// Tests that GetInvalidPolylineBlockTerminator returns non-null message.
///
[TestMethod]
-
public void GetInvalidPolylineBlockTerminator_ReturnsNonNullMessage() {
// Act
string result = ExceptionGuard.ExceptionMessage.GetInvalidPolylineBlockTerminator();
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
index 9fdbbcd3..14cc2bd4 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
@@ -34,8 +34,10 @@ public void Dispose() { }
}
}
+ ///
+ /// Tests that LogOperationStartedDebug WithOperationName LogsStartedMessage.
+ ///
[TestMethod]
-
public void LogOperationStartedDebug_WithOperationName_LogsStartedMessage() {
var logger = new TestLogger();
const string operationName = "TestOperation";
@@ -47,8 +49,10 @@ public void LogOperationStartedDebug_WithOperationName_LogsStartedMessage() {
Assert.Contains($"Operation {operationName} has started.", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFailedDebug WithOperationName LogsFailedMessage.
+ ///
[TestMethod]
-
public void LogOperationFailedDebug_WithOperationName_LogsFailedMessage() {
var logger = new TestLogger();
const string operationName = "TestOperation";
@@ -60,8 +64,10 @@ public void LogOperationFailedDebug_WithOperationName_LogsFailedMessage() {
Assert.Contains($"Operation {operationName} has failed.", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFinishedDebug WithOperationName LogsFinishedMessage.
+ ///
[TestMethod]
-
public void LogOperationFinishedDebug_WithOperationName_LogsFinishedMessage() {
var logger = new TestLogger();
const string operationName = "TestOperation";
@@ -73,8 +79,10 @@ public void LogOperationFinishedDebug_WithOperationName_LogsFinishedMessage() {
Assert.Contains($"Operation {operationName} has finished.", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage.
+ ///
[TestMethod]
-
public void LogDecodedCoordinateDebug_WithCoordinatesAndPosition_LogsDecodedCoordinateMessage() {
var logger = new TestLogger();
const double latitude = 38.5;
@@ -88,8 +96,10 @@ public void LogDecodedCoordinateDebug_WithCoordinatesAndPosition_LogsDecodedCoor
Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationStartedDebug WithNullOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationStartedDebug_WithNullOperationName_LogsMessage() {
var logger = new TestLogger();
const string? operationName = null;
@@ -101,8 +111,10 @@ public void LogOperationStartedDebug_WithNullOperationName_LogsMessage() {
Assert.Contains("Operation", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFailedDebug WithNullOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationFailedDebug_WithNullOperationName_LogsMessage() {
var logger = new TestLogger();
const string? operationName = null;
@@ -114,8 +126,10 @@ public void LogOperationFailedDebug_WithNullOperationName_LogsMessage() {
Assert.Contains("Operation", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFinishedDebug WithNullOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationFinishedDebug_WithNullOperationName_LogsMessage() {
var logger = new TestLogger();
const string? operationName = null;
@@ -127,8 +141,10 @@ public void LogOperationFinishedDebug_WithNullOperationName_LogsMessage() {
Assert.Contains("Operation", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage.
+ ///
[TestMethod]
-
public void LogDecodedCoordinateDebug_WithZeroCoordinates_LogsMessage() {
var logger = new TestLogger();
const double latitude = 0.0;
@@ -142,8 +158,10 @@ public void LogDecodedCoordinateDebug_WithZeroCoordinates_LogsMessage() {
Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage.
+ ///
[TestMethod]
-
public void LogDecodedCoordinateDebug_WithNegativeCoordinates_LogsMessage() {
var logger = new TestLogger();
const double latitude = -90.0;
@@ -157,8 +175,10 @@ public void LogDecodedCoordinateDebug_WithNegativeCoordinates_LogsMessage() {
Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationStartedDebug WithEmptyOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationStartedDebug_WithEmptyOperationName_LogsMessage() {
var logger = new TestLogger();
string operationName = string.Empty;
@@ -170,8 +190,10 @@ public void LogOperationStartedDebug_WithEmptyOperationName_LogsMessage() {
Assert.Contains("Operation", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFailedDebug WithEmptyOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationFailedDebug_WithEmptyOperationName_LogsMessage() {
var logger = new TestLogger();
string operationName = string.Empty;
@@ -183,8 +205,10 @@ public void LogOperationFailedDebug_WithEmptyOperationName_LogsMessage() {
Assert.Contains("Operation", logger.Logs[0].Message, StringComparison.Ordinal);
}
+ ///
+ /// Tests that LogOperationFinishedDebug WithEmptyOperationName LogsMessage.
+ ///
[TestMethod]
-
public void LogOperationFinishedDebug_WithEmptyOperationName_LogsMessage() {
var logger = new TestLogger();
string operationName = string.Empty;
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogWarningExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogWarningExtensionsTests.cs
index a2d31ff8..a4dc4912 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogWarningExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogWarningExtensionsTests.cs
@@ -32,6 +32,9 @@ public void Dispose() { }
}
}
+ ///
+ /// Tests that LogNullArgumentWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogNullArgumentWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -39,6 +42,9 @@ public void LogNullArgumentWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Argument foo is null.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogEmptyArgumentWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogEmptyArgumentWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -46,6 +52,9 @@ public void LogEmptyArgumentWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Argument bar is empty.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogInternalBufferOverflowWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogInternalBufferOverflowWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -53,6 +62,9 @@ public void LogInternalBufferOverflowWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Internal buffer has size of 2. At position 1 is required additional 3 space.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogCannotWriteValueToBufferWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogCannotWriteValueToBufferWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -60,6 +72,9 @@ public void LogCannotWriteValueToBufferWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Cannot write to internal buffer at position 4. Current coordinate is at index 5.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogPolylineCannotBeShorterThanWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogPolylineCannotBeShorterThanWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -67,6 +82,9 @@ public void LogPolylineCannotBeShorterThanWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Polyline is too short. Minimal length is 7. Actual length is 6.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogRequestedBufferSizeExceedsMaxBufferLengthWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogRequestedBufferSizeExceedsMaxBufferLengthWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -74,6 +92,9 @@ public void LogRequestedBufferSizeExceedsMaxBufferLengthWarning_LogsExpectedMess
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Requested buffer size of 8 exceeds maximum allowed buffer length of 9.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogInvalidPolylineWarning LogsExpectedMessage.
+ ///
[TestMethod]
public void LogInvalidPolylineWarning_LogsExpectedMessage() {
var logger = new TestLogger();
@@ -81,6 +102,9 @@ public void LogInvalidPolylineWarning_LogsExpectedMessage() {
Assert.IsTrue(logger.Logs.Exists(l => l.Message.Contains("Polyline is invalid or malformed at position 10.", StringComparison.Ordinal)));
}
+ ///
+ /// Tests that LogInvalidPolylineFormatWarning LogsExpectedMessage.
+ ///
[TestMethod]
[SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "No need to be strict in tests.")]
public void LogInvalidPolylineFormatWarning_LogsExpectedMessage() {
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Pow10Tests.cs b/tests/PolylineAlgorithm.Tests/Internal/Pow10Tests.cs
index 58d4344e..ba3fc860 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Pow10Tests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Pow10Tests.cs
@@ -13,162 +13,37 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class Pow10Tests {
///
- /// Tests that GetFactor with precision 0 returns 1.
+ /// Tests that GetFactor returns the correct power-of-ten factor for the given precision.
///
[TestMethod]
-
- public void GetFactor_With_Precision_Zero_Returns_One() {
+ [DataRow(0u, 1u)]
+ [DataRow(1u, 10u)]
+ [DataRow(2u, 100u)]
+ [DataRow(3u, 1000u)]
+ [DataRow(4u, 10000u)]
+ [DataRow(5u, 100000u)]
+ [DataRow(6u, 1000000u)]
+ [DataRow(7u, 10000000u)]
+ [DataRow(8u, 100000000u)]
+ [DataRow(9u, 1000000000u)]
+ public void GetFactor_With_Valid_Precision_Returns_Expected_Value(uint precision, uint expected) {
// Act
- uint result = Pow10.GetFactor(0);
+ uint result = Pow10.GetFactor(precision);
// Assert
- Assert.AreEqual(1u, result);
+ Assert.AreEqual(expected, result);
}
///
- /// Tests that GetFactor with precision 1 returns 10.
+ /// Tests that GetFactor throws when precision causes overflow.
///
[TestMethod]
-
- public void GetFactor_With_Precision_One_Returns_Ten() {
- // Act
- uint result = Pow10.GetFactor(1);
-
- // Assert
- Assert.AreEqual(10u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 2 returns 100.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Two_Returns_One_Hundred() {
- // Act
- uint result = Pow10.GetFactor(2);
-
- // Assert
- Assert.AreEqual(100u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 3 returns 1000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Three_Returns_One_Thousand() {
- // Act
- uint result = Pow10.GetFactor(3);
-
- // Assert
- Assert.AreEqual(1000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 4 returns 10000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Four_Returns_Ten_Thousand() {
- // Act
- uint result = Pow10.GetFactor(4);
-
- // Assert
- Assert.AreEqual(10000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 5 returns 100000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Five_Returns_One_Hundred_Thousand() {
- // Act
- uint result = Pow10.GetFactor(5);
-
- // Assert
- Assert.AreEqual(100000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 6 returns 1000000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Six_Returns_One_Million() {
- // Act
- uint result = Pow10.GetFactor(6);
-
- // Assert
- Assert.AreEqual(1000000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 7 returns 10000000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Seven_Returns_Ten_Million() {
- // Act
- uint result = Pow10.GetFactor(7);
-
- // Assert
- Assert.AreEqual(10000000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 8 returns 100000000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Eight_Returns_One_Hundred_Million() {
- // Act
- uint result = Pow10.GetFactor(8);
-
- // Assert
- Assert.AreEqual(100000000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision 9 returns 1000000000.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Nine_Returns_One_Billion() {
- // Act
- uint result = Pow10.GetFactor(9);
-
- // Assert
- Assert.AreEqual(1000000000u, result);
- }
-
- ///
- /// Tests that GetFactor with precision causing overflow throws OverflowException.
- ///
- [TestMethod]
-
- public void GetFactor_With_Precision_Causing_Overflow_Throws_OverflowException() {
- // Act & Assert
- Assert.ThrowsExactly(() => Pow10.GetFactor(15));
- }
-
- ///
- /// Tests that GetFactor with large precision causing overflow throws OverflowException.
- ///
- [TestMethod]
-
- public void GetFactor_With_Large_Precision_Causing_Overflow_Throws_OverflowException() {
- // Act & Assert
- Assert.ThrowsExactly(() => Pow10.GetFactor(20));
- }
-
- ///
- /// Tests that GetFactor with maximum uint precision throws OverflowException.
- ///
- [TestMethod]
-
- public void GetFactor_With_Maximum_Uint_Precision_Throws_OverflowException() {
+ [DataRow(10u)]
+ [DataRow(15u)]
+ [DataRow(20u)]
+ [DataRow(uint.MaxValue)]
+ public void GetFactor_With_Overflowing_Precision_Throws_OverflowException(uint precision) {
// Act & Assert
- Assert.ThrowsExactly(() => Pow10.GetFactor(uint.MaxValue));
+ Assert.ThrowsExactly(() => Pow10.GetFactor(precision));
}
-}
\ No newline at end of file
+}
diff --git a/tests/PolylineAlgorithm.Tests/InvalidPolylineExceptionTests.cs b/tests/PolylineAlgorithm.Tests/InvalidPolylineExceptionTests.cs
new file mode 100644
index 00000000..903d85ee
--- /dev/null
+++ b/tests/PolylineAlgorithm.Tests/InvalidPolylineExceptionTests.cs
@@ -0,0 +1,44 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.Tests;
+
+using System;
+
+///
+/// Tests for .
+///
+[TestClass]
+public sealed class InvalidPolylineExceptionTests {
+ ///
+ /// Tests that the default constructor creates an instance with a null message.
+ ///
+ [TestMethod]
+ public void Constructor_Default_CreatesInstance() {
+ // Act
+ InvalidPolylineException ex = new();
+
+ // Assert
+ Assert.IsNotNull(ex);
+ Assert.IsNull(ex.InnerException);
+ }
+
+ ///
+ /// Tests that the message and inner exception constructor stores both values.
+ ///
+ [TestMethod]
+ public void Constructor_WithMessageAndInnerException_StoresBoth() {
+ // Arrange
+ const string message = "polyline is malformed";
+ Exception inner = new InvalidOperationException("inner");
+
+ // Act
+ InvalidPolylineException ex = new(message, inner);
+
+ // Assert
+ Assert.AreEqual(message, ex.Message);
+ Assert.AreSame(inner, ex.InnerException);
+ }
+}
diff --git a/tests/PolylineAlgorithm.Tests/PolylineAlgorithm.Tests.csproj b/tests/PolylineAlgorithm.Tests/PolylineAlgorithm.Tests.csproj
index 72fdded9..ff88dcb7 100644
--- a/tests/PolylineAlgorithm.Tests/PolylineAlgorithm.Tests.csproj
+++ b/tests/PolylineAlgorithm.Tests/PolylineAlgorithm.Tests.csproj
@@ -18,7 +18,6 @@
-
diff --git a/tests/PolylineAlgorithm.Tests/PolylineEncodingTests.cs b/tests/PolylineAlgorithm.Tests/PolylineEncodingTests.cs
index 192fb456..08b8bd0f 100644
--- a/tests/PolylineAlgorithm.Tests/PolylineEncodingTests.cs
+++ b/tests/PolylineAlgorithm.Tests/PolylineEncodingTests.cs
@@ -18,998 +18,526 @@ public sealed class PolylineEncodingTests {
/// Tests that Normalize returns zero when value is zero.
///
[TestMethod]
-
public void Normalize_ZeroValue_ReturnsZero() {
- // Arrange
- const double value = 0.0;
- const uint precision = 5;
-
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ int result = PolylineEncoding.Normalize(0.0);
// Assert
Assert.AreEqual(0, result);
}
///
- /// Tests that Normalize throws when value is NaN.
+ /// Tests that Normalize throws when value is not finite.
///
[TestMethod]
-
- public void Normalize_NaNValue_ThrowsArgumentOutOfRangeException() {
- // Arrange
- const double value = double.NaN;
- const uint precision = 5;
-
+ [DataRow(double.NaN)]
+ [DataRow(double.PositiveInfinity)]
+ [DataRow(double.NegativeInfinity)]
+ public void Normalize_With_NonFinite_Value_Throws_ArgumentOutOfRangeException(double value) {
// Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.Normalize(value, precision));
+ Assert.ThrowsExactly(() => PolylineEncoding.Normalize(value, 5));
}
///
- /// Tests that Normalize throws when value is positive infinity.
+ /// Tests that Normalize returns the expected normalized integer for the given value and precision.
///
[TestMethod]
+ [DataRow(37.78903, 0u, 37)]
+ [DataRow(-122.4123, 0u, -122)]
+ [DataRow(37.78903, 5u, 3778903)]
+ [DataRow(-122.4123, 5u, -12241230)]
+ [DataRow(37.78903, 1u, 377)]
+ [DataRow(37.789034, 6u, 37789034)]
+ [DataRow(37.789999, 5u, 3778999)]
+ [DataRow(0.00001, 5u, 1)]
+ [DataRow(-0.00001, 5u, -1)]
+ public void Normalize_With_Value_And_Precision_Returns_Expected_Normalized_Value(double value, uint precision, int expected) {
+ // Act
+ int result = PolylineEncoding.Normalize(value, precision);
- public void Normalize_PositiveInfinity_ThrowsArgumentOutOfRangeException() {
- // Arrange
- const double value = double.PositiveInfinity;
- const uint precision = 5;
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.Normalize(value, precision));
+ // Assert
+ Assert.AreEqual(expected, result);
}
- ///
- /// Tests that Normalize throws when value is negative infinity.
- ///
- [TestMethod]
-
- public void Normalize_NegativeInfinity_ThrowsArgumentOutOfRangeException() {
- // Arrange
- const double value = double.NegativeInfinity;
- const uint precision = 5;
+ #endregion
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.Normalize(value, precision));
- }
+ #region Denormalize Tests
///
- /// Tests that Normalize with zero precision returns truncated value.
+ /// Tests that Denormalize returns zero when value is zero.
///
[TestMethod]
-
- public void Normalize_ZeroPrecision_ReturnsTruncatedValue() {
- // Arrange
- const double value = 37.78903;
- const uint precision = 0;
-
+ public void Denormalize_ZeroValue_ReturnsZero() {
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ double result = PolylineEncoding.Denormalize(0);
// Assert
- Assert.AreEqual(37, result);
+ Assert.AreEqual(0.0, result);
}
///
- /// Tests that Normalize with zero precision truncates negative values correctly.
+ /// Tests that Denormalize returns the expected floating-point value for the given integer and precision.
///
[TestMethod]
-
- public void Normalize_ZeroPrecisionNegative_ReturnsTruncatedValue() {
- // Arrange
- const double value = -122.4123;
- const uint precision = 0;
-
+ [DataRow(37, 0u, 37.0)]
+ [DataRow(-122, 0u, -122.0)]
+ [DataRow(3778903, 5u, 37.78903)]
+ [DataRow(-12241230, 5u, -122.4123)]
+ [DataRow(377, 1u, 37.7)]
+ [DataRow(37789034, 6u, 37.789034)]
+ [DataRow(1, 5u, 0.00001)]
+ [DataRow(-1, 5u, -0.00001)]
+ public void Denormalize_With_Value_And_Precision_Returns_Expected_Denormalized_Value(int value, uint precision, double expected) {
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ double result = PolylineEncoding.Denormalize(value, precision);
// Assert
- Assert.AreEqual(-122, result);
+ Assert.AreEqual(expected, result, 1e-7);
}
+ #endregion
+
+ #region TryReadValue Tests
+
///
- /// Tests that Normalize with default precision normalizes positive value correctly.
+ /// Tests that TryReadValue returns false when position is at buffer length.
///
[TestMethod]
-
- public void Normalize_DefaultPrecisionPositive_ReturnsNormalizedValue() {
+ public void TryReadValue_PositionAtBufferLength_ReturnsFalse() {
// Arrange
- const double value = 37.78903;
- const uint precision = 5;
+ ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
+ int delta = 0;
+ int position = buffer.Length;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(3778903, result);
+ Assert.IsFalse(result);
+ Assert.AreEqual(0, delta);
}
///
- /// Tests that Normalize with default precision normalizes negative value correctly.
+ /// Tests that TryReadValue returns false when position exceeds buffer length.
///
[TestMethod]
-
- public void Normalize_DefaultPrecisionNegative_ReturnsNormalizedValue() {
+ public void TryReadValue_PositionExceedsBufferLength_ReturnsFalse() {
// Arrange
- const double value = -122.4123;
- const uint precision = 5;
+ ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
+ int delta = 0;
+ int position = buffer.Length + 1;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(-12241230, result);
+ Assert.IsFalse(result);
+ Assert.AreEqual(0, delta);
}
///
- /// Tests that Normalize with precision 1 works correctly.
+ /// Tests that TryReadValue reads a positive single-character encoded value.
///
[TestMethod]
-
- public void Normalize_Precision1_ReturnsNormalizedValue() {
+ public void TryReadValue_PositiveSingleChar_ReadsValueAndReturnsTrue() {
// Arrange
- const double value = 37.78903;
- const uint precision = 1;
+ // Encode value 5: zigzag = 10 = 0x0A; char = 10 + 63 = 73 = 'I'
+ ReadOnlyMemory buffer = "I".AsMemory(); // Single char encoding of value 5
+ int delta = 0;
+ int position = 0;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(377, result);
+ Assert.IsTrue(result);
+ Assert.AreEqual(5, delta);
+ Assert.AreEqual(1, position);
}
///
- /// Tests that Normalize with precision 6 works correctly.
+ /// Tests that TryReadValue reads a positive multi-character encoded value.
///
[TestMethod]
-
- public void Normalize_Precision6_ReturnsNormalizedValue() {
+ public void TryReadValue_PositiveMultiChar_ReadsValueAndReturnsTrue() {
// Arrange
- const double value = 37.789034;
- const uint precision = 6;
+ // _p~iF encodes latitude 38.5 (normalized = 3850000, zigzag = 7700000)
+ ReadOnlyMemory buffer = "_p~iF".AsMemory();
+ int delta = 0;
+ int position = 0;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(37789034, result);
+ Assert.IsTrue(result);
+ Assert.AreEqual(3850000, delta);
+ Assert.AreEqual(5, position);
}
///
- /// Tests that Normalize truncates fractional parts.
+ /// Tests that TryReadValue reads a negative encoded value.
///
[TestMethod]
-
- public void Normalize_ValueWithFractionalPart_TruncatesFractionalPart() {
+ public void TryReadValue_NegativeValue_ReadsValueAndReturnsTrue() {
// Arrange
- const double value = 37.789999;
- const uint precision = 5;
+ // ~ps|U encodes longitude -120.2 (normalized = -12020000, zigzag encodes negative)
+ ReadOnlyMemory buffer = "~ps|U".AsMemory();
+ int delta = 0;
+ int position = 0;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(3778999, result);
+ Assert.IsTrue(result);
+ Assert.AreEqual(-12020000, delta);
+ Assert.AreEqual(5, position);
}
///
- /// Tests that Normalize handles very small values.
+ /// Tests that TryReadValue accumulates into existing delta.
///
[TestMethod]
-
- public void Normalize_VerySmallValue_ReturnsNormalizedValue() {
+ public void TryReadValue_WithExistingDelta_AccumulatesDelta() {
// Arrange
- const double value = 0.00001;
- const uint precision = 5;
+ ReadOnlyMemory buffer = "I".AsMemory(); // encodes 5
+ int delta = 10; // existing delta
+ int position = 0;
// Act
- int result = PolylineEncoding.Normalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(1, result);
+ Assert.IsTrue(result);
+ Assert.AreEqual(15, delta); // 10 + 5 = 15
}
///
- /// Tests that Normalize handles negative very small values.
+ /// Tests that TryReadValue reads multiple values sequentially from the buffer.
///
[TestMethod]
+ public void TryReadValue_MultipleValues_ReadsSequentially() {
+ // Arrange - "_p~iF~ps|U" encodes lat 38.5 then delta lon -120.2
+ ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
+ int delta = 0;
+ int position = 0;
- public void Normalize_NegativeVerySmallValue_ReturnsNormalizedValue() {
- // Arrange
- const double value = -0.00001;
- const uint precision = 5;
+ // Act - read first value
+ bool first = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
+ int firstDelta = delta;
- // Act
- int result = PolylineEncoding.Normalize(value, precision);
+ // read second value
+ bool second = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(-1, result);
+ Assert.IsTrue(first);
+ Assert.IsTrue(second);
+ Assert.AreEqual(3850000, firstDelta);
+ Assert.AreEqual(10, position); // consumed all 10 chars
}
- #endregion
-
- #region Denormalize Tests
-
///
- /// Tests that Denormalize returns zero when value is zero.
+ /// Tests that TryReadValue returns false when buffer ends mid-value.
///
[TestMethod]
-
- public void Denormalize_ZeroValue_ReturnsZero() {
- // Arrange
- const int value = 0;
- const uint precision = 5;
+ public void TryReadValue_BufferEndsMidValue_ReturnsFalse() {
+ // Arrange - truncate a multi-char encoding
+ ReadOnlyMemory buffer = "_p~".AsMemory(); // incomplete multi-char encoding
+ int delta = 0;
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(0.0, result);
+ Assert.IsFalse(result);
}
///
- /// Tests that Denormalize with zero precision returns same value as double.
+ /// Tests that TryReadValue correctly reads from a non-zero starting position.
///
[TestMethod]
-
- public void Denormalize_ZeroPrecision_ReturnsSameValue() {
- // Arrange
- const int value = 37;
- const uint precision = 0;
+ public void TryReadValue_StartingFromMiddle_ReadsCorrectly() {
+ // Arrange - "_p~iF~ps|U": start at position 5 to read the longitude value
+ ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
+ int delta = 0;
+ int position = 5;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
// Assert
- Assert.AreEqual(37.0, result);
+ Assert.IsTrue(result);
+ Assert.AreEqual(-12020000, delta);
+ Assert.AreEqual(10, position);
}
+ #endregion
+
+ #region TryWriteValue Tests
+
///
- /// Tests that Denormalize with zero precision handles negative values.
+ /// Tests that TryWriteValue returns false when the buffer is too small.
///
[TestMethod]
-
- public void Denormalize_ZeroPrecisionNegative_ReturnsSameValue() {
+ public void TryWriteValue_BufferTooSmall_ReturnsFalse() {
// Arrange
- const int value = -122;
- const uint precision = 0;
+ Span buffer = [];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(3850000, buffer, ref position);
// Assert
- Assert.AreEqual(-122.0, result);
+ Assert.IsFalse(result);
+ Assert.AreEqual(0, position);
}
///
- /// Tests that Denormalize with default precision denormalizes positive value correctly.
+ /// Tests that TryWriteValue returns false when the remaining buffer is too small.
///
[TestMethod]
-
- public void Denormalize_DefaultPrecisionPositive_ReturnsDenormalizedValue() {
- // Arrange
- const int value = 3778903;
- const uint precision = 5;
+ public void TryWriteValue_RemainingBufferTooSmall_ReturnsFalse() {
+ // Arrange - need 5 chars for 3850000, but only 3 remain
+ Span buffer = new char[3];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(3850000, buffer, ref position);
// Assert
- Assert.AreEqual(37.78903, result, 0.0000001);
+ Assert.IsFalse(result);
+ Assert.AreEqual(0, position);
}
///
- /// Tests that Denormalize with default precision denormalizes negative value correctly.
+ /// Tests that TryWriteValue correctly encodes zero.
///
[TestMethod]
-
- public void Denormalize_DefaultPrecisionNegative_ReturnsDenormalizedValue() {
+ public void TryWriteValue_ZeroValue_WritesCorrectly() {
// Arrange
- const int value = -12241230;
- const uint precision = 5;
+ Span buffer = new char[10];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(0, buffer, ref position);
// Assert
- Assert.AreEqual(-122.4123, result, 0.0000001);
+ Assert.IsTrue(result);
+ Assert.AreEqual(1, position);
+ Assert.AreEqual('?', buffer[0]); // 0 + 63 = '?'
}
///
- /// Tests that Denormalize with precision 1 works correctly.
+ /// Tests that TryWriteValue correctly encodes a positive value.
///
[TestMethod]
-
- public void Denormalize_Precision1_ReturnsDenormalizedValue() {
+ public void TryWriteValue_PositiveValue_WritesCorrectly() {
// Arrange
- const int value = 377;
- const uint precision = 1;
+ Span buffer = new char[10];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(3850000, buffer, ref position);
// Assert
- Assert.AreEqual(37.7, result, 0.0000001);
+ Assert.IsTrue(result);
+ Assert.AreEqual(5, position);
+ Assert.AreEqual("_p~iF", new string(buffer[..5]));
}
///
- /// Tests that Denormalize with precision 6 works correctly.
+ /// Tests that TryWriteValue correctly encodes a negative value.
///
[TestMethod]
-
- public void Denormalize_Precision6_ReturnsDenormalizedValue() {
+ public void TryWriteValue_NegativeValue_WritesCorrectly() {
// Arrange
- const int value = 37789034;
- const uint precision = 6;
+ Span buffer = new char[10];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(-12020000, buffer, ref position);
// Assert
- Assert.AreEqual(37.789034, result, 0.0000001);
+ Assert.IsTrue(result);
+ Assert.AreEqual(5, position);
+ Assert.AreEqual("~ps|U", new string(buffer[..5]));
}
///
- /// Tests that Denormalize handles very small values.
+ /// Tests that TryWriteValue correctly encodes multiple values sequentially.
///
[TestMethod]
-
- public void Denormalize_VerySmallValue_ReturnsDenormalizedValue() {
+ public void TryWriteValue_MultipleValues_WritesSequentially() {
// Arrange
- const int value = 1;
- const uint precision = 5;
+ Span buffer = new char[20];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool first = PolylineEncoding.TryWriteValue(3850000, buffer, ref position);
+ bool second = PolylineEncoding.TryWriteValue(-12020000, buffer, ref position);
// Assert
- Assert.AreEqual(0.00001, result, 0.0000001);
+ Assert.IsTrue(first);
+ Assert.IsTrue(second);
+ Assert.AreEqual("_p~iF~ps|U", new string(buffer[..10]));
}
///
- /// Tests that Denormalize handles negative very small values.
+ /// Tests that TryWriteValue correctly encodes a small positive value.
///
[TestMethod]
-
- public void Denormalize_NegativeVerySmallValue_ReturnsDenormalizedValue() {
+ public void TryWriteValue_SmallPositiveValue_WritesCorrectly() {
// Arrange
- const int value = -1;
- const uint precision = 5;
+ Span buffer = new char[10];
+ int position = 0;
// Act
- double result = PolylineEncoding.Denormalize(value, precision);
+ bool result = PolylineEncoding.TryWriteValue(5, buffer, ref position);
// Assert
- Assert.AreEqual(-0.00001, result, 0.0000001);
+ Assert.IsTrue(result);
+ Assert.AreEqual(1, position);
+ Assert.AreEqual('I', buffer[0]); // zigzag(5) = 10; 10 + 63 = 73 = 'I'
}
- #endregion
-
- #region TryReadValue Tests
-
///
- /// Tests that TryReadValue returns false when position is at buffer length.
+ /// Tests that TryWriteValue correctly encodes a small negative value.
///
[TestMethod]
-
- public void TryReadValue_PositionAtBufferLength_ReturnsFalse() {
+ public void TryWriteValue_SmallNegativeValue_WritesCorrectly() {
// Arrange
- ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
- int delta = 0;
- int position = buffer.Length;
+ Span buffer = new char[10];
+ int position = 0;
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
+ bool result = PolylineEncoding.TryWriteValue(-5, buffer, ref position);
// Assert
- Assert.IsFalse(result);
- Assert.AreEqual(0, delta);
+ Assert.IsTrue(result);
+ Assert.AreEqual(1, position);
+ Assert.AreEqual('H', buffer[0]); // zigzag(-5) = 9; 9 + 63 = 72 = 'H'
}
///
- /// Tests that TryReadValue returns false when position exceeds buffer length.
+ /// Tests that TryWriteValue writes at the correct non-zero starting position.
///
[TestMethod]
-
- public void TryReadValue_PositionExceedsBufferLength_ReturnsFalse() {
+ public void TryWriteValue_NonZeroStartPosition_WritesAtCorrectPosition() {
// Arrange
- ReadOnlyMemory buffer = "_p~iF~ps|U".AsMemory();
- int delta = 0;
- int position = buffer.Length + 1;
+ Span buffer = new char[20];
+ int position = 5;
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
+ bool result = PolylineEncoding.TryWriteValue(5, buffer, ref position);
// Assert
- Assert.IsFalse(result);
- Assert.AreEqual(0, delta);
+ Assert.IsTrue(result);
+ Assert.AreEqual(6, position);
+ Assert.AreEqual('I', buffer[5]);
}
///
- /// Tests that TryReadValue reads positive single-character value correctly.
+ /// Tests that TryWriteValue correctly encodes a large positive value.
///
[TestMethod]
-
- public void TryReadValue_PositiveSingleChar_ReadsValueAndReturnsTrue() {
+ public void TryWriteValue_LargePositiveValue_WritesCorrectly() {
// Arrange
- ReadOnlyMemory buffer = "?".AsMemory();
- int delta = 0;
+ Span buffer = new char[10];
int position = 0;
+ const int delta = 3778903;
+ int expectedSize = PolylineEncoding.GetRequiredBufferSize(delta);
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
+ bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
// Assert
Assert.IsTrue(result);
- Assert.AreEqual(0, delta);
- Assert.AreEqual(1, position);
+ Assert.AreEqual(expectedSize, position);
}
///
- /// Tests that TryReadValue reads multi-character positive value correctly.
+ /// Tests that TryWriteValue correctly encodes a large negative value.
///
[TestMethod]
-
- public void TryReadValue_PositiveMultiChar_ReadsValueAndReturnsTrue() {
+ public void TryWriteValue_LargeNegativeValue_WritesCorrectly() {
// Arrange
- Span buffer = stackalloc char[10];
- int writePosition = 0;
- const int expectedDelta = 3778903;
-
- // First write the value to get the correct encoding
- PolylineEncoding.TryWriteValue(expectedDelta, buffer, ref writePosition);
- ReadOnlyMemory readBuffer = new string(buffer[..writePosition]).AsMemory();
-
- int delta = 0;
+ Span buffer = new char[10];
int position = 0;
+ const int delta = -12241230;
+ int expectedSize = PolylineEncoding.GetRequiredBufferSize(delta);
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, readBuffer, ref position);
+ bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
// Assert
Assert.IsTrue(result);
- Assert.AreEqual(expectedDelta, delta);
- Assert.AreEqual(writePosition, position);
+ Assert.AreEqual(expectedSize, position);
}
+ #endregion
+
+ #region GetRequiredBufferSize Tests
+
///
- /// Tests that TryReadValue reads negative value correctly.
+ /// Tests that GetRequiredBufferSize returns the expected character count for the given delta.
///
[TestMethod]
-
- public void TryReadValue_NegativeValue_ReadsValueAndReturnsTrue() {
- // Arrange
- Span buffer = stackalloc char[10];
- int writePosition = 0;
- const int expectedDelta = -12241230;
-
- // First write the value to get the correct encoding
- PolylineEncoding.TryWriteValue(expectedDelta, buffer, ref writePosition);
- ReadOnlyMemory readBuffer = new string(buffer[..writePosition]).AsMemory();
-
- int delta = 0;
- int position = 0;
-
+ [DataRow(0, 1)]
+ [DataRow(1, 1)]
+ [DataRow(-1, 1)]
+ [DataRow(15, 1)]
+ [DataRow(16, 2)]
+ [DataRow(3778903, 5)]
+ [DataRow(-12241230, 5)]
+ public void GetRequiredBufferSize_Returns_Expected_Size(int delta, int expectedSize) {
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, readBuffer, ref position);
+ int size = PolylineEncoding.GetRequiredBufferSize(delta);
// Assert
- Assert.IsTrue(result);
- Assert.AreEqual(expectedDelta, delta);
- Assert.AreEqual(writePosition, position);
+ Assert.AreEqual(expectedSize, size);
}
///
- /// Tests that TryReadValue accumulates delta correctly.
+ /// Tests that GetRequiredBufferSize returns a valid size for the maximum positive integer.
///
[TestMethod]
-
- public void TryReadValue_WithExistingDelta_AccumulatesDelta() {
- // Arrange
- Span buffer = stackalloc char[10];
- int writePosition = 0;
- const int valueDelta = 3778903;
-
- // First write the value to get the correct encoding
- PolylineEncoding.TryWriteValue(valueDelta, buffer, ref writePosition);
- ReadOnlyMemory readBuffer = new string(buffer[..writePosition]).AsMemory();
-
- int delta = 100;
- int position = 0;
-
+ public void GetRequiredBufferSize_MaxInt_ReturnsCorrectSize() {
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, readBuffer, ref position);
+ int size = PolylineEncoding.GetRequiredBufferSize(int.MaxValue);
// Assert
- Assert.IsTrue(result);
- Assert.AreEqual(3779003, delta);
+ Assert.IsGreaterThan(0, size);
+ Assert.IsLessThanOrEqualTo(7, size); // Maximum size for int32
}
///
- /// Tests that TryReadValue reads multiple values from buffer.
+ /// Tests that GetRequiredBufferSize returns a valid size for the minimum negative integer.
///
[TestMethod]
-
- public void TryReadValue_MultipleValues_ReadsSequentially() {
- // Arrange
- Span buffer = stackalloc char[20];
- int writePosition = 0;
- const int expectedDelta1 = 3778903;
- const int expectedDelta2 = -12241230;
-
- // Write both values
- PolylineEncoding.TryWriteValue(expectedDelta1, buffer, ref writePosition);
- PolylineEncoding.TryWriteValue(expectedDelta2, buffer, ref writePosition);
- ReadOnlyMemory readBuffer = new string(buffer[..writePosition]).AsMemory();
-
- int delta1 = 0;
- int position = 0;
-
+ public void GetRequiredBufferSize_MinInt_ReturnsCorrectSize() {
// Act
- bool result1 = PolylineEncoding.TryReadValue(ref delta1, readBuffer, ref position);
- int delta2 = 0;
- bool result2 = PolylineEncoding.TryReadValue(ref delta2, readBuffer, ref position);
+ int size = PolylineEncoding.GetRequiredBufferSize(int.MinValue);
// Assert
- Assert.IsTrue(result1);
- Assert.AreEqual(expectedDelta1, delta1);
- Assert.IsTrue(result2);
- Assert.AreEqual(expectedDelta2, delta2);
- Assert.AreEqual(writePosition, position);
+ Assert.IsGreaterThan(0, size);
+ Assert.IsLessThanOrEqualTo(7, size); // Maximum size for int32
}
///
- /// Tests that TryReadValue returns false when buffer ends mid-value.
+ /// Tests that GetRequiredBufferSize is consistent with the actual bytes written by TryWriteValue.
///
[TestMethod]
-
- public void TryReadValue_BufferEndsMidValue_ReturnsFalse() {
+ public void GetRequiredBufferSize_ConsistentWithTryWriteValue_MatchesActualSize() {
// Arrange
- Span fullBuffer = stackalloc char[10];
- int writePosition = 0;
- PolylineEncoding.TryWriteValue(3778903, fullBuffer, ref writePosition);
-
- // Create incomplete buffer (truncate last character)
- ReadOnlyMemory buffer = new string(fullBuffer[..(writePosition - 1)]).AsMemory();
- int delta = 0;
+ const int delta = 3778903;
+ int expectedSize = PolylineEncoding.GetRequiredBufferSize(delta);
+ Span buffer = stackalloc char[expectedSize];
int position = 0;
// Act
- bool result = PolylineEncoding.TryReadValue(ref delta, buffer, ref position);
-
- // Assert
- Assert.IsFalse(result);
- Assert.AreEqual(buffer.Length, position);
- }
-
- ///
- /// Tests that TryReadValue reads value from middle of buffer.
- ///
- [TestMethod]
-
- public void TryReadValue_StartingFromMiddle_ReadsCorrectly() {
- // Arrange
- Span buffer = stackalloc char[20];
- int writePosition = 0;
- const int expectedDelta1 = 3778903;
- const int expectedDelta2 = -12241230;
-
- // Write both values
- PolylineEncoding.TryWriteValue(expectedDelta1, buffer, ref writePosition);
- int secondValuePosition = writePosition;
- PolylineEncoding.TryWriteValue(expectedDelta2, buffer, ref writePosition);
- ReadOnlyMemory readBuffer = new string(buffer[..writePosition]).AsMemory();
-
- int delta = 0;
- int position = secondValuePosition; // Start from second value
-
- // Act
- bool result = PolylineEncoding.TryReadValue(ref delta, readBuffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.AreEqual(expectedDelta2, delta);
- Assert.AreEqual(writePosition, position);
- }
-
- #endregion
-
- #region TryWriteValue Tests
-
- ///
- /// Tests that TryWriteValue returns false when buffer is too small.
- ///
- [TestMethod]
-
- public void TryWriteValue_BufferTooSmall_ReturnsFalse() {
- // Arrange
- Span buffer = stackalloc char[2];
- const int delta = 3778903;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsFalse(result);
- Assert.AreEqual(0, position);
- }
-
- ///
- /// Tests that TryWriteValue returns false when remaining buffer is too small.
- ///
- [TestMethod]
-
- public void TryWriteValue_RemainingBufferTooSmall_ReturnsFalse() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = 3778903;
- int position = 8; // Only 2 chars remaining, need 5
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsFalse(result);
- Assert.AreEqual(8, position);
- }
-
- ///
- /// Tests that TryWriteValue writes zero correctly.
- ///
- [TestMethod]
-
- public void TryWriteValue_ZeroValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = 0;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.AreEqual(1, position);
- Assert.AreEqual('?', buffer[0]);
- }
-
- ///
- /// Tests that TryWriteValue writes positive value correctly.
- ///
- [TestMethod]
-
- public void TryWriteValue_PositiveValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = 3778903;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.IsGreaterThan(0, position);
-
- // Verify by reading back
- ReadOnlyMemory readBuffer = new string(buffer[..position]).AsMemory();
- int readDelta = 0;
- int readPosition = 0;
- bool readResult = PolylineEncoding.TryReadValue(ref readDelta, readBuffer, ref readPosition);
-
- Assert.IsTrue(readResult);
- Assert.AreEqual(delta, readDelta);
- }
-
- ///
- /// Tests that TryWriteValue writes negative value correctly.
- ///
- [TestMethod]
-
- public void TryWriteValue_NegativeValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = -12241230;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.IsGreaterThan(0, position);
-
- // Verify by reading back
- ReadOnlyMemory readBuffer = new string(buffer[..position]).AsMemory();
- int readDelta = 0;
- int readPosition = 0;
- bool readResult = PolylineEncoding.TryReadValue(ref readDelta, readBuffer, ref readPosition);
-
- Assert.IsTrue(readResult);
- Assert.AreEqual(delta, readDelta);
- }
-
- ///
- /// Tests that TryWriteValue writes multiple values sequentially.
- ///
- [TestMethod]
-
- public void TryWriteValue_MultipleValues_WritesSequentially() {
- // Arrange
- Span buffer = stackalloc char[20];
- int position = 0;
- const int delta1 = 3778903;
- const int delta2 = -12241230;
-
- // Act
- bool result1 = PolylineEncoding.TryWriteValue(delta1, buffer, ref position);
- int midPosition = position;
- bool result2 = PolylineEncoding.TryWriteValue(delta2, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result1);
- Assert.IsTrue(result2);
- Assert.IsGreaterThan(midPosition, position);
-
- // Verify by reading back both values
- ReadOnlyMemory readBuffer = new string(buffer[..position]).AsMemory();
- int readDelta1 = 0;
- int readPosition = 0;
- PolylineEncoding.TryReadValue(ref readDelta1, readBuffer, ref readPosition);
- int readDelta2 = 0;
- PolylineEncoding.TryReadValue(ref readDelta2, readBuffer, ref readPosition);
-
- Assert.AreEqual(delta1, readDelta1);
- Assert.AreEqual(delta2, readDelta2);
- }
-
- ///
- /// Tests that TryWriteValue writes small positive value correctly.
- ///
- [TestMethod]
-
- public void TryWriteValue_SmallPositiveValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = 1;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.AreEqual(1, position);
-
- // Verify by reading back
- ReadOnlyMemory readBuffer = new string(buffer[..position]).AsMemory();
- int readDelta = 0;
- int readPosition = 0;
- PolylineEncoding.TryReadValue(ref readDelta, readBuffer, ref readPosition);
- Assert.AreEqual(delta, readDelta);
- }
-
- ///
- /// Tests that TryWriteValue writes small negative value correctly.
- ///
- [TestMethod]
-
- public void TryWriteValue_SmallNegativeValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = -1;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.AreEqual(1, position);
-
- // Verify by reading back
- ReadOnlyMemory readBuffer = new string(buffer[..position]).AsMemory();
- int readDelta = 0;
- int readPosition = 0;
- PolylineEncoding.TryReadValue(ref readDelta, readBuffer, ref readPosition);
- Assert.AreEqual(delta, readDelta);
- }
-
- ///
- /// Tests that TryWriteValue starts writing at specified position.
- ///
- [TestMethod]
-
- public void TryWriteValue_NonZeroStartPosition_WritesAtCorrectPosition() {
- // Arrange
- Span buffer = stackalloc char[10];
- buffer[0] = 'X';
- buffer[1] = 'Y';
- const int delta = 0;
- int position = 2;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.AreEqual(3, position);
- Assert.AreEqual('X', buffer[0]);
- Assert.AreEqual('Y', buffer[1]);
- Assert.AreEqual('?', buffer[2]);
- }
-
- ///
- /// Tests that TryWriteValue handles large positive values.
- ///
- [TestMethod]
-
- public void TryWriteValue_LargePositiveValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = int.MaxValue / 2;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.IsGreaterThan(0, position);
- }
-
- ///
- /// Tests that TryWriteValue handles large negative values.
- ///
- [TestMethod]
-
- public void TryWriteValue_LargeNegativeValue_WritesCorrectly() {
- // Arrange
- Span buffer = stackalloc char[10];
- const int delta = int.MinValue / 2;
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
-
- // Assert
- Assert.IsTrue(result);
- Assert.IsGreaterThan(0, position);
- }
-
- #endregion
-
- #region GetRequiredBufferSize Tests
-
- ///
- /// Tests that GetRequiredBufferSize returns 1 for zero value.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_ZeroValue_ReturnsOne() {
- // Arrange
- const int delta = 0;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(1, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns correct size for small positive value.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_SmallPositiveValue_ReturnsOne() {
- // Arrange
- const int delta = 1;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(1, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns correct size for small negative value.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_SmallNegativeValue_ReturnsOne() {
- // Arrange
- const int delta = -1;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(1, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns correct size for large positive value.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_LargePositiveValue_ReturnsCorrectSize() {
- // Arrange
- const int delta = 3778903;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(5, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns correct size for large negative value.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_LargeNegativeValue_ReturnsCorrectSize() {
- // Arrange
- const int delta = -12241230;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(5, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize handles maximum positive integer.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_MaxInt_ReturnsCorrectSize() {
- // Arrange
- const int delta = int.MaxValue;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.IsGreaterThan(0, size);
- Assert.IsLessThanOrEqualTo(7, size); // Maximum size for int32
- }
-
- ///
- /// Tests that GetRequiredBufferSize handles minimum negative integer.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_MinInt_ReturnsCorrectSize() {
- // Arrange
- const int delta = int.MinValue;
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.IsGreaterThan(0, size);
- Assert.IsLessThanOrEqualTo(7, size); // Maximum size for int32
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns consistent size with TryWriteValue.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_ConsistentWithTryWriteValue_MatchesActualSize() {
- // Arrange
- const int delta = 3778903;
- int expectedSize = PolylineEncoding.GetRequiredBufferSize(delta);
- Span buffer = stackalloc char[expectedSize];
- int position = 0;
-
- // Act
- bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
+ bool result = PolylineEncoding.TryWriteValue(delta, buffer, ref position);
// Assert
Assert.IsTrue(result);
@@ -1017,10 +545,9 @@ public void GetRequiredBufferSize_ConsistentWithTryWriteValue_MatchesActualSize(
}
///
- /// Tests that GetRequiredBufferSize with undersized buffer causes TryWriteValue to fail.
+ /// Tests that an undersized buffer causes TryWriteValue to fail.
///
[TestMethod]
-
public void GetRequiredBufferSize_UndersizedBuffer_CausesTryWriteValueToFail() {
// Arrange
const int delta = 3778903;
@@ -1036,38 +563,6 @@ public void GetRequiredBufferSize_UndersizedBuffer_CausesTryWriteValueToFail() {
Assert.AreEqual(0, position);
}
- ///
- /// Tests that GetRequiredBufferSize returns correct size for boundary value 15.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_BoundaryValue15_ReturnsOne() {
- // Arrange
- const int delta = 15; // 15 << 1 = 30, which is less than 32 (Space)
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(1, size);
- }
-
- ///
- /// Tests that GetRequiredBufferSize returns correct size for boundary value 16.
- ///
- [TestMethod]
-
- public void GetRequiredBufferSize_BoundaryValue16_ReturnsTwo() {
- // Arrange
- const int delta = 16; // 16 << 1 = 32, which equals Space
-
- // Act
- int size = PolylineEncoding.GetRequiredBufferSize(delta);
-
- // Assert
- Assert.AreEqual(2, size);
- }
-
#endregion
#region ValidateFormat Tests
@@ -1076,65 +571,45 @@ public void GetRequiredBufferSize_BoundaryValue16_ReturnsTwo() {
/// Tests that ValidateFormat succeeds with a valid polyline.
///
[TestMethod]
-
public void ValidateFormat_ValidPolyline_DoesNotThrow() {
- // Arrange
- const string polyline = "_p~iF~ps|U_ulLnnqC_mqNvxq`@";
-
// Act & Assert
- PolylineEncoding.ValidateFormat(polyline);
+ PolylineEncoding.ValidateFormat("_p~iF~ps|U_ulLnnqC_mqNvxq`@");
}
///
- /// Tests that ValidateFormat throws when polyline contains invalid character.
+ /// Tests that ValidateFormat throws when polyline contains an invalid character.
///
[TestMethod]
-
public void ValidateFormat_InvalidCharacter_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "_p~iF!ps|U";
-
// Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat(polyline));
+ Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat("_p~iF!ps|U"));
}
///
/// Tests that ValidateFormat throws when polyline has invalid block structure.
///
[TestMethod]
-
public void ValidateFormat_InvalidBlockStructure_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "________"; // All continuation characters, no block terminator
-
// Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat(polyline));
+ Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat("________")); // all continuation chars, no terminator
}
///
- /// Tests that ValidateFormat succeeds with empty polyline ending with terminator.
+ /// Tests that ValidateFormat succeeds with a single terminator character.
///
[TestMethod]
-
- public void ValidateFormat_EmptyPolylineWithTerminator_DoesNotThrow() {
- // Arrange
- const string polyline = "?"; // Single terminator character
-
+ public void ValidateFormat_SingleTerminator_DoesNotThrow() {
// Act & Assert
- PolylineEncoding.ValidateFormat(polyline);
+ PolylineEncoding.ValidateFormat("?");
}
///
- /// Tests that ValidateFormat throws when block is too long.
+ /// Tests that ValidateFormat throws when a block exceeds maximum length.
///
[TestMethod]
-
public void ValidateFormat_BlockTooLong_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "________?"; // 8 characters in block (max is 7)
-
// Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat(polyline));
+ Assert.ThrowsExactly(() => PolylineEncoding.ValidateFormat("________?")); // 8-char block (max is 7)
}
#endregion
@@ -1142,147 +617,30 @@ public void ValidateFormat_BlockTooLong_ThrowsInvalidPolylineException() {
#region ValidateCharRange Tests
///
- /// Tests that ValidateCharRange succeeds with all valid characters.
- ///
- [TestMethod]
-
- public void ValidateCharRange_AllValidCharacters_DoesNotThrow() {
- // Arrange
- const string polyline = "_p~iF~ps|U_ulLnnqC_mqNvxq`@";
-
- // Act & Assert
- PolylineEncoding.ValidateCharRange(polyline);
- }
-
- ///
- /// Tests that ValidateCharRange succeeds with minimum valid character.
- ///
- [TestMethod]
-
- public void ValidateCharRange_MinimumValidCharacter_DoesNotThrow() {
- // Arrange
- const string polyline = "?"; // ASCII 63 (Min)
-
- // Act & Assert
- PolylineEncoding.ValidateCharRange(polyline);
- }
-
- ///
- /// Tests that ValidateCharRange succeeds with maximum valid character.
- ///
- [TestMethod]
-
- public void ValidateCharRange_MaximumValidCharacter_DoesNotThrow() {
- // Arrange
- const string polyline = "~"; // ASCII 126 (Max)
-
- // Act & Assert
- PolylineEncoding.ValidateCharRange(polyline);
- }
-
- ///
- /// Tests that ValidateCharRange throws when character is below minimum.
- ///
- [TestMethod]
-
- public void ValidateCharRange_CharacterBelowMinimum_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = ">"; // ASCII 62 (below Min of 63)
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
- }
-
- ///
- /// Tests that ValidateCharRange throws when character is above maximum.
- ///
- [TestMethod]
-
- public void ValidateCharRange_CharacterAboveMaximum_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "\u007F"; // ASCII 127 (above Max of 126)
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
- }
-
- ///
- /// Tests that ValidateCharRange throws when invalid character is in middle of valid polyline.
- ///
- [TestMethod]
-
- public void ValidateCharRange_InvalidCharacterInMiddle_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "_p~iF!ps|U"; // '!' is ASCII 33 (below Min)
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
- }
-
- ///
- /// Tests that ValidateCharRange succeeds with empty polyline.
- ///
- [TestMethod]
-
- public void ValidateCharRange_EmptyPolyline_DoesNotThrow() {
- // Arrange
- const string polyline = "";
-
- // Act & Assert
- PolylineEncoding.ValidateCharRange(polyline);
- }
-
- ///
- /// Tests that ValidateCharRange throws when invalid character is at end of polyline.
+ /// Tests that ValidateCharRange succeeds for valid polyline strings.
///
[TestMethod]
-
- public void ValidateCharRange_InvalidCharacterAtEnd_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "_p~iF~ps|U!"; // '!' at end
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
- }
-
- ///
- /// Tests that ValidateCharRange succeeds with long polyline to trigger SIMD path.
- ///
- [TestMethod]
-
- public void ValidateCharRange_LongPolyline_DoesNotThrow() {
- // Arrange
- // Create a string long enough to trigger SIMD vectorization (typically 8-16 chars depending on platform)
- const string polyline = "????????????????????????????????";
-
+ [DataRow("_p~iF~ps|U_ulLnnqC_mqNvxq`@")]
+ [DataRow("?")] // min valid char (ASCII 63)
+ [DataRow("~")] // max valid char (ASCII 126)
+ [DataRow("")] // empty is valid
+ [DataRow("????????????????????????????????")] // long string to trigger SIMD path
+ public void ValidateCharRange_With_Valid_Polyline_Does_Not_Throw(string polyline) {
// Act & Assert
PolylineEncoding.ValidateCharRange(polyline);
}
///
- /// Tests that ValidateCharRange throws when invalid character is in SIMD-processed section.
- ///
- [TestMethod]
-
- public void ValidateCharRange_InvalidCharacterInSimdSection_ThrowsInvalidPolylineException() {
- // Arrange
- // Create a long string with invalid character to trigger SIMD path detection
- const string polyline = "????????!???????????????????????";
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
- }
-
- ///
- /// Tests that ValidateCharRange throws when invalid character is in scalar remainder section.
+ /// Tests that ValidateCharRange throws for polylines containing invalid characters.
///
[TestMethod]
-
- public void ValidateCharRange_InvalidCharacterInScalarRemainder_ThrowsInvalidPolylineException() {
- // Arrange
- // Create a string that leaves remainder after SIMD processing
- const string polyline = "????????????????\u007F"; // Valid chars + one invalid at end
-
+ [DataRow(">")] // ASCII 62 (below min of 63)
+ [DataRow("\u007F")] // ASCII 127 (above max of 126)
+ [DataRow("_p~iF!ps|U")] // '!' in middle (ASCII 33)
+ [DataRow("_p~iF~ps|U!")] // '!' at end
+ [DataRow("????????!???????????????????????")] // invalid in SIMD section
+ [DataRow("????????????????\u007F")] // invalid in scalar remainder
+ public void ValidateCharRange_With_Invalid_Character_Throws_InvalidPolylineException(string polyline) {
// Act & Assert
Assert.ThrowsExactly(() => PolylineEncoding.ValidateCharRange(polyline));
}
@@ -1292,134 +650,32 @@ public void ValidateCharRange_InvalidCharacterInScalarRemainder_ThrowsInvalidPol
#region ValidateBlockLength Tests
///
- /// Tests that ValidateBlockLength succeeds with single block.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_SingleBlock_DoesNotThrow() {
- // Arrange
- const string polyline = "?"; // Single terminator
-
- // Act & Assert
- PolylineEncoding.ValidateBlockLength(polyline);
- }
-
- ///
- /// Tests that ValidateBlockLength succeeds with multiple blocks.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_MultipleBlocks_DoesNotThrow() {
- // Arrange
- const string polyline = "_p~iF~ps|U"; // Multiple blocks
-
- // Act & Assert
- PolylineEncoding.ValidateBlockLength(polyline);
- }
-
- ///
- /// Tests that ValidateBlockLength succeeds with maximum length block.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_MaximumLengthBlock_DoesNotThrow() {
- // Arrange
- const string polyline = "______?"; // 6 continuation chars + terminator (max length is 7 total)
-
- // Act & Assert
- PolylineEncoding.ValidateBlockLength(polyline);
- }
-
- ///
- /// Tests that ValidateBlockLength throws when block exceeds maximum length.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_BlockExceedsMaximumLength_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "________?"; // 8 chars in block (exceeds max of 7)
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateBlockLength(polyline));
- }
-
- ///
- /// Tests that ValidateBlockLength throws when polyline does not end with block terminator.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_NoBlockTerminator_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "________"; // All continuation characters, no terminator
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateBlockLength(polyline));
- }
-
- ///
- /// Tests that ValidateBlockLength throws when empty polyline has no block terminator.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_EmptyPolyline_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "";
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateBlockLength(polyline));
- }
-
- ///
- /// Tests that ValidateBlockLength throws when block is too long in middle of polyline.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_TooLongBlockInMiddle_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "?________?"; // Valid block, then too-long block
-
- // Act & Assert
- Assert.ThrowsExactly(() => PolylineEncoding.ValidateBlockLength(polyline));
- }
-
- ///
- /// Tests that ValidateBlockLength succeeds with consecutive terminators.
+ /// Tests that ValidateBlockLength succeeds for valid block structures.
///
[TestMethod]
-
- public void ValidateBlockLength_ConsecutiveTerminators_DoesNotThrow() {
- // Arrange
- const string polyline = "??"; // Two consecutive terminators (two 1-char blocks)
-
- // Act & Assert
- PolylineEncoding.ValidateBlockLength(polyline);
- }
-
- ///
- /// Tests that ValidateBlockLength succeeds with mixed block lengths.
- ///
- [TestMethod]
-
- public void ValidateBlockLength_MixedBlockLengths_DoesNotThrow() {
- // Arrange
- const string polyline = "?__?_____?"; // Blocks of length 1, 2, and 5
-
+ [DataRow("?")] // single terminator
+ [DataRow("_p~iF~ps|U")] // multiple blocks
+ [DataRow("______?")] // 6 continuation chars + terminator (maximum block length)
+ [DataRow("??")] // consecutive terminators
+ [DataRow("?__?_____?")] // mixed block lengths
+ public void ValidateBlockLength_With_Valid_Polyline_Does_Not_Throw(string polyline) {
// Act & Assert
PolylineEncoding.ValidateBlockLength(polyline);
}
///
- /// Tests that ValidateBlockLength throws when second-to-last block is too long.
+ /// Tests that ValidateBlockLength throws for invalid block structures.
///
[TestMethod]
-
- public void ValidateBlockLength_SecondToLastBlockTooLong_ThrowsInvalidPolylineException() {
- // Arrange
- const string polyline = "________?_?"; // First block is 8 chars (too long)
-
+ [DataRow("________?")] // 8-char block (exceeds max of 7)
+ [DataRow("________")] // all continuation chars, no terminator
+ [DataRow("")] // empty polyline has no terminator
+ [DataRow("?________?")] // valid block then too-long block
+ [DataRow("________?_?")] // first block too long
+ public void ValidateBlockLength_With_Invalid_Polyline_Throws_InvalidPolylineException(string polyline) {
// Act & Assert
Assert.ThrowsExactly(() => PolylineEncoding.ValidateBlockLength(polyline));
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
index 85d14b2b..d3d83b9e 100644
--- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
@@ -23,11 +23,11 @@ internal static class RandomValueProvider {
private static readonly PolylineEncoder _encoder = new();
///
- /// Gets a collection of random instances of the specified count.
+ /// Gets a collection of random latitude/longitude tuples of the specified count.
/// The same collection is cached and reused for the same count value.
///
/// The number of coordinates to generate.
- /// An enumerable collection of random objects.
+ /// An enumerable collection of random latitude/longitude tuples.
public static IEnumerable<(double Latitude, double Longitude)> GetCoordinates(int count) {
var entry = GetCaheEntry(count);
@@ -39,11 +39,11 @@ internal static class RandomValueProvider {
}
///
- /// Gets a representing the encoded polyline for a random collection of coordinates of the specified count.
+ /// Gets the encoded polyline string for a random collection of coordinates of the specified count.
/// The same polyline is cached and reused for the same count value.
///
/// The number of coordinates to generate and encode.
- /// A representing the encoded polyline.
+ /// A representing the encoded polyline.
public static string GetPolyline(int count) {
var entry = GetCaheEntry(count);
diff --git a/utilities/PolylineAlgorithm.Utility/StaticValueProvider.cs b/utilities/PolylineAlgorithm.Utility/StaticValueProvider.cs
index 4a07f55a..d6d2813c 100644
--- a/utilities/PolylineAlgorithm.Utility/StaticValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/StaticValueProvider.cs
@@ -18,7 +18,7 @@ internal static class Valid {
private const string Polyline = "???_gsia@_cidP??~fsia@?~fsia@~bidP?~bidP??_gsia@";
///
- /// A predefined collection of instances representing a closed path around the globe.
+ /// A predefined collection of latitude/longitude tuples representing a closed path around the globe.
///
private static readonly IEnumerable<(double Latitude, double Longitude)> _coordinates = [
new (0, 0),
@@ -32,17 +32,17 @@ internal static class Valid {
];
///
- /// Gets the predefined collection of instances.
+ /// Gets the predefined collection of latitude/longitude tuples.
///
- /// An containing the static coordinates.
+ /// An of latitude/longitude tuples containing the static coordinates.
public static IEnumerable<(double Latitude, double Longitude)> GetCoordinates() {
return _coordinates;
}
///
- /// Gets the predefined instance.
+ /// Gets the predefined encoded polyline string.
///
- /// The static value.
+ /// The static encoded polyline string.
public static string GetPolyline() {
return Polyline;
}