Libation 4.0 prep: in process of migrating to new settings files
This commit is contained in:
parent
8391e43b03
commit
643ae09b2b
162
InternalUtilities/Accounts.cs
Normal file
162
InternalUtilities/Accounts.cs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AudibleApi;
|
||||||
|
using AudibleApi.Authorization;
|
||||||
|
using Dinah.Core;
|
||||||
|
using Dinah.Core.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace InternalUtilities
|
||||||
|
{
|
||||||
|
public class AccountsPersister : JsonFilePersister<Accounts>
|
||||||
|
{
|
||||||
|
/// <summary>Alias for Target </summary>
|
||||||
|
public Accounts Accounts => Target;
|
||||||
|
|
||||||
|
/// <summary>uses path. create file if doesn't yet exist</summary>
|
||||||
|
public AccountsPersister(Accounts target, string path, string jsonPath = null)
|
||||||
|
: base(target, path, jsonPath) { }
|
||||||
|
|
||||||
|
/// <summary>load from existing file</summary>
|
||||||
|
public AccountsPersister(string path, string jsonPath = null)
|
||||||
|
: base(path, jsonPath) { }
|
||||||
|
|
||||||
|
protected override JsonSerializerSettings GetSerializerSettings()
|
||||||
|
=> Identity.GetJsonSerializerSettings();
|
||||||
|
}
|
||||||
|
public class Accounts : Updatable
|
||||||
|
{
|
||||||
|
public event EventHandler Updated;
|
||||||
|
private void update(object sender = null, EventArgs e = null)
|
||||||
|
=> Updated?.Invoke(this, new EventArgs());
|
||||||
|
|
||||||
|
public Accounts() { }
|
||||||
|
|
||||||
|
// for some reason this will make the json instantiator use _accountsSettings_json.set()
|
||||||
|
[JsonConstructor]
|
||||||
|
protected Accounts(List<Account> accounts) { }
|
||||||
|
|
||||||
|
#region AccountsSettings
|
||||||
|
private List<Account> _accountsSettings_backing = new List<Account>();
|
||||||
|
[JsonProperty(PropertyName = "AccountsSettings")]
|
||||||
|
private List<Account> _accountsSettings_json
|
||||||
|
{
|
||||||
|
get => _accountsSettings_backing;
|
||||||
|
// 'set' is only used by json deser
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_accountsSettings_backing = value;
|
||||||
|
|
||||||
|
if (_accountsSettings_backing is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var acct in _accountsSettings_backing)
|
||||||
|
acct.Updated += update;
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<Account> AccountsSettings => _accountsSettings_json.AsReadOnly();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static Accounts FromJson(string json)
|
||||||
|
=> JsonConvert.DeserializeObject<Accounts>(json, Identity.GetJsonSerializerSettings());
|
||||||
|
|
||||||
|
public string ToJson(Formatting formatting = Formatting.Indented)
|
||||||
|
=> JsonConvert.SerializeObject(this, formatting, Identity.GetJsonSerializerSettings());
|
||||||
|
|
||||||
|
public void UNITTEST_Seed(Account account)
|
||||||
|
{
|
||||||
|
_accountsSettings_backing.Add(account);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace UNITTEST_Seed
|
||||||
|
|
||||||
|
// when creating Account object (get, update, insert), subscribe to it's update. including all new ones on initial load
|
||||||
|
// removing: unsubscribe
|
||||||
|
|
||||||
|
// IEnumerable<Account> GetAllAccounts
|
||||||
|
|
||||||
|
// void UpsertAccount (id, locale)
|
||||||
|
// if not exists
|
||||||
|
// create account w/null identity
|
||||||
|
// save in file
|
||||||
|
// return Account?
|
||||||
|
// return bool/enum of whether is newly created?
|
||||||
|
|
||||||
|
// how to persist edits to [Account] obj?
|
||||||
|
// account name, decryptkey, id tokens, ...
|
||||||
|
// persistence happens in [Accounts], not [Account]. an [Account] accidentally created directly shouldn't mess up expected workflow ???
|
||||||
|
}
|
||||||
|
public class Account : Updatable
|
||||||
|
{
|
||||||
|
public event EventHandler Updated;
|
||||||
|
private void update(object sender = null, EventArgs e = null)
|
||||||
|
=> Updated?.Invoke(this, new EventArgs());
|
||||||
|
|
||||||
|
// canonical. immutable. email or phone number
|
||||||
|
public string AccountId { get; }
|
||||||
|
|
||||||
|
// user-friendly, non-canonical name. mutable
|
||||||
|
private string _accountName;
|
||||||
|
public string AccountName
|
||||||
|
{
|
||||||
|
get => _accountName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
return;
|
||||||
|
var v = value.Trim();
|
||||||
|
if (v == _accountName)
|
||||||
|
return;
|
||||||
|
_accountName = v;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _decryptKey = "";
|
||||||
|
public string DecryptKey
|
||||||
|
{
|
||||||
|
get => _decryptKey;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var v = (value ?? "").Trim();
|
||||||
|
if (v == _decryptKey)
|
||||||
|
return;
|
||||||
|
_decryptKey = v;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Identity _identity;
|
||||||
|
public Identity IdentityTokens
|
||||||
|
{
|
||||||
|
get => _identity;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_identity is null && value is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_identity != null)
|
||||||
|
_identity.Updated -= update;
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
value.Updated += update;
|
||||||
|
|
||||||
|
_identity = value;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Locale Locale => IdentityTokens?.Locale;
|
||||||
|
|
||||||
|
public Account(string accountId)
|
||||||
|
{
|
||||||
|
ArgumentValidator.EnsureNotNullOrWhiteSpace(accountId, nameof(accountId));
|
||||||
|
AccountId = accountId.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,11 +12,11 @@ namespace InternalUtilities
|
|||||||
{
|
{
|
||||||
public static class AudibleApiActions
|
public static class AudibleApiActions
|
||||||
{
|
{
|
||||||
public static async Task<Api> GetApiAsyncLegacy30(ILoginCallback loginCallback = null)
|
public static async Task<Api> GetApiAsyncLegacy30Async()
|
||||||
{
|
{
|
||||||
Localization.SetLocale(Configuration.Instance.LocaleCountryCode);
|
Localization.SetLocale(Configuration.Instance.LocaleCountryCode);
|
||||||
|
|
||||||
return await EzApiCreator.GetApiAsync(AudibleApiStorage.AccountsSettingsFileLegacy30, null, loginCallback);
|
return await EzApiCreator.GetApiAsync(AudibleApiStorage.AccountsSettingsFileLegacy30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>USE THIS from within Libation. It wraps the call with correct JSONPath</summary>
|
/// <summary>USE THIS from within Libation. It wraps the call with correct JSONPath</summary>
|
||||||
|
|||||||
@ -14,6 +14,15 @@ namespace InternalUtilities
|
|||||||
|
|
||||||
public static string AccountsSettingsFile => Path.Combine(Configuration.Instance.LibationFiles, "AccountsSettings.json");
|
public static string AccountsSettingsFile => Path.Combine(Configuration.Instance.LibationFiles, "AccountsSettings.json");
|
||||||
|
|
||||||
|
public static void EnsureAccountsSettingsFileExists()
|
||||||
|
{
|
||||||
|
if (File.Exists(AccountsSettingsFile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// saves. BEWARE: this will overwrite an existing file
|
||||||
|
_ = new AccountsPersister(new Accounts(), AccountsSettingsFile);
|
||||||
|
}
|
||||||
|
|
||||||
// TEMP
|
// TEMP
|
||||||
public static string GetJsonPath() => null;
|
public static string GetJsonPath() => null;
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsDesktopUtilities", "
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationLauncher", "LibationLauncher\LibationLauncher.csproj", "{F3B04A3A-20C8-4582-A54A-715AF6A5D859}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibationLauncher", "LibationLauncher\LibationLauncher.csproj", "{F3B04A3A-20C8-4582-A54A-715AF6A5D859}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0 Libation Tests", "0 Libation Tests", "{67E66E82-5532-4440-AFB3-9FB1DF9DEF53}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InternalUtilities.Tests", "_Tests\InternalUtilities.Tests\InternalUtilities.Tests.csproj", "{8447C956-B03E-4F59-9DD4-877793B849D9}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -200,6 +204,10 @@ Global
|
|||||||
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Release|Any CPU.Build.0 = Release|Any CPU
|
{F3B04A3A-20C8-4582-A54A-715AF6A5D859}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{8447C956-B03E-4F59-9DD4-877793B849D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8447C956-B03E-4F59-9DD4-877793B849D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8447C956-B03E-4F59-9DD4-877793B849D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8447C956-B03E-4F59-9DD4-877793B849D9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -233,6 +241,7 @@ Global
|
|||||||
{059CE32C-9AD6-45E9-A166-790DFFB0B730} = {43E3ACB3-E0BC-4370-8DBB-E3720C8C8FD1}
|
{059CE32C-9AD6-45E9-A166-790DFFB0B730} = {43E3ACB3-E0BC-4370-8DBB-E3720C8C8FD1}
|
||||||
{E7EFD64D-6630-4426-B09C-B6862A92E3FD} = {F0CBB7A7-D3FB-41FF-8F47-CF3F6A592249}
|
{E7EFD64D-6630-4426-B09C-B6862A92E3FD} = {F0CBB7A7-D3FB-41FF-8F47-CF3F6A592249}
|
||||||
{F3B04A3A-20C8-4582-A54A-715AF6A5D859} = {8679CAC8-9164-4007-BDD2-F004810EDA14}
|
{F3B04A3A-20C8-4582-A54A-715AF6A5D859} = {8679CAC8-9164-4007-BDD2-F004810EDA14}
|
||||||
|
{8447C956-B03E-4F59-9DD4-877793B849D9} = {67E66E82-5532-4440-AFB3-9FB1DF9DEF53}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {615E00ED-BAEF-4E8E-A92A-9B82D87942A9}
|
SolutionGuid = {615E00ED-BAEF-4E8E-A92A-9B82D87942A9}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
<Version>3.1.12.95</Version>
|
<Version>3.1.12.120</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -24,7 +24,7 @@ namespace LibationLauncher
|
|||||||
|
|
||||||
createSettings();
|
createSettings();
|
||||||
|
|
||||||
ensureIdentityFile();
|
AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
||||||
migrateIdentityFile();
|
migrateIdentityFile();
|
||||||
updateSettingsFile();
|
updateSettingsFile();
|
||||||
|
|
||||||
@ -82,18 +82,6 @@ namespace LibationLauncher
|
|||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureIdentityFile()
|
|
||||||
{
|
|
||||||
if (File.Exists(AudibleApiStorage.AccountsSettingsFile))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var jObj = new JObject {
|
|
||||||
{ "AccountsSettings", new JArray() }
|
|
||||||
};
|
|
||||||
var contents = jObj.ToString(Formatting.Indented);
|
|
||||||
File.WriteAllText(AudibleApiStorage.AccountsSettingsFile, contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void migrateIdentityFile()
|
private static void migrateIdentityFile()
|
||||||
{
|
{
|
||||||
if (!File.Exists(AudibleApiStorage.AccountsSettingsFileLegacy30))
|
if (!File.Exists(AudibleApiStorage.AccountsSettingsFileLegacy30))
|
||||||
@ -102,8 +90,9 @@ namespace LibationLauncher
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// for all in here: read directly from json file => JObject. A lot of this is legacy; don't rely on applicable POCOs
|
// in here: read directly from json file => JObject. A lot of this is legacy; don't rely on applicable POCOs
|
||||||
//
|
//
|
||||||
|
|
||||||
var legacyContents = File.ReadAllText(AudibleApiStorage.AccountsSettingsFileLegacy30);
|
var legacyContents = File.ReadAllText(AudibleApiStorage.AccountsSettingsFileLegacy30);
|
||||||
var legacyJObj = JObject.Parse(legacyContents);
|
var legacyJObj = JObject.Parse(legacyContents);
|
||||||
|
|
||||||
@ -127,6 +116,11 @@ namespace LibationLauncher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create new account stub in new file
|
||||||
|
var api = AudibleApiActions.GetApiAsyncLegacy30Async().GetAwaiter().GetResult();
|
||||||
|
var email = api.GetEmailAsync().GetAwaiter().GetResult();
|
||||||
|
var locale = api.GetLocaleAsync(AudibleApi.CustomerOptions.All).GetAwaiter().GetResult();
|
||||||
|
|
||||||
// more to do?
|
// more to do?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
451
_Tests/InternalUtilities.Tests/AccountTests.cs
Normal file
451
_Tests/InternalUtilities.Tests/AccountTests.cs
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AudibleApi;
|
||||||
|
using AudibleApi.Authorization;
|
||||||
|
using Dinah.Core;
|
||||||
|
using FluentAssertions;
|
||||||
|
using InternalUtilities;
|
||||||
|
using Microsoft.VisualStudio.TestPlatform.Common.Filtering;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using Moq.Protected;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using TestAudibleApiCommon;
|
||||||
|
using TestCommon;
|
||||||
|
using static AuthorizationShared.Shared;
|
||||||
|
using static AuthorizationShared.Shared.AccessTokenTemporality;
|
||||||
|
using static TestAudibleApiCommon.ComputedTestValues;
|
||||||
|
|
||||||
|
namespace AccountsTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class FromJson
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void _0_accounts()
|
||||||
|
{
|
||||||
|
var json = @"
|
||||||
|
{
|
||||||
|
""AccountsSettings"": []
|
||||||
|
}
|
||||||
|
".Trim();
|
||||||
|
var accounts = Accounts.FromJson(json);
|
||||||
|
accounts.AccountsSettings.Count.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void _1_account_new()
|
||||||
|
{
|
||||||
|
var json = @"
|
||||||
|
{
|
||||||
|
""AccountsSettings"": [
|
||||||
|
{
|
||||||
|
""AccountId"": ""cng"",
|
||||||
|
""AccountName"": ""my main login"",
|
||||||
|
""DecryptKey"": ""asdfasdf"",
|
||||||
|
""IdentityTokens"": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
".Trim();
|
||||||
|
var accounts = Accounts.FromJson(json);
|
||||||
|
accounts.AccountsSettings.Count.Should().Be(1);
|
||||||
|
accounts.AccountsSettings[0].AccountId.Should().Be("cng");
|
||||||
|
accounts.AccountsSettings[0].IdentityTokens.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void _1_account_populated()
|
||||||
|
{
|
||||||
|
var id = GetIdentityJson(Future);
|
||||||
|
|
||||||
|
var json = $@"
|
||||||
|
{{
|
||||||
|
""AccountsSettings"": [
|
||||||
|
{{
|
||||||
|
""AccountId"": ""cng"",
|
||||||
|
""AccountName"": ""my main login"",
|
||||||
|
""DecryptKey"": ""asdfasdf"",
|
||||||
|
""IdentityTokens"": {id}
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
".Trim();
|
||||||
|
var accounts = Accounts.FromJson(json);
|
||||||
|
accounts.AccountsSettings.Count.Should().Be(1);
|
||||||
|
accounts.AccountsSettings[0].AccountId.Should().Be("cng");
|
||||||
|
accounts.AccountsSettings[0].IdentityTokens.Should().NotBeNull();
|
||||||
|
accounts.AccountsSettings[0].IdentityTokens.ExistingAccessToken.TokenValue.Should().Be(AccessTokenValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ToJson
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void serialize()
|
||||||
|
{
|
||||||
|
var id = JsonConvert.SerializeObject(Identity.Empty, Identity.GetJsonSerializerSettings());
|
||||||
|
var jsonIn = $@"
|
||||||
|
{{
|
||||||
|
""AccountsSettings"": [
|
||||||
|
{{
|
||||||
|
""AccountId"": ""cng"",
|
||||||
|
""AccountName"": ""my main login"",
|
||||||
|
""DecryptKey"": ""asdfasdf"",
|
||||||
|
""IdentityTokens"": {id}
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
".Trim();
|
||||||
|
var accounts = Accounts.FromJson(jsonIn);
|
||||||
|
|
||||||
|
var jsonOut = accounts.ToJson();
|
||||||
|
jsonOut.Should().Be(@"
|
||||||
|
{
|
||||||
|
""AccountsSettings"": [
|
||||||
|
{
|
||||||
|
""AccountId"": ""cng"",
|
||||||
|
""AccountName"": ""my main login"",
|
||||||
|
""DecryptKey"": ""asdfasdf"",
|
||||||
|
""IdentityTokens"": {
|
||||||
|
""LocaleName"": ""[empty]"",
|
||||||
|
""ExistingAccessToken"": {
|
||||||
|
""TokenValue"": ""Atna|"",
|
||||||
|
""Expires"": ""9999-12-31T23:59:59.9999999""
|
||||||
|
},
|
||||||
|
""PrivateKey"": null,
|
||||||
|
""AdpToken"": null,
|
||||||
|
""RefreshToken"": null,
|
||||||
|
""Cookies"": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
".Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AccountsPersisterTestBase
|
||||||
|
{
|
||||||
|
protected string TestFile;
|
||||||
|
|
||||||
|
protected void WriteToTestFile(string contents)
|
||||||
|
=> File.WriteAllText(TestFile, contents);
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void TestInit()
|
||||||
|
=> TestFile = Guid.NewGuid() + ".txt";
|
||||||
|
|
||||||
|
[TestCleanup]
|
||||||
|
public void TestCleanup()
|
||||||
|
{
|
||||||
|
if (File.Exists(TestFile))
|
||||||
|
File.Delete(TestFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ctor : AccountsPersisterTestBase
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void create_file()
|
||||||
|
{
|
||||||
|
File.Exists(TestFile).Should().BeFalse();
|
||||||
|
var accounts = new Accounts();
|
||||||
|
_ = new AccountsPersister(accounts, TestFile);
|
||||||
|
File.Exists(TestFile).Should().BeTrue();
|
||||||
|
File.ReadAllText(TestFile).Should().Be(@"
|
||||||
|
{
|
||||||
|
""AccountsSettings"": []
|
||||||
|
}
|
||||||
|
".Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void overwrite_existing_file()
|
||||||
|
{
|
||||||
|
File.Exists(TestFile).Should().BeFalse();
|
||||||
|
WriteToTestFile("foo");
|
||||||
|
File.Exists(TestFile).Should().BeTrue();
|
||||||
|
|
||||||
|
var accounts = new Accounts();
|
||||||
|
_ = new AccountsPersister(accounts, TestFile);
|
||||||
|
File.Exists(TestFile).Should().BeTrue();
|
||||||
|
File.ReadAllText(TestFile).Should().Be(@"
|
||||||
|
{
|
||||||
|
""AccountsSettings"": []
|
||||||
|
}
|
||||||
|
".Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void save_multiple_children()
|
||||||
|
{
|
||||||
|
var accounts = new Accounts();
|
||||||
|
accounts.UNITTEST_Seed(new Account("a0") { AccountName = "n0" });
|
||||||
|
accounts.UNITTEST_Seed(new Account("a1") { AccountName = "n1" });
|
||||||
|
|
||||||
|
// dispose to cease auto-updates
|
||||||
|
using (var p = new AccountsPersister(accounts, TestFile)) { }
|
||||||
|
|
||||||
|
var persister = new AccountsPersister(TestFile);
|
||||||
|
persister.Accounts.AccountsSettings.Count.Should().Be(2);
|
||||||
|
persister.Accounts.AccountsSettings[1].AccountName.Should().Be("n1");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void save_with_identity()
|
||||||
|
{
|
||||||
|
var usLocale = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var id = new Identity(usLocale);
|
||||||
|
var idJson = JsonConvert.SerializeObject(id, Identity.GetJsonSerializerSettings());
|
||||||
|
|
||||||
|
var accounts = new Accounts();
|
||||||
|
accounts.UNITTEST_Seed(new Account("a0") { AccountName = "n0", IdentityTokens = id });
|
||||||
|
|
||||||
|
// dispose to cease auto-updates
|
||||||
|
using (var p = new AccountsPersister(accounts, TestFile)) { }
|
||||||
|
|
||||||
|
var persister = new AccountsPersister(TestFile);
|
||||||
|
var acct = persister.Accounts.AccountsSettings[0];
|
||||||
|
acct.AccountName.Should().Be("n0");
|
||||||
|
acct.Locale.CountryCode.Should().Be("us");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class save : AccountsPersisterTestBase
|
||||||
|
{
|
||||||
|
// add/save account after file creation
|
||||||
|
[TestMethod]
|
||||||
|
public void save_1_account()
|
||||||
|
{
|
||||||
|
// create initial file
|
||||||
|
using (var p = new AccountsPersister(new Accounts(), TestFile)) { }
|
||||||
|
|
||||||
|
// load file. create account
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var localeIn = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var idIn = new Identity(localeIn);
|
||||||
|
var acctIn = new Account("a0") { AccountName = "n0", IdentityTokens = idIn };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acctIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure account still exists
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(1);
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
acct0.AccountName.Should().Be("n0");
|
||||||
|
acct0.Locale.CountryCode.Should().Be("us");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add/save mult accounts after file creation
|
||||||
|
// separately create 2 accounts. ensure both still exist in the end
|
||||||
|
[TestMethod]
|
||||||
|
public void save_2_accounts()
|
||||||
|
{
|
||||||
|
// create initial file
|
||||||
|
using (var p = new AccountsPersister(new Accounts(), TestFile)) { }
|
||||||
|
|
||||||
|
// load file. create account 0
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var localeIn = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var idIn = new Identity(localeIn);
|
||||||
|
var acctIn = new Account("a0") { AccountName = "n0", IdentityTokens = idIn };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acctIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure account still exists
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(1);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
acct0.AccountName.Should().Be("n0");
|
||||||
|
acct0.Locale.CountryCode.Should().Be("us");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load file. create account 1
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var localeIn = Localization.Locales.Single(l => l.Name == "uk");
|
||||||
|
var idIn = new Identity(localeIn);
|
||||||
|
var acctIn = new Account("a1") { AccountName = "n1", IdentityTokens = idIn };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acctIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure both accounts still exist
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(2);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
acct0.AccountName.Should().Be("n0");
|
||||||
|
acct0.Locale.CountryCode.Should().Be("us");
|
||||||
|
|
||||||
|
var acct1 = p.Accounts.AccountsSettings[1];
|
||||||
|
acct1.AccountName.Should().Be("n1");
|
||||||
|
acct1.Locale.CountryCode.Should().Be("uk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update Account property. must be non-destructive to all other data
|
||||||
|
[TestMethod]
|
||||||
|
public void update_Account_field()
|
||||||
|
{
|
||||||
|
// create initial file
|
||||||
|
using (var p = new AccountsPersister(new Accounts(), TestFile)) { }
|
||||||
|
|
||||||
|
// load file. create 2 accounts
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var locale1 = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var id1 = new Identity(locale1);
|
||||||
|
var acct1 = new Account("a0") { AccountName = "n0", IdentityTokens = id1 };
|
||||||
|
p.Accounts.UNITTEST_Seed(acct1);
|
||||||
|
|
||||||
|
var locale2 = Localization.Locales.Single(l => l.Name == "uk");
|
||||||
|
var id2 = new Identity(locale2);
|
||||||
|
var acct2 = new Account("a1") { AccountName = "n1", IdentityTokens = id2 };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acct2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update AccountName on existing file
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
acct0.AccountName = "new";
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure both accounts still exist
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(2);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
// new
|
||||||
|
acct0.AccountName.Should().Be("new");
|
||||||
|
|
||||||
|
// still here
|
||||||
|
acct0.Locale.CountryCode.Should().Be("us");
|
||||||
|
var acct1 = p.Accounts.AccountsSettings[1];
|
||||||
|
acct1.AccountName.Should().Be("n1");
|
||||||
|
acct1.Locale.CountryCode.Should().Be("uk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update identity. must be non-destructive to all other data
|
||||||
|
[TestMethod]
|
||||||
|
public void replace_identity()
|
||||||
|
{
|
||||||
|
// create initial file
|
||||||
|
using (var p = new AccountsPersister(new Accounts(), TestFile)) { }
|
||||||
|
|
||||||
|
// load file. create 2 accounts
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var locale1 = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var id1 = new Identity(locale1);
|
||||||
|
var acct1 = new Account("a0") { AccountName = "n0", IdentityTokens = id1 };
|
||||||
|
p.Accounts.UNITTEST_Seed(acct1);
|
||||||
|
|
||||||
|
var locale2 = Localization.Locales.Single(l => l.Name == "uk");
|
||||||
|
var id2 = new Identity(locale2);
|
||||||
|
var acct2 = new Account("a1") { AccountName = "n1", IdentityTokens = id2 };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acct2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update identity on existing file
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var locale = Localization.Locales.Single(l => l.Name == "uk");
|
||||||
|
var id = new Identity(locale);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
acct0.IdentityTokens = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure both accounts still exist
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(2);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
// new
|
||||||
|
acct0.Locale.CountryCode.Should().Be("uk");
|
||||||
|
|
||||||
|
// still here
|
||||||
|
acct0.AccountName.Should().Be("n0");
|
||||||
|
var acct1 = p.Accounts.AccountsSettings[1];
|
||||||
|
acct1.AccountName.Should().Be("n1");
|
||||||
|
acct1.Locale.CountryCode.Should().Be("uk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// multi-level subscribe => update
|
||||||
|
// edit field of existing identity. must be non-destructive to all other data
|
||||||
|
[TestMethod]
|
||||||
|
public void update_identity_field()
|
||||||
|
{
|
||||||
|
// create initial file
|
||||||
|
using (var p = new AccountsPersister(new Accounts(), TestFile)) { }
|
||||||
|
|
||||||
|
// load file. create 2 accounts
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
var locale1 = Localization.Locales.Single(l => l.Name == "us");
|
||||||
|
var id1 = new Identity(locale1);
|
||||||
|
var acct1 = new Account("a0") { AccountName = "n0", IdentityTokens = id1 };
|
||||||
|
p.Accounts.UNITTEST_Seed(acct1);
|
||||||
|
|
||||||
|
var locale2 = Localization.Locales.Single(l => l.Name == "uk");
|
||||||
|
var id2 = new Identity(locale2);
|
||||||
|
var acct2 = new Account("a1") { AccountName = "n1", IdentityTokens = id2 };
|
||||||
|
|
||||||
|
p.Accounts.UNITTEST_Seed(acct2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update identity on existing file
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings[0]
|
||||||
|
.IdentityTokens
|
||||||
|
.Update(new AccessToken("Atna|_NEW_", DateTime.Now.AddDays(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-load file. ensure both accounts still exist
|
||||||
|
using (var p = new AccountsPersister(TestFile))
|
||||||
|
{
|
||||||
|
p.Accounts.AccountsSettings.Count.Should().Be(2);
|
||||||
|
|
||||||
|
var acct0 = p.Accounts.AccountsSettings[0];
|
||||||
|
// new
|
||||||
|
acct0.IdentityTokens.ExistingAccessToken.TokenValue.Should().Be("Atna|_NEW_");
|
||||||
|
|
||||||
|
// still here
|
||||||
|
acct0.AccountName.Should().Be("n0");
|
||||||
|
acct0.Locale.CountryCode.Should().Be("us");
|
||||||
|
var acct1 = p.Accounts.AccountsSettings[1];
|
||||||
|
acct1.AccountName.Should().Be("n1");
|
||||||
|
acct1.Locale.CountryCode.Should().Be("uk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\audible api\AudibleApi\_Tests\AudibleApi.Tests\AudibleApi.Tests.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\Dinah.Core\_Tests\TestCommon\TestCommon.csproj" />
|
||||||
|
<ProjectReference Include="..\..\InternalUtilities\InternalUtilities.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Loading…
x
Reference in New Issue
Block a user