Compare commits

...

2 Commits

Author SHA1 Message Date
075a803f4f fix tests with claude
All checks were successful
Publish NuGet Packages / build-and-publish (push) Successful in 27s
2025-10-08 11:11:14 -04:00
1c1b2877cf added From, To and switch GetFormattedAddress to IAddress extension 2025-10-08 10:58:12 -04:00
8 changed files with 144 additions and 110 deletions

View File

@ -2,10 +2,10 @@ namespace Svrnty.GeoManagement.Abstractions.Abstractions;
public interface IAddress public interface IAddress
{ {
public string Line1 { get; } public string Line1 { get; set; }
public string? Line2 { get; } public string? Line2 { get; set; }
public string City { get; } public string City { get; set; }
public string Subdivision { get; } public string Subdivision { get; set; }
public string PostalCode { get; } public string PostalCode { get; set; }
public string Country { get; } public string Country { get; set; }
} }

View File

@ -2,60 +2,17 @@ using Svrnty.GeoManagement.Abstractions.Abstractions;
namespace Svrnty.GeoManagement.Abstractions.Models; namespace Svrnty.GeoManagement.Abstractions.Models;
public record GeoPoint(double Latitude, double Longitude); public record GeoPoint(decimal Latitude, decimal Longitude);
public record Address( public record Address(bool Normalized = false) : IAddress
string Line1,
string? Line2,
string City,
string Subdivision,
string PostalCode,
string Country,
GeoPoint? Location,
string? Note,
bool IsNormalized = false
) : IAddress
{ {
public string GetFormattedAddress( public required string Line1 { get; set; }
FormattedAddressType formatType = FormattedAddressType.Full public string? Line2 { get; set; }
) public required string City { get; set; }
{ public required string Subdivision { get; set; }
return formatType switch public required string PostalCode { get; set; }
{ public required string Country { get; set; }
FormattedAddressType.Full => FormatFullOneLine(), public GeoPoint? Location { get; set; }
FormattedAddressType.Compact => FormatCompactOneLine(), public string? Note { get; set; }
FormattedAddressType.MultiLine => FormatMultiLine(), public bool IsNormalized() => Normalized;
_ => FormatFullOneLine()
};
}
private string FormatFullOneLine()
{
if (string.IsNullOrWhiteSpace(Line2))
{
return $"{Line1}, {City}, {Subdivision} {PostalCode}, {Country}";
}
return $"{Line2}, {Line1}, {City}, {Subdivision} {PostalCode}, {Country}";
}
private string FormatCompactOneLine()
{
if (string.IsNullOrWhiteSpace(Line2))
{
return $"{Line1}, {City}, {Subdivision}";
}
return $"{Line2}, {Line1}, {City}, {Subdivision}";
}
private string FormatMultiLine()
{
if (string.IsNullOrWhiteSpace(Line2))
{
return $"{Line1}\n{City}, {Subdivision} {PostalCode}\n{Country}";
}
return $"{Line2}, {Line1}\n{City}, {Subdivision} {PostalCode}\n{Country}";
}
} }

View File

@ -0,0 +1,68 @@
using Svrnty.GeoManagement.Abstractions.Abstractions;
using Svrnty.GeoManagement.Abstractions.Models;
namespace Svrnty.GeoManagement.Abstractions;
public static class ServiceCollectionExtensions
{
public static void To(this IAddress address, IAddress toAddress)
{
toAddress.Line1 = address.Line1;
toAddress.Line2 = address.Line2;
toAddress.City = address.City;
toAddress.PostalCode = address.PostalCode;
toAddress.Country = address.Country;
toAddress.Subdivision = address.Subdivision;
}
public static void From(this IAddress address, IAddress fromAddress)
{
address.Line1 = fromAddress.Line1;
address.Line2 = fromAddress.Line2;
address.City = fromAddress.City;
address.PostalCode = fromAddress.PostalCode;
address.Country = fromAddress.Country;
address.Subdivision = fromAddress.Subdivision;
}
public static string GetFormattedAddress(this IAddress address, FormattedAddressType formatType = FormattedAddressType.Full)
{
return formatType switch
{
FormattedAddressType.Full => FormatFullOneLine(address),
FormattedAddressType.Compact => FormatCompactOneLine(address),
FormattedAddressType.MultiLine => FormatMultiLine(address),
_ => FormatFullOneLine(address)
};
}
private static string FormatFullOneLine(IAddress address)
{
if (string.IsNullOrWhiteSpace(address.Line2))
{
return $"{address.Line1}, {address.City}, {address.Subdivision} {address.PostalCode}, {address.Country}";
}
return $"{address.Line2}, {address.Line1}, {address.City}, {address.Subdivision} {address.PostalCode}, {address.Country}";
}
private static string FormatCompactOneLine(IAddress address)
{
if (string.IsNullOrWhiteSpace(address.Line2))
{
return $"{address.Line1}, {address.City}, {address.Subdivision}";
}
return $"{address.Line2}, {address.Line1}, {address.City}, {address.Subdivision}";
}
private static string FormatMultiLine(IAddress address)
{
if (string.IsNullOrWhiteSpace(address.Line2))
{
return $"{address.Line1}\n{address.City}, {address.Subdivision} {address.PostalCode}\n{address.Country}";
}
return $"{address.Line2}, {address.Line1}\n{address.City}, {address.Subdivision} {address.PostalCode}\n{address.Country}";
}
}

