356 lines
7.9 KiB
C#
356 lines
7.9 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using AMWD.Common.Packing.Ar;
|
||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||
|
||
namespace UnitTests.Common.Packing.Ar
|
||
{
|
||
[TestClass]
|
||
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
|
||
public class ArReaderTests
|
||
{
|
||
private readonly DateTime fixedDateTime = new(2023, 03, 01, 10, 20, 30, 0, DateTimeKind.Utc);
|
||
|
||
private Dictionary<string, ArFileInfo> files;
|
||
|
||
private Stream inStream;
|
||
|
||
[TestInitialize]
|
||
public void Initialize()
|
||
{
|
||
files = new Dictionary<string, ArFileInfo>
|
||
{
|
||
{
|
||
"abcd.tmp",
|
||
new ArFileInfo
|
||
{
|
||
FileName = "abcd.tmp",
|
||
FileSize = 14,
|
||
GroupId = 456,
|
||
Mode = 33188,
|
||
ModifyTime = fixedDateTime,
|
||
UserId = 123
|
||
}
|
||
},
|
||
{
|
||
"efgh.tmp",
|
||
new ArFileInfo
|
||
{
|
||
FileName = "efgh.tmp",
|
||
FileSize = 14,
|
||
GroupId = 456,
|
||
Mode = 33188,
|
||
ModifyTime = fixedDateTime,
|
||
UserId = 123
|
||
}
|
||
},
|
||
{
|
||
"ijkl.tmp",
|
||
new ArFileInfo
|
||
{
|
||
FileName = "ijkl.tmp",
|
||
FileSize = 13,
|
||
GroupId = 456,
|
||
Mode = 33188,
|
||
ModifyTime = fixedDateTime,
|
||
UserId = 123
|
||
}
|
||
}
|
||
};
|
||
|
||
inStream = new MemoryStream();
|
||
inStream.Write(Encoding.ASCII.GetBytes("!<arch>\n"));
|
||
|
||
foreach (var file in files)
|
||
{
|
||
int unixSeconds = (int)file.Value.ModifyTime.Subtract(DateTime.UnixEpoch).TotalSeconds;
|
||
|
||
inStream.Write(Encoding.ASCII.GetBytes($"{file.Key,-16}{unixSeconds,-12}123 456 100644 {file.Value.FileSize,-10}`\n"));
|
||
inStream.Write(Encoding.UTF8.GetBytes(new string('a', (int)file.Value.FileSize)));
|
||
if (file.Value.FileSize % 2 != 0)
|
||
inStream.Write(Encoding.ASCII.GetBytes("\n"));
|
||
}
|
||
|
||
inStream.Seek(0, SeekOrigin.Begin);
|
||
}
|
||
|
||
[TestCleanup]
|
||
public void Cleanup()
|
||
{
|
||
inStream.Dispose();
|
||
inStream = null;
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldInitializeArchive()
|
||
{
|
||
// Arrange
|
||
inStream.Dispose();
|
||
inStream = new MemoryStream();
|
||
inStream.Write(Encoding.ASCII.GetBytes("!<arch>\n"));
|
||
inStream.Seek(0, SeekOrigin.Begin);
|
||
|
||
// Act
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Assert
|
||
Assert.IsNotNull(reader);
|
||
Assert.IsFalse(reader.GetFileList().Any());
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldInitializeWithFiles()
|
||
{
|
||
// Arrange
|
||
|
||
// Act
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Assert
|
||
Assert.IsNotNull(reader);
|
||
Assert.IsTrue(reader.GetFileList().Any());
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldListFileNames()
|
||
{
|
||
// Arrange
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Act
|
||
var fileList = reader.GetFileList().ToList();
|
||
|
||
// Assert
|
||
Assert.IsNotNull(reader);
|
||
Assert.AreEqual(files.Count, fileList.Count);
|
||
|
||
foreach (string name in files.Keys)
|
||
Assert.IsTrue(fileList.Contains(name));
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldReturnValidFileInfo()
|
||
{
|
||
// Arrange
|
||
var infos = new List<ArFileInfo>();
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Act
|
||
foreach (string name in files.Keys)
|
||
infos.Add(reader.GetFileInfo(name));
|
||
|
||
// Assert
|
||
Assert.IsNotNull(reader);
|
||
Assert.AreEqual(files.Count, infos.Count);
|
||
|
||
foreach (var expected in files.Values)
|
||
{
|
||
var actual = infos.Single(fi => fi.FileName == expected.FileName);
|
||
|
||
Assert.AreEqual(expected.FileName, actual.FileName);
|
||
Assert.AreEqual(expected.FileSize, actual.FileSize);
|
||
Assert.AreEqual(expected.GroupId, actual.GroupId);
|
||
Assert.AreEqual(expected.Mode, actual.Mode);
|
||
Assert.AreEqual(expected.ModifyTime, actual.ModifyTime);
|
||
Assert.AreEqual(expected.UserId, actual.UserId);
|
||
}
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldReturnValidFileContent()
|
||
{
|
||
// Arrange
|
||
var contents = new Dictionary<string, string>();
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Act
|
||
foreach (string name in files.Keys)
|
||
{
|
||
using var ms = new MemoryStream();
|
||
reader.ReadFile(name, ms);
|
||
ms.Seek(0, SeekOrigin.Begin);
|
||
|
||
contents.Add(name, Encoding.UTF8.GetString(ms.ToArray()));
|
||
}
|
||
|
||
// Assert
|
||
Assert.IsNotNull(reader);
|
||
Assert.AreEqual(files.Count, contents.Count);
|
||
|
||
foreach (var expected in files.Values)
|
||
{
|
||
string content = contents[expected.FileName];
|
||
|
||
if (expected.FileSize % 2 != 0)
|
||
Assert.AreEqual(13, content.Length);
|
||
else
|
||
Assert.AreEqual(14, content.Length);
|
||
|
||
Assert.AreEqual(new string('a', (int)expected.FileSize), content);
|
||
}
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldWriteFileToDisk()
|
||
{
|
||
// Arrange
|
||
string tmpFile = Path.GetTempFileName();
|
||
var reader = new ArReader(inStream);
|
||
|
||
try
|
||
{
|
||
// Act
|
||
using var ms = new MemoryStream();
|
||
|
||
reader.ReadFile("abcd.tmp", ms);
|
||
reader.ReadFile("abcd.tmp", tmpFile);
|
||
|
||
// Assert
|
||
CollectionAssert.AreEqual(ms.ToArray(), File.ReadAllBytes(tmpFile));
|
||
}
|
||
finally
|
||
{
|
||
File.Delete(tmpFile);
|
||
}
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentException))]
|
||
public void ShouldThrowExceptionOnMissingRead()
|
||
{
|
||
// Arrange
|
||
using var stream = new OverrideStream();
|
||
stream.CanReadOR = false;
|
||
stream.CanSeekOR = true;
|
||
stream.CanWriteOR = true;
|
||
|
||
// Act
|
||
var reader = new ArReader(stream);
|
||
|
||
// Assert - ArgumentException
|
||
Assert.Fail();
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentException))]
|
||
public void ShouldThrowExceptionOnMissingSeek()
|
||
{
|
||
// Arrange
|
||
using var stream = new OverrideStream();
|
||
stream.CanReadOR = true;
|
||
stream.CanSeekOR = false;
|
||
stream.CanWriteOR = true;
|
||
|
||
// Act
|
||
var reader = new ArReader(stream);
|
||
|
||
// Assert - ArgumentException
|
||
Assert.Fail();
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(ArgumentException))]
|
||
public void ShouldThrowExceptionOnMissingWrite()
|
||
{
|
||
// Arrange
|
||
using var stream = new OverrideStream();
|
||
stream.CanReadOR = true;
|
||
stream.CanSeekOR = true;
|
||
stream.CanWriteOR = false;
|
||
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Act
|
||
reader.ReadFile("abcd.tmp", stream);
|
||
|
||
// Assert - ArgumentException
|
||
Assert.Fail();
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(FormatException))]
|
||
public void ShouldThrowExceptionOnInvalidArchive()
|
||
{
|
||
// Arrange
|
||
inStream.Seek(8, SeekOrigin.Begin);
|
||
|
||
// Act
|
||
_ = new ArReader(inStream);
|
||
|
||
// Assert - FormatException
|
||
Assert.Fail();
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(FormatException))]
|
||
public void ShouldThrowExceptionOnInvalidMagic()
|
||
{
|
||
// Arrange
|
||
inStream.Seek(0, SeekOrigin.End);
|
||
inStream.Write(Encoding.ASCII.GetBytes($"{"foo.bar",-16}{"123456789",-12}123 456 100644 {"0",-10}´\n"));
|
||
inStream.Seek(0, SeekOrigin.Begin);
|
||
|
||
// Act
|
||
_ = new ArReader(inStream);
|
||
|
||
// Assert - FormatException
|
||
Assert.Fail();
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldWriteNothingToStreamForMissingFile()
|
||
{
|
||
// Arrange
|
||
var reader = new ArReader(inStream);
|
||
|
||
// Act
|
||
using var ms = new MemoryStream();
|
||
|
||
reader.ReadFile("foo.bar", ms);
|
||
ms.Seek(0, SeekOrigin.Begin);
|
||
|
||
// Assert
|
||
Assert.AreEqual(0, ms.Length);
|
||
}
|
||
|
||
[TestMethod]
|
||
public void ShouldWriteNothingToDiskForMissingFile()
|
||
{
|
||
// Arrange
|
||
string tmpFile = Path.GetTempFileName();
|
||
var reader = new ArReader(inStream);
|
||
|
||
try
|
||
{
|
||
// Act
|
||
reader.ReadFile("foo.bar", tmpFile);
|
||
|
||
// Assert
|
||
Assert.AreEqual(0, new FileInfo(tmpFile).Length);
|
||
}
|
||
finally
|
||
{
|
||
File.Delete(tmpFile);
|
||
}
|
||
}
|
||
|
||
private class OverrideStream : MemoryStream
|
||
{
|
||
public override bool CanWrite => CanWriteOR;
|
||
|
||
public bool CanWriteOR { get; set; }
|
||
|
||
public override bool CanSeek => CanSeekOR;
|
||
|
||
public bool CanSeekOR { get; set; }
|
||
|
||
public override bool CanRead => CanReadOR;
|
||
|
||
public bool CanReadOR { get; set; }
|
||
}
|
||
}
|
||
}
|