Skip to content

Commit

Permalink
chore: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mdonnalley committed Mar 1, 2022
1 parent dec69c4 commit a520509
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/interfaces/config.ts
Expand Up @@ -97,6 +97,8 @@ export interface Config {
runCommand<T = unknown>(id: string, argv?: string[]): Promise<T>;
runCommand<T = unknown>(id: string, argv?: string[], cachedCommand?: Command.Plugin): Promise<T>;
runHook<T extends keyof Hooks>(event: T, opts: Hooks[T]['options'], timeout?: number): Promise<Hook.Result<Hooks[T]['return']>>;
getAllCommandIDs(): string[]
getAllCommands(): Command.Plugin[]
findCommand(id: string, opts: { must: true }): Command.Plugin;
findCommand(id: string, opts?: { must: boolean }): Command.Plugin | undefined;
findTopic(id: string, opts: { must: true }): Topic;
Expand Down
258 changes: 258 additions & 0 deletions test/config/config.flexible.test.ts
@@ -0,0 +1,258 @@
import * as os from 'os'
import * as path from 'path'

import {Config} from '../../src/config/config'
import {Plugin as IPlugin} from '../../src/interfaces'
import {Command as ICommand} from '../../src/interfaces'

import {expect, fancy} from './test'
import {Flags, Interfaces} from '../../src'

interface Options {
pjson?: any;
homedir?: string;
platform?: string;
env?: {[k: string]: string};
commandIds?: string[];
types?: string[];
}

// @ts-expect-error
class MyComandClass implements ICommand.Class {
_base = ''

aliases: string[] = []

hidden = false

id = 'foo:bar'

flags = {}

new(): ICommand.Instance {
return {
_run(): Promise<any> {
return Promise.resolve()
}}
}

run(): PromiseLike<any> {
return Promise.resolve()
}
}

describe('Config with flexible taxonomy', () => {
const testConfig = ({
homedir = '/my/home',
platform = 'darwin',
env = {},
commandIds = ['foo:bar', 'foo:baz'],
types = [],
}: Options = {}) => {
let test = fancy
.resetConfig()
.env(env, {clear: true})
.stub(os, 'homedir', () => path.join(homedir))
.stub(os, 'platform', () => platform)

const load = async (): Promise<void> => {}
const findCommand = async (): Promise<ICommand.Class> => {
return new MyComandClass() as unknown as ICommand.Class
}

const commandPluginA: ICommand.Plugin = {
strict: false,
aliases: [],
args: [],
flags: {
flagA: Flags.boolean({char: 'a'}),
},
hidden: false,
id: commandIds[0],
async load(): Promise<ICommand.Class> {
return new MyComandClass() as unknown as ICommand.Class
},
pluginType: types[0] ?? 'core',
pluginAlias: '@My/plugina',
}
const commandPluginB: ICommand.Plugin = {
strict: false,
aliases: [],
args: [],
flags: {
flagB: Flags.boolean({}),
},
hidden: false,
id: commandIds[1],
async load(): Promise<ICommand.Class> {
return new MyComandClass() as unknown as ICommand.Class
},
pluginType: types[1] ?? 'core',
pluginAlias: '@My/pluginb',
}
const hooks = {}
const pluginA: IPlugin = {
load,
findCommand,
name: '@My/plugina',
alias: '@My/plugina',
commands: [commandPluginA],
_base: '',
pjson: {} as any,
commandIDs: [commandIds[0]] as string[],
root: '',
version: '0.0.0',
type: types[0] ?? 'core',
hooks,
topics: [],
valid: true,
tag: 'tag',
}

const pluginB: IPlugin = {
load,
findCommand,
name: '@My/pluginb',
alias: '@My/pluginb',
commands: [commandPluginB],
_base: '',
pjson: {} as any,
commandIDs: [commandIds[1]] as string[],
root: '',
version: '0.0.0',
type: types[1] ?? 'core',
hooks,
topics: [],
valid: true,
tag: 'tag',
}
const plugins: IPlugin[] = [pluginA, pluginB]

test = test.add('config', async () => {
const config = await Config.load()
config.flexibleTaxonomy = true
config.plugins = plugins
config.pjson.oclif.plugins = ['@My/pluginb', '@My/plugina']
config.pjson.dependencies = {'@My/pluginb': '0.0.0', '@My/plugina': '0.0.0'}
for (const plugin of config.plugins) {
// @ts-expect-error private method
config.loadCommands(plugin)
// @ts-expect-error private method
config.loadTopics(plugin)
}

return config
})
// @ts-ignore
return {
it(expectation: string, fn: (config: Interfaces.Config) => any) {
test
.do(({config}) => fn(config))
.it(expectation)
return this
},
}
}

testConfig()
.it('has no subtopics', config => {
expect(config.topics.length).to.equal(0)
})
.it('has populated permutation index', config => {
// @ts-expect-error because private member
const permutationIndex = config.permutationIndex
expect(permutationIndex.get('foo')).to.deep.equal(new Set(['foo:bar', 'foo:baz']))
expect(permutationIndex.get('foo:bar')).to.deep.equal(new Set(['foo:bar']))
expect(permutationIndex.get('bar')).to.deep.equal(new Set(['foo:bar']))
expect(permutationIndex.get('bar:foo')).to.deep.equal(new Set(['foo:bar']))
expect(permutationIndex.get('foo:baz')).to.deep.equal(new Set(['foo:baz']))
expect(permutationIndex.get('baz')).to.deep.equal(new Set(['foo:baz']))
expect(permutationIndex.get('baz:foo')).to.deep.equal(new Set(['foo:baz']))
})
.it('has populated command index', config => {
// @ts-expect-error because private member
const commandIndex = config.commandIndex
expect(commandIndex.has('foo:bar')).to.be.true
expect(commandIndex.has('foo:baz')).to.be.true
})
.it('has all command id permutations', config => {
expect(config.getAllCommandIDs()).to.deep.equal([
'foo:bar',
'foo:baz',
'bar:foo',
'baz:foo',
])
})

describe('findMatches', () => {
testConfig()
.it('finds command that contains a partial id', config => {
const matches = config.findMatches('foo', [])
expect(matches.length).to.equal(2)
})
.it('finds command that contains a partial id and matching full flag', config => {
const matches = config.findMatches('foo', ['--flagB'])
expect(matches.length).to.equal(1)
expect(matches[0].id).to.equal('foo:baz')
})
.it('finds command that contains a partial id and matching short flag', config => {
const matches = config.findMatches('foo', ['-a'])
expect(matches.length).to.equal(1)
expect(matches[0].id).to.equal('foo:bar')
})
})

describe('findCommand', () => {
testConfig()
.it('find command with no duplicates', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('pluginAlias', '@My/plugina')
})

testConfig({commandIds: ['foo:bar', 'foo:bar']})
.it('find command with duplicates and choose the one that appears first in oclif.plugins', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('pluginAlias', '@My/pluginb')
})

testConfig({types: ['core', 'user']})
.it('find command with no duplicates core/user', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('id', 'foo:bar')
expect(command).to.have.property('pluginType', 'core')
expect(command).to.have.property('pluginAlias', '@My/plugina')
})

testConfig({types: ['user', 'core']})
.it('find command with no duplicates user/core', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('id', 'foo:bar')
expect(command).to.have.property('pluginType', 'user')
expect(command).to.have.property('pluginAlias', '@My/plugina')
})

testConfig({commandIds: ['foo:bar', 'foo:bar'], types: ['core', 'user']})
.it('find command with duplicates core/user', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('id', 'foo:bar')
expect(command).to.have.property('pluginType', 'core')
expect(command).to.have.property('pluginAlias', '@My/plugina')
})

