HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Representing and handling Data Sizes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
handlingsizesanddatarepresenting

Problem

In a very specific application I have, I needed the ability to easily convert between different data sizes. I.e. when I give an input of 1,048,576KiB, I needed it to say 1GiB, etc.

So, I built a struct for it.

It's pretty robust, includes operations for subtraction, addition, multiplication and division, == and !=, IsSame etc.

I'd like to think it might be useful for others as well.

First bit is the struct:

```
public struct DataSize
{
public ulong SizeInBytes { get; }
public SizeScale Scale { get; }
public double Size => GetSize(Scale);

public DataSize(ulong sizeInBytes)
{
Scale = SizeScale.Bytes;
SizeInBytes = sizeInBytes;
}

public DataSize(ulong sizeInBytes, SizeScale scale)
{
Scale = scale;
SizeInBytes = sizeInBytes;
}

public DataSize(double size, SizeScale scale)
{
Scale = scale;

if (scale == SizeScale.Bits)
{
SizeInBytes = (uint)(size / 8);
return;
}

if (((int)scale & 0x03) == (int)SizeScale.Bytes)
{
SizeInBytes = (uint)(size Math.Pow(10, 3 (((int)scale & 0xFF00) >> 8)));
return;
}

SizeInBytes = (uint)(size Math.Pow(2, 10 (((int)scale & 0xFF00) >> 8)));
}

public double GetSize(SizeScale scale)
{
if (scale == SizeScale.Bits)
{
return SizeInBytes * 8.0;
}

if (((int)scale & 0x03) == (int)SizeScale.Bytes)
{
return SizeInBytes / Math.Pow(10, 3 * (((int)scale & 0xFF00) >> 8));
}

return SizeInBytes / Math.Pow(2, 10 * (((int)scale & 0xFF00) >> 8));
}

///
/// Returns a that is the highest value which will have a non-zero whole-number component.
///
/// When set to the result will be a B type, when set to the result will be a iB type. If set to the same base unit as the source value will be used.
/// A object.
public DataSize G

Solution

I've only looked at your unit tests, not your actual code, but there are a few things that stand out.

TestCategory

It seems odd that you're marking every single test with a category that is essentially the name of the class being tested. You can sort tests by class name, run tests by class name, so it just feels wrong. I tend to use categories for cross cutting tests that have a similar purpose that I might want to run / exclude from test runs. So, things like "Integration Tests", "Database Tests", "Some large feature Tests", etc.

Duplication / Framework choice

There's quite a lot of duplication in your tests. Some people like to be explicit about what they're doing, so don't like breaking down the tests into common method calls. I don't know how tied to MS test framework you are, however other frameworks like NUnit make it quite easy to maintain explicit testing whilst reducing duplication. For example:

[TestFixture, Category("Size Scale Tests")]
public class SizeScaleTests
{
    [TestCase(SizeScale.None, null)]
    [TestCase(SizeScale.Bytes, "B")]
    [TestCase(SizeScale.Bits, "b")]
    [TestCase(SizeScale.Kilobytes, "KB")]
    public void Validate_SizeScale_Abbreviation(SizeScale inputScale, string expectedAbbreviation)
    {
        Assert.AreEqual(expectedAbbreviation, inputScale.Abbreviation());
    }
}


First, notice that the Category attribute can be used at a class level and applies to all tests within the class. Secondly, notice that because I'm supplying the input and expected values to the test, the test itself becomes a one-liner, which is the common method call.

Test Naming

This may be somewhat subjective, but I don't find your test names particularly intuitive. It's not obvious to me from the name what Subtract_2_SizeScale_Bytes_1_SizeScale_Bytes tests. It turns out it's testing that when 1 is subtracted from 2, it results in 1. So your naming convention seems to be something like:

__SizeScale___SizeScale_


Is the SizeScale_ actually relevant to the test (are you testing subtraction, or subtraction for specific scales?) I think the bit that's missing for me (and is the mostly subjective bit) is that your name doesn't specify an expectation. So instead of Subtract_1_From_2_ShouldEqual_1 I have to read the test to figure out what the expectation is.

Code Snippets

[TestFixture, Category("Size Scale Tests")]
public class SizeScaleTests
{
    [TestCase(SizeScale.None, null)]
    [TestCase(SizeScale.Bytes, "B")]
    [TestCase(SizeScale.Bits, "b")]
    [TestCase(SizeScale.Kilobytes, "KB")]
    public void Validate_SizeScale_Abbreviation(SizeScale inputScale, string expectedAbbreviation)
    {
        Assert.AreEqual(expectedAbbreviation, inputScale.Abbreviation());
    }
}
<ActionToTest>_<InputValue>_SizeScale_<Scale>_<Parameter2>_SizeScale_<Scale>

Context

StackExchange Code Review Q#140339, answer score: 3

Revisions (0)

No revisions yet.