Jerko Steiner 8c732ba91e Install eslint and fix errors
- argparse
- scripts
- tasq
- validator
2019-09-15 15:57:22 +07:00

426 lines
11 KiB
TypeScript

import { arg, argparse } from './argparse'
describe('argparse', () => {
const CMD = 'command'
const exit = jest.fn()
const log = jest.fn()
beforeEach(() => {
exit.mockClear()
log.mockClear()
})
it('parses args', () => {
const args = argparse({
one: arg('string', {required: true}),
two: arg('number', {default: 100}),
four: {
type: 'boolean',
},
}).parse([CMD, '--one', '1', '--two', '2', '--four'])
const one: string = args.one
const two: number = args.two
const four: boolean = args.four
expect(one).toBe('1')
expect(two).toBe(2)
expect(four).toBe(true)
})
describe('boolean', () => {
it('is not required, and is false by default', () => {
const result = argparse({
bool: {
type: 'boolean',
},
}).parse([CMD])
const value: boolean = result.bool
expect(value).toBe(false)
})
it('can be made required', () => {
expect(() => argparse({
bool: {
type: 'boolean',
required: true,
},
}).parse([CMD])).toThrowError(/Missing required args: bool/)
})
it('optionally accepts a true/false value', () => {
const {parse} = argparse({
bool: {
type: 'boolean',
alias: 'b',
},
other: {
type: 'string',
},
})
expect(parse([CMD, '--bool']).bool).toBe(true)
expect(parse([CMD, '--bool', 'false']).bool).toBe(false)
expect(parse([CMD, '--bool', 'true']).bool).toBe(true)
expect(parse([CMD, '--bool', '--other', 'value'])).toEqual({
bool: true,
other: 'value',
})
})
it('can be grouped by shorthand (single dash) notation', () => {
const {parse} = argparse({
a1: {
type: 'boolean',
alias: 'a',
},
b: {
type: 'boolean',
alias: 'c',
},
other: {
type: 'string',
alias: 'o',
},
})
expect(parse([CMD])).toEqual({
a1: false,
b: false,
other: '',
})
expect(parse([CMD, '-ab'])).toEqual({
a1: true,
b: true,
other: '',
})
expect(parse([CMD, '-ca'])).toEqual({
a1: true,
b: true,
other: '',
})
expect(parse([CMD, '-abo', 'test'])).toEqual({
a1: true,
b: true,
other: 'test',
})
expect(() => parse([CMD, '-abo'])).toThrowError(/must be a string: -abo/)
})
})
describe('number', () => {
it('sets to NaN by default', () => {
const {parse} = argparse({
a: {
type: 'number',
},
})
expect(parse([CMD])).toEqual({
a: NaN,
})
expect(() => parse([CMD, '-a'])).toThrowError(/must be a number: -a/)
expect(() => parse([CMD, '-a', 'no-number']))
.toThrowError(/must be a number: -a/)
expect(() => parse([CMD, '--a', 'no-number']))
.toThrowError(/must be a number: --a/)
expect(parse([CMD, '-a', '10'])).toEqual({
a: 10,
})
expect(parse([CMD, '--a', '11'])).toEqual({
a: 11,
})
})
})
describe('choices', () => {
it('can enforce typed choices', () => {
const {parse} = argparse({
choice: arg('string', {
choices: ['a', 'b'],
}),
num: arg('number', {
choices: [1, 2],
}),
})
expect(() => parse([CMD, '--choice', 'c'])).toThrowError(/one of: a, b$/)
expect(() => parse([CMD, '--num', '3']))
.toThrowError(/must be one of: 1, 2$/)
expect(parse([CMD, '--choice', 'a', '--num', '1'])).toEqual({
choice: 'a',
num: 1,
})
expect(parse([CMD, '--choice', 'b', '--num', '2'])).toEqual({
choice: 'b',
num: 2,
})
})
})
describe('string[] and n', () => {
it('has a value of n = 1 by default', () => {
const {parse} = argparse({
value: {
type: 'string[]',
},
help: arg('boolean'),
}, '', exit, log)
expect(parse([CMD]).value).toEqual([])
expect(parse([CMD, '--value', 'one']).value).toEqual(['one'])
parse([CMD, '--help'])
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS]`,
'',
'Options:',
' --value [VALUE]',
' --help boolean',
].join('\n'))
})
it('can be used to extract finite number of values', () => {
const {parse} = argparse({
value: {
type: 'string[]',
n: 3,
},
other: {
type: 'number',
alias: 'o',
},
help: arg('boolean'),
}, '', exit, log)
expect(parse([CMD]).value).toEqual([])
expect(parse([CMD, '--value', 'a', 'b', '--other', '-o', '3'])).toEqual({
value: ['a', 'b', '--other'],
other: 3,
help: false,
})
parse([CMD, '--help'])
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS]`,
'',
'Options:',
' --value [VALUE1 VALUE2 VALUE3]',
' -o, --other number',
' --help boolean',
].join('\n'))
})
it('can be used to collect any remaining arguments when n = "+"', () => {
const {parse} = argparse({
value: arg('string[]', {n: '+', required: true}),
other: arg('number'),
help: arg('boolean'),
}, '', exit, log)
expect(() => parse([CMD])).toThrowError(/Missing required args: value/)
expect(parse([CMD, '--value', 'a', '--other', '3'])).toEqual({
value: ['a', '--other', '3'],
other: NaN,
help: false,
})
expect(parse([CMD, '--other', '2', '--value', 'a', '--other', '3']))
.toEqual({
value: ['a', '--other', '3'],
other: 2,
help: false,
})
parse([CMD, '--help'])
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS]`,
'',
'Options:',
' --value VALUE... (required)',
' --other number',
' --help boolean',
].join('\n'))
})
it('can collect remaining positional arguments when n = "*"', () => {
const {parse} = argparse({
value: arg('string[]', {n: '*', required: true, positional: true}),
other: arg('number'),
help: arg('boolean'),
}, '', exit, log)
expect(parse([CMD, 'a', 'b']).value).toEqual(['a', 'b'])
expect(() => parse([CMD, '--other', '3']).value)
.toThrowError(/Missing.*: value/)
expect(parse([CMD, '--other', '2', '--', '--other', '3'])).toEqual({
value: ['--other', '3'],
other: 2,
help: false,
})
expect(parse([CMD, '--', '--other', '3'])).toEqual({
value: ['--other', '3'],
other: NaN,
help: false,
})
expect(parse([CMD, '--other', '3', 'a', 'b', 'c'])).toEqual({
value: ['a', 'b', 'c'],
other: 3,
help: false,
})
parse([CMD, '--help'])
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS] [VALUE...]`,
'',
'Positional arguments:',
' VALUE string[] (required)',
'',
'Options:',
' --other number',
' --help boolean',
].join('\n'))
})
})
describe('positional', () => {
it('can be defined', () => {
const {parse} = argparse({
a: {
type: 'number',
positional: true,
},
}, '', exit, log)
expect(parse([CMD]).a).toBe(NaN)
expect(parse([CMD, '12']).a).toBe(12)
parse([CMD, '--help'])
expect(log.mock.calls[0][0]).toEqual(`${CMD} [A]
Positional arguments:
A number`)
})
it('works with booleans', () => {
const {parse} = argparse({
a: {
type: 'boolean',
positional: true,
},
})
expect(parse([CMD]).a).toBe(false)
expect(parse([CMD, 'true']).a).toBe(true)
expect(parse([CMD, 'false']).a).toBe(false)
expect(() => parse([CMD, 'invalid'])).toThrowError(/true or false/)
})
it('works with strings', () => {
const {parse} = argparse({
a: {
type: 'string',
positional: true,
},
})
expect(parse([CMD]).a).toBe('')
expect(parse([CMD, 'a']).a).toBe('a')
})
it('works with multiple positionals', () => {
const {parse} = argparse({
a: {
type: 'string',
positional: true,
},
b: {
type: 'string',
positional: true,
},
})
expect(parse([CMD, 'aaa', 'bbb'])).toEqual({
a: 'aaa',
b: 'bbb',
})
})
it('works amongst regular arguments', () => {
const {parse} = argparse({
arg1: {
type: 'string',
},
arg2: {
type: 'number',
positional: true,
},
arg3: {
type: 'string',
},
})
expect(parse([CMD, '--arg1', 'one', '--arg3', 'three', '2'])).toEqual({
arg1: 'one',
arg2: 2,
arg3: 'three',
})
expect(parse([CMD, '2'])).toEqual({
arg1: '',
arg2: 2,
arg3: '',
})
})
})
describe('help', () => {
it('prints help string and exits', () => {
const {parse} = argparse({
one: arg('string'),
two: arg('number'),
three: arg('boolean'),
help: arg('boolean'),
}, 'This command does something', exit, log)
expect(exit.mock.calls.length).toBe(0)
parse([CMD, '--help'])
expect(exit.mock.calls.length).toBe(1)
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS]`,
'',
'This command does something',
'',
'Options:',
' --one string',
' --two number',
' --three boolean',
' --help boolean',
].join('\n'))
})
it('returns help string with alias, description, and samples', () => {
const {parse} = argparse({
one: arg('string', {
description: 'first argument',
required: true,
choices: ['choice-1', 'choice-2'],
default: 'choice-1',
alias: 'o',
}),
two: arg('number', {
positional: true,
required: true,
}),
three: arg('number', {
positional: true,
}),
help: arg('boolean'),
}, '', exit, log)
expect(exit.mock.calls.length).toBe(0)
parse([CMD, '--help'])
expect(exit.mock.calls.length).toBe(1)
expect(log.mock.calls[0][0]).toEqual([
`${CMD} [OPTIONS] TWO [THREE]`,
'',
'Positional arguments:',
' TWO number (required)',
' THREE number',
'',
'Options:',
' -o, --one string first argument ' +
'(required, default: choice-1, choices: choice-1,choice-2)',
' --help boolean',
].join('\n'))
})
})
it('throws when required args missing', () => {
expect(() => argparse({
one: {
type: 'string',
required: true,
},
}).parse([CMD])).toThrowError(/missing required/i)
})
it('throws when arg type is unknown', () => {
expect(() => argparse({
a: {
type: 'test',
} as any, // eslint-disable-line
}).parse([CMD, '-a'])).toThrowError(/Unknown type: test/)
})
})