testConfig({commandIds: ['foo:bar', 'foo:bar'], types: ['user', 'core']})
.it('find command with duplicates user/core', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('id', 'foo:bar')
expect(command).to.have.property('pluginType', 'core')
expect(command).to.have.property('pluginAlias', '@My/pluginb')
})

testConfig({commandIds: ['foo:bar', 'foo:bar'], types: ['user', 'user']})
.it('find command with duplicates user/user', config => {
const command = config.findCommand('foo:bar', {must: true})
expect(command).to.have.property('id', 'foo:bar')
expect(command).to.have.property('pluginType', 'user')
expect(command).to.have.property('pluginAlias', '@My/plugina')
})
})
})
34 changes: 34 additions & 0 deletions test/config/util.test.ts
@@ -0,0 +1,34 @@
import {expect, test} from '@oclif/test'
import {collectUsableIds, getCommandIdPermutations} from '../../src/config/util'

describe('util', () => {
describe('collectUsableIds', () => {
test
.it('returns all usable command ids', async () => {
const ids = collectUsableIds(['foo:bar:baz', 'one:two:three'])
expect(ids).to.deep.equal([
'foo',
'foo:bar',
'foo:bar:baz',
'one',
'one:two',
'one:two:three',
])
})
})

describe('getCommandIdPermutations', () => {
test
.it('returns all usable command ids', async () => {
const permutations = getCommandIdPermutations('foo:bar:baz')
expect(permutations).to.deep.equal([
'foo:bar:baz',
'bar:foo:baz',
'bar:baz:foo',
'foo:baz:bar',
'baz:foo:bar',
'baz:bar:foo',
])
})
})
})

0 comments on commit a520509

Please sign in to comment.