text: const t = require('tap')
  const Node = require('../lib/node.js')
  const Link = require('../lib/link.js')
  const Edge = require('../lib/edge.js')
  const printable = require('../lib/printable.js')
  const util = require('util')
  
  t.cleanSnapshot = str => str
    // normalize paths
    .split(process.cwd()).join('{CWD}')
    .replace(/[A-Z]:/g, '')
    .replace(/\\+/g, '/')
    // FIXME: once we drop support to node10 we can remove some of this
    .replace(/:\n? +/g, ':')
    .replace(/\n +/g, '\n')
    .replace(/\n\}/g, ' }')
    .replace(/\n\]/g, ']')
    .replace(/\n\[/g, '[')
    .replace(/\n\{\n/g, ' { ')
    .replace(/Map\([0-9]\)/g, 'Map')
    .replace(/Set\([0-9]\)/g, 'Set')
    .replace(/:\n *Map/g, ':Map')
    .replace(/:\n *Set/g, ':Set')
    .replace(/ArboristNode /g, '')
    .replace(/Edge /g, '')
    .replace(/ *([[\]{}]) */g, '$1')
  
  t.test('printable Node', t => {
    t.test('extraneous tree', t => {
      const tree = new Node({
        name: 'printable-node',
        pkg: {
          name: 'printable-node',
          version: '1.1.1',
          dependencies: { prod: '1.x', b: '', missing: '' },
        },
        path: '/home/user/projects/root',
        realpath: '/home/user/projects/root',
        children: [{
          pkg: {
            name: 'prod',
            version: '1.2.3',
            dependencies: { meta: '', b: '' },
            peerDependencies: { peer: '' },
          },
          fsChildren: [{
            realpath: '/home/user/projects/root/node_modules/prod/foo',
            path: '/home/user/projects/root/node_modules/prod/foo',
            name: 'foo',
            pkg: { name: 'foo', version: '1.2.3', dependencies: { meta: '' } },
          }, {
            realpath: '/home/user/projects/root/node_modules/prod/bar',
            path: '/home/user/projects/root/node_modules/prod/bar',
            name: 'bar',
            pkg: { name: 'bar', version: '1.0.0' },
          }],
          resolved: 'prod',
          integrity: 'prod',
        }, {
          pkg: {
            name: 'b',
            version: '1.2.3',
          },
          resolved: 'b',
          integrity: 'b',
        }, {
          pkg: {
            name: 'c',
          },
          resolved: 'c',
          integrity: 'c',
        }],
      })
      tree.error = { code: 'ERR', path: '/' }
      tree.edgesOut.get('prod').peerConflicted = true
      t.matchSnapshot(util.inspect(tree, { depth: 6 }),
        'should print human readable representation of node tree')
      t.end()
    })
  
    t.test('variations', t => {
      // manually tweaked variations in the tree to reach for
      // possible different trees output
      const tree = new Node({
        name: 'variations',
        pkg: {
          name: 'variations',
          version: '1.0.0',
          dependencies: { a: '^1.0.0', b: '^1.0.0' },
        },
        extraneous: false,
        path: '/home/user/projects/root',
        realpath: '/home/user/projects/root',
      })
  
      // append nodes
      const a = new Node({
        name: 'a',
        pkg: {
          name: 'a',
          version: '1.1.1',
        },
        path: '/home/users/projects/root/node_modules/a',
        realpath: '/home/users/projects/root/node_modules/a',
        parent: tree,
      })
      a.extraneous = false
      a.dev = true
      a.optional = true
      a.getBundler = () => true
      a.errors = [Object.assign(new Error('ERR'), { code: 'ERR' })]
      const b = new Link({
        name: 'b',
        pkg: {
          name: 'b',
          version: '1.0.0',
        },
        optional: true,
        path: '/home/users/projects/root/c-link',
        realpath: '/home/users/projects/root/c',
        parent: tree,
      })
      const c = new Node({
        name: 'c',
        pkg: { name: 'c', version: '1.0.0' },
        path: '/home/user/projects/root/c',
        realpath: '/home/user/projects/root/c',
        fsParent: tree,
      })
      b.target = c
      b.extraneous = false
      b.dev = false
      b.optional = false
      b.peer = false
      b.errors = [Object.assign(new Error('ERR'), {
        code: 'ERR',
        path: '/home/users/projects/root/node_modules/b',
      })]
  
      // another link to c
      new Link({
        name: 'd',
        realpath: '/home/users/projects/root/c',
        target: c,
        parent: tree,
      })
  
      tree.error = a.errors[0]
  
      t.matchSnapshot(util.inspect(tree, { depth: 6 }),
        'should match non-extraneous tree representation')
      t.end()
    })
  
    t.test('do not recurse forever', t => {
      const flags = {
        extraneous: false,
        dev: false,
        devOptional: false,
        optional: false,
        peer: false,
      }
      const tree = new Node({
        name: 'recursive',
        pkg: {
          name: 'recursive',
          version: '1.0.0',
          dependencies: { a: '^1.0.0', b: '^1.0.0' },
        },
        path: '/home/user/projects/root',
        realpath: '/home/user/projects/root',
        ...flags,
      })
      new Node({
        name: 'a',
        pkg: {
          name: 'a',
          version: '1.2.3',
        },
        parent: tree,
        ...flags,
      })
      const target = new Node({
        fsParent: tree,
        path: tree.path + '/b',
        pkg: {
          name: 'b',
          version: '1.2.3',
          dependencies: { c: '' },
        },
        ...flags,
      })
      const c = new Node({
        parent: target,
        pkg: {
          name: 'c',
          version: '1.2.3',
          dependencies: { b: '9.9.9999', notfound: '' },
        },
        ...flags,
      })
      new Link({
        parent: c,
        target,
        ...flags,
      })
      new Link({
        parent: tree,
        target,
        ...flags,
      })
      const s = util.inspect(printable(tree), { depth: Infinity })
      t.matchSnapshot(s)
      t.end()
    })
    t.end()
  })
  
  t.test('virtual roots are shown with their sourceReference', t => {
    const node = new Node({
      path: '/foo/bar/baz',
      pkg: {
        name: 'baz',
        version: '1.2.3',
      },
    })
    const virtual = new Node({ sourceReference: node })
    t.matchSnapshot(printable(virtual))
    t.end()
  })
  
  t.test('broken links dont break the printing', t => {
    const tree = new Node({
      path: '/home/user/projects/root',
    })
  
    // a link with no target
    const brokenLink = new Link({
      name: 'devnull',
      realpath: '/home/user/projects/root/no/thing/here',
      parent: tree,
    })
    brokenLink.target.root = null
  
    t.matchSnapshot(printable(tree))
    t.end()
  })
  
  t.test('show workspaces in printable node output', t => {
    const tree = new Node({
      path: '/home/user/projects/root',
      pkg: {
        workspaces: ['packages/*'],
      },
    })
    new Edge({
      from: tree,
      type: 'workspace',
      name: 'a',
      spec: 'file:/home/user/projects/root/packages/a',
    })
    new Edge({
      from: tree,
      type: 'workspace',
      name: 'b',
      spec: 'file:/home/user/projects/root/packages/b',
    })
    new Link({
      pkg: {
        name: 'a',
        version: '1.2.3',
      },
      realpath: '/home/user/projects/root/packages/a',
      parent: tree,
    })
    new Link({
      pkg: {
        name: 'b',
        version: '1.2.3',
      },
      realpath: '/home/user/projects/root/packages/b',
      parent: tree,
    })
    tree.workspaces = new Map([
      ['a', tree.children.get('a').realpath],
      ['b', tree.children.get('b').realpath],
    ])
  
    t.matchSnapshot(printable(tree))
    t.end()
  })
  
  t.test('show bundle/shrinkwrap info', t => {
    const tree = new Node({
      path: '/path/to/root',
      pkg: {
        name: 'root',
        version: '1.2.3',
        dependencies: {
          bundler: '',
          wrapper: '',
          a: '1',
          b: '2',
          c: '3',
        },
      },
      children: [
        {
          pkg: {
            name: 'bundler',
            version: '1.2.3',
            bundleDependencies: ['a'],
            dependencies: {
              a: '1',
            },
          },
          children: [
            {
              pkg: { name: 'a', version: '1.2.3' },
              integrity: 'a123',
            },
          ],
        },
        {
          pkg: {
            name: 'wrapper',
            version: '1.2.3',
            dependencies: {
              a: '1',
            },
            _hasShrinkwrap: true,
          },
          hasShrinkwrap: true,
          children: [
            {
              pkg: { name: 'a', version: '1.2.3' },
              integrity: 'a123',
            },
          ],
        },
        {
          pkg: { name: 'a', version: '1.2.3' },
          integrity: 'a123',
        },
        {
          pkg: { name: 'c', version: '3.4.5', dependencies: { a: '1' } },
          children: [
            {
              pkg: { name: 'a', version: '1.2.3' },
              integrity: 'a123',
            },
          ],
        },
        {
          pkg: {
            name: 'b',
            version: '2.3.4',
            dependencies: {
              a: '1',
              c: '2',
              d: '3',
            },
          },
          children: [
            { pkg: { name: 'a', version: '1.9.99' } },
            { pkg: { name: 'e', version: '2.3.4' }, integrity: 'y' },
            {
              pkg: {
                name: 'c',
                version: '2.3.4',
                dependencies: { a: '2' },
              },
              children: [
                {
                  pkg: {
                    name: 'a',
                    version: '2.3.99',
                    dependencies: { e: '2' },
                  },
                  integrity: 'a2399',
                  children: [
                    { pkg: { name: 'e', version: '2.0.1' }, integrity: 'x' },
                  ],
                },
              ],
            },
            {
              pkg: {
                name: 'd',
                version: '3.4.5',
                dependencies: {
                  a: '3',
                },
              },
              children: [{ pkg: { name: 'a', version: '3.4.5' } }],
            },
          ],
        },
        { pkg: { name: 'extraneous', version: '1.2.3' } },
      ],
    })
  
    t.matchSnapshot(printable(tree))
    t.end()
  })
  
  t.test('show overrides', (t) => {
    const flags = {
      extraneous: false,
      dev: false,
      peer: false,
      optional: false,
      devOptional: false,
    }
  
    const tree = new Node({
      path: '/some/path',
      loadOverrides: true,
      pkg: {
        name: 'root',
        version: '1.0.0',
        dependencies: {
          foo: '^1.0.0',
          bar: '^1.0.0',
        },
        overrides: {
          'foo@1': '2.0.0',
          bar: '2.0.0',
        },
      },
      children: [
        { pkg: { name: 'foo', version: '2.0.0' }, ...flags },
        { pkg: { name: 'bar', version: '2.0.0' }, ...flags },
      ],
      ...flags,
    })
  
    t.matchSnapshot(util.inspect(printable(tree), { depth: 5 }))
    t.end()
  })
  