Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.

namespace UnitsNet.Tests.QuantityInfos.Builder;

public class QuantitiesSelectorTests
{
[Fact]
public void GetQuantityInfos_WithoutAdditions_ReturnsBaseSelection()
{
var selector = new QuantitiesSelector(() => [Length.Info]);

Assert.Equal([Length.Info], selector.GetQuantityInfos());
}

[Fact]
public void WithAdditionalQuantities_AppendsAllSelectionsInOrder()
{
QuantitiesSelector selector = new QuantitiesSelector(() => [Length.Info])
.WithAdditionalQuantities([Mass.Info])
.WithAdditionalQuantities([Duration.Info]);

Assert.Equal([Length.Info, Mass.Info, Duration.Info], selector.GetQuantityInfos());
}

[Fact]
public void WithAdditionalQuantities_WithNull_ThrowsArgumentNullException()
{
var selector = new QuantitiesSelector(() => [Length.Info]);

Assert.Throws<ArgumentNullException>(() => selector.WithAdditionalQuantities(null!));
}
}
34 changes: 34 additions & 0 deletions UnitsNet.Tests/UnitAbbreviationsCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ public void CreateDefault_ReturnsAnAbbreviationCacheWithDefaultQuantityInfoLooku
Assert.Throws<UnitNotFoundException>(() => unitAbbreviationCache.GetUnitAbbreviations(HowMuchUnit.Some));
}

[Fact]
public void CreateDefault_WithAdditionalQuantity_ReturnsCacheWithExtendedQuantityInfoLookup()
{
var unitAbbreviationCache = UnitAbbreviationsCache.CreateDefault(selector => selector.WithAdditionalQuantities([HowMuch.Info]));

Assert.NotEqual(UnitsNetSetup.Default.Quantities, unitAbbreviationCache.Quantities);
Assert.Equal("g", unitAbbreviationCache.GetUnitAbbreviations(MassUnit.Gram, AmericanCulture)[0]);
Assert.Empty(unitAbbreviationCache.GetUnitAbbreviations(HowMuchUnit.Some, AmericanCulture));
}

[Fact]
public void Create_WithBaseAndAdditionalQuantities_ReturnsConfiguredCache()
{
var unitAbbreviationCache = UnitAbbreviationsCache.Create([Mass.Info],
selector => selector.WithAdditionalQuantities([HowMuch.Info]));

Assert.Equal([Mass.Info, HowMuch.Info], unitAbbreviationCache.Quantities.Infos);
Assert.Throws<UnitNotFoundException>(() => unitAbbreviationCache.GetUnitAbbreviations(LengthUnit.Meter));
}

[Fact]
public void FactoryMethods_WithNullArguments_ThrowArgumentNullException()
{
Assert.Multiple(checks:
[
() => Assert.Equal("configureQuantities",
Assert.Throws<ArgumentNullException>(() => UnitAbbreviationsCache.CreateDefault(null!)).ParamName),
() => Assert.Equal("defaultQuantities",
Assert.Throws<ArgumentNullException>(() => UnitAbbreviationsCache.Create(null!, _ => { })).ParamName),
() => Assert.Equal("configureQuantities",
Assert.Throws<ArgumentNullException>(() => UnitAbbreviationsCache.Create([Mass.Info], null!)).ParamName)
]);
}

[Fact]
public void UnitAbbreviationsCache_Default_ReturnsInstanceFromUnitsNetSetup()
{
Expand Down
54 changes: 54 additions & 0 deletions UnitsNet.Tests/UnitParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,60 @@ public void CreateDefault_CreatesNewAbbreviationsCacheWithDefaultQuantities()
Assert.NotEqual(UnitAbbreviationsCache.Default, unitParser.Abbreviations);
Assert.Equal(UnitsNetSetup.Default.Quantities, unitParser.Quantities);
}

[Fact]
public void CreateDefault_WithAdditionalQuantity_CreatesParserWithExtendedCatalog()
{
var unitParser = UnitParser.CreateDefault(selector => selector.WithAdditionalQuantities([HowMuch.Info]));

Assert.Contains(HowMuch.Info, unitParser.Quantities.Infos);
}

[Fact]
public void CreateDefault_WithConfiguredQuantityAndAbbreviation_ParsesExternalQuantityUnit()
{
var unitParser = UnitParser.CreateDefault(
selector => selector.WithAdditionalQuantities([HowMuch.Info]),
abbreviations => abbreviations.MapUnitToAbbreviation(HowMuchUnit.Some, "some"));

Assert.Equal(HowMuchUnit.Some, unitParser.Parse<HowMuchUnit>("some"));
}

[Fact]
public void Create_WithBaseAndAdditionalQuantities_CreatesParserWithSelectedCatalog()
{
var unitParser = UnitParser.Create([Mass.Info],
selector => selector.WithAdditionalQuantities([HowMuch.Info]));

Assert.Equal([Mass.Info, HowMuch.Info], unitParser.Quantities.Infos);
}

