Browse Source

Validation improved for app guards.

pull/303/head
Sebastian 8 years ago
parent
commit
6ba7652696
  1. 4
      NuGet.Config
  2. BIN
      libs/sharppwned.net/1.0.2-fix/sharppwned.net.1.0.2-fix.nupkg
  3. 1
      libs/sharppwned.net/1.0.2-fix/sharppwned.net.1.0.2-fix.nupkg.sha512
  4. 17
      libs/sharppwned.net/1.0.2-fix/sharppwned.net.nuspec
  5. 34
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardApp.cs
  6. 8
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppClients.cs
  7. 8
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs
  8. 14
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppLanguages.cs
  9. 2
      src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
  10. 4
      src/Squidex.Infrastructure/Validate.cs
  11. 27
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppClientsTests.cs
  12. 26
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs
  13. 22
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppLanguagesTests.cs
  14. 21
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppTests.cs
  15. 54
      tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/ValidationAssert.cs

4
NuGet.Config

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<packageSources> <packageSources>
<add key="localfeed" value="libs" /> <add key="myget.org" value="https://dotnet.myget.org/F/orleans-ci/api/v3/index.json" protocolVersion="3" />
<add key="myget.org" value="https://dotnet.myget.org/F/orleans-ci/api/v3/index.json" protocolVersion="3" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="localfeed" value="libs" />
</packageSources> </packageSources>
</configuration> </configuration>

BIN
libs/sharppwned.net/1.0.2-fix/sharppwned.net.1.0.2-fix.nupkg

Binary file not shown.

1
libs/sharppwned.net/1.0.2-fix/sharppwned.net.1.0.2-fix.nupkg.sha512

@ -0,0 +1 @@
44NJepeJdsgel9jiDTaWOXhCYM08/kGmW81dw8J31py1+4MJoOloWSUtk99fDbzM7X3/pdSNksJWb22liaDsVQ==

17
libs/sharppwned.net/1.0.2-fix/sharppwned.net.nuspec

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>SharpPwned.NET</id>
<version>1.0.2-fix</version>
<authors>SharpPwned.NET</authors>
<owners>SharpPwned.NET</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package Description</description>
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
<dependency id="Newtonsoft.Json" version="10.0.3" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
</package>

34
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardApp.cs

@ -22,14 +22,13 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
return Validate.It(() => "Cannot create app.", async error => return Validate.It(() => "Cannot create app.", async error =>
{ {
if (await appProvider.GetAppAsync(command.Name) != null) if (!command.Name.IsSlug())
{ {
error(new ValidationError($"An app with name '{command.Name}' already exists", nameof(command.Name))); error(new ValidationError("Name must be a valid slug (lowercase characters, numbers and dashes).", nameof(command.Name)));
} }
else if (await appProvider.GetAppAsync(command.Name) != null)
if (!command.Name.IsSlug())
{ {
error(new ValidationError("Name must be a valid slug.", nameof(command.Name))); error(new ValidationError($"An app with name '{command.Name}' already exists.", nameof(command.Name)));
} }
}); });
} }
@ -42,21 +41,24 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (string.IsNullOrWhiteSpace(command.PlanId)) if (string.IsNullOrWhiteSpace(command.PlanId))
{ {
error(new ValidationError("PlanId is not defined.", nameof(command.PlanId))); error(new ValidationError("Plan id is required.", nameof(command.PlanId)));
} }
else if (appPlans.GetPlan(command.PlanId) == null) else
{ {
error(new ValidationError("Plan id not available.", nameof(command.PlanId))); if (appPlans.GetPlan(command.PlanId) == null)
} {
error(new ValidationError($"Plan with id '{command.PlanId}' is not available.", nameof(command.PlanId)));
}
if (!string.IsNullOrWhiteSpace(command.PlanId) && plan != null && !plan.Owner.Equals(command.Actor)) if (!string.IsNullOrWhiteSpace(command.PlanId) && plan != null && !plan.Owner.Equals(command.Actor))
{ {
error(new ValidationError("Plan can only be changed from current user.")); error(new ValidationError("Plan can only changed from the user who configured the plan initially."));
} }
if (string.Equals(command.PlanId, plan?.PlanId, StringComparison.OrdinalIgnoreCase)) if (string.Equals(command.PlanId, plan?.PlanId, StringComparison.OrdinalIgnoreCase))
{ {
error(new ValidationError("App has already this plan.")); error(new ValidationError("App has already this plan."));
}
} }
}); });
} }

