yjs/tests/y-array.tests.js

334 lines
8.9 KiB
JavaScript

import { init, compare, applyRandomTests } from './testHelper.js'
import * as Y from '../src/index.js'
import * as t from 'funlib/testing.js'
import * as prng from 'funlib/prng.js'
export const testDeleteInsert = tc => {
const { users, array0 } = init(tc, { users: 2 })
array0.delete(0, 0)
t.assert(true, 'Does not throw when deleting zero elements with position 0')
t.fails(() => {
array0.delete(1, 1)
}, 'Throws when deleting with an invalid position')
array0.insert(0, ['A'])
array0.delete(1, 0)
t.assert(true, 'Does not throw when deleting zero elements with valid position 1')
compare(users)
}
export const testInsertThreeElementsTryRegetProperty = tc => {
const { testConnector, users, array0, array1 } = init(tc, { users: 2 })
array0.insert(0, [1, 2, 3])
t.compare(array0.toJSON(), [1, 2, 3], '.toJSON() works')
testConnector.flushAllMessages()
t.compare(array1.toJSON(), [1, 2, 3], '.toJSON() works after sync')
compare(users)
}
export const testConcurrentInsertWithThreeConflicts = tc => {
var { users, array0, array1, array2 } = init(tc, { users: 3 })
array0.insert(0, [0])
array1.insert(0, [1])
array2.insert(0, [2])
compare(users)
}
export const testConcurrentInsertDeleteWithThreeConflicts = tc => {
const { testConnector, users, array0, array1, array2 } = init(tc, { users: 3 })
array0.insert(0, ['x', 'y', 'z'])
testConnector.flushAllMessages()
array0.insert(1, [0])
array1.delete(0)
array1.delete(1, 1)
array2.insert(1, [2])
compare(users)
}
export const testInsertionsInLateSync = tc => {
const { testConnector, users, array0, array1, array2 } = init(tc, { users: 3 })
array0.insert(0, ['x', 'y'])
testConnector.flushAllMessages()
users[1].disconnect()
users[2].disconnect()
array0.insert(1, ['user0'])
array1.insert(1, ['user1'])
array2.insert(1, ['user2'])
users[1].connect()
users[2].connect()
testConnector.flushAllMessages()
compare(users)
}
export const testDisconnectReallyPreventsSendingMessages = tc => {
var { testConnector, users, array0, array1 } = init(tc, { users: 3 })
array0.insert(0, ['x', 'y'])
testConnector.flushAllMessages()
users[1].disconnect()
users[2].disconnect()
array0.insert(1, ['user0'])
array1.insert(1, ['user1'])
t.compare(array0.toJSON(), ['x', 'user0', 'y'])
t.compare(array1.toJSON(), ['x', 'user1', 'y'])
users[1].connect()
users[2].connect()
compare(users)
}
export const testDeletionsInLateSync = tc => {
const { testConnector, users, array0, array1 } = init(tc, { users: 2 })
array0.insert(0, ['x', 'y'])
testConnector.flushAllMessages()
users[1].disconnect()
array1.delete(1, 1)
array0.delete(0, 2)
users[1].connect()
compare(users)
}
export const testInsertThenMergeDeleteOnSync = tc => {
const { testConnector, users, array0, array1 } = init(tc, { users: 2 })
array0.insert(0, ['x', 'y', 'z'])
testConnector.flushAllMessages()
users[0].disconnect()
array1.delete(0, 3)
users[0].connect()
compare(users)
}
const compareEvent = (is, should) => {
for (var key in should) {
t.assert(
should[key] === is[key] ||
JSON.stringify(should[key]) === JSON.stringify(is[key])
, 'event works as expected'
)
}
}
export const testInsertAndDeleteEvents = tc => {
const { array0, users } = init(tc, { users: 2 })
let event
array0.observe(e => {
event = e
})
array0.insert(0, [0, 1, 2])
compareEvent(event, {
remote: false
})
array0.delete(0)
compareEvent(event, {
remote: false
})
array0.delete(0, 2)
compareEvent(event, {
remote: false
})
compare(users)
}
export const testInsertAndDeleteEventsForTypes = tc => {
const { array0, users } = init(tc, { users: 2 })
let event
array0.observe(e => {
event = e
})
array0.insert(0, [Y.Array])
compareEvent(event, {
remote: false
})
array0.delete(0)
compareEvent(event, {
remote: false
})
compare(users)
}
export const testInsertAndDeleteEventsForTypes2 = tc => {
const { array0, users } = init(tc, { users: 2 })
let events = []
array0.observe(e => {
events.push(e)
})
array0.insert(0, ['hi', Y.Map])
compareEvent(events[0], {
remote: false
})
t.assert(events.length === 1, 'Event is triggered exactly once for insertion of two elements')
array0.delete(1)
compareEvent(events[1], {
remote: false
})
t.assert(events.length === 2, 'Event is triggered exactly once for deletion')
compare(users)
}
export const testGarbageCollector = tc => {
const { testConnector, users, array0 } = init(tc, { users: 3 })
array0.insert(0, ['x', 'y', 'z'])
testConnector.flushAllMessages()
users[0].disconnect()
array0.delete(0, 3)
users[0].connect()
testConnector.flushAllMessages()
compare(users)
}
export const testEventTargetIsSetCorrectlyOnLocal = tc => {
const { array0, users } = init(tc, { users: 3 })
/**
* @type {any}
*/
let event
array0.observe(e => {
event = e
})
array0.insert(0, ['stuff'])
t.assert(event.target === array0, '"target" property is set correctly')
compare(users)
}
export const testEventTargetIsSetCorrectlyOnRemote = tc => {
const { testConnector, array0, array1, users } = init(tc, { users: 3 })
/**
* @type {any}
*/
let event
array0.observe(e => {
event = e
})
array1.insert(0, ['stuff'])
testConnector.flushAllMessages()
compareEvent(event, {
remote: true
})
t.assert(event.target === array0, '"target" property is set correctly')
compare(users)
}
export const testIteratingArrayContainingTypes = tc => {
const y = new Y.Y()
const arr = y.define('arr', Y.Array)
const numItems = 10
for (let i = 0; i < numItems; i++) {
const map = new Y.Map()
map.set('value', i)
arr.push([map])
}
let cnt = 0
for (let item of arr) {
t.assert(item.get('value') === cnt++, 'value is correct')
}
y.destroy()
}
let _uniqueNumber = 0
const getUniqueNumber = () => _uniqueNumber++
let arrayTransactions = [
function insert (t, user, gen) {
const yarray = user.define('array', Y.Array)
var uniqueNumber = getUniqueNumber()
var content = []
var len = prng.int32(gen, 1, 4)
for (var i = 0; i < len; i++) {
content.push(uniqueNumber)
}
var pos = prng.int32(gen, 0, yarray.length)
yarray.insert(pos, content)
},
function insertTypeArray (t, user, gen) {
const yarray = user.define('array', Y.Array)
var pos = prng.int32(gen, 0, yarray.length)
yarray.insert(pos, [Y.Array])
var array2 = yarray.get(pos)
array2.insert(0, [1, 2, 3, 4])
},
function insertTypeMap (t, user, gen) {
const yarray = user.define('array', Y.Array)
var pos = prng.int32(gen, 0, yarray.length)
yarray.insert(pos, [Y.Map])
var map = yarray.get(pos)
map.set('someprop', 42)
map.set('someprop', 43)
map.set('someprop', 44)
},
function _delete (t, user, gen) {
const yarray = user.define('array', Y.Array)
var length = yarray.length
if (length > 0) {
var somePos = prng.int32(gen, 0, length - 1)
var delLength = prng.int32(gen, 1, Math.min(2, length - somePos))
if (yarray instanceof Y.Array) {
if (prng.bool(gen)) {
var type = yarray.get(somePos)
if (type.length > 0) {
somePos = prng.int32(gen, 0, type.length - 1)
delLength = prng.int32(gen, 0, Math.min(2, type.length - somePos))
type.delete(somePos, delLength)
}
} else {
yarray.delete(somePos, delLength)
}
} else {
yarray.delete(somePos, delLength)
}
}
}
]
export const testRepeatGeneratingYarrayTests20 = tc => {
applyRandomTests(tc, arrayTransactions, 20)
}
export const testRepeatGeneratingYarrayTests40 = tc => {
applyRandomTests(tc, arrayTransactions, 40)
}
export const testRepeatGeneratingYarrayTests42 = tc => {
applyRandomTests(tc, arrayTransactions, 42)
}
export const testRepeatGeneratingYarrayTests43 = tc => {
applyRandomTests(tc, arrayTransactions, 43)
}
export const testRepeatGeneratingYarrayTests44 = tc => {
applyRandomTests(tc, arrayTransactions, 44)
}
export const testRepeatGeneratingYarrayTests45 = tc => {
applyRandomTests(tc, arrayTransactions, 45)
}
export const testRepeatGeneratingYarrayTests46 = tc => {
applyRandomTests(tc, arrayTransactions, 46)
}
export const testRepeatGeneratingYarrayTests300 = tc => {
applyRandomTests(tc, arrayTransactions, 300)
}
export const testRepeatGeneratingYarrayTests400 = tc => {
applyRandomTests(tc, arrayTransactions, 400)
}
export const testRepeatGeneratingYarrayTests500 = tc => {
applyRandomTests(tc, arrayTransactions, 500)
}
export const testRepeatGeneratingYarrayTests600 = tc => {
applyRandomTests(tc, arrayTransactions, 600)
}
export const testRepeatGeneratingYarrayTests1000 = tc => {
applyRandomTests(tc, arrayTransactions, 1000)
}
export const testRepeatGeneratingYarrayTests1800 = tc => {
applyRandomTests(tc, arrayTransactions, 1800)
}
export const testRepeatGeneratingYarrayTests10000 = tc => {
applyRandomTests(tc, arrayTransactions, 10000)
}