Skip to content

Commit

Permalink
Merge pull request #17 from CUMGroup/domain-navigation
Browse files Browse the repository at this point in the history
Domain navigation
  • Loading branch information
AlexMi-Ha authored Oct 29, 2023
2 parents f245d07 + 6004cba commit 90afc4a
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 20 deletions.
205 changes: 205 additions & 0 deletions PWManager.Domain/Abstractions/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
namespace PWManager.Domain.Abstractions;

public enum ResultState : byte {
Faulted,
Success
}

public readonly struct Result<A> : IEquatable<Result<A>>, IComparable<Result<A>> {

internal readonly ResultState State;
internal readonly A Value;
readonly Exception? exception;

public Result(A value) {
State = ResultState.Success;
this.Value = value;
exception = null;
}

public Result(Exception ex) {
State = ResultState.Faulted;
this.exception = ex;
Value = default;
}

public static implicit operator Result<A>(A value) => new(value);

public static implicit operator Result<A>(Exception ex) => new(ex);

public static implicit operator Exception(Result<A> result) => ExceptionOrDefault(result.exception);

public static implicit operator Result(Result<A> res) =>
res.IsFaulted ? new(ExceptionOrDefault(res.exception)) : new();


public bool IsFaulted => State == ResultState.Faulted;

public bool IsSuccess => State == ResultState.Success;

public override string ToString() =>
IsFaulted ?
exception?.ToString() ?? "Undefined Exception!" :
Value?.ToString() ?? "(null)";

public bool Equals(Result<A> b) {
if (IsFaulted && !b.IsFaulted || !IsFaulted && b.IsFaulted) return false;
if (IsFaulted && b.IsFaulted) {
if (exception == null && b.exception == null)
return true;
return exception?.Equals(b.exception) ?? false;
}
if (Value == null && b.Value == null)
return true;
return Value?.Equals(b.Value) ?? false;
}

public static bool operator ==(Result<A> a, Result<A> b) =>
Equals(a, b);

public static bool operator !=(Result<A> a, Result<A> b) =>
!(a == b);

public A IfFail(A defaultValue) =>
IsFaulted ? defaultValue : Value;

public A IfFail(Func<Exception, A> f) =>
IsFaulted ? f(ExceptionOrDefault(exception)) : Value;

public void IfSucc(Action<A> f) {
if (IsSuccess)
f(Value);
}

public R Match<R>(Func<A, R> Succ, Func<Exception, R> Fail) =>
IsFaulted ? Fail(ExceptionOrDefault(exception)) : Succ(Value);

public Result<B> Map<B>(Func<A, B> map) =>
IsFaulted ? new Result<B>(ExceptionOrDefault(exception)) : new Result<B>(map(Value));

public async Task<Result<B>> MapAsync<B>(Func<A, Task<B>> map) =>
IsFaulted ? new Result<B>(ExceptionOrDefault(exception)) : new Result<B>(await map(Value));

public int CompareTo(Result<A> b) {
if (IsFaulted && b.IsFaulted) return 0;
if (IsFaulted && !b.IsFaulted) return -1;
if (!IsFaulted && b.IsFaulted) return 1;
return Comparer<A>.Default.Compare(Value, b.Value);
}

public static bool operator <(Result<A> a, Result<A> b) =>
a.CompareTo(b) < 0;
public static bool operator <=(Result<A> a, Result<A> b) =>
a.CompareTo(b) <= 0;
public static bool operator >(Result<A> a, Result<A> b) =>
a.CompareTo(b) > 0;
public static bool operator >=(Result<A> a, Result<A> b) =>
a.CompareTo(b) >= 0;

public override bool Equals(object? obj) {
return obj != null && obj is Result<A> && Equals((Result<A>)obj);
}

public override int GetHashCode() {
return HashCode.Combine(IsSuccess, Value, exception);
}

private static Exception ExceptionOrDefault(Exception? ex) =>
ex ?? new Exception("Undefined Exception!");
}