View File

@ -3,6 +3,7 @@ using GoogleApi.Entities.Maps.Geocoding.Address.Request;
using GoogleApi.Entities.Maps.Geocoding.Location.Request; using GoogleApi.Entities.Maps.Geocoding.Location.Request;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Svrnty.GeoManagement.Abstractions;
using Svrnty.GeoManagement.Abstractions.Abstractions; using Svrnty.GeoManagement.Abstractions.Abstractions;
using Svrnty.GeoManagement.Abstractions.Models; using Svrnty.GeoManagement.Abstractions.Models;
using Svrnty.GeoManagement.Google.Configuration; using Svrnty.GeoManagement.Google.Configuration;
@ -91,7 +92,7 @@ public class GeoManagementGoogleProvider : IGeoManagementProvider
var request = new LocationGeocodeRequest var request = new LocationGeocodeRequest
{ {
Key = _options.ApiKey, Key = _options.ApiKey,
Location = new GoogleApi.Entities.Common.Coordinate(geoPoint.Latitude, geoPoint.Longitude) Location = new GoogleApi.Entities.Common.Coordinate((double)geoPoint.Latitude, (double)geoPoint.Longitude)
}; };
if (!string.IsNullOrWhiteSpace(_options.Language) && if (!string.IsNullOrWhiteSpace(_options.Language) &&

View File

@ -26,20 +26,20 @@ internal static class GoogleAddressMapper
var country = GetComponentValue(components, "country") ?? string.Empty; var country = GetComponentValue(components, "country") ?? string.Empty;
var location = googleResult.Geometry?.Location != null var location = googleResult.Geometry?.Location != null
? new GeoPoint(googleResult.Geometry.Location.Latitude, googleResult.Geometry.Location.Longitude) ? new GeoPoint((decimal)googleResult.Geometry.Location.Latitude, (decimal)googleResult.Geometry.Location.Longitude)
: null; : null;
return new Abstractions.Models.Address( return new Abstractions.Models.Address(Normalized: true)
Line1: line1, {
Line2: line2, Line1 = line1,
City: city, Line2 = line2,
Subdivision: subdivision, City = city,
PostalCode: postalCode, Subdivision = subdivision,
Country: country, PostalCode = postalCode,
Location: location, Country = country,
Note: null, Location = location,
IsNormalized: true Note = null
); };
} }
private static string BuildLine1(IEnumerable<AddressComponent> components) private static string BuildLine1(IEnumerable<AddressComponent> components)
@ -79,8 +79,8 @@ internal static class GoogleAddressMapper
return null; return null;
return new GeoPoint( return new GeoPoint(
googleResult.Geometry.Location.Latitude, (decimal)googleResult.Geometry.Location.Latitude,
googleResult.Geometry.Location.Longitude (decimal)googleResult.Geometry.Location.Longitude
); );
} }
} }

View File

@ -24,12 +24,12 @@ public class AddressTestData
public class GeoPointTestData public class GeoPointTestData
{ {
public double Latitude { get; set; } public decimal Latitude { get; set; }
public double Longitude { get; set; } public decimal Longitude { get; set; }
} }
public class CoordinateRange public class CoordinateRange
{ {
public double Min { get; set; } public decimal Min { get; set; }
public double Max { get; set; } public decimal Max { get; set; }
} }

View File

