Skip to content

Commit bd09d87

Browse files
Copilotpetesramek
andauthored
test: consolidate and standardize test suite on develop/1.0 (#151)
- [x] Fix stale XML comments and restore PolylineEncoderBenchmark (previous commit) - [x] Add `AbstractPolylineEncoderTests.cs` — constructor paths, Encode valid/empty/cancelled, heap-alloc path, Options property - [x] Add `PolylineEncoderExtensionsTests.cs` — List and Array overloads (null encoder, null coordinates, valid) - [x] Expand `AbstractPolylineDecoderTests.cs` — valid decode, options constructor null check, Options property, custom options, cancellation - [x] Add `InvalidPolylineExceptionTests.cs` — default constructor and message+innerException constructor - [x] All 214 tests pass, build clean, CodeQL: 0 alerts --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com>
1 parent 663fa25 commit bd09d87

18 files changed

Lines changed: 974 additions & 1690 deletions

benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
<ItemGroup>
1818
<Compile Remove="C:\Users\petesramek\.nuget\packages\microsoft.visualstudio.diagnosticshub.benchmarkdotnetdiagnosers\18.3.36812.1\contentFiles\cs\any\BenchmarkProfilerAgentConfig.g.cs" />
19+
<Compile Remove="C:\Users\petesramek\.nuget\packages\microsoft.visualstudio.diagnosticshub.benchmarkdotnetdiagnosers\18.6.37110.2\contentFiles\cs\any\BenchmarkProfilerAgentConfig.g.cs" />
1920
</ItemGroup>
2021

2122
<ItemGroup>
Lines changed: 92 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,92 @@
1-
////
2-
//// Copyright © Pete Sramek. All rights reserved.
3-
//// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4-
////
5-
6-
//namespace PolylineAlgorithm.Benchmarks;
7-
8-
//using BenchmarkDotNet.Attributes;
9-
//using BenchmarkDotNet.Engines;
10-
//using PolylineAlgorithm.Utility;
11-
//using System.Collections.Generic;
12-
13-
///// <summary>
14-
///// Benchmarks for <see cref="PolylineEncoder"/>.
15-
///// </summary>
16-
//public class PolylineEncoderBenchmark {
17-
// private readonly Consumer _consumer = new();
18-
19-
// /// <summary>
20-
// /// Number of coordinates for benchmarks.
21-
// /// </summary>
22-
// [Params(1, 100, 1_000)]
23-
// public int CoordinatesCount { get; set; }
24-
25-
//#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.
26-
// /// <summary>
27-
// /// Coordinates as list.
28-
// /// </summary>
29-
// public List<(double Latitude, double Longitude)> List { get; private set; }
30-
31-
// /// <summary>
32-
// /// Coordinates as array.
33-
// /// </summary>
34-
// public (double Latitude, double Longitude)[] Array { get; private set; }
35-
36-
// /// <summary>
37-
// /// Coordinates as read-only memory.
38-
// /// </summary>
39-
// public ReadOnlyMemory<(double Latitude, double Longitude)> Memory { get; private set; }
40-
41-
//#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.
42-
43-
// /// <summary>
44-
// /// Polyline encoder instance.
45-
// /// </summary>
46-
// private readonly StringPolylineEncoder _stringEncoder = new();
47-
48-
// /// <summary>
49-
// /// Polyline encoder instance.
50-
// /// </summary>
51-
// private readonly CharArrayPolylineEncoder _charArrayEncoder = new();
52-
53-
// /// <summary>
54-
// /// Polyline encoder instance.
55-
// /// </summary>
56-
// private readonly MemoryPolylineEncoder _memoryEncoder = new();
57-
58-
// /// <summary>
59-
// /// Sets up benchmark data.
60-
// /// </summary>
61-
// [GlobalSetup]
62-
// public void SetupData() {
63-
// List = [.. RandomValueProvider.GetCoordinates(CoordinatesCount).Select(c => (c.Latitude, c.Longitude))];
64-
// Array = [.. List];
65-
// Memory = Array.AsMemory();
66-
// }
67-
68-
// /// <summary>
69-
// /// Benchmark: encode coordinates from span.
70-
// /// </summary>
71-
// /// <returns>Encoded polyline.</returns>
72-
// [Benchmark]
73-
// public void PolylineEncoder_Encode_Span() {
74-
// var polyline = _encoder
75-
// .Encode(Memory.Span!);
76-
77-
// _consumer.Consume(polyline);
78-
// }
79-
80-
// /// <summary>
81-
// /// Benchmark: encode coordinates from array.
82-
// /// </summary>
83-
// /// <returns>Encoded polyline.</returns>
84-
// [Benchmark]
85-
// public void PolylineEncoder_Encode_Array() {
86-
// var polyline = _encoder
87-
// .Encode(Array!);
88-
89-
// _consumer.Consume(polyline);
90-
// }
91-
92-
// /// <summary>
93-
// /// Benchmark: encode coordinates from list.
94-
// /// </summary>
95-
// /// <returns>Encoded polyline.</returns>
96-
// [Benchmark]
97-
// public void PolylineEncoder_Encode_List() {
98-
// var polyline = _encoder
99-
// .Encode(List!);
100-
101-
// _consumer.Consume(polyline);
102-
// }
103-
//}
1+
//
2+
// Copyright © Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm.Benchmarks;
7+
8+
using BenchmarkDotNet.Attributes;
9+
using BenchmarkDotNet.Engines;
10+
using PolylineAlgorithm.Abstraction;
11+
using PolylineAlgorithm.Extensions;
12+
using PolylineAlgorithm.Utility;
13+
using System.Collections.Generic;
14+
15+
/// <summary>
16+
/// Benchmarks for <see cref="AbstractPolylineEncoder{TCoordinate, TPolyline}"/>.
17+
/// </summary>
18+
public class PolylineEncoderBenchmark {
19+
private readonly Consumer _consumer = new();
20+
21+
/// <summary>
22+
/// Number of coordinates for benchmarks.
23+
/// </summary>
24+
[Params(1, 100, 1_000)]
25+
public int CoordinatesCount { get; set; }
26+
27+
#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.
28+
/// <summary>
29+
/// Coordinates as list.
30+
/// </summary>
31+
public List<(double Latitude, double Longitude)> List { get; private set; }
32+
33+
/// <summary>
34+
/// Coordinates as array.
35+
/// </summary>
36+
public (double Latitude, double Longitude)[] Array { get; private set; }
37+
38+
/// <summary>
39+
/// Coordinates as read-only memory.
40+
/// </summary>
41+
public ReadOnlyMemory<(double Latitude, double Longitude)> Memory { get; private set; }
42+
43+
#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.
44+
45+
/// <summary>
46+
/// Polyline encoder instance.
47+
/// </summary>
48+
private readonly StringPolylineEncoder _encoder = new();
49+
50+
/// <summary>
51+
/// Sets up benchmark data.
52+
/// </summary>
53+
[GlobalSetup]
54+
public void SetupData() {
55+
List = [.. RandomValueProvider.GetCoordinates(CoordinatesCount)];
56+
Array = [.. List];
57+
Memory = Array.AsMemory();
58+
}
59+
60+
/// <summary>
61+
/// Benchmark: encode coordinates from span.
62+
/// </summary>
63+
[Benchmark]
64+
public void PolylineEncoder_Encode_Span() {
65+
var polyline = _encoder.Encode(Memory.Span);
66+
_consumer.Consume(polyline);
67+
}
68+
69+
/// <summary>
70+
/// Benchmark: encode coordinates from array.
71+
/// </summary>
72+
[Benchmark]
73+
public void PolylineEncoder_Encode_Array() {
74+
var polyline = _encoder.Encode(Array);
75+
_consumer.Consume(polyline);
76+
}
77+
78+
/// <summary>
79+
/// Benchmark: encode coordinates from list.
80+
/// </summary>
81+
[Benchmark]
82+
public void PolylineEncoder_Encode_List() {
83+
var polyline = _encoder.Encode(List);
84+
_consumer.Consume(polyline);
85+
}
86+
87+
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
88+
protected override string CreatePolyline(ReadOnlyMemory<char> polyline) => polyline.ToString();
89+
protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
90+
protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
91+
}
92+
}

