@fluid-experimental/tree 2.0.0-rc.2.0.1 → 2.0.0-rc.3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/api-report/experimental-tree.api.md +2 -2
- package/dist/ChangeCompression.d.ts +2 -2
- package/dist/ChangeCompression.d.ts.map +1 -1
- package/dist/ChangeCompression.js +1 -1
- package/dist/ChangeCompression.js.map +1 -1
- package/dist/ChangeTypes.d.ts +1 -1
- package/dist/ChangeTypes.d.ts.map +1 -1
- package/dist/ChangeTypes.js +4 -4
- package/dist/ChangeTypes.js.map +1 -1
- package/dist/Checkout.d.ts +3 -3
- package/dist/Checkout.d.ts.map +1 -1
- package/dist/Checkout.js +17 -17
- package/dist/Checkout.js.map +1 -1
- package/dist/EditLog.d.ts +1 -1
- package/dist/EditLog.d.ts.map +1 -1
- package/dist/EditLog.js +9 -9
- package/dist/EditLog.js.map +1 -1
- package/dist/EditUtilities.d.ts +3 -3
- package/dist/EditUtilities.d.ts.map +1 -1
- package/dist/EditUtilities.js +6 -6
- package/dist/EditUtilities.js.map +1 -1
- package/dist/Forest.d.ts.map +1 -1
- package/dist/Forest.js +23 -23
- package/dist/Forest.js.map +1 -1
- package/dist/HistoryEditFactory.d.ts +1 -1
- package/dist/HistoryEditFactory.d.ts.map +1 -1
- package/dist/HistoryEditFactory.js +7 -7
- package/dist/HistoryEditFactory.js.map +1 -1
- package/dist/IdConversion.d.ts.map +1 -1
- package/dist/IdConversion.js.map +1 -1
- package/dist/LogViewer.d.ts +2 -2
- package/dist/LogViewer.d.ts.map +1 -1
- package/dist/LogViewer.js +7 -7
- package/dist/LogViewer.js.map +1 -1
- package/dist/MergeHealth.d.ts.map +1 -1
- package/dist/MergeHealth.js +1 -1
- package/dist/MergeHealth.js.map +1 -1
- package/dist/NodeIdUtilities.d.ts +1 -1
- package/dist/NodeIdUtilities.d.ts.map +1 -1
- package/dist/NodeIdUtilities.js +1 -1
- package/dist/NodeIdUtilities.js.map +1 -1
- package/dist/PayloadUtilities.d.ts.map +1 -1
- package/dist/PayloadUtilities.js +2 -2
- package/dist/PayloadUtilities.js.map +1 -1
- package/dist/ReconciliationPath.d.ts +1 -1
- package/dist/ReconciliationPath.d.ts.map +1 -1
- package/dist/ReconciliationPath.js.map +1 -1
- package/dist/RevisionValueCache.d.ts.map +1 -1
- package/dist/RevisionValueCache.js +2 -2
- package/dist/RevisionValueCache.js.map +1 -1
- package/dist/RevisionView.d.ts +2 -2
- package/dist/RevisionView.d.ts.map +1 -1
- package/dist/RevisionView.js.map +1 -1
- package/dist/SerializationUtilities.d.ts +1 -1
- package/dist/SerializationUtilities.d.ts.map +1 -1
- package/dist/SerializationUtilities.js.map +1 -1
- package/dist/SharedTree.d.ts +8 -7
- package/dist/SharedTree.d.ts.map +1 -1
- package/dist/SharedTree.js +78 -78
- package/dist/SharedTree.js.map +1 -1
- package/dist/SharedTreeEncoder.d.ts +1 -1
- package/dist/SharedTreeEncoder.d.ts.map +1 -1
- package/dist/SharedTreeEncoder.js +31 -31
- package/dist/SharedTreeEncoder.js.map +1 -1
- package/dist/Summary.d.ts +2 -2
- package/dist/Summary.d.ts.map +1 -1
- package/dist/Summary.js +2 -2
- package/dist/Summary.js.map +1 -1
- package/dist/SummaryBackCompatibility.d.ts.map +1 -1
- package/dist/SummaryBackCompatibility.js.map +1 -1
- package/dist/SummaryTestUtilities.d.ts +1 -1
- package/dist/SummaryTestUtilities.d.ts.map +1 -1
- package/dist/SummaryTestUtilities.js.map +1 -1
- package/dist/Transaction.d.ts +3 -3
- package/dist/Transaction.d.ts.map +1 -1
- package/dist/Transaction.js +3 -3
- package/dist/Transaction.js.map +1 -1
- package/dist/TransactionInternal.d.ts +3 -3
- package/dist/TransactionInternal.d.ts.map +1 -1
- package/dist/TransactionInternal.js +6 -6
- package/dist/TransactionInternal.js.map +1 -1
- package/dist/TreeCompressor.d.ts +5 -1
- package/dist/TreeCompressor.d.ts.map +1 -1
- package/dist/TreeCompressor.js +5 -5
- package/dist/TreeCompressor.js.map +1 -1
- package/dist/TreeNodeHandle.d.ts +1 -1
- package/dist/TreeNodeHandle.d.ts.map +1 -1
- package/dist/TreeNodeHandle.js.map +1 -1
- package/dist/TreeView.d.ts +1 -1
- package/dist/TreeView.d.ts.map +1 -1
- package/dist/TreeView.js +2 -3
- package/dist/TreeView.js.map +1 -1
- package/dist/UuidUtilities.d.ts.map +1 -1
- package/dist/UuidUtilities.js.map +1 -1
- package/dist/id-compressor/AppendOnlySortedMap.d.ts.map +1 -1
- package/dist/id-compressor/AppendOnlySortedMap.js +3 -3
- package/dist/id-compressor/AppendOnlySortedMap.js.map +1 -1
- package/dist/id-compressor/IdCompressor.d.ts +1 -1
- package/dist/id-compressor/IdCompressor.d.ts.map +1 -1
- package/dist/id-compressor/IdCompressor.js +25 -26
- package/dist/id-compressor/IdCompressor.js.map +1 -1
- package/dist/id-compressor/IdRange.d.ts.map +1 -1
- package/dist/id-compressor/IdRange.js +2 -2
- package/dist/id-compressor/IdRange.js.map +1 -1
- package/dist/id-compressor/NumericUuid.d.ts.map +1 -1
- package/dist/id-compressor/NumericUuid.js +2 -1
- package/dist/id-compressor/NumericUuid.js.map +1 -1
- package/dist/id-compressor/SessionIdNormalizer.d.ts.map +1 -1
- package/dist/id-compressor/SessionIdNormalizer.js +8 -9
- package/dist/id-compressor/SessionIdNormalizer.js.map +1 -1
- package/dist/migration-shim/migrationDeltaHandler.d.ts +1 -1
- package/dist/migration-shim/migrationDeltaHandler.d.ts.map +1 -1
- package/dist/migration-shim/migrationDeltaHandler.js +11 -11
- package/dist/migration-shim/migrationDeltaHandler.js.map +1 -1
- package/dist/migration-shim/migrationShim.d.ts +8 -4
- package/dist/migration-shim/migrationShim.d.ts.map +1 -1
- package/dist/migration-shim/migrationShim.js +13 -13
- package/dist/migration-shim/migrationShim.js.map +1 -1
- package/dist/migration-shim/migrationShimFactory.d.ts +2 -2
- package/dist/migration-shim/migrationShimFactory.d.ts.map +1 -1
- package/dist/migration-shim/migrationShimFactory.js +2 -2
- package/dist/migration-shim/migrationShimFactory.js.map +1 -1
- package/dist/migration-shim/packageVersion.d.ts +0 -2
- package/dist/migration-shim/packageVersion.d.ts.map +1 -1
- package/dist/migration-shim/packageVersion.js +0 -2
- package/dist/migration-shim/packageVersion.js.map +1 -1
- package/dist/migration-shim/sharedTreeDeltaHandler.d.ts.map +1 -1
- package/dist/migration-shim/sharedTreeDeltaHandler.js +8 -8
- package/dist/migration-shim/sharedTreeDeltaHandler.js.map +1 -1
- package/dist/migration-shim/sharedTreeShim.d.ts +2 -2
- package/dist/migration-shim/sharedTreeShim.d.ts.map +1 -1
- package/dist/migration-shim/sharedTreeShim.js +8 -4
- package/dist/migration-shim/sharedTreeShim.js.map +1 -1
- package/dist/migration-shim/sharedTreeShimFactory.d.ts +1 -1
- package/dist/migration-shim/sharedTreeShimFactory.d.ts.map +1 -1
- package/dist/migration-shim/sharedTreeShimFactory.js +2 -2
- package/dist/migration-shim/sharedTreeShimFactory.js.map +1 -1
- package/dist/migration-shim/shimChannelServices.d.ts +1 -1
- package/dist/migration-shim/shimChannelServices.d.ts.map +1 -1
- package/dist/migration-shim/shimChannelServices.js.map +1 -1
- package/dist/migration-shim/shimDeltaConnection.d.ts +1 -1
- package/dist/migration-shim/shimDeltaConnection.d.ts.map +1 -1
- package/dist/migration-shim/shimDeltaConnection.js +2 -2
- package/dist/migration-shim/shimDeltaConnection.js.map +1 -1
- package/dist/migration-shim/shimHandle.d.ts.map +1 -1
- package/dist/migration-shim/shimHandle.js.map +1 -1
- package/dist/migration-shim/types.d.ts +1 -1
- package/dist/migration-shim/types.d.ts.map +1 -1
- package/dist/migration-shim/types.js.map +1 -1
- package/dist/migration-shim/utils.d.ts +1 -1
- package/dist/migration-shim/utils.d.ts.map +1 -1
- package/dist/migration-shim/utils.js.map +1 -1
- package/dist/persisted-types/0.0.2.d.ts +1 -1
- package/dist/persisted-types/0.0.2.d.ts.map +1 -1
- package/dist/persisted-types/0.0.2.js.map +1 -1
- package/dist/persisted-types/0.1.1.d.ts +1 -1
- package/dist/persisted-types/0.1.1.d.ts.map +1 -1
- package/dist/persisted-types/0.1.1.js +3 -3
- package/dist/persisted-types/0.1.1.js.map +1 -1
- package/lib/ChangeCompression.d.ts +2 -2
- package/lib/ChangeCompression.d.ts.map +1 -1
- package/lib/ChangeCompression.js +1 -1
- package/lib/ChangeCompression.js.map +1 -1
- package/lib/ChangeTypes.d.ts +1 -1
- package/lib/ChangeTypes.d.ts.map +1 -1
- package/lib/ChangeTypes.js +2 -2
- package/lib/ChangeTypes.js.map +1 -1
- package/lib/Checkout.d.ts +3 -3
- package/lib/Checkout.d.ts.map +1 -1
- package/lib/Checkout.js +4 -4
- package/lib/Checkout.js.map +1 -1
- package/lib/EditLog.d.ts +1 -1
- package/lib/EditLog.d.ts.map +1 -1
- package/lib/EditLog.js +2 -2
- package/lib/EditLog.js.map +1 -1
- package/lib/EditUtilities.d.ts +3 -3
- package/lib/EditUtilities.d.ts.map +1 -1
- package/lib/EditUtilities.js +5 -5
- package/lib/EditUtilities.js.map +1 -1
- package/lib/Forest.d.ts.map +1 -1
- package/lib/Forest.js +2 -2
- package/lib/Forest.js.map +1 -1
- package/lib/HistoryEditFactory.d.ts +1 -1
- package/lib/HistoryEditFactory.d.ts.map +1 -1
- package/lib/HistoryEditFactory.js +5 -5
- package/lib/HistoryEditFactory.js.map +1 -1
- package/lib/IdConversion.d.ts.map +1 -1
- package/lib/IdConversion.js.map +1 -1
- package/lib/LogViewer.d.ts +2 -2
- package/lib/LogViewer.d.ts.map +1 -1
- package/lib/LogViewer.js +3 -3
- package/lib/LogViewer.js.map +1 -1
- package/lib/MergeHealth.d.ts.map +1 -1
- package/lib/MergeHealth.js +1 -1
- package/lib/MergeHealth.js.map +1 -1
- package/lib/NodeIdUtilities.d.ts +1 -1
- package/lib/NodeIdUtilities.d.ts.map +1 -1
- package/lib/NodeIdUtilities.js +1 -1
- package/lib/NodeIdUtilities.js.map +1 -1
- package/lib/PayloadUtilities.d.ts.map +1 -1
- package/lib/PayloadUtilities.js +1 -1
- package/lib/PayloadUtilities.js.map +1 -1
- package/lib/ReconciliationPath.d.ts +1 -1
- package/lib/ReconciliationPath.d.ts.map +1 -1
- package/lib/ReconciliationPath.js.map +1 -1
- package/lib/RevisionValueCache.d.ts.map +1 -1
- package/lib/RevisionValueCache.js +2 -2
- package/lib/RevisionValueCache.js.map +1 -1
- package/lib/RevisionView.d.ts +2 -2
- package/lib/RevisionView.d.ts.map +1 -1
- package/lib/RevisionView.js.map +1 -1
- package/lib/SerializationUtilities.d.ts +1 -1
- package/lib/SerializationUtilities.d.ts.map +1 -1
- package/lib/SerializationUtilities.js.map +1 -1
- package/lib/SharedTree.d.ts +8 -7
- package/lib/SharedTree.d.ts.map +1 -1
- package/lib/SharedTree.js +13 -13
- package/lib/SharedTree.js.map +1 -1
- package/lib/SharedTreeEncoder.d.ts +1 -1
- package/lib/SharedTreeEncoder.d.ts.map +1 -1
- package/lib/SharedTreeEncoder.js +5 -5
- package/lib/SharedTreeEncoder.js.map +1 -1
- package/lib/Summary.d.ts +2 -2
- package/lib/Summary.d.ts.map +1 -1
- package/lib/Summary.js +1 -1
- package/lib/Summary.js.map +1 -1
- package/lib/SummaryBackCompatibility.d.ts.map +1 -1
- package/lib/SummaryBackCompatibility.js.map +1 -1
- package/lib/SummaryTestUtilities.d.ts +1 -1
- package/lib/SummaryTestUtilities.d.ts.map +1 -1
- package/lib/SummaryTestUtilities.js.map +1 -1
- package/lib/Transaction.d.ts +3 -3
- package/lib/Transaction.d.ts.map +1 -1
- package/lib/Transaction.js +3 -3
- package/lib/Transaction.js.map +1 -1
- package/lib/TransactionInternal.d.ts +3 -3
- package/lib/TransactionInternal.d.ts.map +1 -1
- package/lib/TransactionInternal.js +3 -3
- package/lib/TransactionInternal.js.map +1 -1
- package/lib/TreeCompressor.d.ts +5 -1
- package/lib/TreeCompressor.d.ts.map +1 -1
- package/lib/TreeCompressor.js +2 -2
- package/lib/TreeCompressor.js.map +1 -1
- package/lib/TreeNodeHandle.d.ts +1 -1
- package/lib/TreeNodeHandle.d.ts.map +1 -1
- package/lib/TreeNodeHandle.js.map +1 -1
- package/lib/TreeView.d.ts +1 -1
- package/lib/TreeView.d.ts.map +1 -1
- package/lib/TreeView.js +1 -2
- package/lib/TreeView.js.map +1 -1
- package/lib/UuidUtilities.d.ts.map +1 -1
- package/lib/UuidUtilities.js +1 -1
- package/lib/UuidUtilities.js.map +1 -1
- package/lib/id-compressor/AppendOnlySortedMap.d.ts.map +1 -1
- package/lib/id-compressor/AppendOnlySortedMap.js +1 -1
- package/lib/id-compressor/AppendOnlySortedMap.js.map +1 -1
- package/lib/id-compressor/IdCompressor.d.ts +1 -1
- package/lib/id-compressor/IdCompressor.d.ts.map +1 -1
- package/lib/id-compressor/IdCompressor.js +4 -5
- package/lib/id-compressor/IdCompressor.js.map +1 -1
- package/lib/id-compressor/IdRange.d.ts.map +1 -1
- package/lib/id-compressor/IdRange.js +1 -1
- package/lib/id-compressor/IdRange.js.map +1 -1
- package/lib/id-compressor/NumericUuid.d.ts.map +1 -1
- package/lib/id-compressor/NumericUuid.js +2 -1
- package/lib/id-compressor/NumericUuid.js.map +1 -1
- package/lib/id-compressor/SessionIdNormalizer.d.ts.map +1 -1
- package/lib/id-compressor/SessionIdNormalizer.js +1 -2
- package/lib/id-compressor/SessionIdNormalizer.js.map +1 -1
- package/lib/migration-shim/migrationDeltaHandler.d.ts +1 -1
- package/lib/migration-shim/migrationDeltaHandler.d.ts.map +1 -1
- package/lib/migration-shim/migrationDeltaHandler.js +1 -1
- package/lib/migration-shim/migrationDeltaHandler.js.map +1 -1
- package/lib/migration-shim/migrationShim.d.ts +8 -4
- package/lib/migration-shim/migrationShim.d.ts.map +1 -1
- package/lib/migration-shim/migrationShim.js +3 -3
- package/lib/migration-shim/migrationShim.js.map +1 -1
- package/lib/migration-shim/migrationShimFactory.d.ts +2 -2
- package/lib/migration-shim/migrationShimFactory.d.ts.map +1 -1
- package/lib/migration-shim/migrationShimFactory.js +1 -1
- package/lib/migration-shim/migrationShimFactory.js.map +1 -1
- package/lib/migration-shim/packageVersion.d.ts +0 -2
- package/lib/migration-shim/packageVersion.d.ts.map +1 -1
- package/lib/migration-shim/packageVersion.js +0 -2
- package/lib/migration-shim/packageVersion.js.map +1 -1
- package/lib/migration-shim/sharedTreeDeltaHandler.d.ts.map +1 -1
- package/lib/migration-shim/sharedTreeDeltaHandler.js +1 -1
- package/lib/migration-shim/sharedTreeDeltaHandler.js.map +1 -1
- package/lib/migration-shim/sharedTreeShim.d.ts +2 -2
- package/lib/migration-shim/sharedTreeShim.d.ts.map +1 -1
- package/lib/migration-shim/sharedTreeShim.js +6 -2
- package/lib/migration-shim/sharedTreeShim.js.map +1 -1
- package/lib/migration-shim/sharedTreeShimFactory.d.ts +1 -1
- package/lib/migration-shim/sharedTreeShimFactory.d.ts.map +1 -1
- package/lib/migration-shim/sharedTreeShimFactory.js +1 -1
- package/lib/migration-shim/sharedTreeShimFactory.js.map +1 -1
- package/lib/migration-shim/shimChannelServices.d.ts +1 -1
- package/lib/migration-shim/shimChannelServices.d.ts.map +1 -1
- package/lib/migration-shim/shimChannelServices.js.map +1 -1
- package/lib/migration-shim/shimDeltaConnection.d.ts +1 -1
- package/lib/migration-shim/shimDeltaConnection.d.ts.map +1 -1
- package/lib/migration-shim/shimDeltaConnection.js +1 -1
- package/lib/migration-shim/shimDeltaConnection.js.map +1 -1
- package/lib/migration-shim/shimHandle.d.ts.map +1 -1
- package/lib/migration-shim/shimHandle.js.map +1 -1
- package/lib/migration-shim/types.d.ts +1 -1
- package/lib/migration-shim/types.d.ts.map +1 -1
- package/lib/migration-shim/types.js.map +1 -1
- package/lib/migration-shim/utils.d.ts +1 -1
- package/lib/migration-shim/utils.d.ts.map +1 -1
- package/lib/migration-shim/utils.js.map +1 -1
- package/lib/persisted-types/0.0.2.d.ts +1 -1
- package/lib/persisted-types/0.0.2.d.ts.map +1 -1
- package/lib/persisted-types/0.0.2.js.map +1 -1
- package/lib/persisted-types/0.1.1.d.ts +1 -1
- package/lib/persisted-types/0.1.1.d.ts.map +1 -1
- package/lib/persisted-types/0.1.1.js +1 -1
- package/lib/persisted-types/0.1.1.js.map +1 -1
- package/package.json +33 -32
- package/src/ChangeCompression.ts +8 -8
- package/src/ChangeTypes.ts +5 -4
- package/src/Checkout.ts +9 -7
- package/src/EditLog.ts +4 -3
- package/src/EditUtilities.ts +9 -8
- package/src/Forest.ts +3 -2
- package/src/HistoryEditFactory.ts +12 -11
- package/src/IdConversion.ts +2 -2
- package/src/LogViewer.ts +5 -4
- package/src/MergeHealth.ts +2 -1
- package/src/NodeIdUtilities.ts +2 -2
- package/src/PayloadUtilities.ts +2 -1
- package/src/ReconciliationPath.ts +1 -1
- package/src/RevisionValueCache.ts +3 -2
- package/src/RevisionView.ts +3 -3
- package/src/SerializationUtilities.ts +1 -1
- package/src/SharedTree.ts +46 -49
- package/src/SharedTreeEncoder.ts +30 -29
- package/src/Summary.ts +5 -3
- package/src/SummaryBackCompatibility.ts +1 -0
- package/src/SummaryTestUtilities.ts +2 -1
- package/src/Transaction.ts +7 -6
- package/src/TransactionInternal.ts +17 -16
- package/src/TreeCompressor.ts +6 -4
- package/src/TreeNodeHandle.ts +2 -2
- package/src/TreeView.ts +3 -3
- package/src/UuidUtilities.ts +2 -1
- package/src/id-compressor/AppendOnlySortedMap.ts +2 -1
- package/src/id-compressor/IdCompressor.ts +18 -17
- package/src/id-compressor/IdRange.ts +2 -1
- package/src/id-compressor/NumericUuid.ts +1 -1
- package/src/id-compressor/SessionIdNormalizer.ts +3 -3
- package/src/migration-shim/migrationDeltaHandler.ts +3 -2
- package/src/migration-shim/migrationShim.ts +14 -10
- package/src/migration-shim/migrationShimFactory.ts +6 -4
- package/src/migration-shim/packageVersion.ts +0 -2
- package/src/migration-shim/sharedTreeDeltaHandler.ts +3 -2
- package/src/migration-shim/sharedTreeShim.ts +7 -5
- package/src/migration-shim/sharedTreeShimFactory.ts +3 -3
- package/src/migration-shim/shimChannelServices.ts +1 -1
- package/src/migration-shim/shimDeltaConnection.ts +3 -2
- package/src/migration-shim/shimHandle.ts +1 -0
- package/src/migration-shim/types.ts +3 -1
- package/src/migration-shim/utils.ts +2 -1
- package/src/persisted-types/0.0.2.ts +2 -2
- package/src/persisted-types/0.1.1.ts +10 -8
- package/dist/tree-alpha.d.ts +0 -2901
- package/dist/tree-beta.d.ts +0 -348
- package/dist/tree-public.d.ts +0 -348
- package/dist/tree-untrimmed.d.ts +0 -3820
- package/lib/test/AppendOnlySortedMap.perf.tests.d.ts +0 -6
- package/lib/test/AppendOnlySortedMap.perf.tests.d.ts.map +0 -1
- package/lib/test/AppendOnlySortedMap.perf.tests.js +0 -49
- package/lib/test/AppendOnlySortedMap.perf.tests.js.map +0 -1
- package/lib/test/AppendOnlySortedMap.tests.d.ts +0 -6
- package/lib/test/AppendOnlySortedMap.tests.d.ts.map +0 -1
- package/lib/test/AppendOnlySortedMap.tests.js +0 -213
- package/lib/test/AppendOnlySortedMap.tests.js.map +0 -1
- package/lib/test/ChangeCompression.tests.d.ts +0 -6
- package/lib/test/ChangeCompression.tests.d.ts.map +0 -1
- package/lib/test/ChangeCompression.tests.js +0 -154
- package/lib/test/ChangeCompression.tests.js.map +0 -1
- package/lib/test/Checkout.tests.d.ts +0 -10
- package/lib/test/Checkout.tests.d.ts.map +0 -1
- package/lib/test/Checkout.tests.js +0 -460
- package/lib/test/Checkout.tests.js.map +0 -1
- package/lib/test/Common.tests.d.ts +0 -6
- package/lib/test/Common.tests.d.ts.map +0 -1
- package/lib/test/Common.tests.js +0 -102
- package/lib/test/Common.tests.js.map +0 -1
- package/lib/test/EagerCheckout.tests.d.ts +0 -6
- package/lib/test/EagerCheckout.tests.d.ts.map +0 -1
- package/lib/test/EagerCheckout.tests.js +0 -20
- package/lib/test/EagerCheckout.tests.js.map +0 -1
- package/lib/test/Edit.tests.d.ts +0 -6
- package/lib/test/Edit.tests.d.ts.map +0 -1
- package/lib/test/Edit.tests.js +0 -60
- package/lib/test/Edit.tests.js.map +0 -1
- package/lib/test/EditLog.perf.tests.d.ts +0 -6
- package/lib/test/EditLog.perf.tests.d.ts.map +0 -1
- package/lib/test/EditLog.perf.tests.js +0 -41
- package/lib/test/EditLog.perf.tests.js.map +0 -1
- package/lib/test/EditLog.tests.d.ts +0 -6
- package/lib/test/EditLog.tests.d.ts.map +0 -1
- package/lib/test/EditLog.tests.js +0 -355
- package/lib/test/EditLog.tests.js.map +0 -1
- package/lib/test/EditUtilities.tests.d.ts +0 -6
- package/lib/test/EditUtilities.tests.d.ts.map +0 -1
- package/lib/test/EditUtilities.tests.js +0 -512
- package/lib/test/EditUtilities.tests.js.map +0 -1
- package/lib/test/Forest.perf.tests.d.ts +0 -6
- package/lib/test/Forest.perf.tests.d.ts.map +0 -1
- package/lib/test/Forest.perf.tests.js +0 -135
- package/lib/test/Forest.perf.tests.js.map +0 -1
- package/lib/test/Forest.tests.d.ts +0 -6
- package/lib/test/Forest.tests.d.ts.map +0 -1
- package/lib/test/Forest.tests.js +0 -213
- package/lib/test/Forest.tests.js.map +0 -1
- package/lib/test/GenericTransaction.tests.d.ts +0 -6
- package/lib/test/GenericTransaction.tests.d.ts.map +0 -1
- package/lib/test/GenericTransaction.tests.js +0 -31
- package/lib/test/GenericTransaction.tests.js.map +0 -1
- package/lib/test/HistoryEditFactory.tests.d.ts +0 -6
- package/lib/test/HistoryEditFactory.tests.d.ts.map +0 -1
- package/lib/test/HistoryEditFactory.tests.js +0 -170
- package/lib/test/HistoryEditFactory.tests.js.map +0 -1
- package/lib/test/IdCompressor.perf.tests.d.ts +0 -6
- package/lib/test/IdCompressor.perf.tests.d.ts.map +0 -1
- package/lib/test/IdCompressor.perf.tests.js +0 -290
- package/lib/test/IdCompressor.perf.tests.js.map +0 -1
- package/lib/test/IdCompressor.tests.d.ts +0 -6
- package/lib/test/IdCompressor.tests.d.ts.map +0 -1
- package/lib/test/IdCompressor.tests.js +0 -1542
- package/lib/test/IdCompressor.tests.js.map +0 -1
- package/lib/test/IdConversion.tests.d.ts +0 -6
- package/lib/test/IdConversion.tests.d.ts.map +0 -1
- package/lib/test/IdConversion.tests.js +0 -36
- package/lib/test/IdConversion.tests.js.map +0 -1
- package/lib/test/LazyCheckout.tests.d.ts +0 -6
- package/lib/test/LazyCheckout.tests.d.ts.map +0 -1
- package/lib/test/LazyCheckout.tests.js +0 -22
- package/lib/test/LazyCheckout.tests.js.map +0 -1
- package/lib/test/LogViewer.tests.d.ts +0 -6
- package/lib/test/LogViewer.tests.d.ts.map +0 -1
- package/lib/test/LogViewer.tests.js +0 -588
- package/lib/test/LogViewer.tests.js.map +0 -1
- package/lib/test/MergeHealthTelemetryHeartbeat.tests.d.ts +0 -6
- package/lib/test/MergeHealthTelemetryHeartbeat.tests.d.ts.map +0 -1
- package/lib/test/MergeHealthTelemetryHeartbeat.tests.js +0 -351
- package/lib/test/MergeHealthTelemetryHeartbeat.tests.js.map +0 -1
- package/lib/test/NumericUuid.perf.tests.d.ts +0 -6
- package/lib/test/NumericUuid.perf.tests.d.ts.map +0 -1
- package/lib/test/NumericUuid.perf.tests.js +0 -68
- package/lib/test/NumericUuid.perf.tests.js.map +0 -1
- package/lib/test/NumericUuid.tests.d.ts +0 -6
- package/lib/test/NumericUuid.tests.d.ts.map +0 -1
- package/lib/test/NumericUuid.tests.js +0 -192
- package/lib/test/NumericUuid.tests.js.map +0 -1
- package/lib/test/RevisionValueCache.tests.d.ts +0 -6
- package/lib/test/RevisionValueCache.tests.d.ts.map +0 -1
- package/lib/test/RevisionValueCache.tests.js +0 -106
- package/lib/test/RevisionValueCache.tests.js.map +0 -1
- package/lib/test/RevisionView.tests.d.ts +0 -6
- package/lib/test/RevisionView.tests.d.ts.map +0 -1
- package/lib/test/RevisionView.tests.js +0 -131
- package/lib/test/RevisionView.tests.js.map +0 -1
- package/lib/test/SessionIdNormalizer.tests.d.ts +0 -6
- package/lib/test/SessionIdNormalizer.tests.d.ts.map +0 -1
- package/lib/test/SessionIdNormalizer.tests.js +0 -377
- package/lib/test/SessionIdNormalizer.tests.js.map +0 -1
- package/lib/test/SharedTree.fuzz.tests.d.ts +0 -6
- package/lib/test/SharedTree.fuzz.tests.d.ts.map +0 -1
- package/lib/test/SharedTree.fuzz.tests.js +0 -9
- package/lib/test/SharedTree.fuzz.tests.js.map +0 -1
- package/lib/test/SharedTree.perf.tests.d.ts +0 -6
- package/lib/test/SharedTree.perf.tests.d.ts.map +0 -1
- package/lib/test/SharedTree.perf.tests.js +0 -39
- package/lib/test/SharedTree.perf.tests.js.map +0 -1
- package/lib/test/SharedTree.tests.d.ts +0 -6
- package/lib/test/SharedTree.tests.d.ts.map +0 -1
- package/lib/test/SharedTree.tests.js +0 -22
- package/lib/test/SharedTree.tests.js.map +0 -1
- package/lib/test/StringInterner.tests.d.ts +0 -6
- package/lib/test/StringInterner.tests.d.ts.map +0 -1
- package/lib/test/StringInterner.tests.js +0 -73
- package/lib/test/StringInterner.tests.js.map +0 -1
- package/lib/test/Summary.tests.d.ts +0 -7
- package/lib/test/Summary.tests.d.ts.map +0 -1
- package/lib/test/Summary.tests.js +0 -386
- package/lib/test/Summary.tests.js.map +0 -1
- package/lib/test/Transaction.tests.d.ts +0 -6
- package/lib/test/Transaction.tests.d.ts.map +0 -1
- package/lib/test/Transaction.tests.js +0 -124
- package/lib/test/Transaction.tests.js.map +0 -1
- package/lib/test/TransactionInternal.tests.d.ts +0 -6
- package/lib/test/TransactionInternal.tests.d.ts.map +0 -1
- package/lib/test/TransactionInternal.tests.js +0 -576
- package/lib/test/TransactionInternal.tests.js.map +0 -1
- package/lib/test/TreeCompression.tests.d.ts +0 -6
- package/lib/test/TreeCompression.tests.d.ts.map +0 -1
- package/lib/test/TreeCompression.tests.js +0 -291
- package/lib/test/TreeCompression.tests.js.map +0 -1
- package/lib/test/TreeView.tests.d.ts +0 -6
- package/lib/test/TreeView.tests.d.ts.map +0 -1
- package/lib/test/TreeView.tests.js +0 -178
- package/lib/test/TreeView.tests.js.map +0 -1
- package/lib/test/UndoRedoHandler.tests.d.ts +0 -6
- package/lib/test/UndoRedoHandler.tests.d.ts.map +0 -1
- package/lib/test/UndoRedoHandler.tests.js +0 -37
- package/lib/test/UndoRedoHandler.tests.js.map +0 -1
- package/lib/test/fuzz/Generators.d.ts +0 -8
- package/lib/test/fuzz/Generators.d.ts.map +0 -1
- package/lib/test/fuzz/Generators.js +0 -345
- package/lib/test/fuzz/Generators.js.map +0 -1
- package/lib/test/fuzz/SharedTreeFuzzTests.d.ts +0 -23
- package/lib/test/fuzz/SharedTreeFuzzTests.d.ts.map +0 -1
- package/lib/test/fuzz/SharedTreeFuzzTests.js +0 -241
- package/lib/test/fuzz/SharedTreeFuzzTests.js.map +0 -1
- package/lib/test/fuzz/Types.d.ts +0 -136
- package/lib/test/fuzz/Types.d.ts.map +0 -1
- package/lib/test/fuzz/Types.js +0 -6
- package/lib/test/fuzz/Types.js.map +0 -1
- package/lib/test/utilities/IdCompressorTestUtilities.d.ts +0 -246
- package/lib/test/utilities/IdCompressorTestUtilities.d.ts.map +0 -1
- package/lib/test/utilities/IdCompressorTestUtilities.js +0 -608
- package/lib/test/utilities/IdCompressorTestUtilities.js.map +0 -1
- package/lib/test/utilities/MockTransaction.d.ts +0 -35
- package/lib/test/utilities/MockTransaction.d.ts.map +0 -1
- package/lib/test/utilities/MockTransaction.js +0 -51
- package/lib/test/utilities/MockTransaction.js.map +0 -1
- package/lib/test/utilities/PendingLocalStateTests.d.ts +0 -12
- package/lib/test/utilities/PendingLocalStateTests.d.ts.map +0 -1
- package/lib/test/utilities/PendingLocalStateTests.js +0 -223
- package/lib/test/utilities/PendingLocalStateTests.js.map +0 -1
- package/lib/test/utilities/SharedTreeTests.d.ts +0 -12
- package/lib/test/utilities/SharedTreeTests.d.ts.map +0 -1
- package/lib/test/utilities/SharedTreeTests.js +0 -949
- package/lib/test/utilities/SharedTreeTests.js.map +0 -1
- package/lib/test/utilities/SharedTreeVersioningTests.d.ts +0 -11
- package/lib/test/utilities/SharedTreeVersioningTests.d.ts.map +0 -1
- package/lib/test/utilities/SharedTreeVersioningTests.js +0 -439
- package/lib/test/utilities/SharedTreeVersioningTests.js.map +0 -1
- package/lib/test/utilities/SummaryLoadPerfTests.d.ts +0 -10
- package/lib/test/utilities/SummaryLoadPerfTests.d.ts.map +0 -1
- package/lib/test/utilities/SummaryLoadPerfTests.js +0 -105
- package/lib/test/utilities/SummaryLoadPerfTests.js.map +0 -1
- package/lib/test/utilities/SummarySizeTests.d.ts +0 -11
- package/lib/test/utilities/SummarySizeTests.d.ts.map +0 -1
- package/lib/test/utilities/SummarySizeTests.js +0 -160
- package/lib/test/utilities/SummarySizeTests.js.map +0 -1
- package/lib/test/utilities/TestCommon.d.ts +0 -13
- package/lib/test/utilities/TestCommon.d.ts.map +0 -1
- package/lib/test/utilities/TestCommon.js +0 -19
- package/lib/test/utilities/TestCommon.js.map +0 -1
- package/lib/test/utilities/TestNode.d.ts +0 -140
- package/lib/test/utilities/TestNode.d.ts.map +0 -1
- package/lib/test/utilities/TestNode.js +0 -282
- package/lib/test/utilities/TestNode.js.map +0 -1
- package/lib/test/utilities/TestSerializer.d.ts +0 -24
- package/lib/test/utilities/TestSerializer.d.ts.map +0 -1
- package/lib/test/utilities/TestSerializer.js +0 -40
- package/lib/test/utilities/TestSerializer.js.map +0 -1
- package/lib/test/utilities/TestUtilities.d.ts +0 -212
- package/lib/test/utilities/TestUtilities.d.ts.map +0 -1
- package/lib/test/utilities/TestUtilities.js +0 -413
- package/lib/test/utilities/TestUtilities.js.map +0 -1
- package/lib/test/utilities/UndoRedoTests.d.ts +0 -32
- package/lib/test/utilities/UndoRedoTests.d.ts.map +0 -1
- package/lib/test/utilities/UndoRedoTests.js +0 -317
- package/lib/test/utilities/UndoRedoTests.js.map +0 -1
- /package/{dist → lib}/tsdoc-metadata.json +0 -0
|
@@ -1,949 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { strict as assert } from 'assert';
|
|
6
|
-
import { expect } from 'chai';
|
|
7
|
-
import { SummaryType } from '@fluidframework/protocol-definitions';
|
|
8
|
-
import { MockFluidDataStoreRuntime, validateAssertionError, } from '@fluidframework/test-runtime-utils';
|
|
9
|
-
import { assertArrayOfOne, assertNotUndefined, fail, isSharedTreeEvent } from '../../Common.js';
|
|
10
|
-
import { EditLog } from '../../EditLog.js';
|
|
11
|
-
import { initialTree } from '../../InitialTree.js';
|
|
12
|
-
import { TreeNodeHandle } from '../../TreeNodeHandle.js';
|
|
13
|
-
import { deserialize } from '../../SummaryBackCompatibility.js';
|
|
14
|
-
import { useFailedSequencedEditTelemetry } from '../../MergeHealth.js';
|
|
15
|
-
import { MutableStringInterner } from '../../StringInterner.js';
|
|
16
|
-
import { getChangeNodeFromView } from '../../SerializationUtilities.js';
|
|
17
|
-
import { ChangeTypeInternal, EditStatus, WriteFormat, } from '../../persisted-types/index.js';
|
|
18
|
-
import { SharedTreeEvent } from '../../EventTypes.js';
|
|
19
|
-
import { Change, ChangeType, StablePlace, StableRange } from '../../ChangeTypes.js';
|
|
20
|
-
import { convertTreeNodes, deepCompareNodes } from '../../EditUtilities.js';
|
|
21
|
-
import { serialize } from '../../Summary.js';
|
|
22
|
-
import { InterningTreeCompressor } from '../../TreeCompressor.js';
|
|
23
|
-
import { SharedTreeEncoder_0_0_2, SharedTreeEncoder_0_1_1 } from '../../SharedTreeEncoder.js';
|
|
24
|
-
import { sequencedIdNormalizer } from '../../NodeIdUtilities.js';
|
|
25
|
-
import { convertNodeDataIds } from '../../IdConversion.js';
|
|
26
|
-
import { generateStableId, nilUuid } from '../../UuidUtilities.js';
|
|
27
|
-
import { buildLeaf, SimpleTestTree } from './TestNode.js';
|
|
28
|
-
import { TestFluidHandle, TestFluidSerializer } from './TestSerializer.js';
|
|
29
|
-
import { runSharedTreeUndoRedoTestSuite } from './UndoRedoTests.js';
|
|
30
|
-
import { areNodesEquivalent, assertNoDelta, setUpTestTree, testTrait, testTraitLabel, translateId, spyOnSubmittedOps, normalizeIds, normalizeId, normalizeEdit, getIdNormalizerFromSharedTree, getEditLogInternal, } from './TestUtilities.js';
|
|
31
|
-
function revertEditInTree(tree, edit) {
|
|
32
|
-
return tree.revert(edit);
|
|
33
|
-
}
|
|
34
|
-
// Options for the undo/redo test suite. The undo and redo functions are the same.
|
|
35
|
-
const undoRedoOptions = {
|
|
36
|
-
title: 'Revert',
|
|
37
|
-
undo: revertEditInTree,
|
|
38
|
-
redo: revertEditInTree,
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Runs a test suite for operations on `SharedTree` writing ops at `writeFormat`.
|
|
42
|
-
* This suite can be used to test other implementations that aim to fulfill `SharedTree`'s contract.
|
|
43
|
-
*/
|
|
44
|
-
export function runSharedTreeOperationsTests(title, writeFormat, setUpTestSharedTreeWithDefaultVersion) {
|
|
45
|
-
const setUpTestSharedTree = (options) => setUpTestSharedTreeWithDefaultVersion({ writeFormat, ...options });
|
|
46
|
-
function createSimpleTestTree(options) {
|
|
47
|
-
const { tree: sharedTree, componentRuntime, containerRuntimeFactory } = setUpTestSharedTree(options);
|
|
48
|
-
const testTree = setUpTestTree(sharedTree);
|
|
49
|
-
return { sharedTree, testTree, componentRuntime, containerRuntimeFactory };
|
|
50
|
-
}
|
|
51
|
-
describe(title, () => {
|
|
52
|
-
const testSerializer = new TestFluidSerializer();
|
|
53
|
-
describe('SharedTree before initialization', () => {
|
|
54
|
-
it('can create a new SharedTree', () => {
|
|
55
|
-
const { tree } = setUpTestSharedTree();
|
|
56
|
-
expect(tree).to.not.be.undefined;
|
|
57
|
-
});
|
|
58
|
-
it('valid without initial tree', () => {
|
|
59
|
-
const { tree } = setUpTestSharedTree();
|
|
60
|
-
expect(tree.currentView.getTrait(testTrait(tree.currentView))).deep.equals([], 'Root should exist, and child traits should be valid but empty.');
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe('SharedTree in local state', () => {
|
|
64
|
-
it('does not emit change events for each change in a batch of changes', () => {
|
|
65
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
66
|
-
let changeCount = 0;
|
|
67
|
-
sharedTree.on(SharedTreeEvent.EditCommitted, () => {
|
|
68
|
-
const leftTrait = sharedTree.currentView.getTrait(testTree.left.traitLocation);
|
|
69
|
-
const rightTrait = sharedTree.currentView.getTrait(testTree.right.traitLocation);
|
|
70
|
-
expect(leftTrait.length).to.equal(0); // "left" child is deleted...
|
|
71
|
-
expect(rightTrait.length).to.equal(2); // ...and added to "right" trait
|
|
72
|
-
changeCount += 1;
|
|
73
|
-
});
|
|
74
|
-
sharedTree.applyEdit(...Change.move(StableRange.only(testTree.left), StablePlace.after(testTree.right)));
|
|
75
|
-
expect(changeCount).equals(1);
|
|
76
|
-
});
|
|
77
|
-
it('can insert a wrapped tree', () => {
|
|
78
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
79
|
-
const childNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
80
|
-
const childId = 0;
|
|
81
|
-
const childrenTraitLabel = 'children';
|
|
82
|
-
const parentNode = {
|
|
83
|
-
identifier: testTree.generateNodeId(),
|
|
84
|
-
definition: 'node',
|
|
85
|
-
traits: {
|
|
86
|
-
[childrenTraitLabel]: childId,
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
const parentId = 1;
|
|
90
|
-
const buildChild = Change.build(childNode, childId);
|
|
91
|
-
const buildParent = Change.build(parentNode, parentId);
|
|
92
|
-
const insertParent = Change.insert(parentId, StablePlace.before(testTree.left));
|
|
93
|
-
sharedTree.applyEdit(buildChild, buildParent, insertParent);
|
|
94
|
-
const leftTrait = sharedTree.currentView.getTrait(testTree.left.traitLocation);
|
|
95
|
-
expect(leftTrait.length).to.equal(2);
|
|
96
|
-
expect(leftTrait[0]).to.equal(parentNode.identifier);
|
|
97
|
-
const childrenTrait = sharedTree.currentView.getTrait({
|
|
98
|
-
parent: parentNode.identifier,
|
|
99
|
-
label: childrenTraitLabel,
|
|
100
|
-
});
|
|
101
|
-
expect(childrenTrait.length).to.equal(1);
|
|
102
|
-
expect(childrenTrait[0]).to.equal(childNode.identifier);
|
|
103
|
-
});
|
|
104
|
-
it('prevents multi-parenting detached trees', () => {
|
|
105
|
-
const { sharedTree, testTree } = createSimpleTestTree({ allowMalformed: true });
|
|
106
|
-
const childNode = testTree.buildLeaf();
|
|
107
|
-
const childId = 0;
|
|
108
|
-
const childrenTraitLabel = 'children';
|
|
109
|
-
const parentNode = {
|
|
110
|
-
identifier: testTree.generateNodeId(),
|
|
111
|
-
definition: 'node',
|
|
112
|
-
traits: {
|
|
113
|
-
[childrenTraitLabel]: childId,
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
const parentNode2 = {
|
|
117
|
-
identifier: testTree.generateNodeId(),
|
|
118
|
-
definition: 'node',
|
|
119
|
-
traits: {
|
|
120
|
-
[childrenTraitLabel]: childId,
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
const buildChild = Change.build(childNode, childId);
|
|
124
|
-
const buildParent = Change.build(parentNode, 1);
|
|
125
|
-
const buildParent2 = Change.build(parentNode2, 2);
|
|
126
|
-
assertNoDelta(sharedTree, () => {
|
|
127
|
-
// we don't expect this edit application to change anything
|
|
128
|
-
sharedTree.applyEdit(buildChild, buildParent, buildParent2);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
// TODO:#58052: Make this test pass.
|
|
132
|
-
it.skip('prevents setting the value of a node in a detached subtree', () => {
|
|
133
|
-
const { sharedTree, testTree } = createSimpleTestTree({ allowInvalid: true });
|
|
134
|
-
const detachedNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
135
|
-
const detachedSequenceId = 0;
|
|
136
|
-
const { id } = sharedTree.applyEdit(Change.build(detachedNode, detachedSequenceId), Change.setPayload(detachedNode.identifier, 42), Change.insert(detachedSequenceId, StablePlace.before(testTree.left)));
|
|
137
|
-
const logViewer = sharedTree.logViewer;
|
|
138
|
-
expect(logViewer.getEditResultInMemory(logViewer.log.getIndexOfId(id)).status).equals(EditStatus.Invalid);
|
|
139
|
-
sharedTree.currentView.assertConsistent();
|
|
140
|
-
});
|
|
141
|
-
// TODO:#58052: Make this test pass.
|
|
142
|
-
it.skip('prevents inserting a node in a detached subtree through a local edit', () => {
|
|
143
|
-
const { sharedTree, testTree } = createSimpleTestTree({ allowInvalid: true });
|
|
144
|
-
const detachedNewNode = testTree.buildLeaf();
|
|
145
|
-
const detachedNewNodeSequenceId = 0;
|
|
146
|
-
const detachedRightNodeSequenceId = 1;
|
|
147
|
-
const { id } = sharedTree.applyEdit(Change.build(detachedNewNode, detachedNewNodeSequenceId), Change.detach(StableRange.only(testTree.right), detachedRightNodeSequenceId),
|
|
148
|
-
// This change attempts to insert a node under a detached node
|
|
149
|
-
Change.insert(detachedNewNodeSequenceId, StablePlace.atStartOf({ parent: testTree.right.identifier, label: 'foo' })), Change.insert(detachedRightNodeSequenceId, StablePlace.before(testTree.left)));
|
|
150
|
-
const logViewer = sharedTree.logViewer;
|
|
151
|
-
expect(logViewer.getEditResultInMemory(logViewer.log.getIndexOfId(id)).status).equals(EditStatus.Invalid);
|
|
152
|
-
sharedTree.currentView.assertConsistent();
|
|
153
|
-
});
|
|
154
|
-
it('prevents deletion of the root', () => {
|
|
155
|
-
const { sharedTree } = createSimpleTestTree({ allowInvalid: true });
|
|
156
|
-
const rootId = sharedTree.convertToNodeId(initialTree.identifier);
|
|
157
|
-
expect(sharedTree.currentView.hasNode(rootId));
|
|
158
|
-
assertNoDelta(sharedTree, () => {
|
|
159
|
-
// Try to delete the root
|
|
160
|
-
sharedTree.applyEdit(Change.delete(StableRange.only(rootId)));
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
it('can apply multiple local edits without ack from server', () => {
|
|
164
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
165
|
-
const newNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
166
|
-
sharedTree.applyEdit(...Change.insertTree(newNode, StablePlace.after(testTree.left)));
|
|
167
|
-
sharedTree.applyEdit(...Change.move(StableRange.only(newNode), StablePlace.before(testTree.left)));
|
|
168
|
-
const leftTrait = sharedTree.currentView.getTrait(testTree.left.traitLocation);
|
|
169
|
-
expect(leftTrait.length).equals(2);
|
|
170
|
-
expect(leftTrait[0]).equals(newNode.identifier);
|
|
171
|
-
});
|
|
172
|
-
it('is not equal to a tree with different current views', () => {
|
|
173
|
-
const { sharedTree: sharedTree1 } = createSimpleTestTree();
|
|
174
|
-
const { tree: sharedTree2 } = setUpTestSharedTree();
|
|
175
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.false;
|
|
176
|
-
});
|
|
177
|
-
it('is not equal to a tree with the same current view but different edit logs', () => {
|
|
178
|
-
const { sharedTree: sharedTree1 } = createSimpleTestTree();
|
|
179
|
-
const { sharedTree: sharedTree2 } = createSimpleTestTree();
|
|
180
|
-
// The edits that create the initial tree have different identities.
|
|
181
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.false;
|
|
182
|
-
});
|
|
183
|
-
it('tolerates invalid inserts', () => {
|
|
184
|
-
const { sharedTree, testTree } = createSimpleTestTree({ allowInvalid: true });
|
|
185
|
-
const firstNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
186
|
-
const secondNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
187
|
-
sharedTree.applyEdit(...Change.insertTree(firstNode, StablePlace.after(testTree.left)));
|
|
188
|
-
sharedTree.applyEdit(Change.delete(StableRange.only(firstNode)));
|
|
189
|
-
// Trying to insert next to the deleted node should drop, confirm that it doesn't
|
|
190
|
-
// change the view
|
|
191
|
-
assertNoDelta(sharedTree, () => {
|
|
192
|
-
sharedTree.applyEdit(...Change.insertTree(secondNode, StablePlace.after(firstNode)));
|
|
193
|
-
});
|
|
194
|
-
const leftTrait = sharedTree.currentView.getTrait(testTree.left.traitLocation);
|
|
195
|
-
expect(leftTrait.length).to.equal(1);
|
|
196
|
-
});
|
|
197
|
-
it('tolerates invalid detaches', () => {
|
|
198
|
-
const { sharedTree, testTree } = createSimpleTestTree({ allowInvalid: true });
|
|
199
|
-
const firstNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
200
|
-
const secondNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
201
|
-
const thirdNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
202
|
-
sharedTree.applyEdit(...Change.insertTree([firstNode, secondNode, thirdNode], StablePlace.after(testTree.left)));
|
|
203
|
-
sharedTree.applyEdit(Change.delete(StableRange.only(secondNode)));
|
|
204
|
-
assertNoDelta(sharedTree, () => {
|
|
205
|
-
// Trying to delete from before firstNode to after secondNode should drop
|
|
206
|
-
sharedTree.applyEdit(Change.delete(StableRange.from(StablePlace.before(firstNode)).to(StablePlace.after(secondNode))));
|
|
207
|
-
// Trying to delete from after thirdNode to before firstNode should drop
|
|
208
|
-
sharedTree.applyEdit(Change.delete(StableRange.from(StablePlace.after(thirdNode)).to(StablePlace.before(firstNode))));
|
|
209
|
-
});
|
|
210
|
-
// Expect that firstNode did not get deleted
|
|
211
|
-
const leftTrait = sharedTree.currentView.getTrait(testTree.left.traitLocation);
|
|
212
|
-
expect(leftTrait.length).to.equal(3);
|
|
213
|
-
});
|
|
214
|
-
it('tolerates malformed inserts', () => {
|
|
215
|
-
const { sharedTree } = createSimpleTestTree({ allowMalformed: true });
|
|
216
|
-
assertNoDelta(sharedTree, () => {
|
|
217
|
-
sharedTree.applyEdit(Change.build([], 0));
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
it('correctly reports attribution ID', () => {
|
|
221
|
-
const attributionId = generateStableId();
|
|
222
|
-
const { tree } = setUpTestSharedTree({ attributionId });
|
|
223
|
-
expect(tree.attributionId).to.equal(writeFormat === WriteFormat.v0_0_2 ? nilUuid : attributionId);
|
|
224
|
-
});
|
|
225
|
-
it('correctly attributes node IDs', () => {
|
|
226
|
-
const attributionId = generateStableId();
|
|
227
|
-
const { tree } = setUpTestSharedTree({ attributionId });
|
|
228
|
-
const id = tree.generateNodeId();
|
|
229
|
-
expect(tree.attributeNodeId(id)).to.equal(writeFormat === WriteFormat.v0_0_2 ? nilUuid : attributionId);
|
|
230
|
-
});
|
|
231
|
-
runSharedTreeUndoRedoTestSuite({ localMode: true, ...undoRedoOptions });
|
|
232
|
-
});
|
|
233
|
-
describe('SharedTree in connected state with a remote SharedTree', () => {
|
|
234
|
-
/**
|
|
235
|
-
* Initial tree options for multi-tree tests below.
|
|
236
|
-
* Intended to be passed to {@link createSimpleTestTree}.
|
|
237
|
-
*/
|
|
238
|
-
const tree1Options = { localMode: false };
|
|
239
|
-
/**
|
|
240
|
-
* Secondary tree options derived from some initial tree.
|
|
241
|
-
*/
|
|
242
|
-
function createSecondTreeOptions(containerRuntimeFactory) {
|
|
243
|
-
return {
|
|
244
|
-
containerRuntimeFactory,
|
|
245
|
-
id: 'secondTestSharedTree',
|
|
246
|
-
localMode: false,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
if (writeFormat === WriteFormat.v0_0_2) {
|
|
250
|
-
it('applies unversioned ops in the 0.0.2 format', () => {
|
|
251
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree(tree1Options);
|
|
252
|
-
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
253
|
-
containerRuntimeFactory.processAllMessages();
|
|
254
|
-
const originalPushMessage = containerRuntimeFactory.pushMessage.bind(containerRuntimeFactory);
|
|
255
|
-
containerRuntimeFactory.pushMessage = (msg) => {
|
|
256
|
-
// Drop the version property to replicate ops created before the version property existed
|
|
257
|
-
msg.contents.version = undefined;
|
|
258
|
-
originalPushMessage(msg);
|
|
259
|
-
};
|
|
260
|
-
// Ensure that an edit can be passed and processed between two trees as normal
|
|
261
|
-
sharedTree2.applyEdit(Change.delete(StableRange.only(testTree2.right)));
|
|
262
|
-
const getTestTreeRoot = (sharedTree) => new TreeNodeHandle(sharedTree.currentView, sharedTree.convertToNodeId(sharedTree2.convertToStableNodeId(testTree2.identifier)));
|
|
263
|
-
let root1 = getTestTreeRoot(sharedTree1);
|
|
264
|
-
let root2 = getTestTreeRoot(sharedTree2);
|
|
265
|
-
expect(Array.from(root1.traits[testTree2.right.traitLabel])).to.have.length(1);
|
|
266
|
-
expect(Array.from(root2.traits[testTree2.right.traitLabel] ?? [])).to.have.length(0);
|
|
267
|
-
containerRuntimeFactory.processAllMessages();
|
|
268
|
-
root1 = getTestTreeRoot(sharedTree1);
|
|
269
|
-
root2 = getTestTreeRoot(sharedTree2);
|
|
270
|
-
expect(Array.from(root1.traits[testTree2.right.traitLabel] ?? [])).to.have.length(0);
|
|
271
|
-
expect(Array.from(root2.traits[testTree2.right.traitLabel] ?? [])).to.have.length(0);
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
it('should apply remote changes and converge', () => {
|
|
275
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree(tree1Options);
|
|
276
|
-
const { tree: sharedTree2 } = setUpTestSharedTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
277
|
-
const newNodeId1 = sharedTree1.generateNodeId();
|
|
278
|
-
sharedTree1.applyEdit(...Change.insertTree([buildLeaf(newNodeId1)], StablePlace.atStartOf(testTrait(sharedTree1.currentView))));
|
|
279
|
-
// Sync initial tree
|
|
280
|
-
containerRuntimeFactory.processAllMessages();
|
|
281
|
-
const newNodeId2 = translateId(newNodeId1, sharedTree1, sharedTree2);
|
|
282
|
-
// Both trees should contain 'left'
|
|
283
|
-
expect(sharedTree1.currentView.getViewNode(newNodeId1)).to.not.be.undefined;
|
|
284
|
-
expect(sharedTree2.currentView.getViewNode(newNodeId2)).to.not.be.undefined;
|
|
285
|
-
sharedTree2.applyEdit(Change.delete(StableRange.only(newNodeId2)));
|
|
286
|
-
containerRuntimeFactory.processAllMessages();
|
|
287
|
-
const rootA = sharedTree1.currentView.getViewNode(sharedTree1.currentView.root);
|
|
288
|
-
expect(rootA.traits.get(testTraitLabel)).to.be.undefined;
|
|
289
|
-
const rootB = sharedTree2.currentView.getViewNode(sharedTree2.currentView.root);
|
|
290
|
-
expect(rootB.traits.get(testTraitLabel)).to.be.undefined;
|
|
291
|
-
});
|
|
292
|
-
it('converges in the face of concurrent changes', () => {
|
|
293
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree(tree1Options);
|
|
294
|
-
const { sharedTree: sharedTree2 } = createSimpleTestTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
295
|
-
const newNodeId1 = sharedTree1.generateNodeId();
|
|
296
|
-
sharedTree1.applyEdit(...Change.insertTree([buildLeaf(newNodeId1)], StablePlace.atStartOf(testTrait(sharedTree1.currentView))));
|
|
297
|
-
containerRuntimeFactory.processAllMessages();
|
|
298
|
-
// First client deletes a trait containing a node in the initial tree
|
|
299
|
-
sharedTree1.applyEdit(Change.delete(StableRange.all(testTrait(sharedTree1.currentView))));
|
|
300
|
-
// Second client concurrently adds a new node to that trait
|
|
301
|
-
const newNodeId2 = sharedTree2.generateNodeId();
|
|
302
|
-
sharedTree2.applyEdit(...Change.insertTree([buildLeaf(newNodeId2)], StablePlace.atStartOf(testTrait(sharedTree2.currentView))));
|
|
303
|
-
containerRuntimeFactory.processAllMessages();
|
|
304
|
-
// Second client's change gets sequenced after the deletion, so the trait
|
|
305
|
-
// should exist and contain the second new node on both clients after messages are delivered.
|
|
306
|
-
const leftTrait = normalizeIds(sharedTree1, ...sharedTree1.currentView.getTrait(testTrait(sharedTree1.currentView)));
|
|
307
|
-
const secondLeftTrait = normalizeIds(sharedTree2, ...sharedTree2.currentView.getTrait(testTrait(sharedTree2.currentView)));
|
|
308
|
-
expect(leftTrait.length).equals(1);
|
|
309
|
-
expect(leftTrait[0]).equals(normalizeId(sharedTree2, newNodeId2));
|
|
310
|
-
expect(leftTrait).deep.equals(secondLeftTrait);
|
|
311
|
-
});
|
|
312
|
-
it('is equal to a tree with the same state', () => {
|
|
313
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree(tree1Options);
|
|
314
|
-
const { tree: sharedTree2 } = setUpTestSharedTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
315
|
-
const newNodeId1 = sharedTree1.generateNodeId();
|
|
316
|
-
sharedTree1.applyEdit(...Change.insertTree([
|
|
317
|
-
{
|
|
318
|
-
identifier: newNodeId1,
|
|
319
|
-
definition: 'foo',
|
|
320
|
-
traits: { left: buildLeaf(), right: buildLeaf() },
|
|
321
|
-
},
|
|
322
|
-
], StablePlace.atStartOf(testTrait(sharedTree1.currentView))));
|
|
323
|
-
containerRuntimeFactory.processAllMessages();
|
|
324
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.true;
|
|
325
|
-
sharedTree2.applyEdit(Change.delete(StableRange.only(translateId(newNodeId1, sharedTree1, sharedTree2))));
|
|
326
|
-
containerRuntimeFactory.processAllMessages();
|
|
327
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.true;
|
|
328
|
-
});
|
|
329
|
-
// TODO:#58052: Make this test pass.
|
|
330
|
-
it.skip('prevents inserting a node in a detached subtree as the result of merged edits', () => {
|
|
331
|
-
const { testTree } = createSimpleTestTree();
|
|
332
|
-
const rootNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
333
|
-
const parent1Node = testTree.buildLeaf(testTree.generateNodeId());
|
|
334
|
-
const parent2Node = testTree.buildLeaf(testTree.generateNodeId());
|
|
335
|
-
const parent2Id = parent2Node.identifier;
|
|
336
|
-
const childNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
337
|
-
const childId = childNode.identifier;
|
|
338
|
-
const initialTree = {
|
|
339
|
-
...rootNode,
|
|
340
|
-
traits: {
|
|
341
|
-
parents: [
|
|
342
|
-
{
|
|
343
|
-
...parent1Node,
|
|
344
|
-
traits: { child: childNode },
|
|
345
|
-
},
|
|
346
|
-
parent2Node,
|
|
347
|
-
],
|
|
348
|
-
},
|
|
349
|
-
};
|
|
350
|
-
const childTraitUnderParent2 = { parent: parent2Id, label: 'child' };
|
|
351
|
-
const badTraitUnderChild = { parent: childId, label: 'whatever' };
|
|
352
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree({
|
|
353
|
-
...tree1Options,
|
|
354
|
-
initialTree,
|
|
355
|
-
allowInvalid: true,
|
|
356
|
-
});
|
|
357
|
-
const { tree: sharedTree2 } = setUpTestSharedTree({
|
|
358
|
-
...createSecondTreeOptions(containerRuntimeFactory),
|
|
359
|
-
allowInvalid: true,
|
|
360
|
-
});
|
|
361
|
-
containerRuntimeFactory.processAllMessages();
|
|
362
|
-
// Move the child under parent2
|
|
363
|
-
// This first edit should succeed locally and globally
|
|
364
|
-
const edit1 = sharedTree1.applyEdit(...Change.move(StableRange.only(childId), StablePlace.atStartOf(childTraitUnderParent2)));
|
|
365
|
-
// Concurrently move parent2 under child
|
|
366
|
-
// This first edit should succeed locally but fail globally
|
|
367
|
-
const edit2 = sharedTree2.applyEdit(...Change.move(StableRange.only(parent2Id), StablePlace.atStartOf(badTraitUnderChild)));
|
|
368
|
-
containerRuntimeFactory.processAllMessages();
|
|
369
|
-
const logViewer = sharedTree1.logViewer;
|
|
370
|
-
expect(logViewer.getEditResultInMemory(logViewer.log.getIndexOfId(edit1.id)).status).equals(EditStatus.Applied);
|
|
371
|
-
expect(logViewer.getEditResultInMemory(logViewer.log.getIndexOfId(edit2.id)).status).equals(EditStatus.Invalid);
|
|
372
|
-
sharedTree1.currentView.assertConsistent();
|
|
373
|
-
});
|
|
374
|
-
it('tolerates invalid inserts', () => {
|
|
375
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree({
|
|
376
|
-
...tree1Options,
|
|
377
|
-
allowInvalid: true,
|
|
378
|
-
});
|
|
379
|
-
const { tree: sharedTree2 } = setUpTestSharedTree({
|
|
380
|
-
...createSecondTreeOptions(containerRuntimeFactory),
|
|
381
|
-
allowInvalid: true,
|
|
382
|
-
});
|
|
383
|
-
containerRuntimeFactory.processAllMessages();
|
|
384
|
-
const firstNode2 = buildLeaf(sharedTree2.generateNodeId());
|
|
385
|
-
const firstEdit = sharedTree2.applyEdit(...Change.insertTree(firstNode2, StablePlace.atStartOf(testTrait(sharedTree2.currentView))));
|
|
386
|
-
containerRuntimeFactory.processAllMessages();
|
|
387
|
-
// Concurrently edit, creating invalid insert.
|
|
388
|
-
// Create delete. This will apply.
|
|
389
|
-
const secondEdit = sharedTree1.applyEdit(Change.delete(StableRange.only(translateId(firstNode2, sharedTree2, sharedTree1))));
|
|
390
|
-
let thirdEdit;
|
|
391
|
-
assertNoDelta(sharedTree1, () => {
|
|
392
|
-
// concurrently insert next to the deleted node: this will become invalid.
|
|
393
|
-
const secondNode2 = buildLeaf();
|
|
394
|
-
thirdEdit = sharedTree2.applyEdit(...Change.insertTree(secondNode2, StablePlace.after(firstNode2)));
|
|
395
|
-
containerRuntimeFactory.processAllMessages();
|
|
396
|
-
});
|
|
397
|
-
const leftTrait = sharedTree2.currentView.getTrait(testTrait(sharedTree2.currentView));
|
|
398
|
-
expect(leftTrait.length).to.equal(0);
|
|
399
|
-
const editIds = sharedTree1.edits.editIds;
|
|
400
|
-
expect(editIds[0]).is.equal(firstEdit.id);
|
|
401
|
-
expect(editIds[1]).is.equal(secondEdit.id);
|
|
402
|
-
expect(editIds[2]).is.equal(thirdEdit.id);
|
|
403
|
-
});
|
|
404
|
-
it('tolerates invalid detaches', () => {
|
|
405
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree({
|
|
406
|
-
...tree1Options,
|
|
407
|
-
allowInvalid: true,
|
|
408
|
-
});
|
|
409
|
-
const { tree: sharedTree2 } = setUpTestSharedTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
410
|
-
containerRuntimeFactory.processAllMessages();
|
|
411
|
-
const firstNode2 = buildLeaf(sharedTree2.generateNodeId());
|
|
412
|
-
const secondNode2 = buildLeaf(sharedTree2.generateNodeId());
|
|
413
|
-
const thirdNode = buildLeaf();
|
|
414
|
-
const firstEdit = sharedTree2.applyEdit(...Change.insertTree([firstNode2, secondNode2, thirdNode], StablePlace.atStartOf(testTrait(sharedTree2.currentView))));
|
|
415
|
-
containerRuntimeFactory.processAllMessages();
|
|
416
|
-
// Create delete. This will apply.
|
|
417
|
-
const secondEdit = sharedTree1.applyEdit(Change.delete(StableRange.only(translateId(secondNode2, sharedTree2, sharedTree1))));
|
|
418
|
-
// concurrently delete from before firstNode to after secondNode: this should become invalid
|
|
419
|
-
const thirdEdit = sharedTree2.applyEdit(Change.delete(StableRange.from(StablePlace.before(firstNode2)).to(StablePlace.after(secondNode2))));
|
|
420
|
-
containerRuntimeFactory.processAllMessages();
|
|
421
|
-
// Expect that firstNode did not get deleted
|
|
422
|
-
const leftTrait = sharedTree1.currentView.getTrait(testTrait(sharedTree1.currentView));
|
|
423
|
-
expect(leftTrait.length).to.equal(2);
|
|
424
|
-
const editIds = sharedTree1.edits.editIds;
|
|
425
|
-
expect(editIds[0]).to.equal(firstEdit.id);
|
|
426
|
-
expect(editIds[1]).to.equal(secondEdit.id);
|
|
427
|
-
expect(editIds[2]).to.equal(thirdEdit.id);
|
|
428
|
-
});
|
|
429
|
-
it('tolerates malformed inserts', () => {
|
|
430
|
-
const { sharedTree: sharedTree1, containerRuntimeFactory } = createSimpleTestTree({
|
|
431
|
-
...tree1Options,
|
|
432
|
-
allowMalformed: true,
|
|
433
|
-
});
|
|
434
|
-
const { tree: sharedTree2 } = setUpTestSharedTree(createSecondTreeOptions(containerRuntimeFactory));
|
|
435
|
-
containerRuntimeFactory.processAllMessages();
|
|
436
|
-
let editId;
|
|
437
|
-
assertNoDelta(sharedTree1, () => {
|
|
438
|
-
const build = Change.build([], 0);
|
|
439
|
-
editId = sharedTree2.applyEdit(build).id;
|
|
440
|
-
containerRuntimeFactory.processAllMessages();
|
|
441
|
-
});
|
|
442
|
-
// Edit 0 creates initial tree
|
|
443
|
-
expect(sharedTree1.edits.getIdAtIndex(1)).to.equal(editId);
|
|
444
|
-
});
|
|
445
|
-
runSharedTreeUndoRedoTestSuite({ localMode: false, ...undoRedoOptions });
|
|
446
|
-
// This is a regression test for documents corrupted by the following github issue:
|
|
447
|
-
// https://github.com/microsoft/FluidFramework/issues/4399
|
|
448
|
-
it('tolerates duplicate edits in trailing operations', () => {
|
|
449
|
-
const { sharedTree: sharedTree1, containerRuntimeFactory } = createSimpleTestTree(tree1Options);
|
|
450
|
-
const remoteRuntime = containerRuntimeFactory.createContainerRuntime(new MockFluidDataStoreRuntime());
|
|
451
|
-
const ops = spyOnSubmittedOps(containerRuntimeFactory);
|
|
452
|
-
const initialEditCount = sharedTree1.edits.length;
|
|
453
|
-
sharedTree1.applyEdit(Change.setPayload(sharedTree1.currentView.root, 42));
|
|
454
|
-
remoteRuntime.submit(ops[0], /* localOpMetadata */ undefined);
|
|
455
|
-
containerRuntimeFactory.processAllMessages();
|
|
456
|
-
expect(sharedTree1.edits.length).to.equal(initialEditCount + 1);
|
|
457
|
-
});
|
|
458
|
-
it('detects concurrent duplicate IDs', () => {
|
|
459
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree({
|
|
460
|
-
...tree1Options,
|
|
461
|
-
allowInvalid: true,
|
|
462
|
-
});
|
|
463
|
-
const { tree: sharedTree2 } = setUpTestSharedTree({
|
|
464
|
-
...createSecondTreeOptions(containerRuntimeFactory),
|
|
465
|
-
allowInvalid: true,
|
|
466
|
-
});
|
|
467
|
-
containerRuntimeFactory.processAllMessages();
|
|
468
|
-
const duplicateId = 'duplicate';
|
|
469
|
-
sharedTree1.applyEdit(...Change.insertTree([buildLeaf(sharedTree1.generateNodeId(duplicateId))], StablePlace.atEndOf(testTrait(sharedTree1.currentView))));
|
|
470
|
-
sharedTree2.applyEdit(...Change.insertTree([buildLeaf(sharedTree2.generateNodeId(duplicateId))], StablePlace.atEndOf(testTrait(sharedTree2.currentView))));
|
|
471
|
-
containerRuntimeFactory.processAllMessages();
|
|
472
|
-
expect(sharedTree1.currentView.size).to.equal(2);
|
|
473
|
-
const trait1 = sharedTree1.currentView.getTrait(testTrait(sharedTree1.currentView));
|
|
474
|
-
expect(trait1.length).to.equal(1);
|
|
475
|
-
expect(sharedTree1.convertToStableNodeId(trait1[0])).to.equal(duplicateId);
|
|
476
|
-
expect(sharedTree1.equals(sharedTree2));
|
|
477
|
-
});
|
|
478
|
-
if (writeFormat !== WriteFormat.v0_0_2) {
|
|
479
|
-
it('can exchange attribution IDs', () => {
|
|
480
|
-
const attributionId1 = generateStableId();
|
|
481
|
-
const { tree: sharedTree1, containerRuntimeFactory } = setUpTestSharedTree({
|
|
482
|
-
...tree1Options,
|
|
483
|
-
attributionId: attributionId1,
|
|
484
|
-
});
|
|
485
|
-
const attributionId2 = generateStableId();
|
|
486
|
-
const { tree: sharedTree2 } = setUpTestSharedTree({
|
|
487
|
-
...createSecondTreeOptions(containerRuntimeFactory),
|
|
488
|
-
attributionId: attributionId2,
|
|
489
|
-
});
|
|
490
|
-
containerRuntimeFactory.processAllMessages();
|
|
491
|
-
const nodeId1 = sharedTree1.generateNodeId();
|
|
492
|
-
const stableNodeId1 = sharedTree1.convertToStableNodeId(nodeId1);
|
|
493
|
-
sharedTree1.applyEdit(...Change.insertTree([buildLeaf(nodeId1)], StablePlace.atEndOf(testTrait(sharedTree1.currentView))));
|
|
494
|
-
containerRuntimeFactory.processAllMessages();
|
|
495
|
-
expect(sharedTree2.attributeNodeId(sharedTree2.convertToNodeId(stableNodeId1))).to.equal(attributionId1);
|
|
496
|
-
const nodeId2 = sharedTree2.generateNodeId();
|
|
497
|
-
const stableNodeId2 = sharedTree2.convertToStableNodeId(nodeId1);
|
|
498
|
-
sharedTree2.applyEdit(...Change.insertTree([buildLeaf(nodeId2)], StablePlace.atEndOf(testTrait(sharedTree2.currentView))));
|
|
499
|
-
containerRuntimeFactory.processAllMessages();
|
|
500
|
-
expect(sharedTree1.attributeNodeId(sharedTree1.convertToNodeId(stableNodeId2))).to.equal(attributionId2);
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
describe('SharedTree summarizing', () => {
|
|
505
|
-
const testHandle = new TestFluidHandle();
|
|
506
|
-
it('throws error when given bad json input', () => {
|
|
507
|
-
assert.throws(() => deserialize('', testSerializer));
|
|
508
|
-
assert.throws(() => deserialize('~ malformed JSON ~', testSerializer));
|
|
509
|
-
assert.throws(() => deserialize('{ unrecognizedKey: 42 }', testSerializer));
|
|
510
|
-
});
|
|
511
|
-
it('correctly handles snapshots of default trees', () => {
|
|
512
|
-
const { tree: uninitializedTree } = setUpTestSharedTree();
|
|
513
|
-
// Serialize the state of one uninitialized tree into a second tree
|
|
514
|
-
const serialized = serialize(uninitializedTree.saveSummary(), testSerializer, testHandle);
|
|
515
|
-
const parsedTree = deserialize(serialized, testSerializer);
|
|
516
|
-
if (writeFormat === WriteFormat.v0_0_2) {
|
|
517
|
-
const summary = parsedTree;
|
|
518
|
-
expect(summary.sequencedEdits).to.deep.equal([]);
|
|
519
|
-
expect(deepCompareNodes(summary.currentTree, initialTree)).to.be.true;
|
|
520
|
-
}
|
|
521
|
-
else {
|
|
522
|
-
const summary = parsedTree;
|
|
523
|
-
expect(summary.editHistory).to.deep.equal({ editChunks: [], editIds: [] });
|
|
524
|
-
expect(summary.currentTree).to.be.instanceOf(Array);
|
|
525
|
-
expect(summary.internedStrings).to.have.length(1);
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
[true, false].forEach((hasLocalEdits) => {
|
|
529
|
-
it(`produces correct snapshot for a tree with ${hasLocalEdits ? 'local' : 'acked'} edits`, async () => {
|
|
530
|
-
// The initial tree results in an edit.
|
|
531
|
-
const { sharedTree, testTree, containerRuntimeFactory } = createSimpleTestTree({
|
|
532
|
-
localMode: hasLocalEdits,
|
|
533
|
-
});
|
|
534
|
-
const newNode = testTree.buildLeaf();
|
|
535
|
-
sharedTree.applyEdit(...Change.insertTree(newNode, StablePlace.before(testTree.left)));
|
|
536
|
-
let serialized;
|
|
537
|
-
if (hasLocalEdits) {
|
|
538
|
-
const { summary } = sharedTree.getAttachSummary();
|
|
539
|
-
assert.equal(summary.type, SummaryType.Tree, 'Summary type should be Tree');
|
|
540
|
-
assert.equal(summary.tree.header.type, SummaryType.Blob, 'Summary should contain header blob');
|
|
541
|
-
serialized = summary.tree.header.content;
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
544
|
-
containerRuntimeFactory.processAllMessages();
|
|
545
|
-
serialized = serialize(sharedTree.saveSummary(), testSerializer, testHandle);
|
|
546
|
-
}
|
|
547
|
-
const treeContent = JSON.parse(serialized);
|
|
548
|
-
const parsedTree = writeFormat === WriteFormat.v0_1_1
|
|
549
|
-
? new SharedTreeEncoder_0_1_1(true).decodeSummary(treeContent, sharedTree.attributionId)
|
|
550
|
-
: new SharedTreeEncoder_0_0_2(true).decodeSummary(treeContent);
|
|
551
|
-
expect(parsedTree.currentTree).to.not.be.undefined;
|
|
552
|
-
const testRoot = assertArrayOfOne(assertNotUndefined(parsedTree.currentTree?.traits[testTree.traitLabel]));
|
|
553
|
-
expect(testRoot).to.not.be.undefined;
|
|
554
|
-
expect(testRoot.traits.left).to.not.be.undefined;
|
|
555
|
-
expect(testRoot.traits.right).to.not.be.undefined;
|
|
556
|
-
expect(testRoot.traits.left.length).to.equal(2);
|
|
557
|
-
const editLog = new EditLog(parsedTree.editHistory);
|
|
558
|
-
// Expect there to be a change in the edit history in addition to the one from setUpTestSharedTree
|
|
559
|
-
expect(editLog.length).to.equal(2);
|
|
560
|
-
// The first operation to be sequenced is the tree init
|
|
561
|
-
const treeInitEdit = editLog.tryGetEditAtIndex(1) ?? fail('edit not found');
|
|
562
|
-
expect(treeInitEdit.changes.length).to.equal(2);
|
|
563
|
-
expect(treeInitEdit.changes[0].type).to.equal(ChangeType.Build);
|
|
564
|
-
expect(treeInitEdit.changes[1].type).to.equal(ChangeType.Insert);
|
|
565
|
-
});
|
|
566
|
-
});
|
|
567
|
-
it('can be used to initialize a tree', () => {
|
|
568
|
-
const { sharedTree: sharedTree1, testTree: testTree1, containerRuntimeFactory, } = createSimpleTestTree({ localMode: false });
|
|
569
|
-
const { tree: sharedTree2 } = setUpTestSharedTree();
|
|
570
|
-
const newNode = testTree1.buildLeaf();
|
|
571
|
-
sharedTree1.applyEdit(...Change.insertTree(newNode, StablePlace.before(testTree1.left)));
|
|
572
|
-
containerRuntimeFactory.processAllMessages();
|
|
573
|
-
sharedTree2.loadSummary(sharedTree1.saveSummary());
|
|
574
|
-
// Trees should have equal state since we deserialized the first tree's state into the second tree
|
|
575
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.true;
|
|
576
|
-
});
|
|
577
|
-
it('can be used to initialize a tree with an empty edit list', () => {
|
|
578
|
-
const { sharedTree: sharedTree1, containerRuntimeFactory } = createSimpleTestTree({ localMode: false });
|
|
579
|
-
const { tree: sharedTree2 } = setUpTestSharedTree();
|
|
580
|
-
containerRuntimeFactory.processAllMessages();
|
|
581
|
-
// The second tree is not caught up to the first tree yet
|
|
582
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.false;
|
|
583
|
-
sharedTree2.loadSummary(sharedTree1.saveSummary());
|
|
584
|
-
// Trees should have equal state since we deserialized the first tree's state into the second tree
|
|
585
|
-
expect(sharedTree1.equals(sharedTree2)).to.be.true;
|
|
586
|
-
});
|
|
587
|
-
it('asserts when loading a summary with duplicated edits', () => {
|
|
588
|
-
const { sharedTree: sharedTree1, testTree: testTree1, containerRuntimeFactory, } = createSimpleTestTree({
|
|
589
|
-
localMode: false,
|
|
590
|
-
summarizeHistory: true,
|
|
591
|
-
writeFormat: WriteFormat.v0_0_2,
|
|
592
|
-
});
|
|
593
|
-
const { tree: sharedTree2 } = setUpTestSharedTree();
|
|
594
|
-
const newNode = testTree1.buildLeaf();
|
|
595
|
-
sharedTree1.applyEdit(...Change.insertTree(newNode, StablePlace.before(testTree1.left)));
|
|
596
|
-
containerRuntimeFactory.processAllMessages();
|
|
597
|
-
const summary = sharedTree1.saveSummary();
|
|
598
|
-
const sequencedEdits = assertNotUndefined(summary.sequencedEdits).slice();
|
|
599
|
-
sequencedEdits.push(sequencedEdits[0]);
|
|
600
|
-
const corruptedSummary = {
|
|
601
|
-
...summary,
|
|
602
|
-
sequencedEdits,
|
|
603
|
-
};
|
|
604
|
-
assert.throws(() => sharedTree2.loadSummary(corruptedSummary), (e) => validateAssertionError(e, /Duplicate/));
|
|
605
|
-
});
|
|
606
|
-
it('can be used without history preservation', async () => {
|
|
607
|
-
const { sharedTree, testTree } = createSimpleTestTree({
|
|
608
|
-
localMode: true,
|
|
609
|
-
summarizeHistory: false,
|
|
610
|
-
});
|
|
611
|
-
const newNode = testTree.buildLeaf();
|
|
612
|
-
const { id } = sharedTree.applyEdit(...Change.insertTree(newNode, StablePlace.before(testTree.left)));
|
|
613
|
-
const treeBefore = convertTreeNodes(getChangeNodeFromView(sharedTree.currentView), (node) => convertNodeDataIds(node, (id) => sharedTree.convertToStableNodeId(id)));
|
|
614
|
-
const { summary } = sharedTree.getAttachSummary();
|
|
615
|
-
assert.equal(summary.type, SummaryType.Tree, 'Summary type should be Tree');
|
|
616
|
-
assert.equal(summary.tree.header.type, SummaryType.Blob, 'Summary should contain header blob');
|
|
617
|
-
const treeContent = JSON.parse(summary.tree.header.content);
|
|
618
|
-
const { tree: sharedTree2 } = setUpTestSharedTree();
|
|
619
|
-
sharedTree2.loadSummary(treeContent);
|
|
620
|
-
const treeAfter = convertTreeNodes(getChangeNodeFromView(sharedTree2.currentView), (node) => convertNodeDataIds(node, (id) => sharedTree2.convertToStableNodeId(id)));
|
|
621
|
-
// The current state of the tree should be identical to the one contained in the old summary.
|
|
622
|
-
expect(deepCompareNodes(treeBefore, treeAfter)).to.be.true;
|
|
623
|
-
// The history should have been dropped by the default handling behavior.
|
|
624
|
-
// It will contain a single entry setting the tree to equal the head revision.
|
|
625
|
-
expect(sharedTree2.edits.length).to.equal(1);
|
|
626
|
-
expect(sharedTree2.edits.tryGetEditFromId(id)).to.be.undefined;
|
|
627
|
-
});
|
|
628
|
-
it('correctly handles payloads at the root', () => {
|
|
629
|
-
const payload = 'foo';
|
|
630
|
-
const { tree, containerRuntimeFactory } = setUpTestSharedTree({ summarizeHistory: false });
|
|
631
|
-
tree.applyEdit(Change.setPayload(tree.currentView.root, payload));
|
|
632
|
-
containerRuntimeFactory.processAllMessages();
|
|
633
|
-
const summary = tree.saveSummary();
|
|
634
|
-
const { tree: tree2 } = setUpTestSharedTree({ summarizeHistory: false });
|
|
635
|
-
tree2.loadSummary(summary);
|
|
636
|
-
expect(tree2.currentView.tryGetViewNode(tree2.currentView.root)?.payload).to.equal(payload);
|
|
637
|
-
});
|
|
638
|
-
});
|
|
639
|
-
describe('handles', () => {
|
|
640
|
-
it('can reference a node', () => {
|
|
641
|
-
// Test that a handle can wrap a node and retrieve that node's properties
|
|
642
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
643
|
-
const leftHandle = new TreeNodeHandle(sharedTree.currentView, testTree.left.identifier);
|
|
644
|
-
expect(areNodesEquivalent(testTree.left, leftHandle)).to.be.true;
|
|
645
|
-
expect(areNodesEquivalent(testTree.right, leftHandle)).to.be.false;
|
|
646
|
-
});
|
|
647
|
-
it('can create handles from children', () => {
|
|
648
|
-
// Test that when retrieving children via the "traits" property of a handle, the
|
|
649
|
-
// children are also wrapped in handles
|
|
650
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
651
|
-
const rootHandle = new TreeNodeHandle(sharedTree.currentView, testTree.identifier);
|
|
652
|
-
expect(areNodesEquivalent(testTree, rootHandle)).to.be.true;
|
|
653
|
-
const leftHandle = rootHandle.traits.left[0];
|
|
654
|
-
expect(areNodesEquivalent(testTree.left, leftHandle)).to.be.true;
|
|
655
|
-
expect(leftHandle instanceof TreeNodeHandle).to.be.true;
|
|
656
|
-
});
|
|
657
|
-
it('do not update when the current view of the tree changes', () => {
|
|
658
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
659
|
-
const leftHandle = new TreeNodeHandle(sharedTree.currentView, testTree.left.identifier);
|
|
660
|
-
expect(leftHandle.traits.right).to.be.undefined;
|
|
661
|
-
// Move "right" under "left"
|
|
662
|
-
sharedTree.applyEdit(...Change.move(StableRange.only(testTree.right), StablePlace.atStartOf({ parent: testTree.left.identifier, label: testTree.right.traitLabel })));
|
|
663
|
-
expect(leftHandle.traits.right).to.be.undefined;
|
|
664
|
-
});
|
|
665
|
-
});
|
|
666
|
-
describe('telemetry', () => {
|
|
667
|
-
class LoggerThatOnlySeesSharedTreeEvents {
|
|
668
|
-
constructor(additionalFilter = (e) => true) {
|
|
669
|
-
this.additionalFilter = additionalFilter;
|
|
670
|
-
this.events = [];
|
|
671
|
-
}
|
|
672
|
-
send(event) {
|
|
673
|
-
if (isSharedTreeEvent(event) && this.additionalFilter(event)) {
|
|
674
|
-
this.events.push(event);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
describe('useFailedSequencedEditTelemetry', () => {
|
|
679
|
-
it('decorates events with the correct properties', async () => {
|
|
680
|
-
// Test that a handle can wrap a node and retrieve that node's properties
|
|
681
|
-
const logger = new LoggerThatOnlySeesSharedTreeEvents();
|
|
682
|
-
const { sharedTree, testTree, containerRuntimeFactory } = createSimpleTestTree({
|
|
683
|
-
logger,
|
|
684
|
-
allowInvalid: true,
|
|
685
|
-
});
|
|
686
|
-
useFailedSequencedEditTelemetry(sharedTree);
|
|
687
|
-
// Invalid edit
|
|
688
|
-
sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
689
|
-
containerRuntimeFactory.processAllMessages();
|
|
690
|
-
// Force demand, which will cause a telemetry event for the invalid edit to be emitted
|
|
691
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
692
|
-
expect(logger.events.length).is.greaterThan(0);
|
|
693
|
-
logger.events.forEach((event) => {
|
|
694
|
-
expect(isSharedTreeEvent(event)).is.true;
|
|
695
|
-
});
|
|
696
|
-
});
|
|
697
|
-
it('is logged for invalid locally generated edits when those edits are sequenced', async () => {
|
|
698
|
-
const logger = new LoggerThatOnlySeesSharedTreeEvents((event) => !event.eventName.includes('IdCompressor'));
|
|
699
|
-
const { sharedTree, testTree, containerRuntimeFactory } = createSimpleTestTree({
|
|
700
|
-
logger,
|
|
701
|
-
allowInvalid: true,
|
|
702
|
-
});
|
|
703
|
-
useFailedSequencedEditTelemetry(sharedTree);
|
|
704
|
-
// Invalid edit
|
|
705
|
-
sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
706
|
-
expect(logger.events.length).equals(0);
|
|
707
|
-
containerRuntimeFactory.processAllMessages();
|
|
708
|
-
// Force demand, which will cause a telemetry event for the invalid edit to be emitted
|
|
709
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
710
|
-
expect(logger.events.length).equals(1);
|
|
711
|
-
expect(logger.events[0].category).equals('generic');
|
|
712
|
-
expect(logger.events[0].eventName).equals('SharedTree:SequencedEditApplied:InvalidSharedTreeEdit');
|
|
713
|
-
});
|
|
714
|
-
it('can be disabled and re-enabled', async () => {
|
|
715
|
-
const logger = new LoggerThatOnlySeesSharedTreeEvents((event) => !event.eventName.includes('IdCompressor'));
|
|
716
|
-
const { sharedTree, testTree, containerRuntimeFactory } = createSimpleTestTree({
|
|
717
|
-
logger,
|
|
718
|
-
allowInvalid: true,
|
|
719
|
-
});
|
|
720
|
-
const { disable } = useFailedSequencedEditTelemetry(sharedTree);
|
|
721
|
-
sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
722
|
-
expect(logger.events.length).equals(0);
|
|
723
|
-
containerRuntimeFactory.processAllMessages();
|
|
724
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
725
|
-
expect(logger.events.length).equals(1);
|
|
726
|
-
expect(logger.events[0].eventName).equals('SharedTree:SequencedEditApplied:InvalidSharedTreeEdit');
|
|
727
|
-
disable();
|
|
728
|
-
sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
729
|
-
containerRuntimeFactory.processAllMessages();
|
|
730
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
731
|
-
expect(logger.events.length).equals(1);
|
|
732
|
-
useFailedSequencedEditTelemetry(sharedTree);
|
|
733
|
-
sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
734
|
-
containerRuntimeFactory.processAllMessages();
|
|
735
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
736
|
-
expect(logger.events.length).equals(2);
|
|
737
|
-
expect(logger.events[1].eventName).equals('SharedTree:SequencedEditApplied:InvalidSharedTreeEdit');
|
|
738
|
-
});
|
|
739
|
-
it('is not logged for valid edits', async () => {
|
|
740
|
-
const logger = new LoggerThatOnlySeesSharedTreeEvents((event) => !event.eventName.includes('IdCompressor'));
|
|
741
|
-
const { sharedTree, testTree, containerRuntimeFactory } = createSimpleTestTree({ logger });
|
|
742
|
-
useFailedSequencedEditTelemetry(sharedTree);
|
|
743
|
-
sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
|
744
|
-
containerRuntimeFactory.processAllMessages();
|
|
745
|
-
sharedTree.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
746
|
-
expect(logger.events.length).equals(0);
|
|
747
|
-
});
|
|
748
|
-
it('is not logged for remote edits', async () => {
|
|
749
|
-
const logger = new LoggerThatOnlySeesSharedTreeEvents((event) => !event.eventName.includes('IdCompressor'));
|
|
750
|
-
const { sharedTree: sharedTree1, containerRuntimeFactory } = createSimpleTestTree({
|
|
751
|
-
logger,
|
|
752
|
-
allowInvalid: true,
|
|
753
|
-
localMode: false,
|
|
754
|
-
});
|
|
755
|
-
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree({
|
|
756
|
-
containerRuntimeFactory,
|
|
757
|
-
id: 'secondTestSharedTree',
|
|
758
|
-
localMode: false,
|
|
759
|
-
});
|
|
760
|
-
useFailedSequencedEditTelemetry(sharedTree1);
|
|
761
|
-
sharedTree2.applyEdit(...Change.insertTree([testTree2.buildLeaf()], StablePlace.after(testTree2.buildLeaf(testTree2.generateNodeId()))));
|
|
762
|
-
containerRuntimeFactory.processAllMessages();
|
|
763
|
-
sharedTree1.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
764
|
-
expect(logger.events.length).equals(0);
|
|
765
|
-
});
|
|
766
|
-
});
|
|
767
|
-
});
|
|
768
|
-
describe('Events', () => {
|
|
769
|
-
it('fires an event when an edit is committed', () => {
|
|
770
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
771
|
-
let eventCount = 0;
|
|
772
|
-
let editIdFromEvent;
|
|
773
|
-
sharedTree.on(SharedTreeEvent.EditCommitted, (args) => {
|
|
774
|
-
expect(args.local).true;
|
|
775
|
-
expect(args.tree).equals(sharedTree);
|
|
776
|
-
editIdFromEvent = args.editId;
|
|
777
|
-
eventCount += 1;
|
|
778
|
-
});
|
|
779
|
-
// Invalid change
|
|
780
|
-
const invalidEdit = sharedTree.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.buildLeaf(testTree.generateNodeId()))));
|
|
781
|
-
expect(editIdFromEvent).equals(invalidEdit.id);
|
|
782
|
-
expect(eventCount).equals(1);
|
|
783
|
-
// Valid change
|
|
784
|
-
const { id } = sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
|
785
|
-
expect(editIdFromEvent).equals(id);
|
|
786
|
-
expect(eventCount).equals(2);
|
|
787
|
-
});
|
|
788
|
-
it('fires an event when a sequenced edit is applied', async () => {
|
|
789
|
-
const { sharedTree: sharedTree1, testTree, containerRuntimeFactory, } = createSimpleTestTree({
|
|
790
|
-
allowInvalid: true,
|
|
791
|
-
localMode: false,
|
|
792
|
-
});
|
|
793
|
-
const { tree: sharedTree2 } = setUpTestSharedTree({
|
|
794
|
-
containerRuntimeFactory,
|
|
795
|
-
id: 'secondTestSharedTree',
|
|
796
|
-
localMode: false,
|
|
797
|
-
});
|
|
798
|
-
containerRuntimeFactory.processAllMessages();
|
|
799
|
-
sharedTree1.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
800
|
-
const eventArgs = [];
|
|
801
|
-
sharedTree1.on(SharedTreeEvent.SequencedEditApplied, (args) => eventArgs.push(args));
|
|
802
|
-
// Invalid change
|
|
803
|
-
const change = Change.setPayload(testTree.generateNodeId(), 42);
|
|
804
|
-
const invalidEdit = sharedTree1.applyEdit(change);
|
|
805
|
-
containerRuntimeFactory.processAllMessages();
|
|
806
|
-
sharedTree1.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
807
|
-
expect(eventArgs.length).equals(1);
|
|
808
|
-
expect(eventArgs[0].edit.id).equals(invalidEdit.id);
|
|
809
|
-
expect(eventArgs[0].wasLocal).equals(true);
|
|
810
|
-
expect(eventArgs[0].reconciliationPath.length).equals(0);
|
|
811
|
-
expect(eventArgs[0].outcome.status).equals(EditStatus.Invalid);
|
|
812
|
-
// Valid change
|
|
813
|
-
const validEdit1 = sharedTree2.applyEdit(...Change.insertTree([testTree.buildLeaf()], StablePlace.after(testTree.left.translateId(sharedTree2))));
|
|
814
|
-
// Valid change
|
|
815
|
-
const validEdit2 = sharedTree1.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
|
816
|
-
containerRuntimeFactory.processAllMessages();
|
|
817
|
-
sharedTree1.logViewer.getRevisionViewInMemory(Number.POSITIVE_INFINITY);
|
|
818
|
-
expect(eventArgs.length).equals(3);
|
|
819
|
-
expect(eventArgs[1].edit.id).equals(validEdit1.id);
|
|
820
|
-
expect(eventArgs[1].wasLocal).equals(false);
|
|
821
|
-
expect(eventArgs[1].reconciliationPath.length).equals(0);
|
|
822
|
-
expect(eventArgs[1].outcome.status).equals(EditStatus.Applied);
|
|
823
|
-
expect(eventArgs[2].edit.id).equals(validEdit2.id);
|
|
824
|
-
expect(eventArgs[2].wasLocal).equals(true);
|
|
825
|
-
expect(eventArgs[2].reconciliationPath.length).equals(1);
|
|
826
|
-
expect(eventArgs[2].outcome.status).equals(EditStatus.Applied);
|
|
827
|
-
});
|
|
828
|
-
});
|
|
829
|
-
// This functionality was only implemented in format 0.1.1.
|
|
830
|
-
if (writeFormat !== WriteFormat.v0_0_2) {
|
|
831
|
-
describe('String interning and tree compression', () => {
|
|
832
|
-
function getMutableStringInterner(tree) {
|
|
833
|
-
const summary = tree.saveSummary();
|
|
834
|
-
switch (summary.version) {
|
|
835
|
-
case WriteFormat.v0_0_2:
|
|
836
|
-
return new MutableStringInterner();
|
|
837
|
-
case WriteFormat.v0_1_1:
|
|
838
|
-
return new MutableStringInterner(summary.internedStrings);
|
|
839
|
-
default:
|
|
840
|
-
fail(`Invalid summary format: ${summary.version}`);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
it('compress ops via interning and tree compression and decompress when processing edits', () => {
|
|
844
|
-
const { sharedTree: tree, testTree, containerRuntimeFactory, } = createSimpleTestTree({ writeFormat });
|
|
845
|
-
const { tree: secondTree } = setUpTestSharedTree({ containerRuntimeFactory, writeFormat });
|
|
846
|
-
const remoteRuntime = containerRuntimeFactory.createContainerRuntime(new MockFluidDataStoreRuntime());
|
|
847
|
-
const newNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
848
|
-
tree.applyEdit(...Change.insertTree(newNode, StablePlace.after(testTree.left)));
|
|
849
|
-
tree.applyEdit(...Change.move(StableRange.only(newNode), StablePlace.before(testTree.left)));
|
|
850
|
-
const factory = remoteRuntime.factory;
|
|
851
|
-
const messages = factory.messages;
|
|
852
|
-
expect(messages.length).to.equal(3);
|
|
853
|
-
for (const message of messages.slice(1)) {
|
|
854
|
-
// After the initial setup edit, common definitions should be interned
|
|
855
|
-
for (const change of message.contents.edit.changes) {
|
|
856
|
-
if (change.type === ChangeTypeInternal.CompressedBuild) {
|
|
857
|
-
const stringifiedContents = JSON.stringify(message.contents);
|
|
858
|
-
expect(stringifiedContents).to.not.include(SimpleTestTree.leftTraitLabel);
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
expect(tree.equals(secondTree)).to.be.false;
|
|
863
|
-
containerRuntimeFactory.processAllMessages();
|
|
864
|
-
const { internedStrings } = tree.saveSummary();
|
|
865
|
-
const log = getEditLogInternal(tree);
|
|
866
|
-
const log2 = getEditLogInternal(secondTree);
|
|
867
|
-
const insertEdit = normalizeEdit(tree, log.tryGetEditAtIndex(1) ?? fail('edit not found'));
|
|
868
|
-
const moveEdit = normalizeEdit(tree, log.tryGetEditAtIndex(2) ?? fail('edit not found'));
|
|
869
|
-
const insertEdit2 = normalizeEdit(secondTree, log2.tryGetEditAtIndex(1) ?? fail('edit not found'));
|
|
870
|
-
const moveEdit2 = normalizeEdit(secondTree, log2.tryGetEditAtIndex(2) ?? fail('edit not found'));
|
|
871
|
-
expect(insertEdit).to.deep.equal(insertEdit2);
|
|
872
|
-
expect(moveEdit).to.deep.equal(moveEdit2);
|
|
873
|
-
expect(tree.equals(secondTree)).to.be.true;
|
|
874
|
-
expect(internedStrings).to.include(SimpleTestTree.leftTraitLabel);
|
|
875
|
-
expect(internedStrings).to.include(newNode.definition);
|
|
876
|
-
});
|
|
877
|
-
it('compress summaries via interning and tree compression on save and decompress on load', () => {
|
|
878
|
-
const { sharedTree: tree, testTree: testTree, containerRuntimeFactory, } = createSimpleTestTree({ writeFormat });
|
|
879
|
-
const newNode = testTree.buildLeaf(testTree.generateNodeId());
|
|
880
|
-
tree.applyEdit(...Change.insertTree(newNode, StablePlace.after(testTree.left)));
|
|
881
|
-
tree.applyEdit(...Change.move(StableRange.only(newNode), StablePlace.before(testTree.left)));
|
|
882
|
-
containerRuntimeFactory.processAllMessages();
|
|
883
|
-
const summary = tree.saveSummary();
|
|
884
|
-
expect(summary.internedStrings).to.not.be.undefined;
|
|
885
|
-
expect(summary.internedStrings.length).to.equal(5);
|
|
886
|
-
const interner = new MutableStringInterner(summary.internedStrings);
|
|
887
|
-
const treeCompressor = new InterningTreeCompressor();
|
|
888
|
-
const expectedCompressedTree = treeCompressor.compress(getChangeNodeFromView(tree.currentView), interner, sequencedIdNormalizer(getIdNormalizerFromSharedTree(tree)));
|
|
889
|
-
expect(summary.currentTree).deep.equal(expectedCompressedTree);
|
|
890
|
-
const { tree: secondTree } = setUpTestSharedTree({ writeFormat });
|
|
891
|
-
expect(tree.equals(secondTree)).to.be.false;
|
|
892
|
-
secondTree.loadSummary(summary);
|
|
893
|
-
expect(tree.equals(secondTree)).to.be.true;
|
|
894
|
-
});
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
describe('mergeEditsFrom', () => {
|
|
898
|
-
const getTestTreeRootHandle = (tree, testTree) => {
|
|
899
|
-
const view = tree.currentView;
|
|
900
|
-
const handle = new TreeNodeHandle(view, view.root);
|
|
901
|
-
return handle.traits[testTree.traitLabel][0];
|
|
902
|
-
};
|
|
903
|
-
it('can be used with simple edits', () => {
|
|
904
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
905
|
-
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree();
|
|
906
|
-
sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
|
907
|
-
sharedTree.applyEdit(Change.delete(StableRange.all({ parent: testTree.identifier, label: testTree.right.traitLabel })));
|
|
908
|
-
const preEditRootHandle = getTestTreeRootHandle(sharedTree2, testTree2);
|
|
909
|
-
const edits = [0, 1, 2].map((i) => sharedTree.edits.tryGetEditAtIndex(i) ?? fail('edit not found'));
|
|
910
|
-
// Since the TestTree setup edit is a `setTrait`, this should wipe `testTree2` state.
|
|
911
|
-
sharedTree2.mergeEditsFrom(sharedTree, edits);
|
|
912
|
-
expect(sharedTree2.edits.length).to.equal(4);
|
|
913
|
-
const rootHandle = getTestTreeRootHandle(sharedTree2, testTree2);
|
|
914
|
-
expect(preEditRootHandle.identifier).to.not.equal(rootHandle.identifier);
|
|
915
|
-
expect(rootHandle.traits[testTree2.left.traitLabel].length).to.equal(2);
|
|
916
|
-
});
|
|
917
|
-
it('can be used with a translation map', () => {
|
|
918
|
-
const { sharedTree, testTree } = createSimpleTestTree();
|
|
919
|
-
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree();
|
|
920
|
-
// For each of the identities in the simple test tree...
|
|
921
|
-
const nodeIdGetters = [
|
|
922
|
-
(tree) => tree.identifier,
|
|
923
|
-
(tree) => tree.left.identifier,
|
|
924
|
-
(tree) => tree.right.identifier,
|
|
925
|
-
];
|
|
926
|
-
// Make a map translating that identifier from `testTree` to `testTree2`
|
|
927
|
-
const translationMap = new Map(nodeIdGetters.map((getter) => [
|
|
928
|
-
sharedTree.convertToStableNodeId(getter(testTree)),
|
|
929
|
-
sharedTree2.convertToStableNodeId(getter(testTree2)),
|
|
930
|
-
]));
|
|
931
|
-
sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
|
932
|
-
sharedTree.applyEdit(Change.delete(StableRange.all({ parent: testTree.identifier, label: testTree.right.traitLabel })));
|
|
933
|
-
const edits = [1, 2].map((i) => sharedTree.edits.tryGetEditAtIndex(i) ?? fail('edit not found'));
|
|
934
|
-
sharedTree2.mergeEditsFrom(sharedTree, edits, (id) => translationMap.get(id) ?? id);
|
|
935
|
-
const root = getTestTreeRootHandle(sharedTree, testTree);
|
|
936
|
-
const root2 = getTestTreeRootHandle(sharedTree2, testTree2);
|
|
937
|
-
const leftTrait = root.traits[testTree.left.traitLabel];
|
|
938
|
-
const leftTrait2 = root2.traits[testTree2.left.traitLabel];
|
|
939
|
-
// Inserted leaves should be equivalent.
|
|
940
|
-
expect(leftTrait2.length).to.equal(2);
|
|
941
|
-
expect(leftTrait2[1]).to.deep.equal(leftTrait[1]);
|
|
942
|
-
// Right subtree should have been deleted.
|
|
943
|
-
expect(Object.entries(root2.traits).length).to.equal(1);
|
|
944
|
-
expect(root2.traits[testTree2.right.traitLabel]).to.equal(undefined);
|
|
945
|
-
});
|
|
946
|
-
});
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
//# sourceMappingURL=SharedTreeTests.js.map
|