8
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppClients.cs

@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
} }
else if (clients.ContainsKey(command.Id)) else if (clients.ContainsKey(command.Id))
{ {
error(new ValidationError("Client id already added.", nameof(command.Id))); error(new ValidationError("Client id already exists."));
} }
}); });
} }
@ -60,7 +60,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
if (string.IsNullOrWhiteSpace(command.Name) && command.Permission == null) if (string.IsNullOrWhiteSpace(command.Name) && command.Permission == null)
{ {
error(new ValidationError("Either name or permission is required.", nameof(command.Name), nameof(command.Permission))); error(new ValidationError("Either name or permission must be defined.", nameof(command.Name), nameof(command.Permission)));
} }
if (command.Permission.HasValue && !command.Permission.Value.IsEnumValue()) if (command.Permission.HasValue && !command.Permission.Value.IsEnumValue())
@ -72,12 +72,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (!string.IsNullOrWhiteSpace(command.Name) && string.Equals(client.Name, command.Name)) if (!string.IsNullOrWhiteSpace(command.Name) && string.Equals(client.Name, command.Name))
{ {
error(new ValidationError("Client already has this name.", nameof(command.Permission))); error(new ValidationError("Client has already this name.", nameof(command.Name)));
} }
if (command.Permission == client.Permission) if (command.Permission == client.Permission)
{ {
error(new ValidationError("Client already has this permission.", nameof(command.Permission))); error(new ValidationError("Client has already this permission.", nameof(command.Permission)));
} }
} }
}); });

8
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs

@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
if (string.IsNullOrWhiteSpace(command.ContributorId)) if (string.IsNullOrWhiteSpace(command.ContributorId))
{ {
error(new ValidationError("Contributor id not assigned.", nameof(command.ContributorId))); error(new ValidationError("Contributor id is required.", nameof(command.ContributorId)));
} }
else else
{ {
@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
if (user == null) if (user == null)
{ {
error(new ValidationError("Cannot find contributor id.", nameof(command.ContributorId))); throw new DomainObjectNotFoundException(command.ContributorId, "Contributors", typeof(IAppEntity));
} }
else else
{ {
@ -73,14 +73,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (string.IsNullOrWhiteSpace(command.ContributorId)) if (string.IsNullOrWhiteSpace(command.ContributorId))
{ {
error(new ValidationError("Contributor id not assigned.", nameof(command.ContributorId))); error(new ValidationError("Contributor id is required.", nameof(command.ContributorId)));
} }
var ownerIds = contributors.Where(x => x.Value == AppContributorPermission.Owner).Select(x => x.Key).ToList(); var ownerIds = contributors.Where(x => x.Value == AppContributorPermission.Owner).Select(x => x.Key).ToList();
if (ownerIds.Count == 1 && ownerIds.Contains(command.ContributorId)) if (ownerIds.Count == 1 && ownerIds.Contains(command.ContributorId))
{ {
error(new ValidationError("Cannot remove the only owner.", nameof(command.ContributorId))); error(new ValidationError("Cannot remove the only owner."));
} }
}); });

14
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppLanguages.cs

