From 93a667a0b080c6d65e9dc4b8f079a5c6699ec03f Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 23 Aug 2022 00:03:38 +0200 Subject: [PATCH] Fix JSON dot. (#911) * Fix JSON dot. * Serializer fix. * Fix queries. --- .../Validators/UniqueValidator.cs | 1 - ...ongoAssetFolderRepository_SnapshotStore.cs | 1 - .../MongoAssetRepository_SnapshotStore.cs | 1 - .../Contents/MongoContentCollection.cs | 1 - .../Contents/MongoContentRepository.cs | 4 + .../Contents/Operations/Adapt.cs | 2 +- .../Contents/Operations/QueryAsStream.cs | 1 - .../Schemas/Commands/CreateSchema.cs | 1 - .../Schemas/Commands/SchemaUpdateCommand.cs | 1 - .../BsonEscapedDictionarySerializer.cs | 65 +++++ .../MongoDb/BsonHelper.cs | 12 +- .../MongoDb/BsonJsonConvention.cs | 1 - .../MongoDb/BsonJsonSerializer.cs | 6 +- .../MongoDb/MongoBase.cs | 2 + .../States/MongoSnapshotStoreBase.cs | 1 - .../Json/System/InheritanceConverter.cs | 1 - .../ReadonlyDictionaryConverterFactory.cs | 3 - .../Queries/PropertyPath.cs | 55 +++- .../Controllers/Apps/AppImageController.cs | 1 - backend/src/Squidex/Config/Web/WebServices.cs | 1 - .../Model/Apps/RolesJsonTests.cs | 2 +- .../Model/Contents/WorkflowJsonTests.cs | 2 +- .../Model/Schemas/SchemaTests.cs | 2 +- .../TestHelpers/TestUtils.cs | 34 +-- .../Assets/MongoDb/AssetQueryTests.cs | 10 +- .../Assets/MongoDb/AssetsQueryFixture.cs | 1 - .../Contents/MongoDb/ContentQueryTests.cs | 32 ++- .../Contents/MongoDb/ContentsQueryFixture.cs | 1 - .../Contents/MongoDb/StatusSerializerTests.cs | 4 +- .../Contents/Text/AtlasTextIndexFixture.cs | 5 +- .../Contents/Text/MongoTextIndexFixture.cs | 5 +- .../Schemas/MongoDb/SchemasHashFixture.cs | 4 +- .../DefaultEventFormatterTests.cs | 1 - .../Objects/JsonValuesSerializationTests.cs | 24 +- .../JsonInheritanceConverterBaseTests.cs | 1 - .../MongoDb/DomainIdSerializerTests.cs | 3 +- .../MongoDb/InstantSerializerTests.cs | 2 +- .../MongoDb/MongoQueryTests.cs | 7 +- .../NamedIdTests.cs | 4 +- .../Queries/PropertyPathTests.cs | 102 +++++++ .../TestHelpers/TestUtils.cs | 30 +- .../TestSuite.ApiTests/BackupTests.cs | 5 +- .../TestSuite.ApiTests/ContentCleanupTests.cs | 23 +- .../TestSuite.ApiTests/ContentQueryTests.cs | 49 ++++ .../ContentReferencesTests.cs | 70 +++-- .../ContentScriptingTests.cs | 15 +- ...s.Should_create_json_with_dot.verified.txt | 24 ++ .../TestSuite.ApiTests/ContentUpdateTests.cs | 262 ++++++++++++++---- .../TestSuite.ApiTests/RuleRunnerTests.cs | 5 +- .../TestSuite.LoadTests/WritingBenchmarks.cs | 5 +- 50 files changed, 694 insertions(+), 201 deletions(-) create mode 100644 backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonEscapedDictionarySerializer.cs create mode 100644 backend/tests/Squidex.Infrastructure.Tests/Queries/PropertyPathTests.cs create mode 100644 backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.Should_create_json_with_dot.verified.txt diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs index 097b8e7a8..44004d893 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs @@ -6,7 +6,6 @@ // ========================================================================== using Squidex.Domain.Apps.Core.Contents; -using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Translations; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs index 23eca83ed..0cae620c0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository_SnapshotStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using MongoDB.Bson; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.DomainObject; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs index 5623a8ebe..83f84279f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository_SnapshotStore.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using MongoDB.Bson; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.DomainObject; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs index 51fe183c6..e98f22815 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using MongoDB.Bson; using MongoDB.Driver; using NodaTime; using Squidex.Domain.Apps.Core.Contents; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs index 65c9ffd1b..a6b818e44 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs @@ -16,6 +16,7 @@ using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Hosting; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.Queries; @@ -32,6 +33,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents static MongoContentRepository() { + BsonEscapedDictionarySerializer.Register(); + BsonEscapedDictionarySerializer.Register(); + BsonEscapedDictionarySerializer.Register(); BsonStringSerializer.Register(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Adapt.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Adapt.cs index ba633ab1b..f629e3b67 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Adapt.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/Adapt.cs @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations for (var i = 1; i < path.Count; i++) { - result[i] = result[i].UnescapeEdmField().JsonEscape(); + result[i] = result[i].UnescapeEdmField().JsonToBsonName().JsonEscape(); } return result; diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs index f3a4cf0ec..09c8042f7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs @@ -7,7 +7,6 @@ using System.Runtime.CompilerServices; using MongoDB.Driver; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Infrastructure; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs index 8f8f1b5c2..490f61fba 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Runtime.Serialization; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs index 07750b37a..d0cb2c6ed 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Commands/SchemaUpdateCommand.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Runtime.Serialization; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Schemas.Commands diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonEscapedDictionarySerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonEscapedDictionarySerializer.cs new file mode 100644 index 000000000..56c70c9d8 --- /dev/null +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonEscapedDictionarySerializer.cs @@ -0,0 +1,65 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; + +namespace Squidex.Infrastructure.MongoDb +{ + public sealed class BsonEscapedDictionarySerializer : ClassSerializerBase where TInstance : Dictionary, new() + { + public static void Register() + { + try + { + BsonSerializer.RegisterSerializer(new BsonEscapedDictionarySerializer()); + } + catch (BsonSerializationException) + { + return; + } + } + + protected override TInstance DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) + { + var reader = context.Reader; + + var result = new TInstance(); + + reader.ReadStartDocument(); + + while (reader.ReadBsonType() != BsonType.EndOfDocument) + { + var key = reader.ReadName().BsonToJsonName(); + + result.Add(key, BsonSerializer.Deserialize(reader)); + } + + reader.ReadEndDocument(); + + return result; + } + + protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, TInstance value) + { + var writer = context.Writer; + + writer.WriteStartDocument(); + + foreach (var property in value) + { + writer.WriteName(property.Key.JsonToBsonName()); + + BsonSerializer.Serialize(writer, property.Value); + } + + writer.WriteEndDocument(); + } + } +} diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonHelper.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonHelper.cs index 49e740f0a..b70980787 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonHelper.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonHelper.cs @@ -12,10 +12,10 @@ namespace Squidex.Infrastructure.MongoDb private const string Empty = "§empty"; private const string TypeBson = "§type"; private const string TypeJson = "$type"; - private const string DotSource = "."; - private const string DotReplacement = "_§§_"; + private const string DotBson = "_§§_"; + private const string DotJson = "."; - public static string UnescapeBson(this string value) + public static string BsonToJsonName(this string value) { if (value == Empty) { @@ -27,12 +27,12 @@ namespace Squidex.Infrastructure.MongoDb return TypeJson; } - var result = value.ReplaceFirst('§', '$').Replace(DotReplacement, DotSource, StringComparison.Ordinal); + var result = value.ReplaceFirst('§', '$').Replace(DotBson, DotJson, StringComparison.Ordinal); return result; } - public static string EscapeJson(this string value) + public static string JsonToBsonName(this string value) { if (value.Length == 0) { @@ -44,7 +44,7 @@ namespace Squidex.Infrastructure.MongoDb return TypeBson; } - var result = value.ReplaceFirst('$', '§').Replace(DotSource, DotReplacement, StringComparison.Ordinal); + var result = value.ReplaceFirst('$', '§').Replace(DotJson, DotBson, StringComparison.Ordinal); return result; } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs index febbd8f36..20f24058d 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs @@ -6,7 +6,6 @@ // ========================================================================== using System.Reflection; -using System.Reflection.Metadata; using System.Text.Json; using MongoDB.Bson; using MongoDB.Bson.Serialization; diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonSerializer.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonSerializer.cs index cdef91618..532393c4f 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonSerializer.cs @@ -14,7 +14,7 @@ using Squidex.Infrastructure.ObjectPool; namespace Squidex.Infrastructure.MongoDb { - public sealed class BsonJsonSerializer : ClassSerializerBase, IRepresentationConfigurable> where T : class + public sealed class BsonJsonSerializer : SerializerBase, IRepresentationConfigurable> where T : class { public BsonType Representation { get; } @@ -134,7 +134,7 @@ namespace Squidex.Infrastructure.MongoDb Read(); break; case BsonReaderState.Name: - writer.WritePropertyName(reader.ReadName().UnescapeBson()); + writer.WritePropertyName(reader.ReadName().BsonToJsonName()); Read(); break; case BsonReaderState.Value: @@ -247,7 +247,7 @@ namespace Squidex.Infrastructure.MongoDb foreach (var property in element.EnumerateObject()) { - writer.WriteName(property.Name.EscapeJson()); + writer.WriteName(property.Name.JsonToBsonName()); WriteElement(writer, property.Value); } diff --git a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoBase.cs b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoBase.cs index ec58c7f48..1d9c48f21 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoBase.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoBase.cs @@ -7,6 +7,7 @@ using MongoDB.Bson; using MongoDB.Driver; +using Squidex.Infrastructure.Json.Objects; #pragma warning disable RECS0108 // Warns about static fields in generic types @@ -48,6 +49,7 @@ namespace Squidex.Infrastructure.MongoDb { BsonDefaultConventions.Register(); BsonDomainIdSerializer.Register(); + BsonEscapedDictionarySerializer.Register(); BsonInstantSerializer.Register(); BsonJsonConvention.Register(); BsonJsonValueSerializer.Register(); diff --git a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStoreBase.cs b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStoreBase.cs index 0ed74f32c..55062cac3 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStoreBase.cs +++ b/backend/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStoreBase.cs @@ -6,7 +6,6 @@ // ========================================================================== using System.Runtime.CompilerServices; -using MongoDB.Bson; using MongoDB.Driver; using Squidex.Infrastructure.MongoDb; diff --git a/backend/src/Squidex.Infrastructure/Json/System/InheritanceConverter.cs b/backend/src/Squidex.Infrastructure/Json/System/InheritanceConverter.cs index be34bec72..dedb1b511 100644 --- a/backend/src/Squidex.Infrastructure/Json/System/InheritanceConverter.cs +++ b/backend/src/Squidex.Infrastructure/Json/System/InheritanceConverter.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Text.Json; using Squidex.Infrastructure.Reflection; namespace Squidex.Infrastructure.Json.System diff --git a/backend/src/Squidex.Infrastructure/Json/System/ReadonlyDictionaryConverterFactory.cs b/backend/src/Squidex.Infrastructure/Json/System/ReadonlyDictionaryConverterFactory.cs index 29d65e411..bf8ff255d 100644 --- a/backend/src/Squidex.Infrastructure/Json/System/ReadonlyDictionaryConverterFactory.cs +++ b/backend/src/Squidex.Infrastructure/Json/System/ReadonlyDictionaryConverterFactory.cs @@ -5,9 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; using System.Text.Json; using System.Text.Json.Serialization; using Squidex.Infrastructure.Collections; diff --git a/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs b/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs index b5e1070b0..3562c06f6 100644 --- a/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs +++ b/backend/src/Squidex.Infrastructure/Queries/PropertyPath.cs @@ -24,7 +24,53 @@ namespace Squidex.Infrastructure.Queries public static implicit operator PropertyPath(string path) { - return Create(path?.Split(Separators, StringSplitOptions.RemoveEmptyEntries).ToList()); + var result = new List(); + + var currentPath = path.AsSpan(); + var currentPosition = 0; + + void Add(ReadOnlySpan value) + { + var property = value.Trim(Separators).ToString(); + + if (property.Length == 0) + { + return; + } + + property = property.Replace("\\/", "/", StringComparison.OrdinalIgnoreCase); + property = property.Replace("\\.", ".", StringComparison.OrdinalIgnoreCase); + + result.Add(property); + } + + while (true) + { + var nextDot = currentPath[currentPosition..].IndexOfAny(Separators) + currentPosition; + + if (nextDot < currentPosition) + { + Add(currentPath); + break; + } + else if (nextDot == currentPosition) + { + currentPath = currentPath[1..]; + } + else if (currentPath[nextDot - 1] == '\\') + { + currentPosition = nextDot + 1; + } + else + { + Add(currentPath[..nextDot]); + + currentPath = currentPath[nextDot..].Trim(Separators); + currentPosition = 0; + } + } + + return Create(result); } public static implicit operator PropertyPath(string[] path) @@ -42,6 +88,13 @@ namespace Squidex.Infrastructure.Queries return string.Join(".", this); } + private static string Unescape(string source) + { + return source + .Replace("\\/", "/", StringComparison.OrdinalIgnoreCase) + .Replace("\\.", ".", StringComparison.OrdinalIgnoreCase); + } + private static PropertyPath Create(IEnumerable? source) { var inner = source?.ToList(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs index f7df40861..4faf0a48a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; using Squidex.Assets; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; diff --git a/backend/src/Squidex/Config/Web/WebServices.cs b/backend/src/Squidex/Config/Web/WebServices.cs index 97b83b5b4..4f39e35dd 100644 --- a/backend/src/Squidex/Config/Web/WebServices.cs +++ b/backend/src/Squidex/Config/Web/WebServices.cs @@ -8,7 +8,6 @@ using GraphQL; using GraphQL.DataLoader; using GraphQL.DI; -using GraphQL.Execution; using GraphQL.MicrosoftDI; using GraphQL.Server.Transports.AspNetCore; using GraphQL.SystemTextJson; diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs index 78231b9b7..5c07b5572 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/RolesJsonTests.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Core.Model.Apps "Permission1", "Permission2")); - var roles = source.SerializeAndDeserialize(); + var roles = source.SerializeAndDeserialize>(); roles.Should().BeEquivalentTo(expected); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs index f7d42a8d7..3815f0361 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs @@ -53,7 +53,7 @@ namespace Squidex.Domain.Apps.Core.Model.Contents { var jsonStep = new { noUpdate = true }; - var serialized = jsonStep.SerializeAndDeserialize(); + var serialized = jsonStep.SerializeAndDeserialize(); Assert.Equal(new WorkflowStep(null, null, NoUpdate.Always), serialized); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs index 39b15bab1..775265217 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/SchemaTests.cs @@ -487,7 +487,7 @@ namespace Squidex.Domain.Apps.Core.Model.Schemas new Schema("my-schema", type: SchemaType.Singleton) .Publish(); - var schemaTarget = schemaSource.SerializeAndDeserialize(); + var schemaTarget = schemaSource.SerializeAndDeserialize(); schemaTarget.Should().BeEquivalentTo(expected); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs index 0e4b99d00..6929bb286 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs @@ -59,9 +59,15 @@ namespace Squidex.Domain.Apps.Core.TestHelpers public static void SetupBson() { BsonDomainIdSerializer.Register(); + BsonEscapedDictionarySerializer.Register(); + BsonEscapedDictionarySerializer.Register(); + BsonEscapedDictionarySerializer.Register(); + BsonEscapedDictionarySerializer.Register(); BsonInstantSerializer.Register(); BsonJsonConvention.Register(DefaultOptions()); BsonJsonValueSerializer.Register(); + BsonStringSerializer.Register(); + BsonStringSerializer.Register(); } public static IJsonSerializer CreateSerializer(Action? configure = null) @@ -131,34 +137,37 @@ namespace Squidex.Domain.Apps.Core.TestHelpers } public static T SerializeAndDeserializeBson(this T value) + { + return SerializeAndDeserializeBson(value); + } + + public static TOut SerializeAndDeserializeBson(this TIn value) { using var stream = new MemoryStream(); using (var writer = new BsonBinaryWriter(stream)) { - BsonSerializer.Serialize(writer, new ObjectHolder { Value1 = value, Value2 = value }); + BsonSerializer.Serialize(writer, new ObjectHolder { Value1 = value, Value2 = value }); } stream.Position = 0; using (var reader = new BsonBinaryReader(stream)) { - return BsonSerializer.Deserialize>(reader).Value1; + return BsonSerializer.Deserialize>(reader).Value1; } } - public static T SerializeAndDeserialize(this object value) + public static T SerializeAndDeserialize(this T value) { - var json = DefaultSerializer.Serialize(value); - - return DefaultSerializer.Deserialize(json); + return SerializeAndDeserialize(value); } - public static T SerializeAndDeserialize(this T value) + public static TOut SerializeAndDeserialize(this TIn value) { - var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); + var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); - return DefaultSerializer.Deserialize>(json).Value1; + return DefaultSerializer.Deserialize>(json).Value1; } public static T Deserialize(string value) @@ -168,13 +177,6 @@ namespace Squidex.Domain.Apps.Core.TestHelpers return DefaultSerializer.Deserialize>(json).Value1; } - public static T Deserialize(object value) - { - var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); - - return DefaultSerializer.Deserialize>(json).Value1; - } - public static string CleanJson(this string json) { using var document = JsonDocument.Parse(json); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetQueryTests.cs index bebf3f9b0..d08bd7eb4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetQueryTests.cs @@ -9,11 +9,10 @@ using FakeItEasy; using MongoDB.Bson.Serialization; using MongoDB.Driver; using NodaTime.Text; -using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.MongoDb.Assets; using Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors; using Squidex.Infrastructure; -using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Validation; @@ -29,12 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb static AssetQueryTests() { - BsonDomainIdSerializer.Register(); - - BsonStringSerializer.Register(); - BsonStringSerializer.Register(); - - BsonInstantSerializer.Register(); + TestUtils.SetupBson(); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs index b0cda90de..00270295e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs @@ -8,7 +8,6 @@ using System.Globalization; using MongoDB.Bson; using MongoDB.Driver; -using Newtonsoft.Json; using NodaTime; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.TestHelpers; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentQueryTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentQueryTests.cs index 70301b2ec..ac1b5b1a4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentQueryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentQueryTests.cs @@ -11,14 +11,13 @@ using MongoDB.Driver; using NodaTime.Text; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; -using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.MongoDb.Contents; using Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; -using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.Queries; using Xunit; @@ -35,12 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb static ContentQueryTests() { - BsonDomainIdSerializer.Register(); - - BsonStringSerializer.Register(); - BsonStringSerializer.Register(); - - BsonInstantSerializer.Register(); + TestUtils.SetupBson(); } public ContentQueryTests() @@ -63,8 +57,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb new ReferencesFieldProperties()) .AddString(8, "dashed-field", Partitioning.Invariant, new StringFieldProperties()) - .AddArray(9, "hobbies", Partitioning.Invariant, a => a - .AddString(91, "name")) + .AddJson(9, "json", Partitioning.Invariant, + new JsonFieldProperties()) + .AddArray(10, "hobbies", Partitioning.Invariant, a => a + .AddString(101, "name")) .Update(new SchemaProperties()); var schema = A.Dummy(); @@ -180,6 +176,22 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb AssertQuery("{ 'do.dashed-field.iv' : 'Value' }", filter); } + [Fact] + public void Should_make_query_with_json_dot_field() + { + var filter = ClrFilter.Eq("data/json/iv/with\\.dot", "Value"); + + AssertQuery("{ 'do.json.iv.with_§§_dot' : 'Value' }", filter); + } + + [Fact] + public void Should_make_query_with_json_slash_field() + { + var filter = ClrFilter.Eq("data/json/iv/with\\/slash", "Value"); + + AssertQuery("{ 'do.json.iv.with/slash' : 'Value' }", filter); + } + [Fact] public void Should_make_query_with_references_equals() { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs index 33b29ea79..8b3e261cb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs @@ -11,7 +11,6 @@ using LoremNET; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; -using Newtonsoft.Json; using NodaTime; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/StatusSerializerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/StatusSerializerTests.cs index 4a9e8d4e2..32eb8bf84 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/StatusSerializerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/StatusSerializerTests.cs @@ -8,7 +8,7 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Infrastructure.MongoDb; +using Squidex.Domain.Apps.Core.TestHelpers; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.MongoDb @@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb public StatusSerializerTests() { - BsonStringSerializer.Register(); + TestUtils.SetupBson(); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AtlasTextIndexFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AtlasTextIndexFixture.cs index 52450ee9f..ad75084cf 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AtlasTextIndexFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/AtlasTextIndexFixture.cs @@ -11,7 +11,6 @@ using MongoDB.Driver; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.MongoDb.Text; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure.MongoDb; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.Text @@ -22,9 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text public AtlasTextIndexFixture() { - BsonJsonConvention.Register(TestUtils.DefaultOptions()); - - BsonDomainIdSerializer.Register(); + TestUtils.SetupBson(); var mongoClient = new MongoClient(TestConfig.Configuration["atlas:configuration"]); var mongoDatabase = mongoClient.GetDatabase(TestConfig.Configuration["atlas:database"]); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexFixture.cs index 7e5611f64..36297ab75 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/MongoTextIndexFixture.cs @@ -9,7 +9,6 @@ using MongoDB.Driver; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.MongoDb.Text; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure.MongoDb; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.Text @@ -20,9 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text public MongoTextIndexFixture() { - BsonJsonConvention.Register(TestUtils.DefaultOptions()); - - BsonDomainIdSerializer.Register(); + TestUtils.SetupBson(); var mongoClient = new MongoClient(TestConfig.Configuration["mongodb:configuration"]); var mongoDatabase = mongoClient.GetDatabase(TestConfig.Configuration["mongodb:database"]); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/MongoDb/SchemasHashFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/MongoDb/SchemasHashFixture.cs index fd95465dc..035fcfddb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/MongoDb/SchemasHashFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/MongoDb/SchemasHashFixture.cs @@ -6,9 +6,9 @@ // ========================================================================== using MongoDB.Driver; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.MongoDb.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.Schemas.MongoDb { @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.MongoDb public SchemasHashFixture() { - BsonInstantSerializer.Register(); + TestUtils.SetupBson(); var mongoClient = new MongoClient(TestConfig.Configuration["mongodb:configuration"]); var mongoDatabase = mongoClient.GetDatabase(TestConfig.Configuration["mongodb:database"]); diff --git a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventFormatterTests.cs b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventFormatterTests.cs index 6324d70e0..c1e401ec9 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventFormatterTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventFormatterTests.cs @@ -6,7 +6,6 @@ // ========================================================================== using NodaTime; -using Squidex.Infrastructure.Json.System; using Squidex.Infrastructure.Migrations; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.TestHelpers; diff --git a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs index a3136d4a2..5350544d0 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Json/Objects/JsonValuesSerializationTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.TestHelpers; using Xunit; @@ -39,9 +40,11 @@ namespace Squidex.Infrastructure.Json.Objects [Fact] public void Should_deserialize_integer() { - var serialized = TestUtils.Deserialize(123); + var value = 123; - Assert.Equal(JsonValue.Create(123), serialized); + var serialized = value.SerializeAndDeserialize(); + + Assert.Equal(JsonValue.Create(value), serialized); } [Theory] @@ -152,5 +155,22 @@ namespace Squidex.Infrastructure.Json.Objects Assert.Equal(value, serialized); } + + [Fact] + public void Should_deserialize_from_escaped_dot() + { + var value = new Dictionary + { + ["key.with.dot".JsonToBsonName()] = 10 + }; + + var expected = + new JsonObject() + .Add("key.with.dot", 10); + + var serialized = TestUtils.SerializeAndDeserializeBson>(value); + + Assert.Equal(expected, serialized); + } } } diff --git a/backend/tests/Squidex.Infrastructure.Tests/Json/System/JsonInheritanceConverterBaseTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Json/System/JsonInheritanceConverterBaseTests.cs index 5e53d6b16..b2ca32bc8 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Json/System/JsonInheritanceConverterBaseTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/Json/System/JsonInheritanceConverterBaseTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.TestHelpers; using Xunit; diff --git a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs index ca66777eb..44739ed57 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/DomainIdSerializerTests.cs @@ -9,6 +9,7 @@ using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; +using Squidex.Infrastructure.TestHelpers; using Xunit; namespace Squidex.Infrastructure.MongoDb @@ -28,7 +29,7 @@ namespace Squidex.Infrastructure.MongoDb public DomainIdSerializerTests() { - BsonDomainIdSerializer.Register(); + TestUtils.SetupBson(); } [Fact] diff --git a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/InstantSerializerTests.cs b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/InstantSerializerTests.cs index c1a3befb0..6ab4cdcd8 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/InstantSerializerTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/InstantSerializerTests.cs @@ -15,7 +15,7 @@ namespace Squidex.Infrastructure.MongoDb { public InstantSerializerTests() { - BsonInstantSerializer.Register(); + TestUtils.SetupBson(); } [Fact] diff --git a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/MongoQueryTests.cs b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/MongoQueryTests.cs index 42da581f0..5e7ab2697 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/MongoDb/MongoQueryTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/MongoDb/MongoQueryTests.cs @@ -12,6 +12,7 @@ using NodaTime; using NodaTime.Text; using Squidex.Infrastructure.MongoDb.Queries; using Squidex.Infrastructure.Queries; +using Squidex.Infrastructure.TestHelpers; using Xunit; using ClrFilter = Squidex.Infrastructure.Queries.ClrFilter; using SortBuilder = Squidex.Infrastructure.Queries.SortBuilder; @@ -35,11 +36,7 @@ namespace Squidex.Infrastructure.MongoDb static MongoQueryTests() { - BsonDomainIdSerializer.Register(); - - BsonStringSerializer.Register(); - - BsonInstantSerializer.Register(); + TestUtils.SetupBson(); } [Fact] diff --git a/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs b/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs index 0d1e716cb..d82c22306 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/NamedIdTests.cs @@ -126,7 +126,7 @@ namespace Squidex.Infrastructure { var value = new { id = 42L, name = "my-name" }; - var serialized = value.SerializeAndDeserialize>(); + var serialized = value.SerializeAndDeserialize, object>(); Assert.Equal(NamedId.Of(42L, "my-name"), serialized); } @@ -144,7 +144,7 @@ namespace Squidex.Infrastructure Value = NamedId.Of(42L, "my-name") }; - var serialized = value.SerializeAndDeserialize(); + var serialized = value.SerializeAndDeserialize(); Assert.Equal(expected, serialized); } diff --git a/backend/tests/Squidex.Infrastructure.Tests/Queries/PropertyPathTests.cs b/backend/tests/Squidex.Infrastructure.Tests/Queries/PropertyPathTests.cs new file mode 100644 index 000000000..a3900bee3 --- /dev/null +++ b/backend/tests/Squidex.Infrastructure.Tests/Queries/PropertyPathTests.cs @@ -0,0 +1,102 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Xunit; + +namespace Squidex.Infrastructure.Queries +{ + public class PropertyPathTests + { + [Fact] + public void Should_create() + { + var path = new PropertyPath(new[] { "path", "to", "property" }); + + Assert.Equal(new[] { "path", "to", "property" }, path.ToArray()); + } + + [Fact] + public void Should_convert_to_string() + { + var path = new PropertyPath(new[] { "path", "to", "property" }); + + Assert.Equal("path.to.property", path.ToString()); + } + + [Fact] + public void Should_throw_exception_for_empty_path() + { + Assert.Throws(() => new PropertyPath(Array.Empty())); + } + + [Fact] + public void Should_throw_exception_for_empty_path_from_string() + { + Assert.Throws(() => { PropertyPath p = string.Empty; }); + } + + [Fact] + public void Should_throw_exception_for_empty_path_from_null_string() + { + Assert.Throws(() => { PropertyPath p = (string)null!; }); + } + + [Fact] + public void Should_throw_exception_for_empty_path_from_list() + { + Assert.Throws(() => { PropertyPath p = new List(); }); + } + + [Fact] + public void Should_create_from_dot_string() + { + PropertyPath path = "path.to.property"; + + Assert.Equal(new[] { "path", "to", "property" }, path.ToArray()); + } + + [Fact] + public void Should_create_from_broken_dot_string() + { + PropertyPath path = ".path...to...property."; + + Assert.Equal(new[] { "path", "to", "property" }, path.ToArray()); + } + + [Fact] + public void Should_create_from_slash_string() + { + PropertyPath path = "path/to/property"; + + Assert.Equal(new[] { "path", "to", "property" }, path.ToArray()); + } + + [Fact] + public void Should_create_from_broken_slash_string() + { + PropertyPath path = "/path///to///property/"; + + Assert.Equal(new[] { "path", "to", "property" }, path.ToArray()); + } + + [Fact] + public void Should_create_from_dot_string_and_escape() + { + PropertyPath path = "path.to.complex\\.property"; + + Assert.Equal(new[] { "path", "to", "complex.property" }, path.ToArray()); + } + + [Fact] + public void Should_create_from_slash_string_and_escape() + { + PropertyPath path = "path.to.complex\\/property"; + + Assert.Equal(new[] { "path", "to", "complex/property" }, path.ToArray()); + } + } +} diff --git a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs index a8919d1d3..6e6adf4c7 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestUtils.cs @@ -46,9 +46,11 @@ namespace Squidex.Infrastructure.TestHelpers public static void SetupBson() { BsonDomainIdSerializer.Register(); + BsonEscapedDictionarySerializer.Register(); BsonInstantSerializer.Register(); BsonJsonConvention.Register(DefaultOptions()); BsonJsonValueSerializer.Register(); + BsonStringSerializer.Register(); } public static IJsonSerializer CreateSerializer(Action? configure = null) @@ -99,34 +101,37 @@ namespace Squidex.Infrastructure.TestHelpers } public static T SerializeAndDeserializeBson(this T value) + { + return SerializeAndDeserializeBson(value); + } + + public static TOut SerializeAndDeserializeBson(this TIn value) { using var stream = new MemoryStream(); using (var writer = new BsonBinaryWriter(stream)) { - BsonSerializer.Serialize(writer, new ObjectHolder { Value1 = value, Value2 = value }); + BsonSerializer.Serialize(writer, new ObjectHolder { Value1 = value, Value2 = value }); } stream.Position = 0; using (var reader = new BsonBinaryReader(stream)) { - return BsonSerializer.Deserialize>(reader).Value1; + return BsonSerializer.Deserialize>(reader).Value1; } } - public static T SerializeAndDeserialize(this object value) + public static T SerializeAndDeserialize(this T value) { - var json = DefaultSerializer.Serialize(value); - - return DefaultSerializer.Deserialize(json); + return SerializeAndDeserialize(value); } - public static T SerializeAndDeserialize(this T value) + public static TOut SerializeAndDeserialize(this TIn value) { - var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); + var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); - return DefaultSerializer.Deserialize>(json).Value1; + return DefaultSerializer.Deserialize>(json).Value1; } public static T Deserialize(string value) @@ -136,13 +141,6 @@ namespace Squidex.Infrastructure.TestHelpers return DefaultSerializer.Deserialize>(json).Value1; } - public static T Deserialize(object value) - { - var json = DefaultSerializer.Serialize(new ObjectHolder { Value1 = value, Value2 = value }); - - return DefaultSerializer.Deserialize>(json).Value1; - } - public static string CleanJson(this string json) { using var document = JsonDocument.Parse(json); diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/BackupTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/BackupTests.cs index fea0b12ec..c57ef199d 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/BackupTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/BackupTests.cs @@ -134,7 +134,10 @@ namespace TestSuite.ApiTests var contents = _.ClientManager.CreateContentsClient(appName, schemaName); - await contents.CreateAsync(new TestEntityData { Number = 1 }); + await contents.CreateAsync(new TestEntityData + { + Number = 1 + }); // Upload a test asset diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentCleanupTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentCleanupTests.cs index 87b6608e2..0327dc736 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentCleanupTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentCleanupTests.cs @@ -35,11 +35,12 @@ namespace TestSuite.ApiTests // STEP 2: Create a content for this schema. - var data = new TestEntityData { Number = 12, String = "hello" }; - - var content_1 = await contents.CreateAsync(data); + var content_1 = await contents.CreateAsync(new TestEntityData + { + String = "hello" + }); - Assert.Equal(data.String, content_1.Data.String); + Assert.Equal("hello", content_1.Data.String); // STEP 3: Delete a field from schema. @@ -66,15 +67,17 @@ namespace TestSuite.ApiTests // STEP 2: Create a referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await contents.CreateAsync(dataA); + var contentA_1 = await contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }); // STEP 3: Create a content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - var contentB_1 = await contents.CreateAsync(dataB); + var contentB_1 = await contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }); // STEP 3: Delete a reference diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs index 05a1138b0..cf0da7875 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs @@ -319,6 +319,55 @@ namespace TestSuite.ApiTests AssertItems(items, 1, new[] { 4 }); } + [Fact] + public async Task Should_query_json_with_dot() + { + TestEntity content = null; + try + { + // STEP 1: Create a content item with a text that caused a bug before. + content = await _.Contents.CreateAsync(new TestEntityData + { + Json = new JObject + { + ["search.field.with.dot"] = 42 + } + }, ContentCreateOptions.AsPublish); + + + // STEP 2: Get the item and ensure that the text is the same. + var q = new ContentQuery + { + JsonQuery = new + { + filter = new + { + and = new[] + { + new + { + path = "data.json.iv.search\\.field\\.with\\.dot", + op = "eq", + value = 42 + } + } + } + } + }; + + var queried = await _.Contents.GetAsync(q); + + Assert.Equal(42, (int)queried.Items[0].Data.Json["search.field.with.dot"]); + } + finally + { + if (content != null) + { + await _.Contents.DeleteAsync(content.Id); + } + } + } + [Fact] public async Task Should_return_items_by_near_geoson_location_with_json() { diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentReferencesTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentReferencesTests.cs index a7ff85015..db0d03151 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentReferencesTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentReferencesTests.cs @@ -26,15 +26,17 @@ namespace TestSuite.ApiTests public async Task Should_not_deliver_unpublished_references() { // STEP 1: Create a referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await _.Contents.CreateAsync(dataA); + var contentA_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }); // STEP 2: Create a content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - var contentB_1 = await _.Contents.CreateAsync(dataB, ContentCreateOptions.AsPublish); + var contentB_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }, ContentCreateOptions.AsPublish); // STEP 3: Query new item @@ -60,15 +62,17 @@ namespace TestSuite.ApiTests public async Task Should_not_delete_when_referenced() { // STEP 1: Create a referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await _.Contents.CreateAsync(dataA, ContentCreateOptions.AsPublish); + var contentA_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }, ContentCreateOptions.AsPublish); // STEP 2: Create a content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - await _.Contents.CreateAsync(dataB, ContentCreateOptions.AsPublish); + await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }, ContentCreateOptions.AsPublish); // STEP 3: Try to delete with referrer check. @@ -88,15 +92,17 @@ namespace TestSuite.ApiTests public async Task Should_not_unpublish_when_referenced() { // STEP 1: Create a published referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await _.Contents.CreateAsync(dataA, ContentCreateOptions.AsPublish); + var contentA_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }, ContentCreateOptions.AsPublish); // STEP 2: Create a content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - await _.Contents.CreateAsync(dataB, ContentCreateOptions.AsPublish); + await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }, ContentCreateOptions.AsPublish); // STEP 3: Try to ThrowsAnyAsync with referrer check. @@ -124,15 +130,17 @@ namespace TestSuite.ApiTests public async Task Should_not_delete_with_bulk_when_referenced() { // STEP 1: Create a referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await _.Contents.CreateAsync(dataA, ContentCreateOptions.AsPublish); + var contentA_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }, ContentCreateOptions.AsPublish); // STEP 2: Create a content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - await _.Contents.CreateAsync(dataB, ContentCreateOptions.AsPublish); + await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }, ContentCreateOptions.AsPublish); // STEP 3: Try to delete with referrer check. @@ -175,15 +183,17 @@ namespace TestSuite.ApiTests public async Task Should_not_unpublish_with_bulk_when_referenced() { // STEP 1: Create a published referenced content. - var dataA = new TestEntityWithReferencesData(); - - var contentA_1 = await _.Contents.CreateAsync(dataA, ContentCreateOptions.AsPublish); + var contentA_1 = await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = null + }, ContentCreateOptions.AsPublish); // STEP 2: Create a published content with a reference. - var dataB = new TestEntityWithReferencesData { References = new[] { contentA_1.Id } }; - - await _.Contents.CreateAsync(dataB, ContentCreateOptions.AsPublish); + await _.Contents.CreateAsync(new TestEntityWithReferencesData + { + References = new[] { contentA_1.Id } + }, ContentCreateOptions.AsPublish); // STEP 3: Try to delete with referrer check. diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentScriptingTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentScriptingTests.cs index f1b3bfa4b..1a3519d9a 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentScriptingTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentScriptingTests.cs @@ -43,7 +43,10 @@ namespace TestSuite.ApiTests // STEP 2: Create content var contents = _.ClientManager.CreateContentsClient(schemaName); - var content = await contents.CreateAsync(new TestEntityData { Number = 13 }); + var content = await contents.CreateAsync(new TestEntityData + { + Number = 13 + }); Assert.Equal(26, content.Data.Number); } @@ -65,7 +68,10 @@ namespace TestSuite.ApiTests // STEP 2: Create content var contents = _.ClientManager.CreateContentsClient(schemaName); - var content = await contents.CreateAsync(new TestEntityData { Number = 13 }, ContentCreateOptions.AsPublish); + var content = await contents.CreateAsync(new TestEntityData + { + Number = 13 + }, ContentCreateOptions.AsPublish); Assert.Equal(26, content.Data.Number); } @@ -89,7 +95,10 @@ namespace TestSuite.ApiTests // STEP 2: Create content var contents = _.ClientManager.CreateContentsClient(schemaName); - var content = await contents.CreateAsync(new TestEntityData { Number = 99 }, ContentCreateOptions.AsPublish); + var content = await contents.CreateAsync(new TestEntityData + { + Number = 99 + }, ContentCreateOptions.AsPublish); Assert.Equal(19, content.Data.Number); } diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.Should_create_json_with_dot.verified.txt b/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.Should_create_json_with_dot.verified.txt new file mode 100644 index 000000000..39c0a7898 --- /dev/null +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.Should_create_json_with_dot.verified.txt @@ -0,0 +1,24 @@ +{ + Data: { + Json: { + iv: null + } + }, + Status: Published, + Id: Guid_1, + Version: 1, + _links: { + delete: { + Method: DELETE + }, + draft/create: { + Method: POST + }, + previous: { + Method: GET + }, + self: { + Method: GET + } + } +} \ No newline at end of file diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs index 72316f040..1d6bf3791 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs @@ -33,7 +33,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create the item unpublished. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }); // STEP 2: Publish the item. @@ -62,7 +65,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create the item published. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, ContentCreateOptions.AsPublish); // STEP 2: Archive the item. @@ -94,7 +100,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create the item unpublished. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }); // STEP 2: Change the status to publiushed and then to draft. @@ -132,15 +141,18 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a content item with a text that caused a bug before. - content = await _.Contents.CreateAsync(new TestEntityData { String = text }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = text + }, ContentCreateOptions.AsPublish); // STEP 2: Get the item and ensure that the text is the same. - var updated = await _.Contents.GetAsync(content.Id); + var queried = await _.Contents.GetAsync(content.Id); - Assert.Equal(text, updated.Data.String); + Assert.Equal(text, queried.Data.String); - await Verify(updated); + await Verify(queried); } finally { @@ -168,11 +180,43 @@ namespace TestSuite.ApiTests // STEP 2: Get the item and ensure that the text is the same. - var updated = await _.Contents.GetAsync(content.Id, QueryContext.Default.IgnoreFallback()); + var queried = await _.Contents.GetAsync(content.Id, QueryContext.Default.IgnoreFallback()); - Assert.Null(updated.Data.Localized["en"]); + Assert.Null(queried.Data.Localized["en"]); - await Verify(updated); + await Verify(queried); + } + finally + { + if (content != null) + { + await _.Contents.DeleteAsync(content.Id); + } + } + } + + [Fact] + public async Task Should_create_json_with_dot() + { + TestEntity content = null; + try + { + // STEP 1: Create a content item with a text that caused a bug before. + content = await _.Contents.CreateAsync(new TestEntityData + { + Json = new JObject + { + ["field.with.dot"] = 42 + } + }, ContentCreateOptions.AsPublish); + + + // STEP 2: Get the item and ensure that the text is the same. + var queried = await _.Contents.GetAsync(content.Id, QueryContext.Default.IgnoreFallback()); + + Assert.Equal(42, (int)queried.Data.Json["field.with.dot"]); + + await Verify(queried); } finally { @@ -217,7 +261,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create the item unpublished. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }); // STEP 2. Get a 404 for the item because it is not published. @@ -244,7 +291,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create the item published. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, ContentCreateOptions.AsPublish); // STEP 2: Get the item. @@ -270,7 +320,10 @@ namespace TestSuite.ApiTests // STEP 1: Create a new item with a custom id. var options = new ContentCreateOptions { Id = id, Publish = true }; - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, options); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, options); Assert.Equal(id, content.Id); } @@ -294,7 +347,10 @@ namespace TestSuite.ApiTests // STEP 1: Create a new item with a custom id. var options = new ContentCreateOptions { Id = id, Publish = true }; - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, options); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, options); Assert.Equal(id, content.Id); @@ -302,7 +358,10 @@ namespace TestSuite.ApiTests // STEP 2: Create a new item with a custom id. var ex = await Assert.ThrowsAnyAsync(() => { - return _.Contents.CreateAsync(new TestEntityData { Number = 1 }, options); + return _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, options); }); Assert.Equal(409, ex.StatusCode); @@ -325,19 +384,28 @@ namespace TestSuite.ApiTests try { // STEP 1: Upsert a new item with a custom id. - content = await _.Contents.UpsertAsync(id, new TestEntityData { Number = 1 }, ContentUpsertOptions.AsPublish); + content = await _.Contents.UpsertAsync(id, new TestEntityData + { + Number = 1 + }, ContentUpsertOptions.AsPublish); Assert.Equal(id, content.Id); // STEP 2: Make an update with the upsert endpoint. - content = await _.Contents.UpsertAsync(id, new TestEntityData { Number = 2 }); + content = await _.Contents.UpsertAsync(id, new TestEntityData + { + Number = 2 + }); Assert.Equal(2, content.Data.Number); // STEP 3: Make an update with the update endpoint. - content = await _.Contents.UpdateAsync(id, new TestEntityData { Number = 3 }); + content = await _.Contents.UpdateAsync(id, new TestEntityData + { + Number = 3 + }); Assert.Equal(3, content.Data.Number); } @@ -357,11 +425,17 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); // STEP 2: Update the item and ensure that the data has changed. - await _.Contents.UpdateAsync(content.Id, new TestEntityData { Number = 2 }); + await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + Number = 2 + }); var updated = await _.Contents.GetAsync(content.Id); @@ -383,7 +457,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); var numErrors = 0; @@ -394,7 +471,10 @@ namespace TestSuite.ApiTests { try { - await _.Contents.UpdateAsync(content.Id, new TestEntityData { Number = i }); + await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + Number = i + }); Interlocked.Increment(ref numSuccess); } @@ -411,7 +491,10 @@ namespace TestSuite.ApiTests // STEP 3: Make an normal update to ensure nothing is corrupt. - await _.Contents.UpdateAsync(content.Id, new TestEntityData { Number = 2 }); + await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + Number = 2 + }); var updated = await _.Contents.GetAsync(content.Id); @@ -433,7 +516,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); var numErrors = 0; @@ -444,7 +530,10 @@ namespace TestSuite.ApiTests { try { - await _.Contents.UpsertAsync(content.Id, new TestEntityData { Number = i }); + await _.Contents.UpsertAsync(content.Id, new TestEntityData + { + Number = i + }); Interlocked.Increment(ref numSuccess); } @@ -461,7 +550,10 @@ namespace TestSuite.ApiTests // STEP 3: Make an normal update to ensure nothing is corrupt. - await _.Contents.UpdateAsync(content.Id, new TestEntityData { Number = 2 }); + await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + Number = 2 + }); var updated = await _.Contents.GetAsync(content.Id); @@ -483,11 +575,17 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "initial" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "initial" + }, ContentCreateOptions.AsPublish); // STEP 2: Update the item and ensure that the data has changed. - await _.Contents.UpdateAsync(content.Id, new TestEntityData { String = null }); + await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + String = null + }); var updated = await _.Contents.GetAsync(content.Id); @@ -509,15 +607,24 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "test" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "test" + }, ContentCreateOptions.AsPublish); // STEP 2: Patch an item. - await _.Contents.PatchAsync(content.Id, new TestEntityData { Number = 1 }); + await _.Contents.PatchAsync(content.Id, new TestEntityData + { + Number = 1 + }); // STEP 3: Update the item and ensure that the data has changed. - await _.Contents.PatchAsync(content.Id, new TestEntityData { Number = 2 }); + await _.Contents.PatchAsync(content.Id, new TestEntityData + { + Number = 2 + }); var updated = await _.Contents.GetAsync(content.Id); @@ -544,11 +651,17 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Id = "id1" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Id = "id1" + }, ContentCreateOptions.AsPublish); // STEP 2: Update the item and ensure that the data has changed. - await _.Contents.PatchAsync(content.Id, new TestEntityData { Id = "id2" }); + await _.Contents.PatchAsync(content.Id, new TestEntityData + { + Id = "id2" + }); var updated = await _.Contents.GetAsync(content.Id); @@ -572,11 +685,20 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "initial" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "initial" + }, ContentCreateOptions.AsPublish); // STEP 2: Update the item and ensure that the data has changed. - await _.Contents.PatchAsync(content.Id, new { @string = new { iv = (object)null } }); + await _.Contents.PatchAsync(content.Id, new + { + @string = new + { + iv = (object)null + } + }); var updated = await _.Contents.GetAsync(content.Id); @@ -600,15 +722,24 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "test" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "test" + }, ContentCreateOptions.AsPublish); // STEP 2: Patch an item. - await _.Contents.UpsertAsync(content.Id, new TestEntityData { Number = 1 }, ContentUpsertOptions.AsPatch); + await _.Contents.UpsertAsync(content.Id, new TestEntityData + { + Number = 1 + }, ContentUpsertOptions.AsPatch); // STEP 3: Update the item and ensure that the data has changed. - await _.Contents.UpsertAsync(content.Id, new TestEntityData { Number = 2 }, ContentUpsertOptions.AsPatch); + await _.Contents.UpsertAsync(content.Id, new TestEntityData + { + Number = 2 + }, ContentUpsertOptions.AsPatch); var updated = await _.Contents.GetAsync(content.Id); @@ -635,7 +766,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "test" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "test" + }, ContentCreateOptions.AsPublish); // STEP 2: Patch an item. @@ -719,7 +853,10 @@ namespace TestSuite.ApiTests // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { String = "test" }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + String = "test" + }, ContentCreateOptions.AsPublish); // STEP 2: Patch an item. @@ -785,7 +922,10 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, ContentCreateOptions.AsPublish); // STEP 2: Create draft. @@ -793,7 +933,10 @@ namespace TestSuite.ApiTests // STEP 3: Update the item and ensure that the data has not changed. - await _.Contents.PatchAsync(content.Id, new TestEntityData { Number = 2 }); + await _.Contents.PatchAsync(content.Id, new TestEntityData + { + Number = 2 + }); var updated_1 = await _.Contents.GetAsync(content.Id); @@ -831,7 +974,10 @@ namespace TestSuite.ApiTests public async Task Should_delete_content(bool permanent) { // STEP 1: Create a new item. - var content_1 = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + var content_1 = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); // STEP 2: Delete the item. @@ -858,7 +1004,10 @@ namespace TestSuite.ApiTests public async Task Should_recreate_deleted_content(bool permanent) { // STEP 1: Create a new item. - var content_1 = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + var content_1 = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); // STEP 2: Delete the item. @@ -870,7 +1019,10 @@ namespace TestSuite.ApiTests // STEP 3: Recreate the item with the same id. var deleteOptions = new ContentCreateOptions { Id = content_1.Id, Publish = true }; - var content_2 = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, deleteOptions); + var content_2 = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, deleteOptions); Assert.Equal(Status.Published, content_2.Status); @@ -889,7 +1041,10 @@ namespace TestSuite.ApiTests public async Task Should_recreate_deleted_content_with_upsert(bool permanent) { // STEP 1: Create a new item. - var content_1 = await _.Contents.CreateAsync(new TestEntityData { Number = 2 }, ContentCreateOptions.AsPublish); + var content_1 = await _.Contents.CreateAsync(new TestEntityData + { + Number = 2 + }, ContentCreateOptions.AsPublish); // STEP 2: Delete the item. @@ -899,7 +1054,10 @@ namespace TestSuite.ApiTests // STEP 3: Recreate the item with the same id. - var content_2 = await _.Contents.UpsertAsync(content_1.Id, new TestEntityData { Number = 2 }, ContentUpsertOptions.AsPublish); + var content_2 = await _.Contents.UpsertAsync(content_1.Id, new TestEntityData + { + Number = 2 + }, ContentUpsertOptions.AsPublish); Assert.Equal(Status.Published, content_2.Status); @@ -965,11 +1123,17 @@ namespace TestSuite.ApiTests try { // STEP 1: Create a new item. - content = await _.Contents.CreateAsync(new TestEntityData { Number = 1 }, ContentCreateOptions.AsPublish); + content = await _.Contents.CreateAsync(new TestEntityData + { + Number = 1 + }, ContentCreateOptions.AsPublish); // STEP 2: Update content. - content = await _.Contents.UpdateAsync(content.Id, new TestEntityData { Number = 2 }); + content = await _.Contents.UpdateAsync(content.Id, new TestEntityData + { + Number = 2 + }); // STEP 3: Get current version. diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/RuleRunnerTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/RuleRunnerTests.cs index 0e27a8f97..993611883 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/RuleRunnerTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/RuleRunnerTests.cs @@ -176,7 +176,10 @@ namespace TestSuite.ApiTests // Create a test content. var contents = _.ClientManager.CreateContentsClient(appName, schemaName); - await contents.CreateAsync(new TestEntityData { String = contentString }); + await contents.CreateAsync(new TestEntityData + { + String = contentString + }); } private async Task CreateAppAsync() diff --git a/backend/tools/TestSuite/TestSuite.LoadTests/WritingBenchmarks.cs b/backend/tools/TestSuite/TestSuite.LoadTests/WritingBenchmarks.cs index fda4b898f..d9939793f 100644 --- a/backend/tools/TestSuite/TestSuite.LoadTests/WritingBenchmarks.cs +++ b/backend/tools/TestSuite/TestSuite.LoadTests/WritingBenchmarks.cs @@ -62,7 +62,10 @@ namespace TestSuite.LoadTests await Run.Parallel(numUsers, numIterationsPerUser, async () => { - await _.Contents.CreateAsync(new TestEntityData { Number = random.Next() }, ContentCreateOptions.AsPublish); + await _.Contents.CreateAsync(new TestEntityData + { + Number = random.Next() + }, ContentCreateOptions.AsPublish); }); } }