Befor generating

This commit is contained in:
marys
2026-06-01 13:17:37 +02:00
parent 3383f4bf4a
commit 1aa1b5f625
6756 changed files with 649946 additions and 1 deletions
@@ -0,0 +1,67 @@
import { assert } from "chai";
import * as YAML from '../src/';
import * as util from './testUtil';
suite('YAML Syntax', () => {
test('Allow astral characters', function () {
const key = '𝑘𝑒𝑦';
const value = '𝑣𝑎𝑙𝑢𝑒';
const document = YAML.safeLoad(`${key}: ${value}`);
assert.deepEqual(document.mappings[0].key.value, key);
assert.deepEqual(document.mappings[0].value.value, value);
});
test('Forbid non-printable characters', function () {
testErrors('\x01', [{
line: 1,
column: 0,
message:'the stream contains non-printable characters',
isWarning: false
}]);
testErrors('\x7f', [{
line: 1,
column: 0,
message:'the stream contains non-printable characters',
isWarning: false
}]);
testErrors('\x9f', [{
line: 1,
column: 0,
message:'the stream contains non-printable characters',
isWarning: false
}]);
});
test('Forbid lone surrogates', function () {
testErrors('\udc00\ud800', [{
line: 1,
column: 0,
message:'the stream contains non-printable characters',
isWarning: false
}]);
});
test('Allow non-printable characters inside quoted scalars', function () {
const key = '"\x7f\x9f\udc00\ud800"';
const document = YAML.safeLoad(key);
assert.deepEqual(document.value, '\x7f\x9f\udc00\ud800');
});
test('Forbid control sequences inside quoted scalars', function () {
testErrors('"\x03"', [{
line: 0,
column: 2,
message:'expected valid JSON character',
isWarning: false
}]);
});
});
function testErrors(input: string, expectedErrors: util.TestError[]) {
util.testErrors(input, expectedErrors);
}
+104
View File
@@ -0,0 +1,104 @@
import * as YAML from '../src/'
import { AbstractVisitor } from './visitor'
import * as chai from 'chai'
const assert = chai.assert
function structure(node) {
return new DuplicateStructureBuilder().accept(node);
}
suite('Loading a single document', () => {
test('should work with document-end delimiters', function () {
const input = `---
whatever: true
...`
const doc = YAML.safeLoad(input)
const expected_structure =
YAML.newMap(
[YAML.newMapping(
YAML.newScalar('whatever'),
YAML.newScalar('true'))]);
assert.deepEqual(structure(doc), expected_structure)
assert.lengthOf(doc.errors, 0,
`Found error(s): ${doc.errors.toString()} when expecting none.`)
});
test('Document end position should be equal to input length', function () {
const input = `
outer:
inner:
`;
const doc1 = YAML.load(input);
assert.deepEqual(doc1.endPosition,input.length);
});
});
suite('Loading multiple documents', () => {
test('should work with document-end delimiters', function () {
const docs = []
YAML.loadAll(`---
whatever: true
...
---
whatever: false
...`, d => docs.push(d))
const expected_structure = [
YAML.newMap(
[YAML.newMapping(
YAML.newScalar('whatever'),
YAML.newScalar('true'))]),
YAML.newMap(
[YAML.newMapping(
YAML.newScalar('whatever'),
YAML.newScalar('false'))])
];
assert.deepEqual(docs.map(d => structure(d)), expected_structure)
docs.forEach(doc =>
assert.lengthOf(doc.errors, 0,
`Found error(s): ${doc.errors.toString()} when expecting none.`))
});
test('Last document end position should be equal to input length', function () {
const input = `
outer1:
inner1:
...
---
outer2:
inner2:
`;
const documents: YAML.YAMLDocument[] = [];
YAML.loadAll(input,x=>documents.push(x));
const doc2 = documents[1];
assert.deepEqual(doc2.endPosition,input.length);
});
});
class DuplicateStructureBuilder extends AbstractVisitor {
visitScalar(node: YAML.YAMLScalar) {
return YAML.newScalar(node.value)
}
visitMapping(node: YAML.YAMLMapping) {
return YAML.newMapping(this.visitScalar(node.key), this.accept(node.value))
}
visitSequence(node: YAML.YAMLSequence) {
const seq = YAML.newSeq()
seq.items = node.items.map(n => this.accept(n))
return seq
}
visitMap(node: YAML.YamlMap) {
return YAML.newMap(node.mappings.map(n => this.accept(n)));
}
visitAnchorRef(node: YAML.YAMLAnchorReference) {
throw new Error("Method not implemented.");
}
visitIncludeRef(node: YAML.YAMLNode) {
throw new Error("Method not implemented.");
}
}
@@ -0,0 +1,165 @@
import * as chai from 'chai'
const assert = chai.assert
import { determineScalarType as sut, ScalarType, parseYamlBoolean, parseYamlInteger, parseYamlFloat } from '../src/scalarInference'
import * as Yaml from '../src/index'
suite('determineScalarType', () => {
function determineScalarType(scalar: Yaml.YAMLDocument) {
return sut(<Yaml.YAMLScalar>scalar)
}
function safeLoad(input) {
return Yaml.safeLoad(input, {})
}
let _test = test;
// http://www.yaml.org/spec/1.2/spec.html#id2805071
suite('Plain Tag Resolution', () => {
function test(name, type, acceptable) {
_test(name, function () {
for (const word of acceptable) {
assert.strictEqual(determineScalarType(safeLoad(word)), type, word)
}
})
};
test('boolean', ScalarType.bool, ["true", "True", "TRUE", "false", "False", "FALSE"])
test("null", ScalarType.null, ["null", "Null", "NULL", "~", ""])
_test("null as from an array", function () {
const node = Yaml.newScalar('');
node.plainScalar = true;
assert.strictEqual(determineScalarType(node), ScalarType.null, "unquoted empty string")
})
test("integer", ScalarType.int, ["0", "0o7", "0x3A", "-19"])
test("float", ScalarType.float, ["0.", "-0.0", ".5", "+12e03", "-2E+05"])
test("float-infinity", ScalarType.float, [".inf", "-.Inf", "+.INF"])
test("float-NaN", ScalarType.float, [".nan", ".NaN", ".NAN"])
test("string", ScalarType.string, ["'true'", "TrUe", "nULl", "''", "'0'", '"1"', '" .5"', ".inF", ".nAn"])
})
suite('Flow style', () => {
test('still recognizes types', function () {
const node = <Yaml.YAMLSequence>safeLoad(`[ null,
true,
0,
0.,
.inf,
.nan,
"-123\n345"
]`)
const expected = [ScalarType.null, ScalarType.bool, ScalarType.int, ScalarType.float, ScalarType.float, ScalarType.float, ScalarType.string]
assert.deepEqual(node.items.map(d => determineScalarType(d)), expected)
})
})
suite('Block styles', () => {
var variations = ['>', '|', '>8', '|+1', '>-', '>+', '|-', '|+']
test('are always strings', function () {
for (const variant of variations) {
assert.deepEqual(determineScalarType(safeLoad(variant + "\n 123")), ScalarType.string);
}
})
})
})
suite('parseYamlInteger', () => {
test('decimal', function () {
assert.strictEqual(parseYamlInteger("0"), 0)
assert.strictEqual(parseYamlInteger("-19"), -19)
assert.strictEqual(parseYamlInteger("+1"), 1)
})
test('hexadecimal', function () {
assert.strictEqual(parseYamlInteger("0x3A"), 58)
})
test('octal', function () {
assert.strictEqual(parseYamlInteger("0o7"), 7)
})
test('otherwise', function () {
let error;
try {
parseYamlInteger("'1'")
}
catch (e) {
error = e;
}
assert(error, "should have thrown")
})
})
suite('parseYamlBoolean', () => {
test('true', function () {
for (const value of ["true", "True", "TRUE"]) {
assert.strictEqual(parseYamlBoolean(value), true, value);
}
})
test('false', function () {
for (const value of ["false", "False", "FALSE"]) {
assert.strictEqual(parseYamlBoolean(value), false, value);
}
})
test('otherwise', function () {
let error;
try {
parseYamlBoolean("tRUE")
}
catch (e) {
error = e;
}
assert(error, "should have thrown")
})
})
suite('parseYamlFloat', () => {
test('float', function () {
const values = ["0.", "-0.0", ".5", "+12e03", "-2E+05"]
const expected = [0, -0, 0.5, 12000, -200000]
for (var index = 0; index < values.length; index++) {
assert.strictEqual(parseYamlFloat(values[index]), expected[index])
}
})
test('NaN', function () {
for (const value of [".nan", ".NaN", ".NAN"]) {
assert(isNaN(parseYamlFloat(value)), `isNaN(${value})`)
}
})
test('infinity', function () {
assert.strictEqual(parseYamlFloat(".inf"),
Infinity)
assert.strictEqual(parseYamlFloat("-.Inf"), -Infinity)
assert.strictEqual(parseYamlFloat(".INF"), Infinity)
})
test('otherwise', function () {
let error;
try {
parseYamlFloat("text")
}
catch (e) {
error = e;
}
assert(error, "should have thrown")
})
})
+71
View File
@@ -0,0 +1,71 @@
import util = require("./testUtil");
suite('YAML Syntax', () => {
suite('Warnings for tab symbols', () => {
test('test 001', function () {
testErrors(
"schemas:\n" +
" - !i",
[
{
line: 1,
column: 4,
message: "unknown tag <!i>",
isWarning: false
}
]
);
});
test('test 002', function () {
testErrors(
"schemas:\n" +
" - !in",
[
{
line: 1,
column: 4,
message: "unknown tag <!in>",
isWarning: false
}
]
);
});
test('test 003', function () {
testErrors(
"schemas:\n" +
" - !inc",
[
{
line: 1,
column: 4,
message: "unknown tag <!inc>",
isWarning: false
}
]
);
});
test('test 004', function () {
testErrors(
"schemas:\n" +
" - !incl",
[
{
line: 1,
column: 4,
message: "unknown tag <!incl>",
isWarning: false
}
]
);
});
});
});
function testErrors(input:string,expectedErrors: util.TestError[]) {
util.testErrors(input, expectedErrors);
}
+67
View File
@@ -0,0 +1,67 @@
import YAMLException = require("../src/exception");
import * as chai from 'chai';
const assert = chai.assert;
import {safeLoad as loadYaml} from '../src/index';
import ast=require("../src/yamlAST");
export interface TestError{
message: string
line: number
column: number
isWarning:boolean
}
export function testErrors(input:string,expectedErrors: TestError[]) {
let errorsMap: {[key:string]:boolean} = {};
for(let e of expectedErrors){
let key = `${e.message} at line ${e.line} column ${e.column}`;
if(e.isWarning){
key += " (warning)";
}
errorsMap[key] = true;
}
let ast = safeLoad(input);
if(!ast){
assert.fail("The parser has failed to load YAML AST");
}
let actualErrors = ast.errors;
if(actualErrors.length==0 && expectedErrors.length==0){
assert(true);
return;
}
let unexpectedErrorsMap: {[key:string]:YAMLException} = {};
for(let e of actualErrors){
let key = `${e.reason} at line ${e.mark.line} column ${e.mark.column}`;
if(e.isWarning){
key += " (warning)";
}
if(!errorsMap[key]){
unexpectedErrorsMap[key] = e;
}
else{
delete errorsMap[key];
}
}
let missingErrors = Object.keys(errorsMap);
let unexpectedErrorKeys = Object.keys(unexpectedErrorsMap);
if(missingErrors.length==0 && unexpectedErrorKeys.length==0){
assert(true);
return;
}
let messageComponents:string[] = [];
if(unexpectedErrorKeys.length>0) {
messageComponents.push(`Unexpected errors:\n${unexpectedErrorKeys.join('\n')}`);
}
if(missingErrors.length>0){
messageComponents.push(`Missing errors:\n${missingErrors.join('\n')}`);
}
let testFailureMessage = `\n${messageComponents.join("\n\n")}`;
assert(false,testFailureMessage);
};
export function safeLoad(input):ast.YAMLNode {
return loadYaml(input, {})
}
+44
View File
@@ -0,0 +1,44 @@
import * as YAML from '../src/'
export interface NodeVisitor {
visitScalar(node: YAML.YAMLScalar);
visitMapping(node: YAML.YAMLMapping);
visitSequence(node: YAML.YAMLSequence);
visitMap(node: YAML.YamlMap);
visitAnchorRef(node: YAML.YAMLAnchorReference);
visitIncludeRef(node: YAML.YAMLNode);
}
export abstract class AbstractVisitor implements NodeVisitor {
// Needed in lieu of `accept` method on nodes
accept(node: YAML.YAMLNode) {
switch (node.kind) {
case YAML.Kind.SCALAR: {
return this.visitScalar(<YAML.YAMLScalar>node);
}
case YAML.Kind.MAP: {
return this.visitMap(<YAML.YamlMap>node);
}
case YAML.Kind.MAPPING: {
return this.visitMapping(<YAML.YAMLMapping>node);
}
case YAML.Kind.SEQ: {
return this.visitSequence(<YAML.YAMLSequence>node);
}
case YAML.Kind.ANCHOR_REF: {
return this.visitAnchorRef(<YAML.YAMLAnchorReference>node);
}
case YAML.Kind.INCLUDE_REF: {
return this.visitIncludeRef(node);
}
}
throw new Error(`Kind, ${node.kind} not implemented.`);
}
abstract visitScalar(node: YAML.YAMLScalar);
abstract visitMapping(node: YAML.YAMLMapping);
abstract visitSequence(node: YAML.YAMLSequence);
abstract visitMap(node: YAML.YamlMap);
abstract visitAnchorRef(node: YAML.YAMLAnchorReference);
abstract visitIncludeRef(node: YAML.YAMLNode);
}
+43
View File
@@ -0,0 +1,43 @@
import util = require("./testUtil");
suite('YAML Syntax', () => {
suite('Warnings for tab symbols', () => {
test('test 001', function () {
testErrors(
"schemas:\n" +
"\tsch1:\n",
[
{
line: 1,
column: 0,
message: "Using tabs can lead to unpredictable results",
isWarning: true
}
]
);
});
test('test 002', function () {
testErrors(
"level0:\n" +
" level1:\n" +
" level2:\n" +
" \t level3:\n",
[
{
line: 3,
column: 2,
message: "Using tabs can lead to unpredictable results",
isWarning: true
}
]
);
});
});
});
function testErrors(input:string,expectedErrors: util.TestError[]) {
util.testErrors(input, expectedErrors);
}