text: 'use strict'
  
  const t = require('tap')
  const test = t.test
  const Fastify = require('..')
  const sget = require('simple-get').concat
  const http = require('http')
  const split = require('split2')
  
  test('Should register a versioned route', t => {
    t.plan(11)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.x'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.2.x'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.2.0'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.2.1'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('Should register the same route with different versions', t => {
    t.plan(8)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send('1.2.0')
      }
    })
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.3.0',
      handler: (req, reply) => {
        reply.send('1.3.0')
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.x'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 200)
      t.strictEqual(res.payload, '1.3.0')
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.2.x'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 200)
      t.strictEqual(res.payload, '1.2.0')
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '2.x'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('The versioned route should take precedence', t => {
    t.plan(3)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      handler: (req, reply) => {
        reply.send({ winter: 'is coming' })
      }
    })
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.x'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
      t.strictEqual(res.statusCode, 200)
    })
  })
  
  test('Versioned route but not version header should return a 404', t => {
    t.plan(2)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/'
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('Should register a versioned route', t => {
    t.plan(6)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.listen(0, err => {
      t.error(err)
      fastify.server.unref()
  
      sget({
        method: 'GET',
        url: 'http://localhost:' + fastify.server.address().port,
        headers: {
          'Accept-Version': '1.x'
        }
      }, (err, response, body) => {
        t.error(err)
        t.strictEqual(response.statusCode, 200)
        t.deepEqual(JSON.parse(body), { hello: 'world' })
      })
  
      sget({
        method: 'GET',
        url: 'http://localhost:' + fastify.server.address().port,
        headers: {
          'Accept-Version': '2.x'
        }
      }, (err, response, body) => {
        t.error(err)
        t.strictEqual(response.statusCode, 404)
      })
    })
  })
  
  test('Shorthand route declaration', t => {
    t.plan(5)
    const fastify = Fastify()
  
    fastify.get('/', { version: '1.2.0' }, (req, reply) => {
      reply.send({ hello: 'world' })
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.x'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '1.2.1'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('The not found handler should not use the Accept-Version header', t => {
    t.plan(4)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.setNotFoundHandler(function (req, reply) {
      t.notOk(req.headers['accept-version'])
      reply.code(404).send('not found handler')
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': '2.x'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(res.payload, 'not found handler')
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('Bad accept version (inject)', t => {
    t.plan(4)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': 'a.b.c'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        'Accept-Version': 12
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  
  test('Bas accept version (server)', t => {
    t.plan(5)
    const fastify = Fastify()
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: '1.2.0',
      handler: (req, reply) => {
        reply.send({ hello: 'world' })
      }
    })
  
    fastify.listen(0, err => {
      t.error(err)
      fastify.server.unref()
  
      sget({
        method: 'GET',
        url: 'http://localhost:' + fastify.server.address().port,
        headers: {
          'Accept-Version': 'a.b.c'
        }
      }, (err, response, body) => {
        t.error(err)
        t.strictEqual(response.statusCode, 404)
      })
  
      sget({
        method: 'GET',
        url: 'http://localhost:' + fastify.server.address().port,
        headers: {
          'Accept-Version': 12
        }
      }, (err, response, body) => {
        t.error(err)
        t.strictEqual(response.statusCode, 404)
      })
    })
  })
  
  test('test log stream', t => {
    t.plan(3)
    const stream = split(JSON.parse)
    const fastify = Fastify({
      logger: {
        stream: stream,
        level: 'info'
      }
    })
  
    fastify.get('/', { version: '1.2.0' }, function (req, reply) {
      reply.send(new Error('kaboom'))
    })
  
    fastify.listen(0, err => {
      t.error(err)
      fastify.server.unref()
  
      http.get({
        hostname: 'localhost',
        port: fastify.server.address().port,
        path: '/',
        method: 'GET',
        headers: {
          'Accept-Version': '1.x'
        }
      })
  
      stream.once('data', listenAtLogLine => {
        stream.once('data', line => {
          t.equal(line.req.version, '1.x')
          stream.once('data', line => {
            t.equal(line.req.version, '1.x')
          })
        })
      })
    })
  })
  
  test('Should register a versioned route with custome versioning strategy', t => {
    t.plan(8)
  
    const versioning = {
      storage: function () {
        let versions = {}
        return {
          get: (version) => { return versions[version] || null },
          set: (version, store) => { versions[version] = store },
          del: (version) => { delete versions[version] },
          empty: () => { versions = {} }
        }
      },
      deriveVersion: (req, ctx) => {
        return req.headers['accept']
      }
    }
  
    const fastify = Fastify({ versioning })
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: 'application/vnd.example.api+json;version=2',
      handler: (req, reply) => {
        reply.send({ hello: 'from route v2' })
      }
    })
  
    fastify.route({
      method: 'GET',
      url: '/',
      version: 'application/vnd.example.api+json;version=3',
      handler: (req, reply) => {
        reply.send({ hello: 'from route v3' })
      }
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        Accept: 'application/vnd.example.api+json;version=2'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'from route v2' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        Accept: 'application/vnd.example.api+json;version=3'
      }
    }, (err, res) => {
      t.error(err)
      t.deepEqual(JSON.parse(res.payload), { hello: 'from route v3' })
      t.strictEqual(res.statusCode, 200)
    })
  
    fastify.inject({
      method: 'GET',
      url: '/',
      headers: {
        Accept: 'application/vnd.example.api+json;version=4'
      }
    }, (err, res) => {
      t.error(err)
      t.strictEqual(res.statusCode, 404)
    })
  })
  