@ -54,15 +54,17 @@ public class GoogleProviderTests : IDisposable
public async Task GetGeoPointAsync_WithValidAddress_ReturnsCoordinates() public async Task GetGeoPointAsync_WithValidAddress_ReturnsCoordinates()
{ {
// Arrange // Arrange
var address = new Address( var address = new Address
Line1: _testData.ValidAddress.Line1, {
Line2: _testData.ValidAddress.Line2, Line1 = _testData.ValidAddress.Line1,
City: _testData.ValidAddress.City, Line2 = _testData.ValidAddress.Line2,
Subdivision: _testData.ValidAddress.Subdivision, City = _testData.ValidAddress.City,
PostalCode: _testData.ValidAddress.PostalCode, Subdivision = _testData.ValidAddress.Subdivision,
Country: _testData.ValidAddress.Country, PostalCode = _testData.ValidAddress.PostalCode,
Location: null, Country = _testData.ValidAddress.Country,
Note: null); Location = null,
Note = null
};
// Act // Act
var result = await _provider.GetGeoPointAsync(address); var result = await _provider.GetGeoPointAsync(address);
@ -89,7 +91,7 @@ public class GoogleProviderTests : IDisposable
Assert.NotNull(result.Line1); Assert.NotNull(result.Line1);
Assert.NotNull(result.City); Assert.NotNull(result.City);
Assert.NotNull(result.Country); Assert.NotNull(result.Country);
Assert.True(result.IsNormalized); Assert.True(result.IsNormalized());
Assert.NotNull(result.Location); Assert.NotNull(result.Location);
} }
@ -97,22 +99,24 @@ public class GoogleProviderTests : IDisposable
public async Task NormalizeAddressAsync_WithAddressObject_ReturnsNormalizedAddress() public async Task NormalizeAddressAsync_WithAddressObject_ReturnsNormalizedAddress()
{ {
// Arrange // Arrange
var address = new Address( var address = new Address
Line1: _testData.NormalizeTestAddress.Line1, {
Line2: _testData.NormalizeTestAddress.Line2, Line1 = _testData.NormalizeTestAddress.Line1,
City: _testData.NormalizeTestAddress.City, Line2 = _testData.NormalizeTestAddress.Line2,
Subdivision: _testData.NormalizeTestAddress.Subdivision, City = _testData.NormalizeTestAddress.City,
PostalCode: _testData.NormalizeTestAddress.PostalCode, Subdivision = _testData.NormalizeTestAddress.Subdivision,
Country: _testData.NormalizeTestAddress.Country, PostalCode = _testData.NormalizeTestAddress.PostalCode,
Location: null, Country = _testData.NormalizeTestAddress.Country,
Note: null); Location = null,
Note = null
};
// Act // Act
var result = await _provider.NormalizeAddressAsync(address); var result = await _provider.NormalizeAddressAsync(address);
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.True(result.IsNormalized); Assert.True(result.IsNormalized());
Assert.NotNull(result.Location); Assert.NotNull(result.Location);
Assert.NotNull(result.Line1); Assert.NotNull(result.Line1);
Assert.Contains("Amphitheatre", result.Line1, StringComparison.OrdinalIgnoreCase); Assert.Contains("Amphitheatre", result.Line1, StringComparison.OrdinalIgnoreCase);
@ -129,7 +133,7 @@ public class GoogleProviderTests : IDisposable
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.True(result.IsNormalized); Assert.True(result.IsNormalized());
Assert.NotNull(result.Location); Assert.NotNull(result.Location);
Assert.NotNull(result.Line1); Assert.NotNull(result.Line1);
Assert.Contains("Mountain View", result.City, StringComparison.OrdinalIgnoreCase); Assert.Contains("Mountain View", result.City, StringComparison.OrdinalIgnoreCase);
@ -139,15 +143,17 @@ public class GoogleProviderTests : IDisposable
public async Task GetGeoPointAsync_WithInvalidAddress_ReturnsNull() public async Task GetGeoPointAsync_WithInvalidAddress_ReturnsNull()
{ {
// Arrange // Arrange
var address = new Address( var address = new Address
Line1: _testData.InvalidAddress.Line1, {
Line2: _testData.InvalidAddress.Line2, Line1 = _testData.InvalidAddress.Line1,
City: _testData.InvalidAddress.City, Line2 = _testData.InvalidAddress.Line2,
Subdivision: _testData.InvalidAddress.Subdivision, City = _testData.InvalidAddress.City,
PostalCode: _testData.InvalidAddress.PostalCode, Subdivision = _testData.InvalidAddress.Subdivision,
Country: _testData.InvalidAddress.Country, PostalCode = _testData.InvalidAddress.PostalCode,
Location: null, Country = _testData.InvalidAddress.Country,
Note: null); Location = null,
Note = null
};
// Act // Act
var result = await _provider.GetGeoPointAsync(address); var result = await _provider.GetGeoPointAsync(address);
@ -172,7 +178,7 @@ public class GoogleProviderTests : IDisposable
// This test just verifies it doesn't crash // This test just verifies it doesn't crash
if (result != null) if (result != null)
{ {
Assert.True(result.IsNormalized); Assert.True(result.IsNormalized());
} }
} }

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F728eee8ccad23b8fff516dba093eb71b49fb5ee8839f2118392e9747de4ebb_003FResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>