Even better objects #39

Merged
mahalex merged 10 commits from dev/even-better-objects into master 2025-04-14 19:03:42 +00:00
14 changed files with 236 additions and 358 deletions
Showing only changes of commit 1822e75fd8 - Show all commits

View File

@ -18,6 +18,8 @@ dotnet_analyzer_diagnostic.category-Usage.severity = warning
dotnet_diagnostic.IDE0010.severity = none
dotnet_diagnostic.IDE0072.severity = none
dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA1861.severity = none
#### Core EditorConfig Options ####

View File

@ -1,68 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MatFileHandler.Tests
{
/// <summary>
/// Abstract factory of test data.
/// </summary>
/// <typeparam name="TTestData">Type of test data.</typeparam>
public abstract class AbstractTestDataFactory<TTestData>
{
/// <summary>
/// Initializes a new instance of the <see cref="AbstractTestDataFactory{TTestData}"/> class.
/// </summary>
/// <param name="dataDirectory">Directory with test files.</param>
/// <param name="testFilenameConvention">A convention used to filter test files.</param>
protected AbstractTestDataFactory(string dataDirectory, ITestFilenameConvention testFilenameConvention)
{
DataDirectory = dataDirectory;
TestFilenameConvention = testFilenameConvention;
}
private string DataDirectory { get; }
private ITestFilenameConvention TestFilenameConvention { get; }
/// <summary>
/// Get test data set by name.
/// </summary>
/// <param name="dataSet">Name of the data set.</param>
/// <returns>Test data.</returns>
public TTestData this[string dataSet] =>
ReadTestData(FixPath(TestFilenameConvention.ConvertTestNameToFilename(dataSet)));
/// <summary>
/// Get a sequence of all test data sets in the factory.
/// </summary>
/// <returns>A sequence of data sets.</returns>
public IEnumerable<TTestData> GetAllTestData()
{
var files = Directory.EnumerateFiles(DataDirectory).Where(TestFilenameConvention.FilterFile);
foreach (var filename in files)
{
yield return ReadTestData(filename);
}
}
/// <summary>
/// Read test data from a stream.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <returns>Test data.</returns>
protected abstract TTestData ReadDataFromStream(Stream stream);
private string FixPath(string filename) => Path.Combine(DataDirectory, filename);
private TTestData ReadTestData(string filename)
{
using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
return ReadDataFromStream(stream);
}
}
}
}

View File

