Files
privacy.sexy/tests/unit/application/Parser/CategoryParser.spec.ts
undergroundwires 44d79e2c9a Add more and unify tests for absent object cases
- Unify test data for nonexistence of an object/string and collection.
- Introduce more test through adding missing test data to existing tests.
- Improve logic for checking absence of values to match tests.
- Add missing tests for absent value validation.
- Update documentation to include shared test functionality.
2022-01-21 22:34:11 +01:00

166 lines
6.7 KiB
TypeScript

import 'mocha';
import { expect } from 'chai';
import { parseCategory } from '@/application/Parser/CategoryParser';
import { parseScript } from '@/application/Parser/Script/ScriptParser';
import { parseDocUrls } from '@/application/Parser/DocumentationParser';
import { ScriptCompilerStub } from '@tests/unit/stubs/ScriptCompilerStub';
import { ScriptDataStub } from '@tests/unit/stubs/ScriptDataStub';
import { CategoryCollectionParseContextStub } from '@tests/unit/stubs/CategoryCollectionParseContextStub';
import { LanguageSyntaxStub } from '@tests/unit/stubs/LanguageSyntaxStub';
import { CategoryDataStub } from '@tests/unit/stubs/CategoryDataStub';
import { itEachAbsentCollectionValue, itEachAbsentObjectValue, itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
describe('CategoryParser', () => {
describe('parseCategory', () => {
describe('invalid category', () => {
describe('throws when category data is absent', () => {
itEachAbsentObjectValue((absentValue) => {
// arrange
const expectedMessage = 'missing category';
const category = absentValue;
const context = new CategoryCollectionParseContextStub();
// act
const act = () => parseCategory(category, context);
// assert
expect(act).to.throw(expectedMessage);
});
});
describe('throws when category children is absent', () => {
itEachAbsentCollectionValue((absentValue) => {
// arrange
const categoryName = 'test';
const expectedMessage = `category has no children: "${categoryName}"`;
const category = new CategoryDataStub()
.withName(categoryName)
.withChildren(absentValue);
const context = new CategoryCollectionParseContextStub();
// act
const act = () => parseCategory(category, context);
// assert
expect(act).to.throw(expectedMessage);
});
});
describe('throws when name is absent', () => {
itEachAbsentStringValue((absentValue) => {
// arrange
const expectedMessage = 'category has no name';
const category = new CategoryDataStub()
.withName(absentValue);
const context = new CategoryCollectionParseContextStub();
// act
const act = () => parseCategory(category, context);
// assert
expect(act).to.throw(expectedMessage);
});
});
});
describe('throws when context is absent', () => {
itEachAbsentObjectValue((absentValue) => {
// arrange
const expectedError = 'missing context';
const context = absentValue;
const category = new CategoryDataStub();
// act
const act = () => parseCategory(category, context);
// assert
expect(act).to.throw(expectedError);
});
});
it('returns expected docs', () => {
// arrange
const url = 'https://privacy.sexy';
const expected = parseDocUrls({ docs: url });
const category = new CategoryDataStub()
.withDocs(url);
const context = new CategoryCollectionParseContextStub();
// act
const actual = parseCategory(category, context).documentationUrls;
// assert
expect(actual).to.deep.equal(expected);
});
describe('parses expected subscript', () => {
it('single script with code', () => {
// arrange
const script = ScriptDataStub.createWithCode();
const context = new CategoryCollectionParseContextStub();
const expected = [parseScript(script, context)];
const category = new CategoryDataStub()
.withChildren([script]);
// act
const actual = parseCategory(category, context).scripts;
// assert
expect(actual).to.deep.equal(expected);
});
it('single script with function call', () => {
// arrange
const script = ScriptDataStub.createWithCall();
const compiler = new ScriptCompilerStub()
.withCompileAbility(script);
const context = new CategoryCollectionParseContextStub()
.withCompiler(compiler);
const expected = [parseScript(script, context)];
const category = new CategoryDataStub()
.withChildren([script]);
// act
const actual = parseCategory(category, context).scripts;
// assert
expect(actual).to.deep.equal(expected);
});
it('multiple scripts with function call and code', () => {
// arrange
const callableScript = ScriptDataStub.createWithCall();
const scripts = [callableScript, ScriptDataStub.createWithCode()];
const category = new CategoryDataStub()
.withChildren(scripts);
const compiler = new ScriptCompilerStub()
.withCompileAbility(callableScript);
const context = new CategoryCollectionParseContextStub()
.withCompiler(compiler);
const expected = scripts.map((script) => parseScript(script, context));
// act
const actual = parseCategory(category, context).scripts;
// assert
expect(actual).to.deep.equal(expected);
});
it('script is created with right context', () => { // test through script validation logic
// arrange
const commentDelimiter = 'should not throw';
const duplicatedCode = `${commentDelimiter} duplicate-line\n${commentDelimiter} duplicate-line`;
const parseContext = new CategoryCollectionParseContextStub()
.withSyntax(new LanguageSyntaxStub().withCommentDelimiters(commentDelimiter));
const category = new CategoryDataStub()
.withChildren([
new CategoryDataStub()
.withName('sub-category')
.withChildren([
ScriptDataStub
.createWithoutCallOrCodes()
.withCode(duplicatedCode),
]),
]);
// act
const act = () => parseCategory(category, parseContext).scripts;
// assert
expect(act).to.not.throw();
});
});
it('returns expected subcategories', () => {
// arrange
const expected = [new CategoryDataStub()
.withName('test category')
.withChildren([ScriptDataStub.createWithCode()]),
];
const category = new CategoryDataStub()
.withName('category name')
.withChildren(expected);
const context = new CategoryCollectionParseContextStub();
// act
const actual = parseCategory(category, context).subCategories;
// assert
expect(actual).to.have.lengthOf(1);
expect(actual[0].name).to.equal(expected[0].category);
expect(actual[0].scripts.length).to.equal(expected[0].children.length);
});
});
});