Browse Source

Fix tests hopefully.

pull/1301/head
Sebastian Stehle 6 months ago
parent
commit
16c5083a16
  1. 16
      backend/.editorconfig
  2. 7
      backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs
  3. 6
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetEntity.cs
  4. 6
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetFolderEntity.cs
  5. 5
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetFolderRepository.cs
  6. 8
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetItemClassMap.cs
  7. 5
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetRepository.cs
  8. 8
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/MongoContentEntity.cs
  9. 9
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/MongoContentRepository.cs
  10. 15
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexerState.cs
  11. 25
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextStateClassMap.cs
  12. 27
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/History/MongoHistoryClassMap.cs
  13. 10
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/History/MongoHistoryEventRepository.cs
  14. 8
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/MongoAppEntityClassMap.cs
  15. 6
      backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/MongoEntityClassMap.cs
  16. 37
      backend/src/Squidex.Data.MongoDb/Domain/Users/IdentityUserForwardingSerializer.cs
  17. 116
      backend/src/Squidex.Data.MongoDb/Domain/Users/MongoIdentityClassMap.cs
  18. 16
      backend/src/Squidex.Data.MongoDb/Domain/Users/MongoRoleStore.cs
  19. 116
      backend/src/Squidex.Data.MongoDb/Domain/Users/MongoUserStore.cs
  20. 31
      backend/src/Squidex.Data.MongoDb/Infrastructure/MongoClientFactory.cs
  21. 1
      backend/src/Squidex.Data.MongoDb/Infrastructure/MongoRepositoryBase.cs
  22. 59
      backend/src/Squidex.Data.MongoDb/MongoClientFactory.cs
  23. 14
      backend/src/Squidex.Data.MongoDb/ServiceExtensions.cs
  24. 6
      backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/MySqlMigrationTests.cs
  25. 6
      backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/PostgresMigrationTests.cs
  26. 6
      backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/SqlServerMigrationTests.cs
  27. 8
      backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/MySqlFixture.cs
  28. 8
      backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/PostgresFixture.cs
  29. 10
      backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/SqlServerFixture.cs
  30. 1
      backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs
  31. 6
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Assets/AssetQueryTests.cs
  32. 7
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/AdaptionTests.cs
  33. 1
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ContentMappingTests.cs
  34. 7
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ContentQueryTests.cs
  35. 6
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ExtensionsTests.cs
  36. 6
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/IndexParserTests.cs
  37. 11
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/Text/AtlasTextIndexFixture.cs
  38. 1
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/TokenizerTests.cs
  39. 6
      backend/tests/Squidex.Data.Tests/MongoDb/Domain/Schemas/MongoSchemasHashTests.cs
  40. 1
      backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/EventConsumerProcessorIntegrationTests.cs
  41. 15
      backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/EventSourcing/MongoEventStoreFixture.cs
  42. 5
      backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/NamedIdTests.cs
  43. 5
      backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/Queries/MongoQueryTests.cs
  44. 2
      backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/DocumentDbFixture.cs
  45. 15
      backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoFixture.cs
  46. 26
      backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoSerializerFixture.cs
  47. 19
      backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoTestUtils.cs
  48. 2
      backend/tests/Squidex.Data.Tests/Shared/AssetFolderRepositoryTests.cs
  49. 2
      backend/tests/Squidex.Data.Tests/Shared/AssetRepositoryTests.cs
  50. 2
      backend/tests/Squidex.Data.Tests/Squidex.Data.Tests.csproj
  51. 26
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/ExpressionsAttribute.cs
  52. 2
      backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj
  53. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTests.cs
  54. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AzureTextIndexFixture.cs
  55. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/ElasticSearchTextIndexFixture.cs
  56. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/OpenSearchTextIndexFixture.cs
  57. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj
  58. 2
      backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj
  59. 2
      backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj
  60. 2
      backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs
  61. 2
      backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj
  62. 22
      tools/.editorconfig
  63. 10
      tools/TestSuite/TestSuite.ApiTests/ContentQueryFixture.cs
  64. 14
      tools/TestSuite/TestSuite.ApiTests/GraphQLFixture.cs
  65. 4
      tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj
  66. 1
      tools/TestSuite/TestSuite.LoadTests/ReadingBenchmarks.cs
  67. 4
      tools/TestSuite/TestSuite.LoadTests/ReadingFixture.cs
  68. 1
      tools/TestSuite/TestSuite.LoadTests/Run.cs
  69. 2
      tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj
  70. 6
      tools/TestSuite/TestSuite.Shared/Fixtures/ClientFixture.cs
  71. 2
      tools/TestSuite/TestSuite.Shared/Fixtures/CreatedAppFixture.cs
  72. 2
      tools/TestSuite/TestSuite.Shared/Fixtures/CreatedTeamFixture.cs
  73. 2
      tools/TestSuite/TestSuite.Shared/Fixtures/TestSchemaFixtureBase.cs
  74. 2
      tools/TestSuite/TestSuite.Shared/Fixtures/TestSchemaWithReferencesFixtureBase.cs
  75. 2
      tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

16
backend/.editorconfig

@ -184,4 +184,18 @@ dotnet_diagnostic.SA1623.severity = none
dotnet_diagnostic.SYSLIB1045.severity = none
# xUnit1033: Test classes decorated with 'Xunit.IClassFixture<TFixture>' or 'Xunit.ICollectionFixture<TFixture>' should add a constructor argument of type TFixture
dotnet_diagnostic.xUnit1033.severity = none
dotnet_diagnostic.xUnit1033.severity = none
[*Tests*.cs]
# MA0040: Forward the CancellationToken parameter to methods that take one
dotnet_diagnostic.MA0040.severity = none
# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken
dotnet_diagnostic.xUnit1051.severity = none
# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = none
[*Fixture.cs]
# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = none

7
backend/extensions/Squidex.Extensions/Actions/Kafka/KafkaProducer.cs

@ -96,7 +96,10 @@ public sealed class KafkaProducer
break;
}
log.Log(level, "Kafka log {name}: {message}.", message.Name, message.Message);
if (log.IsEnabled(level))
{
log.Log(level, "Kafka log {name}: {message}.", message.Name, message.Message);
}
}
private static void LogError(ILogger<KafkaProducer> log, Error error)
@ -279,4 +282,4 @@ public sealed class KafkaProducer
return schema?.Tag == expected || (schema is UnionSchema union && union.Schemas.Any(x => x.Tag == expected));
}
}
#endif
#endif

6
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetEntity.cs

