11cb0ef41Sopenharmony_ci// Our coverage mapping means that stuff like this doen't count for coverage.
21cb0ef41Sopenharmony_ci// It does ensure that every command has a usage that renders, contains its
31cb0ef41Sopenharmony_ci// name, a description, and if it has completion it is a function.  That it
41cb0ef41Sopenharmony_ci// renders also ensures that any params we've defined in our commands work.
51cb0ef41Sopenharmony_ciconst t = require('tap')
61cb0ef41Sopenharmony_ciconst util = require('util')
71cb0ef41Sopenharmony_ciconst { load: loadMockNpm } = require('../fixtures/mock-npm.js')
81cb0ef41Sopenharmony_ciconst { commands } = require('../../lib/utils/cmd-list.js')
91cb0ef41Sopenharmony_ciconst BaseCommand = require('../../lib/base-command.js')
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconst isAsyncFn = (v) => typeof v === 'function' && /^\[AsyncFunction:/.test(util.inspect(v))
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cit.test('load each command', async t => {
141cb0ef41Sopenharmony_ci  const counts = {
151cb0ef41Sopenharmony_ci    completion: 0,
161cb0ef41Sopenharmony_ci    ignoreImplicitWorkspace: 0,
171cb0ef41Sopenharmony_ci    workspaces: 0,
181cb0ef41Sopenharmony_ci    noParams: 0,
191cb0ef41Sopenharmony_ci  }
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci  for (const cmd of commands) {
221cb0ef41Sopenharmony_ci    await t.test(cmd, async t => {
231cb0ef41Sopenharmony_ci      const { npm, outputs, cmd: impl } = await loadMockNpm(t, {
241cb0ef41Sopenharmony_ci        command: cmd,
251cb0ef41Sopenharmony_ci        config: { usage: true },
261cb0ef41Sopenharmony_ci      })
271cb0ef41Sopenharmony_ci      const ctor = impl.constructor
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci      t.notOk(impl.completion, 'completion is static, not on instance')
301cb0ef41Sopenharmony_ci      if (ctor.completion) {
311cb0ef41Sopenharmony_ci        t.ok(isAsyncFn(ctor.completion), 'completion is async function')
321cb0ef41Sopenharmony_ci        counts.completion++
331cb0ef41Sopenharmony_ci      }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci      // exec fn
361cb0ef41Sopenharmony_ci      t.ok(isAsyncFn(impl.exec), 'exec is async')
371cb0ef41Sopenharmony_ci      t.ok(impl.exec.length <= 1, 'exec fn has 0 or 1 args')
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci      // workspaces
401cb0ef41Sopenharmony_ci      t.type(ctor.ignoreImplicitWorkspace, 'boolean', 'ctor has ignoreImplictWorkspace boolean')
411cb0ef41Sopenharmony_ci      if (ctor.ignoreImplicitWorkspace !== BaseCommand.ignoreImplicitWorkspace) {
421cb0ef41Sopenharmony_ci        counts.ignoreImplicitWorkspace++
431cb0ef41Sopenharmony_ci      }
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci      t.type(ctor.workspaces, 'boolean', 'ctor has workspaces boolean')
461cb0ef41Sopenharmony_ci      if (ctor.workspaces !== BaseCommand.workspaces) {
471cb0ef41Sopenharmony_ci        counts.workspaces++
481cb0ef41Sopenharmony_ci      }
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci      if (ctor.workspaces) {
511cb0ef41Sopenharmony_ci        t.ok(isAsyncFn(impl.execWorkspaces), 'execWorkspaces is async')
521cb0ef41Sopenharmony_ci        t.ok(impl.exec.length <= 1, 'execWorkspaces fn has 0 or 1 args')
531cb0ef41Sopenharmony_ci      } else {
541cb0ef41Sopenharmony_ci        t.notOk(impl.execWorkspaces, 'has no execWorkspaces fn')
551cb0ef41Sopenharmony_ci      }
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci      // name/desc
581cb0ef41Sopenharmony_ci      t.ok(impl.description, 'implementation has a description')
591cb0ef41Sopenharmony_ci      t.equal(impl.description, ctor.description, 'description is same on instance and ctor')
601cb0ef41Sopenharmony_ci      t.ok(impl.name, 'implementation has a name')
611cb0ef41Sopenharmony_ci      t.equal(impl.name, ctor.name, 'name is same on instance and ctor')
621cb0ef41Sopenharmony_ci      t.equal(cmd, impl.name, 'command list and name are the same')
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci      // params are optional
651cb0ef41Sopenharmony_ci      if (impl.params) {
661cb0ef41Sopenharmony_ci        t.equal(impl.params, ctor.params, 'params is same on instance and ctor')
671cb0ef41Sopenharmony_ci        t.ok(impl.params, 'implementation has a params')
681cb0ef41Sopenharmony_ci      } else {
691cb0ef41Sopenharmony_ci        counts.noParams++
701cb0ef41Sopenharmony_ci      }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci      // usage
731cb0ef41Sopenharmony_ci      t.match(impl.usage, cmd, 'usage contains the command')
741cb0ef41Sopenharmony_ci      await npm.exec(cmd, [])
751cb0ef41Sopenharmony_ci      t.match(outputs[0][0], impl.usage, 'usage is what is output')
761cb0ef41Sopenharmony_ci      t.match(outputs[0][0], ctor.describeUsage, 'usage is what is output')
771cb0ef41Sopenharmony_ci      t.notOk(impl.describeUsage, 'describe usage is only static')
781cb0ef41Sopenharmony_ci    })
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  // make sure refactors dont move or rename these static properties since
821cb0ef41Sopenharmony_ci  // we guard against the tests for them above
831cb0ef41Sopenharmony_ci  t.ok(counts.completion > 0, 'has some completion functions')
841cb0ef41Sopenharmony_ci  t.ok(counts.ignoreImplicitWorkspace > 0, 'has some commands that change ignoreImplicitWorkspace')
851cb0ef41Sopenharmony_ci  t.ok(counts.workspaces > 0, 'has some commands that change workspaces')
861cb0ef41Sopenharmony_ci  t.ok(counts.noParams > 0, 'has some commands that do not have params')
871cb0ef41Sopenharmony_ci})
88