@ -17,50 +17,48 @@ namespace MatFileHandler.Tests
/// <summary>
/// Test writing various things.
/// </summary>
/// <param name="action"></param>
/// <param name="bytes">Bytes to write.</param>
[Theory]
[MemberData(nameof(TestData))]
public void Test(Action<Stream> action)
public void Test(byte[] bytes)
{
using var stream = new MemoryStream();
var sut = new ChecksumCalculatingStream(stream);
action(sut);
sut.Write(bytes, 0, bytes.Length);
var actual = sut.GetCrc();
var expected = ReferenceCalculation(action);
var expected = ReferenceCalculation(bytes);
}
/// <summary>
/// Test data for <see cref="Test"/>.
/// </summary>
/// <returns>Test data.</returns>
public static IEnumerable<object[]> TestData()
public static TheoryData<byte[]> TestData()
{
foreach (var data in TestData_Typed())
var empty = new byte[1234];
var nonEmpty = new byte[12345];
for (var i = 0; i < 1234; i++)
{
yield return new object[] { data };
nonEmpty[i] = (byte)((i * i) % 256);
}
}
private static IEnumerable<Action<Stream>> TestData_Typed()
return new TheoryData<byte[]>()
{
yield return BinaryWriterAction(w => w.Write(true));
yield return BinaryWriterAction(w => w.Write(false));
yield return BinaryWriterAction(w => w.Write(byte.MinValue));
yield return BinaryWriterAction(w => w.Write(byte.MaxValue));
yield return BinaryWriterAction(w => w.Write(short.MinValue));
yield return BinaryWriterAction(w => w.Write(short.MaxValue));
yield return BinaryWriterAction(w => w.Write(int.MinValue));
yield return BinaryWriterAction(w => w.Write(int.MaxValue));
yield return BinaryWriterAction(w => w.Write(long.MinValue));
yield return BinaryWriterAction(w => w.Write(long.MaxValue));
yield return BinaryWriterAction(w => w.Write(decimal.MinValue));
yield return BinaryWriterAction(w => w.Write(decimal.MaxValue));
yield return BinaryWriterAction(w => w.Write(double.MinValue));
yield return BinaryWriterAction(w => w.Write(double.MaxValue));
yield return BinaryWriterAction(w => w.Write(double.PositiveInfinity));
yield return BinaryWriterAction(w => w.Write(double.NaN));
yield return BinaryWriterAction(w => w.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7 }));
yield return BinaryWriterAction(w => w.Write(Enumerable.Range(0, 255).SelectMany(x => Enumerable.Range(0, 255)).Select(x => (byte)x).ToArray()));
new byte[] { 0x00 },
new byte[] { 0x01 },
new byte[] { 0xff },
new byte[] { 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
new byte[] { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
new byte[] { 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, 0x17, 0x1d },
empty,
nonEmpty,
};
}
private static Action<Stream> BinaryWriterAction(Action<BinaryWriter> action)
@ -72,15 +70,15 @@ namespace MatFileHandler.Tests
};
}
private uint ReferenceCalculation(Action<Stream> action)
private static uint ReferenceCalculation(byte[] bytes)
{
using var stream = new MemoryStream();
action(stream);
stream.Write(bytes, 0, bytes.Length);
stream.Position = 0;
return CalculateAdler32Checksum(stream);
}
private static uint CalculateAdler32Checksum(Stream stream)
private static uint CalculateAdler32Checksum(MemoryStream stream)
{
uint s1 = 1;
uint s2 = 0;

View File

@ -1,43 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// A filename convention based on file extensions.
/// </summary>
internal sealed class ExtensionTestFilenameConvention : ITestFilenameConvention
{
/// <summary>
/// Initializes a new instance of the <see cref="ExtensionTestFilenameConvention"/> class.
/// </summary>
/// <param name="extension">File extension.</param>
public ExtensionTestFilenameConvention(string extension)
{
Extension = extension;
}
private string Extension { get; }
/// <summary>
/// Convert test name to filename by adding the extension.
/// </summary>
/// <param name="testName">Test name.</param>
/// <returns>The corresponding filename.</returns>
public string ConvertTestNameToFilename(string testName)
{
return Path.ChangeExtension(testName, Extension);
}
/// <summary>
/// Compare file's extension to the one specified during initialization.
/// </summary>
/// <param name="filename">Filename.</param>
/// <returns>True iff the file has the extension stored in the class.</returns>
public bool FilterFile(string filename)
{
return Path.GetExtension(filename) == "." + Extension;
}
}
}

View File

@ -1,24 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler.Tests
{
/// <summary>
/// Interface for handling filtering tests based on filenames.
/// </summary>
public interface ITestFilenameConvention
{
/// <summary>
/// Convert test name to a filename (e.g., by adding an appropriate extension).
/// </summary>
/// <param name="testName">Name of a test.</param>
/// <returns>Filename.</returns>
string ConvertTestNameToFilename(string testName);
/// <summary>
/// Decide if a file contains a test based on the filename.
/// </summary>
/// <param name="filename">A filename.</param>
/// <returns>True iff the file should contain a test.</returns>
bool FilterFile(string filename);
}
}

View File

