Skip to content

Commit 0b917a5

Browse files
committed
Close remaining final-review gaps
Root cause: the provider-modernization branch still had a small set of follow-up inconsistencies around nullable annotations, Bing response handling, and the shared HttpClient test helper after the larger transport and serializer refactors.
1 parent 47c2c60 commit 0b917a5

5 files changed

Lines changed: 33 additions & 29 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ Before marking work complete, verify:
132132
- **xUnit** as the primary testing framework
133133
- Tests cover all providers with shared base patterns (`GeocoderTest`, `AsyncGeocoderTest`)
134134
- Provider-specific tests extend base test classes
135+
- For `HttpClient` failure-path tests, prefer `TestHttpMessageHandler.CreateResponse(...)` or `CreateResponseAsync(...)` instead of constructing `HttpResponseMessage` inline inside handler lambdas
135136

136137
### Running Tests
137138

src/Geocoding.Core/Extensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public static bool IsNullOrEmpty<T>([NotNullWhen(false)] this ICollection<T>? co
2727
/// <typeparam name="T">The enumerable item type.</typeparam>
2828
/// <param name="self">The source enumerable.</param>
2929
/// <param name="actor">The action to execute for each item.</param>
30-
public static void ForEach<T>(this IEnumerable<T> self, Action<T> actor)
30+
public static void ForEach<T>(this IEnumerable<T>? self, Action<T> actor)
3131
{
3232
if (actor is null)
3333
throw new ArgumentNullException(nameof(actor));
@@ -66,7 +66,7 @@ private static JsonSerializerOptions CreateJsonOptions()
6666
/// </summary>
6767
/// <param name="o">The object to serialize.</param>
6868
/// <returns>The JSON payload, or an empty string when the input is null.</returns>
69-
public static string ToJSON(this object o)
69+
public static string ToJSON(this object? o)
7070
{
7171
if (o is null)
7272
return String.Empty;

src/Geocoding.MapQuest/MapQuestGeocoder.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,11 @@ public MapQuestGeocoder(string key)
4949

5050
private IEnumerable<Address> HandleSingleResponse(MapQuestResponse res)
5151
{
52-
if (res is not null && !res.Results.IsNullOrEmpty())
53-
{
54-
return HandleSingleResponse(from r in res.Results.OfType<MapQuestResult>()
55-
from l in r.Locations?.OfType<MapQuestLocation>() ?? Enumerable.Empty<MapQuestLocation>()
56-
select l);
57-
}
58-
else
59-
return Array.Empty<Address>();
52+
return res is not null && !res.Results.IsNullOrEmpty()
53+
? HandleSingleResponse(from r in res.Results.OfType<MapQuestResult>()
54+
from l in r.Locations?.OfType<MapQuestLocation>() ?? Enumerable.Empty<MapQuestLocation>()
55+
select l)
56+
: Array.Empty<Address>();
6057
}
6158

6259
private IEnumerable<Address> HandleSingleResponse(IEnumerable<MapQuestLocation> locs)

src/Geocoding.Microsoft/BingMapsGeocoder.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private string GetQueryUrl(string address)
7575
first = AppendParameter(parameters, address, Query, first);
7676
first = AppendGlobalParameters(parameters, first);
7777

78-
return String.Format(FormattedQuery, parameters.ToString(), _bingKey);
78+
return String.Format(FormattedQuery, parameters, _bingKey);
7979
}
8080

8181
private string GetQueryUrl(string street, string city, string state, string postalCode, string country)
@@ -89,7 +89,7 @@ private string GetQueryUrl(string street, string city, string state, string post
8989
first = AppendParameter(parameters, street, Address, first);
9090
first = AppendGlobalParameters(parameters, first);
9191

92-
return String.Format(FormattedQuery, parameters.ToString(), _bingKey);
92+
return String.Format(FormattedQuery, parameters, _bingKey);
9393
}
9494

9595
private string GetQueryUrl(double latitude, double longitude)
@@ -249,15 +249,11 @@ protected virtual IEnumerable<BingAddress> ParseResponse(Json.Response response)
249249
if (resourceSet is null)
250250
continue;
251251

252-
var locations = resourceSet.Locations;
253-
if (locations.IsNullOrEmpty())
254-
continue;
255-
256-
foreach (var location in locations.Where(location => location?.Point?.Coordinates is { Length: >= 2 }
252+
foreach (var location in resourceSet.Resources.OfType<Json.Location>().Where(location => location.Point?.Coordinates is { Length: >= 2 }
257253
&& location.Address is not null
258254
&& !String.IsNullOrWhiteSpace(location.Address.FormattedAddress)))
259255
{
260-
var coordinates = location!.Point!.Coordinates!;
256+
var coordinates = location.Point!.Coordinates!;
261257

262258
if (!Enum.TryParse(location.EntityType, out EntityType entityType))
263259
entityType = EntityType.Unknown;
@@ -309,8 +305,8 @@ protected virtual HttpClient BuildClient()
309305

310306
if (!response.IsSuccessStatusCode)
311307
{
312-
var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
313-
throw new BingGeocodingException(new HttpRequestException($"Bing Maps request failed ({(int)response.StatusCode} {response.ReasonPhrase}).{BuildResponsePreview(body)}"));
308+
var preview = await BuildResponsePreviewAsync(response.Content).ConfigureAwait(false);
309+
throw new BingGeocodingException(new HttpRequestException($"Bing Maps request failed ({(int)response.StatusCode} {response.ReasonPhrase}).{preview}"));
314310
}
315311

316312
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
@@ -335,16 +331,21 @@ private ConfidenceLevel EvaluateConfidence(string? confidence)
335331
return ConfidenceLevel.Unknown;
336332
}
337333

338-
private static string BuildResponsePreview(string? body)
334+
private static async Task<string> BuildResponsePreviewAsync(HttpContent content)
339335
{
340-
if (String.IsNullOrWhiteSpace(body))
336+
using var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);
337+
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: false);
338+
var buffer = new char[256];
339+
int read = await reader.ReadBlockAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
340+
341+
if (read == 0)
341342
return String.Empty;
342343

343-
var preview = body!.Trim();
344-
if (preview.Length > 256)
345-
preview = preview.Substring(0, 256) + "...";
344+
var preview = new string(buffer, 0, read).Trim();
345+
if (String.IsNullOrWhiteSpace(preview))
346+
return String.Empty;
346347

347-
return " Response preview: " + preview;
348+
return " Response preview: " + preview + (reader.EndOfStream ? String.Empty : "...");
348349
}
349350

350351
private string BingUrlEncode(string toEncode)

test/Geocoding.Tests/TestHttpMessageHandler.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
1818
return _sendAsync(request, cancellationToken);
1919
}
2020

21-
public static Task<HttpResponseMessage> CreateResponseAsync(HttpStatusCode statusCode, string? reasonPhrase = null, string? body = null)
21+
public static HttpResponseMessage CreateResponse(HttpStatusCode statusCode, string? reasonPhrase = null, string? body = null)
2222
{
23-
return Task.FromResult(new HttpResponseMessage(statusCode)
23+
return new HttpResponseMessage(statusCode)
2424
{
2525
ReasonPhrase = reasonPhrase,
2626
Content = String.IsNullOrWhiteSpace(body) ? null : new StringContent(body, Encoding.UTF8, "text/plain")
27-
});
27+
};
28+
}
29+
30+
public static Task<HttpResponseMessage> CreateResponseAsync(HttpStatusCode statusCode, string? reasonPhrase = null, string? body = null)
31+
{
32+
return Task.FromResult(CreateResponse(statusCode, reasonPhrase, body));
2833
}
2934
}

0 commit comments

Comments
 (0)