@ -21,9 +21,7 @@ public record MongoAssetEntity : Asset, IVersionedEntity<DomainId>
public static void RegisterClassMap()
{
AssetItemClassMap.Register();
BsonClassMap.TryRegisterClassMap<MongoAssetEntity>(cm =>
BsonClassMap.RegisterClassMap<MongoAssetEntity>(cm =>
{
cm.MapProperty(x => x.DocumentId)
.SetElementName("_id")
@ -34,7 +32,7 @@ public record MongoAssetEntity : Asset, IVersionedEntity<DomainId>
.SetIsRequired(true);
});
BsonClassMap.TryRegisterClassMap<Asset>(cm =>
BsonClassMap.RegisterClassMap<Asset>(cm =>
{
cm.MapProperty(x => x.FileName)
.SetElementName("fn")

6
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetFolderEntity.cs

@ -21,7 +21,7 @@ public record MongoAssetFolderEntity : AssetFolder, IVersionedEntity<DomainId>
public static void RegisterClassMap()
{
BsonClassMap.TryRegisterClassMap<MongoAssetFolderEntity>(cm =>
BsonClassMap.RegisterClassMap<MongoAssetFolderEntity>(cm =>
{
cm.MapProperty(x => x.DocumentId)
.SetElementName("_id")
@ -32,14 +32,12 @@ public record MongoAssetFolderEntity : AssetFolder, IVersionedEntity<DomainId>
.SetIsRequired(true);
});
BsonClassMap.TryRegisterClassMap<AssetFolder>(cm =>
BsonClassMap.RegisterClassMap<AssetFolder>(cm =>
{
cm.MapProperty(x => x.FolderName)
.SetElementName("fn")
.SetIsRequired(true);
});
AssetItemClassMap.Register();
}
public static MongoAssetFolderEntity Create(SnapshotWriteJob<AssetFolder> job)

5
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetFolderRepository.cs

@ -15,11 +15,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets;
public sealed partial class MongoAssetFolderRepository(IMongoDatabase database) : MongoRepositoryBase<MongoAssetFolderEntity>(database), IAssetFolderRepository
{
static MongoAssetFolderRepository()
{
MongoAssetFolderEntity.RegisterClassMap();
}
protected override string CollectionName()
{
return "States_AssetFolders2";

8
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/AssetItemClassMap.cs → backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetItemClassMap.cs

@ -10,13 +10,11 @@ using Squidex.Domain.Apps.Core.Assets;
namespace Squidex.Domain.Apps.Entities.Assets;
internal static class AssetItemClassMap
internal static class MongoAssetItemClassMap
{
public static void Register()
public static void RegisterClassMap()
{
AppEntityClassMap.Register();
BsonClassMap.TryRegisterClassMap<AssetItem>(cm =>
BsonClassMap.RegisterClassMap<AssetItem>(cm =>
{
cm.MapProperty(x => x.ParentId)
.SetElementName("pi")

5
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Assets/MongoAssetRepository.cs

@ -24,11 +24,6 @@ public sealed partial class MongoAssetRepository : MongoRepositoryBase<MongoAsse
private readonly MongoCountCollection countCollection;
private readonly string shardKey;
static MongoAssetRepository()
{
MongoAssetEntity.RegisterClassMap();
}
public MongoAssetRepository(IMongoDatabase database, ILogger<MongoAssetRepository> log, string shardKey)
: base(database)
{

8
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/MongoContentEntity.cs

@ -34,9 +34,7 @@ public record MongoContentEntity : Content, IVersionedEntity<DomainId>
public static void RegisterClassMap()
{
AppEntityClassMap.Register();
BsonClassMap.TryRegisterClassMap<MongoContentEntity>(cm =>
BsonClassMap.RegisterClassMap<MongoContentEntity>(cm =>
{
cm.MapProperty(x => x.DocumentId)
.SetElementName("_id")
@ -71,7 +69,7 @@ public record MongoContentEntity : Content, IVersionedEntity<DomainId>
.SetIgnoreIfDefault(true);
});
BsonClassMap.TryRegisterClassMap<Content>(cm =>
BsonClassMap.RegisterClassMap<Content>(cm =>
{
cm.MapProperty(x => x.SchemaId)
.SetElementName("si")
@ -93,8 +91,6 @@ public record MongoContentEntity : Content, IVersionedEntity<DomainId>
.SetElementName("sj")
.SetIgnoreIfDefault(true);
});
EntityClassMap.Register();
}
public WriteContent ToState()

9
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/MongoContentRepository.cs

@ -49,15 +49,6 @@ public partial class MongoContentRepository(
public bool CanUseTransactions { get; private set; }
static MongoContentRepository()
{
BsonEscapedDictionarySerializer<JsonValue, JsonObject>.Register();
BsonEscapedDictionarySerializer<JsonValue, ContentFieldData>.Register();
BsonEscapedDictionarySerializer<ContentFieldData, ContentData>.Register();
BsonStringSerializer<Status>.Register();
MongoContentEntity.RegisterClassMap();
}
public async Task InitializeAsync(
CancellationToken ct)
{

15
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexerState.cs

@ -5,13 +5,11 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.Contents.Text.State;
using Squidex.Domain.Apps.Entities.MongoDb;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents.Text;
@ -21,19 +19,6 @@ public sealed class MongoTextIndexerState(
IContentRepository contentRepository)
: MongoRepositoryBase<TextContentState>(database), ITextIndexerState, IDeleter
{
static MongoTextIndexerState()
{
BsonUniqueContentIdSerializer.Register();
BsonClassMap.TryRegisterClassMap<TextContentState>(cm =>
{
cm.MapIdProperty(x => x.UniqueContentId);
cm.MapProperty(x => x.State)
.SetElementName("s");
});
}
int IDeleter.Order => -2000;
protected override string CollectionName()

25
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextStateClassMap.cs

@ -0,0 +1,25 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using MongoDB.Bson.Serialization;
using Squidex.Domain.Apps.Entities.Contents.Text.State;
namespace Squidex.Domain.Apps.Entities.Contents.Text;
internal static class MongoTextStateClassMap
{
public static void RegisterClassMap()
{
BsonClassMap.RegisterClassMap<TextContentState>(cm =>
{
cm.MapIdProperty(x => x.UniqueContentId);
cm.MapProperty(x => x.State)
.SetElementName("s");
});
}
}

27
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/History/MongoHistoryClassMap.cs

@ -0,0 +1,27 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using MongoDB.Bson.Serialization;
namespace Squidex.Domain.Apps.Entities.History;
internal static class MongoHistoryClassMap
{
public static void RegisterClassMap()
{
BsonClassMap.RegisterClassMap<HistoryEvent>(cm =>
{
cm.AutoMap();
cm.MapProperty(x => x.OwnerId)
.SetElementName("AppId");
cm.MapProperty(x => x.EventType)
.SetElementName("Message");
});
}
}

10
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/History/MongoHistoryEventRepository.cs

@ -17,16 +17,6 @@ public sealed class MongoHistoryEventRepository(IMongoDatabase database) : Mongo
{
static MongoHistoryEventRepository()
{
BsonClassMap.TryRegisterClassMap<HistoryEvent>(cm =>
{
cm.AutoMap();
cm.MapProperty(x => x.OwnerId)
.SetElementName("AppId");
cm.MapProperty(x => x.EventType)
.SetElementName("Message");
});
}
protected override string CollectionName()

8
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/AppEntityClassMap.cs → backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/MongoAppEntityClassMap.cs

@ -10,13 +10,11 @@ using Squidex.Domain.Apps.Core;
namespace Squidex.Domain.Apps.Entities;
public static class AppEntityClassMap
public static class MongoAppEntityClassMap
{
public static void Register()
public static void RegisterClassMap()
{
EntityClassMap.Register();
BsonClassMap.TryRegisterClassMap<AppEntity>(cm =>
BsonClassMap.RegisterClassMap<AppEntity>(cm =>
{
cm.MapProperty(x => x.AppId)
.SetElementName("ai")

6
backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/EntityClassMap.cs → backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/MongoEntityClassMap.cs

@ -10,11 +10,11 @@ using Squidex.Infrastructure.Commands;
namespace Squidex.Domain.Apps.Entities;
internal static class EntityClassMap
internal static class MongoEntityClassMap
{
public static void Register()
public static void RegisterClassMap()
{
BsonClassMap.TryRegisterClassMap<Entity>(cm =>
BsonClassMap.RegisterClassMap<Entity>(cm =>
{
cm.MapProperty(x => x.Id)
.SetElementName("id")

37
backend/src/Squidex.Data.MongoDb/Domain/Users/IdentityUserForwardingSerializer.cs

@ -0,0 +1,37 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Identity;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace Squidex.Domain.Users;
internal sealed class IdentityUserForwardingSerializer
: SerializerBase<IdentityUser>, IBsonDocumentSerializer
{
private static readonly IBsonSerializer<MongoUser> MongoUserSerializer =
BsonSerializer.LookupSerializer<MongoUser>();
public override IdentityUser Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
args.NominalType = typeof(MongoUser);
return MongoUserSerializer.Deserialize(context, args);
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, IdentityUser value)
{
args.NominalType = typeof(MongoUser);
MongoUserSerializer.Serialize(context, args, (MongoUser)value);
}
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
return ((IBsonDocumentSerializer)MongoUserSerializer)
.TryGetMemberSerializationInfo(memberName, out serializationInfo);
}
}

116
backend/src/Squidex.Data.MongoDb/Domain/Users/MongoIdentityClassMap.cs

@ -0,0 +1,116 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Security.Claims;
using Microsoft.AspNetCore.Identity;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace Squidex.Domain.Users;
internal static class MongoIdentityClassMap
{
public static void RegisterClassMap()
{
BsonClassMap.RegisterClassMap<IdentityRole<string>>(cm =>
{
cm.AutoMap();
cm.MapMember(x => x.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId));
cm.UnmapMember(x => x.ConcurrencyStamp);
});
BsonClassMap.RegisterClassMap<Claim>(cm =>
{
cm.MapConstructor(typeof(Claim).GetConstructors()
.First(x =>
{
var parameters = x.GetParameters();
return parameters.Length == 2 &&
parameters[0].Name == "type" &&
parameters[0].ParameterType == typeof(string) &&
parameters[1].Name == "value" &&
parameters[1].ParameterType == typeof(string);
}))
.SetArguments(
[
nameof(Claim.Type),
nameof(Claim.Value),
]);
cm.MapMember(x => x.Type);
cm.MapMember(x => x.Value);
});
BsonClassMap.RegisterClassMap<UserLogin>(cm =>
{
cm.MapConstructor(typeof(UserLogin).GetConstructors()
.First(x =>
{
var parameters = x.GetParameters();
return parameters.Length == 3;
}))
.SetArguments(
[
nameof(UserLogin.LoginProvider),
nameof(UserLogin.ProviderKey),
nameof(UserLogin.ProviderDisplayName),
]);
cm.AutoMap();
});
BsonClassMap.RegisterClassMap<IdentityUserToken<string>>(cm =>
{
cm.AutoMap();
cm.UnmapMember(x => x.UserId);
});
BsonClassMap.RegisterClassMap<IdentityUser<string>>(cm =>
{
cm.AutoMap();
cm.MapMember(x => x.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId));
cm.MapMember(x => x.AccessFailedCount)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.EmailConfirmed)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.LockoutEnd)
.SetElementName("LockoutEndDateUtc").SetIgnoreIfNull(true);
cm.MapMember(x => x.LockoutEnabled)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.PasswordHash)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.PhoneNumber)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.PhoneNumberConfirmed)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.SecurityStamp)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.TwoFactorEnabled)
.SetIgnoreIfDefault(true);
});
BsonSerializer.RegisterSerializer(new IdentityUserForwardingSerializer());
}
}

16
backend/src/Squidex.Data.MongoDb/Domain/Users/MongoRoleStore.cs

@ -6,9 +6,6 @@
// ==========================================================================
using Microsoft.AspNetCore.Identity;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using Squidex.Infrastructure;
@ -16,19 +13,6 @@ namespace Squidex.Domain.Users;
public sealed class MongoRoleStore(IMongoDatabase database) : MongoRepositoryBase<IdentityRole>(database), IRoleStore<IdentityRole>
{
static MongoRoleStore()
{
BsonClassMap.RegisterClassMap<IdentityRole<string>>(cm =>
{
cm.AutoMap();
cm.MapMember(x => x.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId));
cm.UnmapMember(x => x.ConcurrencyStamp);
});
}
protected override string CollectionName()
{
return "Identity_Roles";

116
backend/src/Squidex.Data.MongoDb/Domain/Users/MongoUserStore.cs

@ -8,8 +8,6 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Identity;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using Squidex.Infrastructure;
@ -37,95 +35,6 @@ public sealed class MongoUserStore(IMongoDatabase database) :
private const string RecoveryCodeTokenName = "RecoveryCodes";
private IMongoCollection<IdentityUser> queryableCollection;
static MongoUserStore()
{
BsonClassMap.RegisterClassMap<Claim>(cm =>
{
cm.MapConstructor(typeof(Claim).GetConstructors()
.First(x =>
{
var parameters = x.GetParameters();
return parameters.Length == 2 &&
parameters[0].Name == "type" &&
parameters[0].ParameterType == typeof(string) &&
parameters[1].Name == "value" &&
parameters[1].ParameterType == typeof(string);
}))
.SetArguments(
[
nameof(Claim.Type),
nameof(Claim.Value),
]);
cm.MapMember(x => x.Type);
cm.MapMember(x => x.Value);
});
BsonClassMap.RegisterClassMap<UserLogin>(cm =>
{
cm.MapConstructor(typeof(UserLogin).GetConstructors()
.First(x =>
{
var parameters = x.GetParameters();
return parameters.Length == 3;
}))
.SetArguments(
[
nameof(UserLogin.LoginProvider),
nameof(UserLogin.ProviderKey),
nameof(UserLogin.ProviderDisplayName),
]);
cm.AutoMap();
});
BsonClassMap.RegisterClassMap<IdentityUserToken<string>>(cm =>
{
cm.AutoMap();
cm.UnmapMember(x => x.UserId);
});
BsonClassMap.RegisterClassMap<IdentityUser<string>>(cm =>
{
cm.AutoMap();
cm.MapMember(x => x.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId));
cm.MapMember(x => x.AccessFailedCount)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.EmailConfirmed)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.LockoutEnd)
.SetElementName("LockoutEndDateUtc").SetIgnoreIfNull(true);
cm.MapMember(x => x.LockoutEnabled)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.PasswordHash)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.PhoneNumber)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.PhoneNumberConfirmed)
.SetIgnoreIfDefault(true);
cm.MapMember(x => x.SecurityStamp)
.SetIgnoreIfNull(true);
cm.MapMember(x => x.TwoFactorEnabled)
.SetIgnoreIfDefault(true);
});
BsonSerializer.TryRegisterSerializer(new IdentityUserForwardingSerializer());
}
protected override string CollectionName()
{
return "Identity_Users";
@ -672,29 +581,4 @@ public sealed class MongoUserStore(IMongoDatabase database) :
filter.Eq(x => x.LoginProvider, loginProvider),
filter.Eq(x => x.ProviderKey, providerKey));
}
private sealed class IdentityUserForwardingSerializer
: SerializerBase<IdentityUser>, IBsonDocumentSerializer
{
private static readonly IBsonSerializer<MongoUser> MongoUserSerializer =
BsonSerializer.LookupSerializer<MongoUser>();
public override IdentityUser Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
args.NominalType = typeof(MongoUser);
return MongoUserSerializer.Deserialize(context, args);
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, IdentityUser value)
{
args.NominalType = typeof(MongoUser);
MongoUserSerializer.Serialize(context, args, (MongoUser)value);
}
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
return ((IBsonDocumentSerializer)MongoUserSerializer)
.TryGetMemberSerializationInfo(memberName, out serializationInfo);
}
}
}

31
backend/src/Squidex.Data.MongoDb/Infrastructure/MongoClientFactory.cs

@ -1,31 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using MongoDB.Driver;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Infrastructure;
public static class MongoClientFactory
{
public static MongoClient Create(string? connectionString, Action<MongoClientSettings>? configure = null)
{
BsonDefaultConventions.Register();
BsonDomainIdSerializer.Register();
BsonEscapedDictionarySerializer<JsonValue, JsonObject>.Register();
BsonInstantSerializer.Register();
BsonJsonValueSerializer.Register();
BsonStringSerializer<RefToken>.Register();
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
// If we really need custom config.
configure?.Invoke(clientSettings);
return new MongoClient(clientSettings);
}
}

1
backend/src/Squidex.Data.MongoDb/Infrastructure/MongoRepositoryBase.cs

@ -87,6 +87,7 @@ public abstract class MongoRepositoryBase<T> : MongoBase<T>, IInitializable
{
try
{
Console.WriteLine("AASDASD");
CreateCollection();
await SetupCollectionAsync(Collection, ct);

59
backend/src/Squidex.Data.MongoDb/MongoClientFactory.cs

@ -0,0 +1,59 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Text.Json;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Contents.Text;
using Squidex.Domain.Apps.Entities.History;
using Squidex.Domain.Apps.Entities.MongoDb;
using Squidex.Domain.Users;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex;
public static class MongoClientFactory
{
public static void SetupSerializer(JsonSerializerOptions jsonSerializerOptions, BsonType representation)
{
// Register the serializers first.
BsonDomainIdSerializer.Register();
BsonEscapedDictionarySerializer<JsonValue, JsonObject>.Register();
BsonInstantSerializer.Register();
BsonJsonValueSerializer.Register();
BsonStringSerializer<RefToken>.Register();
BsonUniqueContentIdSerializer.Register();
BsonJsonConvention.Register(jsonSerializerOptions, representation);
// Keep the order, because we have an inheritance between entities.
MongoEntityClassMap.RegisterClassMap();
MongoAppEntityClassMap.RegisterClassMap();
MongoAssetItemClassMap.RegisterClassMap();
MongoAssetEntity.RegisterClassMap();
MongoAssetFolderEntity.RegisterClassMap();
MongoContentEntity.RegisterClassMap();
MongoHistoryClassMap.RegisterClassMap();
MongoIdentityClassMap.RegisterClassMap();
MongoTextStateClassMap.RegisterClassMap();
BsonDefaultConventions.Register();
}
public static MongoClient Create(string? connectionString, Action<MongoClientSettings>? configure = null)
{
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
// If we really need custom config.
configure?.Invoke(clientSettings);
return new MongoClient(clientSettings);
}
}

14
backend/src/Squidex.Data.MongoDb/ServiceExtensions.cs

@ -70,7 +70,8 @@ public static class ServiceExtensions
services.AddSingletonAs(c =>
{
var options = c.GetRequiredService<IOptions<MongoEventStoreOptions>>();
var mongoClient = GetMongoClient(config, "eventStore:mongoDb");
var mongoClient = GetMongoClient(config, c.GetRequiredService<JsonSerializerOptions>(), "eventStore:mongoDb");
var mongoDatabase = mongoClient.GetDatabase(mongoDatabaseName);
return new MongoEventStore(mongoDatabase, options);
@ -85,7 +86,7 @@ public static class ServiceExtensions
services.AddMongoAssetStore(c =>
{
var mongoClient = GetMongoClient(config, "assetStore:mongoDb");
var mongoClient = GetMongoClient(config, c.GetRequiredService<JsonSerializerOptions>(), "assetStore:mongoDb");
var mongoDatabase = mongoClient.GetDatabase(mongoDatabaseName);
return new GridFSBucket<string>(mongoDatabase, new GridFSBucketOptions
@ -105,7 +106,7 @@ public static class ServiceExtensions
return GetDatabase(c, mongoDatabaseName);
});
services.AddSingletonAs(c => GetMongoClient(config, "store:mongoDb"))
services.AddSingletonAs(c => GetMongoClient(config, c.GetRequiredService<JsonSerializerOptions>(), "store:mongoDb"))
.As<IMongoClient>();
services.AddSingletonAs(c => GetDatabase(c, mongoDatabaseName))
@ -288,14 +289,19 @@ public static class ServiceExtensions
.As<IMigration>();
}
private static IMongoClient GetMongoClient(IConfiguration config, string prefix)
private static IMongoClient GetMongoClient(IConfiguration config, JsonSerializerOptions serializerOptions, string prefix)
{
var representation = config.GetValue<BsonType>("store:mongoDB:valueRepresentation");
var mongoConfiguration = config.GetRequiredValue($"{prefix}:configuration")!;
var mongoCertificate = config.GetValue<string>($"{prefix}:certificate");
var cacheKey = $"{mongoConfiguration}_{mongoCertificate}";
return Singletons<IMongoClient>.GetOrAdd(cacheKey, _ =>
{
MongoClientFactory.SetupSerializer(serializerOptions, representation);
return MongoClientFactory.Create(mongoConfiguration, settings =>
{
if (!string.IsNullOrWhiteSpace(mongoCertificate))

6
backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/MySqlMigrationTests.cs

@ -20,12 +20,12 @@ public class MySqlMigrationTests : IAsyncLifetime
{
private readonly MySqlContainer mysql = new MySqlBuilder("mysql:8.0").Build();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await mysql.StartAsync();
await mysql.StartAsync(TestContext.Current.CancellationToken);
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await mysql.DisposeAsync();
}

6
backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/PostgresMigrationTests.cs

@ -22,12 +22,12 @@ public class PostgresMigrationTests : IAsyncLifetime
new PostgreSqlBuilder("postgis/postgis")
.Build();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await postgreSql.StartAsync();
await postgreSql.StartAsync(TestContext.Current.CancellationToken);
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await postgreSql.DisposeAsync();
}

6
backend/tests/Squidex.Data.Tests/EntityFramework/Migrations/SqlServerMigrationTests.cs

@ -22,12 +22,12 @@ public class SqlServerMigrationTests : IAsyncLifetime
new MsSqlBuilder("mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
.Build();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await sqlServer.StartAsync();
await sqlServer.StartAsync(TestContext.Current.CancellationToken);
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await sqlServer.DisposeAsync();
}

8
backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/MySqlFixture.cs

@ -37,9 +37,9 @@ public class MySqlFixture(string? reuseId = null) : IAsyncLifetime, ISqlContentF
public IDbContextNamedFactory<MySqlContentDbContext> DbContextNamedFactory
=> services.GetRequiredService<IDbContextNamedFactory<MySqlContentDbContext>>();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await mysql.StartAsync();
await mysql.StartAsync(TestContext.Current.CancellationToken);
var connectionString = $"{mysql.GetConnectionString()};AllowLoadLocalInfile=true;MaxPoolSize=1000";
@ -77,13 +77,13 @@ public class MySqlFixture(string? reuseId = null) : IAsyncLifetime, ISqlContentF
}
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
foreach (var service in services.GetRequiredService<IEnumerable<IInitializable>>())
{
await service.ReleaseAsync(default);
}
await mysql.StopAsync();
await mysql.StopAsync(TestContext.Current.CancellationToken);
}
}

8
backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/PostgresFixture.cs

@ -36,9 +36,9 @@ public class PostgresFixture(string? reuseId) : IAsyncLifetime, ISqlContentFixtu
public IDbContextNamedFactory<PostgresContentDbContext> DbContextNamedFactory
=> services.GetRequiredService<IDbContextNamedFactory<PostgresContentDbContext>>();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await postgreSql.StartAsync();
await postgreSql.StartAsync(TestContext.Current.CancellationToken);
var connectionString = postgreSql.GetConnectionString();
@ -72,13 +72,13 @@ public class PostgresFixture(string? reuseId) : IAsyncLifetime, ISqlContentFixtu
}
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
foreach (var service in services.GetRequiredService<IEnumerable<IInitializable>>())
{
await service.ReleaseAsync(default);
}
await postgreSql.StopAsync();
await postgreSql.StopAsync(TestContext.Current.CancellationToken);
}
}

10
backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/SqlServerFixture.cs

@ -37,10 +37,10 @@ public class SqlServerFixture(string? reuseId = null) : IAsyncLifetime, ISqlCont
public IDbContextNamedFactory<SqlServerContentDbContext> DbContextNamedFactory
=> services.GetRequiredService<IDbContextNamedFactory<SqlServerContentDbContext>>();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await sqlServer.StartAsync();
await sqlServer.ExecScriptAsync($"create database squidex;");
await sqlServer.StartAsync(TestContext.Current.CancellationToken);
await sqlServer.ExecScriptAsync($"create database squidex;", TestContext.Current.CancellationToken);
var connectionString = GetConnectionString();
@ -74,14 +74,14 @@ public class SqlServerFixture(string? reuseId = null) : IAsyncLifetime, ISqlCont
}
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
foreach (var service in services.GetRequiredService<IEnumerable<IInitializable>>())
{
await service.ReleaseAsync(default);
}
await sqlServer.StopAsync();
await sqlServer.StopAsync(TestContext.Current.CancellationToken);
}
private string GetConnectionString()

1
backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using NetTopologySuite.Geometries;
#pragma warning disable MA0048 // File name must match type name

6
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Assets/AssetQueryTests.cs

@ -24,12 +24,6 @@ public class AssetQueryTests
{
private readonly DomainId appId = DomainId.NewGuid();
static AssetQueryTests()
{
MongoAssetEntity.RegisterClassMap();
MongoTestUtils.SetupBson();
}
[Fact]
public void Should_throw_exception_for_full_text_search()
{

7
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/AdaptionTests.cs

@ -5,18 +5,13 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Contents.Operations;
using Squidex.MongoDb.TestHelpers;
namespace Squidex.MongoDb.Domain.Contents;
public class AdaptionTests
{
static AdaptionTests()
{
MongoContentEntity.RegisterClassMap();
}
[Fact]
public void Should_adapt_to_meta_field()
{

1
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ContentMappingTests.cs

@ -9,6 +9,7 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure.States;
using Squidex.MongoDb.TestHelpers;
namespace Squidex.MongoDb.Domain.Contents;

7
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ContentQueryTests.cs

@ -24,13 +24,6 @@ namespace Squidex.MongoDb.Domain.Contents;
public class ContentQueryTests : GivenContext
{
static ContentQueryTests()
{
MongoContentEntity.RegisterClassMap();
MongoTestUtils.SetupBson();
}
public ContentQueryTests()
{
Schema = Schema with { Version = 3 };

6
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/ExtensionsTests.cs

@ -8,17 +8,13 @@
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.MongoDb.TestHelpers;
using ExtensionSut = Squidex.Domain.Apps.Entities.Contents.Operations.Extensions;
namespace Squidex.MongoDb.Domain.Contents;
public class ExtensionsTests
{
public ExtensionsTests()
{
MongoContentEntity.RegisterClassMap();
}
[Fact]
public void Should_build_projection_without_fields()
{

6
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/IndexParserTests.cs

@ -9,6 +9,7 @@ using MongoDB.Bson;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Infrastructure.Queries;
using Squidex.Infrastructure.States;
using Squidex.MongoDb.TestHelpers;
namespace Squidex.MongoDb.Domain.Contents;
@ -26,11 +27,6 @@ public class IndexParserTests
},
};
static IndexParserTests()
{
MongoContentEntity.RegisterClassMap();
}
[Fact]
public void Should_parse_index()
{

11
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/Text/AtlasTextIndexFixture.cs

@ -11,7 +11,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Entities.Contents.Text;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.MongoDb.TestHelpers;
namespace Squidex.MongoDb.Domain.Contents.Text;
@ -22,8 +21,6 @@ public sealed class AtlasTextIndexFixture : IAsyncLifetime
public AtlasTextIndexFixture()
{
MongoTestUtils.SetupBson();
var mongoClient = MongoClientFactory.Create(TestConfig.Configuration["atlas:configuration"]!);
var mongoDatabase = mongoClient.GetDatabase(TestConfig.Configuration["atlas:database"]!);
@ -50,13 +47,13 @@ public sealed class AtlasTextIndexFixture : IAsyncLifetime
Index = services.GetRequiredService<AtlasTextIndex>();
}
public Task InitializeAsync()
public async ValueTask InitializeAsync()
{
return Index.InitializeAsync(default);
await Index.InitializeAsync(default);
}
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
}

1
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Contents/TokenizerTests.cs

@ -6,6 +6,7 @@
// ==========================================================================
using Squidex.Domain.Apps.Entities.Contents.Text;
using Squidex.MongoDb.TestHelpers;
namespace Squidex.MongoDb.Domain.Contents;

6
backend/tests/Squidex.Data.Tests/MongoDb/Domain/Schemas/MongoSchemasHashTests.cs

@ -24,14 +24,14 @@ public class MongoSchemasHashTests(MongoFixture fixture) : GivenContext, IAsyncL
{
private readonly MongoSchemasHash sut = new MongoSchemasHash(fixture.Database);
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await sut.InitializeAsync(default);
}
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
[Fact]

1
backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/EventConsumerProcessorIntegrationTests.cs

@ -14,6 +14,7 @@ using Squidex.Infrastructure.EventSourcing.Consume;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.States;
using Squidex.Infrastructure.TestHelpers;
using Squidex.MongoDb.TestHelpers;
#pragma warning disable MA0040 // Forward the CancellationToken parameter to methods that take one

15
backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/EventSourcing/MongoEventStoreFixture.cs

@ -8,8 +8,8 @@
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Squidex.Events.Mongo;
using Squidex.Infrastructure;
using Squidex.Infrastructure.TestHelpers;
using Squidex.MongoDb.TestHelpers;
#pragma warning disable MA0048 // File name must match type name
@ -37,11 +37,6 @@ public abstract class MongoEventStoreFixture : IAsyncLifetime
public IMongoDatabase Database { get; }
static MongoEventStoreFixture()
{
BsonJsonConvention.Register(TestUtils.DefaultOptions());
}
protected MongoEventStoreFixture(string connectionString)
{
var mongoClient = MongoClientFactory.Create(connectionString);
@ -52,13 +47,13 @@ public abstract class MongoEventStoreFixture : IAsyncLifetime
EventStore = new MongoEventStore(mongoDatabase, Options.Create(new MongoEventStoreOptions()));
}
public Task InitializeAsync()
public async ValueTask InitializeAsync()
{
return EventStore.InitializeAsync(default);
await EventStore.InitializeAsync(default);
}
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
}

5
backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/NamedIdTests.cs

@ -12,11 +12,6 @@ namespace Squidex.MongoDb.Infrastructure;
public class NamedIdTests
{
static NamedIdTests()
{
MongoTestUtils.SetupBson();
}
[Fact]
public void Should_serialize_and_deserialize_null_guid_token()
{

5
backend/tests/Squidex.Data.Tests/MongoDb/Infrastructure/Queries/MongoQueryTests.cs

@ -33,11 +33,6 @@ public class MongoQueryTests
public long Version { get; set; }
}
static MongoQueryTests()
{
MongoTestUtils.SetupBson();
}
[Fact]
public void Should_not_throw_exception_for_invalid_field()
{

2
backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/DocumentDbFixture.cs

@ -28,8 +28,6 @@ public class DocumentDbFixture
public DocumentDbFixture()
{
MongoTestUtils.SetupBson();
var settings = MongoClientSettings.FromConnectionString(
TestConfig.Configuration.GetValue<string>("documentDb:configuration")
);

15
backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoFixture.cs

@ -30,20 +30,15 @@ public class MongoFixture : IAsyncLifetime
public IMongoDatabase Database => Client.GetDatabase("Test");
public MongoFixture()
public async ValueTask InitializeAsync()
{
MongoTestUtils.SetupBson();
}
public async Task InitializeAsync()
{
await mongoDb.StartAsync();
await mongoDb.StartAsync(TestContext.Current.CancellationToken);
Client = new MongoClient(mongoDb.GetConnectionString());
Client = MongoClientFactory.Create(mongoDb.GetConnectionString());
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await mongoDb.StopAsync();
await mongoDb.StopAsync(TestContext.Current.CancellationToken);
}
}

26
backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoSerializerFixture.cs

@ -0,0 +1,26 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using MongoDB.Bson;
using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.MongoDb.TestHelpers;
[assembly: AssemblyFixture(typeof(MongoSerializerFixture))]
namespace Squidex.MongoDb.TestHelpers;
internal sealed class MongoSerializerFixture : IDisposable
{
public MongoSerializerFixture()
{
MongoClientFactory.SetupSerializer(TestUtils.DefaultOptions(), BsonType.String);
}
public void Dispose()
{
}
}

19
backend/tests/Squidex.Data.Tests/MongoDb/TestHelpers/MongoTestUtils.cs

@ -9,10 +9,7 @@ using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.MongoDb.TestHelpers;
@ -27,22 +24,6 @@ public static class MongoTestUtils
public T Value2 { get; set; }
}
static MongoTestUtils()
{
SetupBson();
}
public static void SetupBson()
{
BsonDefaultConventions.Register();
BsonDomainIdSerializer.Register();
BsonEscapedDictionarySerializer<JsonValue, JsonObject>.Register();
BsonInstantSerializer.Register();
BsonJsonConvention.Register(TestUtils.DefaultOptions());
BsonJsonValueSerializer.Register();
BsonStringSerializer<RefToken>.Register();
}
public static T SerializeAndDeserializeBson<T>(this T value)
{
return value.SerializeAndDeserializeBson<T, T>();

2
backend/tests/Squidex.Data.Tests/Shared/AssetFolderRepositoryTests.cs

@ -97,7 +97,7 @@ public abstract class AssetFolderRepositoryTests : GivenContext
public static readonly TheoryData<DomainId?> ParentIds = new TheoryData<DomainId?>
{
{ null },
{ null as DomainId? },
{ DomainId.Empty },
};

2
backend/tests/Squidex.Data.Tests/Shared/AssetRepositoryTests.cs

@ -123,7 +123,7 @@ public abstract class AssetRepositoryTests : GivenContext
public static readonly TheoryData<DomainId?> ParentIds = new TheoryData<DomainId?>
{
{ null },
{ null as DomainId? },
{ DomainId.Empty },
};

2
backend/tests/Squidex.Data.Tests/Squidex.Data.Tests.csproj

@ -41,7 +41,7 @@
<PackageReference Include="Testcontainers.MsSql" Version="4.11.0" />
<PackageReference Include="Testcontainers.MySql" Version="4.11.0" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.11.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

26
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/ExpressionsAttribute.cs

@ -7,37 +7,41 @@
using System.Reflection;
using Xunit.Sdk;
using Xunit.v3;
namespace Squidex.Domain.Apps.Core.Operations.HandleRules;
public sealed class ExpressionsAttribute(string? interpolationOld, string? interpolationNew, string? script, string? liquid) : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
public override ValueTask<IReadOnlyCollection<ITheoryDataRow>> GetData(MethodInfo testMethod, DisposalTracker disposalTracker)
{
var rows = new List<ITheoryDataRow>();
if (interpolationOld != null)
{
yield return new object[] { interpolationOld };
rows.Add(new TheoryDataRow(interpolationOld));
}
if (interpolationNew != null)
{
yield return new object[] { interpolationNew };
rows.Add(new TheoryDataRow(interpolationNew));
}
if (script != null)
{
yield return new object[]
{
$"Script(`{script}`)",
};
rows.Add(new TheoryDataRow($"Script(`{script}`)"));
}
if (liquid != null)
{
yield return new object[]
{
$"Liquid({liquid})",
};
rows.Add(new TheoryDataRow($"Liquid({liquid})"));
}
return new ValueTask<IReadOnlyCollection<ITheoryDataRow>>(rows);
}
public override bool SupportsDiscoveryEnumeration()
{
return true;
}
}

2
backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj

@ -30,7 +30,7 @@
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.3.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.6.2" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTest.cs → backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTests.cs

@ -16,7 +16,7 @@ using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Billing;
public class UsageNotifierWorkerTest : GivenContext
public class UsageNotifierWorkerTests : GivenContext
{
private readonly TestState<UsageNotifierWorker.State> state = new TestState<UsageNotifierWorker.State>("Default");
private readonly IClock clock = A.Fake<IClock>();
@ -25,7 +25,7 @@ public class UsageNotifierWorkerTest : GivenContext
private readonly UsageNotifierWorker sut;
private Instant time = SystemClock.Instance.GetCurrentInstant();
public UsageNotifierWorkerTest()
public UsageNotifierWorkerTests()
{
A.CallTo(() => clock.GetCurrentInstant())
.ReturnsLazily(() => time);

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AzureTextIndexFixture.cs

@ -22,13 +22,13 @@ public sealed class AzureTextIndexFixture : IAsyncLifetime
TestConfig.Configuration["azureText:indexName"]!);
}
public Task InitializeAsync()
public async ValueTask InitializeAsync()
{
return Index.InitializeAsync(default);
await Index.InitializeAsync(default);
}
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
}

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/ElasticSearchTextIndexFixture.cs

@ -22,9 +22,9 @@ public sealed class ElasticSearchTextIndexFixture : IAsyncLifetime
public ElasticSearchTextIndex Index { get; private set; }
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await elastic.StopAsync();
await elastic.StartAsync(TestContext.Current.CancellationToken);
Index = new ElasticSearchTextIndex(
new ElasticSearchClient(elastic.GetConnectionString()),
@ -34,8 +34,8 @@ public sealed class ElasticSearchTextIndexFixture : IAsyncLifetime
await Index.InitializeAsync(default);
}
public Task DisposeAsync()
public async ValueTask DisposeAsync()
{
return Task.CompletedTask;
await elastic.StopAsync(TestContext.Current.CancellationToken);
}
}

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/OpenSearchTextIndexFixture.cs

@ -23,13 +23,13 @@ public sealed class OpenSearchTextIndexFixture : IAsyncLifetime
TestUtils.DefaultSerializer);
}
public Task InitializeAsync()
public async ValueTask InitializeAsync()
{
return Index.InitializeAsync(default);
await Index.InitializeAsync(default);
}
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
}

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj

@ -43,8 +43,8 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Reactive.Linq" Version="6.1.0" />
<PackageReference Include="System.ValueTuple" Version="4.6.2" />
<PackageReference Include="Verify.Xunit" Version="31.12.5" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="Verify.XunitV3" Version="28.12.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

2
backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj

@ -26,7 +26,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.6.2" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

2
backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj

@ -30,7 +30,7 @@
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.3.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.6.2" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

2
backend/tests/Squidex.Infrastructure.Tests/States/PersistenceEventSourcingTests.cs

@ -19,7 +19,7 @@ public class PersistenceEventSourcingTests
private readonly IEventStore eventStore = A.Fake<IEventStore>();
private readonly IEventStreamNames eventStreamNames = A.Fake<IEventStreamNames>();
private readonly ISnapshotStore<string> snapshotStore = A.Fake<ISnapshotStore<string>>();
private readonly IStore<string> sut;
private readonly Store<string> sut;
public PersistenceEventSourcingTests()
{

2
backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj

@ -27,7 +27,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.3.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

22
tools/.editorconfig

@ -27,9 +27,6 @@ dotnet_diagnostic.IDE0305.severity = none
# CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none
# CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA1861.severity = none
# CA2016: Forward the 'CancellationToken' parameter to methods
dotnet_diagnostic.CA2016.severity = none
@ -187,4 +184,21 @@ dotnet_diagnostic.SA1623.severity = none
dotnet_diagnostic.SYSLIB1045.severity = none
# xUnit1033: Test classes decorated with 'Xunit.IClassFixture<TFixture>' or 'Xunit.ICollectionFixture<TFixture>' should add a constructor argument of type TFixture
dotnet_diagnostic.xUnit1033.severity = none
dotnet_diagnostic.xUnit1033.severity = none
# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken
dotnet_diagnostic.xUnit1051.severity = none
[*Tests*.cs]
# MA0040: Forward the CancellationToken parameter to methods that take one
dotnet_diagnostic.MA0040.severity = none
# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken
dotnet_diagnostic.xUnit1051.severity = none
# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = none
[*Fixture.cs]
# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = none

10
tools/TestSuite/TestSuite.ApiTests/ContentQueryFixture.cs

@ -20,7 +20,7 @@ public sealed class ContentQueryFixture : TestSchemaFixtureBase
{
}
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();
@ -50,19 +50,19 @@ public sealed class ContentQueryFixture : TestSchemaFixtureBase
String = index.ToString(CultureInfo.InvariantCulture),
};
await Contents.CreateAsync(data, ContentCreateOptions.AsPublish);
await Contents.CreateAsync(data, ContentCreateOptions.AsPublish, ct: TestContext.Current.CancellationToken);
}
}
public override async Task DisposeAsync()
public override async ValueTask DisposeAsync()
{
await base.DisposeAsync();
var contents = await Contents.GetAsync();
var contents = await Contents.GetAsync(ct: TestContext.Current.CancellationToken);
foreach (var content in contents.Items)
{
await Contents.DeleteAsync(content);
await Contents.DeleteAsync(content, ct: TestContext.Current.CancellationToken);
}
}
}

14
tools/TestSuite/TestSuite.ApiTests/GraphQLFixture.cs

@ -32,7 +32,7 @@ public sealed class GraphQLFixture : ContentFixture
{
}
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();
@ -46,7 +46,7 @@ public sealed class GraphQLFixture : ContentFixture
{
try
{
var response = await Client.Schemas.PostSchemaAsync(request);
var response = await Client.Schemas.PostSchemaAsync(request, TestContext.Current.CancellationToken);
return response.Id;
}
@ -57,7 +57,7 @@ public sealed class GraphQLFixture : ContentFixture
throw;
}
var schema = await Client.Schemas.GetSchemaAsync(request.Name);
var schema = await Client.Schemas.GetSchemaAsync(request.Name, TestContext.Current.CancellationToken);
return schema.Id;
}
@ -174,7 +174,7 @@ public sealed class GraphQLFixture : ContentFixture
private async Task CreateContentsAsync()
{
var countries = await Countries.GetAsync();
var countries = await Countries.GetAsync(ct: TestContext.Current.CancellationToken);
if (countries.Total > 0)
{
@ -212,7 +212,7 @@ public sealed class GraphQLFixture : ContentFixture
},
};
var city = await Cities.CreateAsync(cityData, ContentCreateOptions.AsPublish);
var city = await Cities.CreateAsync(cityData, ContentCreateOptions.AsPublish, ct: TestContext.Current.CancellationToken);
return city.Id;
}
@ -231,7 +231,7 @@ public sealed class GraphQLFixture : ContentFixture
},
};
var state = await States.CreateAsync(stateData, ContentCreateOptions.AsPublish);
var state = await States.CreateAsync(stateData, ContentCreateOptions.AsPublish, ct: TestContext.Current.CancellationToken);
return state.Id;
}
@ -259,6 +259,6 @@ public sealed class GraphQLFixture : ContentFixture
},
};
await Countries.CreateAsync(countryData, ContentCreateOptions.AsPublish);
await Countries.CreateAsync(countryData, ContentCreateOptions.AsPublish, ct: TestContext.Current.CancellationToken);
}
}

