Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/better validation #99

Merged
merged 2 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>true</WarningsAsErrors>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace MagicBytesValidator.CLI.Exceptions;

public class InvalidProgramCallException : Exception
{
}
5 changes: 5 additions & 0 deletions MagicBytesValidator.CLI/Imports.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Global using directives

global using MagicBytesValidator.CLI.Exceptions;
global using MagicBytesValidator.Services;
global using MagicBytesValidator.Services.Streams;
12 changes: 12 additions & 0 deletions MagicBytesValidator.CLI/MagicBytesValidator.CLI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
kevinmarvinmueller marked this conversation as resolved.
Show resolved Hide resolved

<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>exe</OutputType>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\MagicBytesValidator\MagicBytesValidator.csproj" />
</ItemGroup>

</Project>
83 changes: 83 additions & 0 deletions MagicBytesValidator.CLI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
namespace MagicBytesValidator.CLI;

public class Program
{
public static void Main()
{
Console.WriteLine();
kevinmarvinmueller marked this conversation as resolved.
Show resolved Hide resolved
var streamFileTypeProvider = GetStreamFileTypeProvider();

try
{
var path = LoadPathFromArgs();
var file = File.Open(path, FileMode.Open, FileAccess.Read);

var matches = streamFileTypeProvider
.FindAllMatchesAsync(file, CancellationToken.None)
.GetAwaiter()
.GetResult()
.ToList();

if (matches.Count == 0)
kevinmarvinmueller marked this conversation as resolved.
Show resolved Hide resolved
{
Console.WriteLine("No matches.");
return;
}

Console.WriteLine($"{"FileType",-10}| {"Extensions",-40}| {"MIME Types",-80}");
Console.WriteLine(new string('-', 130));

foreach (var match in matches)
{
var mimeTypeList = string.Join(", ", match.MimeTypes);
var extensionList = string.Join(", ", match.Extensions);

Console.WriteLine($"{match.GetType().Name,-10}| {extensionList,-40}| {mimeTypeList,-80}");
}

Console.WriteLine();
Console.WriteLine($"Unambiguous match: {(matches.Count == 1 ? "Yes" : "No")}");
}
catch (InvalidProgramCallException)
{
Console.Error.WriteLine(
"""
Usage: dotnet run -- [PATH]
PATH must point to an existing, readable file
""");
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("Error: File not found");
}
catch (Exception exception)
{
Console.Error.WriteLine(
"""
Error: Internal Exception.
This should not happen. Please file a GitHub issue with the stack trace attached:
""");
Console.Error.WriteLine(exception);
}
}

private static string LoadPathFromArgs()
{
var args = Environment.GetCommandLineArgs();
if (
args is not { Length: 2 }
|| args is not [_, var path]
|| string.IsNullOrWhiteSpace(path)
)
{
throw new InvalidProgramCallException();
}

return Path.GetFullPath(path);
}

private static StreamFileTypeProvider GetStreamFileTypeProvider()
{
return new StreamFileTypeProvider(new Mapping());
}
}
kevinmarvinmueller marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,70 +1,62 @@
using System.IO;
using System.Linq;
using FluentAssertions;
using MagicBytesValidator.Exceptions.Http;
using MagicBytesValidator.Formats;
using MagicBytesValidator.Services.Http;
using Microsoft.AspNetCore.Http;
using Xunit;
using MagicBytesValidator.Services.Http;

namespace MagicBytesValidator.Tests.Http;

