mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-05-22 19:05:09 -04:00
Some more tests
This commit is contained in:
parent
402b5cc7d0
commit
af11064a85
12 changed files with 513 additions and 101 deletions
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
@ -23,9 +24,12 @@ namespace DiscordChatExporter.Cli.Tests.Fixtures
|
||||||
Guid.NewGuid().ToString()
|
Guid.NewGuid().ToString()
|
||||||
);
|
);
|
||||||
|
|
||||||
public async ValueTask<IHtmlDocument> ExportAsHtmlAsync(Snowflake channelId)
|
public ExportWrapperFixture() => DirectoryEx.Reset(DirPath);
|
||||||
|
|
||||||
|
private async ValueTask<string> ExportAsync(Snowflake channelId, ExportFormat format)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(DirPath, channelId + ".html");
|
var fileName = channelId.ToString() + '.' + format.GetFileExtension();
|
||||||
|
var filePath = Path.Combine(DirPath, fileName);
|
||||||
|
|
||||||
// Perform export only if it hasn't been done before
|
// Perform export only if it hasn't been done before
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
|
@ -35,83 +39,61 @@ namespace DiscordChatExporter.Cli.Tests.Fixtures
|
||||||
TokenValue = Secrets.DiscordToken,
|
TokenValue = Secrets.DiscordToken,
|
||||||
IsBotToken = Secrets.IsDiscordTokenBot,
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
ChannelIds = new[] { channelId },
|
ChannelIds = new[] { channelId },
|
||||||
ExportFormat = ExportFormat.HtmlDark,
|
ExportFormat = format,
|
||||||
OutputPath = filePath
|
OutputPath = filePath
|
||||||
}.ExecuteAsync(new FakeConsole());
|
}.ExecuteAsync(new FakeConsole());
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = await File.ReadAllTextAsync(filePath);
|
return await File.ReadAllTextAsync(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<IHtmlDocument> ExportAsHtmlAsync(Snowflake channelId)
|
||||||
|
{
|
||||||
|
var data = await ExportAsync(channelId, ExportFormat.HtmlDark);
|
||||||
return Html.Parse(data);
|
return Html.Parse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<JsonElement> ExportAsJsonAsync(Snowflake channelId)
|
public async ValueTask<JsonElement> ExportAsJsonAsync(Snowflake channelId)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(DirPath, channelId + ".json");
|
var data = await ExportAsync(channelId, ExportFormat.Json);
|
||||||
|
|
||||||
// Perform export only if it hasn't been done before
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
await new ExportChannelsCommand
|
|
||||||
{
|
|
||||||
TokenValue = Secrets.DiscordToken,
|
|
||||||
IsBotToken = Secrets.IsDiscordTokenBot,
|
|
||||||
ChannelIds = new[] { channelId },
|
|
||||||
ExportFormat = ExportFormat.Json,
|
|
||||||
OutputPath = filePath
|
|
||||||
}.ExecuteAsync(new FakeConsole());
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = await File.ReadAllTextAsync(filePath);
|
|
||||||
|
|
||||||
return Json.Parse(data);
|
return Json.Parse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<string> ExportAsPlainTextAsync(Snowflake channelId)
|
public async ValueTask<string> ExportAsPlainTextAsync(Snowflake channelId)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(DirPath, channelId + ".txt");
|
var data = await ExportAsync(channelId, ExportFormat.PlainText);
|
||||||
|
return data;
|
||||||
// Perform export only if it hasn't been done before
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
await new ExportChannelsCommand
|
|
||||||
{
|
|
||||||
TokenValue = Secrets.DiscordToken,
|
|
||||||
IsBotToken = Secrets.IsDiscordTokenBot,
|
|
||||||
ChannelIds = new[] { channelId },
|
|
||||||
ExportFormat = ExportFormat.PlainText,
|
|
||||||
OutputPath = filePath
|
|
||||||
}.ExecuteAsync(new FakeConsole());
|
|
||||||
}
|
|
||||||
|
|
||||||
return await File.ReadAllTextAsync(filePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<string> ExportAsCsvAsync(Snowflake channelId)
|
public async ValueTask<string> ExportAsCsvAsync(Snowflake channelId)
|
||||||
{
|
{
|
||||||
var filePath = Path.Combine(DirPath, channelId + ".csv");
|
var data = await ExportAsync(channelId, ExportFormat.Csv);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
// Perform export only if it hasn't been done before
|
public async ValueTask<IReadOnlyList<IElement>> GetMessagesAsHtmlAsync(Snowflake channelId)
|
||||||
if (!File.Exists(filePath))
|
{
|
||||||
{
|
var document = await ExportAsHtmlAsync(channelId);
|
||||||
await new ExportChannelsCommand
|
return document.QuerySelectorAll("[data-message-id]").ToArray();
|
||||||
{
|
}
|
||||||
TokenValue = Secrets.DiscordToken,
|
|
||||||
IsBotToken = Secrets.IsDiscordTokenBot,
|
|
||||||
ChannelIds = new[] { channelId },
|
|
||||||
ExportFormat = ExportFormat.Csv,
|
|
||||||
OutputPath = filePath
|
|
||||||
}.ExecuteAsync(new FakeConsole());
|
|
||||||
}
|
|
||||||
|
|
||||||
return await File.ReadAllTextAsync(filePath);
|
public async ValueTask<IReadOnlyList<JsonElement>> GetMessagesAsJsonAsync(Snowflake channelId)
|
||||||
|
{
|
||||||
|
var document = await ExportAsJsonAsync(channelId);
|
||||||
|
return document.GetProperty("messages").EnumerateArray().ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<IElement> GetMessageAsHtmlAsync(Snowflake channelId, Snowflake messageId)
|
public async ValueTask<IElement> GetMessageAsHtmlAsync(Snowflake channelId, Snowflake messageId)
|
||||||
{
|
{
|
||||||
var document = await ExportAsHtmlAsync(channelId);
|
var messages = await GetMessagesAsHtmlAsync(channelId);
|
||||||
|
|
||||||
var message = document.QuerySelector("#message-" + messageId);
|
var message = messages.SingleOrDefault(e =>
|
||||||
|
string.Equals(
|
||||||
|
e.GetAttribute("data-message-id"),
|
||||||
|
messageId.ToString(),
|
||||||
|
StringComparison.OrdinalIgnoreCase
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (message is null)
|
if (message is null)
|
||||||
{
|
{
|
||||||
|
@ -125,16 +107,15 @@ namespace DiscordChatExporter.Cli.Tests.Fixtures
|
||||||
|
|
||||||
public async ValueTask<JsonElement> GetMessageAsJsonAsync(Snowflake channelId, Snowflake messageId)
|
public async ValueTask<JsonElement> GetMessageAsJsonAsync(Snowflake channelId, Snowflake messageId)
|
||||||
{
|
{
|
||||||
var document = await ExportAsJsonAsync(channelId);
|
var messages = await GetMessagesAsJsonAsync(channelId);
|
||||||
|
|
||||||
var message = document
|
var message = messages.FirstOrDefault(j =>
|
||||||
.GetProperty("messages")
|
string.Equals(
|
||||||
.EnumerateArray()
|
|
||||||
.SingleOrDefault(j => string.Equals(
|
|
||||||
j.GetProperty("id").GetString(),
|
j.GetProperty("id").GetString(),
|
||||||
messageId.ToString(),
|
messageId.ToString(),
|
||||||
StringComparison.OrdinalIgnoreCase
|
StringComparison.OrdinalIgnoreCase
|
||||||
));
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (message.ValueKind == JsonValueKind.Undefined)
|
if (message.ValueKind == JsonValueKind.Undefined)
|
||||||
{
|
{
|
||||||
|
@ -146,15 +127,6 @@ namespace DiscordChatExporter.Cli.Tests.Fixtures
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose() => DirectoryEx.DeleteIfExists(DirPath);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.Delete(DirPath, true);
|
|
||||||
}
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
23
DiscordChatExporter.Cli.Tests/Fixtures/TempOutputFixture.cs
Normal file
23
DiscordChatExporter.Cli.Tests/Fixtures/TempOutputFixture.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Utils;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Fixtures
|
||||||
|
{
|
||||||
|
public class TempOutputFixture : IDisposable
|
||||||
|
{
|
||||||
|
public string DirPath { get; } = Path.Combine(
|
||||||
|
Path.GetDirectoryName(typeof(TempOutputFixture).Assembly.Location) ?? Directory.GetCurrentDirectory(),
|
||||||
|
"Temp",
|
||||||
|
Guid.NewGuid().ToString()
|
||||||
|
);
|
||||||
|
|
||||||
|
public TempOutputFixture() => DirectoryEx.Reset(DirPath);
|
||||||
|
|
||||||
|
public string GetTempFilePath(string fileName) => Path.Combine(DirPath, fileName);
|
||||||
|
|
||||||
|
public string GetTempFilePath() => GetTempFilePath(Guid.NewGuid() + ".tmp");
|
||||||
|
|
||||||
|
public void Dispose() => DirectoryEx.DeleteIfExists(DirPath);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ using Xunit;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Tests.Specs.CsvWriting
|
namespace DiscordChatExporter.Cli.Tests.Specs.CsvWriting
|
||||||
{
|
{
|
||||||
public record GeneralSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
public record ContentSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Messages_are_exported_correctly()
|
public async Task Messages_are_exported_correctly()
|
160
DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs
Normal file
160
DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
|
using DiscordChatExporter.Cli.Commands;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Fixtures;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Infra;
|
||||||
|
using DiscordChatExporter.Cli.Tests.TestData;
|
||||||
|
using DiscordChatExporter.Core.Discord;
|
||||||
|
using DiscordChatExporter.Core.Exporting;
|
||||||
|
using FluentAssertions;
|
||||||
|
using JsonExtensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Specs
|
||||||
|
{
|
||||||
|
public record DateRangeSpecs(TempOutputFixture TempOutput) : IClassFixture<TempOutputFixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_after_specific_date_only_include_messages_sent_after_that_date()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var after = new DateTimeOffset(2021, 07, 24, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.DateRangeTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
After = Snowflake.FromDate(after)
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
var timestamps = document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
timestamps.All(t => t > after).Should().BeTrue();
|
||||||
|
|
||||||
|
timestamps.Should().BeEquivalentTo(new[]
|
||||||
|
{
|
||||||
|
new DateTimeOffset(2021, 07, 24, 13, 49, 13, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 09, 08, 14, 26, 35, TimeSpan.Zero)
|
||||||
|
}, o =>
|
||||||
|
{
|
||||||
|
return o
|
||||||
|
.Using<DateTimeOffset>(ctx =>
|
||||||
|
ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromSeconds(1))
|
||||||
|
)
|
||||||
|
.WhenTypeIs<DateTimeOffset>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_before_specific_date_only_include_messages_sent_before_that_date()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var before = new DateTimeOffset(2021, 07, 24, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.DateRangeTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
Before = Snowflake.FromDate(before)
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
var timestamps = document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
timestamps.All(t => t < before).Should().BeTrue();
|
||||||
|
|
||||||
|
timestamps.Should().BeEquivalentTo(new[]
|
||||||
|
{
|
||||||
|
new DateTimeOffset(2021, 07, 19, 13, 34, 18, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 19, 15, 58, 48, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 19, 17, 23, 58, TimeSpan.Zero)
|
||||||
|
}, o =>
|
||||||
|
{
|
||||||
|
return o
|
||||||
|
.Using<DateTimeOffset>(ctx =>
|
||||||
|
ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromSeconds(1))
|
||||||
|
)
|
||||||
|
.WhenTypeIs<DateTimeOffset>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_between_specific_dates_only_include_messages_sent_between_those_dates()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var after = new DateTimeOffset(2021, 07, 24, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var before = new DateTimeOffset(2021, 08, 01, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.DateRangeTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
Before = Snowflake.FromDate(before),
|
||||||
|
After = Snowflake.FromDate(after)
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
var timestamps = document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("timestamp").GetDateTimeOffset())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
timestamps.All(t => t < before && t > after).Should().BeTrue();
|
||||||
|
|
||||||
|
timestamps.Should().BeEquivalentTo(new[]
|
||||||
|
{
|
||||||
|
new DateTimeOffset(2021, 07, 24, 13, 49, 13, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 38, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 39, TimeSpan.Zero),
|
||||||
|
new DateTimeOffset(2021, 07, 24, 14, 52, 40, TimeSpan.Zero)
|
||||||
|
}, o =>
|
||||||
|
{
|
||||||
|
return o
|
||||||
|
.Using<DateTimeOffset>(ctx =>
|
||||||
|
ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromSeconds(1))
|
||||||
|
)
|
||||||
|
.WhenTypeIs<DateTimeOffset>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs
Normal file
135
DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
|
using DiscordChatExporter.Cli.Commands;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Fixtures;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Infra;
|
||||||
|
using DiscordChatExporter.Cli.Tests.TestData;
|
||||||
|
using DiscordChatExporter.Core.Exporting;
|
||||||
|
using DiscordChatExporter.Core.Exporting.Filtering;
|
||||||
|
using FluentAssertions;
|
||||||
|
using JsonExtensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Specs
|
||||||
|
{
|
||||||
|
public record FilterSpecs(TempOutputFixture TempOutput) : IClassFixture<TempOutputFixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_by_text_only_include_messages_that_contain_that_text()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.FilterTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
MessageFilter = MessageFilter.Parse("some text")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("content").GetString())
|
||||||
|
.Should()
|
||||||
|
.ContainSingle("Some random text");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_by_author_only_include_messages_sent_by_that_author()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.FilterTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
MessageFilter = MessageFilter.Parse("from:Tyrrrz")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("author").GetProperty("name").GetString())
|
||||||
|
.Should()
|
||||||
|
.AllBe("Tyrrrz");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_by_content_only_include_messages_that_have_that_content()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.FilterTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
MessageFilter = MessageFilter.Parse("has:image")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("content").GetString())
|
||||||
|
.Should()
|
||||||
|
.ContainSingle("This has image");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_filtered_by_mention_only_include_messages_that_have_that_mention()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.FilterTestCases },
|
||||||
|
ExportFormat = ExportFormat.Json,
|
||||||
|
OutputPath = filePath,
|
||||||
|
MessageFilter = MessageFilter.Parse("mentions:Tyrrrz")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Json.Parse(data);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
document
|
||||||
|
.GetProperty("messages")
|
||||||
|
.EnumerateArray()
|
||||||
|
.Select(j => j.GetProperty("content").GetString())
|
||||||
|
.Should()
|
||||||
|
.ContainSingle("This has mention");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,26 +8,16 @@ using Xunit;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Tests.Specs.HtmlWriting
|
namespace DiscordChatExporter.Cli.Tests.Specs.HtmlWriting
|
||||||
{
|
{
|
||||||
public record GeneralSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
public record ContentSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Messages_are_exported_correctly()
|
public async Task Messages_are_exported_correctly()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var document = await ExportWrapper.ExportAsHtmlAsync(ChannelIds.DateRangeTestCases);
|
var messages = await ExportWrapper.GetMessagesAsHtmlAsync(ChannelIds.DateRangeTestCases);
|
||||||
|
|
||||||
var messageIds = document
|
|
||||||
.QuerySelectorAll(".chatlog__message")
|
|
||||||
.Select(e => e.GetAttribute("data-message-id"))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
var messageTexts = document
|
|
||||||
.QuerySelectorAll(".chatlog__content")
|
|
||||||
.Select(e => e.Text().Trim())
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
messageIds.Should().Equal(
|
messages.Select(e => e.GetAttribute("data-message-id")).Should().Equal(
|
||||||
"866674314627121232",
|
"866674314627121232",
|
||||||
"866710679758045195",
|
"866710679758045195",
|
||||||
"866732113319428096",
|
"866732113319428096",
|
||||||
|
@ -38,7 +28,7 @@ namespace DiscordChatExporter.Cli.Tests.Specs.HtmlWriting
|
||||||
"885169254029213696"
|
"885169254029213696"
|
||||||
);
|
);
|
||||||
|
|
||||||
messageTexts.Should().Equal(
|
messages.Select(e => e.QuerySelector(".chatlog__content")?.Text().Trim()).Should().Equal(
|
||||||
"Hello world",
|
"Hello world",
|
||||||
"Goodbye world",
|
"Goodbye world",
|
||||||
"Foo bar",
|
"Foo bar",
|
|
@ -7,28 +7,16 @@ using Xunit;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Tests.Specs.JsonWriting
|
namespace DiscordChatExporter.Cli.Tests.Specs.JsonWriting
|
||||||
{
|
{
|
||||||
public record GeneralSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
public record ContentSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Messages_are_exported_correctly()
|
public async Task Messages_are_exported_correctly()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var document = await ExportWrapper.ExportAsJsonAsync(ChannelIds.DateRangeTestCases);
|
var messages = await ExportWrapper.GetMessagesAsJsonAsync(ChannelIds.DateRangeTestCases);
|
||||||
|
|
||||||
var messageIds = document
|
|
||||||
.GetProperty("messages")
|
|
||||||
.EnumerateArray()
|
|
||||||
.Select(j => j.GetProperty("id").GetString())
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
var messageTexts = document
|
|
||||||
.GetProperty("messages")
|
|
||||||
.EnumerateArray()
|
|
||||||
.Select(j => j.GetProperty("content").GetString())
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
messageIds.Should().Equal(
|
messages.Select(j => j.GetProperty("id").GetString()).Should().Equal(
|
||||||
"866674314627121232",
|
"866674314627121232",
|
||||||
"866710679758045195",
|
"866710679758045195",
|
||||||
"866732113319428096",
|
"866732113319428096",
|
||||||
|
@ -39,7 +27,7 @@ namespace DiscordChatExporter.Cli.Tests.Specs.JsonWriting
|
||||||
"885169254029213696"
|
"885169254029213696"
|
||||||
);
|
);
|
||||||
|
|
||||||
messageTexts.Should().Equal(
|
messages.Select(j => j.GetProperty("content").GetString()).Should().Equal(
|
||||||
"Hello world",
|
"Hello world",
|
||||||
"Goodbye world",
|
"Goodbye world",
|
||||||
"Foo bar",
|
"Foo bar",
|
67
DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs
Normal file
67
DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
|
using DiscordChatExporter.Cli.Commands;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Fixtures;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Infra;
|
||||||
|
using DiscordChatExporter.Cli.Tests.TestData;
|
||||||
|
using DiscordChatExporter.Core.Exporting;
|
||||||
|
using DiscordChatExporter.Core.Exporting.Partitioning;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Specs
|
||||||
|
{
|
||||||
|
public record PartitioningSpecs(TempOutputFixture TempOutput) : IClassFixture<TempOutputFixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_partitioned_by_count_are_split_into_multiple_files_correctly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
var dirPath = Path.GetDirectoryName(filePath) ?? Directory.GetCurrentDirectory();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.DateRangeTestCases },
|
||||||
|
ExportFormat = ExportFormat.HtmlDark,
|
||||||
|
OutputPath = filePath,
|
||||||
|
PartitionLimit = PartitionLimit.Parse("3")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Directory.EnumerateFiles(dirPath, fileNameWithoutExt + "*")
|
||||||
|
.Should()
|
||||||
|
.HaveCount(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_partitioned_by_file_size_are_split_into_multiple_files_correctly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
var dirPath = Path.GetDirectoryName(filePath) ?? Directory.GetCurrentDirectory();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.DateRangeTestCases },
|
||||||
|
ExportFormat = ExportFormat.HtmlDark,
|
||||||
|
OutputPath = filePath,
|
||||||
|
PartitionLimit = PartitionLimit.Parse("20kb")
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Directory.EnumerateFiles(dirPath, fileNameWithoutExt + "*")
|
||||||
|
.Should()
|
||||||
|
.HaveCount(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ using Xunit;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Cli.Tests.Specs.PlainTextWriting
|
namespace DiscordChatExporter.Cli.Tests.Specs.PlainTextWriting
|
||||||
{
|
{
|
||||||
public record GeneralSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
public record ContentSpecs(ExportWrapperFixture ExportWrapper) : IClassFixture<ExportWrapperFixture>
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Messages_are_exported_correctly()
|
public async Task Messages_are_exported_correctly()
|
49
DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs
Normal file
49
DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
|
using DiscordChatExporter.Cli.Commands;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Fixtures;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Infra;
|
||||||
|
using DiscordChatExporter.Cli.Tests.TestData;
|
||||||
|
using DiscordChatExporter.Cli.Tests.Utils;
|
||||||
|
using DiscordChatExporter.Core.Exporting;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Specs
|
||||||
|
{
|
||||||
|
public record SelfContainedSpecs(TempOutputFixture TempOutput) : IClassFixture<TempOutputFixture>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Messages_in_self_contained_export_only_reference_local_file_resources()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filePath = TempOutput.GetTempFilePath();
|
||||||
|
var dirPath = Path.GetDirectoryName(filePath) ?? Directory.GetCurrentDirectory();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await new ExportChannelsCommand
|
||||||
|
{
|
||||||
|
TokenValue = Secrets.DiscordToken,
|
||||||
|
IsBotToken = Secrets.IsDiscordTokenBot,
|
||||||
|
ChannelIds = new[] { ChannelIds.SelfContainedTestCases },
|
||||||
|
ExportFormat = ExportFormat.HtmlDark,
|
||||||
|
OutputPath = filePath,
|
||||||
|
ShouldDownloadMedia = true
|
||||||
|
}.ExecuteAsync(new FakeConsole());
|
||||||
|
|
||||||
|
var data = await File.ReadAllTextAsync(filePath);
|
||||||
|
var document = Html.Parse(data);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
document
|
||||||
|
.QuerySelectorAll("body [src]")
|
||||||
|
.Select(e => e.GetAttribute("src")!)
|
||||||
|
.Select(f => Path.GetFullPath(f, dirPath))
|
||||||
|
.All(File.Exists)
|
||||||
|
.Should()
|
||||||
|
.BeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,12 @@ namespace DiscordChatExporter.Cli.Tests.TestData
|
||||||
|
|
||||||
public static Snowflake EmbedTestCases { get; } = Snowflake.Parse("866472452459462687");
|
public static Snowflake EmbedTestCases { get; } = Snowflake.Parse("866472452459462687");
|
||||||
|
|
||||||
|
public static Snowflake FilterTestCases { get; } = Snowflake.Parse("866744075033641020");
|
||||||
|
|
||||||
public static Snowflake MentionTestCases { get; } = Snowflake.Parse("866458801389174794");
|
public static Snowflake MentionTestCases { get; } = Snowflake.Parse("866458801389174794");
|
||||||
|
|
||||||
public static Snowflake ReplyTestCases { get; } = Snowflake.Parse("866459871934677052");
|
public static Snowflake ReplyTestCases { get; } = Snowflake.Parse("866459871934677052");
|
||||||
|
|
||||||
|
public static Snowflake SelfContainedTestCases { get; } = Snowflake.Parse("887441432678379560");
|
||||||
}
|
}
|
||||||
}
|
}
|
24
DiscordChatExporter.Cli.Tests/Utils/DirectoryEx.cs
Normal file
24
DiscordChatExporter.Cli.Tests/Utils/DirectoryEx.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Cli.Tests.Utils
|
||||||
|
{
|
||||||
|
internal static class DirectoryEx
|
||||||
|
{
|
||||||
|
public static void DeleteIfExists(string dirPath, bool recursive = true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.Delete(dirPath, recursive);
|
||||||
|
}
|
||||||
|
catch (DirectoryNotFoundException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Reset(string dirPath)
|
||||||
|
{
|
||||||
|
DeleteIfExists(dirPath);
|
||||||
|
Directory.CreateDirectory(dirPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue