Drop the ApiExtendedFunc test hook. Pass the book's marketplace straight to CreateAsync.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Robert McRackanandCursor committed 2026-09-02 15:06:43 -04:00
1 parent 336a01db01
commit 82fb235de9
2 files changed
+15 -118

No files matched your search

+8 -13
View File
@@ -22,28 +22,23 @@ public static class UtilityExtensions
account: libraryBook.Account.ToMask()
);
/// <summary>
/// Test seam. Production leaves this null and talks to Audible through <see cref="ApiExtended.CreateAsync"/>.
/// The locale argument is the marketplace the book was scanned from, which is not always the one the account
/// is registered with.
/// </summary>
public static Func<Account, Locale?, Task<ApiExtended>>? ApiExtendedFunc { get; set; }
public static async Task<AudibleApi.Api> GetApiAsync(this LibraryBook libraryBook)
{
using var accounts = AudibleApiStorage.GetAccountsSettingsPersister();
var account = accounts.AccountsSettings.GetAccount(libraryBook.Account, libraryBook.Book.Locale)
?? throw new InvalidCredentialException($"No account found for '{libraryBook.Account}' and locale '{libraryBook.Book.Locale}'");
// Scanning an extra marketplace tags the book with that store. The license request has to use the same
// host; the account's home store answers NotFound for a title that only lives there. See issue #2020.
var storeLocale = Localization.Get(libraryBook.Book.Locale);
var apiExtended = ApiExtendedFunc is not null
? await ApiExtendedFunc(account, storeLocale)
: await ApiExtended.CreateAsync(account, allowInteractiveLogin: true, storeLocale: storeLocale);
var apiExtended = await ApiExtended.CreateAsync(account, allowInteractiveLogin: true, storeLocale: libraryBook.StoreLocale());
return apiExtended.Api;
}
/// <summary>
/// Marketplace a download or license request must speak to: the one the book was scanned from, which is not
/// always the account's home store. See issue #2020.
/// </summary>
internal static Locale StoreLocale(this LibraryBook libraryBook)
=> Localization.Get(libraryBook.Book.Locale);
public static bool SupportsWidevine(this AudibleApi.Api api)
{
//TODO: Expose Api's identity maintainer directly instead of using reflection.
@@ -1,13 +1,6 @@
using AssertionHelper;
using AudibleApi;
using AudibleApi.Authorization;
using AudibleUtilities;
using DataLayer;
using LibationFileManager;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Threading.Tasks;
namespace FileLiberator.Tests;
@@ -17,106 +10,15 @@ namespace FileLiberator.Tests;
/// correctly, then asked <c>api.audible.de</c> for their licenses and got NotFound.
/// </summary>
[TestClass]
[DoNotParallelize]
public class GetApiStoreLocaleTests
{
private string tempLibationFiles = string.Empty;
[TestInitialize]
public void Initialize()
{
tempLibationFiles = Path.Combine(Path.GetTempPath(), $"libation-getapi-tests-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempLibationFiles);
Environment.SetEnvironmentVariable(LibationFiles.LIBATION_FILES_DIR, tempLibationFiles);
Configuration.CreateMockInstance();
AudibleApiStorage.EnsureAccountsSettingsFileExists();
}
[TestCleanup]
public void Cleanup()
{
UtilityExtensions.ApiExtendedFunc = null;
Configuration.RestoreSingletonInstance();
Environment.SetEnvironmentVariable(LibationFiles.LIBATION_FILES_DIR, null);
try
{
Directory.Delete(tempLibationFiles, recursive: true);
}
catch (IOException)
{
// A leftover temp directory is not worth failing a test over.
}
}
private static void SeedAccount(string registeredLocale, params string[] extraLocales)
{
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
var account = new Account("user@example.com")
{
AccountName = "Main",
IdentityTokens = new Identity(Localization.Get(registeredLocale)),
LibraryScan = true
};
persister.AccountsSettings.Add(account);
foreach (var extra in extraLocales)
account.AddMarketplace(extra);
}
private static async Task<(Account Account, Locale? StoreLocale)> CaptureCreateAsync(LibraryBook libraryBook)
{
Account? capturedAccount = null;
Locale? capturedStore = null;
UtilityExtensions.ApiExtendedFunc = (account, storeLocale) =>
{
capturedAccount = account;
capturedStore = storeLocale;
throw new InvalidOperationException("stop before talking to Audible");
};
try
{
await libraryBook.GetApiAsync();
}
catch (InvalidOperationException ex) when (ex.Message == "stop before talking to Audible")
{
}
capturedAccount.BeNotNull();
return (capturedAccount, capturedStore);
}
[TestMethod]
public void A_book_from_an_extra_marketplace_is_licensed_there_not_at_the_home_store()
=> MockLibraryBook.CreateBook(localeName: "uk", title: "Kill Box")
.StoreLocale().Name.Should().Be("uk");
[TestMethod]
public async Task A_book_from_an_extra_marketplace_is_licensed_there_not_at_the_home_store()
{
SeedAccount("germany", "uk");
var libraryBook = MockLibraryBook.CreateBook(
account: "user@example.com",
localeName: "uk",
title: "Kill Box");
var (account, storeLocale) = await CaptureCreateAsync(libraryBook);
account.Locale!.Name.Should().Be("germany");
storeLocale.BeNotNull();
storeLocale.Name.Should().Be("uk");
}
[TestMethod]
public async Task A_book_from_the_registered_marketplace_is_still_licensed_there()
{
SeedAccount("germany", "uk");
var libraryBook = MockLibraryBook.CreateBook(
account: "user@example.com",
localeName: "germany",
title: "Home Store Title");
var (account, storeLocale) = await CaptureCreateAsync(libraryBook);
account.Locale!.Name.Should().Be("germany");
storeLocale.BeNotNull();
storeLocale.Name.Should().Be("germany");
}
public void A_book_from_the_registered_marketplace_is_still_licensed_there()
=> MockLibraryBook.CreateBook(localeName: "germany", title: "Home Store Title")
.StoreLocale().Name.Should().Be("germany");
}