@ -21,11 +21,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (command.Language == null) if (command.Language == null)
{ {
error(new ValidationError("Language cannot be null.", nameof(command.Language))); error(new ValidationError("Language code is required.", nameof(command.Language)));
} }
else if (languages.Contains(command.Language)) else if (languages.Contains(command.Language))
{ {
error(new ValidationError("Language already added.", nameof(command.Language))); error(new ValidationError("Language has already been added."));
} }
}); });
} }
@ -40,12 +40,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (command.Language == null) if (command.Language == null)
{ {
error(new ValidationError("Language cannot be null.", nameof(command.Language))); error(new ValidationError("Language code is required.", nameof(command.Language)));
} }
if (languages.Master == languageConfig) if (languages.Master == languageConfig)
{ {
error(new ValidationError("Language config is master.", nameof(command.Language))); error(new ValidationError("Master language cannot be removed."));
} }
}); });
} }
@ -60,12 +60,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (command.Language == null) if (command.Language == null)
{ {
error(new ValidationError("Language cannot be null.", nameof(command.Language))); error(new ValidationError("Language is required.", nameof(command.Language)));
} }
if ((languages.Master == languageConfig || command.IsMaster) && command.IsOptional) if ((languages.Master == languageConfig || command.IsMaster) && command.IsOptional)
{ {
error(new ValidationError("Cannot make master language optional.", nameof(command.IsMaster))); error(new ValidationError("Master language cannot be made optional.", nameof(command.IsMaster)));
} }
if (command.Fallback != null) if (command.Fallback != null)
@ -74,7 +74,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
if (!languages.Contains(fallback)) if (!languages.Contains(fallback))
{ {
error(new ValidationError($"Config does not contain fallback language {fallback}.", nameof(command.Fallback))); error(new ValidationError($"App does not have fallback language '{fallback}'.", nameof(command.Fallback)));
} }
} }
} }

2
src/Squidex.Domain.Users/Squidex.Domain.Users.csproj

@ -14,7 +14,7 @@
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.2" /> <PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.0.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" />
<PackageReference Include="SharpPwned.NET" Version="1.0.2" /> <PackageReference Include="SharpPwned.NET" Version="1.0.2-fix" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" /> <PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="System.Linq.Queryable" Version="4.3.0" /> <PackageReference Include="System.Linq.Queryable" Version="4.3.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="4.4.1" /> <PackageReference Include="System.Security.Principal.Windows" Version="4.4.1" />

4
src/Squidex.Infrastructure/Validate.cs

@ -14,7 +14,7 @@ namespace Squidex.Infrastructure
{ {
public static class Validate public static class Validate
{ {
public static void It(Func<string> message, Action<Action<ValidationError>> action) public static void It(Func<string> message, Action<Action<ValidationError>> action, IReadOnlyDictionary<string, string> messages = null)
{ {
var errors = new List<ValidationError>(); var errors = new List<ValidationError>();
@ -26,7 +26,7 @@ namespace Squidex.Infrastructure
} }
} }
public static async Task It(Func<string> message, Func<Action<ValidationError>, Task> action) public static async Task It(Func<string> message, Func<Action<ValidationError>, Task> action, IReadOnlyDictionary<string, string> messages = null)
{ {
var errors = new List<ValidationError>(); var errors = new List<ValidationError>();

27
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppClientsTests.cs

@ -7,6 +7,7 @@
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Xunit; using Xunit;
@ -23,7 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AttachClient(); var command = new AttachClient();
Assert.Throws<ValidationException>(() => GuardAppClients.CanAttach(clients_0, command)); ValidationAssert.Throws(() => GuardAppClients.CanAttach(clients_0, command),
new ValidationError("Client id is required.", "Id"));
} }
[Fact] [Fact]
@ -33,7 +35,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var clients_1 = clients_0.Add("android", "secret"); var clients_1 = clients_0.Add("android", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanAttach(clients_1, command)); ValidationAssert.Throws(() => GuardAppClients.CanAttach(clients_1, command),
new ValidationError("Client id already exists.", "Id"));
} }
[Fact] [Fact]
@ -51,7 +54,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new RevokeClient(); var command = new RevokeClient();
Assert.Throws<ValidationException>(() => GuardAppClients.CanRevoke(clients_0, command)); ValidationAssert.Throws(() => GuardAppClients.CanRevoke(clients_0, command),
new ValidationError("Client id is required.", "Id"));
} }
[Fact] [Fact]
@ -75,9 +79,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
[Fact] [Fact]
public void CanUpdate_should_throw_execption_if_client_id_is_null() public void CanUpdate_should_throw_execption_if_client_id_is_null()
{ {
var command = new UpdateClient(); var command = new UpdateClient { Name = "iOS" };
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_0, command)); ValidationAssert.Throws(() => GuardAppClients.CanUpdate(clients_0, command),
new ValidationError("Client id is required.", "Id"));
} }
[Fact] [Fact]
@ -95,7 +100,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var clients_1 = clients_0.Add("ios", "secret"); var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command)); ValidationAssert.Throws(() => GuardAppClients.CanUpdate(clients_1, command),
new ValidationError("Either name or permission must be defined.", "Name", "Permission"));
} }
[Fact] [Fact]
@ -105,7 +111,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var clients_1 = clients_0.Add("ios", "secret"); var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command)); ValidationAssert.Throws(() => GuardAppClients.CanUpdate(clients_1, command),
new ValidationError("Permission is not valid.", "Permission"));
} }
[Fact] [Fact]
@ -115,7 +122,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var clients_1 = clients_0.Add("ios", "secret"); var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command)); ValidationAssert.Throws(() => GuardAppClients.CanUpdate(clients_1, command),
new ValidationError("Client has already this name.", "Name"));
} }
[Fact] [Fact]
@ -125,7 +133,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var clients_1 = clients_0.Add("ios", "secret"); var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command)); ValidationAssert.Throws(() => GuardAppClients.CanUpdate(clients_1, command),
new ValidationError("Client has already this permission.", "Permission"));
} }
[Fact] [Fact]

