Start working on tests.
This commit is contained in:
parent
ea6eb7bd94
commit
ac821e448d
1
packages/js/.gitignore
vendored
1
packages/js/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
|
dist/
|
1
packages/js/core/dist/document.cjs
vendored
1
packages/js/core/dist/document.cjs
vendored
@ -1 +0,0 @@
|
|||||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("./parser.cjs");function f(r,c=" "){const e=i.createLineData("",c);let n=!1;async function o(t=-1){if(n)n=!1;else{const a=await r();if(a==null)return!1;e.line=a,i.parseLine(e)}return l()<=t?(n=!0,!1):!0}const l=()=>e.level,u=(t=e.offsetHead)=>e.line.slice(t),s=()=>e.line.slice(e.offsetHead,e.offsetTail);return{next:o,level:l,line:u,head:s,tail:()=>e.line.slice(e.offsetTail),match:t=>t===s()}}exports.useDocument=f;
|
|
28
packages/js/core/dist/document.js
vendored
28
packages/js/core/dist/document.js
vendored
@ -1,28 +0,0 @@
|
|||||||
import { parseLine as r, createLineData as u } from "./parser.js";
|
|
||||||
function h(s, f = " ") {
|
|
||||||
const e = u("", f);
|
|
||||||
let n = !1;
|
|
||||||
async function c(t = -1) {
|
|
||||||
if (n)
|
|
||||||
n = !1;
|
|
||||||
else {
|
|
||||||
const i = await s();
|
|
||||||
if (i == null)
|
|
||||||
return !1;
|
|
||||||
e.line = i, r(e);
|
|
||||||
}
|
|
||||||
return l() <= t ? (n = !0, !1) : !0;
|
|
||||||
}
|
|
||||||
const l = () => e.level, o = (t = e.offsetHead) => e.line.slice(t), a = () => e.line.slice(e.offsetHead, e.offsetTail);
|
|
||||||
return {
|
|
||||||
next: c,
|
|
||||||
level: l,
|
|
||||||
line: o,
|
|
||||||
head: a,
|
|
||||||
tail: () => e.line.slice(e.offsetTail),
|
|
||||||
match: (t) => t === a()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export {
|
|
||||||
h as useDocument
|
|
||||||
};
|
|
1
packages/js/core/dist/index.cjs
vendored
1
packages/js/core/dist/index.cjs
vendored
@ -1 +0,0 @@
|
|||||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./parser.cjs"),r=require("./document.cjs");exports.createLineData=e.createLineData;exports.parseLine=e.parseLine;exports.useDocument=r.useDocument;
|
|
7
packages/js/core/dist/index.js
vendored
7
packages/js/core/dist/index.js
vendored
@ -1,7 +0,0 @@
|
|||||||
import { createLineData as o, parseLine as t } from "./parser.js";
|
|
||||||
import { useDocument as m } from "./document.js";
|
|
||||||
export {
|
|
||||||
o as createLineData,
|
|
||||||
t as parseLine,
|
|
||||||
m as useDocument
|
|
||||||
};
|
|
1
packages/js/core/dist/parser.cjs
vendored
1
packages/js/core/dist/parser.cjs
vendored
@ -1 +0,0 @@
|
|||||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function t(e="",r=" "){return{line:e,indent:r,level:0,offsetHead:0,offsetTail:0}}function f(e){if(typeof e!="object"||!e||typeof e.level!="number")throw new Error("'lineData' must be an object with string line and numeric level properties");if(typeof e.indent!="string"||e.indent.length===0||e.indent.length>1)throw new Error("'lineData.indent' must be a single-character string");if(typeof e.line!="string")throw new Error("'lineData.line' must be a string");let r=0;if(!e.line.length)e.level=e.level,e.offsetHead=0,e.offsetTail=0;else{for(;e.line[r]===e.indent&&r<=e.level+1;)++r;for(e.level=r,e.offsetHead=r,e.offsetTail=r;e.line[e.offsetTail]&&e.line[e.offsetTail]!==" ";)++e.offsetTail}return e}exports.createLineData=t;exports.parseLine=f;
|
|
25
packages/js/core/dist/parser.js
vendored
25
packages/js/core/dist/parser.js
vendored
@ -1,25 +0,0 @@
|
|||||||
function f(e = "", r = " ") {
|
|
||||||
return { line: e, indent: r, level: 0, offsetHead: 0, offsetTail: 0 };
|
|
||||||
}
|
|
||||||
function o(e) {
|
|
||||||
if (typeof e != "object" || !e || typeof e.level != "number")
|
|
||||||
throw new Error("'lineData' must be an object with string line and numeric level properties");
|
|
||||||
if (typeof e.indent != "string" || e.indent.length === 0 || e.indent.length > 1)
|
|
||||||
throw new Error("'lineData.indent' must be a single-character string");
|
|
||||||
if (typeof e.line != "string")
|
|
||||||
throw new Error("'lineData.line' must be a string");
|
|
||||||
let r = 0;
|
|
||||||
if (!e.line.length)
|
|
||||||
e.level = e.level, e.offsetHead = 0, e.offsetTail = 0;
|
|
||||||
else {
|
|
||||||
for (; e.line[r] === e.indent && r <= e.level + 1; )
|
|
||||||
++r;
|
|
||||||
for (e.level = r, e.offsetHead = r, e.offsetTail = r; e.line[e.offsetTail] && e.line[e.offsetTail] !== " "; )
|
|
||||||
++e.offsetTail;
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
export {
|
|
||||||
f as createLineData,
|
|
||||||
o as parseLine
|
|
||||||
};
|
|
2
packages/js/core/dist/readers/js-string.cjs
vendored
2
packages/js/core/dist/readers/js-string.cjs
vendored
@ -1,2 +0,0 @@
|
|||||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function n(r,e=0){const t=Array.isArray(r)?r:r.split(`
|
|
||||||
`);return e--,()=>(e++,e>=t.length?null:t[e])}exports.createStringReader=n;
|
|
8
packages/js/core/dist/readers/js-string.js
vendored
8
packages/js/core/dist/readers/js-string.js
vendored
@ -1,8 +0,0 @@
|
|||||||
function e(t, r = 0) {
|
|
||||||
const n = Array.isArray(t) ? t : t.split(`
|
|
||||||
`);
|
|
||||||
return r--, () => (r++, r >= n.length ? null : n[r]);
|
|
||||||
}
|
|
||||||
export {
|
|
||||||
e as createStringReader
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const r=require("node:fs"),n=require("node:readline/promises"),t=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},o=t(r),u=t(n);function d(e){const a=u.default.createInterface({input:o.default.createReadStream(e,"utf-8")})[Symbol.asyncIterator]();return async()=>(await a.next()).value}exports.createReadlineReader=d;
|
|
11
packages/js/core/dist/readers/node-readline.js
vendored
11
packages/js/core/dist/readers/node-readline.js
vendored
@ -1,11 +0,0 @@
|
|||||||
import r from "node:fs";
|
|
||||||
import a from "node:readline/promises";
|
|
||||||
function c(e) {
|
|
||||||
const t = a.createInterface({
|
|
||||||
input: r.createReadStream(e, "utf-8")
|
|
||||||
})[Symbol.asyncIterator]();
|
|
||||||
return async () => (await t.next()).value;
|
|
||||||
}
|
|
||||||
export {
|
|
||||||
c as createReadlineReader
|
|
||||||
};
|
|
@ -26,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest ./src",
|
"test": "node ./test/index.js",
|
||||||
"dev": "vite build --watch",
|
"dev": "vite build --watch",
|
||||||
"build": "vite build"
|
"build": "vite build"
|
||||||
},
|
},
|
@ -42,7 +42,7 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
|||||||
const level = () => lineData.level
|
const level = () => lineData.level
|
||||||
const line = (startOffset: number = lineData.offsetHead) => lineData.line.slice(startOffset)
|
const line = (startOffset: number = lineData.offsetHead) => lineData.line.slice(startOffset)
|
||||||
const head = () => lineData.line.slice(lineData.offsetHead, lineData.offsetTail)
|
const head = () => lineData.line.slice(lineData.offsetHead, lineData.offsetTail)
|
||||||
const tail = () => lineData.line.slice(lineData.offsetTail)
|
const tail = () => lineData.line.slice(lineData.offsetTail + 1) // Skip the space
|
||||||
const match = (matchHead: string): boolean => matchHead === head()
|
const match = (matchHead: string): boolean => matchHead === head()
|
||||||
|
|
||||||
return {
|
return {
|
@ -2,10 +2,18 @@ import fs from 'node:fs'
|
|||||||
import readline from 'node:readline/promises'
|
import readline from 'node:readline/promises'
|
||||||
import type { Reader } from './reader'
|
import type { Reader } from './reader'
|
||||||
|
|
||||||
export function createReadlineReader(path: string): Reader {
|
export function createFileReader(path: string): Reader {
|
||||||
const it = readline.createInterface({
|
const it = readline.createInterface({
|
||||||
input: fs.createReadStream(path, 'utf-8'),
|
input: fs.createReadStream(path, 'utf-8'),
|
||||||
})[Symbol.asyncIterator]()
|
})[Symbol.asyncIterator]()
|
||||||
|
|
||||||
return async () => (await it.next()).value
|
return async () => (await it.next()).value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createStdinReader(): Reader {
|
||||||
|
const it = readline.createInterface({
|
||||||
|
input: process.stdin
|
||||||
|
})[Symbol.asyncIterator]()
|
||||||
|
|
||||||
|
return async () => (await it.next()).value
|
||||||
|
}
|
23
packages/js/test/index.js
Normal file
23
packages/js/test/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { createLineData, parseLine, useDocument } from '@terrace/core'
|
||||||
|
import { createStdinReader } from '@terrace/core/readers/node-readline'
|
||||||
|
|
||||||
|
const testName = process.argv[2]
|
||||||
|
|
||||||
|
|
||||||
|
const tests = {
|
||||||
|
'linedata:basic': async () => {
|
||||||
|
const { level, line, head, tail, next } = useDocument(createStdinReader())
|
||||||
|
while(await next()) {
|
||||||
|
console.log(`level: ${level()} | head: ${head()} | tail: ${tail()} | line: ${line()}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'linedata:tabs': async () => {
|
||||||
|
const { level, line, head, tail, next } = useDocument(createStdinReader(), '\t')
|
||||||
|
while(await next()) {
|
||||||
|
console.log(`level: ${level()} | head: ${head()} | tail: ${tail()} | line: ${line()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const test = tests[testName]
|
||||||
|
await test()
|
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@ -8,11 +8,11 @@ importers:
|
|||||||
jest: ^29.4.1
|
jest: ^29.4.1
|
||||||
turbo: ^1.7.3
|
turbo: ^1.7.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@terrace/core': link:packages/js/core
|
'@terrace/core': link:packages/js
|
||||||
jest: 29.4.1
|
jest: 29.4.1
|
||||||
turbo: 1.7.3
|
turbo: 1.7.3
|
||||||
|
|
||||||
packages/js/core:
|
packages/js:
|
||||||
specifiers:
|
specifiers:
|
||||||
vite: ^3.2.3
|
vite: ^3.2.3
|
||||||
vitest: ^0.24.5
|
vitest: ^0.24.5
|
||||||
@ -24,7 +24,7 @@ importers:
|
|||||||
specifiers:
|
specifiers:
|
||||||
'@terrace/core': workspace:*
|
'@terrace/core': workspace:*
|
||||||
dependencies:
|
dependencies:
|
||||||
'@terrace/core': link:../packages/js/core
|
'@terrace/core': link:../packages/js
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
packages:
|
packages:
|
||||||
- "./test"
|
- "./test"
|
||||||
- "./packages/js/*"
|
- "./packages/*"
|
||||||
- "./experiments/*"
|
- "./experiments/*"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "@terrace/test",
|
"name": "@terrace/test",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@terrace/core": "workspace:*"
|
"@terrace/core": "workspace:*"
|
||||||
|
@ -1,43 +1,83 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import fs from 'node:fs/promises'
|
import fs from 'node:fs/promises'
|
||||||
|
import { execSync } from 'node:child_process'
|
||||||
import { useDocument } from '@terrace/core'
|
import { useDocument } from '@terrace/core'
|
||||||
import { createReadlineReader } from '@terrace/core/readers/node-readline'
|
import { createFileReader } from '@terrace/core/readers/node-readline'
|
||||||
|
|
||||||
async function loadTests(path) {
|
async function loadTests(path) {
|
||||||
const { next, level, head, tail, line, match } = useDocument(createReadlineReader(path))
|
const { next, level, head, tail, line, match } = useDocument(createFileReader(path))
|
||||||
|
|
||||||
const tests = {}
|
const descriptions = {}
|
||||||
|
|
||||||
while (await next()) {
|
while (await next()) {
|
||||||
if (!head() || match('#schema')) continue
|
if (!head() || match('#schema')) continue
|
||||||
|
const tests = descriptions[tail()] = []
|
||||||
|
|
||||||
const rootLevel = level()
|
const rootLevel = level()
|
||||||
|
|
||||||
const test = tests[tail().trim()] = { input: [], output: [] }
|
|
||||||
|
|
||||||
while (await next(rootLevel)) {
|
while (await next(rootLevel)) {
|
||||||
|
if (!match('it')) continue
|
||||||
|
|
||||||
|
const test = { it: tail(), packages: [], key: '', input: [], output: [] }
|
||||||
|
tests.push(test)
|
||||||
|
|
||||||
const testLevel = level()
|
const testLevel = level()
|
||||||
if (match('input')) {
|
|
||||||
while (await next(testLevel)) {
|
while (await next(testLevel)) {
|
||||||
test.input.push(line(testLevel))
|
if (match('key')) test.key = tail()
|
||||||
|
if (match('packages')) test.packages = tail().split(' ')
|
||||||
|
|
||||||
|
const propertyLevel = level()
|
||||||
|
if (match('input')) {
|
||||||
|
// TODO: Find a way to handle newlines better.
|
||||||
|
if (tail().startsWith('literal')) {
|
||||||
|
test.input = tail()
|
||||||
|
.split('literal ').join('')
|
||||||
|
.replaceAll('\\n', '\n')
|
||||||
|
.replaceAll('\\t', '\t')
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (await next(propertyLevel)) test.input.push(line(propertyLevel))
|
||||||
|
test.input = test.input.join('\n').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match('output')) {
|
if (match('output')) {
|
||||||
while (await next(testLevel)) {
|
// TODO: Find a way to handle newlines better.
|
||||||
test.output.push(line(testLevel))
|
if (tail().startsWith('literal')) {
|
||||||
|
test.output = tail().split('literal ').join('').replace('\\n', '\n')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
while (await next(propertyLevel)) test.output.push(line())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
test.output = test.output.join('\n').trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return descriptions
|
||||||
return tests
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Runs a basic test', async () => {
|
function callTest(pkg, name, input) {
|
||||||
const tests = await loadTests('./tests.tce', 'utf-8')
|
return new Promise((resolve, reject) => {
|
||||||
|
const stdout = execSync(`npm run --silent test ${name}`, {
|
||||||
|
cwd: `../packages/${pkg}`,
|
||||||
|
input
|
||||||
|
})
|
||||||
|
|
||||||
console.log(tests)
|
resolve(stdout.toString().trim())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
expect(1).to.equal(1)
|
const descriptions = await loadTests('./tests.tce')
|
||||||
})
|
|
||||||
|
for (const [name, tests] of Object.entries(descriptions)) {
|
||||||
|
describe(name, () => {
|
||||||
|
for (const test of tests) {
|
||||||
|
test.packages.forEach(pkg => {
|
||||||
|
it(`${pkg}: ${test.it}`, async () => {
|
||||||
|
expect(await callTest(pkg, test.key, test.input)).to.equal(test.output)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -1,8 +1,54 @@
|
|||||||
#schema test
|
#schema test
|
||||||
|
|
||||||
test Basic
|
describe LineData
|
||||||
input
|
it Handles a blank line at indent level 0
|
||||||
key value
|
key linedata:basic
|
||||||
|
packages js
|
||||||
|
input literal \n
|
||||||
output
|
output
|
||||||
level: 0 | head: key | tail: value | line: key value
|
level: 0 | head: | tail: | line:
|
||||||
|
|
||||||
|
it Handles a blank line with a single space at indent level 1
|
||||||
|
key linedata:basic
|
||||||
|
packages js
|
||||||
|
input literal \n
|
||||||
|
output
|
||||||
|
level: 1 | head: | tail: | line:
|
||||||
|
|
||||||
|
it Handles a blank line with two spaces
|
||||||
|
key linedata:basic
|
||||||
|
packages js
|
||||||
|
input literal \n
|
||||||
|
output
|
||||||
|
level: 2 | head: | tail: | line:
|
||||||
|
|
||||||
|
it Handles a normal line at indent level 1
|
||||||
|
key linedata:basic
|
||||||
|
packages js
|
||||||
|
input literal line 1
|
||||||
|
output
|
||||||
|
level: 1 | head: line | tail: 1 | line: line 1
|
||||||
|
|
||||||
|
it Handles a normal line at indent level 1 indented with tabs
|
||||||
|
key linedata:tabs
|
||||||
|
packages js
|
||||||
|
input literal \tline 1
|
||||||
|
output
|
||||||
|
level: 1 | head: line | tail: 1 | line: line 1
|
||||||
|
|
||||||
|
it Handles a normal line at indent level 2 indented with tabs
|
||||||
|
key linedata:tabs
|
||||||
|
packages js
|
||||||
|
input literal \t\tline 1
|
||||||
|
output
|
||||||
|
level: 2 | head: line | tail: 1 | line: line 1
|
||||||
|
|
||||||
|
it Nests a normal line under a preceding normal line
|
||||||
|
key linedata:basic
|
||||||
|
packages js
|
||||||
|
input
|
||||||
|
line 1
|
||||||
|
line 2
|
||||||
|
output
|
||||||
|
level: 0 | head: line | tail: 1 | line: line 1
|
||||||
|
level: 1 | head: line | tail: 2 | line: line 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user