public readonly struct Result : IEquatable<Result>, IComparable<Result> {

internal readonly ResultState State;
readonly Exception? exception;

public Result() {
State = ResultState.Success;
exception = null;
}

public Result(Exception ex) {
State = ResultState.Faulted;
this.exception = ex;
}

public static implicit operator Result(bool value) => value ? new() : new(new Exception("Undefined Exception!"));

public static implicit operator Result(Exception ex) => new(ex);

public static implicit operator Exception(Result result) => ExceptionOrDefault(result.exception);


public static implicit operator Result<bool>(Result res) =>
res.IsFaulted ? new(ExceptionOrDefault(res.exception)) : new(true);


public bool IsFaulted => State == ResultState.Faulted;

public bool IsSuccess => State == ResultState.Success;

public override string ToString() =>
IsFaulted ?
exception?.ToString() ?? "Undefined Exception!" :
"Successful";

public bool Equals(Result b) {
if (IsFaulted && !b.IsFaulted || !IsFaulted && b.IsFaulted) return false;
if (IsFaulted && b.IsFaulted) {
if (exception == null && b.exception == null)
return true;
return exception?.Equals(b.exception) ?? false;
}
return true;
}

public static bool operator ==(Result a, Result b) =>
Equals(a, b);

public static bool operator !=(Result a, Result b) =>
!(a == b);

public void IfFail(Action<Exception> f) {
if (IsFaulted)
f(ExceptionOrDefault(exception));
}
public void IfFail(Action f) {
if (IsFaulted)
f();
}

public void IfSucc(Action f) {
if (IsSuccess)
f();
}

public R Match<R>(Func<R> Succ, Func<Exception, R> Fail) =>
IsFaulted ? Fail(ExceptionOrDefault(exception)) : Succ();

public int CompareTo(Result b) {
if (IsFaulted && b.IsFaulted) return 0;
if (IsFaulted && !b.IsFaulted) return -1;
if (!IsFaulted && b.IsFaulted) return 1;
return 0;
}

public static bool operator <(Result a, Result b) =>
a.CompareTo(b) < 0;
public static bool operator <=(Result a, Result b) =>
a.CompareTo(b) <= 0;
public static bool operator >(Result a, Result b) =>
a.CompareTo(b) > 0;
public static bool operator >=(Result a, Result b) =>
a.CompareTo(b) >= 0;

private static Exception ExceptionOrDefault(Exception? ex) =>
ex ?? new Exception("Undefined Exception!");

public override bool Equals(object? obj) {
return obj != null && obj is Result && Equals((Result)obj);
}

public override int GetHashCode() {
return HashCode.Combine(IsSuccess, exception);
}
}
32 changes: 25 additions & 7 deletions PWManager.Domain/Entities/Group.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,38 @@