src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
//
55

66
using Microsoft.Extensions.Logging;
7-
using PolylineAlgorithm.Diagnostics;
87
using PolylineAlgorithm.Internal;
98
using PolylineAlgorithm.Internal.Diagnostics;
10-
using PolylineAlgorithm.Internal.Diagnostics;
119
using System.Runtime.CompilerServices;
1210

1311
namespace PolylineAlgorithm.Abstraction {
@@ -54,27 +52,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
5452
/// </summary>
5553
public PolylineEncodingOptions Options { get; }
5654

57-
/// <summary>
58-
/// Decodes an encoded <typeparamref name="TPolyline"/> into a sequence of <typeparamref name="TCoordinate"/> instances.
59-
/// </summary>
60-
/// <param name="polyline">
61-
/// The <typeparamref name="TPolyline"/> instance containing the encoded polyline string to decode.
62-
/// </param>
63-
/// <returns>
64-
/// An <see cref="IEnumerable{T}"/> of <typeparamref name="TCoordinate"/> representing the decoded latitude and longitude pairs.
65-
/// </returns>
66-
/// <exception cref="ArgumentNullException">
67-
/// Thrown when <paramref name="polyline"/> is <see langword="null"/>.
68-
/// </exception>
69-
/// <exception cref="ArgumentException">
70-
/// Thrown when <paramref name="polyline"/> is empty.
71-
/// </exception>
72-
/// <exception cref="InvalidPolylineException">
73-
/// Thrown when the polyline format is invalid or malformed at a specific position.
74-
/// </exception>
75-
public IEnumerable<TCoordinate> Decode(TPolyline polyline)
76-
=> Decode(polyline, CancellationToken.None);
77-
7855
/// <summary>
7956
/// Decodes an encoded <typeparamref name="TPolyline"/> into a sequence of <typeparamref name="TCoordinate"/> instances,
8057
/// with support for cancellation.
@@ -100,7 +77,7 @@ public IEnumerable<TCoordinate> Decode(TPolyline polyline)
10077
/// <exception cref="OperationCanceledException">
10178
/// Thrown when <paramref name="cancellationToken"/> is canceled during decoding.
10279
/// </exception>
103-
public IEnumerable<TCoordinate> Decode(TPolyline polyline, CancellationToken cancellationToken) {
80+
public IEnumerable<TCoordinate> Decode(TPolyline polyline, CancellationToken cancellationToken = default) {
10481
const string OperationName = nameof(Decode);
10582

10683
_logger?.LogOperationStartedDebug(OperationName);

src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ namespace PolylineAlgorithm.Abstraction;
99
using PolylineAlgorithm;
1010
using PolylineAlgorithm.Internal;
1111
using PolylineAlgorithm.Internal.Diagnostics;
12-
using PolylineAlgorithm.Internal.Diagnostics;
1312
using System;
1413
using System.Buffers;
1514
using System.Diagnostics;
1615
using System.Runtime.CompilerServices;
16+
using System.Threading;
1717

1818
/// <summary>
1919
/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
@@ -61,6 +61,9 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
6161
/// <param name="coordinates">
6262
/// The collection of <typeparamref name="TCoordinate"/> objects to encode.
6363
/// </param>
64+
/// <param name="cancellationToken">
65+
/// A <see cref="CancellationToken"/> that can be used to cancel the encoding operation.
66+
/// </param>
6467
/// <returns>
6568
/// An instance of <typeparamref name="TPolyline"/> representing the encoded coordinates.
6669
/// </returns>
@@ -74,7 +77,7 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
7477
/// Thrown when the internal encoding buffer cannot accommodate the encoded value.
7578
/// </exception>
7679
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")]
77-
public TPolyline Encode(ReadOnlySpan<TCoordinate> coordinates) {
80+
public TPolyline Encode(ReadOnlySpan<TCoordinate> coordinates, CancellationToken cancellationToken = default) {
7881
const string OperationName = nameof(Encode);
7982

8083
_logger
@@ -98,6 +101,7 @@ public TPolyline Encode(ReadOnlySpan<TCoordinate> coordinates) {
98101

99102
try {
100103
for (var i = 0; i < coordinates.Length; i++) {
104+
cancellationToken.ThrowIfCancellationRequested();
101105

102106
delta
103107
.Next(
@@ -150,7 +154,7 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan<TCoordinate> coordinates,
150154
logger
151155
.LogEmptyArgumentWarning(nameof(coordinates));
152156

153-
ExceptionGuard.ThrwoArgumentCannotBeEmptyEnumerationMessage(nameof(coordinates));
157+
ExceptionGuard.ThrowArgumentCannotBeEmptyEnumerationMessage(nameof(coordinates));
154158
}
155159
}
156160
}

src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs

Lines changed: 0 additions & 86 deletions
This file was deleted.

0 commit comments

Comments
 (0)