[Fact]
public void Create_WithConfiguredAbbreviation_ParsesExternalQuantityUnit()
{
var unitParser = UnitParser.Create([HowMuch.Info], _ => { },
abbreviations => abbreviations.MapUnitToAbbreviation(HowMuchUnit.Some, "some"));

Assert.Equal(HowMuchUnit.Some, unitParser.Parse<HowMuchUnit>("some"));
}

[Fact]
public void FactoryMethods_WithNullArguments_ThrowArgumentNullException()
{
Assert.Multiple(checks:
[
() => Assert.Equal("configureQuantities",
Assert.Throws<ArgumentNullException>(() => UnitParser.CreateDefault((Action<QuantitiesSelector>)null!)).ParamName),
() => Assert.Equal("configureAbbreviations",
Assert.Throws<ArgumentNullException>(() => UnitParser.CreateDefault(_ => { }, null!)).ParamName),
() => Assert.Equal("defaultQuantities",
Assert.Throws<ArgumentNullException>(() => UnitParser.Create(null!, _ => { })).ParamName),
() => Assert.Equal("configureQuantities",
Assert.Throws<ArgumentNullException>(() => UnitParser.Create([Mass.Info], null!)).ParamName),
() => Assert.Equal("configureAbbreviations",
Assert.Throws<ArgumentNullException>(() => UnitParser.Create([Mass.Info], _ => { }, null!)).ParamName)
]);
}

[Theory]
[InlineData("m^^2", AreaUnit.SquareMeter)]
Expand Down
69 changes: 69 additions & 0 deletions UnitsNet.Tests/UnitsNetSetupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.

using UnitsNet.Tests.CustomQuantities;
using UnitsNet.Units;

namespace UnitsNet.Tests;

public class UnitsNetSetupTests
{
[Fact]
public void Create_WithSelectedQuantities_WiresIsolatedComponentsToSameCatalog()
{
UnitsNetSetup setup = UnitsNetSetup.Create(builder => builder.WithQuantities([Mass.Info]));

Assert.Equal([Mass.Info], setup.Quantities.Infos);
Assert.Same(setup.Quantities, setup.UnitAbbreviations.Quantities);
Assert.Same(setup.UnitAbbreviations, setup.UnitParser.Abbreviations);
Assert.NotSame(UnitsNetSetup.Default, setup);
Assert.Throws<UnitNotFoundException>(() => setup.Quantities.GetQuantityByUnitType(typeof(LengthUnit)));
}

[Fact]
public void Create_WithAdditionalQuantities_AppendsToSelectedCatalog()
{
UnitsNetSetup setup = UnitsNetSetup.Create(builder => builder
.WithQuantities([Mass.Info])
.WithAdditionalQuantities([HowMuch.Info]));

Assert.Equal([Mass.Info, HowMuch.Info], setup.Quantities.Infos);
}

[Fact]
public void Create_WithSelectedAndAdditionalQuantities_AppendsToSelectedCatalog()
{
UnitsNetSetup setup = UnitsNetSetup.Create(builder => builder.WithQuantities([Mass.Info],
selector => selector.WithAdditionalQuantities([HowMuch.Info])));

Assert.Equal([Mass.Info, HowMuch.Info], setup.Quantities.Infos);
}

[Fact]
public void FactoryMethods_WithNullArguments_ThrowArgumentNullException()
{
var builder = new UnitsNetSetup.DefaultConfigurationBuilder();

Assert.Multiple(checks:
[
() => Assert.Equal("configuration",
Assert.Throws<ArgumentNullException>(() => UnitsNetSetup.Create(null!)).ParamName),
() => Assert.Equal("quantities",
Assert.Throws<ArgumentNullException>(() => builder.WithQuantities((IEnumerable<QuantityInfo>)null!)).ParamName),
() => Assert.Equal("quantities",
Assert.Throws<ArgumentNullException>(() => builder.WithQuantities((Func<IEnumerable<QuantityInfo>>)null!)).ParamName),
() => Assert.Equal("quantities",
Assert.Throws<ArgumentNullException>(() => builder.WithQuantities((IEnumerable<QuantityInfo>)null!, _ => { })).ParamName),
() => Assert.Equal("configureQuantities",
Assert.Throws<ArgumentNullException>(() => builder.WithQuantities(() => [Mass.Info], null!)).ParamName)
]);
}

[Fact]
public void Builder_WithQuantitiesTwice_ThrowsInvalidOperationException()
{
Assert.Throws<InvalidOperationException>(() => UnitsNetSetup.Create(builder => builder
.WithQuantities([Mass.Info])
.WithQuantities([Length.Info])));
}
}
39 changes: 39 additions & 0 deletions UnitsNet/CustomCode/QuantityInfo/Builder/QuantitiesSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed under MIT No Attribution, see LICENSE file at the root.
// Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet.

using System.Linq;

namespace UnitsNet;

