Skip to content

Commit

Permalink
Add tests to cover error cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
drakedevel committed Jan 20, 2024
1 parent be5654c commit d9f4cd2
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 5 deletions.
16 changes: 11 additions & 5 deletions tests/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,17 @@ describe('Template', () => {
});
});

test('#lookup works', () => {
template.parse('{{ define "foo" }}{{ end }}');
const fooTemplate = template.lookup('foo');
expect(fooTemplate).toBeInstanceOf(Template);
expect(fooTemplate?.name()).toBe('foo');
describe('#lookup', () => {
it('works', () => {
template.parse('{{ define "foo" }}{{ end }}');
const fooTemplate = template.lookup('foo');
expect(fooTemplate).toBeInstanceOf(Template);
expect(fooTemplate?.name()).toBe('foo');
});

it('returns undefined on invalid templates', () => {
expect(template.lookup('invalid')).toBeUndefined();
});
});

test('#name works', () => {
Expand Down
144 changes: 144 additions & 0 deletions tests/error_handling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import * as binding from '..';
import {Template} from '..';

describe('Template', () => {
let template: Template;

beforeEach(() => {
template = new Template('test_template');
});

test('constructor handles incorrect argument types', () => {
// @ts-expect-error: testing bad arguments
expect(() => new Template(0)).toThrow('A string was expected');
});

test('#delims handles incorrect argument types', () => {
// @ts-expect-error: testing bad arguments
expect(() => template.delims(0, '')).toThrow('A string was expected');
// @ts-expect-error: testing bad arguments
expect(() => template.delims('', 0)).toThrow('A string was expected');
});

const unaryMethods = [
'executeTemplateString',
'lookup',
'new',
'option',
'parse',
'parseFiles',
'parseGlob',
] as const;
test.each(unaryMethods)('#%s handles incorrect argument types', (name) => {
// @ts-expect-error: testing bad arguments
expect(() => template[name](0)).toThrow('A string was expected');
});

const staticMethods = ['parseFiles', 'parseGlob'] as const;
test.each(staticMethods)('static .%s handles incorrect argument types', (name) => {
// @ts-expect-error: testing bad arguments
expect(() => Template[name](0)).toThrow('A string was expected');
});

describe('#executeString', () => {
it('handles unsupported value types', () => {
expect(() => template.executeString(Symbol())).toThrow('Unsupported value type');
expect(() => template.executeString([Symbol()])).toThrow('Unsupported value type');
expect(() => template.executeString({a: Symbol()})).toThrow('Unsupported value type');
});

it('propagates errors from property accesses', () => {
const err = new Error();
const badObj = {};
Object.defineProperty(badObj, 'poison', {enumerable: true, get() { throw err; }});
expect(() => template.executeString(badObj)).toThrow(err);
const badArr: unknown[] = [];
Object.defineProperty(badArr, 0, {enumerable: true, get() { throw err; }});
expect(() => template.executeString(badArr)).toThrow(err);
});
});

describe('#executeTemplateString', () => {
it('handles unsupported value types', () => {
expect(() => template.executeTemplateString('', Symbol())).toThrow('Unsupported value type');
});

it('handles invalid template names', () => {
expect(() => template.executeTemplateString('invalid')).toThrow('no template "invalid"');
});
});

describe('#funcs', () => {
it('captures panics', () => {
expect(() => template.funcs({ ['']() {} })).toThrowErrorMatchingInlineSnapshot(`"caught panic: function name "" is not a valid identifier"`);
});

it('ignores undefined functions', () => {
// @ts-expect-error: testing invalid args
template.funcs({ myFunc() { return 'hello' }, myUndef: undefined });
expect(template.parse('{{ myFunc }}').executeString()).toBe('hello');
expect(() => template.parse('{{ myUndef }}')).toThrow('function "myUndef" not defined');
});

it('handles incorrect argument types', () => {
// @ts-expect-error: testing invalid args
expect(() => template.funcs(null)).toThrow('Cannot convert undefined or null to object');
});

it('handles invalid function types', () => {
// @ts-expect-error: testing invalid args
expect(() => template.funcs({ invalid: 42 })).toThrowErrorMatchingInlineSnapshot(`"Key 'invalid' is not a function"`);
});

it('handles un-mappable Go types', () => {
const myFunc = jest.fn();
template.funcs({myFunc}).parse('{{ myFunc 123i }}');
expect(() => template.executeString()).toThrow("can't convert Go value of type complex128");
// TODO: List and map with Sprig functions
expect(myFunc).not.toHaveBeenCalled();
});

it('propagates errors from property accesses', () => {
const err = new Error();
const funcs = {};
Object.defineProperty(funcs, 'poison', {enumerable: true, get() { throw err; }});
expect(() => template.funcs(funcs)).toThrow(err);
});
});

test('#parseFiles propagates errors', () => {
expect(() => template.parseFiles('/invalid/path/to/template/file')).toThrow('no such file or directory');
});

test('#parseGlob propagates errors', () => {
expect(() => template.parseGlob('/invalid/path/to/template/dir/*')).toThrow('pattern matches no files');
});

test('static .parseFiles propagates errors', () => {
expect(() => Template.parseFiles('/invalid/path/to/template/file')).toThrow('no such file or directory');
});

test('static .parseGlob propagates errors', () => {
expect(() => Template.parseGlob('/invalid/path/to/template/dir/*')).toThrow('pattern matches no files');
});

test('methods handle missing arguments', () => {
// @ts-expect-error: testing missing argument
expect(() => template.parse()).toThrow('A string was expected');
});

test('methods handle invalid this value', () => {
// @ts-expect-error: testing missing argument
const unwrapped = new Template();
expect(() => unwrapped.parse('')).toThrow('missing or invalid type tag');
});

test('static methods handle missing arguments', () => {
// @ts-expect-error: testing missing argument
expect(() => Template.parseGlob()).toThrow('A string was expected');
});
});

test('helpers handle unsupported value types', () => {
expect(() => binding.htmlEscaper(Symbol())).toThrow('Unsupported value type');
});

0 comments on commit d9f4cd2

Please sign in to comment.