@ -1,6 +1,7 @@
// Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
@ -19,9 +20,9 @@ namespace MatFileHandler.Tests
/// Test reading all files in a given test set.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestReader(AbstractTestDataFactory<IMatFile> testFactory)
public void TestReader(MatFileReadingMethod method)
{
foreach (var matFile in testFactory.GetAllTestData())
foreach (var matFile in ReadAllTestFiles(method))
{
Assert.NotEmpty(matFile.Variables);
}
@ -31,9 +32,9 @@ namespace MatFileHandler.Tests
/// Test reading lower and upper limits of integer data types.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestLimits(AbstractTestDataFactory<IMatFile> testFactory)
public void TestLimits(MatFileReadingMethod method)
{
var matFile = testFactory["limits"];
var matFile = ReadTestFile("limits", method);
IArray array;
array = matFile["int8_"].Value;
CheckLimits(array as IArrayOf<sbyte>, CommonData.Int8Limits);
@ -65,9 +66,9 @@ namespace MatFileHandler.Tests
/// Test writing lower and upper limits of integer-based complex data types.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestComplexLimits(AbstractTestDataFactory<IMatFile> testFactory)
public void TestComplexLimits(MatFileReadingMethod method)
{
var matFile = testFactory["limits_complex"];
var matFile = ReadTestFile("limits_complex", method);
IArray array;
array = matFile["int8_complex"].Value;
CheckComplexLimits(array as IArrayOf<ComplexOf<sbyte>>, CommonData.Int8Limits);
@ -101,9 +102,9 @@ namespace MatFileHandler.Tests
/// Test reading an ASCII-encoded string.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestAscii(AbstractTestDataFactory<IMatFile> testFactory)
public void TestAscii(MatFileReadingMethod method)
{
var matFile = testFactory["ascii"];
var matFile = ReadTestFile("ascii", method);
var arrayAscii = matFile["s"].Value as ICharArray;
Assert.NotNull(arrayAscii);
Assert.Equal(new[] { 1, 3 }, arrayAscii.Dimensions);
@ -115,9 +116,9 @@ namespace MatFileHandler.Tests
/// Test reading a Unicode string.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestUnicode(AbstractTestDataFactory<IMatFile> testFactory)
public void TestUnicode(MatFileReadingMethod method)
{
var matFile = testFactory["unicode"];
var matFile = ReadTestFile("unicode", method);
var arrayUnicode = matFile["s"].Value as ICharArray;
Assert.NotNull(arrayUnicode);
Assert.Equal(new[] { 1, 2 }, arrayUnicode.Dimensions);
@ -130,9 +131,9 @@ namespace MatFileHandler.Tests
/// Test reading a wide Unicode string.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestUnicodeWide(AbstractTestDataFactory<IMatFile> testFactory)
public void TestUnicodeWide(MatFileReadingMethod method)
{
var matFile = testFactory["unicode-wide"];
var matFile = ReadTestFile("unicode-wide", method);
var arrayUnicodeWide = matFile["s"].Value as ICharArray;
Assert.NotNull(arrayUnicodeWide);
Assert.Equal(new[] { 1, 2 }, arrayUnicodeWide.Dimensions);
@ -143,9 +144,9 @@ namespace MatFileHandler.Tests
/// Test converting a structure array to a Double array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestConvertToDoubleArray(AbstractTestDataFactory<IMatFile> testFactory)
public void TestConvertToDoubleArray(MatFileReadingMethod method)
{
var matFile = testFactory["struct"];
var matFile = ReadTestFile("struct", method);
var array = matFile.Variables[0].Value;
Assert.Null(array.ConvertToDoubleArray());
}
@ -155,9 +156,9 @@ namespace MatFileHandler.Tests
/// </summary>
/// <returns>Should return null.</returns>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestConvertToComplexArray(AbstractTestDataFactory<IMatFile> testFactory)
public void TestConvertToComplexArray(MatFileReadingMethod method)
{
var matFile = testFactory["struct"];
var matFile = ReadTestFile("struct", method);
var array = matFile.Variables[0].Value;
Assert.Null(array.ConvertToComplexArray());
}
@ -166,9 +167,9 @@ namespace MatFileHandler.Tests
/// Test reading an enumeration.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestEnum(AbstractTestDataFactory<IMatFile> testFactory)
public void TestEnum(MatFileReadingMethod method)
{
var matFile = testFactory["enum"];
var matFile = ReadTestFile("enum", method);
var days = matFile["days"].Value;
var enumeration = new EnumAdapter(days);
Assert.Equal(5, enumeration.Values.Count);
@ -183,9 +184,9 @@ namespace MatFileHandler.Tests
/// Test reading a structure array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestStruct(AbstractTestDataFactory<IMatFile> testFactory)
public void TestStruct(MatFileReadingMethod method)
{
var matFile = testFactory["struct"];
var matFile = ReadTestFile("struct", method);
var structure = matFile["struct_"].Value as IStructureArray;
Assert.NotNull(structure);
Assert.Equal(new[] { "x", "y" }, structure.FieldNames);
@ -237,9 +238,9 @@ namespace MatFileHandler.Tests
/// Test reading a sparse array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestSparse(AbstractTestDataFactory<IMatFile> testFactory)
public void TestSparse(MatFileReadingMethod method)
{
var matFile = testFactory["sparse"];
var matFile = ReadTestFile("sparse", method);
var sparseArray = matFile["sparse_"].Value as ISparseArrayOf<double>;
Assert.NotNull(sparseArray);
Assert.Equal(new[] { 4, 5 }, sparseArray.Dimensions);
@ -267,9 +268,9 @@ namespace MatFileHandler.Tests
/// Test reading a logical array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestLogical(AbstractTestDataFactory<IMatFile> testFactory)
public void TestLogical(MatFileReadingMethod method)
{
var matFile = testFactory["logical"];
var matFile = ReadTestFile("logical", method);
var array = matFile["logical_"].Value;
var logicalArray = array as IArrayOf<bool>;
Assert.NotNull(logicalArray);
@ -285,9 +286,9 @@ namespace MatFileHandler.Tests
/// Test reading a sparse logical array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestSparseLogical(AbstractTestDataFactory<IMatFile> testFactory)
public void TestSparseLogical(MatFileReadingMethod method)
{
var matFile = testFactory["sparse_logical"];
var matFile = ReadTestFile("sparse_logical", method);
var array = matFile["sparse_logical"].Value;
var sparseArray = array as ISparseArrayOf<bool>;
Assert.NotNull (sparseArray);
@ -304,9 +305,9 @@ namespace MatFileHandler.Tests
/// Test reading a global variable.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestGlobal(AbstractTestDataFactory<IMatFile> testFactory)
public void TestGlobal(MatFileReadingMethod method)
{
var matFile = testFactory["global"];
var matFile = ReadTestFile("global", method);
var variable = matFile.Variables.First();
Assert.True(variable.IsGlobal);
}
@ -315,9 +316,9 @@ namespace MatFileHandler.Tests
/// Test reading a sparse complex array.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TextSparseComplex(AbstractTestDataFactory<IMatFile> testFactory)
public void TextSparseComplex(MatFileReadingMethod method)
{
var matFile = testFactory["sparse_complex"];
var matFile = ReadTestFile("sparse_complex", method);
var array = matFile["sparse_complex"].Value;
var sparseArray = array as ISparseArrayOf<Complex>;
Assert.NotNull(sparseArray);
@ -331,9 +332,9 @@ namespace MatFileHandler.Tests
/// Test reading an object.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestObject(AbstractTestDataFactory<IMatFile> testFactory)
public void TestObject(MatFileReadingMethod method)
{
var matFile = testFactory["object"];
var matFile = ReadTestFile("object", method);
var obj = matFile["object_"].Value as IMatObject;
Assert.NotNull(obj);
Assert.Equal("Point", obj.ClassName);
@ -348,9 +349,9 @@ namespace MatFileHandler.Tests
/// Test reading another object.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestObject2(AbstractTestDataFactory<IMatFile> testFactory)
public void TestObject2(MatFileReadingMethod method)
{
var matFile = testFactory["object2"];
var matFile = ReadTestFile("object2", method);
var obj = matFile["object2"].Value as IMatObject;
Assert.NotNull(obj);
Assert.Equal("Point", obj.ClassName);
@ -371,9 +372,9 @@ namespace MatFileHandler.Tests
/// Test reading a table.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestTable(AbstractTestDataFactory<IMatFile> testFactory)
public void TestTable(MatFileReadingMethod method)
{
var matFile = testFactory["table"];
var matFile = ReadTestFile("table", method);
var obj = matFile["table_"].Value as IMatObject;
var table = new TableAdapter(obj);
Assert.Equal(3, table.NumberOfRows);
@ -392,9 +393,9 @@ namespace MatFileHandler.Tests
/// Test reading a deeply nested table.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestDeepTable(AbstractTestDataFactory<IMatFile> testFactory)
public void TestDeepTable(MatFileReadingMethod method)
{
var matFile = testFactory["table-deep"];
var matFile = ReadTestFile("table-deep", method);
var obj = matFile["t"].Value as IMatObject;
var table = new TableAdapter(obj);
Assert.Equal(1, table.NumberOfRows);
@ -416,9 +417,9 @@ namespace MatFileHandler.Tests
/// Test reading a table with strings
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestTableWithStrings(AbstractTestDataFactory<IMatFile> testFactory)
public void TestTableWithStrings(MatFileReadingMethod method)
{
var matFile = testFactory["table-with-strings"];
var matFile = ReadTestFile("table-with-strings", method);
var obj = matFile["t"].Value as IMatObject;
var table = new TableAdapter(obj);
Assert.Equal(5, table.NumberOfRows);
@ -441,9 +442,9 @@ namespace MatFileHandler.Tests
/// Test subobjects within objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestSubobjects(AbstractTestDataFactory<IMatFile> testFactory)
public void TestSubobjects(MatFileReadingMethod method)
{
var matFile = testFactory["pointWithSubpoints"];
var matFile = ReadTestFile("pointWithSubpoints", method);
var p = matFile["p"].Value as IMatObject;
Assert.Equal("Point", p.ClassName);
var x = p["x"] as IMatObject;
@ -464,9 +465,9 @@ namespace MatFileHandler.Tests
/// Test nested objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestNestedObjects(AbstractTestDataFactory<IMatFile> testFactory)
public void TestNestedObjects(MatFileReadingMethod method)
{
var matFile = testFactory["subsubPoint"];
var matFile = ReadTestFile("subsubPoint", method);
var p = matFile["p"].Value as IMatObject;
Assert.Equal("Point", p.ClassName);
Assert.Equal(new[] { 1.0 }, p["x"].ConvertToDoubleArray());
@ -482,9 +483,9 @@ namespace MatFileHandler.Tests
/// Test datetime objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestDatetime(AbstractTestDataFactory<IMatFile> testFactory)
public void TestDatetime(MatFileReadingMethod method)
{
var matFile = testFactory["datetime"];
var matFile = ReadTestFile("datetime", method);
var d = matFile["d"].Value as IMatObject;
var datetime = new DatetimeAdapter(d);
Assert.Equal(new[] { 1, 2 }, datetime.Dimensions);
@ -496,9 +497,9 @@ namespace MatFileHandler.Tests
/// Another test for datetime objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestDatetime2(AbstractTestDataFactory<IMatFile> testFactory)
public void TestDatetime2(MatFileReadingMethod method)
{
var matFile = testFactory["datetime2"];
var matFile = ReadTestFile("datetime2", method);
var d = matFile["d"].Value as IMatObject;
var datetime = new DatetimeAdapter(d);
Assert.Equal(new[] { 1, 1 }, datetime.Dimensions);
@ -511,9 +512,9 @@ namespace MatFileHandler.Tests
/// Test string objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestString(AbstractTestDataFactory<IMatFile> testFactory)
public void TestString(MatFileReadingMethod method)
{
var matFile = testFactory["string"];
var matFile = ReadTestFile("string", method);
var s = matFile["s"].Value as IMatObject;
var str = new StringAdapter(s);
Assert.Equal(new[] { 4, 1 }, str.Dimensions);
@ -527,9 +528,9 @@ namespace MatFileHandler.Tests
/// Test duration objects.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestDuration(AbstractTestDataFactory<IMatFile> testFactory)
public void TestDuration(MatFileReadingMethod method)
{
var matFile = testFactory["duration"];
var matFile = ReadTestFile("duration", method);
var d = matFile["d"].Value as IMatObject;
var duration = new DurationAdapter(d);
Assert.Equal(new[] { 1, 3 }, duration.Dimensions);
@ -542,9 +543,9 @@ namespace MatFileHandler.Tests
/// Test unrepresentable datetime.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void TestDatetime_Unrepresentable(AbstractTestDataFactory<IMatFile> testFactory)
public void TestDatetime_Unrepresentable(MatFileReadingMethod method)
{
var matFile = testFactory["datetime-unrepresentable"];
var matFile = ReadTestFile("datetime-unrepresentable", method);
var obj = matFile["d"].Value as IMatObject;
var datetime = new DatetimeAdapter(obj);
var d0 = datetime[0];
@ -555,9 +556,9 @@ namespace MatFileHandler.Tests
/// Test 3-dimensional arrays.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void Test_3DArrays(AbstractTestDataFactory<IMatFile> testFactory)
public void Test_3DArrays(MatFileReadingMethod method)
{
var matFile = testFactory["issue20.mat"];
var matFile = ReadTestFile("issue20", method);
var obj = matFile["a3d"].Value;
var values = obj.ConvertToDoubleArray();
Assert.Equal(Enumerable.Range(1, 24).Select(x => (double)x).ToArray(), values);
@ -590,9 +591,9 @@ namespace MatFileHandler.Tests
/// Test four-dimensional arrays.
/// </summary>
[Theory, MemberData(nameof(TestDataFactories))]
public void Test4DArrays(AbstractTestDataFactory<IMatFile> testFactory)
public void Test4DArrays(MatFileReadingMethod method)
{
var matFile = testFactory["issue20.mat"];
var matFile = ReadTestFile("issue20", method);
var obj = matFile["a4d"].Value;
Assert.Equal(Enumerable.Range(1, 120).Select(x => (double)x).ToArray(), obj.ConvertToDoubleArray());
Assert.Null(obj.ConvertTo2dDoubleArray());
@ -601,19 +602,36 @@ namespace MatFileHandler.Tests
/// <summary>
/// Returns the factories that provide test data in various configurations.
/// </summary>
public static TheoryData<AbstractTestDataFactory<IMatFile>> TestDataFactories
public static TheoryData<MatFileReadingMethod> TestDataFactories
{
get
{
return new TheoryData<AbstractTestDataFactory<IMatFile>>
return new TheoryData<MatFileReadingMethod>
{
new MatTestDataFactory(Path.Combine(TestDirectory, "good")),
new PartialReadMatTestDataFactory(Path.Combine(TestDirectory, "good")),
new UnalignedMatTestDataFactory(Path.Combine(TestDirectory, "good")),
MatFileReadingMethod.NormalStream,
MatFileReadingMethod.PartialStream,
MatFileReadingMethod.UnalignedStream,
};
}
}
private static IMatFile ReadTestFile(string fileName, MatFileReadingMethod method)
{
var fullFileName = Path.Combine("test-data", "good", $"{fileName}.mat");
return MatFileReadingMethods.ReadMatFile(method, fullFileName);
}
private static IEnumerable<IMatFile> ReadAllTestFiles(MatFileReadingMethod method)
{
foreach (var fileName in Directory.EnumerateFiles(
Path.Combine("test-data", "good"),
"*.mat"))
{
var fullFileName = fileName;
yield return MatFileReadingMethods.ReadMatFile(method, fullFileName);
}
}
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
where T : struct
{

View File

@ -0,0 +1,29 @@
// Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler.Tests;
/// <summary>
/// Method of reading .mat files for testing.
/// </summary>
public enum MatFileReadingMethod
{
/// <summary>
/// Undefined.
/// </summary>
Undefined = 0,
/// <summary>
/// Normal stream (like memory or file stream).
/// </summary>
NormalStream,
/// <summary>
/// Partial stream (only is capable of reading one byte at a time).
/// </summary>
PartialStream,
/// <summary>
/// Unaligned stream (what happens if the data don't start at the beginning?).
/// </summary>
UnalignedStream,
}

View File

@ -0,0 +1,38 @@
using System;
using System.IO;
namespace MatFileHandler.Tests;
internal static class MatFileReadingMethods
{
public static IMatFile ReadMatFile(MatFileReadingMethod method, string fullFileName)
{
using var stream = File.OpenRead(fullFileName);
switch (method)
{
case MatFileReadingMethod.NormalStream:
return ReadFromStream(stream);
case MatFileReadingMethod.PartialStream:
{
using var wrapper = new PartialUnseekableReadStream(stream);
return ReadFromStream(wrapper);
}
case MatFileReadingMethod.UnalignedStream:
{
using var ms = new MemoryStream();
ms.Seek(3, SeekOrigin.Begin);
stream.CopyTo(ms);
ms.Seek(3, SeekOrigin.Begin);
return ReadFromStream(ms);
}
default:
throw new NotImplementedException();
}
}
private static IMatFile ReadFromStream(Stream stream)
{
var reader = new MatFileReader(stream);
return reader.Read();
}
}

View File

@ -1,9 +1,27 @@
namespace MatFileHandler.Tests;
/// <summary>
/// Options to give to MatFileWriter constructor for testing it.
/// </summary>
public enum MatFileWriterOptionsForTests
{
/// <summary>
/// Undefined.
/// </summary>
Undefined = 0,
/// <summary>
/// No options.
/// </summary>
None,
/// <summary>
/// Option to always use compression.
/// </summary>
Always,
/// <summary>
/// Option to never use compression.
/// </summary>
Never,
}

View File

@ -247,10 +247,7 @@ namespace MatFileHandler.Tests
}
}
private static AbstractTestDataFactory<IMatFile> GetMatTestData(string factoryName) =>
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
private void CompareSparseArrays<T>(ISparseArrayOf<T> expected, ISparseArrayOf<T> actual)
private static void CompareSparseArrays<T>(ISparseArrayOf<T> expected, ISparseArrayOf<T> actual)
where T : struct
{
Assert.NotNull(actual);
@ -258,7 +255,7 @@ namespace MatFileHandler.Tests
Assert.Equal(expected.Data, actual.Data);
}
private void CompareStructureArrays(IStructureArray expected, IStructureArray actual)
private static void CompareStructureArrays(IStructureArray expected, IStructureArray actual)
{
Assert.NotNull(actual);
Assert.Equal(expected.Dimensions, actual.Dimensions);
@ -272,7 +269,7 @@ namespace MatFileHandler.Tests
}
}
private void CompareCellArrays(ICellArray expected, ICellArray actual)
private static void CompareCellArrays(ICellArray expected, ICellArray actual)
{
Assert.NotNull(actual);
Assert.Equal(expected.Dimensions, actual.Dimensions);
@ -282,21 +279,21 @@ namespace MatFileHandler.Tests
}
}
private void CompareNumericalArrays<T>(IArrayOf<T> expected, IArrayOf<T> actual)
private static void CompareNumericalArrays<T>(IArrayOf<T> expected, IArrayOf<T> actual)
{
Assert.NotNull(actual);
Assert.Equal(expected.Dimensions, actual.Dimensions);
Assert.Equal(expected.Data, actual.Data);
}
private void CompareCharArrays(ICharArray expected, ICharArray actual)
private static void CompareCharArrays(ICharArray expected, ICharArray actual)
{
Assert.NotNull(actual);
Assert.Equal(expected.Dimensions, actual.Dimensions);
Assert.Equal(expected.String, actual.String);
}
private void CompareMatArrays(IArray expected, IArray actual)
private static void CompareMatArrays(IArray expected, IArray actual)
{
switch (expected)
{
@ -387,7 +384,7 @@ namespace MatFileHandler.Tests
throw new NotSupportedException();
}
private void CompareMatFiles(IMatFile expected, IMatFile actual)
private static void CompareMatFiles(IMatFile expected, IMatFile actual)
{
Assert.Equal(expected.Variables.Length, actual.Variables.Length);
for (var i = 0; i < expected.Variables.Length; i++)
@ -400,14 +397,17 @@ namespace MatFileHandler.Tests
}
}
private void MatCompareWithTestData(
private static void MatCompareWithTestData(
string factoryName,
string testName,
IMatFile actual,
MatFileWritingMethod method,
MatFileWriterOptionsForTests options)
{
var expected = GetMatTestData(factoryName)[testName];
var fullFileName = Path.Combine("test-data", "good", $"{testName}.mat");
var expected = MatFileReadingMethods.ReadMatFile(
MatFileReadingMethod.NormalStream,
fullFileName);
var buffer = MatFileWritingMethods.WriteMatFile(method, options, actual);
using var stream = new MemoryStream(buffer);
var reader = new MatFileReader(stream);
@ -415,7 +415,7 @@ namespace MatFileHandler.Tests
CompareMatFiles(expected, actualRead);
}
private ComplexOf<T>[] CreateComplexLimits<T>(T[] limits)
private static ComplexOf<T>[] CreateComplexLimits<T>(T[] limits)
where T : struct
{
return new[] { new ComplexOf<T>(limits[0], limits[1]), new ComplexOf<T>(limits[1], limits[0]) };

View File

@ -1,12 +1,29 @@
// Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler.Tests
{
namespace MatFileHandler.Tests;
/// <summary>
/// Method of writing .mat files for testing.
/// </summary>
public enum MatFileWritingMethod
{
Undefined,
/// <summary>
/// Undefined.
/// </summary>
Undefined = 0,
/// <summary>
/// Normal stream (like memory or file stream).
/// </summary>
NormalStream,
/// <summary>
/// A stream that cannot be seeked (like a deflate stream).
/// </summary>
UnseekableStream,
/// <summary>
/// Unaligned stream (what happens if the data don't start at the beginning?).
/// </summary>
UnalignedStream,
}
}

View File

@ -1,35 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// Factory providing the parsed contents of .mat files.
/// </summary>
public class MatTestDataFactory : AbstractTestDataFactory<IMatFile>
{
/// <summary>
/// Initializes a new instance of the <see cref="MatTestDataFactory"/> class.
/// </summary>
/// <param name="testDirectory">Directory containing test files.</param>
public MatTestDataFactory(string testDirectory)
: base(
testDirectory,
new ExtensionTestFilenameConvention("mat"))
{
}
/// <summary>
/// Read and parse data from a .mat file.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <returns>Parsed contents of the file.</returns>
protected override IMatFile ReadDataFromStream(Stream stream)
{
var matFileReader = new MatFileReader(stream);
var matFile = matFileReader.Read();
return matFile;
}
}
}

View File

@ -1,35 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// Factory providing the parsed contents of .mat files,
/// wrapped in a <see cref="PartialUnseekableReadStream"/>.
/// </summary>
public class PartialReadMatTestDataFactory : MatTestDataFactory
{
/// <summary>
/// Initializes a new instance of the <see cref="PartialReadMatTestDataFactory"/> class.
/// </summary>
/// <param name="testDirectory">Directory containing test files.</param>
public PartialReadMatTestDataFactory(string testDirectory)
: base(testDirectory)
{
}
/// <summary>
/// Read and parse data from a .mat file.
/// </summary>
/// <param name="stream">Input stream.</param>
/// <returns>Parsed contents of the file.</returns>
protected override IMatFile ReadDataFromStream(Stream stream)
{
using (var wrapper = new PartialUnseekableReadStream(stream))
{
return base.ReadDataFromStream(wrapper);
}
}
}
}

View File

@ -1,37 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// Factory providing the parsed contents of .mat files,
/// which start at a non-8 byte-aligned offset in the stream.
/// </summary>
public class UnalignedMatTestDataFactory : MatTestDataFactory
{
/// <summary>
/// Initializes a new instance of the <see cref="PartialReadMatTestDataFactory"/> class.
/// </summary>
/// <param name="testDirectory">Directory containing test files.</param>
public UnalignedMatTestDataFactory(string testDirectory)
: base(testDirectory)
{
}
/// <inheritdoc/>
protected override IMatFile ReadDataFromStream(Stream stream)
{
using (var ms = new MemoryStream())
{
ms.Seek(3, SeekOrigin.Begin);
stream.CopyTo(ms);
ms.Seek(3, SeekOrigin.Begin);
return base.ReadDataFromStream(ms);
}
}
}
}