From e3ed5e9d66d43a70d6734a261bdfadbf26b59708 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:20:10 -0300 Subject: [PATCH 01/75] feat: introduce `SubscriptionChannel` to bind `yunobserve()` --- YDotNet/Native/Types/SubscriptionChannel.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 YDotNet/Native/Types/SubscriptionChannel.cs diff --git a/YDotNet/Native/Types/SubscriptionChannel.cs b/YDotNet/Native/Types/SubscriptionChannel.cs new file mode 100644 index 00000000..7f03cf27 --- /dev/null +++ b/YDotNet/Native/Types/SubscriptionChannel.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace YDotNet.Native.Types; + +internal static class SubscriptionChannel +{ + [DllImport(ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yunobserve")] + public static extern void Unobserve(nint subscription); +} From 117872eeac04774ef72361e5febfc353b80476a5 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:22:15 -0300 Subject: [PATCH 02/75] feat: update `EventSubscriber` to match `SubscriptionChannel.Unobserve()` --- YDotNet/Document/Events/EventSubscriber.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/YDotNet/Document/Events/EventSubscriber.cs b/YDotNet/Document/Events/EventSubscriber.cs index c132d1ab..75dbd93a 100644 --- a/YDotNet/Document/Events/EventSubscriber.cs +++ b/YDotNet/Document/Events/EventSubscriber.cs @@ -5,15 +5,17 @@ internal class EventSubscriber : IEventSubscriber private readonly EventManager manager; private readonly nint owner; private readonly EventPublisher publisher = new(); - private readonly Func, (uint Handle, object Callback)> subscribe; - private readonly Action unsubscribe; - private (uint Handle, object? Callback) nativeSubscription; + private readonly Func, (nint Handle, object Callback)> subscribe; + private readonly Action unsubscribe; + private (nint Handle, object? Callback) nativeSubscription; + // The native callback, returned by `subscribe`, must be stored so it doesn't + // throw exceptions later if the Rust side invokes it after it's been collected. public EventSubscriber( EventManager manager, nint owner, - Func, (uint Handle, object Callback)> subscribe, - Action unsubscribe) + Func, (nint Handle, object Callback)> subscribe, + Action unsubscribe) { this.manager = manager; this.owner = owner; @@ -56,7 +58,7 @@ private void UnsubscribeWhenSubscribed() // If this is the last subscription, we can unsubscribe from the native source again. if (publisher.Count == 0 && nativeSubscription.Callback != null) { - unsubscribe(owner, nativeSubscription.Handle); + unsubscribe(nativeSubscription.Handle); nativeSubscription = default; From c3757126065fdbdf3716202d1699ec301dd5659c Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:25:55 -0300 Subject: [PATCH 03/75] feat: update `Array` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/Arrays/Array.cs | 2 +- YDotNet/Native/Types/ArrayChannel.cs | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/YDotNet/Document/Types/Arrays/Array.cs b/YDotNet/Document/Types/Arrays/Array.cs index 907abe34..9d3c4578 100644 --- a/YDotNet/Document/Types/Arrays/Array.cs +++ b/YDotNet/Document/Types/Arrays/Array.cs @@ -31,7 +31,7 @@ internal Array(nint handle, Doc doc, bool isDeleted) return (ArrayChannel.Observe(array, nint.Zero, callback), callback); }, - ArrayChannel.Unobserve); + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/Types/ArrayChannel.cs b/YDotNet/Native/Types/ArrayChannel.cs index 0c383dd8..6a2312e4 100644 --- a/YDotNet/Native/Types/ArrayChannel.cs +++ b/YDotNet/Native/Types/ArrayChannel.cs @@ -58,7 +58,7 @@ internal static class ArrayChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yarray_observe")] - public static extern uint Observe(nint array, nint state, ObserveCallback callback); + public static extern nint Observe(nint array, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, @@ -77,10 +77,4 @@ internal static class ArrayChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "yarray_event_delta")] public static extern nint ObserveEventDelta(nint arrayEvent, out uint length); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yarray_unobserve")] - public static extern void Unobserve(nint array, uint subscriptionId); } From aa521eeff718506c7c61c8ff7d865802738f779a Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:26:11 -0300 Subject: [PATCH 04/75] feat: update `Branch` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/Branches/Branch.cs | 3 ++- YDotNet/Native/Types/Branches/BranchChannel.cs | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 0d9dbfa6..896f1253 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -3,6 +3,7 @@ using YDotNet.Document.Types.Events; using YDotNet.Infrastructure; using YDotNet.Native.Document.Events; +using YDotNet.Native.Types; using YDotNet.Native.Types.Branches; namespace YDotNet.Document.Types.Branches; @@ -36,7 +37,7 @@ internal protected Branch(nint handle, Doc doc, bool isDeleted) return (BranchChannel.ObserveDeep(branch, nint.Zero, callback), callback); }, - (branch, s) => BranchChannel.UnobserveDeep(branch, s)); + SubscriptionChannel.Unobserve); #pragma warning restore CA1806 // Do not ignore method results } diff --git a/YDotNet/Native/Types/Branches/BranchChannel.cs b/YDotNet/Native/Types/Branches/BranchChannel.cs index 3d231a47..d21cb338 100644 --- a/YDotNet/Native/Types/Branches/BranchChannel.cs +++ b/YDotNet/Native/Types/Branches/BranchChannel.cs @@ -10,13 +10,7 @@ internal static class BranchChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yobserve_deep")] - public static extern uint ObserveDeep(nint type, nint state, ObserveCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yunobserve_deep")] - public static extern uint UnobserveDeep(nint type, uint subscriptionId); + public static extern nint ObserveDeep(nint type, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, From 1ff43823a021e23eb57100049232ab604f53ce31 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:26:31 -0300 Subject: [PATCH 05/75] feat: update `Map` to use `SubscriptionChannel.Unobserve` feat: update `Map` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/Maps/Map.cs | 3 ++- YDotNet/Native/Types/Maps/MapChannel.cs | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/YDotNet/Document/Types/Maps/Map.cs b/YDotNet/Document/Types/Maps/Map.cs index a7357cff..8f356b18 100644 --- a/YDotNet/Document/Types/Maps/Map.cs +++ b/YDotNet/Document/Types/Maps/Map.cs @@ -5,6 +5,7 @@ using YDotNet.Document.Types.Maps.Events; using YDotNet.Infrastructure; using YDotNet.Infrastructure.Extensions; +using YDotNet.Native.Types; using YDotNet.Native.Types.Maps; namespace YDotNet.Document.Types.Maps; @@ -29,7 +30,7 @@ internal Map(nint handle, Doc doc, bool isDeleted) return (MapChannel.Observe(map, nint.Zero, callback), callback); }, - MapChannel.Unobserve); + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/Types/Maps/MapChannel.cs b/YDotNet/Native/Types/Maps/MapChannel.cs index ea4e24b6..e9846ec3 100644 --- a/YDotNet/Native/Types/Maps/MapChannel.cs +++ b/YDotNet/Native/Types/Maps/MapChannel.cs @@ -64,7 +64,7 @@ internal static class MapChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ymap_observe")] - public static extern uint Observe(nint map, nint state, ObserveCallback callback); + public static extern nint Observe(nint map, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, @@ -83,10 +83,4 @@ internal static class MapChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ymap_event_target")] public static extern nint ObserveEventTarget(nint mapEvent); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ymap_unobserve")] - public static extern void Unobserve(nint map, uint subscriptionId); } From f67d5ca46dcf967620f11fdeeedd6de42fc7eaa7 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:26:41 -0300 Subject: [PATCH 06/75] feat: update `Text` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/Texts/Text.cs | 3 ++- YDotNet/Native/Types/Texts/TextChannel.cs | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/YDotNet/Document/Types/Texts/Text.cs b/YDotNet/Document/Types/Texts/Text.cs index 58ebd15c..40f9a35a 100644 --- a/YDotNet/Document/Types/Texts/Text.cs +++ b/YDotNet/Document/Types/Texts/Text.cs @@ -7,6 +7,7 @@ using YDotNet.Infrastructure; using YDotNet.Infrastructure.Extensions; using YDotNet.Native.StickyIndex; +using YDotNet.Native.Types; using YDotNet.Native.Types.Texts; namespace YDotNet.Document.Types.Texts; @@ -31,7 +32,7 @@ internal Text(nint handle, Doc doc, bool isDeleted) return (TextChannel.Observe(text, nint.Zero, callback), callback); }, - TextChannel.Unobserve); + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/Types/Texts/TextChannel.cs b/YDotNet/Native/Types/Texts/TextChannel.cs index 6ab2e8ee..1b58b06a 100644 --- a/YDotNet/Native/Types/Texts/TextChannel.cs +++ b/YDotNet/Native/Types/Texts/TextChannel.cs @@ -52,7 +52,7 @@ internal static class TextChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ytext_observe")] - public static extern uint Observe(nint text, nint state, ObserveCallback callback); + public static extern nint Observe(nint text, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, @@ -71,10 +71,4 @@ internal static class TextChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ytext_event_target")] public static extern nint ObserveEventTarget(nint textEvent); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ytext_unobserve")] - public static extern void Unobserve(nint text, uint subscriptionId); } From 1f707107999e88af28c73407d3387478986a9fad Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:26:55 -0300 Subject: [PATCH 07/75] feat: update `XmlElement` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/XmlElements/XmlElement.cs | 2 +- YDotNet/Native/Types/XmlElementChannel.cs | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/YDotNet/Document/Types/XmlElements/XmlElement.cs b/YDotNet/Document/Types/XmlElements/XmlElement.cs index 64368581..d8b9d375 100644 --- a/YDotNet/Document/Types/XmlElements/XmlElement.cs +++ b/YDotNet/Document/Types/XmlElements/XmlElement.cs @@ -31,7 +31,7 @@ internal XmlElement(nint handle, Doc doc, bool isDeleted) return (XmlElementChannel.Observe(xmlElement, nint.Zero, callback), callback); }, - XmlElementChannel.Unobserve); + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/Types/XmlElementChannel.cs b/YDotNet/Native/Types/XmlElementChannel.cs index 6c40f24c..a5e7714a 100644 --- a/YDotNet/Native/Types/XmlElementChannel.cs +++ b/YDotNet/Native/Types/XmlElementChannel.cs @@ -106,7 +106,7 @@ internal static class XmlElementChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yxmlelem_observe")] - public static extern uint Observe(nint handle, nint state, ObserveCallback callback); + public static extern nint Observe(nint handle, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, @@ -131,10 +131,4 @@ internal static class XmlElementChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "yxmlelem_event_keys")] public static extern nint ObserveEventKeys(nint eventHandle, out uint length); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yxmlelem_unobserve")] - public static extern void Unobserve(nint handle, uint subscriptionId); } From 81baa394e37d70dad5e36f70b40631388d17bea2 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:28:17 -0300 Subject: [PATCH 08/75] feat: update `XmlText` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Types/XmlTexts/XmlText.cs | 4 ++-- YDotNet/Native/Types/XmlTextChannel.cs | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/YDotNet/Document/Types/XmlTexts/XmlText.cs b/YDotNet/Document/Types/XmlTexts/XmlText.cs index bc972389..e6bfad88 100644 --- a/YDotNet/Document/Types/XmlTexts/XmlText.cs +++ b/YDotNet/Document/Types/XmlTexts/XmlText.cs @@ -32,7 +32,7 @@ internal XmlText(nint handle, Doc doc, bool isDeleted) return (XmlTextChannel.Observe(xmlText, nint.Zero, callback), callback); }, - XmlTextChannel.Unobserve); + SubscriptionChannel.Unobserve); } /// @@ -270,7 +270,7 @@ public IDisposable Observe(Action action) { ThrowIfDisposed(); - var handle = StickyIndexChannel.FromIndex(Handle, transaction.Handle, index, (sbyte)associationType); + var handle = StickyIndexChannel.FromIndex(Handle, transaction.Handle, index, (sbyte) associationType); return handle != nint.Zero ? new StickyIndex(handle) : null; } diff --git a/YDotNet/Native/Types/XmlTextChannel.cs b/YDotNet/Native/Types/XmlTextChannel.cs index 0363d709..a7a5e71b 100644 --- a/YDotNet/Native/Types/XmlTextChannel.cs +++ b/YDotNet/Native/Types/XmlTextChannel.cs @@ -70,7 +70,7 @@ internal static class XmlTextChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yxmltext_observe")] - public static extern uint Observe(nint handle, nint state, ObserveCallback callback); + public static extern nint Observe(nint handle, nint state, ObserveCallback callback); [DllImport( ChannelSettings.NativeLib, @@ -89,10 +89,4 @@ internal static class XmlTextChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "yxmltext_event_keys")] public static extern nint ObserveEventKeys(nint eventHandle, out uint length); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yxmltext_unobserve")] - public static extern void Unobserve(nint handle, uint subscriptionId); } From 8efa594c961eadaebf2a77e091275021cf79df73 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:28:47 -0300 Subject: [PATCH 09/75] feat: update `UndoManager` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/UndoManagers/UndoManager.cs | 7 +++---- YDotNet/Native/UndoManager/UndoManagerChannel.cs | 16 ++-------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/YDotNet/Document/UndoManagers/UndoManager.cs b/YDotNet/Document/UndoManagers/UndoManager.cs index 06f44fa9..3ff22a6e 100644 --- a/YDotNet/Document/UndoManagers/UndoManager.cs +++ b/YDotNet/Document/UndoManagers/UndoManager.cs @@ -3,6 +3,7 @@ using YDotNet.Document.Types.Branches; using YDotNet.Document.UndoManagers.Events; using YDotNet.Infrastructure; +using YDotNet.Native.Types; using YDotNet.Native.UndoManager; using YDotNet.Native.UndoManager.Events; @@ -25,7 +26,6 @@ public class UndoManager : UnmanagedResource public UndoManager(Doc doc, Branch branch, UndoManagerOptions? options = null) : base(Create(doc, branch, options)) { -#pragma warning disable CA1806 // Do not ignore method results onAdded = new EventSubscriber( doc.EventManager, Handle, @@ -36,7 +36,7 @@ public UndoManager(Doc doc, Branch branch, UndoManagerOptions? options = null) return (UndoManagerChannel.ObserveAdded(Handle, nint.Zero, callback), callback); }, - (owner, s) => UndoManagerChannel.UnobserveAdded(owner, s)); + SubscriptionChannel.Unobserve); onPopped = new EventSubscriber( doc.EventManager, @@ -48,8 +48,7 @@ public UndoManager(Doc doc, Branch branch, UndoManagerOptions? options = null) return (UndoManagerChannel.ObservePopped(Handle, nint.Zero, callback), callback); }, - (owner, s) => UndoManagerChannel.UnobservePopped(owner, s)); -#pragma warning restore CA1806 // Do not ignore method results + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/UndoManager/UndoManagerChannel.cs b/YDotNet/Native/UndoManager/UndoManagerChannel.cs index e8b9d1ef..081b9463 100644 --- a/YDotNet/Native/UndoManager/UndoManagerChannel.cs +++ b/YDotNet/Native/UndoManager/UndoManagerChannel.cs @@ -24,25 +24,13 @@ internal static class UndoManagerChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yundo_manager_observe_added")] - public static extern uint ObserveAdded(nint undoManager, nint state, ObserveAddedCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yundo_manager_unobserve_added")] - public static extern uint UnobserveAdded(nint undoManager, uint subscriptionId); + public static extern nint ObserveAdded(nint undoManager, nint state, ObserveAddedCallback callback); [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "yundo_manager_observe_popped")] - public static extern uint ObservePopped(nint undoManager, nint state, ObservePoppedCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yundo_manager_unobserve_popped")] - public static extern uint UnobservePopped(nint undoManager, uint subscriptionId); + public static extern nint ObservePopped(nint undoManager, nint state, ObservePoppedCallback callback); [DllImport( ChannelSettings.NativeLib, From 9efa7a6bf022fd0619a4480239149d86a4e95e2d Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:29:51 -0300 Subject: [PATCH 10/75] feat: update `Doc` to use `SubscriptionChannel.Unobserve` --- YDotNet/Document/Doc.cs | 10 +++---- YDotNet/Native/Document/DocChannel.cs | 40 ++++----------------------- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/YDotNet/Document/Doc.cs b/YDotNet/Document/Doc.cs index 19568e4a..26eb3b92 100644 --- a/YDotNet/Document/Doc.cs +++ b/YDotNet/Document/Doc.cs @@ -77,7 +77,7 @@ internal Doc(nint handle, Doc? parent, bool isDeleted) return (DocChannel.ObserveClear(doc, nint.Zero, callback), callback); }, - (doc, s) => DocChannel.UnobserveClear(doc, s)); + SubscriptionChannel.Unobserve); onUpdateV1 = new EventSubscriber( EventManager, @@ -89,7 +89,7 @@ internal Doc(nint handle, Doc? parent, bool isDeleted) return (DocChannel.ObserveUpdatesV1(Handle, nint.Zero, callback), callback); }, - (doc, s) => DocChannel.UnobserveUpdatesV1(doc, s)); + SubscriptionChannel.Unobserve); onUpdateV2 = new EventSubscriber( EventManager, @@ -101,7 +101,7 @@ internal Doc(nint handle, Doc? parent, bool isDeleted) return (DocChannel.ObserveUpdatesV2(Handle, nint.Zero, callback), callback); }, - (doc, s) => DocChannel.UnobserveUpdatesV2(doc, s)); + SubscriptionChannel.Unobserve); onAfterTransaction = new EventSubscriber( EventManager, @@ -114,7 +114,7 @@ internal Doc(nint handle, Doc? parent, bool isDeleted) return (DocChannel.ObserveAfterTransaction(doc, nint.Zero, callback), callback); }, - (doc, s) => DocChannel.UnobserveAfterTransaction(doc, s)); + SubscriptionChannel.Unobserve); onSubDocs = new EventSubscriber( EventManager, @@ -126,7 +126,7 @@ internal Doc(nint handle, Doc? parent, bool isDeleted) return (DocChannel.ObserveSubDocs(doc, nint.Zero, callback), callback); }, - (doc, s) => DocChannel.UnobserveSubDocs(doc, s)); + SubscriptionChannel.Unobserve); } /// diff --git a/YDotNet/Native/Document/DocChannel.cs b/YDotNet/Native/Document/DocChannel.cs index 462011e4..9085b639 100644 --- a/YDotNet/Native/Document/DocChannel.cs +++ b/YDotNet/Native/Document/DocChannel.cs @@ -118,59 +118,29 @@ internal static class DocChannel ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ydoc_observe_clear")] - public static extern uint ObserveClear(nint doc, nint state, ObserveClearCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ydoc_unobserve_clear")] - public static extern uint UnobserveClear(nint doc, uint subscriptionId); + public static extern nint ObserveClear(nint doc, nint state, ObserveClearCallback callback); [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ydoc_observe_updates_v1")] - public static extern uint ObserveUpdatesV1(nint doc, nint state, ObserveUpdatesCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ydoc_unobserve_updates_v1")] - public static extern uint UnobserveUpdatesV1(nint doc, uint subscriptionId); + public static extern nint ObserveUpdatesV1(nint doc, nint state, ObserveUpdatesCallback callback); [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ydoc_observe_updates_v2")] - public static extern uint ObserveUpdatesV2(nint doc, nint state, ObserveUpdatesCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ydoc_unobserve_updates_v2")] - public static extern uint UnobserveUpdatesV2(nint doc, uint subscriptionId); + public static extern nint ObserveUpdatesV2(nint doc, nint state, ObserveUpdatesCallback callback); [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ydoc_observe_after_transaction")] - public static extern uint ObserveAfterTransaction(nint doc, nint state, ObserveAfterTransactionCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ydoc_unobserve_after_transaction")] - public static extern uint UnobserveAfterTransaction(nint doc, uint subscriptionId); + public static extern nint ObserveAfterTransaction(nint doc, nint state, ObserveAfterTransactionCallback callback); [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ydoc_observe_subdocs")] - public static extern uint ObserveSubDocs(nint doc, nint state, ObserveSubdocsCallback callback); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ydoc_unobserve_subdocs")] - public static extern uint UnobserveSubDocs(nint doc, uint subscriptionId); + public static extern nint ObserveSubDocs(nint doc, nint state, ObserveSubdocsCallback callback); } From 1f9415d0bb2232f8b85c8bce4cf1c0ab2ad1ffc8 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:32:29 -0300 Subject: [PATCH 11/75] test: dispose subscription on tests for `Text.ObserveDeep()` --- Tests/YDotNet.Tests.Unit/Branches/TextObserveDeepTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/YDotNet.Tests.Unit/Branches/TextObserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/TextObserveDeepTests.cs index cea21446..ea3066d5 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/TextObserveDeepTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/TextObserveDeepTests.cs @@ -53,5 +53,8 @@ public void ObserveDeepHasPathWhenAdded() // Assert Assert.That(pathSegments.Count(), Is.EqualTo(expected: 1)); + + // Act + subscription.Dispose(); } } From e99603cfe9e819b46d287d8a691fef23c81710dc Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:32:54 -0300 Subject: [PATCH 12/75] style: fix access modifier order in `Branch` --- YDotNet/Document/Types/Branches/Branch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 896f1253..cfeb19b0 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -15,7 +15,7 @@ public abstract class Branch : UnmanagedResource { private readonly EventSubscriber onDeep; - internal protected Branch(nint handle, Doc doc, bool isDeleted) + protected internal Branch(nint handle, Doc doc, bool isDeleted) : base(handle, isDeleted) { Doc = doc; From fbc9c06037abb6ba700ceb4ddf23d5df42cd1635 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Fri, 15 Mar 2024 18:34:41 -0300 Subject: [PATCH 13/75] fix: remove unnecessary null conditional operator from `XmlText.Format()` --- YDotNet/Document/Types/XmlTexts/XmlText.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/XmlTexts/XmlText.cs b/YDotNet/Document/Types/XmlTexts/XmlText.cs index e6bfad88..01fa5d05 100644 --- a/YDotNet/Document/Types/XmlTexts/XmlText.cs +++ b/YDotNet/Document/Types/XmlTexts/XmlText.cs @@ -198,7 +198,7 @@ public void Format(Transaction transaction, uint index, uint length, Input attri { ThrowIfDisposed(); - using var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); + using var unsafeAttributes = MemoryWriter.WriteStruct(attributes.InputNative); XmlTextChannel.Format(Handle, transaction.Handle, index, length, unsafeAttributes.Handle); } From 5567037f658974ef97fce7135da5aa2e8b1e3dae Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 11:48:32 -0300 Subject: [PATCH 14/75] feat: add the `OutputTag.XmlFragment` constant --- YDotNet/Document/Cells/OutputTag.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/YDotNet/Document/Cells/OutputTag.cs b/YDotNet/Document/Cells/OutputTag.cs index df06a9c4..b733738d 100644 --- a/YDotNet/Document/Cells/OutputTag.cs +++ b/YDotNet/Document/Cells/OutputTag.cs @@ -78,11 +78,13 @@ public enum OutputTag /// XmlText = 5, - // The following constant is commented because it's not exposed by `Input` or `Output`. - // XmlFragment = 6, + /// + /// Represents a cell with an value. + /// + XmlFragment = 6, /// /// Represents a cell with an value. /// - Doc = 7, + Doc = 7 } From 27e516cc13c32c726a6f23e130bd696402756c72 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 11:51:32 -0300 Subject: [PATCH 15/75] feat: update `EventBranchTag` to include `XmlFragment` and synchronize with `BranchKind` --- YDotNet/Document/Types/Events/EventBranchTag.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/YDotNet/Document/Types/Events/EventBranchTag.cs b/YDotNet/Document/Types/Events/EventBranchTag.cs index bd398d91..b8da36fc 100644 --- a/YDotNet/Document/Types/Events/EventBranchTag.cs +++ b/YDotNet/Document/Types/Events/EventBranchTag.cs @@ -2,7 +2,9 @@ using YDotNet.Document.Types.Maps.Events; using YDotNet.Document.Types.Texts.Events; using YDotNet.Document.Types.XmlElements.Events; +using YDotNet.Document.Types.XmlFragments.Events; using YDotNet.Document.Types.XmlTexts.Events; +using YDotNet.Native.Types.Branches; namespace YDotNet.Document.Types.Events; @@ -14,25 +16,30 @@ public enum EventBranchTag : sbyte /// /// This event holds an instance. /// - Array = 1, + Array = BranchKind.Array, /// /// This event holds an instance. /// - Map = 2, + Map = BranchKind.Map, /// /// This event holds an instance. /// - Text = 3, + Text = BranchKind.Text, /// /// This event holds an instance. /// - XmlElement = 4, + XmlElement = BranchKind.XmlElement, /// /// This event holds an instance. /// - XmlText = 5, + XmlText = BranchKind.XmlText, + + /// + /// This event holds an instance. + /// + XmlFragment = BranchKind.XmlFragment } From 55c64813dfab71046d5291fb3df41b18e947d7fa Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 11:52:38 -0300 Subject: [PATCH 16/75] feat: synchronize `BranchKind` with `OutputTag` --- YDotNet/Native/Types/Branches/BranchKind.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/YDotNet/Native/Types/Branches/BranchKind.cs b/YDotNet/Native/Types/Branches/BranchKind.cs index 73ec7fb3..20e806b9 100644 --- a/YDotNet/Native/Types/Branches/BranchKind.cs +++ b/YDotNet/Native/Types/Branches/BranchKind.cs @@ -1,11 +1,14 @@ +using YDotNet.Document.Cells; + namespace YDotNet.Native.Types.Branches; internal enum BranchKind { - Null = 0, - Array = 1, - Map = 2, - Text = 3, - XmlElement = 4, - XmlText = 5, + Null = OutputTag.Null, + Array = OutputTag.Array, + Map = OutputTag.Map, + Text = OutputTag.Text, + XmlElement = OutputTag.XmlElement, + XmlText = OutputTag.XmlText, + XmlFragment = OutputTag.XmlFragment } From 83aae2d3128fc313c23239c957da288dc6e89da1 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 11:53:46 -0300 Subject: [PATCH 17/75] feat: introduce `XmlFragment` and `XmlFragmentEvent` --- .../XmlFragments/Events/XmlFragmentEvent.cs | 69 +++++++ .../Types/XmlFragments/XmlFragment.cs | 175 ++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 YDotNet/Document/Types/XmlFragments/Events/XmlFragmentEvent.cs create mode 100644 YDotNet/Document/Types/XmlFragments/XmlFragment.cs diff --git a/YDotNet/Document/Types/XmlFragments/Events/XmlFragmentEvent.cs b/YDotNet/Document/Types/XmlFragments/Events/XmlFragmentEvent.cs new file mode 100644 index 00000000..308d9edc --- /dev/null +++ b/YDotNet/Document/Types/XmlFragments/Events/XmlFragmentEvent.cs @@ -0,0 +1,69 @@ +using YDotNet.Document.Types.Events; +using YDotNet.Infrastructure; +using YDotNet.Infrastructure.Extensions; +using YDotNet.Native.Types; + +namespace YDotNet.Document.Types.XmlFragments.Events; + +/// +/// Represents the event that's part of an operation within an instance. +/// +public class XmlFragmentEvent : UnmanagedResource +{ + private readonly Lazy delta; + private readonly Lazy path; + private readonly Lazy target; + + internal XmlFragmentEvent(nint handle, Doc doc) + : base(handle) + { + path = new Lazy( + () => + { + var pathHandle = XmlElementChannel.ObserveEventPath(handle, out var length).Checked(); + + return new EventPath(pathHandle, length); + }); + + delta = new Lazy( + () => + { + var deltaHandle = XmlElementChannel.ObserveEventDelta(handle, out var length).Checked(); + + return new EventChanges(deltaHandle, length, doc); + }); + + target = new Lazy( + () => + { + var targetHandle = XmlElementChannel.ObserveEventTarget(handle).Checked(); + + return doc.GetXmlFragment(targetHandle, isDeleted: false); + }); + } + + /// + /// Gets the changes within the instance and triggered this event. + /// + /// This property can only be accessed during the callback that exposes this instance. + public EventChanges Delta => delta.Value; + + /// + /// Gets the path from the observed instanced down to the current instance. + /// + /// This property can only be accessed during the callback that exposes this instance. + public EventPath Path => path.Value; + + /// + /// Gets the instance that is + /// related to this instance. + /// + /// The target of the event. + public XmlFragment Target => target.Value; + + /// + protected override void DisposeCore(bool disposing) + { + // The event has no explicit garbage collection, but is released automatically after the event has been completed. + } +} diff --git a/YDotNet/Document/Types/XmlFragments/XmlFragment.cs b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs new file mode 100644 index 00000000..64f3dcc0 --- /dev/null +++ b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs @@ -0,0 +1,175 @@ +using YDotNet.Document.Cells; +using YDotNet.Document.Events; +using YDotNet.Document.Transactions; +using YDotNet.Document.Types.Branches; +using YDotNet.Document.Types.XmlElements; +using YDotNet.Document.Types.XmlElements.Events; +using YDotNet.Document.Types.XmlElements.Trees; +using YDotNet.Document.Types.XmlFragments.Events; +using YDotNet.Document.Types.XmlTexts; +using YDotNet.Infrastructure; +using YDotNet.Infrastructure.Extensions; +using YDotNet.Native.Types; + +namespace YDotNet.Document.Types.XmlFragments; + +/// +/// +/// A shared data type that represents an untagged collection of XML nodes, +/// ( and ). +/// +/// +/// The is similar to but +/// it doesn't have a tag or attributes. +/// +/// +public class XmlFragment : Branch +{ + private readonly EventSubscriber onObserve; + + internal XmlFragment(nint handle, Doc doc, bool isDeleted) + : base(handle, doc, isDeleted) + { + onObserve = new EventSubscriber( + doc.EventManager, + handle, + (xmlFragment, action) => + { + XmlElementChannel.ObserveCallback callback = (_, eventHandle) => + action(new XmlElementEvent(eventHandle, Doc)); + + return (XmlElementChannel.Observe(xmlFragment, nint.Zero, callback), callback); + }, + SubscriptionChannel.Unobserve); + } + + /// + /// Returns a number of direct child nodes (both and ) + /// of this . + /// + /// + /// This function doesn't count a recursive nodes, only direct children of this . + /// + /// The transaction that wraps this operation. + /// The number of direct child nodes of this . + public uint ChildLength(Transaction transaction) + { + ThrowIfDisposed(); + + return XmlElementChannel.ChildLength(Handle, transaction.Handle); + } + + /// + /// Inserts an as a child of this at the given + /// . + /// + /// The transaction that wraps this operation. + /// The index that the will be inserted. + /// The inserted at the given . + public XmlText InsertText(Transaction transaction, uint index) + { + ThrowIfDisposed(); + + var handle = XmlElementChannel.InsertText(Handle, transaction.Handle, index); + + return Doc.GetXmlText(handle, isDeleted: false); + } + + /// + /// Inserts an as a child of this at the given + /// . + /// + /// The transaction that wraps this operation. + /// The index that the will be inserted. + /// The name (or tag) of the that will be inserted. + /// The inserted at the given . + public XmlElement InsertElement(Transaction transaction, uint index, string name) + { + ThrowIfDisposed(); + + using var unsafeName = MemoryWriter.WriteUtf8String(name); + + var handle = XmlElementChannel.InsertElement(Handle, transaction.Handle, index, unsafeName.Handle); + + return Doc.GetXmlElement(handle, isDeleted: false); + } + + /// + /// Removes a consecutive range of direct child nodes starting at the through the + /// . + /// + /// The transaction that wraps this operation. + /// The index to start removing the child nodes. + /// The amount of child nodes to remove, starting at . + public void RemoveRange(Transaction transaction, uint index, uint length) + { + ThrowIfDisposed(); + + XmlElementChannel.RemoveRange(Handle, transaction.Handle, index, length); + } + + /// + /// Returns an cell or null if the is out of bounds. + /// + /// The transaction that wraps this operation. + /// The index to retrieve the cell. + /// An cell or null if the is out of bounds. + public Output? Get(Transaction transaction, uint index) + { + ThrowIfDisposed(); + + var handle = XmlElementChannel.Get(Handle, transaction.Handle, index); + + return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + } + + /// + /// Returns the first child of the current node which can be an + /// or an or null if this node is empty. + /// + /// The transaction that wraps this operation. + /// + /// The first child of the current node which can be an + /// or an or null if this node is empty. + /// + public Output? FirstChild(Transaction transaction) + { + ThrowIfDisposed(); + + var handle = XmlElementChannel.FirstChild(Handle, transaction.Handle); + + return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + } + + /// + /// Returns an for this . + /// + /// + /// Check the documentation of for more information. + /// + /// The transaction that wraps this operation. + /// An for this . + public XmlTreeWalker TreeWalker(Transaction transaction) + { + ThrowIfDisposed(); + + var handle = XmlElementChannel.TreeWalker(Handle, transaction.Handle); + + return new XmlTreeWalker(handle.Checked(), Doc); + } + + /// + /// Subscribes a callback function for changes performed within the instance. + /// + /// + /// The callbacks are triggered whenever a is committed. + /// + /// The callback to be executed when a is committed. + /// The subscription for the event. It may be used to unsubscribe later. + public IDisposable Observe(Action action) + { + ThrowIfDisposed(); + + return onObserve.Subscribe(action); + } +} From 84a04fbd2e2228ab02772f0e8e0816c543903513 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 11:54:33 -0300 Subject: [PATCH 18/75] feat: update `XmlElement` and `XmlElementEvent` to inherit from their `XmlFragment*` counterparts --- .../XmlElements/Events/XmlElementEvent.cs | 44 ++------------ .../Document/Types/XmlElements/XmlElement.cs | 60 ++++++------------- 2 files changed, 21 insertions(+), 83 deletions(-) diff --git a/YDotNet/Document/Types/XmlElements/Events/XmlElementEvent.cs b/YDotNet/Document/Types/XmlElements/Events/XmlElementEvent.cs index a7dc12d3..797d5a49 100644 --- a/YDotNet/Document/Types/XmlElements/Events/XmlElementEvent.cs +++ b/YDotNet/Document/Types/XmlElements/Events/XmlElementEvent.cs @@ -1,5 +1,5 @@ using YDotNet.Document.Types.Events; -using YDotNet.Infrastructure; +using YDotNet.Document.Types.XmlFragments.Events; using YDotNet.Infrastructure.Extensions; using YDotNet.Native.Types; @@ -8,32 +8,14 @@ namespace YDotNet.Document.Types.XmlElements.Events; /// /// Represents the event that's part of an operation within an instance. /// -public class XmlElementEvent : UnmanagedResource +public class XmlElementEvent : XmlFragmentEvent { - private readonly Lazy delta; private readonly Lazy keys; - private readonly Lazy path; private readonly Lazy target; internal XmlElementEvent(nint handle, Doc doc) - : base(handle) + : base(handle, doc) { - path = new Lazy( - () => - { - var pathHandle = XmlElementChannel.ObserveEventPath(handle, out var length).Checked(); - - return new EventPath(pathHandle, length); - }); - - delta = new Lazy( - () => - { - var deltaHandle = XmlElementChannel.ObserveEventDelta(handle, out var length).Checked(); - - return new EventChanges(deltaHandle, length, doc); - }); - keys = new Lazy( () => { @@ -51,18 +33,6 @@ internal XmlElementEvent(nint handle, Doc doc) }); } - /// - /// Gets the changes within the instance and triggered this event. - /// - /// This property can only be accessed during the callback that exposes this instance. - public EventChanges Delta => delta.Value; - - /// - /// Gets the path from the observed instanced down to the current instance. - /// - /// This property can only be accessed during the callback that exposes this instance. - public EventPath Path => path.Value; - /// /// Gets the attributes that changed within the instance and triggered this event. /// @@ -73,11 +43,5 @@ internal XmlElementEvent(nint handle, Doc doc) /// Gets the instance that is related to this instance. /// /// The target of the event. - public XmlElement Target => target.Value; - - /// - protected override void DisposeCore(bool disposing) - { - // The event has no explicit garbage collection, but is released automatically after the event has been completed. - } + public new XmlElement Target => target.Value; } diff --git a/YDotNet/Document/Types/XmlElements/XmlElement.cs b/YDotNet/Document/Types/XmlElements/XmlElement.cs index d8b9d375..949ed690 100644 --- a/YDotNet/Document/Types/XmlElements/XmlElement.cs +++ b/YDotNet/Document/Types/XmlElements/XmlElement.cs @@ -1,9 +1,9 @@ using YDotNet.Document.Cells; using YDotNet.Document.Events; using YDotNet.Document.Transactions; -using YDotNet.Document.Types.Branches; using YDotNet.Document.Types.XmlElements.Events; using YDotNet.Document.Types.XmlElements.Trees; +using YDotNet.Document.Types.XmlFragments; using YDotNet.Document.Types.XmlTexts; using YDotNet.Infrastructure; using YDotNet.Infrastructure.Extensions; @@ -14,7 +14,7 @@ namespace YDotNet.Document.Types.XmlElements; /// /// A shared data type that represents an XML element. /// -public class XmlElement : Branch +public class XmlElement : XmlFragment { private readonly EventSubscriber onObserve; @@ -143,11 +143,9 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// /// The transaction that wraps this operation. /// The number of direct child nodes of this . - public uint ChildLength(Transaction transaction) + public new uint ChildLength(Transaction transaction) { - ThrowIfDisposed(); - - return XmlElementChannel.ChildLength(Handle, transaction.Handle); + return base.ChildLength(transaction); } /// @@ -157,32 +155,22 @@ public uint ChildLength(Transaction transaction) /// The transaction that wraps this operation. /// The index that the will be inserted. /// The inserted at the given . - public XmlText InsertText(Transaction transaction, uint index) + public new XmlText InsertText(Transaction transaction, uint index) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.InsertText(Handle, transaction.Handle, index); - - return Doc.GetXmlText(handle, isDeleted: false); + return base.InsertText(transaction, index); } /// - /// Inserts an as a child of this at the given + /// Inserts an as a child of this at the given /// . /// /// The transaction that wraps this operation. /// The index that the will be inserted. /// The name (or tag) of the that will be inserted. /// The inserted at the given . - public XmlElement InsertElement(Transaction transaction, uint index, string name) + public new XmlElement InsertElement(Transaction transaction, uint index, string name) { - ThrowIfDisposed(); - - using var unsafeName = MemoryWriter.WriteUtf8String(name); - - var handle = XmlElementChannel.InsertElement(Handle, transaction.Handle, index, unsafeName.Handle); - - return Doc.GetXmlElement(handle, isDeleted: false); + return base.InsertElement(transaction, index, name); } /// @@ -192,11 +180,9 @@ public XmlElement InsertElement(Transaction transaction, uint index, string name /// The transaction that wraps this operation. /// The index to start removing the child nodes. /// The amount of child nodes to remove, starting at . - public void RemoveRange(Transaction transaction, uint index, uint length) + public new void RemoveRange(Transaction transaction, uint index, uint length) { - ThrowIfDisposed(); - - XmlElementChannel.RemoveRange(Handle, transaction.Handle, index, length); + base.RemoveRange(transaction, index, length); } /// @@ -205,13 +191,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// The transaction that wraps this operation. /// The index to retrieve the cell. /// An cell or null if the is out of bounds. - public Output? Get(Transaction transaction, uint index) + public new Output? Get(Transaction transaction, uint index) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.Get(Handle, transaction.Handle, index); - - return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + return base.Get(transaction, index); } /// @@ -261,13 +243,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// The first child of the current node which can be an /// or an or null if this node is empty. /// - public Output? FirstChild(Transaction transaction) + public new Output? FirstChild(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.FirstChild(Handle, transaction.Handle); - - return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + return base.FirstChild(transaction); } /// @@ -296,13 +274,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// /// The transaction that wraps this operation. /// An for this . - public XmlTreeWalker TreeWalker(Transaction transaction) + public new XmlTreeWalker TreeWalker(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.TreeWalker(Handle, transaction.Handle); - - return new XmlTreeWalker(handle.Checked(), Doc); + return base.TreeWalker(transaction); } /// From 90a9a2e35b9b7dcb456125d9d6a804d0c989cf6f Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:02:12 -0300 Subject: [PATCH 19/75] feat: update `Doc` and `DocChannel` to only allow getting root-level `XmlFragment` --- YDotNet/Document/Doc.cs | 40 +++++++++------------------ YDotNet/Native/Document/DocChannel.cs | 10 ++----- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/YDotNet/Document/Doc.cs b/YDotNet/Document/Doc.cs index 26eb3b92..27500344 100644 --- a/YDotNet/Document/Doc.cs +++ b/YDotNet/Document/Doc.cs @@ -4,6 +4,7 @@ using YDotNet.Document.Types.Maps; using YDotNet.Document.Types.Texts; using YDotNet.Document.Types.XmlElements; +using YDotNet.Document.Types.XmlFragments; using YDotNet.Document.Types.XmlTexts; using YDotNet.Infrastructure; using YDotNet.Native.Document; @@ -298,43 +299,23 @@ public Array Array(string name) } /// - /// Gets or creates a new shared data type instance as a + /// Gets or creates a new shared data type instance as a /// root-level type in this document. /// /// /// This structure can later be accessed using its name. /// - /// The name of the instance to get. - /// The instance related to the name provided. - public XmlElement XmlElement(string name) + /// The name of the instance to get. + /// The instance related to the name provided. + public XmlFragment XmlFragment(string name) { ThrowIfDisposed(); ThrowIfOpenTransaction(); using var unsafeName = MemoryWriter.WriteUtf8String(name); - var handle = DocChannel.XmlElement(Handle, unsafeName.Handle); + var handle = DocChannel.XmlFragment(Handle, unsafeName.Handle); - return GetXmlElement(handle, isDeleted: false); - } - - /// - /// Gets or creates a new shared data type instance as a - /// root-level type in this document. - /// - /// - /// This structure can later be accessed using its name. - /// - /// The name of the instance to get. - /// The instance related to the name provided. - public XmlText XmlText(string name) - { - ThrowIfDisposed(); - ThrowIfOpenTransaction(); - - using var unsafeName = MemoryWriter.WriteUtf8String(name); - var handle = DocChannel.XmlText(Handle, unsafeName.Handle); - - return GetXmlText(handle, isDeleted: false); + return GetXmlFragment(handle, isDeleted: false); } /// @@ -347,7 +328,7 @@ public Transaction WriteTransaction(byte[]? origin = null) { ThrowIfDisposed(); - var handle = DocChannel.WriteTransaction(Handle, (uint)(origin?.Length ?? 0), origin); + var handle = DocChannel.WriteTransaction(Handle, (uint) (origin?.Length ?? 0), origin); if (handle == nint.Zero) { @@ -532,6 +513,11 @@ internal XmlElement GetXmlElement(nint handle, bool isDeleted) return GetOrAdd(handle, (h, doc) => new XmlElement(h, doc, isDeleted)); } + internal XmlFragment GetXmlFragment(nint handle, bool isDeleted) + { + return GetOrAdd(handle, (h, doc) => new XmlFragment(h, doc, isDeleted)); + } + /// protected override void DisposeCore(bool disposing) { diff --git a/YDotNet/Native/Document/DocChannel.cs b/YDotNet/Native/Document/DocChannel.cs index 9085b639..8c045571 100644 --- a/YDotNet/Native/Document/DocChannel.cs +++ b/YDotNet/Native/Document/DocChannel.cs @@ -81,14 +81,8 @@ internal static class DocChannel [DllImport( ChannelSettings.NativeLib, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yxmlelem")] - public static extern nint XmlElement(nint doc, nint name); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "yxmltext")] - public static extern nint XmlText(nint doc, nint name); + EntryPoint = "yxmlfragment")] + public static extern nint XmlFragment(nint doc, nint name); [DllImport( ChannelSettings.NativeLib, From 1be876a78fefe55fcc7a3004049f6c5480ec565c Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:05:56 -0300 Subject: [PATCH 20/75] feat: update `Transaction` to only allow getting root-level `XmlFragment` --- YDotNet/Document/Transactions/Transaction.cs | 50 +++++++------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/YDotNet/Document/Transactions/Transaction.cs b/YDotNet/Document/Transactions/Transaction.cs index 5dbaf53c..41f1a478 100644 --- a/YDotNet/Document/Transactions/Transaction.cs +++ b/YDotNet/Document/Transactions/Transaction.cs @@ -1,8 +1,7 @@ using YDotNet.Document.Options; using YDotNet.Document.Types.Maps; using YDotNet.Document.Types.Texts; -using YDotNet.Document.Types.XmlElements; -using YDotNet.Document.Types.XmlTexts; +using YDotNet.Document.Types.XmlFragments; using YDotNet.Infrastructure; using YDotNet.Infrastructure.Extensions; using YDotNet.Native.Transaction; @@ -121,7 +120,7 @@ public byte[] StateVectorV1() public byte[] StateDiffV1(byte[]? stateVector) { var handle = TransactionChannel.StateDiffV1( - Handle, stateVector, (uint)(stateVector?.Length ?? 0), out var length); + Handle, stateVector, (uint) (stateVector?.Length ?? 0), out var length); return MemoryReader.ReadAndDestroyBytes(handle, length); } @@ -155,7 +154,7 @@ public byte[] StateDiffV2(byte[]? stateVector) var handle = TransactionChannel.StateDiffV2( Handle, stateVector, - (uint)(stateVector?.Length ?? 0), + (uint) (stateVector?.Length ?? 0), out var length); return MemoryReader.ReadAndDestroyBytes(handle, length); @@ -172,7 +171,7 @@ public byte[] StateDiffV2(byte[]? stateVector) /// The result of the update operation. public TransactionUpdateResult ApplyV1(byte[] stateDiff) { - return (TransactionUpdateResult)TransactionChannel.ApplyV1(Handle, stateDiff, (uint)stateDiff.Length); + return (TransactionUpdateResult) TransactionChannel.ApplyV1(Handle, stateDiff, (uint) stateDiff.Length); } /// @@ -186,7 +185,7 @@ public TransactionUpdateResult ApplyV1(byte[] stateDiff) /// The result of the update operation. public TransactionUpdateResult ApplyV2(byte[] stateDiff) { - return (TransactionUpdateResult)TransactionChannel.ApplyV2(Handle, stateDiff, (uint)stateDiff.Length); + return (TransactionUpdateResult) TransactionChannel.ApplyV2(Handle, stateDiff, (uint) stateDiff.Length); } /// @@ -238,7 +237,7 @@ public byte[] Snapshot() var handle = TransactionChannel.EncodeStateFromSnapshotV1( Handle, snapshot, - (uint)snapshot.Length, + (uint) snapshot.Length, out var length); return handle != nint.Zero ? MemoryReader.ReadAndDestroyBytes(handle, length) : null; @@ -275,7 +274,7 @@ public byte[] Snapshot() var handle = TransactionChannel.EncodeStateFromSnapshotV2( Handle, snapshot, - (uint)snapshot.Length, + (uint) snapshot.Length, out var length); return handle != nint.Zero ? MemoryReader.ReadAndDestroyBytes(handle, length) : null; @@ -330,36 +329,19 @@ public byte[] Snapshot() } /// - /// Returns the at the root level, identified by , - /// or - /// null if no entry was defined under before. - /// - /// The name of the instance to get. - /// - /// The at the root level, identified by , or - /// null if no entry was defined under before. - /// - public XmlElement? GetXmlElement(string name) - { - var handle = GetWithKind(name, BranchKind.XmlElement); - - return handle != nint.Zero ? doc.GetXmlElement(handle, isDeleted: false) : null; - } - - /// - /// Returns the at the root level, identified by , or - /// null if no entry was defined under before. + /// Returns the at the root level, identified by + /// , or null if no entry was defined under before. /// - /// The name of the instance to get. + /// The name of the instance to get. /// - /// The at the root level, identified by , or - /// null if no entry was defined under before. + /// The at the root level, identified by , + /// or null if no entry was defined under before. /// - public XmlText? GetXmlText(string name) + public XmlFragment? GetXmlFragment(string name) { - var handle = GetWithKind(name, BranchKind.XmlText); + var handle = GetWithKind(name, BranchKind.XmlFragment); - return handle != nint.Zero ? doc.GetXmlText(handle, isDeleted: false) : null; + return handle != nint.Zero ? doc.GetXmlFragment(handle, isDeleted: false) : null; } private nint GetWithKind(string name, BranchKind expectedKind) @@ -372,7 +354,7 @@ private nint GetWithKind(string name, BranchKind expectedKind) return nint.Zero; } - var branchKind = (BranchKind)BranchChannel.Kind(branchHandle); + var branchKind = (BranchKind) BranchChannel.Kind(branchHandle); if (branchKind == BranchKind.Null) { From 7ef9c0da7c01b52bd7896c21ee7a8b7ca15d9844 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:07:35 -0300 Subject: [PATCH 21/75] feat: update `EventBranch` to expose `XmlFragmentEvent` --- YDotNet/Document/Types/Events/EventBranch.cs | 37 +++++++++----------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/YDotNet/Document/Types/Events/EventBranch.cs b/YDotNet/Document/Types/Events/EventBranch.cs index e88c6831..c011e17c 100644 --- a/YDotNet/Document/Types/Events/EventBranch.cs +++ b/YDotNet/Document/Types/Events/EventBranch.cs @@ -2,6 +2,7 @@ using YDotNet.Document.Types.Maps.Events; using YDotNet.Document.Types.Texts.Events; using YDotNet.Document.Types.XmlElements.Events; +using YDotNet.Document.Types.XmlFragments.Events; using YDotNet.Document.Types.XmlTexts.Events; using YDotNet.Native; using YDotNet.Native.Document.Events; @@ -18,7 +19,7 @@ public class EventBranch internal EventBranch(NativeWithHandle native, Doc doc) { - Tag = (EventBranchTag)native.Value.Tag; + Tag = (EventBranchTag) native.Value.Tag; value = BuildValue(native, doc, Tag); } @@ -58,30 +59,26 @@ internal EventBranch(NativeWithHandle native, Doc doc) /// Value is not a . public XmlTextEvent XmlTextEvent => GetValue(EventBranchTag.XmlText); + /// + /// Gets the value. + /// + /// Value is not a . + public XmlFragmentEvent XmlFragmentEvent => GetValue(EventBranchTag.XmlFragment); + private static object? BuildValue(NativeWithHandle native, Doc doc, EventBranchTag tag) { var handle = native.Value.ValueHandle(native.Handle); - switch (tag) + return tag switch { - case EventBranchTag.Map: - return new MapEvent(handle, doc); - - case EventBranchTag.Text: - return new TextEvent(handle, doc); - - case EventBranchTag.Array: - return new ArrayEvent(handle, doc); - - case EventBranchTag.XmlElement: - return new XmlElementEvent(handle, doc); - - case EventBranchTag.XmlText: - return new XmlTextEvent(handle, doc); - - default: - return null; - } + EventBranchTag.Map => new MapEvent(handle, doc), + EventBranchTag.Text => new TextEvent(handle, doc), + EventBranchTag.Array => new ArrayEvent(handle, doc), + EventBranchTag.XmlElement => new XmlElementEvent(handle, doc), + EventBranchTag.XmlText => new XmlTextEvent(handle, doc), + EventBranchTag.XmlFragment => new XmlFragmentEvent(handle, doc), + _ => null + }; } private T GetValue(EventBranchTag expectedType) From fa0c56361c7756fbb6ed4d90c589e42720c7c5bb Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:45:22 -0300 Subject: [PATCH 22/75] test: update existing unit tests to use root-level `XmlFragment` when needed --- .../Branches/ReadTransactionTests.cs | 22 ++------ .../Branches/WriteTransactionTests.cs | 18 +------ .../Branches/XmlElementObserveDeepTests.cs | 6 ++- .../Branches/XmlElementUnobserveDeepTests.cs | 11 +++- .../Branches/XmlTextUnobserveDeepTests.cs | 11 +++- .../Document/ReadTransactionTests.cs | 18 +------ .../Document/WriteTransactionTests.cs | 18 +------ .../StickyIndexes/ReadTests.cs | 17 +++--- .../StickyIndexes/StickyIndexTests.cs | 8 ++- .../Transactions/GetTests.cs | 23 +++----- .../UndoManagers/ObserveAddedTests.cs | 31 +++++------ .../UndoManagers/ObservePoppedTests.cs | 25 +++++---- .../UndoManagers/RedoTests.cs | 18 +++++-- .../UndoManagers/UndoTests.cs | 18 +++++-- .../XmlElements/ChildLengthTests.cs | 31 ++++++++++- .../XmlElements/CreateTests.cs | 5 +- .../XmlElements/FirstChildTests.cs | 29 ++++++++-- .../XmlElements/GetAttributeTests.cs | 22 ++++++-- .../XmlElements/GetTests.cs | 15 ++++-- .../XmlElements/InsertElementTests.cs | 16 ++++-- .../XmlElements/InsertTextTests.cs | 16 ++++-- .../XmlElements/IterateTests.cs | 22 ++++++-- .../XmlElements/NextSiblingTests.cs | 7 ++- .../XmlElements/ObserveTests.cs | 54 ++++++++++++++----- .../XmlElements/ParentTests.cs | 22 ++++++-- .../XmlElements/PreviousSiblingTests.cs | 7 ++- .../XmlElements/RemoveRangeTests.cs | 15 ++++-- .../XmlElements/StringTests.cs | 18 +++++-- .../XmlElements/TagTests.cs | 12 +++-- .../XmlElements/TreeWalkerTests.cs | 22 ++++++-- .../XmlElements/UnobserveTests.cs | 8 ++- .../XmlTexts/CreateTests.cs | 5 +- .../XmlTexts/FormatTests.cs | 3 +- .../XmlTexts/GetAttributeTests.cs | 3 +- .../XmlTexts/InsertAttributeTests.cs | 3 +- .../XmlTexts/InsertEmbedTests.cs | 3 +- .../XmlTexts/InsertTexts.cs | 16 ++++-- .../XmlTexts/IterateTests.cs | 14 +++-- .../XmlTexts/LengthTests.cs | 16 ++++-- .../XmlTexts/NextSiblingTests.cs | 3 +- .../XmlTexts/ObserveTests.cs | 52 +++++++++++++----- .../XmlTexts/PreviousSiblingTests.cs | 3 +- .../XmlTexts/RemoveAttributeTests.cs | 3 +- .../XmlTexts/RemoveRangeTests.cs | 36 ++++++++++--- .../XmlTexts/StringTests.cs | 32 ++++++++--- .../XmlTexts/UnobserveTests.cs | 8 ++- 46 files changed, 527 insertions(+), 238 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Branches/ReadTransactionTests.cs b/Tests/YDotNet.Tests.Unit/Branches/ReadTransactionTests.cs index aa46409f..d126a46c 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/ReadTransactionTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/ReadTransactionTests.cs @@ -57,7 +57,7 @@ public void StartReadTransactionWhileWriteTransactionIsOpen() { // Arrange var doc = new Doc(); - Branch branch = doc.XmlElement("branch"); + Branch branch = doc.XmlFragment("branch"); // Act var writeTransaction = branch.WriteTransaction(); @@ -72,7 +72,7 @@ public void StartReadTransactionWhileDocumentWriteTransactionIsOpen() { // Arrange var doc = new Doc(); - Branch branch = doc.XmlText("branch"); + Branch branch = doc.XmlFragment("branch"); // Act var documentTransaction = doc.WriteTransaction(); @@ -125,7 +125,7 @@ public void GetRootTextWithOpenTransactionNotAllowed() } [Test] - public void GetRootXmlTextWithOpenTransactionNotAllowed() + public void GetRootXmlFragmentWithOpenTransactionNotAllowed() { // Arrange var doc = new Doc(); @@ -135,20 +135,6 @@ public void GetRootXmlTextWithOpenTransactionNotAllowed() map.Length(map.ReadTransaction()); // Assert - Assert.Throws(() => doc.XmlText("XmlText")); - } - - [Test] - public void GetRootXmlElementWithOpenTransactionNotAllowed() - { - // Arrange - var doc = new Doc(); - var map = doc.Map("Map"); - - // Keep the transaction open. - map.Length(map.ReadTransaction()); - - // Assert - Assert.Throws(() => doc.XmlElement("XmlElement")); + Assert.Throws(() => doc.XmlFragment("xml-fragment")); } } diff --git a/Tests/YDotNet.Tests.Unit/Branches/WriteTransactionTests.cs b/Tests/YDotNet.Tests.Unit/Branches/WriteTransactionTests.cs index 2830f798..c13ce422 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/WriteTransactionTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/WriteTransactionTests.cs @@ -123,7 +123,7 @@ public void GetRootTextWithOpenTransactionNotAllowed() } [Test] - public void GetRootXmlTextWithOpenTransactionNotAllowed() + public void GetRootXmlFragmentWithOpenTransactionNotAllowed() { // Arrange var doc = new Doc(); @@ -133,20 +133,6 @@ public void GetRootXmlTextWithOpenTransactionNotAllowed() map.Length(map.WriteTransaction()); // Assert - Assert.Throws(() => doc.XmlText("XmlText")); - } - - [Test] - public void GetRootXmlElementWithOpenTransactionNotAllowed() - { - // Arrange - var doc = new Doc(); - var map = doc.Map("Map"); - - // Keep the transaction open. - map.Length(map.WriteTransaction()); - - // Assert - Assert.Throws(() => doc.XmlElement("XmlElement")); + Assert.Throws(() => doc.XmlFragment("xml-fragment")); } } diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlElementObserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlElementObserveDeepTests.cs index 3007d4ec..bd3dc1ab 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/XmlElementObserveDeepTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlElementObserveDeepTests.cs @@ -131,9 +131,13 @@ public void ObserveDeepHasPathWhenRemovedAttributes() private (Doc, XmlElement, XmlElement, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement1 = doc.XmlElement("xml-element-1"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement1 = xmlFragment.InsertElement(transaction, index: 0, "xml-element-1"); + transaction.Commit(); + + transaction = doc.WriteTransaction(); xmlElement1.InsertText(transaction, index: 0); xmlElement1.InsertText(transaction, index: 1); var xmlElement2 = xmlElement1.InsertElement(transaction, index: 2, "xml-element-2"); diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlElementUnobserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlElementUnobserveDeepTests.cs index a4b6d3fb..0c834515 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/XmlElementUnobserveDeepTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlElementUnobserveDeepTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using YDotNet.Document; +using YDotNet.Document.Cells; namespace YDotNet.Tests.Unit.Branches; @@ -10,12 +11,18 @@ public void TriggersWhenMapChangedUntilUnobserved() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var map = doc.Map("map"); + + var transaction = doc.WriteTransaction(); + map.Insert(transaction, "xml-element", Input.XmlElement("xml-element")); + var xmlElement = map.Get(transaction, "xml-element").XmlElement; + transaction.Commit(); + var called = 0; var subscription = xmlElement.ObserveDeep(_ => called++); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlTextUnobserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlTextUnobserveDeepTests.cs index 5f641f0c..26d4f1d5 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/XmlTextUnobserveDeepTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlTextUnobserveDeepTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using YDotNet.Document; +using YDotNet.Document.Cells; namespace YDotNet.Tests.Unit.Branches; @@ -10,12 +11,18 @@ public void TriggersWhenChangedUntilUnobserved() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var map = doc.Map("map"); + + var transaction = doc.WriteTransaction(); + map.Insert(transaction, "xml-text", Input.XmlText("xml-text")); + var xmlText = map.Get(transaction, "xml-text").XmlText; + transaction.Commit(); + var called = 0; var subscription = xmlText.ObserveDeep(_ => called++); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "World"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs b/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs index 38cebf06..c845eb1e 100644 --- a/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs +++ b/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs @@ -75,7 +75,7 @@ public void GetRootTextWithOpenTransactionNotAllowed() } [Test] - public void GetRootXmlTextWithOpenTransactionNotAllowed() + public void GetRootXmlFragmentWithOpenTransactionNotAllowed() { // Arrange var doc = new Doc(); @@ -85,20 +85,6 @@ public void GetRootXmlTextWithOpenTransactionNotAllowed() map.Length(doc.ReadTransaction()); // Assert - Assert.Throws(() => doc.XmlText("XmlText")); - } - - [Test] - public void GetRootXmlElementWithOpenTransactionNotAllowed() - { - // Arrange - var doc = new Doc(); - var map = doc.Map("Map"); - - // Keep the transaction open. - map.Length(doc.ReadTransaction()); - - // Assert - Assert.Throws(() => doc.XmlElement("XmlElement")); + Assert.Throws(() => doc.XmlFragment("xml-fragment")); } } diff --git a/Tests/YDotNet.Tests.Unit/Document/WriteTransactionTests.cs b/Tests/YDotNet.Tests.Unit/Document/WriteTransactionTests.cs index 1f48f6ce..8c3653ce 100644 --- a/Tests/YDotNet.Tests.Unit/Document/WriteTransactionTests.cs +++ b/Tests/YDotNet.Tests.Unit/Document/WriteTransactionTests.cs @@ -72,7 +72,7 @@ public void GetRootTextWithOpenTransactionNotAllowed() } [Test] - public void GetRootXmlTextWithOpenTransactionNotAllowed() + public void GetRootXmlFragmentWithOpenTransactionNotAllowed() { // Arrange var doc = new Doc(); @@ -82,20 +82,6 @@ public void GetRootXmlTextWithOpenTransactionNotAllowed() map.Length(doc.WriteTransaction()); // Assert - Assert.Throws(() => doc.XmlText("XmlText")); - } - - [Test] - public void GetRootXmlElementWithOpenTransactionNotAllowed() - { - // Arrange - var doc = new Doc(); - var map = doc.Map("Map"); - - // Keep the transaction open. - map.Length(doc.WriteTransaction()); - - // Assert - Assert.Throws(() => doc.XmlElement("XmlElement")); + Assert.Throws(() => doc.XmlFragment("xml-fragment")); } } diff --git a/Tests/YDotNet.Tests.Unit/StickyIndexes/ReadTests.cs b/Tests/YDotNet.Tests.Unit/StickyIndexes/ReadTests.cs index a5166f1b..85833070 100644 --- a/Tests/YDotNet.Tests.Unit/StickyIndexes/ReadTests.cs +++ b/Tests/YDotNet.Tests.Unit/StickyIndexes/ReadTests.cs @@ -54,7 +54,7 @@ public void ReadIndexFromArray() var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] { Input.Long(value: 2469L), Input.Null(), Input.Boolean(value: false) }); + transaction, index: 0, Input.Long(value: 2469L), Input.Null(), Input.Boolean(value: false)); var stickyIndexBefore = array.StickyIndex(transaction, index: 1, StickyAssociationType.Before); var stickyIndexAfter = array.StickyIndex(transaction, index: 1, StickyAssociationType.After); transaction.Commit(); @@ -71,10 +71,10 @@ public void ReadIndexFromArray() // Act transaction = doc.WriteTransaction(); - array.InsertRange(transaction, index: 1, new[] { Input.String("(") }); - array.InsertRange(transaction, index: 3, new[] { Input.String(")") }); - array.InsertRange(transaction, index: 4, new[] { Input.String(" Viana") }); - array.InsertRange(transaction, index: 0, new[] { Input.String("Hello, ") }); + array.InsertRange(transaction, index: 1, Input.String("(")); + array.InsertRange(transaction, index: 3, Input.String(")")); + array.InsertRange(transaction, index: 4, Input.String(" Viana")); + array.InsertRange(transaction, index: 0, Input.String("Hello, ")); beforeIndex = stickyIndexBefore.Read(transaction); afterIndex = stickyIndexAfter.Read(transaction); transaction.Commit(); @@ -89,9 +89,14 @@ public void ReadIndexFromXmlText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); var stickyIndexBefore = xmlText.StickyIndex(transaction, index: 3, StickyAssociationType.Before); var stickyIndexAfter = xmlText.StickyIndex(transaction, index: 3, StickyAssociationType.After); diff --git a/Tests/YDotNet.Tests.Unit/StickyIndexes/StickyIndexTests.cs b/Tests/YDotNet.Tests.Unit/StickyIndexes/StickyIndexTests.cs index 064b6e9d..eea409aa 100644 --- a/Tests/YDotNet.Tests.Unit/StickyIndexes/StickyIndexTests.cs +++ b/Tests/YDotNet.Tests.Unit/StickyIndexes/StickyIndexTests.cs @@ -49,10 +49,14 @@ public void CreateFromXmlText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var stickyIndexAfter = xmlText.StickyIndex(transaction, index: 0, StickyAssociationType.After); var stickyIndexBefore = xmlText.StickyIndex(transaction, index: 0, StickyAssociationType.Before); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/Transactions/GetTests.cs b/Tests/YDotNet.Tests.Unit/Transactions/GetTests.cs index 9f44ecbd..8203f833 100644 --- a/Tests/YDotNet.Tests.Unit/Transactions/GetTests.cs +++ b/Tests/YDotNet.Tests.Unit/Transactions/GetTests.cs @@ -16,16 +16,14 @@ public void GetOnUndefinedKeyReturnsNull() var array = transaction.GetArray("array"); var map = transaction.GetMap("map"); var text = transaction.GetText("text"); - var xmlElement = transaction.GetXmlElement("xml-element"); - var xmlText = transaction.GetXmlText("xml-text"); + var xmlFragment = transaction.GetXmlFragment("xml-element"); transaction.Commit(); // Assert Assert.That(array, Is.Null); Assert.That(map, Is.Null); Assert.That(text, Is.Null); - Assert.That(xmlElement, Is.Null); - Assert.That(xmlText, Is.Null); + Assert.That(xmlFragment, Is.Null); } [Test] @@ -36,24 +34,21 @@ public void GetOnDefinedKeyWithCorrectTypeReturnsValue() doc.Array("array"); doc.Map("map"); doc.Text("text"); - doc.XmlElement("xml-element"); - doc.XmlText("xml-text"); + doc.XmlFragment("xml-fragment"); // Act var transaction = doc.ReadTransaction(); var array = transaction.GetArray("array"); var map = transaction.GetMap("map"); var text = transaction.GetText("text"); - var xmlElement = transaction.GetXmlElement("xml-element"); - var xmlText = transaction.GetXmlText("xml-text"); + var xmlFragment = transaction.GetXmlFragment("xml-fragment"); transaction.Commit(); // Assert Assert.That(array, Is.Not.Null); Assert.That(map, Is.Not.Null); Assert.That(text, Is.Not.Null); - Assert.That(xmlElement, Is.Not.Null); - Assert.That(xmlText, Is.Not.Null); + Assert.That(xmlFragment, Is.Not.Null); } [Test] @@ -64,16 +59,14 @@ public void GetOnDefinedKeyWithWrongTypeThrowsException() doc.Array("array"); doc.Map("map"); doc.Text("text"); - doc.XmlElement("xml-element"); - doc.XmlText("xml-text"); + doc.XmlFragment("xml-fragment"); // Act var transaction = doc.ReadTransaction(); Assert.Throws(() => transaction.GetArray("map")); Assert.Throws(() => transaction.GetMap("text")); - Assert.Throws(() => transaction.GetText("xml-element")); - Assert.Throws(() => transaction.GetXmlElement("xml-text")); - Assert.Throws(() => transaction.GetXmlText("array")); + Assert.Throws(() => transaction.GetText("xml-fragment")); + Assert.Throws(() => transaction.GetXmlFragment("array")); transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs index 481dc935..bc5c4c88 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs @@ -92,12 +92,7 @@ public void TriggersAfterAddingAndRemovingContentOnArray() // Act var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Long(value: 2469L), - Input.Boolean(value: false), - Input.String("Lucas") - }); + transaction, index: 0, Input.Long(value: 2469L), Input.Boolean(value: false), Input.String("Lucas")); transaction.Commit(); // Assert @@ -111,11 +106,7 @@ public void TriggersAfterAddingAndRemovingContentOnArray() undoEvent = null; transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 2, new[] - { - Input.Bytes(new byte[] { 2, 4, 6, 9 }), - Input.XmlText("Lucas") - }); + transaction, index: 2, Input.Bytes(new byte[] { 2, 4, 6, 9 }), Input.XmlText("Lucas")); transaction.Commit(); // Assert @@ -204,7 +195,12 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() { // Arrange var doc = new Doc(new DocOptions { Id = 7853 }); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + var undoManager = new UndoManager( doc, xmlText, new UndoManagerOptions { @@ -215,7 +211,7 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() undoManager.ObserveAdded(e => undoEvent = e); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); @@ -272,7 +268,12 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() { // Arrange var doc = new Doc(new DocOptions { Id = 8137 }); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + var undoManager = new UndoManager( doc, xmlElement, new UndoManagerOptions { @@ -283,7 +284,7 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() undoManager.ObserveAdded(e => undoEvent = e); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); var xmlText = xmlElement.InsertText(transaction, index: 0); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs index 3c66ab21..0f43c207 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs @@ -85,12 +85,7 @@ public void TriggersAfterAddingAndRemovingContentOnArray() // Act var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Long(value: 2469L), - Input.Boolean(value: false), - Input.Undefined() - }); + transaction, index: 0, Input.Long(value: 2469L), Input.Boolean(value: false), Input.Undefined()); transaction.Commit(); undoManager.Undo(); @@ -204,14 +199,19 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() { // Arrange var doc = new Doc(new DocOptions { Id = 7938 }); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + var undoManager = new UndoManager(doc, xmlText, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); UndoEvent? undoEvent = null; undoManager.ObservePopped(e => undoEvent = e); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); undoManager.Undo(); @@ -291,14 +291,19 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() { // Arrange var doc = new Doc(new DocOptions { Id = 5903 }); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + var undoManager = new UndoManager(doc, xmlElement, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); UndoEvent? undoEvent = null; undoManager.ObservePopped(e => undoEvent = e); // Act (add element and undo) - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "color"); transaction.Commit(); undoManager.Undo(); diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs index ecfe3dc5..d97eb09f 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs @@ -191,9 +191,14 @@ public void RedoAddingAndUpdatingAndRemovingContentOnXmlText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); - var undoManager = new UndoManager(doc, xmlText, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + var xmlFragment = doc.XmlFragment("xml-fragment"); + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + var undoManager = new UndoManager(doc, xmlText, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertAttribute(transaction, "bold", "true"); xmlText.InsertEmbed(transaction, index: 3, Input.Boolean(value: true)); @@ -245,9 +250,14 @@ public void RedoAddingAndUpdatingAndRemovingContentOnXmlElement() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); - var undoManager = new UndoManager(doc, xmlElement, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + var xmlFragment = doc.XmlFragment("xml-fragment"); + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + var undoManager = new UndoManager(doc, xmlElement, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertAttribute(transaction, "bold", "true"); xmlElement.InsertElement(transaction, index: 1, "color"); diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs index b63de805..196817f5 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs @@ -184,9 +184,14 @@ public void UndoAddingAndUpdatingAndRemovingContentOnXmlText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); - var undoManager = new UndoManager(doc, xmlText, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + var xmlFragment = doc.XmlFragment("xml-fragment"); + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + var undoManager = new UndoManager(doc, xmlText, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertAttribute(transaction, "bold", "true"); xmlText.InsertEmbed(transaction, index: 3, Input.Boolean(value: true)); @@ -233,9 +238,14 @@ public void UndoAddingAndUpdatingAndRemovingContentOnXmlElement() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); - var undoManager = new UndoManager(doc, xmlElement, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + var xmlFragment = doc.XmlFragment("xml-fragment"); + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + var undoManager = new UndoManager(doc, xmlElement, new UndoManagerOptions { CaptureTimeoutMilliseconds = 0 }); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertAttribute(transaction, "bold", "true"); xmlElement.InsertElement(transaction, index: 1, "color"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/ChildLengthTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/ChildLengthTests.cs index a5aea81e..f1fced5c 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/ChildLengthTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/ChildLengthTests.cs @@ -10,14 +10,41 @@ public void InitialLengthIsZero() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var childLength = xmlElement.ChildLength(transaction); transaction.Commit(); // Assert Assert.That(childLength, Is.EqualTo(expected: 0)); } + + [Test] + public void ChildLengthMatchesAmountOfChildrenAdded() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + xmlElement.InsertElement(transaction, index: 0, "xml-element-child-1"); + xmlElement.InsertElement(transaction, index: 1, "xml-element-child-2"); + xmlElement.InsertText(transaction, index: 2); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var childLength = xmlElement.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 3)); + } } diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/CreateTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/CreateTests.cs index 8e60bd6a..ead2c864 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/CreateTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/CreateTests.cs @@ -10,9 +10,12 @@ public void Create() { // Arrange var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); // Act - var xmlElement = doc.XmlElement("xml-element"); + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Assert Assert.That(xmlElement.Handle, Is.GreaterThan(nint.Zero)); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/FirstChildTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/FirstChildTests.cs index 176b96bd..9489e403 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/FirstChildTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/FirstChildTests.cs @@ -10,10 +10,14 @@ public void FirstChildOfRootEmptyNodeIsNull() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var childXmlElement = xmlElement.FirstChild(transaction); transaction.Commit(); @@ -26,9 +30,14 @@ public void FirstChildOfRootFilledNodeIsCorrect() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "color"); xmlElement.InsertText(transaction, index: 2); @@ -48,9 +57,14 @@ public void FirstChildOfNestedEmptyNodeIsNull() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "color"); var childXmlElement = xmlElement.Get(transaction, index: 0).XmlElement; transaction.Commit(); @@ -69,9 +83,14 @@ public void FirstChildOfNestedFilledNodeIsCorrect() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "color"); var childXmlElement = xmlElement.Get(transaction, index: 0).XmlElement; childXmlElement.InsertElement(transaction, index: 0, "alpha"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/GetAttributeTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/GetAttributeTests.cs index d9668c55..92852f5b 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/GetAttributeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/GetAttributeTests.cs @@ -10,10 +10,14 @@ public void GetAttributeThatDoesNotExistReturnsNull() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var value = xmlElement.GetAttribute(transaction, "href"); transaction.Commit(); @@ -26,9 +30,14 @@ public void GetAttributeThatExistsAndIsEmptyWorks() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", string.Empty); transaction.Commit(); @@ -46,9 +55,14 @@ public void GetAttributeThatExistsAndIsFilledWorks() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/GetTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/GetTests.cs index c0266885..e7853560 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/GetTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/GetTests.cs @@ -11,10 +11,14 @@ public void GetOutsideOfValidBounds() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var value = xmlElement.Get(transaction, index: 1); transaction.Commit(); @@ -55,9 +59,14 @@ public void GetXmlElement() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertText(transaction, index: 1); xmlElement.InsertElement(transaction, index: 2, "color"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs index 83062212..2a562d42 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs @@ -10,10 +10,14 @@ public void InsertSingleElement() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var addedXmlElement = xmlElement.InsertElement(transaction, index: 0, "color"); var childLength = xmlElement.ChildLength(transaction); transaction.Commit(); @@ -29,10 +33,14 @@ public void InsertMultipleElements() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var xmlElement1 = xmlElement.InsertElement(transaction, index: 0, "color"); var xmlElement2 = xmlElement.InsertElement(transaction, index: 0, "width"); var xmlElement3 = xmlElement.InsertElement(transaction, index: 0, "height"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/InsertTextTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/InsertTextTests.cs index e65a478e..90c85d6a 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/InsertTextTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/InsertTextTests.cs @@ -10,10 +10,14 @@ public void InsertSingleText() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var xmlText = xmlElement.InsertText(transaction, index: 0); var childLength = xmlElement.ChildLength(transaction); transaction.Commit(); @@ -28,10 +32,14 @@ public void InsertMultipleTexts() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertText(transaction, index: 0); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/IterateTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/IterateTests.cs index 2c88c191..3a02c0be 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/IterateTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/IterateTests.cs @@ -10,10 +10,14 @@ public void IteratesOnEmpty() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var iterator = xmlElement.Iterate(transaction); var values = iterator.ToArray(); transaction.Commit(); @@ -27,9 +31,14 @@ public void IteratesOnSingleItem() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); @@ -49,9 +58,14 @@ public void IteratesOnMultiItem() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); xmlElement.InsertAttribute(transaction, "as", "document"); xmlElement.InsertAttribute(transaction, "rel", "preload"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/NextSiblingTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/NextSiblingTests.cs index a0a9d9b5..a5a2191d 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/NextSiblingTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/NextSiblingTests.cs @@ -57,9 +57,14 @@ public void GetsNextSiblingAtEnding() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "width"); xmlElement.InsertText(transaction, index: 1); xmlElement.InsertElement(transaction, index: 2, "color"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs index c3130054..9bd0c886 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs @@ -12,13 +12,17 @@ public void ObserveHasTarget() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); XmlElement? target = null; xmlElement.Observe(e => target = e.Target); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); transaction.Commit(); @@ -32,13 +36,17 @@ public void ObserveHasDeltaWhenAddedXmlElementsAndTexts() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); IEnumerable? eventChanges = null; xmlElement.Observe(e => eventChanges = e.Delta.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "color"); xmlElement.InsertText(transaction, index: 2); @@ -60,13 +68,17 @@ public void ObserveDoesNotHaveDeltaWhenAddedAttributes() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); IEnumerable? eventChanges = null; xmlElement.Observe(e => eventChanges = e.Delta.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); @@ -80,13 +92,17 @@ public void ObserveHasKeysWhenAddedAttributes() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); IEnumerable? keyChanges = null; xmlElement.Observe(e => keyChanges = e.Keys.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); xmlElement.InsertAttribute(transaction, "rel", "preload"); xmlElement.InsertAttribute(transaction, "as", "document"); @@ -112,9 +128,14 @@ public void ObserveHasKeysWhenUpdatedAttributes() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); @@ -140,9 +161,14 @@ public void ObserveHasKeysWhenRemovedAttributes() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); @@ -167,13 +193,17 @@ public void ObserveDoesNotHaveKeysWhenAddedXmlElementsAndTexts() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); IEnumerable? keyChanges = null; xmlElement.Observe(e => keyChanges = e.Keys.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "color"); xmlElement.InsertText(transaction, index: 2); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/ParentTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/ParentTests.cs index 052d9fb9..7c37a8f6 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/ParentTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/ParentTests.cs @@ -11,10 +11,14 @@ public void ParentOfRootNodeReturnsNull() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var parentXmlElement = xmlElement.Parent(transaction); transaction.Commit(); @@ -69,9 +73,14 @@ public void ParentOfNestedNodeAtFirstLevelReturnsCorrectParent() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "width"); xmlElement.InsertElement(transaction, index: 1, "color"); transaction.Commit(); @@ -94,9 +103,14 @@ public void ParentOfNestedNodeAtSecondLevelReturnsCorrectParent() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var childXmlElement = xmlElement.InsertElement(transaction, index: 0, "dimensions"); childXmlElement.InsertElement(transaction, index: 0, "width"); childXmlElement.InsertElement(transaction, index: 0, "height"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/PreviousSiblingTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/PreviousSiblingTests.cs index 837348cf..a3dc3d46 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/PreviousSiblingTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/PreviousSiblingTests.cs @@ -57,9 +57,14 @@ public void GetsPreviousSiblingAtEnding() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "width"); xmlElement.InsertText(transaction, index: 1); xmlElement.InsertElement(transaction, index: 2, "color"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/RemoveRangeTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/RemoveRangeTests.cs index 3567549a..e07a13e5 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/RemoveRangeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/RemoveRangeTests.cs @@ -11,10 +11,14 @@ public void RemoveEmptyRangeOnEmptyElement() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.RemoveRange(transaction, index: 0, length: 0); var childLength = xmlElement.ChildLength(transaction); transaction.Commit(); @@ -90,9 +94,14 @@ public void RemoveAllItemsAtOnce() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertText(transaction, index: 1); xmlElement.InsertElement(transaction, index: 2, "color"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/StringTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/StringTests.cs index dde4fed6..3025574c 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/StringTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/StringTests.cs @@ -11,10 +11,14 @@ public void RootLevelNodeHasCorrectStringWithoutChildren() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var text = xmlElement.String(transaction); transaction.Commit(); @@ -27,10 +31,14 @@ public void RootLevelNodeHasCorrectStringWithChildren() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertElement(transaction, index: 0, "color"); var xmlText = xmlElement.InsertText(transaction, index: 1); xmlText.Insert(transaction, index: 0, "red"); @@ -73,7 +81,7 @@ public void NodeNestedOnArrayHasCorrectString() var array = doc.Array("array"); var transaction = doc.WriteTransaction(); - array.InsertRange(transaction, index: 0, new[] { Input.XmlElement("color") }); + array.InsertRange(transaction, index: 0, Input.XmlElement("color")); var xmlElement = array.Get(transaction, index: 0).XmlElement; var xmlText = xmlElement.InsertText(transaction, index: 0); xmlText.Insert(transaction, index: 0, "purple"); diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs index 69687895..7e709570 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs @@ -11,7 +11,11 @@ public void RootNodesHaveUndefinedAsTag() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Act var tag = xmlElement.Tag; @@ -25,11 +29,11 @@ public void NodeNestedOnRootNodeHasCorrectTag() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); // Act var transaction = doc.WriteTransaction(); - var childXmlElement = xmlElement.InsertElement(transaction, index: 0, "color"); + var childXmlElement = xmlFragment.InsertElement(transaction, index: 0, "color"); var tag = childXmlElement.Tag; transaction.Commit(); @@ -65,7 +69,7 @@ public void NodeNestedOnArrayHasCorrectTag() var array = doc.Array("array"); var transaction = doc.WriteTransaction(); - array.InsertRange(transaction, index: 0, new[] { Input.XmlElement("color") }); + array.InsertRange(transaction, index: 0, Input.XmlElement("color")); transaction.Commit(); // Act diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs index 2d40c025..c37cc040 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs @@ -10,10 +10,14 @@ public void WalksOnEmptyTree() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var xmlTreeWalker = xmlElement.TreeWalker(transaction); transaction.Commit(); @@ -27,9 +31,14 @@ public void WalksOnTreeWithSingleLevelOfDepth() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "color"); xmlElement.InsertText(transaction, index: 2); @@ -56,9 +65,14 @@ public void WalksOnTreeWithMultipleLevelsOfDepth() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "color"); var childXmlElement = xmlElement.Get(transaction, index: 1).XmlElement; diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/UnobserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/UnobserveTests.cs index 59e33e8f..86a6b8b2 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/UnobserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/UnobserveTests.cs @@ -10,13 +10,17 @@ public void TriggersWhenXmlElementChangedUntilUnobserved() { // Arrange var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); + transaction.Commit(); var called = 0; var subscription = xmlElement.Observe(_ => called++); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlElement.InsertText(transaction, index: 0); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/CreateTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/CreateTests.cs index 355c7caf..8d33f314 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/CreateTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/CreateTests.cs @@ -10,9 +10,12 @@ public void Create() { // Arrange var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); // Act - var xmlText = doc.XmlText("xml-text"); + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); // Assert Assert.That(xmlText.Handle, Is.GreaterThan(nint.Zero)); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/FormatTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/FormatTests.cs index 2b1df8e4..b1395de0 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/FormatTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/FormatTests.cs @@ -84,9 +84,10 @@ public void FormatsTextAtEnding() private (Doc, XmlText) ArrangeDoc() { var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/GetAttributeTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/GetAttributeTests.cs index dbfb400c..175c5a97 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/GetAttributeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/GetAttributeTests.cs @@ -54,9 +54,10 @@ public void GetAttributeThatExistsAndIsFilledWorks() private (Doc, XmlText) ArrangeDoc() { var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.InsertAttribute(transaction, "empty", string.Empty); xmlText.InsertAttribute(transaction, "number", "7️⃣"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertAttributeTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertAttributeTests.cs index f8a328dc..fb79555b 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertAttributeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertAttributeTests.cs @@ -101,9 +101,10 @@ public void InsertAttributeWithTheSameNameReplacesIt() private static (Doc, XmlText) ArrangeDoc() { var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.Insert(transaction, index: 0, "saturn-🪐"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertEmbedTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertEmbedTests.cs index dacf2a82..0f2c1072 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertEmbedTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertEmbedTests.cs @@ -199,9 +199,10 @@ public void InsertBooleanEmbedWithAttributes() private (Doc, XmlText) ArrangeXmlText() { var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertTexts.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertTexts.cs index 5ce0d3a5..38e2b17a 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/InsertTexts.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/InsertTexts.cs @@ -11,10 +11,14 @@ public void InsertWithoutAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); var text = xmlText.String(transaction); transaction.Commit(); @@ -37,10 +41,14 @@ public void InsertWithAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert( transaction, index: 0, diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/IterateTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/IterateTests.cs index 4af4bbf6..98d99a57 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/IterateTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/IterateTests.cs @@ -10,10 +10,14 @@ public void IteratesOnEmpty() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var iterator = xmlText.Iterate(transaction); var values = iterator.ToArray(); transaction.Commit(); @@ -27,9 +31,10 @@ public void IteratesOnSingleItem() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); transaction.Commit(); @@ -49,9 +54,10 @@ public void IteratesOnMultiItem() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); xmlText.InsertAttribute(transaction, "as", "document"); xmlText.InsertAttribute(transaction, "rel", "preload"); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/LengthTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/LengthTests.cs index f2dd0357..79e3f4a5 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/LengthTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/LengthTests.cs @@ -11,10 +11,14 @@ public void LengthIsInitiallyZero() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); var length = xmlText.Length(transaction); transaction.Commit(); @@ -27,10 +31,14 @@ public void LengthIncreasesWhenTextIsAdded() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Greetings"); var length = xmlText.Length(transaction); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/NextSiblingTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/NextSiblingTests.cs index 46e52bec..02bccc5a 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/NextSiblingTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/NextSiblingTests.cs @@ -57,9 +57,10 @@ public void GetsNextSiblingAtEnding() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "width"); xmlElement.InsertText(transaction, index: 2); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/ObserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/ObserveTests.cs index d888476a..fb1dfb2c 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/ObserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/ObserveTests.cs @@ -13,13 +13,17 @@ public void ObserveHasTarget() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); XmlText? target = null; var subscription = xmlText.Observe(e => target = e.Target); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); @@ -33,13 +37,17 @@ public void ObserveHasDeltaWhenAddedTextsAndEmbeds() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); IEnumerable? deltas = null; xmlText.Observe(e => deltas = e.Delta.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertEmbed( transaction, index: 3, Input.Boolean(value: true), Input.Object( @@ -78,13 +86,17 @@ public void ObserveDoesNotHaveDeltaWhenAddedAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); IEnumerable? deltas = null; xmlText.Observe(e => deltas = e.Delta.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.InsertAttribute(transaction, "color", "red"); transaction.Commit(); @@ -98,13 +110,17 @@ public void ObserveHasKeysWhenAddedAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); IEnumerable? deltas = null; xmlText.Observe(e => deltas = e.Keys.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.InsertAttribute(transaction, "color", "red"); xmlText.InsertAttribute(transaction, "width", "16"); transaction.Commit(); @@ -123,9 +139,13 @@ public void ObserveHasKeysWhenUpdatedAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + transaction = doc.WriteTransaction(); xmlText.InsertAttribute(transaction, "color", "red"); transaction.Commit(); @@ -150,9 +170,13 @@ public void ObserveHasKeysWhenRemovedAttributes() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + transaction = doc.WriteTransaction(); xmlText.InsertAttribute(transaction, "color", "red"); transaction.Commit(); @@ -177,13 +201,17 @@ public void ObserveDoesNotHaveKeysWhenAddedTextsAndEmbeds() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); IEnumerable? keyChanges = null; xmlText.Observe(e => keyChanges = e.Keys.ToArray()); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertEmbed(transaction, index: 3, Input.Boolean(value: true)); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/PreviousSiblingTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/PreviousSiblingTests.cs index 92e37ee5..d7613e56 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/PreviousSiblingTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/PreviousSiblingTests.cs @@ -57,9 +57,10 @@ public void GetsPreviousSiblingAtEnding() private (Doc, XmlElement) ArrangeDoc() { var doc = new Doc(); - var xmlElement = doc.XmlElement("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); xmlElement.InsertText(transaction, index: 0); xmlElement.InsertElement(transaction, index: 1, "width"); xmlElement.InsertText(transaction, index: 2); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveAttributeTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveAttributeTests.cs index 3d78fd5d..292071df 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveAttributeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveAttributeTests.cs @@ -45,9 +45,10 @@ public void RemoveAttributeThatExists() private (Doc, XmlText) ArrangeDoc() { var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); xmlText.InsertAttribute(transaction, "empty", string.Empty); xmlText.InsertAttribute(transaction, "number", "7️⃣"); transaction.Commit(); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveRangeTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveRangeTests.cs index b21765d6..0e091722 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveRangeTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/RemoveRangeTests.cs @@ -11,10 +11,14 @@ public void RemoveNothing() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.RemoveRange(transaction, index: 0, length: 0); var text = xmlText.String(transaction); transaction.Commit(); @@ -28,9 +32,14 @@ public void RemovePartialText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); @@ -49,9 +58,14 @@ public void RemoveFullText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); @@ -70,9 +84,14 @@ public void RemoveBooleanEmbed() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertEmbed(transaction, index: 2, Input.Boolean(value: true)); transaction.Commit(); @@ -101,9 +120,14 @@ public void RemoveObjectEmbed() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); xmlText.InsertEmbed( transaction, index: 2, Input.Object( diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/StringTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/StringTests.cs index ee8c4047..919e299b 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/StringTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/StringTests.cs @@ -11,10 +11,14 @@ public void StringIsInitiallyEmpty() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); // Act - var transaction = doc.ReadTransaction(); + transaction = doc.ReadTransaction(); var text = xmlText.String(transaction); transaction.Commit(); @@ -27,10 +31,14 @@ public void StringShowsInsertedText() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas Viana"); var text = xmlText.String(transaction); transaction.Commit(); @@ -44,10 +52,14 @@ public void StringDoesNotShowInsertedAttribute() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas Viana"); xmlText.InsertAttribute(transaction, "color", "red"); var text = xmlText.String(transaction); @@ -62,10 +74,14 @@ public void StringShowsInsertedEmbed() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-text"); + var xmlFragment = doc.XmlFragment("xml-fragment"); - // Act var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Act + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas Viana"); xmlText.InsertEmbed(transaction, index: 3, Input.Boolean(value: true)); xmlText.InsertEmbed(transaction, index: 8, Input.Long(value: 2469L)); diff --git a/Tests/YDotNet.Tests.Unit/XmlTexts/UnobserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlTexts/UnobserveTests.cs index 1fe59ffe..affeab86 100644 --- a/Tests/YDotNet.Tests.Unit/XmlTexts/UnobserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlTexts/UnobserveTests.cs @@ -10,13 +10,17 @@ public void TriggersWhenXmlTextChangedUntilUnobserved() { // Arrange var doc = new Doc(); - var xmlText = doc.XmlText("xml-element"); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); var called = 0; var subscription = xmlText.Observe(_ => called++); // Act - var transaction = doc.WriteTransaction(); + transaction = doc.WriteTransaction(); xmlText.Insert(transaction, index: 0, "Lucas"); transaction.Commit(); From fee50a175fac174f90e538186dc5634c84741ba4 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:46:24 -0300 Subject: [PATCH 23/75] test: introduce unit tests for `XmlFragment` --- .../XmlFragments/ChildLengthTests.cs | 46 ++++++++ .../XmlFragments/CreateTests.cs | 20 ++++ .../XmlFragments/FirstChildTests.cs | 92 +++++++++++++++ .../XmlFragments/GetTests.cs | 71 ++++++++++++ .../XmlFragments/InsertElementTests.cs | 48 ++++++++ .../XmlFragments/InsertTextTests.cs | 44 ++++++++ .../XmlFragments/ObserveTests.cs | 57 ++++++++++ .../XmlFragments/RemoveRangeTests.cs | 106 ++++++++++++++++++ .../XmlFragments/TreeWalkerTests.cs | 91 +++++++++++++++ .../XmlFragments/UnobserveTests.cs | 36 ++++++ 10 files changed, 611 insertions(+) create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/ChildLengthTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/CreateTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/FirstChildTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/GetTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/InsertTextTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/RemoveRangeTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/XmlFragments/UnobserveTests.cs diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/ChildLengthTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/ChildLengthTests.cs new file mode 100644 index 00000000..928d64f8 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/ChildLengthTests.cs @@ -0,0 +1,46 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class ChildLengthTests +{ + [Test] + public void InitialLengthIsZero() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.ReadTransaction(); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 0)); + } + + [Test] + public void ChildLengthMatchesAmountOfChildrenAdded() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + xmlFragment.InsertElement(transaction, index: 0, "xml-element-child-1"); + xmlFragment.InsertElement(transaction, index: 1, "xml-element-child-2"); + xmlFragment.InsertText(transaction, index: 2); + xmlFragment.InsertText(transaction, index: 3); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 4)); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/CreateTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/CreateTests.cs new file mode 100644 index 00000000..f90f7624 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/CreateTests.cs @@ -0,0 +1,20 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class CreateTests +{ + [Test] + public void Create() + { + // Arrange + var doc = new Doc(); + + // Act + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Assert + Assert.That(xmlFragment.Handle, Is.GreaterThan(nint.Zero)); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/FirstChildTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/FirstChildTests.cs new file mode 100644 index 00000000..36a3a722 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/FirstChildTests.cs @@ -0,0 +1,92 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class FirstChildTests +{ + [Test] + public void FirstChildOfRootEmptyNodeIsNull() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.ReadTransaction(); + var childXmlElement = xmlFragment.FirstChild(transaction); + transaction.Commit(); + + // Assert + Assert.That(childXmlElement, Is.Null); + } + + [Test] + public void FirstChildOfRootFilledNodeIsCorrect() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertElement(transaction, index: 1, "color"); + xmlFragment.InsertText(transaction, index: 2); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var childXmlElement = xmlFragment.FirstChild(transaction); + transaction.Commit(); + + // Assert + Assert.That(childXmlElement.XmlText, Is.Not.Null); + } + + [Test] + public void FirstChildOfNestedEmptyNodeIsNull() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertElement(transaction, index: 0, "color"); + var childXmlElement = xmlFragment.Get(transaction, index: 0).XmlElement; + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var grandChildXmlElement = childXmlElement.FirstChild(transaction); + transaction.Commit(); + + // Assert + Assert.That(grandChildXmlElement, Is.Null); + } + + [Test] + public void FirstChildOfNestedFilledNodeIsCorrect() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertElement(transaction, index: 0, "color"); + var childXmlElement = xmlFragment.Get(transaction, index: 0).XmlElement; + childXmlElement.InsertElement(transaction, index: 0, "alpha"); + childXmlElement.InsertElement(transaction, index: 0, "hex"); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var grandChildXmlElement = childXmlElement.FirstChild(transaction); + transaction.Commit(); + + // Assert + Assert.That(grandChildXmlElement.XmlElement, Is.Not.Null); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/GetTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/GetTests.cs new file mode 100644 index 00000000..c2ef65b3 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/GetTests.cs @@ -0,0 +1,71 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Types.XmlFragments; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class GetTests +{ + [Test] + public void GetOutsideOfValidBounds() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + var value = xmlFragment.Get(transaction, index: 1); + transaction.Commit(); + + // Assert + Assert.That(value, Is.Null); + } + + [Test] + public void GetXmlText() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + var output = xmlFragment.Get(transaction, index: 1); + transaction.Commit(); + + // Assert + Assert.That(output.XmlText, Is.Not.Null); + } + + [Test] + public void GetXmlElement() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + var output = xmlFragment.Get(transaction, index: 2); + transaction.Commit(); + + // Assert + Assert.That(output.XmlElement, Is.Not.Null); + } + + private (Doc, XmlFragment) ArrangeDoc() + { + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertText(transaction, index: 1); + xmlFragment.InsertElement(transaction, index: 2, "color"); + xmlFragment.InsertText(transaction, index: 3); + xmlFragment.InsertElement(transaction, index: 4, "border"); + transaction.Commit(); + + return (doc, xmlFragment); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs new file mode 100644 index 00000000..7b914798 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class InsertElementTests +{ + [Test] + public void InsertSingleElement() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + var addedXmlElement = xmlFragment.InsertElement(transaction, index: 0, "color"); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(addedXmlElement.Handle, Is.Not.EqualTo(nint.Zero)); + Assert.That(addedXmlElement.Tag, Is.EqualTo("color")); + Assert.That(childLength, Is.EqualTo(expected: 1)); + } + + [Test] + public void InsertMultipleElements() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + var xmlElement1 = xmlFragment.InsertElement(transaction, index: 0, "color"); + var xmlElement2 = xmlFragment.InsertElement(transaction, index: 0, "width"); + var xmlElement3 = xmlFragment.InsertElement(transaction, index: 0, "height"); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(xmlElement1.Tag, Is.EqualTo("color")); + Assert.That(xmlElement2.Tag, Is.EqualTo("width")); + Assert.That(xmlElement3.Tag, Is.EqualTo("height")); + Assert.That(childLength, Is.EqualTo(expected: 3)); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/InsertTextTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertTextTests.cs new file mode 100644 index 00000000..baf78560 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertTextTests.cs @@ -0,0 +1,44 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class InsertTextTests +{ + [Test] + public void InsertSingleText() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + var xmlText = xmlFragment.InsertText(transaction, index: 0); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(xmlText.Handle, Is.Not.EqualTo(nint.Zero)); + Assert.That(childLength, Is.EqualTo(expected: 1)); + } + + [Test] + public void InsertMultipleTexts() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertText(transaction, index: 0); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 3)); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs new file mode 100644 index 00000000..1e15e5a8 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs @@ -0,0 +1,57 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Types.Events; +using YDotNet.Document.Types.XmlFragments; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class ObserveTests +{ + [Test] + public void ObserveHasTarget() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + XmlFragment? target = null; + xmlFragment.Observe(e => target = e.Target); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Assert + Assert.That(target, Is.Not.Null); + Assert.That(target.Handle, Is.Not.EqualTo(nint.Zero)); + } + + [Test] + public void ObserveHasDeltaWhenAddedXmlElementsAndTexts() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + IEnumerable? eventChanges = null; + xmlFragment.Observe(e => eventChanges = e.Delta.ToArray()); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertElement(transaction, index: 1, "color"); + xmlFragment.InsertText(transaction, index: 2); + transaction.Commit(); + + // Assert + Assert.That(eventChanges, Is.Not.Null); + Assert.That(eventChanges.Count(), Is.EqualTo(expected: 1)); + Assert.That(eventChanges.First().Tag, Is.EqualTo(EventChangeTag.Add)); + Assert.That(eventChanges.First().Length, Is.EqualTo(expected: 3)); + Assert.That(eventChanges.First().Values.ElementAt(index: 0).XmlText, Is.Not.Null); + Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement, Is.Not.Null); + Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(eventChanges.First().Values.ElementAt(index: 2).XmlText, Is.Not.Null); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/RemoveRangeTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/RemoveRangeTests.cs new file mode 100644 index 00000000..4436393e --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/RemoveRangeTests.cs @@ -0,0 +1,106 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Types.XmlFragments; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class RemoveRangeTests +{ + [Test] + public void RemoveEmptyRangeOnEmptyElement() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.RemoveRange(transaction, index: 0, length: 0); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 0)); + } + + [Test] + public void RemoveEmptyRangeOnFilledElement() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.RemoveRange(transaction, index: 2, length: 0); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 5)); + } + + [Test] + public void RemoveSingleItemRange() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.RemoveRange(transaction, index: 3, length: 1); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 4)); + } + + [Test] + public void RemoveMultipleItemsRange() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.RemoveRange(transaction, index: 2, length: 3); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 2)); + } + + [Test] + public void RemoveAllItemsAtOnce() + { + // Arrange + var (doc, xmlFragment) = ArrangeDoc(); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.RemoveRange(transaction, index: 0, length: 5); + var childLength = xmlFragment.ChildLength(transaction); + transaction.Commit(); + + // Assert + Assert.That(childLength, Is.EqualTo(expected: 0)); + } + + private (Doc, XmlFragment) ArrangeDoc() + { + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertText(transaction, index: 1); + xmlFragment.InsertElement(transaction, index: 2, "color"); + xmlFragment.InsertText(transaction, index: 3); + xmlFragment.InsertElement(transaction, index: 4, "border"); + transaction.Commit(); + + return (doc, xmlFragment); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs new file mode 100644 index 00000000..401ef6a3 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs @@ -0,0 +1,91 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class TreeWalkerTests +{ + [Test] + public void WalksOnEmptyTree() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.ReadTransaction(); + var xmlTreeWalker = xmlFragment.TreeWalker(transaction); + transaction.Commit(); + + // Assert + Assert.That(xmlTreeWalker, Is.Not.Null); + Assert.That(xmlTreeWalker.ToArray().Length, Is.EqualTo(expected: 0)); + } + + [Test] + public void WalksOnTreeWithSingleLevelOfDepth() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertElement(transaction, index: 1, "color"); + xmlFragment.InsertText(transaction, index: 2); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var xmlTreeWalker = xmlFragment.TreeWalker(transaction); + transaction.Commit(); + + // Assert + var xmlNodes = xmlTreeWalker.ToArray(); + + Assert.That(xmlTreeWalker, Is.Not.Null); + Assert.That(xmlNodes.Length, Is.EqualTo(expected: 3)); + Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 2).XmlText, Is.Not.Null); + } + + [Test] + public void WalksOnTreeWithMultipleLevelsOfDepth() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + xmlFragment.InsertElement(transaction, index: 1, "color"); + var childXmlElement = xmlFragment.Get(transaction, index: 1).XmlElement; + childXmlElement.InsertElement(transaction, index: 0, "alpha"); + childXmlElement.InsertElement(transaction, index: 1, "hex"); + childXmlElement.InsertText(transaction, index: 2); + transaction.Commit(); + + // Act + transaction = doc.ReadTransaction(); + var xmlTreeWalker = xmlFragment.TreeWalker(transaction); + transaction.Commit(); + + // Assert + var xmlNodes = xmlTreeWalker.ToArray(); + + Assert.That(xmlTreeWalker, Is.Not.Null); + Assert.That(xmlNodes.Length, Is.EqualTo(expected: 5)); + Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 2).XmlElement, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 2).XmlElement.Tag, Is.EqualTo("alpha")); + Assert.That(xmlNodes.ElementAt(index: 3).XmlElement, Is.Not.Null); + Assert.That(xmlNodes.ElementAt(index: 3).XmlElement.Tag, Is.EqualTo("hex")); + Assert.That(xmlNodes.ElementAt(index: 4).XmlText, Is.Not.Null); + } +} diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/UnobserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/UnobserveTests.cs new file mode 100644 index 00000000..1a6c745f --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/UnobserveTests.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.XmlFragments; + +public class UnobserveTests +{ + [Test] + public void TriggersWhenXmlElementChangedUntilUnobserved() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var called = 0; + var subscription = xmlFragment.Observe(_ => called++); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Assert + Assert.That(called, Is.EqualTo(expected: 1)); + + // Act + subscription.Dispose(); + + transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 1); + transaction.Commit(); + + // Assert + Assert.That(called, Is.EqualTo(expected: 1)); + } +} From 0c4fee306c79c7eef4dd4ec25330c06943eba512 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 17 Mar 2024 12:46:51 -0300 Subject: [PATCH 24/75] test: introduce unit tests for `ObserveDeep()` in `XmlFragment` --- .../Branches/XmlFragmentObserveDeepTests.cs | 157 ++++++++++++++++++ .../Branches/XmlFragmentUnobserveDeepTests.cs | 36 ++++ 2 files changed, 193 insertions(+) create mode 100644 Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs create mode 100644 Tests/YDotNet.Tests.Unit/Branches/XmlFragmentUnobserveDeepTests.cs diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs new file mode 100644 index 00000000..dc1e8e0b --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs @@ -0,0 +1,157 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Types.Events; +using YDotNet.Document.Types.XmlElements; +using YDotNet.Document.Types.XmlFragments; + +namespace YDotNet.Tests.Unit.Branches; + +public class XmlFragmentObserveDeepTests +{ + [Test] + public void ObserveDeepHasPathWhenAddedXmlElementsAndTexts() + { + // Arrange + var (doc, xmlFragment, xmlElement1, _, xmlElement3) = ArrangeDoc(); + + IEnumerable? pathSegments = null; + + var subscription = + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlFragmentEvent.Path.ToArray()); + + // Act + var transaction = doc.WriteTransaction(); + xmlElement3.InsertText(transaction, index: 0); + transaction.Commit(); + + // Assert + Assert.That(pathSegments, Is.Not.Null); + Assert.That(pathSegments.Count(), Is.EqualTo(expected: 3)); + Assert.That(pathSegments.All(x => x.Tag == EventPathSegmentTag.Index), Is.True); + Assert.That(pathSegments.All(x => x.Key == null), Is.True); + Assert.That(pathSegments.ElementAt(index: 0).Index, Is.EqualTo(expected: 0)); + Assert.That(pathSegments.ElementAt(index: 1).Index, Is.EqualTo(expected: 2)); + Assert.That(pathSegments.ElementAt(index: 2).Index, Is.EqualTo(expected: 1)); + + // Act + transaction = doc.WriteTransaction(); + xmlElement3.InsertElement(transaction, index: 1, "xml-element-4"); + transaction.Commit(); + + // Assert + Assert.That(pathSegments, Is.Not.Null); + Assert.That(pathSegments.Count(), Is.EqualTo(expected: 3)); + Assert.That(pathSegments.All(x => x.Tag == EventPathSegmentTag.Index), Is.True); + Assert.That(pathSegments.All(x => x.Key == null), Is.True); + Assert.That(pathSegments.ElementAt(index: 0).Index, Is.EqualTo(expected: 0)); + Assert.That(pathSegments.ElementAt(index: 1).Index, Is.EqualTo(expected: 2)); + Assert.That(pathSegments.ElementAt(index: 2).Index, Is.EqualTo(expected: 1)); + } + + [Test] + public void ObserveDeepHasPathWhenAddedAttributes() + { + // Arrange + var (doc, xmlFragment, xmlElement1, _, xmlElement3) = ArrangeDoc(); + + IEnumerable? pathSegments = null; + + var subscription = + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlFragmentEvent.Path.ToArray()); + + // Act + var transaction = doc.WriteTransaction(); + xmlElement3.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); + transaction.Commit(); + + // Assert + Assert.That(pathSegments, Is.Not.Null); + Assert.That(pathSegments.Count(), Is.EqualTo(expected: 3)); + Assert.That(pathSegments.All(x => x.Tag == EventPathSegmentTag.Index), Is.True); + Assert.That(pathSegments.All(x => x.Key == null), Is.True); + Assert.That(pathSegments.ElementAt(index: 0).Index, Is.EqualTo(expected: 0)); + Assert.That(pathSegments.ElementAt(index: 1).Index, Is.EqualTo(expected: 2)); + Assert.That(pathSegments.ElementAt(index: 2).Index, Is.EqualTo(expected: 1)); + } + + [Test] + public void ObserveDeepHasPathWhenUpdatedAttributes() + { + // Arrange + var (doc, xmlFragment, xmlElement1, _, xmlElement3) = ArrangeDoc(); + + var transaction = doc.WriteTransaction(); + xmlElement3.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); + transaction.Commit(); + + IEnumerable? pathSegments = null; + + var subscription = + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlElementEvent.Path.ToArray()); + + // Act + transaction = doc.WriteTransaction(); + xmlElement3.InsertAttribute(transaction, "href", "https://github.com/LSViana/y-crdt"); + transaction.Commit(); + + // Assert + Assert.That(pathSegments, Is.Not.Null); + Assert.That(pathSegments.Count(), Is.EqualTo(expected: 3)); + Assert.That(pathSegments.All(x => x.Tag == EventPathSegmentTag.Index), Is.True); + Assert.That(pathSegments.All(x => x.Key == null), Is.True); + Assert.That(pathSegments.ElementAt(index: 0).Index, Is.EqualTo(expected: 0)); + Assert.That(pathSegments.ElementAt(index: 1).Index, Is.EqualTo(expected: 2)); + Assert.That(pathSegments.ElementAt(index: 2).Index, Is.EqualTo(expected: 1)); + } + + [Test] + public void ObserveDeepHasPathWhenRemovedAttributes() + { + // Arrange + var (doc, xmlFragment, xmlElement1, _, xmlElement3) = ArrangeDoc(); + + var transaction = doc.WriteTransaction(); + xmlElement3.InsertAttribute(transaction, "href", "https://lsviana.github.io/"); + transaction.Commit(); + + IEnumerable? pathSegments = null; + + var subscription = + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlElementEvent.Path.ToArray()); + + // Act + transaction = doc.WriteTransaction(); + xmlElement3.RemoveAttribute(transaction, "href"); + transaction.Commit(); + + // Assert + Assert.That(pathSegments, Is.Not.Null); + Assert.That(pathSegments.Count(), Is.EqualTo(expected: 3)); + Assert.That(pathSegments.All(x => x.Tag == EventPathSegmentTag.Index), Is.True); + Assert.That(pathSegments.All(x => x.Key == null), Is.True); + Assert.That(pathSegments.ElementAt(index: 0).Index, Is.EqualTo(expected: 0)); + Assert.That(pathSegments.ElementAt(index: 1).Index, Is.EqualTo(expected: 2)); + Assert.That(pathSegments.ElementAt(index: 2).Index, Is.EqualTo(expected: 1)); + } + + private (Doc, XmlFragment, XmlElement, XmlElement, XmlElement) ArrangeDoc() + { + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var transaction = doc.WriteTransaction(); + var xmlElement1 = xmlFragment.InsertElement(transaction, index: 0, "xml-element-1"); + transaction.Commit(); + + transaction = doc.WriteTransaction(); + xmlElement1.InsertText(transaction, index: 0); + xmlElement1.InsertText(transaction, index: 1); + var xmlElement2 = xmlElement1.InsertElement(transaction, index: 2, "xml-element-2"); + + xmlElement2.InsertText(transaction, index: 0); + var xmlElement3 = xmlElement2.InsertElement(transaction, index: 1, "xml-element-3"); + transaction.Commit(); + + return (doc, xmlFragment, xmlElement1, xmlElement2, xmlElement3); + } +} diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentUnobserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentUnobserveDeepTests.cs new file mode 100644 index 00000000..8649aacd --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentUnobserveDeepTests.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.Branches; + +public class XmlFragmentUnobserveDeepTests +{ + [Test] + public void TriggersWhenChangedUntilUnobserved() + { + // Arrange + var doc = new Doc(); + var xmlFragment = doc.XmlFragment("xml-fragment"); + + var called = 0; + var subscription = xmlFragment.ObserveDeep(_ => called++); + + // Act + var transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Assert + Assert.That(called, Is.EqualTo(expected: 1)); + + // Act + subscription.Dispose(); + + transaction = doc.WriteTransaction(); + xmlFragment.InsertText(transaction, index: 0); + transaction.Commit(); + + // Assert + Assert.That(called, Is.EqualTo(expected: 1)); + } +} From b3ebc365b5b161d0cffc10c99136ff0e64a3ae8f Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 20:39:22 -0300 Subject: [PATCH 25/75] feat: use exact type comparison to prevent inheritance from allowing multiple events to be exposed in `EventBranch` --- YDotNet/Document/Types/Events/EventBranch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/YDotNet/Document/Types/Events/EventBranch.cs b/YDotNet/Document/Types/Events/EventBranch.cs index c011e17c..74df1df6 100644 --- a/YDotNet/Document/Types/Events/EventBranch.cs +++ b/YDotNet/Document/Types/Events/EventBranch.cs @@ -83,11 +83,11 @@ internal EventBranch(NativeWithHandle native, Doc doc) private T GetValue(EventBranchTag expectedType) { - if (value is not T typed) + if (value?.GetType() != typeof(T)) { throw new YDotNetException($"Expected {expectedType}, got {Tag}."); } - return typed; + return (T) value; } } From 77173f71661ab513d1c20c423ccddde5dfac9714 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:27:40 -0300 Subject: [PATCH 26/75] feat: drop `BranchChannel.WriteTransaction()` --- YDotNet/Native/Types/Branches/BranchChannel.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/YDotNet/Native/Types/Branches/BranchChannel.cs b/YDotNet/Native/Types/Branches/BranchChannel.cs index d21cb338..903c1a7e 100644 --- a/YDotNet/Native/Types/Branches/BranchChannel.cs +++ b/YDotNet/Native/Types/Branches/BranchChannel.cs @@ -23,10 +23,4 @@ internal static class BranchChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ybranch_read_transaction")] public static extern nint ReadTransaction(nint branch); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ybranch_write_transaction")] - public static extern nint WriteTransaction(nint branch); } From 88c8a9e42230ee786b2ac19d703218a73dd9fdce Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:27:56 -0300 Subject: [PATCH 27/75] feat: update `Branch.WriteTransaction()` to use `Doc.WriteTransaction()` --- YDotNet/Document/Types/Branches/Branch.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index cfeb19b0..3ec8b9eb 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -66,15 +66,7 @@ public Transaction WriteTransaction() { ThrowIfDisposed(); - var handle = BranchChannel.WriteTransaction(Handle); - - if (handle == nint.Zero) - { - ThrowHelper.PendingTransaction(); - return default!; - } - - return new Transaction(handle, Doc); + return Doc.WriteTransaction(); } /// From a7a70fdaa752154332e756de0a0befabaae70433 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:28:28 -0300 Subject: [PATCH 28/75] chore: fix typos in `Branch` and `Doc` --- YDotNet/Document/Doc.cs | 4 ++-- YDotNet/Document/Types/Branches/Branch.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/YDotNet/Document/Doc.cs b/YDotNet/Document/Doc.cs index 27500344..d38238a8 100644 --- a/YDotNet/Document/Doc.cs +++ b/YDotNet/Document/Doc.cs @@ -323,7 +323,7 @@ public XmlFragment XmlFragment(string name) /// /// Optional byte marker to indicate the source of changes to be applied by this transaction. /// The to perform write operations in the document. - /// Another write transaction has been created and not commited yet. + /// Another write transaction has been created and not committed yet. public Transaction WriteTransaction(byte[]? origin = null) { ThrowIfDisposed(); @@ -343,7 +343,7 @@ public Transaction WriteTransaction(byte[]? origin = null) /// Starts a new read-only on this document. /// /// The to perform read operations in the document. - /// Another write transaction has been created and not commited yet. + /// Another write transaction has been created and not committed yet. public Transaction ReadTransaction() { ThrowIfDisposed(); diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 3ec8b9eb..ae527ff2 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -61,7 +61,7 @@ public IDisposable ObserveDeep(Action> action) /// Starts a new read-write on this instance. /// /// The to perform operations in the document. - /// Another write transaction has been created and not commited yet. + /// Another write transaction has been created and not committed yet. public Transaction WriteTransaction() { ThrowIfDisposed(); @@ -73,7 +73,7 @@ public Transaction WriteTransaction() /// Starts a new read-only on this instance. /// /// The to perform operations in the branch. - /// Another write transaction has been created and not commited yet. + /// Another write transaction has been created and not committed yet. public Transaction ReadTransaction() { ThrowIfDisposed(); From 8d4299f0fa60de024735cc3aae1957eaa51a55b1 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:28:51 -0300 Subject: [PATCH 29/75] feat: drop `BranchChannel.ReadTransaction()` --- YDotNet/Native/Types/Branches/BranchChannel.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/YDotNet/Native/Types/Branches/BranchChannel.cs b/YDotNet/Native/Types/Branches/BranchChannel.cs index 903c1a7e..a393beaa 100644 --- a/YDotNet/Native/Types/Branches/BranchChannel.cs +++ b/YDotNet/Native/Types/Branches/BranchChannel.cs @@ -17,10 +17,4 @@ internal static class BranchChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ytype_kind")] public static extern byte Kind(nint branch); - - [DllImport( - ChannelSettings.NativeLib, - CallingConvention = CallingConvention.Cdecl, - EntryPoint = "ybranch_read_transaction")] - public static extern nint ReadTransaction(nint branch); } From 98ac7276827a5243b915bf0f76e8b8e3cda387d3 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:29:00 -0300 Subject: [PATCH 30/75] feat: update `Branch.ReadTransaction()` to use `Doc.ReadTransaction()` --- YDotNet/Document/Types/Branches/Branch.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index ae527ff2..d043aaeb 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -78,15 +78,7 @@ public Transaction ReadTransaction() { ThrowIfDisposed(); - var handle = BranchChannel.ReadTransaction(Handle); - - if (handle == nint.Zero) - { - ThrowHelper.PendingTransaction(); - return default!; - } - - return new Transaction(handle, Doc); + return Doc.ReadTransaction(); } /// From b82e13bb3a564cf8973bb4d4cd1d8dee61fcfc58 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:45:27 -0300 Subject: [PATCH 31/75] feat: update `XmlElement.Parent()` to only return a value if the parent is also an `XmlElement` --- YDotNet/Document/Types/XmlElements/XmlElement.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/XmlElements/XmlElement.cs b/YDotNet/Document/Types/XmlElements/XmlElement.cs index 949ed690..ac0b7eab 100644 --- a/YDotNet/Document/Types/XmlElements/XmlElement.cs +++ b/YDotNet/Document/Types/XmlElements/XmlElement.cs @@ -8,6 +8,7 @@ using YDotNet.Infrastructure; using YDotNet.Infrastructure.Extensions; using YDotNet.Native.Types; +using YDotNet.Native.Types.Branches; namespace YDotNet.Document.Types.XmlElements; @@ -263,7 +264,14 @@ public XmlAttributeIterator Iterate(Transaction transaction) var handle = XmlElementChannel.Parent(Handle, transaction.Handle); - return handle != nint.Zero ? Doc.GetXmlElement(handle, isDeleted: false) : null; + if (handle == nint.Zero) + { + return null; + } + + var kind = (BranchKind) BranchChannel.Kind(handle); + + return kind == BranchKind.XmlElement ? Doc.GetXmlElement(handle, isDeleted: false) : null; } /// From 08b7c5a3d3faad72b3e49225fe0c6c39c9f36d2c Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 20 Mar 2024 22:45:44 -0300 Subject: [PATCH 32/75] test: fix unit tests of `XmlFragment.ObserveDeep()` --- .../Branches/XmlFragmentObserveDeepTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs index dc1e8e0b..2ac9d840 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/XmlFragmentObserveDeepTests.cs @@ -17,7 +17,7 @@ public void ObserveDeepHasPathWhenAddedXmlElementsAndTexts() IEnumerable? pathSegments = null; var subscription = - xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlFragmentEvent.Path.ToArray()); + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlElementEvent.Path.ToArray()); // Act var transaction = doc.WriteTransaction(); @@ -57,7 +57,7 @@ public void ObserveDeepHasPathWhenAddedAttributes() IEnumerable? pathSegments = null; var subscription = - xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlFragmentEvent.Path.ToArray()); + xmlFragment.ObserveDeep(events => pathSegments = events.First().XmlElementEvent.Path.ToArray()); // Act var transaction = doc.WriteTransaction(); From 4cb5cdcfc01b49a4cdde3512092038335c47f6ab Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:39:59 -0300 Subject: [PATCH 33/75] feat: introduce `BranchIdNative*` structs --- YDotNet/Native/Types/Branches/BranchIdNative.cs | 13 +++++++++++++ .../Native/Types/Branches/BranchIdVariantNative.cs | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 YDotNet/Native/Types/Branches/BranchIdNative.cs create mode 100644 YDotNet/Native/Types/Branches/BranchIdVariantNative.cs diff --git a/YDotNet/Native/Types/Branches/BranchIdNative.cs b/YDotNet/Native/Types/Branches/BranchIdNative.cs new file mode 100644 index 00000000..8e5d08e2 --- /dev/null +++ b/YDotNet/Native/Types/Branches/BranchIdNative.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace YDotNet.Native.Types.Branches; + +[StructLayout(LayoutKind.Explicit, Size = 16)] +internal readonly struct BranchIdNative +{ + [field: FieldOffset(offset: 0)] + public long ClientIdOrLength { get; } + + [field: FieldOffset(offset: 8)] + public BranchIdVariantNative BranchIdVariant { get; } +} diff --git a/YDotNet/Native/Types/Branches/BranchIdVariantNative.cs b/YDotNet/Native/Types/Branches/BranchIdVariantNative.cs new file mode 100644 index 00000000..df7e261b --- /dev/null +++ b/YDotNet/Native/Types/Branches/BranchIdVariantNative.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace YDotNet.Native.Types.Branches; + +[StructLayout(LayoutKind.Explicit, Size = 8)] +internal readonly struct BranchIdVariantNative +{ + [field: FieldOffset(offset: 0)] + public uint Clock { get; } + + [field: FieldOffset(offset: 0)] + public nint NamePointer { get; } +} From a4bd1ab3bfadd6e2ecbd73d7c56f120f1acc9c7d Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:40:10 -0300 Subject: [PATCH 34/75] feat: introduce `BranchChannel.Id()` --- YDotNet/Native/Types/Branches/BranchChannel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/YDotNet/Native/Types/Branches/BranchChannel.cs b/YDotNet/Native/Types/Branches/BranchChannel.cs index a393beaa..313c88ed 100644 --- a/YDotNet/Native/Types/Branches/BranchChannel.cs +++ b/YDotNet/Native/Types/Branches/BranchChannel.cs @@ -17,4 +17,10 @@ internal static class BranchChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ytype_kind")] public static extern byte Kind(nint branch); + + [DllImport( + ChannelSettings.NativeLib, + CallingConvention = CallingConvention.Cdecl, + EntryPoint = "ybranch_id")] + public static extern BranchIdNative Id(nint branch); } From 85a8c02bed07bc9359520bb3e8bf7b8745eaff27 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:40:19 -0300 Subject: [PATCH 35/75] feat: introduce `BranchId` class --- YDotNet/Document/Types/Branches/BranchId.cs | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 YDotNet/Document/Types/Branches/BranchId.cs diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs new file mode 100644 index 00000000..88d0cd6c --- /dev/null +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -0,0 +1,26 @@ +using YDotNet.Infrastructure; +using YDotNet.Native.Types.Branches; + +namespace YDotNet.Document.Types.Branches; + +public class BranchId +{ + internal BranchId(BranchIdNative native) + { + Native = native; + } + + private BranchIdNative Native { get; } + + public bool HasClientIdAndClock => Native.ClientIdOrLength > 0; + + public bool HasLengthAndName => !HasClientIdAndClock; + + public long? ClientId => HasClientIdAndClock ? Native.ClientIdOrLength : null; + + public uint? Clock => HasClientIdAndClock ? Native.BranchIdVariant.Clock : null; + + public long? Length => HasClientIdAndClock ? null : -Native.ClientIdOrLength; + + public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); +} From 4fa76562ab7c3351f7f33efe08e047f4a0bdac82 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:40:29 -0300 Subject: [PATCH 36/75] feat: introduce `Branch.Id()` method --- YDotNet/Document/Types/Branches/Branch.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index d043aaeb..8e9e1393 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -81,6 +81,15 @@ public Transaction ReadTransaction() return Doc.ReadTransaction(); } + public BranchId Id() + { + ThrowIfDisposed(); + + var branchIdNative = BranchChannel.Id(Handle); + + return new BranchId(branchIdNative); + } + /// protected override void DisposeCore(bool disposing) { From 8e27e8810479e2ee15f3b184dfde992ecb07bb97 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:40:36 -0300 Subject: [PATCH 37/75] test: introduce tests for `Branch.Id()` --- Tests/YDotNet.Tests.Unit/Branches/IdTests.cs | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Tests/YDotNet.Tests.Unit/Branches/IdTests.cs diff --git a/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs b/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs new file mode 100644 index 00000000..1c45fc0b --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs @@ -0,0 +1,77 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Cells; +using YDotNet.Document.Options; +using YDotNet.Document.Types.Branches; + +namespace YDotNet.Tests.Unit.Branches; + +public class IdTests +{ + [Test] + public void ReturnsIdForRootLevelType() + { + // Arrange + var doc = new Doc(); + var branch = doc.Text("text"); + + // Act + var id = branch.Id(); + + // Assert + Assert.That(id, Is.Not.Null); + Assert.That(id.HasLengthAndName, Is.True); + Assert.That(id.HasClientIdAndClock, Is.False); + Assert.That(id.Length, Is.EqualTo(expected: 4)); + Assert.That(id.Name, Is.EqualTo("text")); + Assert.That(id.ClientId, Is.EqualTo(expected: null)); + Assert.That(id.Clock, Is.EqualTo(expected: null)); + } + + [Test] + public void ReturnsIdForNestedType() + { + // Arrange + var doc = new Doc( + new DocOptions + { + Id = 37 + }); + var map = doc.Map("map"); + + var transaction = map.WriteTransaction(); + map.Insert(transaction, "text", Input.Text("")); + Branch branch = map.Get(transaction, "text")!.Text; + transaction.Commit(); + + // Act + var id = branch.Id(); + + // Assert + Assert.That(id, Is.Not.Null); + Assert.That(id.HasLengthAndName, Is.False); + Assert.That(id.HasClientIdAndClock, Is.True); + Assert.That(id.Length, Is.Null); + Assert.That(id.Name, Is.Null); + Assert.That(id.ClientId, Is.EqualTo(expected: 37)); + Assert.That(id.Clock, Is.EqualTo(expected: 0)); + + // Arrange + transaction = map.WriteTransaction(); + map.Insert(transaction, "array", Input.Array(Array.Empty())); + branch = map.Get(transaction, "array")!.Array; + transaction.Commit(); + + // Act + id = branch.Id(); + + // Assert + Assert.That(id, Is.Not.Null); + Assert.That(id.HasLengthAndName, Is.False); + Assert.That(id.HasClientIdAndClock, Is.True); + Assert.That(id.Length, Is.Null); + Assert.That(id.Name, Is.Null); + Assert.That(id.ClientId, Is.EqualTo(expected: 37)); + Assert.That(id.Clock, Is.EqualTo(expected: 1)); + } +} From 67d04092b002e51cce0ea8e42be0515d3002f1ac Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:49:38 -0300 Subject: [PATCH 38/75] feat: drop `BranchId.Length` and rename `HasLengthAndName` to `HasName` --- YDotNet/Document/Types/Branches/BranchId.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs index 88d0cd6c..a9890752 100644 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -14,13 +14,11 @@ internal BranchId(BranchIdNative native) public bool HasClientIdAndClock => Native.ClientIdOrLength > 0; - public bool HasLengthAndName => !HasClientIdAndClock; + public bool HasName => !HasClientIdAndClock; public long? ClientId => HasClientIdAndClock ? Native.ClientIdOrLength : null; public uint? Clock => HasClientIdAndClock ? Native.BranchIdVariant.Clock : null; - public long? Length => HasClientIdAndClock ? null : -Native.ClientIdOrLength; - public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); } From 80bcf59022355c19afb9f82f0d3b183ac15cfde3 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:51:55 -0300 Subject: [PATCH 39/75] docs: add documentation for `BranchId` class and properties --- YDotNet/Document/Types/Branches/BranchId.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs index a9890752..1448ea4f 100644 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -3,6 +3,9 @@ namespace YDotNet.Document.Types.Branches; +/// +/// Represents a logical identifier for a shared collection. +/// public class BranchId { internal BranchId(BranchIdNative native) @@ -12,13 +15,30 @@ internal BranchId(BranchIdNative native) private BranchIdNative Native { get; } + /// + /// Gets a value indicating whether and have values. + /// If this is false, check . + /// public bool HasClientIdAndClock => Native.ClientIdOrLength > 0; + /// + /// Gets a value indicating whether has values. + /// If this is false, check . + /// public bool HasName => !HasClientIdAndClock; + /// + /// Gets the client ID of a creator of a nested shared type that this points to. + /// public long? ClientId => HasClientIdAndClock ? Native.ClientIdOrLength : null; + /// + /// Gets the clock number timestamp when the creator of a nested shared type created it. + /// public uint? Clock => HasClientIdAndClock ? Native.BranchIdVariant.Clock : null; + /// + /// Gets the name of the root-level shared type. + /// public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); } From aeb97d3e32ad491cde972afcac3fe481c2e2f424 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:52:04 -0300 Subject: [PATCH 40/75] docs: add documentation for `Branch.Id()` --- YDotNet/Document/Types/Branches/Branch.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 8e9e1393..c2a6a3f2 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -81,6 +81,10 @@ public Transaction ReadTransaction() return Doc.ReadTransaction(); } + /// + /// Returns the of this collection. + /// + /// The of this collection. public BranchId Id() { ThrowIfDisposed(); From 30e19c0b4eac38210f97ce49f50744bf93c184ea Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 08:52:19 -0300 Subject: [PATCH 41/75] test: update unit tests of `Branch.Id()` after API changes on `BranchId` --- Tests/YDotNet.Tests.Unit/Branches/IdTests.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs b/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs index 1c45fc0b..2de40922 100644 --- a/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs +++ b/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs @@ -20,9 +20,8 @@ public void ReturnsIdForRootLevelType() // Assert Assert.That(id, Is.Not.Null); - Assert.That(id.HasLengthAndName, Is.True); + Assert.That(id.HasName, Is.True); Assert.That(id.HasClientIdAndClock, Is.False); - Assert.That(id.Length, Is.EqualTo(expected: 4)); Assert.That(id.Name, Is.EqualTo("text")); Assert.That(id.ClientId, Is.EqualTo(expected: null)); Assert.That(id.Clock, Is.EqualTo(expected: null)); @@ -49,9 +48,8 @@ public void ReturnsIdForNestedType() // Assert Assert.That(id, Is.Not.Null); - Assert.That(id.HasLengthAndName, Is.False); + Assert.That(id.HasName, Is.False); Assert.That(id.HasClientIdAndClock, Is.True); - Assert.That(id.Length, Is.Null); Assert.That(id.Name, Is.Null); Assert.That(id.ClientId, Is.EqualTo(expected: 37)); Assert.That(id.Clock, Is.EqualTo(expected: 0)); @@ -67,9 +65,8 @@ public void ReturnsIdForNestedType() // Assert Assert.That(id, Is.Not.Null); - Assert.That(id.HasLengthAndName, Is.False); + Assert.That(id.HasName, Is.False); Assert.That(id.HasClientIdAndClock, Is.True); - Assert.That(id.Length, Is.Null); Assert.That(id.Name, Is.Null); Assert.That(id.ClientId, Is.EqualTo(expected: 37)); Assert.That(id.Clock, Is.EqualTo(expected: 1)); From 241b8d4c8055d4e9b8971bcda11feda015375c0b Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 13:15:43 -0300 Subject: [PATCH 42/75] feat: adjust `BranchId` to store a reference to the related `Doc` --- YDotNet/Document/Types/Branches/Branch.cs | 2 +- YDotNet/Document/Types/Branches/BranchId.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index c2a6a3f2..87c4cf40 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -91,7 +91,7 @@ public BranchId Id() var branchIdNative = BranchChannel.Id(Handle); - return new BranchId(branchIdNative); + return new BranchId(branchIdNative, Doc); } /// diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs index 1448ea4f..debf3b8b 100644 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -1,3 +1,4 @@ +using YDotNet.Document.Transactions; using YDotNet.Infrastructure; using YDotNet.Native.Types.Branches; @@ -8,8 +9,12 @@ namespace YDotNet.Document.Types.Branches; /// public class BranchId { - internal BranchId(BranchIdNative native) + private readonly Doc doc; + + internal BranchId(BranchIdNative native, Doc doc) { + this.doc = doc; + Native = native; } From ffff0810f5d2e669d2be72a2b131514a33ce46d7 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 13:23:40 -0300 Subject: [PATCH 43/75] feat: introduce `BranchId.Get()` and `Get()` and `Alive()` in `BranchChannel` --- YDotNet/Document/Types/Branches/BranchId.cs | 35 +++++++++++++++++++ .../Native/Types/Branches/BranchChannel.cs | 12 +++++++ 2 files changed, 47 insertions(+) diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs index debf3b8b..07574c4a 100644 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -46,4 +46,39 @@ internal BranchId(BranchIdNative native, Doc doc) /// Gets the name of the root-level shared type. /// public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); + + public Branch? Get(Transaction transaction) + { + var handle = MemoryWriter.WriteStruct(Native); + + var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); + + handle.Dispose(); + + if (branchHandle == nint.Zero) + { + return null; + } + + var branchKind = (BranchKind) BranchChannel.Kind(branchHandle); + var branchDeleted = BranchChannel.Alive(branchHandle) == 0; + + switch (branchKind) + { + case BranchKind.Array: + return doc.GetArray(branchHandle, branchDeleted); + case BranchKind.Map: + return doc.GetMap(branchHandle, branchDeleted); + case BranchKind.Text: + return doc.GetText(branchHandle, branchDeleted); + case BranchKind.XmlElement: + return doc.GetXmlElement(branchHandle, branchDeleted); + case BranchKind.XmlText: + return doc.GetXmlText(branchHandle, branchDeleted); + case BranchKind.XmlFragment: + return doc.GetXmlFragment(branchHandle, branchDeleted); + default: + return null; + } + } } diff --git a/YDotNet/Native/Types/Branches/BranchChannel.cs b/YDotNet/Native/Types/Branches/BranchChannel.cs index 313c88ed..a5349fc4 100644 --- a/YDotNet/Native/Types/Branches/BranchChannel.cs +++ b/YDotNet/Native/Types/Branches/BranchChannel.cs @@ -23,4 +23,16 @@ internal static class BranchChannel CallingConvention = CallingConvention.Cdecl, EntryPoint = "ybranch_id")] public static extern BranchIdNative Id(nint branch); + + [DllImport( + ChannelSettings.NativeLib, + CallingConvention = CallingConvention.Cdecl, + EntryPoint = "ybranch_get")] + public static extern nint Get(nint branchId, nint transaction); + + [DllImport( + ChannelSettings.NativeLib, + CallingConvention = CallingConvention.Cdecl, + EntryPoint = "ybranch_alive")] + public static extern byte Alive(nint branchId); } From 97d5cf9220ef0ed80d6fcd71158c6606ae59f393 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 13:28:30 -0300 Subject: [PATCH 44/75] test: introduce tests for `BranchId.Get()` --- .../Branches/BranchId/GetTests.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs diff --git a/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs b/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs new file mode 100644 index 00000000..e47c9d69 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs @@ -0,0 +1,33 @@ +using NUnit.Framework; +using YDotNet.Document; +using YDotNet.Document.Types.Texts; + +namespace YDotNet.Tests.Unit.Branches.BranchId; + +public class GetTests +{ + [Test] + public void ReturnsTheCorrectBranchWhenAlive() + { + // Arrange + var doc = new Doc(); + var branch = doc.Text("text"); + var branchId = branch.Id(); + + // Act + var transaction = doc.ReadTransaction(); + var newBranch = branchId.Get(transaction); + transaction.Commit(); + + // Assert + Assert.That(newBranch, Is.Not.Null); + Assert.That(newBranch, Is.TypeOf()); + Assert.That(newBranch, Is.EqualTo(branch)); + } + + [Test] + [Ignore("TODO: Check how to mark a Branch as deleted.")] + public void ReturnsTheCorrectBranchWhenNotAlive() + { + } +} From 42a989f7c89b7e629fc614f8ea9a4d13ff3212d6 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 13:33:43 -0300 Subject: [PATCH 45/75] feat: introduce `Branch.Alive()` --- YDotNet/Document/Types/Branches/Branch.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 87c4cf40..ebe2e056 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -94,6 +94,15 @@ public BranchId Id() return new BranchId(branchIdNative, Doc); } + /// + /// Indicates whether the instance is alive. + /// + /// A value indicating whether the is alive. + public bool Alive() + { + return BranchChannel.Alive(Handle) == 1; + } + /// protected override void DisposeCore(bool disposing) { From a78770b72a57ebf29932a3ef21109546049e20ae Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sat, 23 Mar 2024 13:33:56 -0300 Subject: [PATCH 46/75] test: introduce tests for `Branch.Alive()` --- .../YDotNet.Tests.Unit/Branches/AliveTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs diff --git a/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs b/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs new file mode 100644 index 00000000..16908a02 --- /dev/null +++ b/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs @@ -0,0 +1,27 @@ +using NUnit.Framework; +using YDotNet.Document; + +namespace YDotNet.Tests.Unit.Branches; + +public class AliveTests +{ + [Test] + public void ReturnsTrueWhenAlive() + { + // Arrange + var doc = new Doc(); + var text = doc.Text("text"); + + // Act + var alive = text.Alive(); + + // Assert + Assert.That(alive, Is.True); + } + + [Test] + [Ignore("TODO: Check how to mark a Branch as deleted.")] + public void ReturnsFalseWhenNotAlive() + { + } +} From 94dc35c91635d3b8f0415a1e6dc4cdb051829064 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 26 Mar 2024 20:38:34 -0300 Subject: [PATCH 47/75] revert: use constant numbers in `BranchKind` This prevents creating dependencies from the `Native` to the `Document` namespace. --- YDotNet/Native/Types/Branches/BranchKind.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/YDotNet/Native/Types/Branches/BranchKind.cs b/YDotNet/Native/Types/Branches/BranchKind.cs index 20e806b9..13a04064 100644 --- a/YDotNet/Native/Types/Branches/BranchKind.cs +++ b/YDotNet/Native/Types/Branches/BranchKind.cs @@ -1,14 +1,12 @@ -using YDotNet.Document.Cells; - namespace YDotNet.Native.Types.Branches; internal enum BranchKind { - Null = OutputTag.Null, - Array = OutputTag.Array, - Map = OutputTag.Map, - Text = OutputTag.Text, - XmlElement = OutputTag.XmlElement, - XmlText = OutputTag.XmlText, - XmlFragment = OutputTag.XmlFragment + Null = 0, + Array = 1, + Map = 2, + Text = 3, + XmlElement = 4, + XmlText = 5, + XmlFragment = 6 } From 76cfddc0e621bc0adf83b924028e0450fdf00258 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 26 Mar 2024 20:41:37 -0300 Subject: [PATCH 48/75] style: format `Transaction` --- YDotNet/Document/Transactions/Transaction.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/YDotNet/Document/Transactions/Transaction.cs b/YDotNet/Document/Transactions/Transaction.cs index 41f1a478..6cbae948 100644 --- a/YDotNet/Document/Transactions/Transaction.cs +++ b/YDotNet/Document/Transactions/Transaction.cs @@ -120,7 +120,10 @@ public byte[] StateVectorV1() public byte[] StateDiffV1(byte[]? stateVector) { var handle = TransactionChannel.StateDiffV1( - Handle, stateVector, (uint) (stateVector?.Length ?? 0), out var length); + Handle, + stateVector, + (uint)(stateVector?.Length ?? 0), + out var length); return MemoryReader.ReadAndDestroyBytes(handle, length); } @@ -154,7 +157,7 @@ public byte[] StateDiffV2(byte[]? stateVector) var handle = TransactionChannel.StateDiffV2( Handle, stateVector, - (uint) (stateVector?.Length ?? 0), + (uint)(stateVector?.Length ?? 0), out var length); return MemoryReader.ReadAndDestroyBytes(handle, length); @@ -171,7 +174,7 @@ public byte[] StateDiffV2(byte[]? stateVector) /// The result of the update operation. public TransactionUpdateResult ApplyV1(byte[] stateDiff) { - return (TransactionUpdateResult) TransactionChannel.ApplyV1(Handle, stateDiff, (uint) stateDiff.Length); + return (TransactionUpdateResult)TransactionChannel.ApplyV1(Handle, stateDiff, (uint)stateDiff.Length); } /// @@ -185,7 +188,7 @@ public TransactionUpdateResult ApplyV1(byte[] stateDiff) /// The result of the update operation. public TransactionUpdateResult ApplyV2(byte[] stateDiff) { - return (TransactionUpdateResult) TransactionChannel.ApplyV2(Handle, stateDiff, (uint) stateDiff.Length); + return (TransactionUpdateResult)TransactionChannel.ApplyV2(Handle, stateDiff, (uint)stateDiff.Length); } /// @@ -237,7 +240,7 @@ public byte[] Snapshot() var handle = TransactionChannel.EncodeStateFromSnapshotV1( Handle, snapshot, - (uint) snapshot.Length, + (uint)snapshot.Length, out var length); return handle != nint.Zero ? MemoryReader.ReadAndDestroyBytes(handle, length) : null; @@ -274,7 +277,7 @@ public byte[] Snapshot() var handle = TransactionChannel.EncodeStateFromSnapshotV2( Handle, snapshot, - (uint) snapshot.Length, + (uint)snapshot.Length, out var length); return handle != nint.Zero ? MemoryReader.ReadAndDestroyBytes(handle, length) : null; @@ -354,7 +357,7 @@ private nint GetWithKind(string name, BranchKind expectedKind) return nint.Zero; } - var branchKind = (BranchKind) BranchChannel.Kind(branchHandle); + var branchKind = (BranchKind)BranchChannel.Kind(branchHandle); if (branchKind == BranchKind.Null) { From bdc897545ed6c2a540a3926a31ec6ac63d459702 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 14 Apr 2024 22:34:42 +0200 Subject: [PATCH 49/75] Test change. --- .../Events/EventSubscriberFromId{TEvent}.cs | 85 +++++++++++++++++++ YDotNet/Document/Types/Arrays/Array.cs | 54 ++++++------ YDotNet/Document/Types/Branches/Branch.cs | 48 ++--------- YDotNet/Document/Types/Branches/BranchId.cs | 47 +++++----- 4 files changed, 139 insertions(+), 95 deletions(-) create mode 100644 YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs diff --git a/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs b/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs new file mode 100644 index 00000000..96894103 --- /dev/null +++ b/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs @@ -0,0 +1,85 @@ +using System.Collections.Concurrent; +using YDotNet.Document.Types.Branches; + +namespace YDotNet.Document.Events; + +internal class EventSubscriberFromId : IEventSubscriber +{ + private readonly EventManager manager; + private readonly Branch owner; + private readonly EventPublisher publisher = new(); + private readonly Func, (nint Handle, object Callback)> subscribe; + private readonly Action unsubscribe; + private (nint Handle, object? Callback) nativeSubscription; + + // The native callback, returned by `subscribe`, must be stored so it doesn't + // throw exceptions later if the Rust side invokes it after it's been collected. + public EventSubscriberFromId( + EventManager manager, + Branch owner, + Func, (nint Handle, object Callback)> subscribe, + Action unsubscribe) + { + this.manager = manager; + this.owner = owner; + this.subscribe = subscribe; + this.unsubscribe = unsubscribe; + } + + public void Clear() + { + publisher.Clear(); + + UnsubscribeWhenSubscribed(); + } + + public IDisposable Subscribe(Action handler) + { + // If this is the first native subscription, subscribe to the actual source by invoking the action. + if (nativeSubscription.Callback == null) + { + using (var transaction = owner.ReadTransaction()) + { + var handle = owner.BranchId.GetHandle(transaction); + + nativeSubscription = subscribe(handle, publisher.Publish); + } + + // Register the subscriber as active in the manager. + manager.Register(this); + } + + publisher.Subscribe(handler); + + return new DelegateDisposable(() => Unsubscribe(handler)); + } + + private void Unsubscribe(Action handler) + { + publisher.Unsubscribe(handler); + + UnsubscribeWhenSubscribed(); + } + + private void UnsubscribeWhenSubscribed() + { + // If this is the last subscription, we can unsubscribe from the native source again. + if (publisher.Count == 0 && nativeSubscription.Callback != null) + { + unsubscribe(nativeSubscription.Handle); + + nativeSubscription = default; + + // The manager will clear all active subscriptions when the document where the manager belongs to is disposed. + manager.Unregister(this); + } + } + + private sealed record DelegateDisposable(Action Delegate) : IDisposable + { + public void Dispose() + { + Delegate(); + } + } +} diff --git a/YDotNet/Document/Types/Arrays/Array.cs b/YDotNet/Document/Types/Arrays/Array.cs index 9d3c4578..104039c5 100644 --- a/YDotNet/Document/Types/Arrays/Array.cs +++ b/YDotNet/Document/Types/Arrays/Array.cs @@ -1,3 +1,4 @@ +using System.Reflection.Metadata; using YDotNet.Document.Cells; using YDotNet.Document.Events; using YDotNet.Document.StickyIndexes; @@ -16,14 +17,14 @@ namespace YDotNet.Document.Types.Arrays; /// public class Array : Branch { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal Array(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (array, action) => { ArrayChannel.ObserveCallback callback = (_, eventHandle) => @@ -35,16 +36,17 @@ internal Array(nint handle, Doc doc, bool isDeleted) } /// - /// Gets the number of elements stored within current instance of . + /// Gets the number of elements stored within current instance of . /// - public uint Length + /// The transaction that wraps this operation. + /// + /// The length. + /// + public uint Length(Transaction transaction) { - get - { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - return ArrayChannel.Length(Handle); - } + return ArrayChannel.Length(handle); } /// @@ -55,11 +57,11 @@ public uint Length /// The items to be inserted. public void InsertRange(Transaction transaction, uint index, params Input[] inputs) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); using var unsafeInputs = MemoryWriter.WriteStructArray(inputs.Select(x => x.InputNative).ToArray()); - ArrayChannel.InsertRange(Handle, transaction.Handle, index, unsafeInputs.Handle, (uint)inputs.Length); + ArrayChannel.InsertRange(handle, transaction.Handle, index, unsafeInputs.Handle, (uint)inputs.Length); } /// @@ -70,9 +72,9 @@ public void InsertRange(Transaction transaction, uint index, params Input[] inpu /// The amount of items to remove. public void RemoveRange(Transaction transaction, uint index, uint length) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - ArrayChannel.RemoveRange(Handle, transaction.Handle, index, length); + ArrayChannel.RemoveRange(handle, transaction.Handle, index, length); } /// @@ -88,11 +90,11 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public Output? Get(Transaction transaction, uint index) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - var handle = ArrayChannel.Get(Handle, transaction.Handle, index); + var outputHandle = ArrayChannel.Get(handle, transaction.Handle, index); - return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + return outputHandle != nint.Zero ? Output.CreateAndRelease(outputHandle, Doc) : null; } /// @@ -106,9 +108,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// The index to which the item will be moved to. public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - ArrayChannel.Move(Handle, transaction.Handle, sourceIndex, targetIndex); + ArrayChannel.Move(handle, transaction.Handle, sourceIndex, targetIndex); } /// @@ -119,11 +121,11 @@ public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) /// The instance. public ArrayIterator Iterate(Transaction transaction) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - var handle = ArrayChannel.Iterator(Handle, transaction.Handle); + var iteratorHandle = ArrayChannel.Iterator(handle, transaction.Handle); - return new ArrayIterator(handle.Checked(), Doc); + return new ArrayIterator(iteratorHandle.Checked(), Doc); } /// @@ -136,8 +138,6 @@ public ArrayIterator Iterate(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - return onObserve.Subscribe(action); } @@ -155,10 +155,10 @@ public IDisposable Observe(Action action) /// public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { - ThrowIfDisposed(); + var handle = BranchId.GetHandle(transaction); - var handle = StickyIndexChannel.FromIndex(Handle, transaction.Handle, index, (sbyte)associationType); + var indexHandle = StickyIndexChannel.FromIndex(handle, transaction.Handle, index, (sbyte)associationType); - return handle != nint.Zero ? new StickyIndex(handle) : null; + return indexHandle != nint.Zero ? new StickyIndex(indexHandle) : null; } } diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index ebe2e056..109d5191 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -11,19 +11,19 @@ namespace YDotNet.Document.Types.Branches; /// /// The generic type that can be used to refer to all shared data type instances. /// -public abstract class Branch : UnmanagedResource +public abstract class Branch { - private readonly EventSubscriber onDeep; + private readonly EventSubscriberFromId onDeep; protected internal Branch(nint handle, Doc doc, bool isDeleted) - : base(handle, isDeleted) { Doc = doc; -#pragma warning disable CA1806 // Do not ignore method results - onDeep = new EventSubscriber( + BranchId = BranchId.FromHandle(handle, isDeleted); + + onDeep = new EventSubscriberFromId( doc.EventManager, - handle, + this, (branch, action) => { BranchChannel.ObserveCallback callback = (_, length, ev) => @@ -38,9 +38,10 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) return (BranchChannel.ObserveDeep(branch, nint.Zero, callback), callback); }, SubscriptionChannel.Unobserve); -#pragma warning restore CA1806 // Do not ignore method results } + internal BranchId BranchId { get; } + internal Doc Doc { get; } /// @@ -64,8 +65,6 @@ public IDisposable ObserveDeep(Action> action) /// Another write transaction has been created and not committed yet. public Transaction WriteTransaction() { - ThrowIfDisposed(); - return Doc.WriteTransaction(); } @@ -76,37 +75,6 @@ public Transaction WriteTransaction() /// Another write transaction has been created and not committed yet. public Transaction ReadTransaction() { - ThrowIfDisposed(); - return Doc.ReadTransaction(); } - - /// - /// Returns the of this collection. - /// - /// The of this collection. - public BranchId Id() - { - ThrowIfDisposed(); - - var branchIdNative = BranchChannel.Id(Handle); - - return new BranchId(branchIdNative, Doc); - } - - /// - /// Indicates whether the instance is alive. - /// - /// A value indicating whether the is alive. - public bool Alive() - { - return BranchChannel.Alive(Handle) == 1; - } - - /// - protected override void DisposeCore(bool disposing) - { - // Nothing should be done to dispose `Branch` instances (shared types). - // They're disposed automatically when their parent `Doc` is disposed. - } } diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs index 07574c4a..3458ecc2 100644 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ b/YDotNet/Document/Types/Branches/BranchId.cs @@ -7,15 +7,20 @@ namespace YDotNet.Document.Types.Branches; /// /// Represents a logical identifier for a shared collection. /// -public class BranchId +internal record struct BranchId { - private readonly Doc doc; + private readonly bool isDeleted; - internal BranchId(BranchIdNative native, Doc doc) + internal BranchId(BranchIdNative native, bool isDeleted) { - this.doc = doc; - Native = native; + + this.isDeleted = isDeleted; + } + + public static BranchId FromHandle(nint handle, bool isDeleted) + { + return new BranchId(isDeleted ? default : BranchChannel.Id(handle), isDeleted); } private BranchIdNative Native { get; } @@ -47,38 +52,24 @@ internal BranchId(BranchIdNative native, Doc doc) /// public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); - public Branch? Get(Transaction transaction) + public nint GetHandle(Transaction transaction) { + if (isDeleted) + { + throw new ObjectDisposedException("Object is disposed."); + } + var handle = MemoryWriter.WriteStruct(Native); var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); handle.Dispose(); - if (branchHandle == nint.Zero) + if (branchHandle == nint.Zero || BranchChannel.Alive(branchHandle) == 0) { - return null; + throw new ObjectDisposedException("Object is disposed."); } - var branchKind = (BranchKind) BranchChannel.Kind(branchHandle); - var branchDeleted = BranchChannel.Alive(branchHandle) == 0; - - switch (branchKind) - { - case BranchKind.Array: - return doc.GetArray(branchHandle, branchDeleted); - case BranchKind.Map: - return doc.GetMap(branchHandle, branchDeleted); - case BranchKind.Text: - return doc.GetText(branchHandle, branchDeleted); - case BranchKind.XmlElement: - return doc.GetXmlElement(branchHandle, branchDeleted); - case BranchKind.XmlText: - return doc.GetXmlText(branchHandle, branchDeleted); - case BranchKind.XmlFragment: - return doc.GetXmlFragment(branchHandle, branchDeleted); - default: - return null; - } + return branchHandle; } } From a8e313f487b2ab957538c39630a2775e84ed483f Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 23 Apr 2024 22:46:11 -0300 Subject: [PATCH 50/75] feat: remove unused tests and classes --- .../YDotNet.Tests.Unit/Branches/AliveTests.cs | 27 ------- .../Branches/BranchId/GetTests.cs | 33 -------- Tests/YDotNet.Tests.Unit/Branches/IdTests.cs | 74 ------------------ YDotNet/Document/Types/Branches/BranchId.cs | 75 ------------------- 4 files changed, 209 deletions(-) delete mode 100644 Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs delete mode 100644 Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs delete mode 100644 Tests/YDotNet.Tests.Unit/Branches/IdTests.cs delete mode 100644 YDotNet/Document/Types/Branches/BranchId.cs diff --git a/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs b/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs deleted file mode 100644 index 16908a02..00000000 --- a/Tests/YDotNet.Tests.Unit/Branches/AliveTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using NUnit.Framework; -using YDotNet.Document; - -namespace YDotNet.Tests.Unit.Branches; - -public class AliveTests -{ - [Test] - public void ReturnsTrueWhenAlive() - { - // Arrange - var doc = new Doc(); - var text = doc.Text("text"); - - // Act - var alive = text.Alive(); - - // Assert - Assert.That(alive, Is.True); - } - - [Test] - [Ignore("TODO: Check how to mark a Branch as deleted.")] - public void ReturnsFalseWhenNotAlive() - { - } -} diff --git a/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs b/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs deleted file mode 100644 index e47c9d69..00000000 --- a/Tests/YDotNet.Tests.Unit/Branches/BranchId/GetTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -using NUnit.Framework; -using YDotNet.Document; -using YDotNet.Document.Types.Texts; - -namespace YDotNet.Tests.Unit.Branches.BranchId; - -public class GetTests -{ - [Test] - public void ReturnsTheCorrectBranchWhenAlive() - { - // Arrange - var doc = new Doc(); - var branch = doc.Text("text"); - var branchId = branch.Id(); - - // Act - var transaction = doc.ReadTransaction(); - var newBranch = branchId.Get(transaction); - transaction.Commit(); - - // Assert - Assert.That(newBranch, Is.Not.Null); - Assert.That(newBranch, Is.TypeOf()); - Assert.That(newBranch, Is.EqualTo(branch)); - } - - [Test] - [Ignore("TODO: Check how to mark a Branch as deleted.")] - public void ReturnsTheCorrectBranchWhenNotAlive() - { - } -} diff --git a/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs b/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs deleted file mode 100644 index 2de40922..00000000 --- a/Tests/YDotNet.Tests.Unit/Branches/IdTests.cs +++ /dev/null @@ -1,74 +0,0 @@ -using NUnit.Framework; -using YDotNet.Document; -using YDotNet.Document.Cells; -using YDotNet.Document.Options; -using YDotNet.Document.Types.Branches; - -namespace YDotNet.Tests.Unit.Branches; - -public class IdTests -{ - [Test] - public void ReturnsIdForRootLevelType() - { - // Arrange - var doc = new Doc(); - var branch = doc.Text("text"); - - // Act - var id = branch.Id(); - - // Assert - Assert.That(id, Is.Not.Null); - Assert.That(id.HasName, Is.True); - Assert.That(id.HasClientIdAndClock, Is.False); - Assert.That(id.Name, Is.EqualTo("text")); - Assert.That(id.ClientId, Is.EqualTo(expected: null)); - Assert.That(id.Clock, Is.EqualTo(expected: null)); - } - - [Test] - public void ReturnsIdForNestedType() - { - // Arrange - var doc = new Doc( - new DocOptions - { - Id = 37 - }); - var map = doc.Map("map"); - - var transaction = map.WriteTransaction(); - map.Insert(transaction, "text", Input.Text("")); - Branch branch = map.Get(transaction, "text")!.Text; - transaction.Commit(); - - // Act - var id = branch.Id(); - - // Assert - Assert.That(id, Is.Not.Null); - Assert.That(id.HasName, Is.False); - Assert.That(id.HasClientIdAndClock, Is.True); - Assert.That(id.Name, Is.Null); - Assert.That(id.ClientId, Is.EqualTo(expected: 37)); - Assert.That(id.Clock, Is.EqualTo(expected: 0)); - - // Arrange - transaction = map.WriteTransaction(); - map.Insert(transaction, "array", Input.Array(Array.Empty())); - branch = map.Get(transaction, "array")!.Array; - transaction.Commit(); - - // Act - id = branch.Id(); - - // Assert - Assert.That(id, Is.Not.Null); - Assert.That(id.HasName, Is.False); - Assert.That(id.HasClientIdAndClock, Is.True); - Assert.That(id.Name, Is.Null); - Assert.That(id.ClientId, Is.EqualTo(expected: 37)); - Assert.That(id.Clock, Is.EqualTo(expected: 1)); - } -} diff --git a/YDotNet/Document/Types/Branches/BranchId.cs b/YDotNet/Document/Types/Branches/BranchId.cs deleted file mode 100644 index 3458ecc2..00000000 --- a/YDotNet/Document/Types/Branches/BranchId.cs +++ /dev/null @@ -1,75 +0,0 @@ -using YDotNet.Document.Transactions; -using YDotNet.Infrastructure; -using YDotNet.Native.Types.Branches; - -namespace YDotNet.Document.Types.Branches; - -/// -/// Represents a logical identifier for a shared collection. -/// -internal record struct BranchId -{ - private readonly bool isDeleted; - - internal BranchId(BranchIdNative native, bool isDeleted) - { - Native = native; - - this.isDeleted = isDeleted; - } - - public static BranchId FromHandle(nint handle, bool isDeleted) - { - return new BranchId(isDeleted ? default : BranchChannel.Id(handle), isDeleted); - } - - private BranchIdNative Native { get; } - - /// - /// Gets a value indicating whether and have values. - /// If this is false, check . - /// - public bool HasClientIdAndClock => Native.ClientIdOrLength > 0; - - /// - /// Gets a value indicating whether has values. - /// If this is false, check . - /// - public bool HasName => !HasClientIdAndClock; - - /// - /// Gets the client ID of a creator of a nested shared type that this points to. - /// - public long? ClientId => HasClientIdAndClock ? Native.ClientIdOrLength : null; - - /// - /// Gets the clock number timestamp when the creator of a nested shared type created it. - /// - public uint? Clock => HasClientIdAndClock ? Native.BranchIdVariant.Clock : null; - - /// - /// Gets the name of the root-level shared type. - /// - public string? Name => HasClientIdAndClock ? null : MemoryReader.ReadUtf8String(Native.BranchIdVariant.NamePointer); - - public nint GetHandle(Transaction transaction) - { - if (isDeleted) - { - throw new ObjectDisposedException("Object is disposed."); - } - - var handle = MemoryWriter.WriteStruct(Native); - - var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); - - handle.Dispose(); - - if (branchHandle == nint.Zero || BranchChannel.Alive(branchHandle) == 0) - { - throw new ObjectDisposedException("Object is disposed."); - } - - return branchHandle; - } -} From 4f37b4ad9064f3432773cc6d93d07aba07db88b0 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 23 Apr 2024 22:46:48 -0300 Subject: [PATCH 51/75] feat: update `Branch` to hold a `BranchIdNative` and expose the `GetHandle()` method --- .../Events/EventSubscriberFromId{TEvent}.cs | 35 +++++++------ YDotNet/Document/Types/Arrays/Array.cs | 31 ++++++----- YDotNet/Document/Types/Branches/Branch.cs | 51 ++++++++++++++++--- 3 files changed, 75 insertions(+), 42 deletions(-) diff --git a/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs b/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs index 96894103..7ad0bf45 100644 --- a/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs +++ b/YDotNet/Document/Events/EventSubscriberFromId{TEvent}.cs @@ -1,5 +1,4 @@ -using System.Collections.Concurrent; -using YDotNet.Document.Types.Branches; +using YDotNet.Document.Types.Branches; namespace YDotNet.Document.Events; @@ -28,50 +27,50 @@ public EventSubscriberFromId( public void Clear() { - publisher.Clear(); + this.publisher.Clear(); - UnsubscribeWhenSubscribed(); + this.UnsubscribeWhenSubscribed(); } public IDisposable Subscribe(Action handler) { // If this is the first native subscription, subscribe to the actual source by invoking the action. - if (nativeSubscription.Callback == null) + if (this.nativeSubscription.Callback == null) { - using (var transaction = owner.ReadTransaction()) + using (var transaction = this.owner.ReadTransaction()) { - var handle = owner.BranchId.GetHandle(transaction); + var handle = this.owner.GetHandle(transaction); - nativeSubscription = subscribe(handle, publisher.Publish); + this.nativeSubscription = this.subscribe(handle, this.publisher.Publish); } // Register the subscriber as active in the manager. - manager.Register(this); + this.manager.Register(this); } - publisher.Subscribe(handler); + this.publisher.Subscribe(handler); - return new DelegateDisposable(() => Unsubscribe(handler)); + return new DelegateDisposable(() => this.Unsubscribe(handler)); } private void Unsubscribe(Action handler) { - publisher.Unsubscribe(handler); + this.publisher.Unsubscribe(handler); - UnsubscribeWhenSubscribed(); + this.UnsubscribeWhenSubscribed(); } private void UnsubscribeWhenSubscribed() { // If this is the last subscription, we can unsubscribe from the native source again. - if (publisher.Count == 0 && nativeSubscription.Callback != null) + if (this.publisher.Count == 0 && this.nativeSubscription.Callback != null) { - unsubscribe(nativeSubscription.Handle); + this.unsubscribe(this.nativeSubscription.Handle); - nativeSubscription = default; + this.nativeSubscription = default; // The manager will clear all active subscriptions when the document where the manager belongs to is disposed. - manager.Unregister(this); + this.manager.Unregister(this); } } @@ -79,7 +78,7 @@ private sealed record DelegateDisposable(Action Delegate) : IDisposable { public void Dispose() { - Delegate(); + this.Delegate(); } } } diff --git a/YDotNet/Document/Types/Arrays/Array.cs b/YDotNet/Document/Types/Arrays/Array.cs index 104039c5..b20117f2 100644 --- a/YDotNet/Document/Types/Arrays/Array.cs +++ b/YDotNet/Document/Types/Arrays/Array.cs @@ -1,4 +1,3 @@ -using System.Reflection.Metadata; using YDotNet.Document.Cells; using YDotNet.Document.Events; using YDotNet.Document.StickyIndexes; @@ -22,13 +21,13 @@ public class Array : Branch internal Array(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriberFromId( + this.onObserve = new EventSubscriberFromId( doc.EventManager, this, (array, action) => { ArrayChannel.ObserveCallback callback = (_, eventHandle) => - action(new ArrayEvent(eventHandle, Doc)); + action(new ArrayEvent(eventHandle, this.Doc)); return (ArrayChannel.Observe(array, nint.Zero, callback), callback); }, @@ -40,11 +39,11 @@ internal Array(nint handle, Doc doc, bool isDeleted) /// /// The transaction that wraps this operation. /// - /// The length. + /// The length. /// public uint Length(Transaction transaction) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); return ArrayChannel.Length(handle); } @@ -57,11 +56,11 @@ public uint Length(Transaction transaction) /// The items to be inserted. public void InsertRange(Transaction transaction, uint index, params Input[] inputs) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); using var unsafeInputs = MemoryWriter.WriteStructArray(inputs.Select(x => x.InputNative).ToArray()); - ArrayChannel.InsertRange(handle, transaction.Handle, index, unsafeInputs.Handle, (uint)inputs.Length); + ArrayChannel.InsertRange(handle, transaction.Handle, index, unsafeInputs.Handle, (uint) inputs.Length); } /// @@ -72,7 +71,7 @@ public void InsertRange(Transaction transaction, uint index, params Input[] inpu /// The amount of items to remove. public void RemoveRange(Transaction transaction, uint index, uint length) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); ArrayChannel.RemoveRange(handle, transaction.Handle, index, length); } @@ -90,11 +89,11 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public Output? Get(Transaction transaction, uint index) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); var outputHandle = ArrayChannel.Get(handle, transaction.Handle, index); - return outputHandle != nint.Zero ? Output.CreateAndRelease(outputHandle, Doc) : null; + return outputHandle != nint.Zero ? Output.CreateAndRelease(outputHandle, this.Doc) : null; } /// @@ -108,7 +107,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// The index to which the item will be moved to. public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); ArrayChannel.Move(handle, transaction.Handle, sourceIndex, targetIndex); } @@ -121,11 +120,11 @@ public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) /// The instance. public ArrayIterator Iterate(Transaction transaction) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); var iteratorHandle = ArrayChannel.Iterator(handle, transaction.Handle); - return new ArrayIterator(iteratorHandle.Checked(), Doc); + return new ArrayIterator(iteratorHandle.Checked(), this.Doc); } /// @@ -138,7 +137,7 @@ public ArrayIterator Iterate(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - return onObserve.Subscribe(action); + return this.onObserve.Subscribe(action); } /// @@ -155,9 +154,9 @@ public IDisposable Observe(Action action) /// public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { - var handle = BranchId.GetHandle(transaction); + var handle = this.GetHandle(transaction); - var indexHandle = StickyIndexChannel.FromIndex(handle, transaction.Handle, index, (sbyte)associationType); + var indexHandle = StickyIndexChannel.FromIndex(handle, transaction.Handle, index, (sbyte) associationType); return indexHandle != nint.Zero ? new StickyIndex(indexHandle) : null; } diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 109d5191..8d39c7a3 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -11,17 +11,18 @@ namespace YDotNet.Document.Types.Branches; /// /// The generic type that can be used to refer to all shared data type instances. /// -public abstract class Branch +public abstract class Branch : UnmanagedResource { private readonly EventSubscriberFromId onDeep; protected internal Branch(nint handle, Doc doc, bool isDeleted) + : base(handle, isDeleted) { - Doc = doc; + this.Doc = doc; - BranchId = BranchId.FromHandle(handle, isDeleted); + this.BranchId = isDeleted ? null : BranchChannel.Id(handle); - onDeep = new EventSubscriberFromId( + this.onDeep = new EventSubscriberFromId( doc.EventManager, this, (branch, action) => @@ -40,7 +41,7 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) SubscriptionChannel.Unobserve); } - internal BranchId BranchId { get; } + internal BranchIdNative? BranchId { get; } internal Doc Doc { get; } @@ -55,7 +56,7 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable ObserveDeep(Action> action) { - return onDeep.Subscribe(action); + return this.onDeep.Subscribe(action); } /// @@ -65,7 +66,7 @@ public IDisposable ObserveDeep(Action> action) /// Another write transaction has been created and not committed yet. public Transaction WriteTransaction() { - return Doc.WriteTransaction(); + return this.Doc.WriteTransaction(); } /// @@ -75,6 +76,40 @@ public Transaction WriteTransaction() /// Another write transaction has been created and not committed yet. public Transaction ReadTransaction() { - return Doc.ReadTransaction(); + return this.Doc.ReadTransaction(); + } + + /// + /// Gets a handle using the stored . + /// + /// The transaction used to acquire the handle to the . + /// The handle to the . + /// If is true. + protected internal nint GetHandle(Transaction transaction) + { + if (this.IsDisposed) + { + throw new ObjectDisposedException("Object is disposed."); + } + + var handle = MemoryWriter.WriteStruct(this.BranchId); + + var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); + + handle.Dispose(); + + if (branchHandle == nint.Zero || BranchChannel.Alive(branchHandle) == 0) + { + throw new ObjectDisposedException("Object is disposed."); + } + + return branchHandle; + } + + /// + protected override void DisposeCore(bool disposing) + { + // Nothing should be done to dispose `Branch` instances (shared types). + // They're disposed automatically when their parent `Doc` is disposed. } } From bc8846d5e155e6e21d72bd39637798c789faf2b5 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 23 Apr 2024 22:47:07 -0300 Subject: [PATCH 52/75] test: update unit tests to adapt to the new API of `Array.Length()` --- .../YDotNet.Tests.Unit/Arrays/CreateTests.cs | 5 ++- .../Arrays/InsertRangeTests.cs | 20 +++++------ .../YDotNet.Tests.Unit/Arrays/LengthTests.cs | 33 ++++++++----------- Tests/YDotNet.Tests.Unit/Arrays/MoveTests.cs | 13 +++----- .../Arrays/RemoveRangeTests.cs | 16 ++++----- Tests/YDotNet.Tests.Unit/Maps/GetTests.cs | 7 ++-- .../UndoManagers/RedoTests.cs | 12 +++++-- .../UndoManagers/UndoTests.cs | 12 +++++-- 8 files changed, 61 insertions(+), 57 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Arrays/CreateTests.cs b/Tests/YDotNet.Tests.Unit/Arrays/CreateTests.cs index 7e63086d..02356053 100644 --- a/Tests/YDotNet.Tests.Unit/Arrays/CreateTests.cs +++ b/Tests/YDotNet.Tests.Unit/Arrays/CreateTests.cs @@ -13,9 +13,12 @@ public void Create() // Act var array = doc.Array("array"); + var transaction = doc.ReadTransaction(); + var length = array.Length(transaction); + transaction.Commit(); // Assert Assert.That(array.Handle, Is.GreaterThan(nint.Zero)); - Assert.That(array.Length, Is.EqualTo(expected: 0)); + Assert.That(length, Is.EqualTo(expected: 0)); } } diff --git a/Tests/YDotNet.Tests.Unit/Arrays/InsertRangeTests.cs b/Tests/YDotNet.Tests.Unit/Arrays/InsertRangeTests.cs index 2cf77042..62240def 100644 --- a/Tests/YDotNet.Tests.Unit/Arrays/InsertRangeTests.cs +++ b/Tests/YDotNet.Tests.Unit/Arrays/InsertRangeTests.cs @@ -16,10 +16,11 @@ public void InsertEmptyRange() // Act var transaction = doc.WriteTransaction(); array.InsertRange(transaction, index: 0); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 0)); + Assert.That(length, Is.EqualTo(expected: 0)); } [Test] @@ -32,14 +33,12 @@ public void InsertSingleItemRange() // Act var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Boolean(value: true) - }); + transaction, index: 0, Input.Boolean(value: true)); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 1)); + Assert.That(length, Is.EqualTo(expected: 1)); } [Test] @@ -52,14 +51,11 @@ public void InsertMultiItemRange() // Act var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Boolean(value: true), - Input.Long(value: 2469L) - }); + transaction, index: 0, Input.Boolean(value: true), Input.Long(value: 2469L)); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 2)); + Assert.That(length, Is.EqualTo(expected: 2)); } } diff --git a/Tests/YDotNet.Tests.Unit/Arrays/LengthTests.cs b/Tests/YDotNet.Tests.Unit/Arrays/LengthTests.cs index bc4e456c..32f25ba5 100644 --- a/Tests/YDotNet.Tests.Unit/Arrays/LengthTests.cs +++ b/Tests/YDotNet.Tests.Unit/Arrays/LengthTests.cs @@ -14,7 +14,9 @@ public void InitialLengthIsZero() var array = doc.Array("array"); // Act - var length = array.Length; + var transaction = doc.ReadTransaction(); + var length = array.Length(transaction); + transaction.Commit(); // Assert Assert.That(length, Is.EqualTo(expected: 0)); @@ -30,26 +32,22 @@ public void IncreasesWhenAdded() // Act var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Boolean(value: true) - }); + transaction, index: 0, Input.Boolean(value: true)); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 1)); + Assert.That(length, Is.EqualTo(expected: 1)); // Act transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Boolean(value: true) - }); + transaction, index: 0, Input.Boolean(value: true)); + length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 2)); + Assert.That(length, Is.EqualTo(expected: 2)); } [Test] @@ -60,23 +58,20 @@ public void DecreasesWhenRemoved() var array = doc.Array("array"); var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Boolean(value: true), - Input.Long(value: 2469L), - Input.Undefined() - }); + transaction, index: 0, Input.Boolean(value: true), Input.Long(value: 2469L), Input.Undefined()); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 3)); + Assert.That(length, Is.EqualTo(expected: 3)); // Act transaction = doc.WriteTransaction(); array.RemoveRange(transaction, index: 1, length: 2); + length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 1)); + Assert.That(length, Is.EqualTo(expected: 1)); } } diff --git a/Tests/YDotNet.Tests.Unit/Arrays/MoveTests.cs b/Tests/YDotNet.Tests.Unit/Arrays/MoveTests.cs index ff7485b9..2a45c384 100644 --- a/Tests/YDotNet.Tests.Unit/Arrays/MoveTests.cs +++ b/Tests/YDotNet.Tests.Unit/Arrays/MoveTests.cs @@ -15,7 +15,7 @@ public void MoveFromBeginningToEnding() // Act var transaction = doc.WriteTransaction(); - array.Move(transaction, sourceIndex: 0, array.Length); + array.Move(transaction, sourceIndex: 0, array.Length(transaction)); transaction.Commit(); // Assert @@ -30,7 +30,7 @@ public void MoveFromEndingToBeginning() // Act var transaction = doc.WriteTransaction(); - array.Move(transaction, array.Length - 1, targetIndex: 0); + array.Move(transaction, array.Length(transaction) - 1, targetIndex: 0); transaction.Commit(); // Assert @@ -74,13 +74,8 @@ public void MoveToTheSameIndex() var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Long(value: 1), - Input.Long(value: 2), - Input.Long(value: 3), - Input.Long(value: 4) - }); + transaction, index: 0, Input.Long(value: 1), Input.Long(value: 2), Input.Long(value: 3), + Input.Long(value: 4)); transaction.Commit(); return (doc, array); diff --git a/Tests/YDotNet.Tests.Unit/Arrays/RemoveRangeTests.cs b/Tests/YDotNet.Tests.Unit/Arrays/RemoveRangeTests.cs index 5afd4b72..b4639b43 100644 --- a/Tests/YDotNet.Tests.Unit/Arrays/RemoveRangeTests.cs +++ b/Tests/YDotNet.Tests.Unit/Arrays/RemoveRangeTests.cs @@ -16,10 +16,11 @@ public void RemoveEmptyRange() // Act var transaction = doc.WriteTransaction(); array.RemoveRange(transaction, index: 0, length: 0); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 3)); + Assert.That(length, Is.EqualTo(expected: 3)); } [Test] @@ -31,10 +32,11 @@ public void RemoveSingleItemRange() // Act var transaction = doc.WriteTransaction(); array.RemoveRange(transaction, index: 1, length: 1); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 2)); + Assert.That(length, Is.EqualTo(expected: 2)); } [Test] @@ -46,10 +48,11 @@ public void RemoveMultiItemRange() // Act var transaction = doc.WriteTransaction(); array.RemoveRange(transaction, index: 0, length: 3); + var length = array.Length(transaction); transaction.Commit(); // Assert - Assert.That(array.Length, Is.EqualTo(expected: 0)); + Assert.That(length, Is.EqualTo(expected: 0)); } private (Doc, Array) ArrangeDoc() @@ -59,12 +62,7 @@ public void RemoveMultiItemRange() var transaction = doc.WriteTransaction(); array.InsertRange( - transaction, index: 0, new[] - { - Input.Long(value: 420L), - Input.Boolean(value: true), - Input.Null() - }); + transaction, index: 0, Input.Long(value: 420L), Input.Boolean(value: true), Input.Null()); transaction.Commit(); return (doc, array); diff --git a/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs b/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs index f5c03ab3..3216a37b 100644 --- a/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs +++ b/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs @@ -119,8 +119,8 @@ public void GetCollection() // Assert //Assert.That(value1, Is.EqualTo(new byte[] { 2, 4, 6, 9 })); Assert.That(value1.Count, Is.EqualTo(expected: 2)); - Assert.That(value1[0].Long, Is.EqualTo(expected: 2469)); - Assert.That(value1[1].Long, Is.EqualTo(expected: -420L)); + Assert.That(value1[index: 0].Long, Is.EqualTo(expected: 2469)); + Assert.That(value1[index: 1].Long, Is.EqualTo(expected: -420L)); Assert.That(value2.Tag, Is.EqualTo(OutputTag.Boolean)); } @@ -226,11 +226,12 @@ public void GetArray() // Act var value1 = map.Get(transaction, "value1").Array; + var value1Length = value1.Length(transaction); var value2 = map.Get(transaction, "value2"); // Assert Assert.That(value1, Is.Not.Null); - Assert.That(value1.Length, Is.EqualTo(expected: 2)); + Assert.That(value1Length, Is.EqualTo(expected: 2)); Assert.That(value2.Tag, Is.EqualTo(OutputTag.Null)); } diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs index d97eb09f..d0b9ca73 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/RedoTests.cs @@ -107,8 +107,12 @@ public void RedoAddingAndUpdatingAndRemovingContentOnArray() undoManager.Undo(); var result = undoManager.Redo(); + transaction = doc.ReadTransaction(); + var length = array.Length(transaction); + transaction.Commit(); + // Assert - Assert.That(array.Length, Is.EqualTo(expected: 4)); + Assert.That(length, Is.EqualTo(expected: 4)); Assert.That(result, Is.True); // Act (remove, undo, and redo) @@ -118,8 +122,12 @@ public void RedoAddingAndUpdatingAndRemovingContentOnArray() undoManager.Undo(); result = undoManager.Redo(); + transaction = doc.ReadTransaction(); + length = array.Length(transaction); + transaction.Commit(); + // Assert - Assert.That(array.Length, Is.EqualTo(expected: 2)); + Assert.That(length, Is.EqualTo(expected: 2)); Assert.That(result, Is.True); } diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs index 196817f5..d69ae5fd 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/UndoTests.cs @@ -102,8 +102,12 @@ public void UndoAddingAndUpdatingAndRemovingContentOnArray() transaction.Commit(); var result = undoManager.Undo(); + transaction = doc.ReadTransaction(); + var length = array.Length(transaction); + transaction.Commit(); + // Assert - Assert.That(array.Length, Is.EqualTo(expected: 3)); + Assert.That(length, Is.EqualTo(expected: 3)); Assert.That(result, Is.True); // Act (remove and undo) @@ -112,10 +116,14 @@ public void UndoAddingAndUpdatingAndRemovingContentOnArray() transaction.Commit(); result = undoManager.Undo(); + transaction = doc.ReadTransaction(); + length = array.Length(transaction); + transaction.Commit(); + // Assert // TODO [LSViana] Check with the team why the amount of items isn't 3. - Assert.That(array.Length, Is.EqualTo(expected: 3)); + Assert.That(length, Is.EqualTo(expected: 3)); Assert.That(result, Is.True); } From 7a7c2bc5cd8322104b0c9f67cf71b197be201498 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 21:42:11 -0300 Subject: [PATCH 53/75] style: inline usages of `GetHandle()` in `Array` --- YDotNet/Document/Types/Arrays/Array.cs | 37 +++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/YDotNet/Document/Types/Arrays/Array.cs b/YDotNet/Document/Types/Arrays/Array.cs index b20117f2..4827368c 100644 --- a/YDotNet/Document/Types/Arrays/Array.cs +++ b/YDotNet/Document/Types/Arrays/Array.cs @@ -43,9 +43,7 @@ internal Array(nint handle, Doc doc, bool isDeleted) /// public uint Length(Transaction transaction) { - var handle = this.GetHandle(transaction); - - return ArrayChannel.Length(handle); + return ArrayChannel.Length(this.GetHandle(transaction)); } /// @@ -56,11 +54,14 @@ public uint Length(Transaction transaction) /// The items to be inserted. public void InsertRange(Transaction transaction, uint index, params Input[] inputs) { - var handle = this.GetHandle(transaction); - using var unsafeInputs = MemoryWriter.WriteStructArray(inputs.Select(x => x.InputNative).ToArray()); - ArrayChannel.InsertRange(handle, transaction.Handle, index, unsafeInputs.Handle, (uint) inputs.Length); + ArrayChannel.InsertRange( + this.GetHandle(transaction), + transaction.Handle, + index, + unsafeInputs.Handle, + (uint) inputs.Length); } /// @@ -71,9 +72,7 @@ public void InsertRange(Transaction transaction, uint index, params Input[] inpu /// The amount of items to remove. public void RemoveRange(Transaction transaction, uint index, uint length) { - var handle = this.GetHandle(transaction); - - ArrayChannel.RemoveRange(handle, transaction.Handle, index, length); + ArrayChannel.RemoveRange(this.GetHandle(transaction), transaction.Handle, index, length); } /// @@ -89,9 +88,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public Output? Get(Transaction transaction, uint index) { - var handle = this.GetHandle(transaction); - - var outputHandle = ArrayChannel.Get(handle, transaction.Handle, index); + var outputHandle = ArrayChannel.Get(this.GetHandle(transaction), transaction.Handle, index); return outputHandle != nint.Zero ? Output.CreateAndRelease(outputHandle, this.Doc) : null; } @@ -107,9 +104,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// The index to which the item will be moved to. public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) { - var handle = this.GetHandle(transaction); - - ArrayChannel.Move(handle, transaction.Handle, sourceIndex, targetIndex); + ArrayChannel.Move(this.GetHandle(transaction), transaction.Handle, sourceIndex, targetIndex); } /// @@ -120,9 +115,7 @@ public void Move(Transaction transaction, uint sourceIndex, uint targetIndex) /// The instance. public ArrayIterator Iterate(Transaction transaction) { - var handle = this.GetHandle(transaction); - - var iteratorHandle = ArrayChannel.Iterator(handle, transaction.Handle); + var iteratorHandle = ArrayChannel.Iterator(this.GetHandle(transaction), transaction.Handle); return new ArrayIterator(iteratorHandle.Checked(), this.Doc); } @@ -154,9 +147,11 @@ public IDisposable Observe(Action action) /// public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { - var handle = this.GetHandle(transaction); - - var indexHandle = StickyIndexChannel.FromIndex(handle, transaction.Handle, index, (sbyte) associationType); + var indexHandle = StickyIndexChannel.FromIndex( + this.GetHandle(transaction), + transaction.Handle, + index, + (sbyte) associationType); return indexHandle != nint.Zero ? new StickyIndex(indexHandle) : null; } From c025081c9c1c60af175550cb0264fda4250c6de3 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 21:42:27 -0300 Subject: [PATCH 54/75] style: update accessors and code style in `UnmanagedResource` --- YDotNet/Infrastructure/UnmanagedResource.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/YDotNet/Infrastructure/UnmanagedResource.cs b/YDotNet/Infrastructure/UnmanagedResource.cs index e3fc9cf5..05ca7d4b 100644 --- a/YDotNet/Infrastructure/UnmanagedResource.cs +++ b/YDotNet/Infrastructure/UnmanagedResource.cs @@ -5,10 +5,10 @@ namespace YDotNet.Infrastructure; /// public abstract class UnmanagedResource : Resource { - internal protected UnmanagedResource(nint handle, bool isDisposed = false) + protected internal UnmanagedResource(nint handle, bool isDisposed = false) : base(isDisposed) { - Handle = handle; + this.Handle = handle; } internal nint Handle { get; } From e3002cb770e7ce789702961b68a635761dabeaed Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 21:47:18 -0300 Subject: [PATCH 55/75] feat: replace `this.Handle` with `this.GetHandle()` in `Map` --- YDotNet/Document/Types/Maps/Map.cs | 36 +++++++++--------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/YDotNet/Document/Types/Maps/Map.cs b/YDotNet/Document/Types/Maps/Map.cs index 8f356b18..a831beb6 100644 --- a/YDotNet/Document/Types/Maps/Map.cs +++ b/YDotNet/Document/Types/Maps/Map.cs @@ -20,13 +20,13 @@ public class Map : Branch internal Map(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + this.onObserve = new EventSubscriber( doc.EventManager, handle, (map, action) => { MapChannel.ObserveCallback callback = (_, eventHandle) => - action(new MapEvent(eventHandle, Doc)); + action(new MapEvent(eventHandle, this.Doc)); return (MapChannel.Observe(map, nint.Zero, callback), callback); }, @@ -44,12 +44,10 @@ internal Map(nint handle, Doc doc, bool isDeleted) /// The instance to be inserted. public void Insert(Transaction transaction, string key, Input input) { - ThrowIfDisposed(); - using var unsafeKey = MemoryWriter.WriteUtf8String(key); using var unsafeValue = MemoryWriter.WriteStruct(input.InputNative); - MapChannel.Insert(Handle, transaction.Handle, unsafeKey.Handle, unsafeValue.Handle); + MapChannel.Insert(this.GetHandle(transaction), transaction.Handle, unsafeKey.Handle, unsafeValue.Handle); } /// @@ -63,13 +61,11 @@ public void Insert(Transaction transaction, string key, Input input) /// The or null if entry not found. public Output? Get(Transaction transaction, string key) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(key); - var handle = MapChannel.Get(Handle, transaction.Handle, unsafeName.Handle); + var handle = MapChannel.Get(this.GetHandle(transaction), transaction.Handle, unsafeName.Handle); - return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; + return handle != nint.Zero ? Output.CreateAndRelease(handle, this.Doc) : null; } /// @@ -79,9 +75,7 @@ public void Insert(Transaction transaction, string key, Input input) /// The number of entries stored in the . public uint Length(Transaction transaction) { - ThrowIfDisposed(); - - return MapChannel.Length(Handle, transaction.Handle); + return MapChannel.Length(this.GetHandle(transaction), transaction.Handle); } /// @@ -92,11 +86,9 @@ public uint Length(Transaction transaction) /// `true` if the entry was found and removed, `false` if no entry was found. public bool Remove(Transaction transaction, string key) { - ThrowIfDisposed(); - using var unsafeKey = MemoryWriter.WriteUtf8String(key); - return MapChannel.Remove(Handle, transaction.Handle, unsafeKey.Handle) == 1; + return MapChannel.Remove(this.GetHandle(transaction), transaction.Handle, unsafeKey.Handle) == 1; } /// @@ -105,9 +97,7 @@ public bool Remove(Transaction transaction, string key) /// The transaction that wraps this operation. public void RemoveAll(Transaction transaction) { - ThrowIfDisposed(); - - MapChannel.RemoveAll(Handle, transaction.Handle); + MapChannel.RemoveAll(this.GetHandle(transaction), transaction.Handle); } /// @@ -118,11 +108,9 @@ public void RemoveAll(Transaction transaction) /// The instance. public MapIterator Iterate(Transaction transaction) { - ThrowIfDisposed(); - - var handle = MapChannel.Iterator(Handle, transaction.Handle).Checked(); + var handle = MapChannel.Iterator(this.GetHandle(transaction), transaction.Handle).Checked(); - return new MapIterator(handle, Doc); + return new MapIterator(handle, this.Doc); } /// @@ -135,8 +123,6 @@ public MapIterator Iterate(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - - return onObserve.Subscribe(action); + return this.onObserve.Subscribe(action); } } From 0c810bc30c0127cdbd94a7dc7dcbc87bdaa23bc5 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 21:47:32 -0300 Subject: [PATCH 56/75] chore: update the demo code to match the new API of `Array` --- Demo/Callback.cs | 102 +++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/Demo/Callback.cs b/Demo/Callback.cs index 26e3a513..268c34f4 100644 --- a/Demo/Callback.cs +++ b/Demo/Callback.cs @@ -35,69 +35,77 @@ public ValueTask OnDocumentLoadedAsync(DocumentLoadEvent @event) var map = @event.Document.Map("increment"); - map?.ObserveDeep(changes => - { - foreach (var change in changes) + map?.ObserveDeep( + changes => { - var key = change.MapEvent?.Keys.FirstOrDefault(x => x.Key == "value" && x.Tag != EventKeyChangeTag.Remove); - - if (key != null) + foreach (var change in changes) { - var valueOld = key.OldValue?.Double; - var valueNew = key.NewValue?.Double; + var key = change.MapEvent?.Keys.FirstOrDefault( + x => x.Key == "value" && x.Tag != EventKeyChangeTag.Remove); - if (valueOld == valueNew) + if (key != null) { - continue; - } + var valueOld = key.OldValue?.Double; + var valueNew = key.NewValue?.Double; + + if (valueOld == valueNew) + { + continue; + } - log.LogInformation("Counter updated from {oldValue} to {newValue}.", valueOld, valueNew); + log.LogInformation("Counter updated from {oldValue} to {newValue}.", valueOld, valueNew); + } } - } - }); + }); var chat = @event.Document.Array("stream"); - chat?.ObserveDeep(async changes => - { - var newNotificationsRaw = - changes - .Where(x => x.Tag == EventBranchTag.Array) - .Select(x => x.ArrayEvent) - .SelectMany(x => x.Delta.Where(x => x.Tag == EventChangeTag.Add)) - .SelectMany(x => x.Values) - .ToArray(); - - if (newNotificationsRaw.Length == 0) + chat?.ObserveDeep( + async changes => { - return; - } - - await Task.Delay(100); - - var notificationCtx = new DocumentContext("notifications", 0); - - await @event.Source.UpdateDocAsync(notificationCtx, (doc) => - { - List notifications; - - // Keep the transaction open as short as possible. - using (var transaction = @event.Document.ReadTransaction()) + var newNotificationsRaw = + changes + .Where(x => x.Tag == EventBranchTag.Array) + .Select(x => x.ArrayEvent) + .SelectMany(x => x.Delta.Where(x => x.Tag == EventChangeTag.Add)) + .SelectMany(x => x.Values) + .ToArray(); + + if (newNotificationsRaw.Length == 0) { - notifications = newNotificationsRaw.Select(x => x.To(transaction)).ToList(); + return; } - var array = doc.Array("stream"); + await Task.Delay(millisecondsDelay: 100); - notifications = notifications.Select(x => new Notification { Text = $"You got the follow message: {x.Text}" }).ToList(); + var notificationCtx = new DocumentContext("notifications", ClientId: 0); - // Keep the transaction open as short as possible. - using (var transaction = doc.WriteTransaction()) - { - array.InsertRange(transaction, array.Length, notifications.Select(x => x.ToInput()).ToArray()); - } + await @event.Source.UpdateDocAsync( + notificationCtx, doc => + { + List notifications; + + // Keep the transaction open as short as possible. + using (var transaction = @event.Document.ReadTransaction()) + { + notifications = newNotificationsRaw.Select(x => x.To(transaction)).ToList(); + } + + var array = doc.Array("stream"); + + notifications = notifications.Select( + x => new Notification { Text = $"You got the follow message: {x.Text}" }) + .ToList(); + + // Keep the transaction open as short as possible. + using (var transaction = doc.WriteTransaction()) + { + array.InsertRange( + transaction, array.Length(transaction), + notifications.Select(x => x.ToInput()).ToArray()); + } + }); }); - }); return default; From 5a6c00defc206bc2e060c42ab0c79bbca73a5071 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 21:49:55 -0300 Subject: [PATCH 57/75] feat: replace `this.Handle` with `this.GetHandle()` in `Text` --- YDotNet/Document/Types/Texts/Text.cs | 56 +++++++++++++--------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/YDotNet/Document/Types/Texts/Text.cs b/YDotNet/Document/Types/Texts/Text.cs index 40f9a35a..7386946f 100644 --- a/YDotNet/Document/Types/Texts/Text.cs +++ b/YDotNet/Document/Types/Texts/Text.cs @@ -22,13 +22,13 @@ public class Text : Branch internal Text(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + this.onObserve = new EventSubscriber( doc.EventManager, handle, (text, action) => { TextChannel.ObserveCallback callback = (_, eventHandle) => - action(new TextEvent(eventHandle, Doc)); + action(new TextEvent(eventHandle, this.Doc)); return (TextChannel.Observe(text, nint.Zero, callback), callback); }, @@ -47,12 +47,15 @@ internal Text(nint handle, Doc doc, bool isDeleted) /// public void Insert(Transaction transaction, uint index, string value, Input? attributes = null) { - ThrowIfDisposed(); - using var unsafeValue = MemoryWriter.WriteUtf8String(value); using var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); - TextChannel.Insert(Handle, transaction.Handle, index, unsafeValue.Handle, unsafeAttributes.Handle); + TextChannel.Insert( + this.GetHandle(transaction), + transaction.Handle, + index, + unsafeValue.Handle, + unsafeAttributes.Handle); } /// @@ -67,12 +70,15 @@ public void Insert(Transaction transaction, uint index, string value, Input? att /// public void InsertEmbed(Transaction transaction, uint index, Input content, Input? attributes = null) { - ThrowIfDisposed(); - var unsafeContent = MemoryWriter.WriteStruct(content.InputNative); var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); - TextChannel.InsertEmbed(Handle, transaction.Handle, index, unsafeContent.Handle, unsafeAttributes.Handle); + TextChannel.InsertEmbed( + this.GetHandle(transaction), + transaction.Handle, + index, + unsafeContent.Handle, + unsafeAttributes.Handle); } /// @@ -86,9 +92,7 @@ public void InsertEmbed(Transaction transaction, uint index, Input content, Inpu /// public void RemoveRange(Transaction transaction, uint index, uint length) { - ThrowIfDisposed(); - - TextChannel.RemoveRange(Handle, transaction.Handle, index, length); + TextChannel.RemoveRange(this.GetHandle(transaction), transaction.Handle, index, length); } /// @@ -106,11 +110,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public void Format(Transaction transaction, uint index, uint length, Input attributes) { - ThrowIfDisposed(); - using var unsafeAttributes = MemoryWriter.WriteStruct(attributes.InputNative); - TextChannel.Format(Handle, transaction.Handle, index, length, unsafeAttributes.Handle); + TextChannel.Format(this.GetHandle(transaction), transaction.Handle, index, length, unsafeAttributes.Handle); } /// @@ -120,11 +122,9 @@ public void Format(Transaction transaction, uint index, uint length, Input attri /// The that compose this . public TextChunks Chunks(Transaction transaction) { - ThrowIfDisposed(); - - var handle = TextChannel.Chunks(Handle, transaction.Handle, out var length).Checked(); + var handle = TextChannel.Chunks(this.GetHandle(transaction), transaction.Handle, out var length).Checked(); - return new TextChunks(handle, length, Doc); + return new TextChunks(handle, length, this.Doc); } /// @@ -134,9 +134,7 @@ public TextChunks Chunks(Transaction transaction) /// The full string stored in the instance. public string String(Transaction transaction) { - ThrowIfDisposed(); - - var handle = TextChannel.String(Handle, transaction.Handle); + var handle = TextChannel.String(this.GetHandle(transaction), transaction.Handle); return MemoryReader.ReadStringAndDestroy(handle); } @@ -151,9 +149,7 @@ public string String(Transaction transaction) /// The length, in bytes, of the string stored in the instance. public uint Length(Transaction transaction) { - ThrowIfDisposed(); - - return TextChannel.Length(Handle, transaction.Handle); + return TextChannel.Length(this.GetHandle(transaction), transaction.Handle); } /// @@ -163,9 +159,7 @@ public uint Length(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - - return onObserve.Subscribe(action); + return this.onObserve.Subscribe(action); } /// @@ -182,9 +176,11 @@ public IDisposable Observe(Action action) /// public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { - ThrowIfDisposed(); - - var handle = StickyIndexChannel.FromIndex(Handle, transaction.Handle, index, (sbyte)associationType); + var handle = StickyIndexChannel.FromIndex( + this.GetHandle(transaction), + transaction.Handle, + index, + (sbyte) associationType); return handle != nint.Zero ? new StickyIndex(handle) : null; } From ebcefa7e4f6abb6998473aa2a246cfeee8a694cd Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Tue, 30 Apr 2024 22:04:53 -0300 Subject: [PATCH 58/75] fix: use correct handle when reading `XmlTextEvent.Target` --- YDotNet/Document/Types/XmlTexts/Events/XmlTextEvent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/XmlTexts/Events/XmlTextEvent.cs b/YDotNet/Document/Types/XmlTexts/Events/XmlTextEvent.cs index 4ea1360c..b2d68a3d 100644 --- a/YDotNet/Document/Types/XmlTexts/Events/XmlTextEvent.cs +++ b/YDotNet/Document/Types/XmlTexts/Events/XmlTextEvent.cs @@ -38,7 +38,7 @@ internal XmlTextEvent(nint handle, Doc doc) { var targetHandle = XmlTextChannel.ObserveEventTarget(handle).Checked(); - return doc.GetXmlText(handle, isDeleted: false); + return doc.GetXmlText(targetHandle, isDeleted: false); }); } From 5c8a1569baec5f2277c594823f9fd0a3aaba64ce Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:01:29 -0300 Subject: [PATCH 59/75] feat: replace `this.Handle` with `this.GetHandle()` in `XmlElement` --- .../Document/Types/XmlElements/XmlElement.cs | 53 +++++++------------ 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/YDotNet/Document/Types/XmlElements/XmlElement.cs b/YDotNet/Document/Types/XmlElements/XmlElement.cs index ac0b7eab..f88df54a 100644 --- a/YDotNet/Document/Types/XmlElements/XmlElement.cs +++ b/YDotNet/Document/Types/XmlElements/XmlElement.cs @@ -41,16 +41,13 @@ internal XmlElement(nint handle, Doc doc, bool isDeleted) /// /// This property returns null for root-level XML nodes. /// - public string? Tag + /// The transaction used to read the tag. + /// The tag of the element, if available. + public string? Tag(Transaction transaction) { - get - { - ThrowIfDisposed(); - - var handle = XmlElementChannel.Tag(Handle); + var handle = XmlElementChannel.Tag(GetHandle(transaction)); - return handle != nint.Zero ? MemoryReader.ReadStringAndDestroy(handle) : null; - } + return handle != nint.Zero ? MemoryReader.ReadStringAndDestroy(handle) : null; } /// @@ -63,9 +60,7 @@ public string? Tag /// The string representation of the instance. public string String(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.String(Handle, transaction.Handle); + var handle = XmlElementChannel.String(GetHandle(transaction), transaction.Handle); return MemoryReader.ReadStringAndDestroy(handle.Checked()); } @@ -81,12 +76,14 @@ public string String(Transaction transaction) /// The value of the attribute to be added. public void InsertAttribute(Transaction transaction, string name, string value) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); using var unsafeValue = MemoryWriter.WriteUtf8String(value); - XmlElementChannel.InsertAttribute(Handle, transaction.Handle, unsafeName.Handle, unsafeValue.Handle); + XmlElementChannel.InsertAttribute( + GetHandle(transaction), + transaction.Handle, + unsafeName.Handle, + unsafeValue.Handle); } /// @@ -96,11 +93,9 @@ public void InsertAttribute(Transaction transaction, string name, string value) /// The name of the attribute to be removed. public void RemoveAttribute(Transaction transaction, string name) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); - XmlElementChannel.RemoveAttribute(Handle, transaction.Handle, unsafeName.Handle); + XmlElementChannel.RemoveAttribute(GetHandle(transaction), transaction.Handle, unsafeName.Handle); } /// @@ -111,11 +106,9 @@ public void RemoveAttribute(Transaction transaction, string name) /// The value of the attribute or null if it doesn't exist. public string? GetAttribute(Transaction transaction, string name) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); - var handle = XmlElementChannel.GetAttribute(Handle, transaction.Handle, unsafeName.Handle); + var handle = XmlElementChannel.GetAttribute(GetHandle(transaction), transaction.Handle, unsafeName.Handle); return handle != nint.Zero ? MemoryReader.ReadStringAndDestroy(handle) : null; } @@ -128,9 +121,7 @@ public void RemoveAttribute(Transaction transaction, string name) /// The instance or null if failed. public XmlAttributeIterator Iterate(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.AttributeIterator(Handle, transaction.Handle); + var handle = XmlElementChannel.AttributeIterator(GetHandle(transaction), transaction.Handle); return new XmlAttributeIterator(handle.Checked()); } @@ -209,9 +200,7 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// public Output? PreviousSibling(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlChannel.PreviousSibling(Handle, transaction.Handle); + var handle = XmlChannel.PreviousSibling(GetHandle(transaction), transaction.Handle); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -228,9 +217,7 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// public Output? NextSibling(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlChannel.NextSibling(Handle, transaction.Handle); + var handle = XmlChannel.NextSibling(GetHandle(transaction), transaction.Handle); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -260,16 +247,14 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// public XmlElement? Parent(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.Parent(Handle, transaction.Handle); + var handle = XmlElementChannel.Parent(GetHandle(transaction), transaction.Handle); if (handle == nint.Zero) { return null; } - var kind = (BranchKind) BranchChannel.Kind(handle); + var kind = (BranchKind)BranchChannel.Kind(handle); return kind == BranchKind.XmlElement ? Doc.GetXmlElement(handle, isDeleted: false) : null; } @@ -297,8 +282,6 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - return onObserve.Subscribe(action); } } From 4e40f96013ca82055daf4f78846da67d457546fd Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:02:23 -0300 Subject: [PATCH 60/75] feat: replace `this.Handle` with `this.GetHandle()` in `XmlFragment` --- .../Types/XmlFragments/XmlFragment.cs | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/YDotNet/Document/Types/XmlFragments/XmlFragment.cs b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs index 64f3dcc0..0bbea8a0 100644 --- a/YDotNet/Document/Types/XmlFragments/XmlFragment.cs +++ b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs @@ -54,9 +54,7 @@ internal XmlFragment(nint handle, Doc doc, bool isDeleted) /// The number of direct child nodes of this . public uint ChildLength(Transaction transaction) { - ThrowIfDisposed(); - - return XmlElementChannel.ChildLength(Handle, transaction.Handle); + return XmlElementChannel.ChildLength(GetHandle(transaction), transaction.Handle); } /// @@ -68,9 +66,7 @@ public uint ChildLength(Transaction transaction) /// The inserted at the given . public XmlText InsertText(Transaction transaction, uint index) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.InsertText(Handle, transaction.Handle, index); + var handle = XmlElementChannel.InsertText(GetHandle(transaction), transaction.Handle, index); return Doc.GetXmlText(handle, isDeleted: false); } @@ -85,11 +81,9 @@ public XmlText InsertText(Transaction transaction, uint index) /// The inserted at the given . public XmlElement InsertElement(Transaction transaction, uint index, string name) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); - var handle = XmlElementChannel.InsertElement(Handle, transaction.Handle, index, unsafeName.Handle); + var handle = XmlElementChannel.InsertElement(GetHandle(transaction), transaction.Handle, index, unsafeName.Handle); return Doc.GetXmlElement(handle, isDeleted: false); } @@ -103,9 +97,7 @@ public XmlElement InsertElement(Transaction transaction, uint index, string name /// The amount of child nodes to remove, starting at . public void RemoveRange(Transaction transaction, uint index, uint length) { - ThrowIfDisposed(); - - XmlElementChannel.RemoveRange(Handle, transaction.Handle, index, length); + XmlElementChannel.RemoveRange(GetHandle(transaction), transaction.Handle, index, length); } /// @@ -116,9 +108,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// An cell or null if the is out of bounds. public Output? Get(Transaction transaction, uint index) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.Get(Handle, transaction.Handle, index); + var handle = XmlElementChannel.Get(GetHandle(transaction), transaction.Handle, index); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -134,9 +124,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public Output? FirstChild(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.FirstChild(Handle, transaction.Handle); + var handle = XmlElementChannel.FirstChild(GetHandle(transaction), transaction.Handle); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -151,9 +139,7 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// An for this . public XmlTreeWalker TreeWalker(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlElementChannel.TreeWalker(Handle, transaction.Handle); + var handle = XmlElementChannel.TreeWalker(GetHandle(transaction), transaction.Handle); return new XmlTreeWalker(handle.Checked(), Doc); } @@ -168,8 +154,6 @@ public XmlTreeWalker TreeWalker(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - return onObserve.Subscribe(action); } } From 02a3120e966a6a08be4d14e5bc3af59702e39215 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:02:54 -0300 Subject: [PATCH 61/75] feat: replace `this.Handle` with `this.GetHandle()` in `XmlText` --- YDotNet/Document/Types/XmlTexts/XmlText.cs | 54 ++++++---------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/YDotNet/Document/Types/XmlTexts/XmlText.cs b/YDotNet/Document/Types/XmlTexts/XmlText.cs index 01fa5d05..64a246b5 100644 --- a/YDotNet/Document/Types/XmlTexts/XmlText.cs +++ b/YDotNet/Document/Types/XmlTexts/XmlText.cs @@ -42,9 +42,7 @@ internal XmlText(nint handle, Doc doc, bool isDeleted) /// The length of the text, in bytes, stored in the . public uint Length(Transaction transaction) { - ThrowIfDisposed(); - - return XmlTextChannel.Length(Handle, transaction.Handle); + return XmlTextChannel.Length(GetHandle(transaction), transaction.Handle); } /// @@ -59,12 +57,10 @@ public uint Length(Transaction transaction) /// public void Insert(Transaction transaction, uint index, string value, Input? attributes = null) { - ThrowIfDisposed(); - using var unsafeValue = MemoryWriter.WriteUtf8String(value); using var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); - XmlTextChannel.Insert(Handle, transaction.Handle, index, unsafeValue.Handle, unsafeAttributes.Handle); + XmlTextChannel.Insert(GetHandle(transaction), transaction.Handle, index, unsafeValue.Handle, unsafeAttributes.Handle); } /// @@ -79,12 +75,10 @@ public void Insert(Transaction transaction, uint index, string value, Input? att /// public void InsertEmbed(Transaction transaction, uint index, Input content, Input? attributes = null) { - ThrowIfDisposed(); - using var unsafeContent = MemoryWriter.WriteStruct(content.InputNative); using var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); - XmlTextChannel.InsertEmbed(Handle, transaction.Handle, index, unsafeContent.Handle, unsafeAttributes.Handle); + XmlTextChannel.InsertEmbed(GetHandle(transaction), transaction.Handle, index, unsafeContent.Handle, unsafeAttributes.Handle); } /// @@ -98,12 +92,10 @@ public void InsertEmbed(Transaction transaction, uint index, Input content, Inpu /// The value of the attribute to be added. public void InsertAttribute(Transaction transaction, string name, string value) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); using var unsafeValue = MemoryWriter.WriteUtf8String(value); - XmlTextChannel.InsertAttribute(Handle, transaction.Handle, unsafeName.Handle, unsafeValue.Handle); + XmlTextChannel.InsertAttribute(GetHandle(transaction), transaction.Handle, unsafeName.Handle, unsafeValue.Handle); } /// @@ -113,11 +105,9 @@ public void InsertAttribute(Transaction transaction, string name, string value) /// The name of the attribute to be removed. public void RemoveAttribute(Transaction transaction, string name) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); - XmlTextChannel.RemoveAttribute(Handle, transaction.Handle, unsafeName.Handle); + XmlTextChannel.RemoveAttribute(GetHandle(transaction), transaction.Handle, unsafeName.Handle); } /// @@ -128,11 +118,9 @@ public void RemoveAttribute(Transaction transaction, string name) /// The value of the attribute or null if it doesn't exist. public string? GetAttribute(Transaction transaction, string name) { - ThrowIfDisposed(); - using var unsafeName = MemoryWriter.WriteUtf8String(name); - var handle = XmlTextChannel.GetAttribute(Handle, transaction.Handle, unsafeName.Handle); + var handle = XmlTextChannel.GetAttribute(GetHandle(transaction), transaction.Handle, unsafeName.Handle); return handle != nint.Zero ? MemoryReader.ReadStringAndDestroy(handle) : null; } @@ -144,9 +132,7 @@ public void RemoveAttribute(Transaction transaction, string name) /// The instance. public XmlAttributeIterator Iterate(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlTextChannel.AttributeIterator(Handle, transaction.Handle).Checked(); + var handle = XmlTextChannel.AttributeIterator(GetHandle(transaction), transaction.Handle).Checked(); return new XmlAttributeIterator(handle); } @@ -158,9 +144,7 @@ public XmlAttributeIterator Iterate(Transaction transaction) /// The string representation of the instance. public string String(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlTextChannel.String(Handle, transaction.Handle); + var handle = XmlTextChannel.String(GetHandle(transaction), transaction.Handle); return MemoryReader.ReadStringAndDestroy(handle); } @@ -176,9 +160,7 @@ public string String(Transaction transaction) /// public void RemoveRange(Transaction transaction, uint index, uint length) { - ThrowIfDisposed(); - - XmlTextChannel.RemoveRange(Handle, transaction.Handle, index, length); + XmlTextChannel.RemoveRange(GetHandle(transaction), transaction.Handle, index, length); } /// @@ -196,11 +178,9 @@ public void RemoveRange(Transaction transaction, uint index, uint length) /// public void Format(Transaction transaction, uint index, uint length, Input attributes) { - ThrowIfDisposed(); - using var unsafeAttributes = MemoryWriter.WriteStruct(attributes.InputNative); - XmlTextChannel.Format(Handle, transaction.Handle, index, length, unsafeAttributes.Handle); + XmlTextChannel.Format(GetHandle(transaction), transaction.Handle, index, length, unsafeAttributes.Handle); } /// @@ -214,9 +194,7 @@ public void Format(Transaction transaction, uint index, uint length, Input attri /// public Output? PreviousSibling(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlChannel.PreviousSibling(Handle, transaction.Handle); + var handle = XmlChannel.PreviousSibling(GetHandle(transaction), transaction.Handle); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -232,9 +210,7 @@ public void Format(Transaction transaction, uint index, uint length, Input attri /// public Output? NextSibling(Transaction transaction) { - ThrowIfDisposed(); - - var handle = XmlChannel.NextSibling(Handle, transaction.Handle); + var handle = XmlChannel.NextSibling(GetHandle(transaction), transaction.Handle); return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } @@ -249,8 +225,6 @@ public void Format(Transaction transaction, uint index, uint length, Input attri /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - ThrowIfDisposed(); - return onObserve.Subscribe(action); } @@ -268,9 +242,7 @@ public IDisposable Observe(Action action) /// public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { - ThrowIfDisposed(); - - var handle = StickyIndexChannel.FromIndex(Handle, transaction.Handle, index, (sbyte) associationType); + var handle = StickyIndexChannel.FromIndex(GetHandle(transaction), transaction.Handle, index, (sbyte)associationType); return handle != nint.Zero ? new StickyIndex(handle) : null; } From f4cb4d3724e6b25cbcb38f10cab563ceabff49ed Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:03:49 -0300 Subject: [PATCH 62/75] style: format `Branch` and `UnmanagedResource` --- YDotNet/Document/Types/Branches/Branch.cs | 16 ++++++++-------- YDotNet/Infrastructure/UnmanagedResource.cs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 8d39c7a3..ffa7174c 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -18,11 +18,11 @@ public abstract class Branch : UnmanagedResource protected internal Branch(nint handle, Doc doc, bool isDeleted) : base(handle, isDeleted) { - this.Doc = doc; + Doc = doc; - this.BranchId = isDeleted ? null : BranchChannel.Id(handle); + BranchId = isDeleted ? null : BranchChannel.Id(handle); - this.onDeep = new EventSubscriberFromId( + onDeep = new EventSubscriberFromId( doc.EventManager, this, (branch, action) => @@ -56,7 +56,7 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable ObserveDeep(Action> action) { - return this.onDeep.Subscribe(action); + return onDeep.Subscribe(action); } /// @@ -66,7 +66,7 @@ public IDisposable ObserveDeep(Action> action) /// Another write transaction has been created and not committed yet. public Transaction WriteTransaction() { - return this.Doc.WriteTransaction(); + return Doc.WriteTransaction(); } /// @@ -76,7 +76,7 @@ public Transaction WriteTransaction() /// Another write transaction has been created and not committed yet. public Transaction ReadTransaction() { - return this.Doc.ReadTransaction(); + return Doc.ReadTransaction(); } /// @@ -87,12 +87,12 @@ public Transaction ReadTransaction() /// If is true. protected internal nint GetHandle(Transaction transaction) { - if (this.IsDisposed) + if (IsDisposed) { throw new ObjectDisposedException("Object is disposed."); } - var handle = MemoryWriter.WriteStruct(this.BranchId); + var handle = MemoryWriter.WriteStruct(BranchId); var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); diff --git a/YDotNet/Infrastructure/UnmanagedResource.cs b/YDotNet/Infrastructure/UnmanagedResource.cs index 05ca7d4b..bb17ff09 100644 --- a/YDotNet/Infrastructure/UnmanagedResource.cs +++ b/YDotNet/Infrastructure/UnmanagedResource.cs @@ -8,7 +8,7 @@ public abstract class UnmanagedResource : Resource protected internal UnmanagedResource(nint handle, bool isDisposed = false) : base(isDisposed) { - this.Handle = handle; + Handle = handle; } internal nint Handle { get; } From d2499f5859e44e719ba97c596c2efff8f1ff4241 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:06:45 -0300 Subject: [PATCH 63/75] test: update unit tests after migrating `Branch` types to `GetHandle()` --- Tests/YDotNet.Tests.Unit/Maps/GetTests.cs | 2 +- Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs | 3 ++- Tests/YDotNet.Tests.Unit/Texts/StringTests.cs | 3 ++- .../XmlElements/InsertElementTests.cs | 18 ++++++++++-------- .../XmlElements/ObserveTests.cs | 6 +++++- .../YDotNet.Tests.Unit/XmlElements/TagTests.cs | 8 ++++---- .../XmlElements/TreeWalkerTests.cs | 14 ++++++++------ .../XmlFragments/InsertElementTests.cs | 14 ++++++++------ .../XmlFragments/ObserveTests.cs | 6 +++++- .../XmlFragments/TreeWalkerTests.cs | 14 ++++++++------ 10 files changed, 53 insertions(+), 35 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs b/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs index 3216a37b..339c65d5 100644 --- a/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs +++ b/Tests/YDotNet.Tests.Unit/Maps/GetTests.cs @@ -276,7 +276,7 @@ public void GetXmlElement() // Assert Assert.That(value1, Is.Not.Null); - Assert.That(value1.Tag, Is.EqualTo("person")); + Assert.That(value1.Tag(transaction), Is.EqualTo("person")); Assert.That(value2.Tag, Is.EqualTo(OutputTag.Null)); } diff --git a/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs b/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs index 10787398..10830411 100644 --- a/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs +++ b/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs @@ -17,7 +17,6 @@ public void ChunkIsTheWholeText() var transaction = doc.WriteTransaction(); text.Insert(transaction, index: 0, "Lucas"); - transaction.Commit(); // Act var chunks = text.Chunks(transaction); @@ -25,6 +24,8 @@ public void ChunkIsTheWholeText() // Assert Assert.That(chunks.Count, Is.EqualTo(expected: 1)); Assert.That(chunks.First().Attributes, Is.Empty); + + transaction.Commit(); } [Test] diff --git a/Tests/YDotNet.Tests.Unit/Texts/StringTests.cs b/Tests/YDotNet.Tests.Unit/Texts/StringTests.cs index fa4951d2..b49570cf 100644 --- a/Tests/YDotNet.Tests.Unit/Texts/StringTests.cs +++ b/Tests/YDotNet.Tests.Unit/Texts/StringTests.cs @@ -15,9 +15,10 @@ public void ReturnsTheFullText() // Act var transaction = doc.WriteTransaction(); text.Insert(transaction, index: 0, "Star. ⭐"); - transaction.Commit(); // Assert Assert.That(text.String(transaction), Is.EqualTo("Star. ⭐")); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs index 2a562d42..46133c31 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/InsertElementTests.cs @@ -13,19 +13,20 @@ public void InsertSingleElement() var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); - var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); transaction.Commit(); // Act transaction = doc.WriteTransaction(); var addedXmlElement = xmlElement.InsertElement(transaction, index: 0, "color"); var childLength = xmlElement.ChildLength(transaction); - transaction.Commit(); // Assert Assert.That(addedXmlElement.Handle, Is.Not.EqualTo(nint.Zero)); - Assert.That(addedXmlElement.Tag, Is.EqualTo("color")); + Assert.That(addedXmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(childLength, Is.EqualTo(expected: 1)); + + transaction.Commit(); } [Test] @@ -36,7 +37,7 @@ public void InsertMultipleElements() var xmlFragment = doc.XmlFragment("xml-fragment"); var transaction = doc.WriteTransaction(); - var xmlElement = xmlFragment.InsertElement(transaction, 0, "xml-element"); + var xmlElement = xmlFragment.InsertElement(transaction, index: 0, "xml-element"); transaction.Commit(); // Act @@ -45,12 +46,13 @@ public void InsertMultipleElements() var xmlElement2 = xmlElement.InsertElement(transaction, index: 0, "width"); var xmlElement3 = xmlElement.InsertElement(transaction, index: 0, "height"); var childLength = xmlElement.ChildLength(transaction); - transaction.Commit(); // Assert - Assert.That(xmlElement1.Tag, Is.EqualTo("color")); - Assert.That(xmlElement2.Tag, Is.EqualTo("width")); - Assert.That(xmlElement3.Tag, Is.EqualTo("height")); + Assert.That(xmlElement1.Tag(transaction), Is.EqualTo("color")); + Assert.That(xmlElement2.Tag(transaction), Is.EqualTo("width")); + Assert.That(xmlElement3.Tag(transaction), Is.EqualTo("height")); Assert.That(childLength, Is.EqualTo(expected: 3)); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs index 9bd0c886..ad3c409e 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/ObserveTests.cs @@ -53,14 +53,18 @@ public void ObserveHasDeltaWhenAddedXmlElementsAndTexts() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(eventChanges, Is.Not.Null); Assert.That(eventChanges.Count(), Is.EqualTo(expected: 1)); Assert.That(eventChanges.First().Tag, Is.EqualTo(EventChangeTag.Add)); Assert.That(eventChanges.First().Length, Is.EqualTo(expected: 3)); Assert.That(eventChanges.First().Values.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(eventChanges.First().Values.ElementAt(index: 2).XmlText, Is.Not.Null); + + transaction.Commit(); } [Test] diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs index 7e709570..3aa2bba0 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs @@ -18,7 +18,7 @@ public void RootNodesHaveUndefinedAsTag() transaction.Commit(); // Act - var tag = xmlElement.Tag; + var tag = xmlElement.Tag(transaction); // Assert Assert.That(tag, Is.EqualTo("xml-element")); @@ -34,7 +34,7 @@ public void NodeNestedOnRootNodeHasCorrectTag() // Act var transaction = doc.WriteTransaction(); var childXmlElement = xmlFragment.InsertElement(transaction, index: 0, "color"); - var tag = childXmlElement.Tag; + var tag = childXmlElement.Tag(transaction); transaction.Commit(); // Assert @@ -54,7 +54,7 @@ public void NodeNestedOnMapHasCorrectTag() // Act transaction = doc.ReadTransaction(); - var tag = map.Get(transaction, "xml-element").XmlElement.Tag; + var tag = map.Get(transaction, "xml-element").XmlElement.Tag(transaction); transaction.Commit(); // Assert @@ -74,7 +74,7 @@ public void NodeNestedOnArrayHasCorrectTag() // Act transaction = doc.ReadTransaction(); - var tag = array.Get(transaction, index: 0).XmlElement.Tag; + var tag = array.Get(transaction, index: 0).XmlElement.Tag(transaction); transaction.Commit(); // Assert diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs index c37cc040..8f2b3639 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/TreeWalkerTests.cs @@ -47,7 +47,6 @@ public void WalksOnTreeWithSingleLevelOfDepth() // Act transaction = doc.ReadTransaction(); var xmlTreeWalker = xmlElement.TreeWalker(transaction); - transaction.Commit(); // Assert var xmlNodes = xmlTreeWalker.ToArray(); @@ -56,8 +55,10 @@ public void WalksOnTreeWithSingleLevelOfDepth() Assert.That(xmlNodes.Length, Is.EqualTo(expected: 3)); Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(xmlNodes.ElementAt(index: 2).XmlText, Is.Not.Null); + + transaction.Commit(); } [Test] @@ -84,7 +85,6 @@ public void WalksOnTreeWithMultipleLevelsOfDepth() // Act transaction = doc.ReadTransaction(); var xmlTreeWalker = xmlElement.TreeWalker(transaction); - transaction.Commit(); // Assert var xmlNodes = xmlTreeWalker.ToArray(); @@ -93,11 +93,13 @@ public void WalksOnTreeWithMultipleLevelsOfDepth() Assert.That(xmlNodes.Length, Is.EqualTo(expected: 5)); Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(xmlNodes.ElementAt(index: 2).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 2).XmlElement.Tag, Is.EqualTo("alpha")); + Assert.That(xmlNodes.ElementAt(index: 2).XmlElement.Tag(transaction), Is.EqualTo("alpha")); Assert.That(xmlNodes.ElementAt(index: 3).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 3).XmlElement.Tag, Is.EqualTo("hex")); + Assert.That(xmlNodes.ElementAt(index: 3).XmlElement.Tag(transaction), Is.EqualTo("hex")); Assert.That(xmlNodes.ElementAt(index: 4).XmlText, Is.Not.Null); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs index 7b914798..5c8d282f 100644 --- a/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/InsertElementTests.cs @@ -16,12 +16,13 @@ public void InsertSingleElement() var transaction = doc.WriteTransaction(); var addedXmlElement = xmlFragment.InsertElement(transaction, index: 0, "color"); var childLength = xmlFragment.ChildLength(transaction); - transaction.Commit(); // Assert Assert.That(addedXmlElement.Handle, Is.Not.EqualTo(nint.Zero)); - Assert.That(addedXmlElement.Tag, Is.EqualTo("color")); + Assert.That(addedXmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(childLength, Is.EqualTo(expected: 1)); + + transaction.Commit(); } [Test] @@ -37,12 +38,13 @@ public void InsertMultipleElements() var xmlElement2 = xmlFragment.InsertElement(transaction, index: 0, "width"); var xmlElement3 = xmlFragment.InsertElement(transaction, index: 0, "height"); var childLength = xmlFragment.ChildLength(transaction); - transaction.Commit(); // Assert - Assert.That(xmlElement1.Tag, Is.EqualTo("color")); - Assert.That(xmlElement2.Tag, Is.EqualTo("width")); - Assert.That(xmlElement3.Tag, Is.EqualTo("height")); + Assert.That(xmlElement1.Tag(transaction), Is.EqualTo("color")); + Assert.That(xmlElement2.Tag(transaction), Is.EqualTo("width")); + Assert.That(xmlElement3.Tag(transaction), Is.EqualTo("height")); Assert.That(childLength, Is.EqualTo(expected: 3)); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs index 1e15e5a8..b2627abd 100644 --- a/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/ObserveTests.cs @@ -45,13 +45,17 @@ public void ObserveHasDeltaWhenAddedXmlElementsAndTexts() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(eventChanges, Is.Not.Null); Assert.That(eventChanges.Count(), Is.EqualTo(expected: 1)); Assert.That(eventChanges.First().Tag, Is.EqualTo(EventChangeTag.Add)); Assert.That(eventChanges.First().Length, Is.EqualTo(expected: 3)); Assert.That(eventChanges.First().Values.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(eventChanges.First().Values.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(eventChanges.First().Values.ElementAt(index: 2).XmlText, Is.Not.Null); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs b/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs index 401ef6a3..3014ef16 100644 --- a/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlFragments/TreeWalkerTests.cs @@ -39,7 +39,6 @@ public void WalksOnTreeWithSingleLevelOfDepth() // Act transaction = doc.ReadTransaction(); var xmlTreeWalker = xmlFragment.TreeWalker(transaction); - transaction.Commit(); // Assert var xmlNodes = xmlTreeWalker.ToArray(); @@ -48,8 +47,10 @@ public void WalksOnTreeWithSingleLevelOfDepth() Assert.That(xmlNodes.Length, Is.EqualTo(expected: 3)); Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(xmlNodes.ElementAt(index: 2).XmlText, Is.Not.Null); + + transaction.Commit(); } [Test] @@ -72,7 +73,6 @@ public void WalksOnTreeWithMultipleLevelsOfDepth() // Act transaction = doc.ReadTransaction(); var xmlTreeWalker = xmlFragment.TreeWalker(transaction); - transaction.Commit(); // Assert var xmlNodes = xmlTreeWalker.ToArray(); @@ -81,11 +81,13 @@ public void WalksOnTreeWithMultipleLevelsOfDepth() Assert.That(xmlNodes.Length, Is.EqualTo(expected: 5)); Assert.That(xmlNodes.ElementAt(index: 0).XmlText, Is.Not.Null); Assert.That(xmlNodes.ElementAt(index: 1).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag, Is.EqualTo("color")); + Assert.That(xmlNodes.ElementAt(index: 1).XmlElement.Tag(transaction), Is.EqualTo("color")); Assert.That(xmlNodes.ElementAt(index: 2).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 2).XmlElement.Tag, Is.EqualTo("alpha")); + Assert.That(xmlNodes.ElementAt(index: 2).XmlElement.Tag(transaction), Is.EqualTo("alpha")); Assert.That(xmlNodes.ElementAt(index: 3).XmlElement, Is.Not.Null); - Assert.That(xmlNodes.ElementAt(index: 3).XmlElement.Tag, Is.EqualTo("hex")); + Assert.That(xmlNodes.ElementAt(index: 3).XmlElement.Tag(transaction), Is.EqualTo("hex")); Assert.That(xmlNodes.ElementAt(index: 4).XmlText, Is.Not.Null); + + transaction.Commit(); } } From fdef31898e5ecf19644e0c711a7bfac5dc80061c Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:07:01 -0300 Subject: [PATCH 64/75] test: fix tests for `Doc.ReadTransaction()` --- Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs b/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs index c845eb1e..335d8663 100644 --- a/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs +++ b/Tests/YDotNet.Tests.Unit/Document/ReadTransactionTests.cs @@ -12,7 +12,7 @@ public void ReadTransaction() var doc = new Doc(); // Act - var transaction = doc.WriteTransaction(); + var transaction = doc.ReadTransaction(); // Assert Assert.That(transaction.Handle, Is.GreaterThan(nint.Zero)); From dadf0196551daa2aabc4409cfd2daaa204898246 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:32:25 -0300 Subject: [PATCH 65/75] feat: drop `Insertions` and `Deletions` from `UndoEvent` and `UndoEventNative` to mirror `yffi` definitions --- .../Document/UndoManagers/Events/UndoEvent.cs | 17 +---------------- .../UndoManager/Events/UndoEventNative.cs | 5 ----- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/YDotNet/Document/UndoManagers/Events/UndoEvent.cs b/YDotNet/Document/UndoManagers/Events/UndoEvent.cs index 2978bf09..3b335559 100644 --- a/YDotNet/Document/UndoManagers/Events/UndoEvent.cs +++ b/YDotNet/Document/UndoManagers/Events/UndoEvent.cs @@ -1,4 +1,3 @@ -using YDotNet.Document.State; using YDotNet.Native.UndoManager.Events; namespace YDotNet.Document.UndoManagers.Events; @@ -16,12 +15,8 @@ internal UndoEvent(UndoEventNative native) { UndoEventKindNative.Undo => UndoEventKind.Undo, UndoEventKindNative.Redo => UndoEventKind.Redo, - _ => throw new NotSupportedException($"The value \"{native.KindNative}\" for {nameof(UndoEventKindNative)} is not supported."), + _ => throw new NotSupportedException($"The value \"{native.KindNative}\" for {nameof(UndoEventKindNative)} is not supported.") }; - - Insertions = new DeleteSet(native.Insertions); - - Deletions = new DeleteSet(native.Deletions); } /// @@ -36,14 +31,4 @@ internal UndoEvent(UndoEventNative native) /// The is a binary marker. /// public byte[]? Origin { get; } - - /// - /// Gets the entries for inserted content. - /// - public DeleteSet Insertions { get; } - - /// - /// Gets the entries for deleted content. - /// - public DeleteSet Deletions { get; } } diff --git a/YDotNet/Native/UndoManager/Events/UndoEventNative.cs b/YDotNet/Native/UndoManager/Events/UndoEventNative.cs index 580b7748..482fa6ac 100644 --- a/YDotNet/Native/UndoManager/Events/UndoEventNative.cs +++ b/YDotNet/Native/UndoManager/Events/UndoEventNative.cs @@ -1,6 +1,5 @@ using System.Runtime.InteropServices; using YDotNet.Infrastructure; -using YDotNet.Native.Document.State; namespace YDotNet.Native.UndoManager.Events; @@ -13,10 +12,6 @@ internal struct UndoEventNative public uint OriginLength { get; set; } - public DeleteSetNative Insertions { get; set; } - - public DeleteSetNative Deletions { get; set; } - public byte[]? Origin() { if (OriginHandle == nint.Zero || OriginLength <= 0) From 0658f5035fd853216564239f39a3ee9c71e9eaee Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 00:32:44 -0300 Subject: [PATCH 66/75] test: fix tests for `ObserveAdded()` and `ObservePopped()` of `UndoManager` --- .../UndoManagers/ObserveAddedTests.cs | 66 ---------------- .../UndoManagers/ObservePoppedTests.cs | 76 ------------------- 2 files changed, 142 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs index bc5c4c88..7c4af22f 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/ObserveAddedTests.cs @@ -2,7 +2,6 @@ using YDotNet.Document; using YDotNet.Document.Cells; using YDotNet.Document.Options; -using YDotNet.Document.State; using YDotNet.Document.UndoManagers; using YDotNet.Document.UndoManagers.Events; @@ -38,8 +37,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (1234, new[] { new IdRange(Start: 0, End: 5) })); // Act undoEvent = null; @@ -51,8 +48,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (1234, new[] { new IdRange(Start: 5, End: 11) })); // Act undoEvent = null; @@ -64,10 +59,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet( - undoEvent.Deletions, - (1234, new[] { new IdRange(Start: 0, End: 2), new IdRange(Start: 8, End: 11) })); - AssertDeleteSet(undoEvent.Insertions); } [Test] @@ -99,8 +90,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5678, new[] { new IdRange(Start: 0, End: 3) })); // Act undoEvent = null; @@ -113,8 +102,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5678, new[] { new IdRange(Start: 3, End: 10) })); // Act undoEvent = null; @@ -126,9 +113,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Insertions); - AssertDeleteSet( - undoEvent.Deletions, (5678, new[] { new IdRange(Start: 1, End: 2), new IdRange(Start: 3, End: 4) })); } [Test] @@ -157,8 +141,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (9012, new[] { new IdRange(Start: 0, End: 3) })); // Act undoEvent = null; @@ -171,8 +153,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (9012, new[] { new IdRange(Start: 3, End: 10) })); // Act undoEvent = null; @@ -185,9 +165,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Insertions); - AssertDeleteSet( - undoEvent.Deletions, (9012, new[] { new IdRange(Start: 1, End: 2), new IdRange(Start: 3, End: 4) })); } [Test] @@ -219,8 +196,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7853, new[] { new IdRange(Start: 0, End: 5) })); // Act undoEvent = null; @@ -232,8 +207,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7853, new[] { new IdRange(Start: 5, End: 6) })); // Act undoEvent = null; @@ -245,8 +218,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7853, new[] { new IdRange(Start: 6, End: 7) })); // Act undoEvent = null; @@ -258,9 +229,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Insertions); - AssertDeleteSet( - undoEvent.Deletions, (7853, new[] { new IdRange(Start: 2, End: 3), new IdRange(Start: 6, End: 7) })); } [Test] @@ -292,8 +260,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (8137, new[] { new IdRange(Start: 0, End: 1) })); // Act undoEvent = null; @@ -305,8 +271,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (8137, new[] { new IdRange(Start: 1, End: 6) })); // Act undoEvent = null; @@ -318,8 +282,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (8137, new[] { new IdRange(Start: 6, End: 7) })); // Act undoEvent = null; @@ -331,8 +293,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (8137, new[] { new IdRange(Start: 7, End: 8) })); // Act undoEvent = null; @@ -345,8 +305,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (8137, new[] { new IdRange(Start: 8, End: 14) })); // Act undoEvent = null; @@ -358,29 +316,5 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Null); - AssertDeleteSet(undoEvent.Insertions); - AssertDeleteSet( - undoEvent.Deletions, (8137, new[] { new IdRange(Start: 7, End: 14) })); - } - - private void AssertDeleteSet(DeleteSet deleteSet, params (uint ClientId, IdRange[] IdRanges)[] idRangesPerClientId) - { - Assert.That(deleteSet.Ranges.Count, Is.EqualTo(idRangesPerClientId.Length)); - - foreach (var entry in idRangesPerClientId) - { - var idRanges = deleteSet.Ranges[entry.ClientId]; - - Assert.That(idRanges.Length, Is.EqualTo(entry.IdRanges.Length), "The amount of IdRanges is different."); - - for (var i = 0; i < idRanges.Length; i++) - { - Assert.That( - idRanges[i].Start, Is.EqualTo(entry.IdRanges[i].Start), - $"The start of the IdRange[{i}] is different."); - Assert.That( - idRanges[i].End, Is.EqualTo(entry.IdRanges[i].End), $"The end of the IdRange[{i}] is different."); - } - } } } diff --git a/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs b/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs index 0f43c207..b46920e4 100644 --- a/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs +++ b/Tests/YDotNet.Tests.Unit/UndoManagers/ObservePoppedTests.cs @@ -2,7 +2,6 @@ using YDotNet.Document; using YDotNet.Document.Cells; using YDotNet.Document.Options; -using YDotNet.Document.State; using YDotNet.Document.UndoManagers; using YDotNet.Document.UndoManagers.Events; @@ -31,8 +30,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (1234, new[] { new IdRange(Start: 0, End: 5) })); // Act undoEvent = null; @@ -42,8 +39,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (1234, new[] { new IdRange(Start: 0, End: 5) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -56,8 +51,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (1234, new[] { new IdRange(Start: 8, End: 10) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -67,8 +60,6 @@ public void TriggersAfterAddingAndRemovingContentOnText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (1234, new[] { new IdRange(Start: 10, End: 12) })); } [Test] @@ -93,8 +84,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5678, new[] { new IdRange(Start: 0, End: 3) })); // Act undoEvent = null; @@ -104,8 +93,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (5678, new[] { new IdRange(Start: 0, End: 3) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -118,8 +105,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (5678, new[] { new IdRange(Start: 4, End: 6) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -129,8 +114,6 @@ public void TriggersAfterAddingAndRemovingContentOnArray() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5678, new[] { new IdRange(Start: 6, End: 8) })); } [Test] @@ -154,8 +137,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (9581, new[] { new IdRange(Start: 0, End: 1) })); // Act undoEvent = null; @@ -165,8 +146,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (9581, new[] { new IdRange(Start: 0, End: 1) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -179,8 +158,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (9581, new[] { new IdRange(Start: 1, End: 2) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -190,8 +167,6 @@ public void TriggersAfterAddingAndRemovingContentOnMap() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (9581, new[] { new IdRange(Start: 2, End: 3) })); } [Test] @@ -220,8 +195,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7938, new[] { new IdRange(Start: 0, End: 5) })); // Act GC.Collect(); @@ -232,8 +205,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (7938, new[] { new IdRange(Start: 0, End: 5) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -246,8 +217,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7938, new[] { new IdRange(Start: 10, End: 11) })); // Act undoEvent = null; @@ -257,8 +226,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (7938, new[] { new IdRange(Start: 10, End: 11) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -271,8 +238,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (7938, new[] { new IdRange(Start: 7, End: 10) })); - AssertDeleteSet(undoEvent.Insertions); // Act undoEvent = null; @@ -282,8 +247,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlText() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (7938, new[] { new IdRange(Start: 12, End: 15) })); } [Test] @@ -312,8 +275,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5903, new[] { new IdRange(Start: 0, End: 1) })); GC.Collect(); // Act (redo add element) @@ -324,8 +285,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (5903, new[] { new IdRange(Start: 0, End: 1) })); - AssertDeleteSet(undoEvent.Insertions); // Act (add attribute and undo) undoEvent = null; @@ -338,8 +297,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5903, new[] { new IdRange(Start: 2, End: 3) })); // Act (redo add attribute) undoEvent = null; @@ -349,8 +306,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (5903, new[] { new IdRange(Start: 2, End: 3) })); - AssertDeleteSet(undoEvent.Insertions); // Act (add text and undo) transaction = doc.WriteTransaction(); @@ -362,8 +317,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5903, new[] { new IdRange(Start: 4, End: 5) })); // Act (redo add text) undoEvent = null; @@ -385,9 +338,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet( - undoEvent.Deletions, (5903, new[] { new IdRange(Start: 1, End: 2), new IdRange(Start: 5, End: 6) })); - AssertDeleteSet(undoEvent.Insertions); // Act (redo remove range) undoEvent = null; @@ -397,8 +347,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - AssertDeleteSet(undoEvent.Insertions, (5903, new[] { new IdRange(Start: 6, End: 8) })); // Act (remove attribute and undo) undoEvent = null; @@ -411,8 +359,6 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Undo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions, (5903, new[] { new IdRange(Start: 3, End: 4) })); - AssertDeleteSet(undoEvent.Insertions); // Act (redo remove attribute) undoEvent = null; @@ -422,27 +368,5 @@ public void TriggersAfterAddingAndRemovingContentOnXmlElement() Assert.That(undoEvent, Is.Not.Null); Assert.That(undoEvent.Kind, Is.EqualTo(UndoEventKind.Redo)); Assert.That(undoEvent.Origin, Is.Not.Null); - AssertDeleteSet(undoEvent.Deletions); - } - - private void AssertDeleteSet(DeleteSet deleteSet, params (uint ClientId, IdRange[] IdRanges)[] idRangesPerClientId) - { - Assert.That(deleteSet.Ranges.Count, Is.EqualTo(idRangesPerClientId.Length)); - - foreach (var entry in idRangesPerClientId) - { - var idRanges = deleteSet.Ranges[entry.ClientId]; - - Assert.That(idRanges.Length, Is.EqualTo(entry.IdRanges.Length), "The amount of IdRanges is different."); - - for (var i = 0; i < idRanges.Length; i++) - { - Assert.That( - idRanges[i].Start, Is.EqualTo(entry.IdRanges[i].Start), - $"The start of the IdRange[{i}] is different."); - Assert.That( - idRanges[i].End, Is.EqualTo(entry.IdRanges[i].End), $"The end of the IdRange[{i}] is different."); - } - } } } From 4792552e871cc084f33ebc60f308aae3eb208b46 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 01:05:12 -0300 Subject: [PATCH 67/75] ci: fix build patch --- native/build.patch | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/native/build.patch b/native/build.patch index 7926666d..339fac58 100644 --- a/native/build.patch +++ b/native/build.patch @@ -2,8 +2,7 @@ diff --git a/yffi/Cargo.toml b/yffi/Cargo.toml index e951bd1..e994e36 100644 --- a/yffi/Cargo.toml +++ b/yffi/Cargo.toml -@@ -16,5 +16,5 @@ yrs = { path = "../yrs", version = "0.17", features = ["weak"] } - rand = "0.7.0" +@@ -16,5 +16,5 @@ [lib] -crate-type = ["staticlib"] From 33a37b50120a310618bdbe3bd208e28ed125c768 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Wed, 1 May 2024 01:12:09 -0300 Subject: [PATCH 68/75] ci: fix matrix definition for macOS x86 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 906220de..c42c309e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: os: ubuntu-latest # macOS - - build: macos-x86_64 + - build: macos-aarch64 os: macos-latest steps: From 3deb5d51c128a58740b9121b0934ad501c3344d7 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 12 May 2024 21:29:39 -0300 Subject: [PATCH 69/75] feat: replace `EventSubscriber` with `EventSubscriberFromId` in `Map`, `Text`, `XmlElement`, `XmlFragment`, and `XmlText` --- YDotNet/Document/Types/Maps/Map.cs | 26 ++++++++-------- YDotNet/Document/Types/Texts/Text.cs | 30 +++++++++---------- .../Document/Types/XmlElements/XmlElement.cs | 6 ++-- .../Types/XmlFragments/XmlFragment.cs | 6 ++-- YDotNet/Document/Types/XmlTexts/XmlText.cs | 6 ++-- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/YDotNet/Document/Types/Maps/Map.cs b/YDotNet/Document/Types/Maps/Map.cs index a831beb6..21b2c084 100644 --- a/YDotNet/Document/Types/Maps/Map.cs +++ b/YDotNet/Document/Types/Maps/Map.cs @@ -15,18 +15,18 @@ namespace YDotNet.Document.Types.Maps; /// public class Map : Branch { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal Map(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - this.onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (map, action) => { MapChannel.ObserveCallback callback = (_, eventHandle) => - action(new MapEvent(eventHandle, this.Doc)); + action(new MapEvent(eventHandle, Doc)); return (MapChannel.Observe(map, nint.Zero, callback), callback); }, @@ -47,7 +47,7 @@ public void Insert(Transaction transaction, string key, Input input) using var unsafeKey = MemoryWriter.WriteUtf8String(key); using var unsafeValue = MemoryWriter.WriteStruct(input.InputNative); - MapChannel.Insert(this.GetHandle(transaction), transaction.Handle, unsafeKey.Handle, unsafeValue.Handle); + MapChannel.Insert(GetHandle(transaction), transaction.Handle, unsafeKey.Handle, unsafeValue.Handle); } /// @@ -63,9 +63,9 @@ public void Insert(Transaction transaction, string key, Input input) { using var unsafeName = MemoryWriter.WriteUtf8String(key); - var handle = MapChannel.Get(this.GetHandle(transaction), transaction.Handle, unsafeName.Handle); + var handle = MapChannel.Get(GetHandle(transaction), transaction.Handle, unsafeName.Handle); - return handle != nint.Zero ? Output.CreateAndRelease(handle, this.Doc) : null; + return handle != nint.Zero ? Output.CreateAndRelease(handle, Doc) : null; } /// @@ -75,7 +75,7 @@ public void Insert(Transaction transaction, string key, Input input) /// The number of entries stored in the . public uint Length(Transaction transaction) { - return MapChannel.Length(this.GetHandle(transaction), transaction.Handle); + return MapChannel.Length(GetHandle(transaction), transaction.Handle); } /// @@ -88,7 +88,7 @@ public bool Remove(Transaction transaction, string key) { using var unsafeKey = MemoryWriter.WriteUtf8String(key); - return MapChannel.Remove(this.GetHandle(transaction), transaction.Handle, unsafeKey.Handle) == 1; + return MapChannel.Remove(GetHandle(transaction), transaction.Handle, unsafeKey.Handle) == 1; } /// @@ -97,7 +97,7 @@ public bool Remove(Transaction transaction, string key) /// The transaction that wraps this operation. public void RemoveAll(Transaction transaction) { - MapChannel.RemoveAll(this.GetHandle(transaction), transaction.Handle); + MapChannel.RemoveAll(GetHandle(transaction), transaction.Handle); } /// @@ -108,9 +108,9 @@ public void RemoveAll(Transaction transaction) /// The instance. public MapIterator Iterate(Transaction transaction) { - var handle = MapChannel.Iterator(this.GetHandle(transaction), transaction.Handle).Checked(); + var handle = MapChannel.Iterator(GetHandle(transaction), transaction.Handle).Checked(); - return new MapIterator(handle, this.Doc); + return new MapIterator(handle, Doc); } /// @@ -123,6 +123,6 @@ public MapIterator Iterate(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - return this.onObserve.Subscribe(action); + return onObserve.Subscribe(action); } } diff --git a/YDotNet/Document/Types/Texts/Text.cs b/YDotNet/Document/Types/Texts/Text.cs index 7386946f..895ac2aa 100644 --- a/YDotNet/Document/Types/Texts/Text.cs +++ b/YDotNet/Document/Types/Texts/Text.cs @@ -17,18 +17,18 @@ namespace YDotNet.Document.Types.Texts; /// public class Text : Branch { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal Text(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - this.onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (text, action) => { TextChannel.ObserveCallback callback = (_, eventHandle) => - action(new TextEvent(eventHandle, this.Doc)); + action(new TextEvent(eventHandle, Doc)); return (TextChannel.Observe(text, nint.Zero, callback), callback); }, @@ -51,7 +51,7 @@ public void Insert(Transaction transaction, uint index, string value, Input? att using var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); TextChannel.Insert( - this.GetHandle(transaction), + GetHandle(transaction), transaction.Handle, index, unsafeValue.Handle, @@ -74,7 +74,7 @@ public void InsertEmbed(Transaction transaction, uint index, Input content, Inpu var unsafeAttributes = MemoryWriter.WriteStruct(attributes?.InputNative); TextChannel.InsertEmbed( - this.GetHandle(transaction), + GetHandle(transaction), transaction.Handle, index, unsafeContent.Handle, @@ -92,7 +92,7 @@ public void InsertEmbed(Transaction transaction, uint index, Input content, Inpu /// public void RemoveRange(Transaction transaction, uint index, uint length) { - TextChannel.RemoveRange(this.GetHandle(transaction), transaction.Handle, index, length); + TextChannel.RemoveRange(GetHandle(transaction), transaction.Handle, index, length); } /// @@ -112,7 +112,7 @@ public void Format(Transaction transaction, uint index, uint length, Input attri { using var unsafeAttributes = MemoryWriter.WriteStruct(attributes.InputNative); - TextChannel.Format(this.GetHandle(transaction), transaction.Handle, index, length, unsafeAttributes.Handle); + TextChannel.Format(GetHandle(transaction), transaction.Handle, index, length, unsafeAttributes.Handle); } /// @@ -122,9 +122,9 @@ public void Format(Transaction transaction, uint index, uint length, Input attri /// The that compose this . public TextChunks Chunks(Transaction transaction) { - var handle = TextChannel.Chunks(this.GetHandle(transaction), transaction.Handle, out var length).Checked(); + var handle = TextChannel.Chunks(GetHandle(transaction), transaction.Handle, out var length).Checked(); - return new TextChunks(handle, length, this.Doc); + return new TextChunks(handle, length, Doc); } /// @@ -134,7 +134,7 @@ public TextChunks Chunks(Transaction transaction) /// The full string stored in the instance. public string String(Transaction transaction) { - var handle = TextChannel.String(this.GetHandle(transaction), transaction.Handle); + var handle = TextChannel.String(GetHandle(transaction), transaction.Handle); return MemoryReader.ReadStringAndDestroy(handle); } @@ -149,7 +149,7 @@ public string String(Transaction transaction) /// The length, in bytes, of the string stored in the instance. public uint Length(Transaction transaction) { - return TextChannel.Length(this.GetHandle(transaction), transaction.Handle); + return TextChannel.Length(GetHandle(transaction), transaction.Handle); } /// @@ -159,7 +159,7 @@ public uint Length(Transaction transaction) /// The subscription for the event. It may be used to unsubscribe later. public IDisposable Observe(Action action) { - return this.onObserve.Subscribe(action); + return onObserve.Subscribe(action); } /// @@ -177,10 +177,10 @@ public IDisposable Observe(Action action) public StickyIndex? StickyIndex(Transaction transaction, uint index, StickyAssociationType associationType) { var handle = StickyIndexChannel.FromIndex( - this.GetHandle(transaction), + GetHandle(transaction), transaction.Handle, index, - (sbyte) associationType); + (sbyte)associationType); return handle != nint.Zero ? new StickyIndex(handle) : null; } diff --git a/YDotNet/Document/Types/XmlElements/XmlElement.cs b/YDotNet/Document/Types/XmlElements/XmlElement.cs index f88df54a..168995cf 100644 --- a/YDotNet/Document/Types/XmlElements/XmlElement.cs +++ b/YDotNet/Document/Types/XmlElements/XmlElement.cs @@ -17,14 +17,14 @@ namespace YDotNet.Document.Types.XmlElements; /// public class XmlElement : XmlFragment { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal XmlElement(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (xmlElement, action) => { XmlElementChannel.ObserveCallback callback = (_, eventHandle) => diff --git a/YDotNet/Document/Types/XmlFragments/XmlFragment.cs b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs index 0bbea8a0..8ad3ea0a 100644 --- a/YDotNet/Document/Types/XmlFragments/XmlFragment.cs +++ b/YDotNet/Document/Types/XmlFragments/XmlFragment.cs @@ -25,14 +25,14 @@ namespace YDotNet.Document.Types.XmlFragments; /// public class XmlFragment : Branch { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal XmlFragment(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (xmlFragment, action) => { XmlElementChannel.ObserveCallback callback = (_, eventHandle) => diff --git a/YDotNet/Document/Types/XmlTexts/XmlText.cs b/YDotNet/Document/Types/XmlTexts/XmlText.cs index 64a246b5..330fb0be 100644 --- a/YDotNet/Document/Types/XmlTexts/XmlText.cs +++ b/YDotNet/Document/Types/XmlTexts/XmlText.cs @@ -17,14 +17,14 @@ namespace YDotNet.Document.Types.XmlTexts; /// public class XmlText : Branch { - private readonly EventSubscriber onObserve; + private readonly EventSubscriberFromId onObserve; internal XmlText(nint handle, Doc doc, bool isDeleted) : base(handle, doc, isDeleted) { - onObserve = new EventSubscriber( + onObserve = new EventSubscriberFromId( doc.EventManager, - handle, + this, (xmlText, action) => { XmlTextChannel.ObserveCallback callback = (_, eventHandle) => From 9d88a194d9dc7d8231baff7d9b379bba84fa6309 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 12 May 2024 21:33:12 -0300 Subject: [PATCH 70/75] style: use `default` instead of `null` when fetching the `BranchId` --- YDotNet/Document/Types/Branches/Branch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index ffa7174c..96c1e4cb 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -20,7 +20,7 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) { Doc = doc; - BranchId = isDeleted ? null : BranchChannel.Id(handle); + BranchId = isDeleted ? default : BranchChannel.Id(handle); onDeep = new EventSubscriberFromId( doc.EventManager, From 9298507a169665c9d86bf03f84fc83ef4abaee80 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 12 May 2024 21:34:24 -0300 Subject: [PATCH 71/75] feat: make `Branch.BranchId` a `private` property --- YDotNet/Document/Types/Branches/Branch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 96c1e4cb..790dbfee 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -41,7 +41,7 @@ protected internal Branch(nint handle, Doc doc, bool isDeleted) SubscriptionChannel.Unobserve); } - internal BranchIdNative? BranchId { get; } + private BranchIdNative? BranchId { get; } internal Doc Doc { get; } From d3e35ce99c45611296060288f849c3990042e602 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Sun, 12 May 2024 21:37:47 -0300 Subject: [PATCH 72/75] feat: apply `using` to make the scope of `handle` clearer in `Branch.GetHandle()` --- YDotNet/Document/Types/Branches/Branch.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index 790dbfee..acc44d4a 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -92,12 +92,10 @@ protected internal nint GetHandle(Transaction transaction) throw new ObjectDisposedException("Object is disposed."); } - var handle = MemoryWriter.WriteStruct(BranchId); + using var handle = MemoryWriter.WriteStruct(BranchId); var branchHandle = BranchChannel.Get(handle.Handle, transaction.Handle); - handle.Dispose(); - if (branchHandle == nint.Zero || BranchChannel.Alive(branchHandle) == 0) { throw new ObjectDisposedException("Object is disposed."); From 93ff21bb4fc6f2163fcff95991a6e76416e41670 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Thu, 6 Jun 2024 20:50:18 -0300 Subject: [PATCH 73/75] chore: fix warnings throughout the project --- YDotNet/Document/Types/Branches/Branch.cs | 2 +- YDotNet/Document/Types/Events/EventPath.cs | 1 + YDotNet/Document/Types/Events/EventPathSegment.cs | 8 ++++++-- YDotNet/Native/Document/State/IdRangeNative.cs | 3 +++ YDotNet/Native/Document/State/StateVectorNative.cs | 2 ++ YDotNet/Native/NativeWithHandle.cs | 3 +++ YDotNet/Native/Types/Events/EventPathSegmentNative.cs | 2 ++ 7 files changed, 18 insertions(+), 3 deletions(-) diff --git a/YDotNet/Document/Types/Branches/Branch.cs b/YDotNet/Document/Types/Branches/Branch.cs index acc44d4a..42c668cb 100644 --- a/YDotNet/Document/Types/Branches/Branch.cs +++ b/YDotNet/Document/Types/Branches/Branch.cs @@ -84,7 +84,7 @@ public Transaction ReadTransaction() /// /// The transaction used to acquire the handle to the . /// The handle to the . - /// If is true. + /// If is true. protected internal nint GetHandle(Transaction transaction) { if (IsDisposed) diff --git a/YDotNet/Document/Types/Events/EventPath.cs b/YDotNet/Document/Types/Events/EventPath.cs index 8a977a73..32fc5e39 100644 --- a/YDotNet/Document/Types/Events/EventPath.cs +++ b/YDotNet/Document/Types/Events/EventPath.cs @@ -1,6 +1,7 @@ using System.Collections.ObjectModel; using YDotNet.Infrastructure; using YDotNet.Native.Types; +using YDotNet.Native.Types.Events; namespace YDotNet.Document.Types.Events; diff --git a/YDotNet/Document/Types/Events/EventPathSegment.cs b/YDotNet/Document/Types/Events/EventPathSegment.cs index 4cd03773..9676c108 100644 --- a/YDotNet/Document/Types/Events/EventPathSegment.cs +++ b/YDotNet/Document/Types/Events/EventPathSegment.cs @@ -1,3 +1,5 @@ +using YDotNet.Native.Types.Events; + namespace YDotNet.Document.Types.Events; /// @@ -27,12 +29,14 @@ internal EventPathSegment(EventPathSegmentNative native) public EventPathSegmentTag Tag { get; } /// - /// Gets the key, if is , or null otherwise. + /// Gets the key, if is , or null + /// otherwise. /// public string? Key { get; } /// - /// Gets the index, if is , or null otherwise. + /// Gets the index, if is , or + /// null otherwise. /// public uint? Index { get; } } diff --git a/YDotNet/Native/Document/State/IdRangeNative.cs b/YDotNet/Native/Document/State/IdRangeNative.cs index 2024cc7d..f69c31c8 100644 --- a/YDotNet/Native/Document/State/IdRangeNative.cs +++ b/YDotNet/Native/Document/State/IdRangeNative.cs @@ -1,5 +1,8 @@ +using System.Runtime.InteropServices; + namespace YDotNet.Native.Document.State; +[StructLayout(LayoutKind.Sequential)] internal readonly struct IdRangeNative { public uint Start { get; } diff --git a/YDotNet/Native/Document/State/StateVectorNative.cs b/YDotNet/Native/Document/State/StateVectorNative.cs index a0d569c6..33f0a048 100644 --- a/YDotNet/Native/Document/State/StateVectorNative.cs +++ b/YDotNet/Native/Document/State/StateVectorNative.cs @@ -1,7 +1,9 @@ +using System.Runtime.InteropServices; using YDotNet.Infrastructure; namespace YDotNet.Native.Document.State; +[StructLayout(LayoutKind.Sequential)] internal readonly struct StateVectorNative { public uint EntriesCount { get; } diff --git a/YDotNet/Native/NativeWithHandle.cs b/YDotNet/Native/NativeWithHandle.cs index c4771995..a37eadb4 100644 --- a/YDotNet/Native/NativeWithHandle.cs +++ b/YDotNet/Native/NativeWithHandle.cs @@ -1,4 +1,7 @@ +using System.Runtime.InteropServices; + namespace YDotNet.Native; +[StructLayout(LayoutKind.Sequential)] internal record struct NativeWithHandle(T Value, nint Handle) where T : struct; diff --git a/YDotNet/Native/Types/Events/EventPathSegmentNative.cs b/YDotNet/Native/Types/Events/EventPathSegmentNative.cs index 3004dfe7..552dbd5d 100644 --- a/YDotNet/Native/Types/Events/EventPathSegmentNative.cs +++ b/YDotNet/Native/Types/Events/EventPathSegmentNative.cs @@ -1,6 +1,8 @@ using System.Runtime.InteropServices; using YDotNet.Infrastructure; +namespace YDotNet.Native.Types.Events; + [StructLayout(LayoutKind.Explicit)] internal readonly struct EventPathSegmentNative { From fb8af8000504d28a725a1e01fb9e551100881470 Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Thu, 6 Jun 2024 21:35:49 -0300 Subject: [PATCH 74/75] test: fix unit tests that used `Transaction` incorrectly --- Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs | 17 ++++++++----- Tests/YDotNet.Tests.Unit/Texts/FormatTests.cs | 12 ++++++++++ Tests/YDotNet.Tests.Unit/Texts/InsertTests.cs | 24 +++++++++++++++++++ .../XmlElements/TagTests.cs | 2 ++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs b/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs index 10830411..269a46d2 100644 --- a/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs +++ b/Tests/YDotNet.Tests.Unit/Texts/ChunksTests.cs @@ -1,7 +1,6 @@ using NUnit.Framework; using YDotNet.Document; using YDotNet.Document.Cells; -using YDotNet.Document.Transactions; using YDotNet.Document.Types.Texts; namespace YDotNet.Tests.Unit.Texts; @@ -32,10 +31,12 @@ public void ChunkIsTheWholeText() public void ChunksFormattedAtBeginning() { // Arrange - var (text, transaction) = ArrangeText(index: 0, length: 2); + var text = ArrangeText(index: 0, length: 2); // Act + var transaction = text.ReadTransaction(); var chunks = text.Chunks(transaction); + transaction.Commit(); // Assert Assert.That(chunks.Count, Is.EqualTo(expected: 2)); @@ -58,10 +59,12 @@ public void ChunksFormattedAtBeginning() public void ChunksFormattedAtMiddle() { // Arrange - var (text, transaction) = ArrangeText(index: 2, length: 2); + var text = ArrangeText(index: 2, length: 2); // Act + var transaction = text.ReadTransaction(); var chunks = text.Chunks(transaction); + transaction.Commit(); // Assert Assert.That(chunks.Count, Is.EqualTo(expected: 3)); @@ -89,10 +92,12 @@ public void ChunksFormattedAtMiddle() public void ChunksFormattedAtEnding() { // Arrange - var (text, transaction) = ArrangeText(index: 3, length: 2); + var text = ArrangeText(index: 3, length: 2); // Act + var transaction = text.ReadTransaction(); var chunks = text.Chunks(transaction); + transaction.Commit(); // Assert Assert.That(chunks.Count, Is.EqualTo(expected: 2)); @@ -111,7 +116,7 @@ public void ChunksFormattedAtEnding() Assert.That(secondChunkAttribute.Value.Boolean, Is.True); } - private (Text, Transaction) ArrangeText(uint index, uint length) + private Text ArrangeText(uint index, uint length) { var doc = new Doc(); var text = doc.Text("value"); @@ -128,6 +133,6 @@ public void ChunksFormattedAtEnding() transaction.Commit(); - return (text, transaction); + return text; } } diff --git a/Tests/YDotNet.Tests.Unit/Texts/FormatTests.cs b/Tests/YDotNet.Tests.Unit/Texts/FormatTests.cs index 3bd04350..40aa65ec 100644 --- a/Tests/YDotNet.Tests.Unit/Texts/FormatTests.cs +++ b/Tests/YDotNet.Tests.Unit/Texts/FormatTests.cs @@ -24,8 +24,12 @@ public void FormatsTextAtBeginning() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); var chunks = text.Chunks(transaction); + Assert.That(chunks.Count, Is.EqualTo(expected: 2)); + + transaction.Commit(); } [Test] @@ -45,8 +49,12 @@ public void FormatsTextAtMiddle() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); var chunks = text.Chunks(transaction); + Assert.That(chunks.Count, Is.EqualTo(expected: 3)); + + transaction.Commit(); } [Test] @@ -66,8 +74,12 @@ public void FormatsTextAtEnding() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); var chunks = text.Chunks(transaction); + Assert.That(chunks.Count, Is.EqualTo(expected: 2)); + + transaction.Commit(); } private (Doc, Text) ArrangeText() diff --git a/Tests/YDotNet.Tests.Unit/Texts/InsertTests.cs b/Tests/YDotNet.Tests.Unit/Texts/InsertTests.cs index e335d634..be64d462 100644 --- a/Tests/YDotNet.Tests.Unit/Texts/InsertTests.cs +++ b/Tests/YDotNet.Tests.Unit/Texts/InsertTests.cs @@ -19,7 +19,11 @@ public void AddsTextAtBeginning() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Hello")); + + transaction.Commit(); } [Test] @@ -36,7 +40,11 @@ public void AddsTextAtEnding() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Hello, world!")); + + transaction.Commit(); } [Test] @@ -53,7 +61,11 @@ public void AddsTextAtMiddle() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Lucas")); + + transaction.Commit(); } [Test] @@ -73,7 +85,11 @@ public void AddsTextAtBeginningWithAttributes() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Hello")); + + transaction.Commit(); } [Test] @@ -94,7 +110,11 @@ public void AddsTextAtEndingWithAttributes() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Hello, world!")); + + transaction.Commit(); } [Test] @@ -115,6 +135,10 @@ public void AddsTextAtMiddleWithAttributes() transaction.Commit(); // Assert + transaction = doc.ReadTransaction(); + Assert.That(text.String(transaction), Is.EqualTo("Lucas")); + + transaction.Commit(); } } diff --git a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs index 3aa2bba0..d2acd003 100644 --- a/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs +++ b/Tests/YDotNet.Tests.Unit/XmlElements/TagTests.cs @@ -18,7 +18,9 @@ public void RootNodesHaveUndefinedAsTag() transaction.Commit(); // Act + transaction = doc.ReadTransaction(); var tag = xmlElement.Tag(transaction); + transaction.Commit(); // Assert Assert.That(tag, Is.EqualTo("xml-element")); From ba69d1055d56c5be1469378e93433fdf14ae893e Mon Sep 17 00:00:00 2001 From: Lucas Viana Date: Thu, 6 Jun 2024 21:36:30 -0300 Subject: [PATCH 75/75] chore: fix typo in comments of `Transaction.Commit()` --- YDotNet/Document/Transactions/Transaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YDotNet/Document/Transactions/Transaction.cs b/YDotNet/Document/Transactions/Transaction.cs index 6cbae948..87dcae50 100644 --- a/YDotNet/Document/Transactions/Transaction.cs +++ b/YDotNet/Document/Transactions/Transaction.cs @@ -57,7 +57,7 @@ protected override void DisposeCore(bool disposing) /// public void Commit() { - // The dispose method has a solution to prevent multiple dipose, so we can just use that. + // The dispose method has a solution to prevent multiple dispose, so we can just use that. Dispose(); }