2
0
forked from sim0n00ps/OF-DL
OF-DL/OF DL.Tests/Services/TestDoubles.cs

514 lines
24 KiB
C#

using Newtonsoft.Json.Linq;
using OF_DL.Enumerations;
using OF_DL.Models;
using OF_DL.Models.Config;
using OF_DL.Models.Downloads;
using OF_DL.Services;
using Serilog.Core;
using Serilog.Events;
using ArchivedEntities = OF_DL.Models.Entities.Archived;
using MessageEntities = OF_DL.Models.Entities.Messages;
using PostEntities = OF_DL.Models.Entities.Posts;
using PurchasedEntities = OF_DL.Models.Entities.Purchased;
using StreamEntities = OF_DL.Models.Entities.Streams;
using UserEntities = OF_DL.Models.Entities.Users;
namespace OF_DL.Tests.Services;
internal sealed class TempFolder : IDisposable
{
public TempFolder()
{
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ofdl-tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(Path);
}
public string Path { get; }
public void Dispose()
{
try
{
Directory.Delete(Path, true);
}
catch
{
// ignored
}
}
}
internal sealed class ProgressRecorder : IProgressReporter
{
public long Total { get; private set; }
public void ReportProgress(long increment) => Total += increment;
}
internal sealed class FakeConfigService(Config config) : IConfigService
{
public Config CurrentConfig { get; private set; } = config;
public bool IsCliNonInteractive { get; } = config.NonInteractiveMode;
public Task<bool> LoadConfigurationAsync(string[] args) => Task.FromResult(true);
public Task SaveConfigurationAsync(string filePath = "config.conf") => Task.CompletedTask;
public void UpdateConfig(Config newConfig) => CurrentConfig = newConfig;
public List<(string Name, bool Value)> GetToggleableProperties() => [];
public bool ApplyToggleableSelections(List<string> selectedNames) => false;
}
internal sealed class MediaTrackingDbService : IDbService
{
public bool CheckDownloadedResult { get; init; }
public long StoredFileSize { get; init; }
public (string folder, long mediaId, string apiType, string directory, string filename, long size,
bool downloaded, DateTime createdAt)? LastUpdateMedia { get; private set; }
public Task UpdateMedia(string folder, long mediaId, string apiType, string directory, string filename,
long size, bool downloaded, DateTime createdAt)
{
LastUpdateMedia = (folder, mediaId, apiType, directory, filename, size, downloaded, createdAt);
return Task.CompletedTask;
}
public Task<long> GetStoredFileSize(string folder, long mediaId, string apiType) =>
Task.FromResult(StoredFileSize);
public Task<bool> CheckDownloaded(string folder, long mediaId, string apiType) =>
Task.FromResult(CheckDownloadedResult);
public Task AddMessage(string folder, long postId, string messageText, string price, bool isPaid,
bool isArchived, DateTime createdAt, long userId) => throw new NotImplementedException();
public Task AddPost(string folder, long postId, string messageText, string price, bool isPaid, bool isArchived,
DateTime createdAt) => throw new NotImplementedException();
public Task AddStory(string folder, long postId, string messageText, string price, bool isPaid, bool isArchived,
DateTime createdAt) => throw new NotImplementedException();
public Task CreateDb(string folder) => throw new NotImplementedException();
public Task CreateUsersDb(Dictionary<string, long> users) => throw new NotImplementedException();
public Task CheckUsername(KeyValuePair<string, long> user, string path) => throw new NotImplementedException();
public Task AddMedia(string folder, long mediaId, long postId, string link, string? directory,
string? filename, long? size, string apiType, string mediaType, bool preview, bool downloaded,
DateTime? createdAt) => throw new NotImplementedException();
public Task<DateTime?> GetMostRecentPostDate(string folder) => throw new NotImplementedException();
}
internal sealed class StaticApiService : IApiService
{
public Dictionary<long, string>? MediaToReturn { get; init; }
public DateTime LastModifiedToReturn { get; set; } = new(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public bool OfdlCalled { get; private set; }
public bool CdmCalled { get; private set; }
public Task<(string pssh, DateTime lastModified, double? durationSeconds)> GetDrmMpdInfo(
string mpdUrl, string policy, string signature, string kvp) =>
Task.FromResult<(string pssh, DateTime lastModified, double? durationSeconds)>(
("pssh", LastModifiedToReturn, null));
public Task<string> GetDecryptionKeyOfdl(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh)
{
OfdlCalled = true;
return Task.FromResult("ofdl-key");
}
public Task<string> GetDecryptionKeyCdm(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh)
{
CdmCalled = true;
return Task.FromResult("cdm-key");
}
public Dictionary<string, string> GetDynamicHeaders(string path, string queryParam) =>
new() { { "X-Test", "value" } };
public Task<Dictionary<long, string>?> GetMedia(MediaType mediaType, string endpoint, string? username,
string folder) => Task.FromResult(MediaToReturn);
public Task<Dictionary<string, long>?> GetLists(string endpoint) => throw new NotImplementedException();
public Task<List<string>?> GetListUsers(string endpoint) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Purchased.PaidPostCollection> GetPaidPosts(string endpoint, string folder,
string username, List<long> paidPostIds, IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Posts.PostCollection> GetPosts(string endpoint, string folder,
List<long> paidPostIds, IStatusReporter statusReporter) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Posts.SinglePostCollection> GetPost(string endpoint, string folder) =>
throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Streams.StreamsCollection> GetStreams(string endpoint, string folder,
List<long> paidPostIds, IStatusReporter statusReporter) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Archived.ArchivedCollection> GetArchived(string endpoint, string folder,
IStatusReporter statusReporter) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Messages.MessageCollection> GetMessages(string endpoint, string folder,
IStatusReporter statusReporter) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Purchased.PaidMessageCollection> GetPaidMessages(string endpoint,
string folder, string username, IStatusReporter statusReporter) => throw new NotImplementedException();
public Task<OF_DL.Models.Entities.Purchased.SinglePaidMessageCollection> GetPaidMessage(string endpoint,
string folder) => throw new NotImplementedException();
public Task<Dictionary<string, long>> GetPurchasedTabUsers(string endpoint, Dictionary<string, long> users) =>
throw new NotImplementedException();
public Task<List<OF_DL.Models.Entities.Purchased.PurchasedTabCollection>> GetPurchasedTab(string endpoint,
string folder, Dictionary<string, long> users) => throw new NotImplementedException();
public Task<UserEntities.User?> GetUserInfo(string endpoint) =>
throw new NotImplementedException();
public Task<JObject?> GetUserInfoById(string endpoint) =>
throw new NotImplementedException();
public Task<Dictionary<string, long>?> GetActiveSubscriptions(string endpoint,
bool includeRestrictedSubscriptions) => throw new NotImplementedException();
public Task<Dictionary<string, long>?> GetExpiredSubscriptions(string endpoint,
bool includeRestrictedSubscriptions) => throw new NotImplementedException();
}
internal sealed class ConfigurableApiService : IApiService
{
public Func<string, bool, Task<Dictionary<string, long>?>>? ActiveSubscriptionsHandler { get; init; }
public Func<string, bool, Task<Dictionary<string, long>?>>? ExpiredSubscriptionsHandler { get; init; }
public Func<string, Task<Dictionary<string, long>?>>? ListsHandler { get; init; }
public Func<string, Task<List<string>?>>? ListUsersHandler { get; init; }
public Func<MediaType, string, string?, string, Task<Dictionary<long, string>?>>? MediaHandler { get; init; }
public Func<string, string, Task<PostEntities.SinglePostCollection>>? PostHandler { get; init; }
public Func<string, string, Task<PurchasedEntities.SinglePaidMessageCollection>>? PaidMessageHandler { get; init; }
public Func<string, Task<UserEntities.User?>>? UserInfoHandler { get; init; }
public Func<string, Task<JObject?>>? UserInfoByIdHandler { get; init; }
public Task<Dictionary<string, long>?> GetActiveSubscriptions(string endpoint,
bool includeRestrictedSubscriptions) =>
ActiveSubscriptionsHandler?.Invoke(endpoint, includeRestrictedSubscriptions) ??
Task.FromResult<Dictionary<string, long>?>(null);
public Task<Dictionary<string, long>?> GetExpiredSubscriptions(string endpoint,
bool includeRestrictedSubscriptions) =>
ExpiredSubscriptionsHandler?.Invoke(endpoint, includeRestrictedSubscriptions) ??
Task.FromResult<Dictionary<string, long>?>(null);
public Task<Dictionary<string, long>?> GetLists(string endpoint) =>
ListsHandler?.Invoke(endpoint) ?? Task.FromResult<Dictionary<string, long>?>(null);
public Task<List<string>?> GetListUsers(string endpoint) =>
ListUsersHandler?.Invoke(endpoint) ?? Task.FromResult<List<string>?>(null);
public Task<Dictionary<long, string>?> GetMedia(MediaType mediaType, string endpoint, string? username,
string folder) =>
MediaHandler?.Invoke(mediaType, endpoint, username, folder) ??
Task.FromResult<Dictionary<long, string>?>(null);
public Task<PostEntities.SinglePostCollection> GetPost(string endpoint, string folder) =>
PostHandler?.Invoke(endpoint, folder) ?? Task.FromResult(new PostEntities.SinglePostCollection());
public Task<PurchasedEntities.SinglePaidMessageCollection> GetPaidMessage(string endpoint, string folder) =>
PaidMessageHandler?.Invoke(endpoint, folder) ??
Task.FromResult(new PurchasedEntities.SinglePaidMessageCollection());
public Task<UserEntities.User?> GetUserInfo(string endpoint) =>
UserInfoHandler?.Invoke(endpoint) ?? Task.FromResult<UserEntities.User?>(null);
public Task<JObject?> GetUserInfoById(string endpoint) =>
UserInfoByIdHandler?.Invoke(endpoint) ?? Task.FromResult<JObject?>(null);
public Task<PurchasedEntities.PaidPostCollection> GetPaidPosts(string endpoint, string folder, string username,
List<long> paidPostIds, IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<PostEntities.PostCollection> GetPosts(string endpoint, string folder, List<long> paidPostIds,
IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<StreamEntities.StreamsCollection> GetStreams(string endpoint, string folder, List<long> paidPostIds,
IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<ArchivedEntities.ArchivedCollection> GetArchived(string endpoint, string folder,
IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<MessageEntities.MessageCollection> GetMessages(string endpoint, string folder,
IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<PurchasedEntities.PaidMessageCollection> GetPaidMessages(string endpoint, string folder,
string username, IStatusReporter statusReporter) =>
throw new NotImplementedException();
public Task<Dictionary<string, long>> GetPurchasedTabUsers(string endpoint, Dictionary<string, long> users) =>
throw new NotImplementedException();
public Task<List<PurchasedEntities.PurchasedTabCollection>> GetPurchasedTab(string endpoint, string folder,
Dictionary<string, long> users) =>
throw new NotImplementedException();
public Dictionary<string, string> GetDynamicHeaders(string path, string queryParam) =>
throw new NotImplementedException();
public Task<string> GetDecryptionKeyCdm(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh) =>
throw new NotImplementedException();
public Task<(string pssh, DateTime lastModified, double? durationSeconds)> GetDrmMpdInfo(
string mpdUrl, string policy, string signature, string kvp) =>
throw new NotImplementedException();
public Task<string> GetDecryptionKeyOfdl(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh) =>
throw new NotImplementedException();
}
internal sealed class OrchestrationDownloadServiceStub : IDownloadService
{
public bool SinglePostCalled { get; private set; }
public bool SinglePaidMessageCalled { get; private set; }
public DownloadResult? SinglePostResult { get; init; }
public DownloadResult? SinglePaidMessageResult { get; init; }
public DownloadResult? StoriesResult { get; init; }
public Task<long> CalculateTotalFileSize(List<string> urls) => Task.FromResult((long)urls.Count);
public Task<bool> ProcessMediaDownload(string folder, long mediaId, string apiType, string url, string path,
string serverFileName, string resolvedFileName, string extension, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<(string decryptionKey, DateTime lastModified, double? mpdDurationSeconds)?> GetDecryptionInfo(string mpdUrl, string policy,
string signature, string kvp, string mediaId, string contentId, string drmType, bool clientIdBlobMissing,
bool devicePrivateKeyMissing) =>
throw new NotImplementedException();
public Task DownloadAvatarHeader(string? avatarUrl, string? headerUrl, string folder, string username) =>
Task.CompletedTask;
public Task<DownloadResult> DownloadHighlights(string username, long userId, string path,
HashSet<long> paidPostIds, IProgressReporter progressReporter) =>
Task.FromResult(new DownloadResult());
public Task<DownloadResult> DownloadStories(string username, long userId, string path,
HashSet<long> paidPostIds, IProgressReporter progressReporter) =>
Task.FromResult(StoriesResult ?? new DownloadResult());
public Task<DownloadResult> DownloadArchived(string username, long userId, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
ArchivedEntities.ArchivedCollection archived, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadMessages(string username, long userId, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
MessageEntities.MessageCollection messages, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadPaidMessages(string username, string path, Dictionary<string, long> users,
bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PurchasedEntities.PaidMessageCollection paidMessageCollection, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadStreams(string username, long userId, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
StreamEntities.StreamsCollection streams, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadFreePosts(string username, long userId, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PostEntities.PostCollection posts, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadPaidPosts(string username, long userId, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PurchasedEntities.PaidPostCollection purchasedPosts, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadPaidPostsPurchasedTab(string username, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PurchasedEntities.PaidPostCollection purchasedPosts, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadPaidMessagesPurchasedTab(string username, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PurchasedEntities.PaidMessageCollection paidMessageCollection, IProgressReporter progressReporter) =>
throw new NotImplementedException();
public Task<DownloadResult> DownloadSinglePost(string username, string path, Dictionary<string, long> users,
bool clientIdBlobMissing, bool devicePrivateKeyMissing, PostEntities.SinglePostCollection post,
IProgressReporter progressReporter)
{
SinglePostCalled = true;
return Task.FromResult(SinglePostResult ?? new DownloadResult());
}
public Task<DownloadResult> DownloadSinglePaidMessage(string username, string path,
Dictionary<string, long> users, bool clientIdBlobMissing, bool devicePrivateKeyMissing,
PurchasedEntities.SinglePaidMessageCollection singlePaidMessageCollection,
IProgressReporter progressReporter)
{
SinglePaidMessageCalled = true;
return Task.FromResult(SinglePaidMessageResult ?? new DownloadResult());
}
}
internal sealed class UserTrackingDbService : IDbService
{
public Dictionary<string, long>? CreatedUsers { get; private set; }
public List<string> CreatedDbs { get; } = [];
public (KeyValuePair<string, long> user, string path)? CheckedUser { get; private set; }
public Task CreateDb(string folder)
{
CreatedDbs.Add(folder);
return Task.CompletedTask;
}
public Task CreateUsersDb(Dictionary<string, long> users)
{
CreatedUsers = new Dictionary<string, long>(users);
return Task.CompletedTask;
}
public Task CheckUsername(KeyValuePair<string, long> user, string path)
{
CheckedUser = (user, path);
return Task.CompletedTask;
}
public Task AddMessage(string folder, long postId, string messageText, string price, bool isPaid,
bool isArchived, DateTime createdAt, long userId) => throw new NotImplementedException();
public Task AddPost(string folder, long postId, string messageText, string price, bool isPaid,
bool isArchived, DateTime createdAt) => throw new NotImplementedException();
public Task AddStory(string folder, long postId, string messageText, string price, bool isPaid,
bool isArchived, DateTime createdAt) => throw new NotImplementedException();
public Task AddMedia(string folder, long mediaId, long postId, string link, string? directory,
string? filename, long? size, string apiType, string mediaType, bool preview, bool downloaded,
DateTime? createdAt) => throw new NotImplementedException();
public Task UpdateMedia(string folder, long mediaId, string apiType, string directory, string filename,
long size, bool downloaded, DateTime createdAt) => throw new NotImplementedException();
public Task<long> GetStoredFileSize(string folder, long mediaId, string apiType) =>
throw new NotImplementedException();
public Task<bool> CheckDownloaded(string folder, long mediaId, string apiType) =>
throw new NotImplementedException();
public Task<DateTime?> GetMostRecentPostDate(string folder) => throw new NotImplementedException();
}
internal sealed class RecordingDownloadEventHandler : IDownloadEventHandler
{
public List<string> Messages { get; } = [];
public List<(string contentType, int mediaCount, int objectCount)> ContentFound { get; } = [];
public List<string> NoContent { get; } = [];
public List<(string contentType, DownloadResult result)> DownloadCompletes { get; } = [];
public List<(string description, long maxValue, bool showSize)> ProgressCalls { get; } = [];
public Task<T> WithStatusAsync<T>(string statusMessage, Func<IStatusReporter, Task<T>> work) =>
work(new RecordingStatusReporter(statusMessage));
public Task<T> WithProgressAsync<T>(string description, long maxValue, bool showSize,
Func<IProgressReporter, Task<T>> work)
{
ProgressCalls.Add((description, maxValue, showSize));
return work(new ProgressRecorder());
}
public void OnContentFound(string contentType, int mediaCount, int objectCount) =>
ContentFound.Add((contentType, mediaCount, objectCount));
public void OnNoContentFound(string contentType) => NoContent.Add(contentType);
public void OnDownloadComplete(string contentType, DownloadResult result) =>
DownloadCompletes.Add((contentType, result));
public void OnUserStarting(string username) => Messages.Add($"Starting {username}");
public void OnUserComplete(string username, CreatorDownloadResult result) =>
Messages.Add($"Completed {username}");
public void OnPurchasedTabUserComplete(string username, int paidPostCount, int paidMessagesCount) =>
Messages.Add($"Purchased {username}");
public void OnScrapeComplete(TimeSpan elapsed) => Messages.Add("Scrape complete");
public void OnMessage(string message) => Messages.Add(message);
}
internal sealed class RecordingStatusReporter : IStatusReporter
{
private readonly List<string> _statuses;
public RecordingStatusReporter(string initialStatus)
{
_statuses = [initialStatus];
}
public IReadOnlyList<string> Statuses => _statuses;
public void ReportStatus(string message) => _statuses.Add(message);
}
internal sealed class FakeFileNameService : IFileNameService
{
public Task<string> BuildFilename(string fileFormat, Dictionary<string, string> values) =>
throw new NotImplementedException();
public Task<Dictionary<string, string>> GetFilename(object info, object media, object author,
List<string> selectedProperties, string username, Dictionary<string, long>? users = null) =>
throw new NotImplementedException();
}
internal sealed class FakeAuthService : IAuthService
{
public Auth? CurrentAuth { get; set; }
public Task<bool> LoadFromFileAsync(string filePath = "auth.json") => throw new NotImplementedException();
public Task<bool> LoadFromBrowserAsync() => throw new NotImplementedException();
public Task SaveToFileAsync(string filePath = "auth.json") => throw new NotImplementedException();
public void ValidateCookieString() => throw new NotImplementedException();
public Task<UserEntities.User?> ValidateAuthAsync() => throw new NotImplementedException();
public void Logout() => throw new NotImplementedException();
}
internal sealed class FakeLoggingService : ILoggingService
{
public LoggingLevelSwitch LevelSwitch { get; } = new();
public LoggingLevel LastLevel { get; private set; } = LoggingLevel.Error;
public int UpdateCount { get; private set; }
public void UpdateLoggingLevel(LoggingLevel newLevel)
{
UpdateCount++;
LastLevel = newLevel;
LevelSwitch.MinimumLevel = (LogEventLevel)newLevel;
}
public LoggingLevel GetCurrentLoggingLevel() => (LoggingLevel)LevelSwitch.MinimumLevel;
}