26
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs

@ -10,6 +10,7 @@ using FakeItEasy;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Domain.Apps.Entities.Apps.Services;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -53,7 +54,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AssignContributor(); var command = new AssignContributor();
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan)); return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan),
new ValidationError("Contributor id is required.", "ContributorId"));
} }
[Fact] [Fact]
@ -61,7 +63,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AssignContributor { ContributorId = "1", Permission = (AppContributorPermission)10 }; var command = new AssignContributor { ContributorId = "1", Permission = (AppContributorPermission)10 };
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan)); return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan),
new ValidationError("Permission is not valid.", "Permission"));
} }
[Fact] [Fact]
@ -71,7 +74,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner); var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_1, command, users, appPlan)); return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_1, command, users, appPlan),
new ValidationError("Contributor has already this permission.", "Permission"));
} }
[Fact] [Fact]
@ -79,15 +83,16 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AssignContributor { ContributorId = "notfound", Permission = (AppContributorPermission)10 }; var command = new AssignContributor { ContributorId = "notfound", Permission = (AppContributorPermission)10 };
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan)); return Assert.ThrowsAsync<DomainObjectNotFoundException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan));
} }
[Fact] [Fact]
public Task CanAssign_should_throw_exception_if_user_is_actor() public Task CanAssign_should_throw_exception_if_user_is_actor()
{ {
var command = new AssignContributor { ContributorId = "3", Permission = (AppContributorPermission)10, Actor = new RefToken("user", "3") }; var command = new AssignContributor { ContributorId = "3", Permission = AppContributorPermission.Editor, Actor = new RefToken("user", "3") };
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan)); return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan),
new ValidationError("You cannot change your own permission."));
} }
[Fact] [Fact]
@ -101,7 +106,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner); var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor); var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor);
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_2, command, users, appPlan)); return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_2, command, users, appPlan),
new ValidationError("You have reached the maximum number of contributors for your plan."));
} }
[Fact] [Fact]
@ -151,7 +157,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new RemoveContributor(); var command = new RemoveContributor();
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors_0, command)); ValidationAssert.Throws(() => GuardAppContributors.CanRemove(contributors_0, command),
new ValidationError("Contributor id is required.", "ContributorId"));
} }
[Fact] [Fact]
@ -170,7 +177,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner); var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor); var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor);
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors_2, command)); ValidationAssert.Throws(() => GuardAppContributors.CanRemove(contributors_2, command),
new ValidationError("Cannot remove the only owner."));
} }
[Fact] [Fact]

22
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppLanguagesTests.cs

@ -8,6 +8,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Xunit; using Xunit;
@ -24,7 +25,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AddLanguage(); var command = new AddLanguage();
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages_0, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(languages_0, command),
new ValidationError("Language code is required.", "Language"));
} }
[Fact] [Fact]
@ -32,7 +34,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new AddLanguage { Language = Language.DE }; var command = new AddLanguage { Language = Language.DE };
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages_0, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(languages_0, command),
new ValidationError("Language has already been added."));
} }
[Fact] [Fact]
@ -48,7 +51,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new RemoveLanguage(); var command = new RemoveLanguage();
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanRemove(languages_0, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(languages_0, command),
new ValidationError("Language code is required.", "Language"));
} }
[Fact] [Fact]
@ -64,7 +68,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new RemoveLanguage { Language = Language.DE }; var command = new RemoveLanguage { Language = Language.DE };
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanRemove(languages_0, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(languages_0, command),
new ValidationError("Master language cannot be removed."));
} }
[Fact] [Fact]
@ -84,7 +89,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN)); var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(languages_1, command),
new ValidationError("Language is required.", "Language"));
} }
[Fact] [Fact]
@ -94,7 +100,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN)); var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(languages_1, command),
new ValidationError("Master language cannot be made optional.", "IsMaster"));
} }
[Fact] [Fact]
@ -104,7 +111,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN)); var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, command)); ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(languages_1, command),
new ValidationError("App does not have fallback language 'Italian'.", "Fallback"));
} }
[Fact] [Fact]