/// <summary>
/// Selects the quantities used to construct an isolated UnitsNet component or setup.
/// </summary>
public sealed class QuantitiesSelector
{
private readonly Func<IEnumerable<QuantityInfo>> _defaultQuantities;
private IEnumerable<QuantityInfo>? _additionalQuantities;

internal QuantitiesSelector(Func<IEnumerable<QuantityInfo>> defaultQuantities)
{
_defaultQuantities = defaultQuantities ?? throw new ArgumentNullException(nameof(defaultQuantities));
}

/// <summary>
/// Appends external quantity definitions to the current selection.
/// </summary>
/// <param name="quantities">The quantity definitions to append.</param>
/// <returns>This selector, for method chaining.</returns>
public QuantitiesSelector WithAdditionalQuantities(IEnumerable<QuantityInfo> quantities)
{
if (quantities is null) throw new ArgumentNullException(nameof(quantities));

_additionalQuantities = _additionalQuantities?.Concat(quantities) ?? quantities;
return this;
}

internal IEnumerable<QuantityInfo> GetQuantityInfos()
{
IEnumerable<QuantityInfo> quantities = _defaultQuantities();
return _additionalQuantities is null ? quantities : quantities.Concat(_additionalQuantities);
}
}
21 changes: 21 additions & 0 deletions UnitsNet/CustomCode/UnitAbbreviationsCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ public static UnitAbbreviationsCache CreateDefault()
return new UnitAbbreviationsCache();
}

/// <summary>
/// Creates a cache for the built-in quantities and any additions made by <paramref name="configureQuantities" />.
/// </summary>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <returns>A cache mapped to the configured quantity selection.</returns>
public static UnitAbbreviationsCache CreateDefault(Action<QuantitiesSelector> configureQuantities)
{
return Create(Quantity.DefaultProvider.Quantities, configureQuantities);
}

/// <summary>
/// Creates a cache for a configured selection based on <paramref name="defaultQuantities" />.
/// </summary>
/// <param name="defaultQuantities">The initial quantity definitions.</param>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <returns>A cache mapped to the configured quantity selection.</returns>
public static UnitAbbreviationsCache Create(IEnumerable<QuantityInfo> defaultQuantities, Action<QuantitiesSelector> configureQuantities)
{
return new UnitAbbreviationsCache(QuantityInfoLookup.Create(defaultQuantities, configureQuantities));
}

#region MapUnitToAbbreviation overloads

/// <summary>
Expand Down
49 changes: 49 additions & 0 deletions UnitsNet/CustomCode/UnitParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,55 @@ public static UnitParser CreateDefault()
return new UnitParser(UnitAbbreviationsCache.CreateDefault());
}

/// <summary>
/// Creates a parser for the built-in quantities and any additions made by <paramref name="configureQuantities" />.
/// </summary>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <returns>A parser for the configured quantity selection.</returns>
public static UnitParser CreateDefault(Action<QuantitiesSelector> configureQuantities)
{
return new UnitParser(UnitAbbreviationsCache.CreateDefault(configureQuantities));
}

/// <summary>
/// Creates a parser for the built-in quantities, with configurable quantities and abbreviations.
/// </summary>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <param name="configureAbbreviations">Configures abbreviations before constructing the parser.</param>
/// <returns>A parser for the configured quantities and abbreviations.</returns>
public static UnitParser CreateDefault(Action<QuantitiesSelector> configureQuantities, Action<UnitAbbreviationsCache> configureAbbreviations)
{
return Create(Quantity.DefaultProvider.Quantities, configureQuantities, configureAbbreviations);
}

/// <summary>
/// Creates a parser for a configured selection based on <paramref name="defaultQuantities" />.
/// </summary>
/// <param name="defaultQuantities">The initial quantity definitions.</param>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <returns>A parser for the configured quantity selection.</returns>
public static UnitParser Create(IEnumerable<QuantityInfo> defaultQuantities, Action<QuantitiesSelector> configureQuantities)
{
return new UnitParser(UnitAbbreviationsCache.Create(defaultQuantities, configureQuantities));
}

/// <summary>
/// Creates a parser for a base catalog, with configurable quantities and abbreviations.
/// </summary>
/// <param name="defaultQuantities">The initial quantity definitions.</param>
/// <param name="configureQuantities">Configures the selected quantities.</param>
/// <param name="configureAbbreviations">Configures abbreviations before constructing the parser.</param>
/// <returns>A parser for the configured quantities and abbreviations.</returns>
public static UnitParser Create(IEnumerable<QuantityInfo> defaultQuantities, Action<QuantitiesSelector> configureQuantities,
Action<UnitAbbreviationsCache> configureAbbreviations)
{
if (configureAbbreviations is null) throw new ArgumentNullException(nameof(configureAbbreviations));

var unitAbbreviations = UnitAbbreviationsCache.Create(defaultQuantities, configureQuantities);
configureAbbreviations(unitAbbreviations);
return new UnitParser(unitAbbreviations);
}

/// <summary>
/// Parses a unit abbreviation for a given unit enumeration type.
/// Example: Parse&lt;LengthUnit&gt;("km") => LengthUnit.Kilometer
Expand Down
Loading
Loading