254 lines
8.8 KiB
TypeScript
254 lines
8.8 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { createLineData, parseLine } from './parser'
|
|
|
|
describe(`LineData`, () => {
|
|
it(`is an object`, () => {
|
|
const lineData = createLineData()
|
|
expect(lineData).toBeTypeOf(`object`)
|
|
})
|
|
|
|
it(`has five properties`, () => {
|
|
const lineData = createLineData()
|
|
expect(Object.keys(lineData).length).to.equal(5)
|
|
})
|
|
|
|
it(`'line' is a string|null initialized to null`, () => {
|
|
const lineData = createLineData()
|
|
expect(lineData.level).to.equal(0)
|
|
})
|
|
|
|
it(`'level' is an integer initialized to zero`, () => {
|
|
const lineData = createLineData()
|
|
expect(lineData.level).to.equal(0)
|
|
})
|
|
|
|
it(`'offsetHead' is an integer initialized to zero`, () => {
|
|
const lineData = createLineData()
|
|
expect(lineData.offsetHead).to.equal(0)
|
|
})
|
|
|
|
it(`'offsetTail' is an integer initialized to zero`, () => {
|
|
const lineData = createLineData()
|
|
expect(lineData.offsetTail).to.equal(0)
|
|
})
|
|
})
|
|
|
|
describe(`parseLine`, () => {
|
|
it(`Requres 'lineData' to be an object with string line and numeric level properties`, () => {
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, 0)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, [])).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, {})).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, null)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, true)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, () => {})).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, { line: '', level: '' })).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
// @ts-ignore
|
|
expect(() => parseLine(``, { line: '', level: 0 })).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
|
})
|
|
|
|
it(`Requres 'indent' to be a single-character string`, () => {
|
|
const lineData = createLineData()
|
|
lineData.line = ``
|
|
// @ts-ignore
|
|
lineData.indent = 0
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
// @ts-ignore
|
|
lineData.indent = []
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
// @ts-ignore
|
|
lineData.indent = {}
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
// @ts-ignore
|
|
lineData.indent = null
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
// @ts-ignore
|
|
lineData.indent = true
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
// @ts-ignore
|
|
lineData.indent = () => {}
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
lineData.indent = ` `
|
|
expect(() => parseLine(lineData)).toThrowError(`'lineData.indent' must be a single-character string`)
|
|
})
|
|
|
|
it(`Handles a blank line at indent level 0`, () => {
|
|
const line = ``
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 0, offsetHead: 0, offsetTail: 0 })
|
|
})
|
|
|
|
it(`Handles a line with a single space at indent level 1`, () => {
|
|
const line = ` `
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 1, offsetHead: 1, offsetTail: 1 })
|
|
})
|
|
|
|
it(`Handles a line with two spaces`, () => {
|
|
const line = ` `
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 2, offsetHead: 2, offsetTail: 2 })
|
|
})
|
|
|
|
it(`Handles a normal line at indent level 0`, () => {
|
|
const line = `line 1`
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 0, offsetHead: 0, offsetTail: 4 })
|
|
})
|
|
|
|
it(`Handles a normal line at indent level 1`, () => {
|
|
const line = ` line 1`
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 1, offsetHead: 1, offsetTail: 5 })
|
|
})
|
|
|
|
it(`Handles a normal line at indent level 2`, () => {
|
|
const line = ` line 1`
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: ` `, level: 2, offsetHead: 2, offsetTail: 6 })
|
|
})
|
|
|
|
it(`Handles a normal line at indent level 1 indented with tabs`, () => {
|
|
const line = `\tline 1`
|
|
const lineData = createLineData(line, `\t`)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: `\t`, level: 1, offsetHead: 1, offsetTail: 5 })
|
|
})
|
|
|
|
it(`Handles a normal line at indent level 2 indented with tabs`, () => {
|
|
const line = `\t\tline 1`
|
|
const lineData = createLineData(line, `\t`)
|
|
parseLine(lineData)
|
|
expect(lineData).to.deep.equal({ line, indent: `\t`, level: 2, offsetHead: 2, offsetTail: 6})
|
|
})
|
|
|
|
it(`Nests a normal line under a preceding normal line`, () => {
|
|
const lines = [
|
|
'line 1',
|
|
' line 2'
|
|
]
|
|
|
|
const lineData = createLineData()
|
|
const results = lines.map(line => {
|
|
lineData.line = line
|
|
parseLine(lineData)
|
|
return {...lineData}
|
|
})
|
|
|
|
expect(results).to.deep.equal([
|
|
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
|
{ line: lines[1], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 }
|
|
])
|
|
})
|
|
|
|
it(`Nests multiple normal line under a preceding normal line`, () => {
|
|
const lines = [
|
|
'line 1',
|
|
' line 2',
|
|
' line 3',
|
|
' line 4',
|
|
]
|
|
|
|
const lineData = createLineData()
|
|
const results = lines.map(line => {
|
|
lineData.line = line
|
|
parseLine(lineData)
|
|
return {...lineData}
|
|
})
|
|
|
|
expect(results).to.deep.equal([
|
|
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
|
{ line: lines[1], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 },
|
|
{ line: lines[2], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 },
|
|
{ line: lines[3], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 }
|
|
])
|
|
})
|
|
|
|
it(`Does not nest an empty line under a preceding normal line`, () => {
|
|
const lines = [
|
|
'line 1',
|
|
''
|
|
]
|
|
|
|
const lineData = createLineData()
|
|
const results = lines.map(line => {
|
|
lineData.line = line
|
|
parseLine(lineData)
|
|
return {...lineData}
|
|
})
|
|
|
|
expect(results).to.deep.equal([
|
|
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
|
{ line: lines[1], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
|
])
|
|
})
|
|
|
|
it(`Does not nest multiple empty lines under a preceding normal line`, () => {
|
|
const lines = [
|
|
'line 1',
|
|
'',
|
|
'',
|
|
'',
|
|
]
|
|
|
|
const lineData = createLineData()
|
|
const results = lines.map(line => {
|
|
lineData.line = line
|
|
parseLine(lineData)
|
|
return {...lineData}
|
|
})
|
|
|
|
expect(results).to.deep.equal([
|
|
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
|
{ line: lines[1], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 },
|
|
{ line: lines[2], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 },
|
|
{ line: lines[3], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
|
])
|
|
})
|
|
|
|
it(`Handle head and tail matching for lines with head and tail`, () => {
|
|
const line = ` head tail1 tail2 tail3`
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
|
|
const head = line.slice(lineData.offsetHead, lineData.offsetTail)
|
|
const tail = line.slice(lineData.offsetTail + 1)
|
|
expect(head).to.equal(`head`)
|
|
expect(tail).to.equal(`tail1 tail2 tail3`)
|
|
})
|
|
|
|
it(`Handle head and tail matching for lines with head but no tail`, () => {
|
|
const line = ` head`
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
|
|
const head = line.slice(lineData.offsetHead, lineData.offsetTail)
|
|
const tail = line.slice(lineData.offsetTail + 1)
|
|
expect(head).to.equal(`head`)
|
|
expect(tail).to.equal(``)
|
|
})
|
|
|
|
it(`Handle head and tail matching for lines with head and trailing space`, () => {
|
|
const line = ` head `
|
|
const lineData = createLineData(line)
|
|
parseLine(lineData)
|
|
|
|
const head = line.slice(lineData.offsetHead, lineData.offsetTail)
|
|
const tail = line.slice(lineData.offsetTail + 1)
|
|
expect(head).to.equal(`head`)
|
|
expect(tail).to.equal(``)
|
|
})
|
|
})
|