21
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppTests.cs

@ -10,6 +10,7 @@ using FakeItEasy;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Domain.Apps.Entities.Apps.Services;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Shared.Users; using Squidex.Shared.Users;
using Xunit; using Xunit;
@ -42,7 +43,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var command = new CreateApp { Name = "new-app" }; var command = new CreateApp { Name = "new-app" };
return Assert.ThrowsAsync<ValidationException>(() => GuardApp.CanCreate(command, apps)); return ValidationAssert.ThrowsAsync(() => GuardApp.CanCreate(command, apps),
new ValidationError("An app with name 'new-app' already exists.", "Name"));
} }
[Fact] [Fact]
@ -50,7 +52,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
{ {
var command = new CreateApp { Name = "INVALID NAME" }; var command = new CreateApp { Name = "INVALID NAME" };
return Assert.ThrowsAsync<ValidationException>(() => GuardApp.CanCreate(command, apps)); return ValidationAssert.ThrowsAsync(() => GuardApp.CanCreate(command, apps),
new ValidationError("Name must be a valid slug (lowercase characters, numbers and dashes).", "Name"));
} }
[Fact] [Fact]
@ -62,13 +65,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
} }
[Fact] [Fact]
public void CanChangePlan_should_throw_exception_if_plan_id_null() public void CanChangePlan_should_throw_exception_if_plan_id_is_null()
{ {
var command = new ChangePlan { Actor = new RefToken("user", "me") }; var command = new ChangePlan { Actor = new RefToken("user", "me") };
AppPlan plan = null; AppPlan plan = null;
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, plan, appPlans),
new ValidationError("Plan id is required.", "PlanId"));
} }
[Fact] [Fact]
@ -81,7 +85,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
AppPlan plan = null; AppPlan plan = null;
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, plan, appPlans),
new ValidationError("Plan with id 'free' is not available.", "PlanId"));
} }
[Fact] [Fact]
@ -91,7 +96,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var plan = new AppPlan(new RefToken("user", "other"), "premium"); var plan = new AppPlan(new RefToken("user", "other"), "premium");
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, plan, appPlans),
new ValidationError("Plan can only changed from the user who configured the plan initially."));
} }
[Fact] [Fact]
@ -101,7 +107,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var plan = new AppPlan(new RefToken("user", "me"), "free"); var plan = new AppPlan(new RefToken("user", "me"), "free");
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, plan, appPlans),
new ValidationError("App has already this plan."));
} }
[Fact] [Fact]

54
tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/ValidationAssert.cs

@ -0,0 +1,54 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Entities.TestHelpers
{
public static class ValidationAssert
{
public static void Throws(Action action, params ValidationError[] errors)
{
try
{
action();
Assert.True(false, $"Expected {typeof(ValidationException)} but succeeded");
}
catch (ValidationException ex)
{
ex.Errors.ToArray().ShouldBeEquivalent(errors);
}
catch (Exception ex)
{
Assert.True(false, $"Excepted {typeof(ValidationException)}, but got {ex.GetType()}");
}
}
public static async Task ThrowsAsync(Func<Task> action, params ValidationError[] errors)
{
try
{
await action();
Assert.True(false, $"Expected {typeof(ValidationException)} but succeeded");
}
catch (ValidationException ex)
{
ex.Errors.ToArray().ShouldBeEquivalent(errors);
}
catch (Exception ex)
{
Assert.True(false, $"Excepted {typeof(ValidationException)}, but got {ex.GetType()}");
}
}
}
}
Loading…
Cancel
Save