From 4da7514dfed3700783a5ac16e2749fc734825430 Mon Sep 17 00:00:00 2001 From: Haga R Date: Tue, 9 Jan 2024 14:50:10 +0100 Subject: [PATCH] (Tests) Add unit tests (#140) * Remove Fluxzy directory from codecov ignore list The 'src/Fluxzy' directory was mistakenly added to the codecov ignore list. This commit corrects this by removing it from the list, ensuring that this directory is now considered in the code coverage reports. * Add Fluxzy component to codecov.yml This commit includes the Fluxzy main component in the codecov file, defining its paths for tracking. It helps to accurately measure the test coverage for the overall Fluxzy project. * Add new test data * Add unit tests for SearchTextFilter New tests have been added for SearchTextFilter in the Fluxzy application. These tests assess a variety of scenarios, including searching in the request body, request header, response body, and response header. * Add 'with-request-payload.fxzy' to Fluxzy.Tests This update includes the addition of 'with-request-payload.fxzy' to the Fluxzy.Tests project. The file has been marked to preserve the newest copy when it is output. * Remove LegacyPcapWriter class The LegacyPcapWriter class was removed from the Fluxzy.Core.Pcap project. This was a deprecated class handling specific pcap writing activities, which are now handled by more efficient or updated components within the system. This aims to improve the overall efficiency and maintainability of the code. * Add NSubstitute package to Fluxzy.Tests.csproj . * Refactor ResponseSuggestedExtension method in HeaderUtility class The ResponseSuggestedExtension method in HeaderUtility.cs file was refactored to avoid redundant code and promote reusability. The response type check was replaced with a call to a new method that performs the same task, reducing code length and improving readability. * Fix bad GetHashCode that prevents equality . * Add HeaderUtility unit tests This commit introduces unit tests for the HeaderUtility class in the Fluxzy.Tests project. These tests utilize example content types and validate returns for the following methods: GetRequestSuggestedExtension, GetResponseSuggestedExtension, and GetSimplifiedContentType. * Add equality tests for various classes This commit introduces specific equality tests for `Authority`, `FluxzyEndPoint`, `ProxyBindPoint`, `SystemProxySetting` and `Tag` classes. These tests utilize a base testing class `EqualityTesterBase` which provides a standard test structure and enforces equality and non-equality checks for each class. * Update codecov.yml to ignore debugging code In the updated configuration for Codecov, debugging related files under "src/Fluxzy.Core/Clients" and "src/Fluxzy.Core/Misc/Streams" directories are added to be ignored. This means these files are no longer considered in code coverage statistics. * Add ArchiveReader unit tests This commit introduces unit tests for ArchiveReader in the Fluxzy.Tests project. Each test thoroughly inspects different aspects of the ArchiveReader's functionality and assures that all components are properly working. Separate tests have been also created for FluxzyArchiveReader and DirectoryArchiveReader. * Add additional assertions in EqualityTesterBase unit tests These changes refine the unit tests by adding more assertions for equality and inequality in the EqualityTesterBase class. This includes checks for object equivalence and verifies that a string labeled "notEqual" is also recognized as not equal. * Add ClientErrorEquality unit test . * Remove BOM * Add ImportEngineProvider unit tests A new ImportEngineProvider unit test file has been added to improve the code coverage. Changes also include minor adjustments in the Fluxzy.Tests.csproj and ImportEngineProvider.cs files, such as copy-to-output directory options and coding style. * Add unit tests for Agent and AuthorityInfo equality This commit introduces two new unit tests. These tests are for the equality operators of the Agent and AuthorityInfo classes. They ensure that instances of these classes are properly evaluated for their equivalence or lack thereof. * Increase timeouts in proxy and OS detection The timeout in AddHocConfigurableProxy has been increased from 20 to 40 to allow for more flexibility. Timeout for OS detection under OSX platform has also been extended from 40 to 60, allowing more time for slower systems and preventing premature termination. --------- Co-authored-by: fluxzy-ci --- codecov.yml | 10 +- src/Fluxzy.Core.Pcap/LegacyPcapWriter.cs | 201 ------------------ .../Archiving/Readers/ImportEngineProvider.cs | 2 +- .../Core/Proxy/SystemProxySetting.cs | 2 +- src/Fluxzy.Core/Core/ProxyOrchestrator.cs | 4 +- src/Fluxzy.Core/Utils/HeaderUtility.cs | 49 +---- src/Fluxzy.Core/Utils/SubdomainUtility.cs | 6 + test/Fluxzy.Tests/Fluxzy.Tests.csproj | 10 + test/Fluxzy.Tests/TimeoutConstants.cs | 2 +- .../UnitTests/Archiving/ArchiveReaderTests.cs | 104 +++++++++ .../Archiving/DirectoryArchiveReaderTests.cs | 14 ++ .../UnitTests/Equality/AgentEquality.cs | 22 ++ .../UnitTests/Equality/AuthorityEquality.cs | 20 ++ .../Equality/AuthorityInfoEquality.cs | 25 +++ .../UnitTests/Equality/ClientErrorEquality.cs | 20 ++ .../UnitTests/Equality/EqualityTesterBase.cs | 52 +++++ .../Equality/FluxzyEndPointEquality.cs | 24 +++ .../Equality/ProxyBindPointEquality.cs | 22 ++ .../Equality/SystemProxySettingEquality.cs | 23 ++ .../UnitTests/Equality/TagEquality.cs | 22 ++ .../Packagers/FxzyImportEngineTests.cs | 49 +++++ .../Packagers/ImportEngineProviderTests.cs | 29 +++ .../UnitTests/Rules/BreakPointRules.cs | 2 +- .../UnitTests/Rules/SearchTextFilterTests.cs | 90 ++++++++ .../UnitTests/Settings/FluxzySettingTests.cs | 20 ++ .../UnitTests/Util/HeaderUtilityTests.cs | 101 +++++++++ .../UnitTests/Util/StringHelperTests.cs | 49 +++++ .../UnitTests/Util/SubdomainUtilityTests.cs | 29 +++ .../_Files/Archives/with-request-payload.fxzy | Bin 0 -> 13491 bytes .../_Fixtures/ProduceDeletableItem.cs | 7 + 30 files changed, 759 insertions(+), 251 deletions(-) delete mode 100644 src/Fluxzy.Core.Pcap/LegacyPcapWriter.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Archiving/ArchiveReaderTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Archiving/DirectoryArchiveReaderTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/AgentEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/AuthorityEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/AuthorityInfoEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/ClientErrorEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/EqualityTesterBase.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/FluxzyEndPointEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/ProxyBindPointEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/SystemProxySettingEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Equality/TagEquality.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Packagers/FxzyImportEngineTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Packagers/ImportEngineProviderTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Rules/SearchTextFilterTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Util/HeaderUtilityTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Util/StringHelperTests.cs create mode 100644 test/Fluxzy.Tests/UnitTests/Util/SubdomainUtilityTests.cs create mode 100644 test/Fluxzy.Tests/_Files/Archives/with-request-payload.fxzy diff --git a/codecov.yml b/codecov.yml index 4123480a4..0379e541a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -13,10 +13,18 @@ component_management: name: Fluxzy.Core paths: - src/Fluxzy.Core/** + - component_id: Fluxzy + name: Fluxzy + paths: + - src/Fluxzy/** ignore: - "src/Fluxzy.Core.Pcap/**" - "src/Fluxzy.Core.Pcap.Cli/**" - "src/Fluxzy.Core.Pcap/**" - "src/Fluxzy.Extensions/**" - "src/Fluxzy.Tools.DocGen/**" - - "src/Fluxzy/**" \ No newline at end of file + +# Ignore debugging code + - "src/Fluxzy.Core/Clients/H2Logger.cs" + - "src/Fluxzy.Core/Clients/H1Logger.cs" + - "src/Fluxzy.Core/Misc/Streams/DebugFileStream.cs" \ No newline at end of file diff --git a/src/Fluxzy.Core.Pcap/LegacyPcapWriter.cs b/src/Fluxzy.Core.Pcap/LegacyPcapWriter.cs deleted file mode 100644 index e8c216ad4..000000000 --- a/src/Fluxzy.Core.Pcap/LegacyPcapWriter.cs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright © 2023 Haga RAKOTOHARIVELO - -using System.Buffers; -using System.Runtime.InteropServices; -using Fluxzy.Core.Pcap.Writing; -using SharpPcap; -using SharpPcap.LibPcap; - -namespace Fluxzy.Core.Pcap -{ - internal class LegacyPcapWriter : IRawCaptureWriter - { - private readonly int _headerLength; - - private readonly bool _isOsx; - private readonly bool _isShortTimeVal; - private readonly object _locker = new(); - private byte[]? _waitBuffer; - - private Stream _waitStream; - - public LegacyPcapWriter(long key) - { - Key = key; - _isOsx = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - _isShortTimeVal = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - _headerLength = GetPreHeaderHeaderLength() + sizeof(long); - - // TODO put _waitBuffer length into config file / env variable - - _waitBuffer = ArrayPool.Shared.Rent(8 * 1024); - _waitStream = new MemoryStream(_waitBuffer); - } - - public bool Faulted { get; private set; } - - public void Flush() - { - if (_waitStream is FileStream fileStream) - fileStream.Flush(); // We probably broke thread safety here - } - - public void Register(string outFileName) - { - if (_waitBuffer == null) - throw new InvalidOperationException("Already registered!"); - - Directory.CreateDirectory(Path.GetDirectoryName(outFileName)!); - - var fileStream = File.Open(outFileName, FileMode.Create, FileAccess.Write, FileShare.Read); - - fileStream.Write(PcapFileHeaderBuilder.Buffer); - - lock (_locker) { - fileStream.Write(_waitBuffer, 0, (int) _waitStream.Position); // We copy content to buffer - - ArrayPool.Shared.Return(_waitBuffer); - _waitBuffer = null; - - _waitStream = fileStream; - } - } - - public void Write(PacketCapture packetCapture) - { - Write(packetCapture.Data, packetCapture.Header.Timeval); - } - - public void StoreKey(string nssKey) - { - // We cannot store keys under legacy pcapfile - } - - public void Dispose() - { - lock (_locker) { - if (_waitBuffer != null) { - ArrayPool.Shared.Return(_waitBuffer); - _waitBuffer = null; - } - - _waitStream?.Dispose(); - } - } - - public long Key { get; } - - public void Write(ReadOnlySpan data, PosixTimeval timeVal) - { - try { - if (Faulted) - return; - - // We are dumping on file so no need to lock or whatsoever - if (_waitStream is FileStream fileStream) { - InternalWrite(data, timeVal, fileStream); - - return; - } - - // Check for buffer overflow here - // _waitStream need to be protected - - lock (_locker) { - InternalWrite(data, timeVal, _waitStream); - } - } - catch { - Faulted = true; - - // Free the memory when disposed - Dispose(); - - throw; - } - } - - private void InternalWrite(ReadOnlySpan data, PosixTimeval timeVal, Stream destination) - { - var timeValMicroseconds = timeVal.MicroSeconds; - var timeValSeconds = timeVal.Seconds; - - // Building header - - Span headerBuffer = stackalloc byte[_headerLength]; - var original = headerBuffer; - - - if (_isShortTimeVal) { - BitConverter.TryWriteBytes(headerBuffer, (int) timeValSeconds); - headerBuffer = headerBuffer.Slice(4); - BitConverter.TryWriteBytes(headerBuffer, (uint) timeValMicroseconds); - headerBuffer = headerBuffer.Slice(4); - } - else { - if (_isOsx) { - BitConverter.TryWriteBytes(headerBuffer, (long) timeValSeconds); - headerBuffer = headerBuffer.Slice(8); - BitConverter.TryWriteBytes(headerBuffer, (uint) timeValMicroseconds); - headerBuffer = headerBuffer.Slice(4); - } - else { - BitConverter.TryWriteBytes(headerBuffer, (long) timeValSeconds); - headerBuffer = headerBuffer.Slice(8); - BitConverter.TryWriteBytes(headerBuffer, timeValMicroseconds); - headerBuffer = headerBuffer.Slice(8); - } - } - - - BitConverter.TryWriteBytes(headerBuffer, (uint) data.Length); - headerBuffer = headerBuffer.Slice(4); - - BitConverter.TryWriteBytes(headerBuffer, (uint) data.Length); - - - destination.Write(original); - destination.Write(data); - } - - private int GetPreHeaderHeaderLength() - { - if (_isShortTimeVal) - return 8; - - if (_isOsx) - return 12; - - return 16; - } - - public ValueTask DisposeAsync() - { - Dispose(); - - return default; - } - } - - internal static class PcapFileHeaderBuilder - { - static PcapFileHeaderBuilder() - { - var tempFile = Environment.GetEnvironmentVariable("FLUXZY_BASE_DIR") - ?? Environment.ExpandEnvironmentVariables("%appdata%/fluxzy/pcap/header"); - - Directory.CreateDirectory(tempFile); - - var tempFileName = Path.Combine(tempFile, "header.pcap"); - - using (var deviceWriter = new CaptureFileWriterDevice(tempFileName, FileMode.Create)) { - // Writing file header - deviceWriter.Open(); - } - - Buffer = File.ReadAllBytes(tempFileName); - } - - public static byte[] Buffer { get; } - } -} diff --git a/src/Fluxzy.Core/Archiving/Readers/ImportEngineProvider.cs b/src/Fluxzy.Core/Archiving/Readers/ImportEngineProvider.cs index 8b31806fb..b36dcb7b4 100644 --- a/src/Fluxzy.Core/Archiving/Readers/ImportEngineProvider.cs +++ b/src/Fluxzy.Core/Archiving/Readers/ImportEngineProvider.cs @@ -22,7 +22,7 @@ public ImportEngineProvider(FxzyDirectoryPackager directoryPackager) public IReadOnlyCollection Engines { get; } - public IImportEngine? GetImportEngine(string fileName) + public IImportEngine? GetImportEngine(string fileName) { return Engines.FirstOrDefault(r => r.IsFormat(fileName)); } diff --git a/src/Fluxzy.Core/Core/Proxy/SystemProxySetting.cs b/src/Fluxzy.Core/Core/Proxy/SystemProxySetting.cs index 12b8bb95e..0bd8bad6e 100644 --- a/src/Fluxzy.Core/Core/Proxy/SystemProxySetting.cs +++ b/src/Fluxzy.Core/Core/Proxy/SystemProxySetting.cs @@ -61,7 +61,7 @@ public override bool Equals(object? obj) public override int GetHashCode() { - return HashCode.Combine(BoundHost, ListenPort, ByPassHosts); + return HashCode.Combine(BoundHost, ListenPort); } } } diff --git a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs index c4ee5bab9..936ce65a0 100644 --- a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs +++ b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs @@ -176,10 +176,10 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion if (exchange.Context.HasRequestBodySubstitution) { originalRequestBodyStream = exchange.Request.Body; exchange.Request.Body = await - exchange.Context.GetSubstitutedRequestBody(exchange.Request.Body, exchange); + exchange.Context.GetSubstitutedRequestBody(exchange.Request.Body!, exchange); } - exchange.Request.Body = new DispatchStream(exchange.Request.Body, + exchange.Request.Body = new DispatchStream(exchange.Request.Body!, true, _archiveWriter.CreateRequestBodyStream(exchange.Id)); } diff --git a/src/Fluxzy.Core/Utils/HeaderUtility.cs b/src/Fluxzy.Core/Utils/HeaderUtility.cs index daa3eab02..2c3c316f4 100644 --- a/src/Fluxzy.Core/Utils/HeaderUtility.cs +++ b/src/Fluxzy.Core/Utils/HeaderUtility.cs @@ -1,7 +1,6 @@ // Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak using System; -using System.Buffers; using System.Linq; using Fluxzy.Clients.H2.Encoder.Utils; @@ -16,6 +15,11 @@ public static string GetResponseSuggestedExtension(IExchange exchange) ?.Where(r => r.Name.Span.Equals("content-type", StringComparison.OrdinalIgnoreCase)) .LastOrDefault(); + return ResponseSuggestedExtension(contentTypeHeader); + } + + internal static string ResponseSuggestedExtension(HeaderFieldInfo? contentTypeHeader) + { if (contentTypeHeader == null) return "data"; @@ -67,48 +71,7 @@ public static string GetRequestSuggestedExtension(IExchange exchange) ?.Where(r => r.Name.Span.Equals("content-type", StringComparison.OrdinalIgnoreCase)) .LastOrDefault(); - if (contentTypeHeader == null) - return "data"; - - if (contentTypeHeader.Value.Span.Contains("json", StringComparison.OrdinalIgnoreCase)) - return "json"; - - if (contentTypeHeader.Value.Span.Contains("html", StringComparison.OrdinalIgnoreCase)) - return "html"; - - if (contentTypeHeader.Value.Span.Contains("css", StringComparison.OrdinalIgnoreCase)) - return "css"; - - if (contentTypeHeader.Value.Span.Contains("xml", StringComparison.OrdinalIgnoreCase)) - return "xml"; - - if (contentTypeHeader.Value.Span.Contains("javascript", StringComparison.OrdinalIgnoreCase)) - return "js"; - - if (contentTypeHeader.Value.Span.Contains("font", StringComparison.OrdinalIgnoreCase)) - return "font"; - - if (contentTypeHeader.Value.Span.Contains("png", StringComparison.OrdinalIgnoreCase)) - return "png"; - - if (contentTypeHeader.Value.Span.Contains("jpeg", StringComparison.OrdinalIgnoreCase) - || contentTypeHeader.Value.Span.Contains("jpg", StringComparison.OrdinalIgnoreCase) - ) - return "jpeg"; - - if (contentTypeHeader.Value.Span.Contains("gif", StringComparison.OrdinalIgnoreCase)) - return "gif"; - - if (contentTypeHeader.Value.Span.Contains("svg", StringComparison.OrdinalIgnoreCase)) - return "svg"; - - if (contentTypeHeader.Value.Span.Contains("pdf", StringComparison.OrdinalIgnoreCase)) - return "pdf"; - - if (contentTypeHeader.Value.Span.Contains("text", StringComparison.OrdinalIgnoreCase)) - return "txt"; - - return "data"; + return ResponseSuggestedExtension(contentTypeHeader); } public static string? GetSimplifiedContentType(IExchange exchange) diff --git a/src/Fluxzy.Core/Utils/SubdomainUtility.cs b/src/Fluxzy.Core/Utils/SubdomainUtility.cs index c093412e1..acfb94245 100644 --- a/src/Fluxzy.Core/Utils/SubdomainUtility.cs +++ b/src/Fluxzy.Core/Utils/SubdomainUtility.cs @@ -15,6 +15,12 @@ public static bool TryGetSubDomain(string host, out string? subDomain) return true; } + if (splittedHost.Length == 2) { + subDomain = host; + + return true; + } + subDomain = null; return false; diff --git a/test/Fluxzy.Tests/Fluxzy.Tests.csproj b/test/Fluxzy.Tests/Fluxzy.Tests.csproj index e85e918c2..55839b268 100644 --- a/test/Fluxzy.Tests/Fluxzy.Tests.csproj +++ b/test/Fluxzy.Tests/Fluxzy.Tests.csproj @@ -21,9 +21,18 @@ + + PreserveNewest + Always + + Never + + + PreserveNewest + PreserveNewest @@ -40,6 +49,7 @@ + diff --git a/test/Fluxzy.Tests/TimeoutConstants.cs b/test/Fluxzy.Tests/TimeoutConstants.cs index 93bd56439..862857a4e 100644 --- a/test/Fluxzy.Tests/TimeoutConstants.cs +++ b/test/Fluxzy.Tests/TimeoutConstants.cs @@ -10,7 +10,7 @@ public static int Regular { get { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - return 40; + return 60; } else { return 15; diff --git a/test/Fluxzy.Tests/UnitTests/Archiving/ArchiveReaderTests.cs b/test/Fluxzy.Tests/UnitTests/Archiving/ArchiveReaderTests.cs new file mode 100644 index 000000000..6e867b3df --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Archiving/ArchiveReaderTests.cs @@ -0,0 +1,104 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Linq; +using Fluxzy.Misc.Streams; +using Fluxzy.Readers; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Archiving +{ + public abstract class ArchiveReaderTests + { + private readonly IArchiveReader _archiveReader; + + protected ArchiveReaderTests(IArchiveReader archiveReader) + { + _archiveReader = archiveReader; + } + + [Fact] + public void ReadMetaInformation() + { + var metaInformation = _archiveReader.ReadMetaInformation(); + Assert.NotNull(metaInformation); + Assert.NotNull(metaInformation.ArchiveVersion); + Assert.NotNull(metaInformation.FluxzyVersion); + Assert.NotNull(metaInformation.Tags); + Assert.NotNull(metaInformation.ViewFilters); + Assert.NotEqual(default, metaInformation.CaptureDate); + } + + [Fact] + public void Invalid_Exchange() + { + var result = _archiveReader.ReadExchange(9556461); + Assert.Null(result); + } + + [Fact] + public void Read_DownStreamErrors() + { + var exchanges = _archiveReader.ReaderAllDownstreamErrors()?.ToList(); + + Assert.NotNull(exchanges!); + } + + [Fact] + public void Read_Exchanges() + { + var exchanges = _archiveReader.ReadAllExchanges()?.ToList(); + + Assert.NotNull(exchanges!); + Assert.NotEmpty(exchanges); + + foreach (var exchange in exchanges) { + var result = _archiveReader.ReadExchange(exchange.Id); + Assert.NotNull(result); + } + } + + [Fact] + public void Validate_Connections() + { + var connections = _archiveReader.ReadAllConnections()?.ToList(); + + Assert.NotNull(connections!); + Assert.NotEmpty(connections); + + foreach (var connection in connections) { + var result = _archiveReader.ReadConnection(connection.Id); + Assert.NotNull(result); + + _ = _archiveReader.HasResponseBody(connection.Id); + _ = _archiveReader.HasRequestBody(connection.Id); + + Assert.True(_archiveReader.HasCapture(connection.Id)); + + using var rawCaptureStream = _archiveReader.GetRawCaptureStream(connection.Id); + using var rawCaptureKeyStream = _archiveReader.GetRawCaptureKeyStream(connection.Id); + + Assert.NotNull(rawCaptureStream!); + Assert.NotNull(rawCaptureKeyStream!); + var length = rawCaptureStream.Drain(); + + var keyStreamLength = rawCaptureKeyStream.Drain(); + + Assert.True(length > 0); + Assert.True(keyStreamLength > 0); + + if (_archiveReader is DirectoryArchiveReader directoryArchiveReader) { + var rawCaptureFile = directoryArchiveReader.GetRawCaptureFile(connection.Id); + Assert.NotNull(rawCaptureFile!); + } + } + } + } + + public class FluxzyArchiveReaderTests : ArchiveReaderTests + { + public FluxzyArchiveReaderTests() + : base(new FluxzyArchiveReader("_Files/Archives/with-request-payload.fxzy")) + { + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Archiving/DirectoryArchiveReaderTests.cs b/test/Fluxzy.Tests/UnitTests/Archiving/DirectoryArchiveReaderTests.cs new file mode 100644 index 000000000..7a3c80046 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Archiving/DirectoryArchiveReaderTests.cs @@ -0,0 +1,14 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using Fluxzy.Readers; + +namespace Fluxzy.Tests.UnitTests.Archiving +{ + public class DirectoryArchiveReaderTests : ArchiveReaderTests + { + public DirectoryArchiveReaderTests() + : base(new DirectoryArchiveReader(".artefacts/tests/pink-floyd")) + { + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Equality/AgentEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/AgentEquality.cs new file mode 100644 index 000000000..cd679db83 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/AgentEquality.cs @@ -0,0 +1,22 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Collections.Generic; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class AgentEquality : EqualityTesterBase + { + protected override Agent Item { get; } = new(9, "browser"); + + protected override IEnumerable EqualItems { get; } = + new[] { + new Agent(9, "browser") + }; + + protected override IEnumerable NotEqualItems { get; } + = new[] { + new Agent(91, "browser"), + new Agent(9, "browsers") + }; + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Equality/AuthorityEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/AuthorityEquality.cs new file mode 100644 index 000000000..cbdd28e9f --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/AuthorityEquality.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Fluxzy.Core; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class AuthorityEquality : EqualityTesterBase + { + protected override Authority Item { get; } = new Authority("host", 256, true); + + protected override IEnumerable EqualItems { get; } = + new[] { new Authority("host", 256, true) }; + + protected override IEnumerable NotEqualItems { get; } + = new[] { + new Authority("host", 256, false), + new Authority("hosta", 256, true), + new Authority("host", 2856, true), + }; + } +} \ No newline at end of file diff --git a/test/Fluxzy.Tests/UnitTests/Equality/AuthorityInfoEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/AuthorityInfoEquality.cs new file mode 100644 index 000000000..d0030ca76 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/AuthorityInfoEquality.cs @@ -0,0 +1,25 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Collections.Generic; +using Fluxzy.Core; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class AuthorityInfoEquality : EqualityTesterBase + { + protected override AuthorityInfo Item { get; } = new("google.com", 266, true); + + protected override IEnumerable EqualItems { get; } = + new[] { + new AuthorityInfo("google.com", 266, true), + new AuthorityInfo(new Authority("google.com", 266, true)) + }; + + protected override IEnumerable NotEqualItems { get; } + = new[] { + new AuthorityInfo("google.coma", 266, true), + new AuthorityInfo("google.com", 2661, true), + new AuthorityInfo("google.com", 266, false) + }; + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Equality/ClientErrorEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/ClientErrorEquality.cs new file mode 100644 index 000000000..6fb85797c --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/ClientErrorEquality.cs @@ -0,0 +1,20 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Collections.Generic; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class ClientErrorEquality : EqualityTesterBase + { + protected override ClientError Item { get; } = new ClientError(9, "message"); + + protected override IEnumerable EqualItems { get; } = + new[] { new ClientError(9, "message") }; + + protected override IEnumerable NotEqualItems { get; } + = new[] { + new ClientError(9, "messages"), + new ClientError(90, "message"), + }; + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Equality/EqualityTesterBase.cs b/test/Fluxzy.Tests/UnitTests/Equality/EqualityTesterBase.cs new file mode 100644 index 000000000..e74b3770a --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/EqualityTesterBase.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public abstract class EqualityTesterBase + { + protected abstract T Item { get; } + + protected abstract IEnumerable EqualItems { get; } + + protected abstract IEnumerable NotEqualItems { get; } + + [Fact] + public void Test_Same_Ref() + { + Assert.Equal(Item, Item); + } + + [Fact] + public void Test_With_Null() + { + Assert.NotEqual(default, Item); + Assert.NotEqual(Item, default); + } + + [Fact] + public void Test_Equal() + { + foreach (var equal in EqualItems) + { + var set = new HashSet { equal }; + Assert.Contains(Item, set); + + Assert.Equal((object?) equal, Item); + } + } + + [Fact] + public void Test_Not_Equal() + { + foreach (var notEqual in NotEqualItems) + { + var set = new HashSet { notEqual }; + Assert.DoesNotContain(Item, set); + + Assert.NotEqual((object?) notEqual, Item); + Assert.NotEqual((object?) "notEqual", Item); + } + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Equality/FluxzyEndPointEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/FluxzyEndPointEquality.cs new file mode 100644 index 000000000..67fda009e --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/FluxzyEndPointEquality.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Net; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class FluxzyEndPointEquality : EqualityTesterBase + { + protected override FluxzyEndPoint Item { get; } = new("127.0.0.1", 256); + + protected override IEnumerable EqualItems { get; } = + new FluxzyEndPoint[] { + new (new IPEndPoint(IPAddress.Loopback, 256)), + new ("127.0.0.1", 256) + }; + + protected override IEnumerable NotEqualItems { get; } + = new FluxzyEndPoint[] { + new (new IPEndPoint(IPAddress.Loopback, 2566)), + new (new IPEndPoint(IPAddress.IPv6Loopback, 256)), + new ("127.0.0.1", 2564), + new ("127.0.2.1", 2564), + }; + } +} \ No newline at end of file diff --git a/test/Fluxzy.Tests/UnitTests/Equality/ProxyBindPointEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/ProxyBindPointEquality.cs new file mode 100644 index 000000000..706770442 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/ProxyBindPointEquality.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Net; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class ProxyBindPointEquality : EqualityTesterBase + { + protected override ProxyBindPoint Item { get; } = new(new IPEndPoint(IPAddress.Loopback, 256), true); + + protected override IEnumerable EqualItems { get; } = + new ProxyBindPoint[] { + new (new IPEndPoint(IPAddress.Loopback, 256), true), + }; + + protected override IEnumerable NotEqualItems { get; } + = new ProxyBindPoint[] { + new (new IPEndPoint(IPAddress.IPv6Loopback, 256), true), + new (new IPEndPoint(IPAddress.Loopback, 256), false), + new (new IPEndPoint(IPAddress.Loopback, 251), true), + }; + } +} \ No newline at end of file diff --git a/test/Fluxzy.Tests/UnitTests/Equality/SystemProxySettingEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/SystemProxySettingEquality.cs new file mode 100644 index 000000000..e7a108d20 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/SystemProxySettingEquality.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Fluxzy.Core.Proxy; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class SystemProxySettingEquality : EqualityTesterBase + { + protected override SystemProxySetting Item { get; } = new("127.0.0.1", 256, "google.com"); + + protected override IEnumerable EqualItems { get; } = + new SystemProxySetting[] { + new("127.0.0.1", 256, "google.com") + }; + + protected override IEnumerable NotEqualItems { get; } + = new SystemProxySetting[] { + new("192.0.0.1", 256, "google.com"), + new("127.0.0.1", 257, "google.com"), + new("127.0.0.1", 256, "googled.com"), + new("127.0.0.1", 256, ""), + }; + } +} \ No newline at end of file diff --git a/test/Fluxzy.Tests/UnitTests/Equality/TagEquality.cs b/test/Fluxzy.Tests/UnitTests/Equality/TagEquality.cs new file mode 100644 index 000000000..6291c3d9d --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Equality/TagEquality.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace Fluxzy.Tests.UnitTests.Equality +{ + public class TagEquality : EqualityTesterBase + { + protected override Tag Item { get; } = new(new Guid("EA196F45-6709-4E1D-AFB9-1EFA8A61CBD1"), "tag"); + + protected override IEnumerable EqualItems { get; } = + new Tag[] { + new(new Guid("EA196F45-6709-4E1D-AFB9-1EFA8A61CBD1"), "tag") + }; + + protected override IEnumerable NotEqualItems { get; } + = new Tag[] { + new(new Guid("EA196F45-6709-4E1D-AFB9-1EFA8A61CBD2"), "tag"), + new(new Guid("EA196F45-6709-4E1D-AFB9-1EFA8A61CBD1"), "tago"), + new("tag"), + }; + } +} \ No newline at end of file diff --git a/test/Fluxzy.Tests/UnitTests/Packagers/FxzyImportEngineTests.cs b/test/Fluxzy.Tests/UnitTests/Packagers/FxzyImportEngineTests.cs new file mode 100644 index 000000000..1be233db2 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Packagers/FxzyImportEngineTests.cs @@ -0,0 +1,49 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.IO; +using Fluxzy.Readers; +using Fluxzy.Tests._Fixtures; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Packagers +{ + public class FxzyImportEngineTests : ProduceDeletableItem + { + [Fact] + public void Test_Valid() + { + var archiveFile = "_Files/Archives/pink-floyd.fxzy"; + var packager = new FxzyDirectoryPackager(); + var importEngine = new FxzyImportEngine(packager); + + var result = importEngine.IsFormat(archiveFile); + + Assert.True(result); + } + + [Fact] + public void Test_Invalid_File_Missing() + { + var archiveFile = "_Files/Archives/not-a-file.fxzy"; + var packager = new FxzyDirectoryPackager(); + var importEngine = new FxzyImportEngine(packager); + + var result = importEngine.IsFormat(archiveFile); + + Assert.False(result); + } + + [Fact] + public void Test_Unpack() + { + var validArchiveFile = "_Files/Archives/pink-floyd.fxzy"; + var packager = new FxzyDirectoryPackager(); + var importEngine = new FxzyImportEngine(packager); + var directory = GetRegisteredRandomDirectory(); + + importEngine.WriteToDirectory(validArchiveFile, directory); + + Assert.True(Directory.Exists(directory)); + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Packagers/ImportEngineProviderTests.cs b/test/Fluxzy.Tests/UnitTests/Packagers/ImportEngineProviderTests.cs new file mode 100644 index 000000000..2fd372795 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Packagers/ImportEngineProviderTests.cs @@ -0,0 +1,29 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using Fluxzy.Readers; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Packagers +{ + public class ImportEngineProviderTests + { + private readonly ImportEngineProvider _importEngineProvider; + + public ImportEngineProviderTests() + { + _importEngineProvider = new ImportEngineProvider(new FxzyDirectoryPackager()); + } + + [Theory] + [InlineData(nameof(FxzyImportEngine), "_Files/Archives/pink-floyd.fxzy")] + [InlineData(nameof(HarImportEngine), "_Files/Archives/minimal.har")] + [InlineData(nameof(SazImportEngine), "_Files/Archives/minimal.saz")] + public void Test(string className, string filename) + { + var importEngine = _importEngineProvider.GetImportEngine(filename); + + Assert.NotNull(importEngine); + Assert.Equal(className, importEngine.GetType().Name); + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Rules/BreakPointRules.cs b/test/Fluxzy.Tests/UnitTests/Rules/BreakPointRules.cs index b7f48927c..6e155fbb1 100644 --- a/test/Fluxzy.Tests/UnitTests/Rules/BreakPointRules.cs +++ b/test/Fluxzy.Tests/UnitTests/Rules/BreakPointRules.cs @@ -373,7 +373,7 @@ public async Task ChangeEntireResponse(string host, TestBreakpointPayloadType pa [MemberData(nameof(TestConstants.GetHosts), MemberType = typeof(TestConstants))] public async Task ChangeEntireResponseInvalidHeaders(string host) { - await using var proxy = new AddHocConfigurableProxy(1, 20); + await using var proxy = new AddHocConfigurableProxy(1, 40); var payloadType = TestBreakpointPayloadType.FromFile; diff --git a/test/Fluxzy.Tests/UnitTests/Rules/SearchTextFilterTests.cs b/test/Fluxzy.Tests/UnitTests/Rules/SearchTextFilterTests.cs new file mode 100644 index 000000000..6a87f0c5a --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Rules/SearchTextFilterTests.cs @@ -0,0 +1,90 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Threading.Tasks; +using Fluxzy.Readers; +using Fluxzy.Rules; +using Fluxzy.Rules.Actions; +using Fluxzy.Rules.Filters; +using Fluxzy.Rules.Filters.ViewOnlyFilters; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Rules +{ + public class SearchTextFilterTests : FilterTestTemplate + { + [Theory] + [InlineData(true, + "20px;width:1.4285714em;height:1", false, false, true, false)] + [InlineData(false, + "20px;width:1.4898sd46285714em;height:1", false, false, true, false)] + [InlineData(true, + "he;desc=\"hit-front\", host;desc=", false, false, false, true)] + [InlineData(false, + "he;desc=\"hit-front\", host;desc=", false, false, true, false)] + [InlineData(true, + "oIP=FR:IDF:Maisons-Laffitte:48.95:2.15:v4", false, true, false, false)] + [InlineData(false, + "oIP=FR:IDF:Maisons-Laffitte:48.95:2.15:v4", false, false, true, false)] + public async Task CheckPass_SearchTextFilter( + bool expectedResult, string pattern, + bool searchInRequestBody, bool searchInRequestHeader, + bool searchInResponseBody, bool searchInResponseHeader) + { + var archiveFile = "_Files/Archives/pink-floyd.fxzy"; + var exchangeId = 45; + + var filter = new SearchTextFilter(pattern) { + SearchInRequestBody = searchInRequestBody, + SearchInRequestHeader = searchInRequestHeader, + SearchInResponseBody = searchInResponseBody, + SearchInResponseHeader = searchInResponseHeader + }; + + var archiveReader = new FluxzyArchiveReader(archiveFile); + var exchange = archiveReader.ReadExchange(exchangeId)!; + var filteringContext = new ExchangeInfoFilteringContext(archiveReader, exchangeId); + + var rule = new Rule(new ApplyCommentAction("hello"), filter); + + var actualResult = filter.Apply(null, null!, exchange, filteringContext); + + Assert.Equal(expectedResult, actualResult); + } + + [Theory] + [InlineData(true, + "zozoz45", true, true, true, true)] + [InlineData(true, + "zozoz45", true, false, false, false)] + [InlineData(false, + "zozozy45", true, false, false, false)] + [InlineData(false, + "zozoz45", false, true, true, true)] + public async Task CheckPass_SearchTextFilter_Request_Body( + bool expectedResult, string pattern, + bool searchInRequestBody, bool searchInRequestHeader, + bool searchInResponseBody, bool searchInResponseHeader) + { + var archiveFile = "_Files/Archives/with-request-payload.fxzy"; + var exchangeId = 103; + + var filter = new SearchTextFilter(pattern) { + SearchInRequestBody = searchInRequestBody, + SearchInRequestHeader = searchInRequestHeader, + SearchInResponseBody = searchInResponseBody, + SearchInResponseHeader = searchInResponseHeader, + CaseSensitive = searchInRequestHeader + }; + + var archiveReader = new FluxzyArchiveReader(archiveFile); + var exchange = archiveReader.ReadExchange(exchangeId)!; + var filteringContext = new ExchangeInfoFilteringContext(archiveReader, exchangeId); + + var rule = new Rule(new ApplyCommentAction("hello"), filter); + + var actualResult = filter.Apply(null, null!, exchange, filteringContext); + + Assert.Equal(expectedResult, actualResult); + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Settings/FluxzySettingTests.cs b/test/Fluxzy.Tests/UnitTests/Settings/FluxzySettingTests.cs index 8c23dab42..ef1d7e18f 100644 --- a/test/Fluxzy.Tests/UnitTests/Settings/FluxzySettingTests.cs +++ b/test/Fluxzy.Tests/UnitTests/Settings/FluxzySettingTests.cs @@ -1,5 +1,10 @@ using System.Net; +using System.Security.Authentication; using System.Text.Json; +using Fluxzy.Certificates; +using Fluxzy.Rules.Actions; +using Fluxzy.Rules.Filters; +using Fluxzy.Rules.Filters.RequestFilters; using Xunit; namespace Fluxzy.Tests.UnitTests.Settings @@ -14,7 +19,22 @@ public void Read_Write() { var settings = FluxzySetting.CreateDefault(); + // TODO make, distinct tests for each method + settings.AddBoundAddress(IPAddress.IPv6Any, 652); + settings.AddBoundAddress("127.0.0.1", 54652); + settings.ClearSaveFilter(); + settings.SetSaveFilter(new HostFilter("google.com")); + settings.SetByPassedHosts("google.com", "facebook.com"); + settings.AddTunneledHosts("microsoft.com", "apple.com"); + settings.SetConnectionPerHost(9); + settings.SetServerProtocols(SslProtocols.Tls12); + settings.SetCheckCertificateRevocation(false); + settings.SetCaCertificate(Certificate.UseDefault()); + settings.AddAlterationRules(new NoOpAction(), AnyFilter.Default); + settings.SetVerbose(true); + settings.UseBouncyCastleSslEngine(); + settings.SetCertificateCacheDirectory("/temp"); var jsonString = JsonSerializer.Serialize(settings, GlobalArchiveOption.ConfigSerializerOptions); diff --git a/test/Fluxzy.Tests/UnitTests/Util/HeaderUtilityTests.cs b/test/Fluxzy.Tests/UnitTests/Util/HeaderUtilityTests.cs new file mode 100644 index 000000000..a6433969d --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Util/HeaderUtilityTests.cs @@ -0,0 +1,101 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using Fluxzy.Utils; +using NSubstitute; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Util +{ + public class HeaderUtilityTests + { + [Theory] + [InlineData("application/json", "json")] + [InlineData("application/xml", "xml")] + [InlineData("text/html", "html")] + [InlineData("text/plain", "txt")] + [InlineData("application/javascript", "js")] + [InlineData("application/pdf", "pdf")] + [InlineData("text/font", "font")] + [InlineData("text/css", "css")] + [InlineData("img/jpg", "jpeg")] + [InlineData("img/jpeg", "jpeg")] + [InlineData("img/png", "png")] + [InlineData("img/gif", "gif")] + [InlineData("img/svg", "svg")] + [InlineData("unknown/unknown", "data")] + public void GetRequestSuggestedExtension(string contentType, string result) + { + var exchange = Substitute.For(); + + exchange.GetRequestHeaders().Returns( + new[] { + new HeaderFieldInfo("Content-Type", contentType) + } + ); + + var suggestion = HeaderUtility.GetRequestSuggestedExtension(exchange); + + Assert.Equal(result, suggestion); + } + + [Theory] + [InlineData("application/json", "json")] + [InlineData("application/xml", "xml")] + [InlineData("text/html", "html")] + [InlineData("text/plain", "txt")] + [InlineData("application/javascript", "js")] + [InlineData("application/pdf", "pdf")] + [InlineData("text/font", "font")] + [InlineData("text/css", "css")] + [InlineData("img/jpg", "jpeg")] + [InlineData("img/jpeg", "jpeg")] + [InlineData("img/png", "png")] + [InlineData("img/gif", "gif")] + [InlineData("img/svg", "svg")] + [InlineData("unknown/unknown", "data")] + public void GetResponseSuggestedExtension(string contentType, string result) + { + var exchange = Substitute.For(); + + exchange.GetResponseHeaders().Returns( + new[] { + new HeaderFieldInfo("Content-Type", contentType) + } + ); + + var suggestion = HeaderUtility.GetResponseSuggestedExtension(exchange); + + Assert.Equal(result, suggestion); + } + + [Theory] + [InlineData("application/json", "json")] + [InlineData("application/xml", "xml")] + [InlineData("text/html", "html")] + [InlineData("text/plain", "text")] + [InlineData("application/javascript", "js")] + [InlineData("application/pdf", "pdf")] + [InlineData("text/font", "font")] + [InlineData("text/css", "css")] + [InlineData("image/jpg", "img")] + [InlineData("image/jpeg", "img")] + [InlineData("image/png", "img")] + [InlineData("image/gif", "img")] + [InlineData("image/svg", "img")] + [InlineData("application/octet-stream", "bin")] + public void GetSimplifiedContentType(string contentType, string result) + { + var exchange = Substitute.For(); + + exchange.GetResponseHeaders().Returns( + new[] { + new HeaderFieldInfo("Content-Type", contentType) + } + ); + + var suggestion = HeaderUtility.GetSimplifiedContentType(exchange); + + Assert.Equal(result, suggestion); + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Util/StringHelperTests.cs b/test/Fluxzy.Tests/UnitTests/Util/StringHelperTests.cs new file mode 100644 index 000000000..dca04b083 --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Util/StringHelperTests.cs @@ -0,0 +1,49 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using Fluxzy.Utils; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Util +{ + public class StringHelperTests + { + [Theory] + [InlineData("HelloWorld", "helloWorld")] + [InlineData("helloWorld", "helloWorld")] + [InlineData("hello", "hello")] + [InlineData("h", "h")] + [InlineData("", "")] + public void ToCamelCase(string input, string expected) + { + var result = input.ToCamelCase(); + + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("helloWorld", "HelloWorld.")] + [InlineData("HelloWorld", "HelloWorld.")] + [InlineData("hello", "Hello.")] + [InlineData("h", "h")] + [InlineData("", "")] + public void AddTrailingDotAndUpperCaseFirstChar(string input, string expected) + { + var result = input.AddTrailingDotAndUpperCaseFirstChar(); + + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("hello\"World", "hello\\\"World")] + [InlineData("helloWorld", "helloWorld")] + [InlineData("hello", "hello")] + [InlineData("h", "h")] + [InlineData("", "")] + public void EscapeDoubleQuote(string input, string expected) + { + var result = input.EscapeDoubleQuote(); + + Assert.Equal(expected, result); + } + } +} diff --git a/test/Fluxzy.Tests/UnitTests/Util/SubdomainUtilityTests.cs b/test/Fluxzy.Tests/UnitTests/Util/SubdomainUtilityTests.cs new file mode 100644 index 000000000..f1813143f --- /dev/null +++ b/test/Fluxzy.Tests/UnitTests/Util/SubdomainUtilityTests.cs @@ -0,0 +1,29 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using Fluxzy.Utils; +using Xunit; + +namespace Fluxzy.Tests.UnitTests.Util +{ + public class SubdomainUtilityTests + { + [Theory] + [InlineData("www.google.com", "google.com")] + [InlineData("google.com", "google.com")] + [InlineData("google", null)] + [InlineData("", null)] + public void TryGetSubDomain(string input, string? expected) + { + var result = SubdomainUtility.TryGetSubDomain(input, out var subDomain); + + if (expected != null) { + Assert.True(result); + Assert.Equal(expected, subDomain); + } + else { + Assert.False(result); + Assert.Null(subDomain); + } + } + } +} diff --git a/test/Fluxzy.Tests/_Files/Archives/with-request-payload.fxzy b/test/Fluxzy.Tests/_Files/Archives/with-request-payload.fxzy new file mode 100644 index 0000000000000000000000000000000000000000..e3e506c5792d3d7d89429ddf5462ca67580e8bb5 GIT binary patch literal 13491 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 T<}QKS3KWnlu-9YZg5CWeDZU5* literal 0 HcmV?d00001 diff --git a/test/Fluxzy.Tests/_Fixtures/ProduceDeletableItem.cs b/test/Fluxzy.Tests/_Fixtures/ProduceDeletableItem.cs index 5f451a8ff..d384f66f2 100644 --- a/test/Fluxzy.Tests/_Fixtures/ProduceDeletableItem.cs +++ b/test/Fluxzy.Tests/_Fixtures/ProduceDeletableItem.cs @@ -42,6 +42,13 @@ protected string GetRegisteredRandomFile() return RegisterFile(tempFileName); } + protected string GetRegisteredRandomDirectory(bool create = false) + { + var tempFileName = $"{nameof(ProduceDeletableItem)}/_dir{Guid.NewGuid()}"; + + return RegisterDirectory(tempFileName, create); + } + protected string RegisterFile(string fileName, bool createParentDirectory = true) { var fileInfo = new FileInfo(fileName);