namespace PWManager.Domain.Entities {
public class Group : Entity {
public string UserID { get; set; }
public string UserId { get; set; }
public List<Account> Accounts { get; set; }

public Group(string userID) : this(userID, new List<Account>()) {}
public Group(string id, DateTimeOffset created, DateTimeOffset updated, string userID) : this(id, created, updated, userID, new List<Account>()) {}
public Group(string userId) : this(userId, new List<Account>()) {}
public Group(string id, DateTimeOffset created, DateTimeOffset updated, string userId) : this(id, created, updated, userId, new List<Account>()) {}

public Group(string userID, List<Account> accounts) : base() {
UserID = userID;
public Group(string userId, List<Account> accounts) : base() {
UserId = userId;
Accounts = accounts;
}

public Group(string id, DateTimeOffset created, DateTimeOffset updated, string userID, List<Account> accounts) : base(id, created, updated) {
UserID = userID;
public Group(string id, DateTimeOffset created, DateTimeOffset updated, string userId, List<Account> accounts) : base(id, created, updated) {
UserId = userId;
Accounts = accounts;
}

public void AddAccount(Account acc) {
Accounts.Add(acc);
}

public Account? GetAccount(string accId) {
return Accounts.Find(e => e.Id.Equals(accId));
}

public bool RemoveAccount(string accId) {
var acc = GetAccount(accId);
return acc is not null && RemoveAccount(acc);
}

public bool RemoveAccount(Account acc) {
return Accounts.Remove(acc);
}

}
}
12 changes: 6 additions & 6 deletions PWManager.Domain/Entities/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

namespace PWManager.Domain.Entities {
public class Settings : Entity {
public string UserID { get; set; }
public PasswordGeneratorCriteria PWGenCriteria { get; set; }
public string UserId { get; set; }
public PasswordGeneratorCriteria PwGenCriteria { get; set; }
public ClipboardTimeoutSetting ClipboardTimeout { get; set; }
public MainGroupSetting MainGroup { get; set; }

public Settings(string userId, PasswordGeneratorCriteria pwGenCriteria, ClipboardTimeoutSetting clipboardTimeout, MainGroupSetting mainGroup) : base(){
UserID = userId;
PWGenCriteria = pwGenCriteria;
UserId = userId;
PwGenCriteria = pwGenCriteria;
ClipboardTimeout = clipboardTimeout;
MainGroup = mainGroup;
}
public Settings(string id, DateTimeOffset created, DateTimeOffset updated, string userId, PasswordGeneratorCriteria pwGenCriteria, ClipboardTimeoutSetting clipboardTimeout, MainGroupSetting mainGroup) : base(id, created, updated) {
UserID = userId;
PWGenCriteria = pwGenCriteria;
UserId = userId;
PwGenCriteria = pwGenCriteria;
ClipboardTimeout = clipboardTimeout;
MainGroup = mainGroup;
}
Expand Down
96 changes: 96 additions & 0 deletions PWManager.UnitTests/Domain/Entities/GroupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using PWManager.Domain.Entities;

namespace PWManager.UnitTests.Domain.Entities;

public class GroupTests {

private Group _sut;

public GroupTests() {
_sut = new Group("test-userId");
}

#region AddAccount
[Fact]
public void Group_Should_AddNewAccount() {
var acc = new Account("Hello", "Password");
_sut.AddAccount(acc);

Assert.True(_sut.Accounts.Count == 1);
Assert.Equal(acc, _sut.Accounts[0]);
}
#endregion
#region GetAccount
[Fact]
public void Group_Should_GetValidAccount() {
AddAccountsToGroup(_sut, 5);
var acc = _sut.Accounts[3];

var returnedAccount = _sut.GetAccount(acc.Id);

Assert.Equal(acc, returnedAccount);
}

[Fact]
public void Group_ShouldNot_GetNonExistingAccount() {
AddAccountsToGroup(_sut, 5);

var returnedAccount = _sut.GetAccount("$NON_EXISTENT_ID$");

Assert.Null(returnedAccount);
}

[Fact]
public void Group_ShouldNot_GetAccountOnEmptyAccounts() {
var returnedAccount = _sut.GetAccount("$NON_EXISTING_ID$");

Assert.Null(returnedAccount);
}
#endregion
#region Remove Account
[Fact]
public void Group_Should_RemoveAccountById() {
AddAccountsToGroup(_sut, 5);
var acc = _sut.Accounts[3];

bool ret = _sut.RemoveAccount(acc.Id);

Assert.True(ret);
Assert.True(_sut.Accounts.Count == 4);
Assert.DoesNotContain(_sut.Accounts, account => account.Id.Equals(acc.Id));
}
[Fact]
public void Group_Should_RemoveAccount() {
AddAccountsToGroup(_sut, 5);
var acc = _sut.Accounts[3];

var ret = _sut.RemoveAccount(acc);

Assert.True(ret);
Assert.True(_sut.Accounts.Count == 4);
Assert.DoesNotContain(_sut.Accounts, account => account.Equals(acc));
}

[Fact]
public void Group_ShouldNot_RemoveNonExistingAccount() {
AddAccountsToGroup(_sut, 5);

var ret = _sut.RemoveAccount("$NON_EXISTING_ID$");

Assert.False(ret);
Assert.True(_sut.Accounts.Count == 5);
}
[Fact]
public void Group_ShouldNot_RemoveEmptyAccounts() {
var ret = _sut.RemoveAccount("$NON_EXISTING_ID$");

Assert.False(ret);
}
#endregion

private static void AddAccountsToGroup(Group g, int numAccounts) {
for (int i = 0; i < numAccounts; ++i) {
g.Accounts.Add(new Account($"Cool Account Name {i}", "This is a very secure password"));
}
}
}
File renamed without changes.
7 changes: 5 additions & 2 deletions PWManager.UnitTests/PWManager.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0"/>
<PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand All @@ -24,6 +24,9 @@

<ItemGroup>
<ProjectReference Include="..\PWManager.Application\PWManager.Application.csproj" />
<ProjectReference Include="..\PWManager.CLI\PWManager.CLI.csproj" />
<ProjectReference Include="..\PWManager.Data\PWManager.Data.csproj" />
<ProjectReference Include="..\PWManager.Domain\PWManager.Domain.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit 90afc4a

Please sign in to comment.