4
tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj

@ -19,8 +19,8 @@
<PackageReference Include="Squidex.Assets" Version="8.0.0" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="8.0.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify.Xunit" Version="31.12.5" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="Verify.XunitV3" Version="28.12.0" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

1
tools/TestSuite/TestSuite.LoadTests/ReadingBenchmarks.cs

@ -7,7 +7,6 @@
using TestSuite.Fixtures;
using Xunit;
using Xunit.Abstractions;
#pragma warning disable SA1300 // Element should begin with upper-case letter

4
tools/TestSuite/TestSuite.LoadTests/ReadingFixture.cs

@ -20,7 +20,7 @@ public sealed class ReadingFixture : TestSchemaFixtureBase
{
}
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();
@ -54,7 +54,7 @@ public sealed class ReadingFixture : TestSchemaFixtureBase
}
}
public override async Task DisposeAsync()
public override async ValueTask DisposeAsync()
{
await base.DisposeAsync();

1
tools/TestSuite/TestSuite.LoadTests/Run.cs

@ -8,7 +8,6 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using Xunit;
using Xunit.Abstractions;
namespace TestSuite.LoadTests;

2
tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj

@ -13,7 +13,7 @@
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3" Version="3.2.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

6
tools/TestSuite/TestSuite.Shared/Fixtures/ClientFixture.cs

@ -90,7 +90,7 @@ public class ClientFixture : IAsyncLifetime
return (client, await client.Apps.PostAppAsync(request));
}
public virtual async Task InitializeAsync()
public virtual async ValueTask InitializeAsync()
{
Squidex = await Factories.CreateAsync(nameof(ClientWrapper), async () =>
{
@ -102,8 +102,8 @@ public class ClientFixture : IAsyncLifetime
});
}
public virtual Task DisposeAsync()
public virtual ValueTask DisposeAsync()
{
return Task.CompletedTask;
return default;
}
}

