How can I simulate an environment where BitConverter.IsLittleEndian is the opposite for my unit tests?
Asked Answered
D

1

8

I am using the two methods BitConverter.GetBytes and Array.Reverse to read and write binary data from a file due the endianness.

My unit tests are passing and the implementation seems fine.

How can I simulate an environment where BitConverter.IsLittleEndian is the opposite for my unit tests?

Diabetic answered 11/5, 2015 at 10:24 Comment(2)
Bwahahahahaha... You can't :-) But it is a great question! Even using Fakes, you would have to rewrite so many methods to simulate it...Trot
What you should do: create a wrapper class around BitConverter that accepts the parameter "required endianness" and has internal a flag containing the BitConverter.IsLittleEndian that can be "manipulated" externally by unit tests. This class implements all the needed methods of BitConverter, and if requiredEndianness == savedIsLittleEndian then it directy uses BitConverter, else it uses BitConverter + Array.Reverse. You write the unit tests for this class and live happy.Trot
T
4

To expand my comment: you'll need to use IoC (Inversion of Control) to inject a BitConverterEx instance where you need it. This class has a single "parameter": the endianness of the output byte[] that it will read/write.

In the end this problem is similar to the common problem "how can I mock DateTime.Now"

In the unit tests, instead of injecting a BitConverterEx you can inject the ManipulableBitConverterEx where you can control the processor flag. Or more correctly you should unit test independently the BitConverterEx and your classes, so that when you test your classes, you know that the results of BitConverterEx are correct.

public class BitConverterEx
{
    public bool ProcessorLittleEndian { get; protected set; }
    public bool DataLittleEndian { get; protected set; }

    public BitConverterEx(bool dataLittleEndian)
    {
        ProcessorLittleEndian = BitConverter.IsLittleEndian;
        DataLittleEndian = dataLittleEndian;
    }

    public byte[] GetBytes(int value)
    {
        byte[] bytes = BitConverter.GetBytes(value);

        if (DataLittleEndian != ProcessorLittleEndian)
        {
            Array.Reverse(bytes);
        }

        return bytes;
    }

    public int ToInt32(byte[] value, int startIndex)
    {
        if (DataLittleEndian == ProcessorLittleEndian)
        {
            return BitConverter.ToInt32(value, startIndex);
        }

        byte[] value2 = new byte[sizeof(int)];
        Array.Copy(value, startIndex, value2, 0, value2.Length);
        Array.Reverse(value2);
        return BitConverter.ToInt32(value2, 0);
    }
}

public class ManipulableBitConverterEx : BitConverterEx
{
    public ManipulableBitConverterEx(bool processorLittleEndian, bool dataLittleEndian)
        : base(dataLittleEndian)
    {
        ProcessorLittleEndian = processorLittleEndian;
    }
}

Note that if you need to reuse many times this class, Array.Reverse could be "slow". There are solutions to invert the endianness of data types that manipulate the single bytes using shift, or, xor, ...

Trot answered 11/5, 2015 at 10:50 Comment(1)
Thanks for the suggestion; I think that this is a great solution :)Diabetic

© 2022 - 2024 — McMap. All rights reserved.