Skip to content

Commit

Permalink
Added hashcode, equals, and operator overloading (arithmetic, compari…
Browse files Browse the repository at this point in the history
…son, equality, and converting to and from longs)
  • Loading branch information
Aldaviva committed Jan 23, 2020
1 parent 8e6b18e commit 1fb5d07
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 5 deletions.
58 changes: 56 additions & 2 deletions DataSizeUnits/DataSize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ namespace DataSizeUnits {
/// <para><c>var kilobyte = new DataSize(1, Unit.Kilobyte);</c></para>
/// </summary>
[Serializable]
public struct DataSize {
public struct DataSize: IComparable<DataSize> {

public double Quantity;
public Unit Unit;

private double AsBits => Quantity * CountBitsInUnit(Unit);

/// <summary>
/// <para>Create a new instance with the given quantity of the given unit of data.</para>
/// <para><c>var kilobyte = new DataSize(1, Unit.Kilobyte);</c></para>
Expand Down Expand Up @@ -53,7 +55,7 @@ public DataSize Normalize(bool useBitsInsteadOfBytes = false) {
/// <param name="destinationUnit">The data size unit that the resulting instance should use.</param>
/// <returns>A new instance with the converted quantity and unit. The original instance is unchanged.</returns>
public DataSize ConvertToUnit(Unit destinationUnit) {
return new DataSize(Quantity * CountBitsInUnit(Unit) / CountBitsInUnit(destinationUnit), destinationUnit);
return new DataSize(AsBits / CountBitsInUnit(destinationUnit), destinationUnit);
}

/// <summary>
Expand Down Expand Up @@ -266,6 +268,58 @@ public string ToString(int precision) {
return Quantity.ToString("N", culture) + " " + Unit.ToAbbreviation();
}

public bool Equals(DataSize other) {
return AsBits.Equals(other.AsBits);
}

public override bool Equals(object obj) {
return obj is DataSize other && Equals(other);
}

public override int GetHashCode() {
return AsBits.GetHashCode();
}

public int CompareTo(DataSize other) {
return AsBits.CompareTo(other.AsBits);
}

public static bool operator <(DataSize a, DataSize b) => a.AsBits < b.AsBits;

public static bool operator >(DataSize a, DataSize b) => a.AsBits > b.AsBits;

public static bool operator <=(DataSize a, DataSize b) => a.AsBits <= b.AsBits;

public static bool operator >=(DataSize a, DataSize b) => a.AsBits >= b.AsBits;

public static DataSize operator +(DataSize a, DataSize b) {
return new DataSize(a.Quantity + b.ConvertToUnit(a.Unit).Quantity, a.Unit);
}

public static DataSize operator -(DataSize a, DataSize b) {
return new DataSize(a.Quantity - b.ConvertToUnit(a.Unit).Quantity, a.Unit);
}

public static DataSize operator *(DataSize a, double b) {
return new DataSize(a.Quantity * b, a.Unit);
}

public static DataSize operator /(DataSize a, double b) {
if (!b.Equals(0)) {
return new DataSize(a.Quantity / b, a.Unit);
} else {
throw new DivideByZeroException();
}
}

public static bool operator ==(DataSize a, DataSize b) => a.Equals(b);

public static bool operator !=(DataSize a, DataSize b) => !a.Equals(b);

public static implicit operator long(DataSize dataSize) => (long) dataSize.AsBits / 8;

public static implicit operator DataSize(long bytes) => new DataSize(bytes);

}

}
103 changes: 102 additions & 1 deletion Tests/DataSizeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DataSizeUnits;
using System;
using DataSizeUnits;
using Xunit;

namespace Tests {
Expand All @@ -8,6 +9,7 @@ public class DataSizeTests {
[Theory, MemberData(nameof(AutoScaleData))]
public void AutoScale(long inputBytes, double expectedSize, Unit expectedUnit, bool useBytes) {
DataSize actual = new DataSize(inputBytes).Normalize(!useBytes);

Assert.Equal(expectedSize, actual.Quantity, 3);
Assert.Equal(expectedUnit, actual.Unit);
}
Expand Down Expand Up @@ -38,6 +40,7 @@ public void AutoScale(long inputBytes, double expectedSize, Unit expectedUnit, b
[Theory, MemberData(nameof(ScaleToData))]
public void ManualScale(long inputBytes, Unit inputDestinationScale, double expectedValue) {
DataSize actual = new DataSize(inputBytes).ConvertToUnit(inputDestinationScale);

Assert.Equal(expectedValue, actual.Quantity, 3);
Assert.Equal(inputDestinationScale, actual.Unit);
}
Expand All @@ -59,10 +62,108 @@ public void ManualScale(long inputBytes, Unit inputDestinationScale, double expe
[Fact]
public void ScaleUnitToUnit() {
DataSize actual = new DataSize(150, Unit.Megabit).ConvertToUnit(Unit.Megabyte);

Assert.Equal(17.8813934326171875, actual.Quantity, 3);
Assert.Equal(Unit.Megabyte, actual.Unit);
}

[Theory, MemberData(nameof(EqualityData))]
public void Equality(double quantity1, Unit unit1, double quantity2, Unit unit2) {
var dataSize1 = new DataSize(quantity1, unit1);
var dataSize2 = new DataSize(quantity2, unit2);

Assert.True(dataSize1.Equals(dataSize2));
Assert.True(dataSize1.Equals((object) dataSize2));
Assert.True(dataSize1 == dataSize2);
Assert.True(dataSize1 >= dataSize2);
Assert.True(dataSize1 <= dataSize2);
Assert.False(dataSize1 != dataSize2);
Assert.False(dataSize1 < dataSize2);
Assert.False(dataSize1 > dataSize2);
Assert.Equal(dataSize1.GetHashCode(), dataSize2.GetHashCode());
Assert.Equal(0, dataSize1.CompareTo(dataSize2));
}

public static TheoryData<double, Unit, double, Unit> EqualityData => new TheoryData<double, Unit, double, Unit> {
{ 1, Unit.Megabyte, 1, Unit.Megabyte },
{ 1, Unit.Megabyte, 1024, Unit.Kilobyte },
{ 1, Unit.Megabyte, 1048576, Unit.Byte },
{ 1, Unit.Megabyte, 8388608, Unit.Bit }
};

[Theory, MemberData(nameof(InequalityData))]
public void Inequality(double quantity1, Unit unit1, double quantity2, Unit unit2, bool isInput2BiggerThanInput1) {
var dataSize1 = new DataSize(quantity1, unit1);
var dataSize2 = new DataSize(quantity2, unit2);

Assert.False(dataSize1.Equals(dataSize2));
Assert.False(dataSize1 == dataSize2);
Assert.True(dataSize1 != dataSize2);
Assert.NotEqual(dataSize1.GetHashCode(), dataSize2.GetHashCode());
int comparison = dataSize1.CompareTo(dataSize2);
if (isInput2BiggerThanInput1) {
Assert.True(comparison < 0);
Assert.True(dataSize1 < dataSize2);
Assert.True(dataSize1 <= dataSize2);
} else {
Assert.True(comparison > 0);
Assert.True(dataSize1 > dataSize2);
Assert.True(dataSize1 >= dataSize2);
}
}

public static TheoryData<double, Unit, double, Unit, bool> InequalityData => new TheoryData<double, Unit, double, Unit, bool> {
{ 1, Unit.Kilobyte, 1, Unit.Megabyte, true },
{ 1.4, Unit.Megabyte, 1.44, Unit.Megabyte, true },
{ 1, Unit.Gigabyte, 1000, Unit.Megabyte, false },
{ 1, Unit.Megabyte, 1, Unit.Megabit, false }
};

[Fact]
public void Addition() {
DataSize actual = new DataSize(1, Unit.Megabyte) + new DataSize(2, Unit.Megabyte);
Assert.Equal(3, actual.Quantity);
Assert.Equal(Unit.Megabyte, actual.Unit);
}

[Fact]
public void Subtraction() {
DataSize actual = new DataSize(3, Unit.Megabyte) - new DataSize(2048, Unit.Kilobyte);
Assert.Equal(1, actual.Quantity);
Assert.Equal(Unit.Megabyte, actual.Unit);
}

[Fact]
public void Multiplication() {
DataSize actual = new DataSize(1, Unit.Megabyte) * 3;
Assert.Equal(3, actual.Quantity);
Assert.Equal(Unit.Megabyte, actual.Unit);
}

[Fact]
public void Division() {
DataSize actual = new DataSize(6, Unit.Megabyte) / 3;
Assert.Equal(2, actual.Quantity);
Assert.Equal(Unit.Megabyte, actual.Unit);
}

[Fact]
public void DivisionByZero() {
Assert.Throws<DivideByZeroException>(() => new DataSize(1) / 0);
}

[Fact]
public void ToBytes() {
long actual = new DataSize(1, Unit.Kilobyte);
Assert.Equal(1024, actual);
}

[Fact]
public void FromBytes() {
DataSize actual = 1024;
Assert.Equal(1024, actual.Quantity);
Assert.Equal(Unit.Byte, actual.Unit);
}
}

}
4 changes: 2 additions & 2 deletions Tests/Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
Expand All @@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down

0 comments on commit 1fb5d07

Please sign in to comment.