2
tools/TestSuite/TestSuite.Shared/Fixtures/CreatedAppFixture.cs

@ -11,7 +11,7 @@ namespace TestSuite.Fixtures;
public class CreatedAppFixture : ClientFixture
{
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();

2
tools/TestSuite/TestSuite.Shared/Fixtures/CreatedTeamFixture.cs

@ -17,7 +17,7 @@ public class CreatedTeamFixture : ClientFixture
public TeamDto Team { get; private set; }
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();

2
tools/TestSuite/TestSuite.Shared/Fixtures/TestSchemaFixtureBase.cs

@ -16,7 +16,7 @@ public abstract class TestSchemaFixtureBase(string schemaName) : CreatedAppFixtu
public string SchemaName { get; } = schemaName;
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();

2
tools/TestSuite/TestSuite.Shared/Fixtures/TestSchemaWithReferencesFixtureBase.cs

@ -16,7 +16,7 @@ public abstract class TestSchemaWithReferencesFixtureBase(string schemaName) : C
public string SchemaName { get; } = schemaName;
public override async Task InitializeAsync()
public override async ValueTask InitializeAsync()
{
await base.InitializeAsync();

2
tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

@ -22,7 +22,7 @@
<PackageReference Include="Squidex.ClientLibrary.ServiceExtensions" Version="22.2.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify" Version="31.12.5" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.v3.extensibility.core" Version="3.2.2" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />

Loading…
Cancel
Save