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
60 changes: 60 additions & 0 deletions UnitsNet.Tests/DummyIQuantity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Text;
using JetBrains.Annotations;

namespace UnitsNet.Tests
{
internal class DummyIQuantity : IQuantity
{
public QuantityType Type => throw new NotImplementedException();

public BaseDimensions Dimensions => throw new NotImplementedException();

public QuantityInfo QuantityInfo => throw new NotImplementedException();

public Enum Unit => throw new NotImplementedException();

public double Value => throw new NotImplementedException();

public double As(Enum unit)
{
throw new NotImplementedException();
}

public double As(UnitSystem unitSystem)
{
throw new NotImplementedException();
}

public string ToString([CanBeNull] IFormatProvider provider)
{
throw new NotImplementedException();
}

public string ToString([CanBeNull] IFormatProvider provider, int significantDigitsAfterRadix)
{
throw new NotImplementedException();
}

public string ToString([CanBeNull] IFormatProvider provider, [NotNull] string format, [NotNull] params object[] args)
{
throw new NotImplementedException();
}

public string ToString(string format, IFormatProvider formatProvider)
{
throw new NotImplementedException();
}

public IQuantity ToUnit(Enum unit)
{
throw new NotImplementedException();
}

public IQuantity ToUnit(UnitSystem unitSystem)
{
throw new NotImplementedException();
}
}
}
30 changes: 30 additions & 0 deletions UnitsNet.Tests/QuantityTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Globalization;
using System.Linq;
using JetBrains.Annotations;
using UnitsNet.Units;
using Xunit;

Expand Down Expand Up @@ -135,6 +136,13 @@ public void TryFrom_GivenValueAndUnit_ReturnsQuantity()
Assert.Equal(Pressure.FromMegabars(3), parsedPressure);
}

[Fact]
public void TryParse_GivenInvalidQuantityType_ReturnsFalseAndNullQuantity()
{
Assert.False(Quantity.TryParse(typeof(DummyIQuantity), "3.0 cm", out IQuantity parsedLength));
Assert.Null(parsedLength);
}

[Fact]
public void TryParse_GivenInvalidString_ReturnsFalseAndNullQuantity()
{
Expand Down Expand Up @@ -171,5 +179,27 @@ public void Types_ReturnsKnownQuantityTypes()
Assert.Superset(knownQuantities.ToHashSet(), types.ToHashSet());
Assert.Equal(QuantityCount, types.Length);
}

[Fact]
public void FromQuantityType_GivenUndefinedQuantityType_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => Quantity.FromQuantityType(QuantityType.Undefined, 0.0));
}

[Fact]
public void FromQuantityType_GivenInvalidQuantityType_ThrowsArgumentException()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this test case

{
Assert.Throws<ArgumentException>(() => Quantity.FromQuantityType((QuantityType)(-1), 0.0));
}

[Fact]
public void FromQuantityType_GivenLengthQuantityType_ReturnsLengthQuantity()
{
var fromQuantity = Quantity.FromQuantityType(QuantityType.Length, 0.0);

Assert.Equal(0.0, fromQuantity.Value);
Assert.Equal(QuantityType.Length, fromQuantity.Type);
Assert.Equal(Length.BaseUnit, fromQuantity.Unit);
}
}
}
65 changes: 54 additions & 11 deletions UnitsNet/CustomCode/Quantity.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using JetBrains.Annotations;
using UnitsNet.InternalHelpers;

namespace UnitsNet
Expand All @@ -15,17 +17,9 @@ static Quantity()
Types = quantityTypes;
Names = quantityTypes.Select(qt => qt.ToString()).ToArray();

// A bunch of reflection to enumerate quantity types, instantiate with the default constructor and return its QuantityInfo property
InfosLazy = new Lazy<QuantityInfo[]>(() => typeof(Length)
.Wrap()
.Assembly
.GetExportedTypes()
.Where(typeof(IQuantity).IsAssignableFrom)
.Where(t => t.Wrap().IsClass || t.Wrap().IsValueType) // Future-proofing: Considering changing quantities from struct to class
.Select(Activator.CreateInstance)
.Cast<IQuantity>()
.Select(q => q.QuantityInfo)
.OrderBy(q => q.Name)
InfosLazy = new Lazy<QuantityInfo[]>(() => Types
.Select(quantityType => FromQuantityType(quantityType, 0.0).QuantityInfo)
.OrderBy(quantityInfo => quantityInfo.Name)
.ToArray());
}

Expand Down Expand Up @@ -60,6 +54,55 @@ public static IQuantity From(QuantityValue value, Enum unit)
$"Unit value {unit} of type {unit.GetType()} is not a known unit enum type. Expected types like UnitsNet.Units.LengthUnit. Did you pass in a third-party enum type defined outside UnitsNet library?");
}

/// <inheritdoc cref="TryFrom(QuantityValue,System.Enum,out UnitsNet.IQuantity)"/>
public static bool TryFrom(double value, Enum unit, out IQuantity quantity)
{
// Implicit cast to QuantityValue would prevent TryFrom from being called,
// so we need to explicitly check this here for double arguments.
if (double.IsNaN(value) || double.IsInfinity(value))
{
quantity = default(IQuantity);
return false;
}

return TryFrom((QuantityValue)value, unit, out quantity);
}

/// <inheritdoc cref="Parse(IFormatProvider, System.Type,string)"/>
public static IQuantity Parse(Type quantityType, string quantityString) => Parse(null, quantityType, quantityString);

/// <summary>
/// Dynamically parse a quantity string representation.
/// </summary>
/// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="CultureInfo.CurrentUICulture" /> if null.</param>
/// <param name="quantityType">Type of quantity, such as <see cref="Length"/>.</param>
/// <param name="quantityString">Quantity string representation, such as "1.5 kg". Must be compatible with given quantity type.</param>
/// <returns>The parsed quantity.</returns>
/// <exception cref="ArgumentException">Type must be of type UnitsNet.IQuantity -or- Type is not a known quantity type.</exception>
public static IQuantity Parse([CanBeNull] IFormatProvider formatProvider, Type quantityType, string quantityString)
{
if (!typeof(IQuantity).Wrap().IsAssignableFrom(quantityType))
throw new ArgumentException($"Type {quantityType} must be of type UnitsNet.IQuantity.");

if (TryParse(formatProvider, quantityType, quantityString, out IQuantity quantity)) return quantity;

throw new ArgumentException($"Quantity string could not be parsed to quantity {quantityType}.");
}

/// <inheritdoc cref="TryParse(IFormatProvider,System.Type,string,out UnitsNet.IQuantity)"/>
public static bool TryParse(Type quantityType, string quantityString, out IQuantity quantity) =>
TryParse(null, quantityType, quantityString, out quantity);

/// <summary>
/// Get information about the given quantity type.
/// </summary>
/// <param name="quantityType">The quantity type enum value.</param>
/// <returns>Information about the quantity and its units.</returns>
public static QuantityInfo GetInfo(QuantityType quantityType)
{
return Infos.First(qi => qi.QuantityType == quantityType);
}

/// <summary>
/// Get a list of quantities that has the given base dimensions.
/// </summary>
Expand Down
Loading