Files
atom/spec/dom-element-pool-spec.js
Nathan Sobo 5753b75f09 Fail assertion with content metadata if the same element is freed twice
This changes the element pool to only remove elements' children right
before we use an element again in order to preserve the structure of
double-freed elements. This will aid in debugging double-free
occurrences. It's also less work in cases where nodes aren't reused.
2017-02-13 10:30:51 -07:00

84 lines
3.3 KiB
JavaScript

const DOMElementPool = require ('../src/dom-element-pool')
describe('DOMElementPool', function () {
let domElementPool
beforeEach(() => { domElementPool = new DOMElementPool() })
it('builds DOM nodes, recycling them when they are freed', function () {
let elements
const [div, span1, span2, span3, span4, span5, textNode] = Array.from(elements = [
domElementPool.buildElement('div'),
domElementPool.buildElement('span'),
domElementPool.buildElement('span'),
domElementPool.buildElement('span'),
domElementPool.buildElement('span'),
domElementPool.buildElement('span'),
domElementPool.buildText('Hello world!')
])
div.appendChild(span1)
span1.appendChild(span2)
div.appendChild(span3)
span3.appendChild(span4)
span4.appendChild(textNode)
domElementPool.freeElementAndDescendants(div)
domElementPool.freeElementAndDescendants(span5)
expect(elements.includes(domElementPool.buildElement('div'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(true)
expect(elements.includes(domElementPool.buildText('another text'))).toBe(true)
expect(elements.includes(domElementPool.buildElement('div'))).toBe(false)
expect(elements.includes(domElementPool.buildElement('span'))).toBe(false)
expect(elements.includes(domElementPool.buildText('unexisting'))).toBe(false)
})
it('forgets free nodes after being cleared', function () {
const span = domElementPool.buildElement('span')
const div = domElementPool.buildElement('div')
domElementPool.freeElementAndDescendants(span)
domElementPool.freeElementAndDescendants(div)
domElementPool.clear()
expect(domElementPool.buildElement('span')).not.toBe(span)
expect(domElementPool.buildElement('div')).not.toBe(div)
})
it('fails an assertion when freeing the same element twice', function () {
let failure
atom.onDidFailAssertion((error) => failure = error)
const div = domElementPool.buildElement('div')
div.textContent = 'testing'
domElementPool.freeElementAndDescendants(div)
expect(failure).toBeUndefined()
domElementPool.freeElementAndDescendants(div)
expect(failure.message).toBe('Assertion failed: The element has already been freed!')
expect(failure.metadata.content).toBe('<div>testing</div>')
})
it('fails an assertion when freeing the same text node twice', function () {
let failure
atom.onDidFailAssertion((error) => failure = error)
const node = domElementPool.buildText('testing')
domElementPool.freeElementAndDescendants(node)
expect(failure).toBeUndefined()
domElementPool.freeElementAndDescendants(node)
expect(failure.message).toBe('Assertion failed: The element has already been freed!')
expect(failure.metadata.content).toBe('testing')
})
it('throws an error when trying to free an invalid element', function () {
expect(() => domElementPool.freeElementAndDescendants(null)).toThrow()
expect(() => domElementPool.freeElementAndDescendants(undefined)).toThrow()
})
})