public class FormFileTypeProviderTests
public class FindFileTypeForFormFile
{
[Fact]
public void Should_find_by_extension()
public async Task Should_find_by_extension()
{
var formFile = ProvideGifFile("trp.gif", "image/gif");

var sut = new FormFileTypeProvider();

var result = sut.FindFileTypeForFormFile(formFile);
var result = await sut.FindValidatedTypeAsync(formFile, null, CancellationToken.None);

result.Should().BeOfType<Gif>();
}

[Fact]
public void Should_find_by_content_type()
public async Task Should_find_by_content_type()
{
var formFile = ProvideGifFile(string.Empty, "image/gif");

var sut = new FormFileTypeProvider();

var result = sut.FindFileTypeForFormFile(formFile);
var result = await sut.FindValidatedTypeAsync(formFile, null, CancellationToken.None);

result.Should().BeOfType<Gif>();
}

[Fact]
public void Should_return_null_on_not_found()
public async Task Should_return_null_on_not_found()
{
var formFile = ProvideGifFile(string.Empty, "trp/nms");

var sut = new FormFileTypeProvider();

var result = sut.FindFileTypeForFormFile(formFile);
var result = await sut.FindValidatedTypeAsync(formFile, null, CancellationToken.None);

result.Should().BeNull();
}

[Fact]
public void Should_throw_on_mismatch()
public async Task Should_throw_on_mismatch()
{
var formFile = ProvideGifFile("trp.gif", "image/png");

var sut = new FormFileTypeProvider();

Assert.Throws<MimeTypeMismatchException>(() => sut.FindFileTypeForFormFile(formFile));
await Assert.ThrowsAsync<MimeTypeMismatchException>(async () => await sut.FindValidatedTypeAsync(formFile, null, CancellationToken.None));
}

private static IFormFile ProvideGifFile(string name, string contentType)
{
var fileTypeGif = new Gif();
var fileContents = fileTypeGif.MagicByteSequences.First().Concat(new byte[] { 0x11, 0x12 }).ToArray();
var fileStream = new MemoryStream(fileContents);
byte[] gifSequence = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x11, 0x12];
var fileStream = new MemoryStream(gifSequence);

return new FormFile(
new MemoryStream(fileContents.ToArray()),
new MemoryStream(gifSequence),
0,
fileStream.Length,
name,
Expand Down
105 changes: 105 additions & 0 deletions MagicBytesValidator.Tests/Http/FindValidatedTypeAsync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
namespace MagicBytesValidator.Tests.Http;

public class FindValidatedTypeAsync
{
[Fact]
public async Task Should_find_by_extension()
{
var formFile = ProvideGifFile("trp.gif", "image/gif");

var sut = new FormFileTypeProvider();

var result = await sut.FindValidatedTypeAsync(
formFile,
null,
CancellationToken.None
);

result.Should().BeOfType<Gif>();
}

[Fact]
public async Task Should_find_by_content_type()
{
var formFile = ProvideGifFile(string.Empty, "image/gif");

var sut = new FormFileTypeProvider();

var result = await sut.FindValidatedTypeAsync(
formFile,
null,
CancellationToken.None
);

result.Should().BeOfType<Gif>();
}

[Fact]
public async Task Should_return_null_on_not_found()
{
var formFile = ProvideGifFile(string.Empty, "trp/crly");

var sut = new FormFileTypeProvider();

var result = await sut.FindValidatedTypeAsync(
formFile,
null,
CancellationToken.None
);

result.Should().BeNull();
}

[Fact]
public async Task Should_throw_on_type_vs_name_mismatch()
{
var formFile = ProvideGifFile("trp.gif", "image/png");

var sut = new FormFileTypeProvider();

await Assert.ThrowsAsync<MimeTypeMismatchException>(async () =>
await sut.FindValidatedTypeAsync(
formFile,
null,
CancellationToken.None
)
);
}

[Fact]
public async Task Should_throw_on_type_vs_content_mismatch()
{
var formFile = ProvideGifFile("trp.png", "image/png");

var sut = new FormFileTypeProvider();

await Assert.ThrowsAsync<MimeTypeMismatchException>(async () =>
await sut.FindValidatedTypeAsync(
formFile,
null,
CancellationToken.None
)
);
}

private static IFormFile ProvideGifFile(string name, string contentType)
{
byte[] gifSequence = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61];
var fileContents = gifSequence.Concat(new byte[] { 0x11, 0x12 }).ToArray();
var fileStream = new MemoryStream(fileContents.ToArray());

return new FormFile(
new MemoryStream(fileContents.ToArray()),
0,
fileStream.Length,
name,
name
)
{
Headers = new HeaderDictionary
{
{ "Content-Type", contentType }
}
};
}
}
17 changes: 17 additions & 0 deletions MagicBytesValidator.Tests/Imports.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Global using directives

global using System;
global using System.IO;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
global using FluentAssertions;
global using MagicBytesValidator.Exceptions.Http;
global using MagicBytesValidator.Formats;
global using MagicBytesValidator.Models;
global using MagicBytesValidator.Services;
global using MagicBytesValidator.Services.Http;
global using MagicBytesValidator.Services.Streams;
global using Microsoft.AspNetCore.Http;
global using Moq;
global using Xunit;
Loading
Loading