<commit_before>/**
 * The combo plugin for http concat module
 */
(function(seajs) {

  var comboHash = {}
  var cachedModules = seajs.cache
  var configData = seajs.config.data

  initCombo()
  seajs.on("config", initCombo)

  function initCombo() {
    detachEvents()

    if (configData.debug) {
      seajs.log("Combo is turned off in debug mode")
      return
    }

    seajs.on("load", setComboHash)
    seajs.on("fetch", setRequestUri)
  }

  function detachEvents() {
    seajs.off("load", setComboHash)
    seajs.off("fetch", setRequestUri)
  }

  function setComboHash(uris) {
    var needComboUris = []
    var comboExcludes = configData.comboExcludes

    forEach(uris, function(uri) {
      var mod = cachedModules[uri]

      // Remove fetching and fetched uris, excluded uris, combo uris
      if (mod.status < mod.constructor.STATUS.FETCHING &&
          (!comboExcludes || !comboExcludes.test(uri)) &&
          !isComboUri(uri)) {
        needComboUris.push(uri)
      }
    })

    if (needComboUris.length > 1) {
      paths2hash(uris2paths(needComboUris))
    }
  }

  function setRequestUri(data) {
    var uri = data.uri
    data.requestUri = comboHash[uri] || uri
  }

  // Helpers

  var forEach = [].forEach ?
      function(arr, fn) {
        arr.forEach(fn)
      } :
      function(arr, fn) {
        for (var i = 0; i < arr.length; i++) {
          fn(arr[i], i, arr)
        }
      }

  function uris2paths(uris) {
    return meta2paths(uris2meta(uris))
  }

  // [
  //   "http://example.com/p/a.js",
  //   "https://example2.com/b.js",
  //   "http://example.com/p/c/d.js",
  //   "http://example.com/p/c/e.js"
  // ]
  // ==>
  // {
  //   "http__example.com": {
  //                          "p": {
  //                                 "a.js": { __KEYS: [] },
  //                                 "c": {
  //                                        "d.js": { __KEYS: [] },
  //                                        "e.js": { __KEYS: [] },
  //                                        __KEYS: ["d.js", "e.js"]
  //                                 },
  //                                 __KEYS: ["a.js", "c"]
  //                               },
  //                          __KEYS: ["p"]
  //                        },
  //   "https__example2.com": {
  //                            "b.js": { __KEYS: [] },
  //                            _KEYS: ["b.js"]
  //                          },
  //   __KEYS: ["http__example.com", "https__example2.com"]
  // }
  function uris2meta(uris) {
    var meta = { __KEYS: [] }

    forEach(uris, function(uri) {
      var parts = uri.replace("://", "__").split("/")
      var m = meta

      forEach(parts, function(part) {
        if (!m[part]) {
          m[part] = { __KEYS: [] }
          m.__KEYS.push(part)
        }
        m = m[part]
      })

    })

    return meta
  }

  // {
  //   "http__example.com": {
  //                          "p": {
  //                                 "a.js": { __KEYS: [] },
  //                                 "c": {
  //                                        "d.js": { __KEYS: [] },
  //                                        "e.js": { __KEYS: [] },
  //                                        __KEYS: ["d.js", "e.js"]
  //                                 },
  //                                 __KEYS: ["a.js", "c"]
  //                               },
  //                          __KEYS: ["p"]
  //                        },
  //   "https__example2.com": {
  //                            "b.js": { __KEYS: [] },
  //                            _KEYS: ["b.js"]
  //                          },
  //   __KEYS: ["http__example.com", "https__example2.com"]
  // }
  // ==>
  // [
  //   ["http://example.com/p", ["a.js", "c/d.js", "c/e.js"]]
  // ]
  function meta2paths(meta) {
    var paths = []

    forEach(meta.__KEYS, function(part) {
      var root = part
      var m = meta[part]
      var KEYS = m.__KEYS

      while(KEYS.length === 1) {
        root += "/" + KEYS[0]
        m = m[KEYS[0]]
        KEYS = m.__KEYS
      }

      if (KEYS.length) {
        paths.push([root.replace("__", "://"), meta2arr(m)])
      }
    })

    return paths
  }

  // {
  //   "a.js": { __KEYS: [] },
  //   "c": {
  //          "d.js": { __KEYS: [] },
  //          "e.js": { __KEYS: [] },
  //          __KEYS: ["d.js", "e.js"]
  //        },
  //   __KEYS: ["a.js", "c"]
  // }
  // ==>
  // [
  //   "a.js", "c/d.js", "c/e.js"
  // ]
  function meta2arr(meta) {
    var arr = []

    forEach(meta.__KEYS, function(key) {
      var r = meta2arr(meta[key])

      // key = "c"
      // r = ["d.js", "e.js"]
      if (r.length) {
        forEach(r, function(part) {
          arr.push(key + "/" + part)
        })
      }
      else {
        arr.push(key)
      }
    })

    return arr
  }

  // [
  //   [ "http://example.com/p", ["a.js", "c/d.js", "c/e.js", "a.css", "b.css"] ]
  // ]
  // ==>
  //
  // a hash cache
  //
  // "http://example.com/p/a.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/c/d.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/c/e.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/a.css"  ==> "http://example.com/p/??a.css,b.css"
  // "http://example.com/p/b.css"  ==> "http://example.com/p/??a.css,b.css"
  //
  function paths2hash(paths) {
    var comboSyntax = configData.comboSyntax || ["??", ","]

    forEach(paths, function(path) {
      var root = path[0] + "/"
      var group = files2group(path[1])

      forEach(group, function(files) {
        var comboPath = root + comboSyntax[0] + files.join(comboSyntax[1])

        // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url
        if (comboPath.length > 2000) {
          throw new Error("The combo url is too long: " + comboPath)
        }

        forEach(files, function(part) {
          comboHash[root + part] = comboPath
        })
      })

    })

    return comboHash
  }

  //
  //  ["a.js", "c/d.js", "c/e.js", "a.css", "b.css", "z"]
  // ==>
  //  [ ["a.js", "c/d.js", "c/e.js"], ["a.css", "b.css"] ]
  //
  function files2group(files) {
    var group = []
    var hash = {}

    forEach(files, function(file) {
      var ext = getExt(file)
      if (ext) {
        (hash[ext] || (hash[ext] = [])).push(file)
      }
    })

    for (var ext in hash) {
      if (hash.hasOwnProperty(ext)) {
        group.push(hash[ext])
      }
    }

    return group
  }

  function getExt(file) {
    var p = file.lastIndexOf(".")
    return p >= 0 ? file.substring(p) : ""
  }

  function isComboUri(uri) {
    var comboSyntax = configData.comboSyntax || ["??", ","]
    var s1 = comboSyntax[0]
    var s2 = comboSyntax[1]

    return s1 && uri.indexOf(s1) > 0 || s2 && uri.indexOf(s2) > 0
  }

  // For test
  if (configData.test) {
    var test = seajs.test || (seajs.test = {})
    test.uris2paths = uris2paths
    test.paths2hash = paths2hash
  }

})(seajs);

<commit_msg>Make debug mode do not affect combo plugin<commit_after>/**
 * The combo plugin for http concat module
 */
(function(seajs) {

  var comboHash = {}
  var cachedModules = seajs.cache
  var configData = seajs.config.data

  seajs.on("load", setComboHash)
  seajs.on("fetch", setRequestUri)

  function setComboHash(uris) {
    var needComboUris = []
    var comboExcludes = configData.comboExcludes

    forEach(uris, function(uri) {
      var mod = cachedModules[uri]

      // Remove fetching and fetched uris, excluded uris, combo uris
      if (mod.status < mod.constructor.STATUS.FETCHING &&
          (!comboExcludes || !comboExcludes.test(uri)) &&
          !isComboUri(uri)) {
        needComboUris.push(uri)
      }
    })

    if (needComboUris.length > 1) {
      paths2hash(uris2paths(needComboUris))
    }
  }

  function setRequestUri(data) {
    var uri = data.uri
    data.requestUri = comboHash[uri] || uri
  }

  // Helpers

  var forEach = [].forEach ?
      function(arr, fn) {
        arr.forEach(fn)
      } :
      function(arr, fn) {
        for (var i = 0; i < arr.length; i++) {
          fn(arr[i], i, arr)
        }
      }

  function uris2paths(uris) {
    return meta2paths(uris2meta(uris))
  }

  // [
  //   "http://example.com/p/a.js",
  //   "https://example2.com/b.js",
  //   "http://example.com/p/c/d.js",
  //   "http://example.com/p/c/e.js"
  // ]
  // ==>
  // {
  //   "http__example.com": {
  //                          "p": {
  //                                 "a.js": { __KEYS: [] },
  //                                 "c": {
  //                                        "d.js": { __KEYS: [] },
  //                                        "e.js": { __KEYS: [] },
  //                                        __KEYS: ["d.js", "e.js"]
  //                                 },
  //                                 __KEYS: ["a.js", "c"]
  //                               },
  //                          __KEYS: ["p"]
  //                        },
  //   "https__example2.com": {
  //                            "b.js": { __KEYS: [] },
  //                            _KEYS: ["b.js"]
  //                          },
  //   __KEYS: ["http__example.com", "https__example2.com"]
  // }
  function uris2meta(uris) {
    var meta = { __KEYS: [] }

    forEach(uris, function(uri) {
      var parts = uri.replace("://", "__").split("/")
      var m = meta

      forEach(parts, function(part) {
        if (!m[part]) {
          m[part] = { __KEYS: [] }
          m.__KEYS.push(part)
        }
        m = m[part]
      })

    })

    return meta
  }

  // {
  //   "http__example.com": {
  //                          "p": {
  //                                 "a.js": { __KEYS: [] },
  //                                 "c": {
  //                                        "d.js": { __KEYS: [] },
  //                                        "e.js": { __KEYS: [] },
  //                                        __KEYS: ["d.js", "e.js"]
  //                                 },
  //                                 __KEYS: ["a.js", "c"]
  //                               },
  //                          __KEYS: ["p"]
  //                        },
  //   "https__example2.com": {
  //                            "b.js": { __KEYS: [] },
  //                            _KEYS: ["b.js"]
  //                          },
  //   __KEYS: ["http__example.com", "https__example2.com"]
  // }
  // ==>
  // [
  //   ["http://example.com/p", ["a.js", "c/d.js", "c/e.js"]]
  // ]
  function meta2paths(meta) {
    var paths = []

    forEach(meta.__KEYS, function(part) {
      var root = part
      var m = meta[part]
      var KEYS = m.__KEYS

      while(KEYS.length === 1) {
        root += "/" + KEYS[0]
        m = m[KEYS[0]]
        KEYS = m.__KEYS
      }

      if (KEYS.length) {
        paths.push([root.replace("__", "://"), meta2arr(m)])
      }
    })

    return paths
  }

  // {
  //   "a.js": { __KEYS: [] },
  //   "c": {
  //          "d.js": { __KEYS: [] },
  //          "e.js": { __KEYS: [] },
  //          __KEYS: ["d.js", "e.js"]
  //        },
  //   __KEYS: ["a.js", "c"]
  // }
  // ==>
  // [
  //   "a.js", "c/d.js", "c/e.js"
  // ]
  function meta2arr(meta) {
    var arr = []

    forEach(meta.__KEYS, function(key) {
      var r = meta2arr(meta[key])

      // key = "c"
      // r = ["d.js", "e.js"]
      if (r.length) {
        forEach(r, function(part) {
          arr.push(key + "/" + part)
        })
      }
      else {
        arr.push(key)
      }
    })

    return arr
  }

  // [
  //   [ "http://example.com/p", ["a.js", "c/d.js", "c/e.js", "a.css", "b.css"] ]
  // ]
  // ==>
  //
  // a hash cache
  //
  // "http://example.com/p/a.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/c/d.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/c/e.js"  ==> "http://example.com/p/??a.js,c/d.js,c/e.js"
  // "http://example.com/p/a.css"  ==> "http://example.com/p/??a.css,b.css"
  // "http://example.com/p/b.css"  ==> "http://example.com/p/??a.css,b.css"
  //
  function paths2hash(paths) {
    var comboSyntax = configData.comboSyntax || ["??", ","]

    forEach(paths, function(path) {
      var root = path[0] + "/"
      var group = files2group(path[1])

      forEach(group, function(files) {
        var comboPath = root + comboSyntax[0] + files.join(comboSyntax[1])

        // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url
        if (comboPath.length > 2000) {
          throw new Error("The combo url is too long: " + comboPath)
        }

        forEach(files, function(part) {
          comboHash[root + part] = comboPath
        })
      })

    })

    return comboHash
  }

  //
  //  ["a.js", "c/d.js", "c/e.js", "a.css", "b.css", "z"]
  // ==>
  //  [ ["a.js", "c/d.js", "c/e.js"], ["a.css", "b.css"] ]
  //
  function files2group(files) {
    var group = []
    var hash = {}

    forEach(files, function(file) {
      var ext = getExt(file)
      if (ext) {
        (hash[ext] || (hash[ext] = [])).push(file)
      }
    })

    for (var ext in hash) {
      if (hash.hasOwnProperty(ext)) {
        group.push(hash[ext])
      }
    }

    return group
  }

  function getExt(file) {
    var p = file.lastIndexOf(".")
    return p >= 0 ? file.substring(p) : ""
  }

  function isComboUri(uri) {
    var comboSyntax = configData.comboSyntax || ["??", ","]
    var s1 = comboSyntax[0]
    var s2 = comboSyntax[1]

    return s1 && uri.indexOf(s1) > 0 || s2 && uri.indexOf(s2) > 0
  }

  // For test
  if (configData.test) {
    var test = seajs.test || (seajs.test = {})
    test.uris2paths = uris2paths
    test.paths2hash = paths2hash
  }

})(seajs);

<|endoftext|>


<commit_before>var canvas = content.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
//document.documentElement.appendChild(canvas);

function makeScreenShot(pos, maxSize, backgroundColor) {
  console.log("shooting area", pos.x, pos.y, "w/h", pos.w, pos.h, !!maxSize);
  if (maxSize) {
    canvas.width = maxSize.w;
    canvas.height = maxSize.h;
  } else {
    canvas.width = pos.w;
    canvas.height = pos.h;
  }
  let ctx = canvas.getContext('2d');
  if (maxSize) {
    ctx.scale(maxSize.w / pos.w, maxSize.h / pos.h);
  }
  backgroundColor = backgroundColor || "#000";
  ctx.drawWindow(content, pos.x, pos.y, pos.w, pos.h, backgroundColor);
  return canvas.toDataURL();
}

addMessageListener("pageshot@pageshot:request-screenshot", function (event) {
  var result;
  try {
    result = {
      imageUrl: makeScreenShot(event.data.pos, event.data.maxSize, event.data.backgroundColor)
    };
  } catch (e) {
    result = {
      error: {
        name: e.name,
        description: e+""
      }
    };
  }
  sendAsyncMessage("pageshot@pageshot:get-screenshot", result);
});
<commit_msg>Look into the viewer iframe in the framescript, what we previously did in the addon code<commit_after>var canvas = content.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');

function getWindow() {
  if (content.document.getElementById("frame")) {
    return content.document.getElementById("frame").contentWindow;
  }
  return content;
}

function makeScreenShot(pos, maxSize, backgroundColor) {
  console.log("shooting area", pos.x, pos.y, "w/h", pos.w, pos.h, !!maxSize);
  if (maxSize) {
    canvas.width = maxSize.w;
    canvas.height = maxSize.h;
  } else {
    canvas.width = pos.w;
    canvas.height = pos.h;
  }
  let ctx = canvas.getContext('2d');
  if (maxSize) {
    ctx.scale(maxSize.w / pos.w, maxSize.h / pos.h);
  }
  backgroundColor = backgroundColor || "#000";
  ctx.drawWindow(getWindow(), pos.x, pos.y, pos.w, pos.h, backgroundColor);
  return canvas.toDataURL();
}

addMessageListener("pageshot@pageshot:request-screenshot", function (event) {
  var result;
  try {
    result = {
      imageUrl: makeScreenShot(event.data.pos, event.data.maxSize, event.data.backgroundColor)
    };
  } catch (e) {
    console.log("Error making shot:", e);
    console.trace();
    result = {
      error: {
        name: e.name,
        description: e+""
      }
    };
  }
  sendAsyncMessage("pageshot@pageshot:get-screenshot", result);
});
<|endoftext|>


<commit_before>const reviews = (state=[], action) => {
  switch (action.type) {
    case 'ADD_REVIEW':
      return [
        ...state, {
          id: action.id,
          item_id: action.item_id,
          reviewer: action.reviewer,
          text: action.text,
          rating: action.rating,
          flag: false
        }
      ]
    case 'DELETE_REVIEW':
      return state.filter(review => review.id !== action.id);
    case 'FLAG_REVIEW':
      return state.map(review => review.id === action.id ? Object.assign({}, review, { flag: action.flag}): review)
    case 'RATE_REVIEW':
      return state.map(review => review.id === action.id ? {...review, rating: action.rating }: review)
    default:
      return state;
  }
}

export default reviews;
<commit_msg>[Chore] Use types from file<commit_after>import types from '../../actionTypes';

const reviews = (state=[], action) => {
  switch (action.type) {
    case types.reviews.ADD_REVIEW:
      return [
        ...state, {
          id: action.id,
          item_id: action.item_id,
          reviewer: action.reviewer,
          text: action.text,
          rating: action.rating,
          flag: false
        }
      ]
    case types.reviews.DELETE_REVIEW:
      return state.filter(review => review.id !== action.id);
    case types.reviews.FLAG_REVIEW:
      return state.map(review => review.id === action.id ? Object.assign({}, review, { flag: action.flag}): review)
    case types.reviews.RATE_REVIEW:
      return state.map(review => review.id === action.id ? {...review, rating: action.rating }: review)
    default:
      return sretate;
  }
}

export default reviews;
<|endoftext|>


<commit_before>var should = require('should'),
    Geocoder = require('../lib/W3W.Geocoder'),
    API_KEY = process.env.W3W_API_KEY ||  null;

describe('what3words API Wrapper', function() {
    var w3w;

    describe('Initialising', function() {
        it('without any arguments', function() {
            (function() {
                w3w = new Geocoder();
            }).should.throw();
        });

        it('with a valid API KEY', function() {
            (function() {
                w3w = new Geocoder({
                    apiKey: API_KEY
                });
                w3w.getLanguages({});
            }).should.not.throw();
        });

        it('with additional arguments', function() {
            w3w = new Geocoder({
                apiKey: API_KEY,
                language: 'ru',
                userAgent: 'custom'
            });

            w3w.getLanguage().should.be.exactly('ru').and.be.a.String;
            w3w.getUserAgent().should.be.exactly('custom').and.be.a.String;
            w3w.getEndpoint().should.be.exactly('https://api.what3words.com/v2/').and.be.a.String;
        });
    });

    describe('API responses', function() {
        beforeEach(function(done) {
            w3w = new Geocoder({
                apiKey: API_KEY
            });
            done();
        });

        it('should return all languages', function(done) {
            w3w.getLanguages({}).then(function(res) {
                //res.should.eql(['de', 'en', 'es', 'fr', 'it', 'pt', 'ru', 'sv', 'sw', 'tr']);
                //regarding evolving languages just check this is an array
                res.should.be.a.array;
                res.length.should.be.greaterThan(0);
                done();
            });
        });

        it('should be able to forward geocode (translate 3 word address to coordinates)', function(done) {
            w3w.forward({
                addr: 'prom.cape.pump'
            }).then(function(res) {
                res.should.eql('51.484463,-0.195405').and.be.a.String;
                done();
            });
        });

        it('should be able to forward geocode with full response (translate 3 word address to coordinates)', function(done) {
            w3w.forward({
                addr: 'prom.cape.pump',
                full: true
            }).then(function(res) {
                res.should.have.property('words');
                res.words.should.eql('prom.cape.pump').and.be.a.String;
                res.should.have.property('geometry');
                res.geometry.should.have.property('lat');
                res.geometry.should.have.property('lng');
                res.geometry.lat.should.eql(51.484463);
                res.geometry.lng.should.eql(-0.195405);
                done();
            });
        });

        it('should be able to forward geocode in v1 legacy mode (translate 3 word address to coordinates)', function(done) {
            w3w.wordsToPosition({
                addr: 'prom.cape.pump'
            }).then(function(res) {
                res.should.eql('51.484463,-0.195405').and.be.a.String;
                done();
            });
        });

        it('should be able to reverse geocode (translate coordinates to 3 word address)', function(done) {
            w3w.reverse({
                coords: '51.484463,-0.195405'
            }).then(function(res) {
                res.should.eql('prom.cape.pump').and.be.a.String;
                done();
            });
        });

        it('should be able to reverse geocode with full response (translate coordinates to 3 word address)', function(done) {
            w3w.reverse({
                coords: '51.484463,-0.195405',
                full: true
            }).then(function(res) {
                res.should.have.property('words');
                res.words.should.eql('prom.cape.pump').and.be.a.String;
                res.should.have.property('geometry');
                res.geometry.should.have.property('lat');
                res.geometry.should.have.property('lng');
                res.geometry.lat.should.eql(51.484463);
                res.geometry.lng.should.eql(-0.195405);
                done();
            });
        });

        it('should be able to reverse geocode in v1 legacy mode (translate coordinates to 3 word address)', function(done) {
            w3w.positionToWords({
                coords: '51.484463,-0.195405'
            }).then(function(res) {
                res.should.eql('prom.cape.pump').and.be.a.String;
                done();
            });
        });

        it('should be able to autosuggest 3 word addresses', function(done) {
            w3w.autosuggest({
                addr: 'plan.clips.a'
            }).then(function(res) {
                res.should.be.json;
                res.suggestions.should.be.array;
                done();
            });
        });

        it('should be able to return a blend', function(done) {
            w3w.standardBlend({
                addr: 'plan.clips.a'
            }).then(function(res) {
                res.should.be.json;
                res.blends.should.be.array;
                done();
            });
        });

        it('should be able return a grid', function(done) {
            w3w.grid({
                bbox: '52.208867,0.117540,52.207988,0.116126'
            }).then(function(res) {
                res.should.be.json;
                res.lines.should.be.array;
                done();
            });
        });
    });
});
<commit_msg>uses chai.should and adds a forward geocode test with accent<commit_after>// jshint -W030
var should = require('chai').should(),
  Geocoder = require('../lib/W3W.Geocoder'),
  API_KEY = process.env.W3W_API_KEY ||  null;

describe('what3words API Wrapper', function() {
  var w3w;

  describe('Initialising', function() {
    it('without any arguments', function() {
      (function() {
        w3w = new Geocoder();
      }).should.throw();
    });

    it('with a valid API KEY', function() {
      (function() {
        w3w = new Geocoder({
          apiKey: API_KEY
        });
        w3w.getLanguages({});
      }).should.not.throw();
    });

    it('with additional arguments', function() {
      w3w = new Geocoder({
        apiKey: API_KEY,
        language: 'ru',
        userAgent: 'custom'
      });

      w3w.getLanguage().should.be.equal('ru').and.be.a.String;
      w3w.getUserAgent().should.be.equal('custom').and.be.a.String;
      w3w.getEndpoint().should.be.equal('https://api.what3words.com/v2/').and.be.a.String;
    });
  });

  describe('API responses', function() {
    beforeEach(function(done) {
      w3w = new Geocoder({
        apiKey: API_KEY
      });
      done();
    });

    it('should return all languages', function(done) {
      w3w.languages({}).then(function(res) {
        //res.should.eql(['de', 'en', 'es', 'fr', 'it', 'pt', 'ru', 'sv', 'sw', 'tr']);
        //regarding evolving languages just check this is an array
        res.should.be.a.array;
        res.length.should.be.greaterThan(0);
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should return all languages (legacy)', function(done) {
      w3w.getLanguages({}).then(function(res) {
        //res.should.eql(['de', 'en', 'es', 'fr', 'it', 'pt', 'ru', 'sv', 'sw', 'tr']);
        //regarding evolving languages just check this is an array
        res.should.be.a.array;
        res.length.should.be.greaterThan(0);
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to forward geocode (translate 3 word address to coordinates)', function(done) {
      w3w.forward({
        addr: 'prom.cape.pump'
      }).then(function(res) {
        res.should.eql('51.484463,-0.195405').and.be.a.String;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to forward geocode with full response (translate 3 word address to coordinates)', function(done) {
      w3w.forward({
        addr: 'prom.cape.pump',
        full: true
      }).then(function(res) {
        res.should.have.property('words');
        res.words.should.eql('prom.cape.pump').and.be.a.String;
        res.should.have.property('geometry');
        res.geometry.should.have.property('lat');
        res.geometry.should.have.property('lng');
        res.geometry.lat.should.eql(51.484463);
        res.geometry.lng.should.eql(-0.195405);
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to forward geocode french with full response (translate 3 word address to coordinates)', function(done) {
      w3w.forward({
        addr: 'concevoir.époque.amasser',
        lang: 'fr',
        full: true
      }).then(function(res) {
        res.should.have.property('words');
        res.words.should.eql('concevoir.époque.amasser').and.be.a.String;
        res.should.have.property('geometry');
        res.geometry.should.have.property('lat');
        res.geometry.should.have.property('lng');
        res.geometry.lat.should.eql(51.484463);
        res.geometry.lng.should.eql(-0.195405);
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to forward geocode in v1 legacy mode (translate 3 word address to coordinates)', function(done) {
      w3w.wordsToPosition({
        addr: 'prom.cape.pump'
      }).then(function(res) {
        res.should.eql('51.484463,-0.195405').and.be.a.String;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to reverse geocode (translate coordinates to 3 word address)', function(done) {
      w3w.reverse({
        coords: '51.484463,-0.195405'
      }).then(function(res) {
        res.should.eql('prom.cape.pump').and.be.a.String;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to reverse geocode with full response (translate coordinates to 3 word address)', function(done) {
      w3w.reverse({
        coords: '51.484463,-0.195405',
        full: true
      }).then(function(res) {
        res.should.have.property('words');
        res.words.should.eql('prom.cape.pump').and.be.a.String;
        res.should.have.property('geometry');
        res.geometry.should.have.property('lat');
        res.geometry.should.have.property('lng');
        res.geometry.lat.should.eql(51.484463);
        res.geometry.lng.should.eql(-0.195405);
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to reverse geocode in v1 legacy mode (translate coordinates to 3 word address)', function(done) {
      w3w.positionToWords({
        coords: '51.484463,-0.195405'
      }).then(function(res) {
        res.should.eql('prom.cape.pump').and.be.a.String;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to autosuggest 3 word addresses', function(done) {
      w3w.autosuggest({
        addr: 'plan.clips.a'
      }).then(function(res) {
        res.should.be.json;
        res.suggestions.should.be.array;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able to return a blend', function(done) {
      w3w.standardBlend({
        addr: 'plan.clips.a'
      }).then(function(res) {
        res.should.be.json;
        res.blends.should.be.array;
        done();
      }).catch(function(err) {
        done(err);
      });
    });

    it('should be able return a grid', function(done) {
      w3w.grid({
        bbox: '52.208867,0.117540,52.207988,0.116126'
      }).then(function(res) {
        res.should.be.json;
        res.lines.should.be.array;
        done();
      }).catch(function(err) {
        done(err);
      });
    });
  });
});
<|endoftext|>


<commit_before>require('../support/test_helper');

var assert = require('../support/assert');
var TestClient = require('../support/test_client');
var SubstitutionTokens = require('../../lib/windshaft/renderers/torque/substitution_tokens');

describe('torque', function() {

    function createTorqueMapConfig(cartoCss) {
        return {
            version: '1.1.0',
            layers: [
                {
                    type: 'torque',
                    options: {
                        sql: 'select cartodb_id, the_geom from test_table',
                        geom_column: 'the_geom',
                        srid: 4326,
                        cartocss: cartoCss
                    }
                }
            ]
        };
    }

    it("missing required property `-torque-frame-count` from torque layer", function(done) {
        var testClient = new TestClient(createTorqueMapConfig('Map { marker-fill:blue; }'));
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(err.message, "Missing required property '-torque-frame-count' in torque layer CartoCSS");
            done();
        });
    });

    it("missing required property `-torque-resolution` from torque layer", function(done) {
        var testClient = new TestClient(createTorqueMapConfig('Map { -torque-frame-count: 2; }'));
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(err.message, "Missing required property '-torque-resolution' in torque layer CartoCSS");
            done();
        });
    });

    it("missing required property `-torque-aggregation-function` from torque layer", function(done) {
        var testClient = new TestClient(
            createTorqueMapConfig('Map { -torque-frame-count: 2; -torque-resolution: 3; }')
        );
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(
                err.message,
                "Missing required property '-torque-aggregation-function' in torque layer CartoCSS"
            );
            done();
        });
    });

    // See http://github.com/CartoDB/Windshaft/issues/150
    it("unquoted property in torque layer", function(done) {
      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select updated_at as d, cartodb_id as id, the_geom from test_table',
               geom_column: 'the_geom',
               srid: 4326,
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:"d"; ' +
                   '-torque-aggregation-function:count(id); }'
             } }
        ]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unexpected type for property '-torque-aggregation-function', expected string");
            done();
        });
    });

    var validTorqueMapConfig = {
        version: '1.1.0',
        layers: [
            { type: 'torque', options: {
                sql: "select 1 as id, '1970-01-02'::date as d, 'POINT(0 0)'::geometry as the_geom UNION select 2, " +
                    "'1970-01-01'::date, 'POINT(1 1)'::geometry",
                geom_column: 'the_geom',
                cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                    '-torque-aggregation-function:\'count(id)\'; }',
                cartocss_version: '2.0.1'
            } }
        ]
    };

    it("should create a layergroup for valid mapconfig", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.createLayergroup(function (err, layergroup) {
            assert.equal(layergroup.metadata.layers.length, 1);
            var meta = layergroup.metadata;
            assert.ok(meta, 'No metadata in torque MapConfig creation response: ' + layergroup);
            var tm = meta.torque;
            assert.ok(tm, 'No "torque" in metadata:' + JSON.stringify(meta));
            var tm0 = tm[0];
            assert.ok(tm0, 'No layer 0 in "torque" in metadata:' + JSON.stringify(tm));
            var expectedTorqueMetadata = {"start": 0, "end": 86400000, "data_steps": 2, "column_type": "date"};
            assert.deepEqual(tm0, expectedTorqueMetadata);
            assert.deepEqual(meta.layers[0].meta, expectedTorqueMetadata);

            done();
        });
    });

    ['torque.json', 'json.torque'].forEach(function(format) {
        it("should render a torque tile for valid mapconfig, format=" + format, function(done) {
            var expectedTorqueTileAt_0_0_0 = [
                {
                    x__uint8: 43,
                    y__uint8:43,
                    vals__uint8: [1,1],
                    dates__uint16: [0,1]
                }
            ];

            var testClient = new TestClient(validTorqueMapConfig);
            testClient.getTile(0, 0, 0, {layer: 0, format: format}, function(err, torqueTile) {
                assert.ok(!err);
                assert.deepEqual(torqueTile, expectedTorqueTileAt_0_0_0);
                done();
            });
        });
    });

    it("should fail for undefined layer", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.getTile(0, 0, 0, { layer: undefined }, function(err) {
            assert.ok(err);
            assert.equal(err.message, "No 'mapnik' layers in MapConfig");
            done();
        });
    });

    it("should fails for grid.json format", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.getTile(0, 0, 0, {layer: 0, format: 'grid.json'}, function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unsupported format grid.json");
            done();
        });
    });

    // Test that you cannot write to the database from a torque tile request
    //
    // Test for http://github.com/CartoDB/Windshaft/issues/130
    //
    it("database access is read-only", function(done) {
      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 'SRID=3857;POINT(0 0)'::geometry as g, now() as d,* from " +
                   "test_table_inserter(st_setsrid(st_point(0,0),4326),'write')",
               geom_column: 'g',
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                   '-torque-aggregation-function:\'count(*)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };
        var testClient = new TestClient(mapconfig);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "TorqueRenderer: cannot execute INSERT in a read-only transaction");
            done();
        });
    });

    // See http://github.com/CartoDB/Windshaft/issues/164
    it("gives a 500 on database connection refused", function(done) {

      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 1 as id, '1970-01-03'::date as d, 'POINT(0 0)'::geometry as the_geom UNION select 2, " +
                   "'1970-01-01'::date, 'POINT(1 1)'::geometry",
               geom_column: 'the_geom',
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                   '-torque-aggregation-function:\'count(id)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };

        var testClient = new TestClient(mapconfig);
        testClient.createLayergroup({dbport: 1234567}, function(err) {
            assert.ok(err);
            assert.equal(err.message, "TorqueRenderer: cannot connect to the database");
            done();
        });
    });

    it("checks types for torque-specific styles", function(done) {
      var wrongStyle = ["Map {",
                       "-torque-frame-count:512;",
                       "-torque-animation-duration:30;",
                       "-torque-time-attribute:'cartodb_id';",
                       "-torque-aggregation-function:count(cartodb_id);", //unquoted aggregation function
                       "-torque-resolution:4;",
                       "-torque-data-aggregation:linear;",
                       "}"].join(" ");
      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select cartodb_id, the_geom from test_table',
               geom_column: 'the_geom',
               srid: 4326,
               cartocss: wrongStyle
             } }
        ]
      };

        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unexpected type for property '-torque-aggregation-function', expected string");
            done();
        });
    });

    it('query can hold substitution tokens', function(done) {

        var tokens = ['bbox', 'scale_denominator', 'pixel_width', 'pixel_height'].map(function(token) {
            return "!" + token + "! as " + token;
        });

        var sql = 'select *, ' + tokens.join(', ') + ' from test_table';

        var mapConfig = {
            version: '1.1.0',
            layers: [
                {
                    type: 'torque',
                    options: {
                        sql: sql,
                        geom_column: 'the_geom',
                        cartocss: 'Map {' +
                            '-torque-frame-count:2;' +
                            '-torque-resolution:1;' +
                            '-torque-time-attribute:cartodb_id;' +
                            '-torque-aggregation-function:\'count(cartodb_id)\';' +
                            '}',
                        cartocss_version: '2.0.1'
                    }
                }
            ]
        };

        var expectedSubstitutionTokens = [
            {
                bbox: 'ST_MakeEnvelope(0,0,0,0)',
                scale_denominator: '0',
                pixel_width: '1',
                pixel_height: '1'
            },
            {
                bbox: 'ST_MakeEnvelope(-20037508.5,20037508.5,20037508.5,-20037508.5,3857)',
                scale_denominator: 559082268.4151787,
                pixel_width: 156543.03515625,
                pixel_height: 156543.03515625
            }
        ];

        var replaceFn = SubstitutionTokens.replace;
        SubstitutionTokens.replace = function(sql, replaceValues) {
            assert.deepEqual(replaceValues, expectedSubstitutionTokens.shift());
            return replaceFn(sql, replaceValues);
        };

        var testClient = new TestClient(mapConfig);
        testClient.getTile(0, 0, 0, {layer: 0, format: 'torque.json'}, function(err, torqueTile) {
            SubstitutionTokens.replace = replaceFn;

            assert.ok(!err, err);
            assert.deepEqual(torqueTile, [{ x__uint8: 128, y__uint8: 128, vals__uint8: [2,3], dates__uint16: [1,0] }]);

            assert.equal(expectedSubstitutionTokens.length, 0);

            done();
        });
    });
});
<commit_msg>Fix test due introducing steps in torque metadata<commit_after>require('../support/test_helper');

var assert = require('../support/assert');
var TestClient = require('../support/test_client');
var SubstitutionTokens = require('../../lib/windshaft/renderers/torque/substitution_tokens');

describe('torque', function() {

    function createTorqueMapConfig(cartoCss) {
        return {
            version: '1.1.0',
            layers: [
                {
                    type: 'torque',
                    options: {
                        sql: 'select cartodb_id, the_geom from test_table',
                        geom_column: 'the_geom',
                        srid: 4326,
                        cartocss: cartoCss
                    }
                }
            ]
        };
    }

    it("missing required property `-torque-frame-count` from torque layer", function(done) {
        var testClient = new TestClient(createTorqueMapConfig('Map { marker-fill:blue; }'));
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(err.message, "Missing required property '-torque-frame-count' in torque layer CartoCSS");
            done();
        });
    });

    it("missing required property `-torque-resolution` from torque layer", function(done) {
        var testClient = new TestClient(createTorqueMapConfig('Map { -torque-frame-count: 2; }'));
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(err.message, "Missing required property '-torque-resolution' in torque layer CartoCSS");
            done();
        });
    });

    it("missing required property `-torque-aggregation-function` from torque layer", function(done) {
        var testClient = new TestClient(
            createTorqueMapConfig('Map { -torque-frame-count: 2; -torque-resolution: 3; }')
        );
        testClient.createLayergroup(function (err) {
            assert.ok(err);
            assert.equal(
                err.message,
                "Missing required property '-torque-aggregation-function' in torque layer CartoCSS"
            );
            done();
        });
    });

    // See http://github.com/CartoDB/Windshaft/issues/150
    it("unquoted property in torque layer", function(done) {
      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select updated_at as d, cartodb_id as id, the_geom from test_table',
               geom_column: 'the_geom',
               srid: 4326,
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:"d"; ' +
                   '-torque-aggregation-function:count(id); }'
             } }
        ]
      };
        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unexpected type for property '-torque-aggregation-function', expected string");
            done();
        });
    });

    var validTorqueMapConfig = {
        version: '1.1.0',
        layers: [
            { type: 'torque', options: {
                sql: "select 1 as id, '1970-01-02'::date as d, 'POINT(0 0)'::geometry as the_geom UNION select 2, " +
                    "'1970-01-01'::date, 'POINT(1 1)'::geometry",
                geom_column: 'the_geom',
                cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                    '-torque-aggregation-function:\'count(id)\'; }',
                cartocss_version: '2.0.1'
            } }
        ]
    };

    it("should create a layergroup for valid mapconfig", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.createLayergroup(function (err, layergroup) {
            assert.equal(layergroup.metadata.layers.length, 1);
            var meta = layergroup.metadata;
            assert.ok(meta, 'No metadata in torque MapConfig creation response: ' + layergroup);
            var tm = meta.torque;
            assert.ok(tm, 'No "torque" in metadata:' + JSON.stringify(meta));
            var tm0 = tm[0];
            assert.ok(tm0, 'No layer 0 in "torque" in metadata:' + JSON.stringify(tm));
            var expectedTorqueMetadata = {
                "start": 0, "end": 86400000, "steps": 2, "data_steps": 2, "column_type": "date"
            };
            assert.deepEqual(tm0, expectedTorqueMetadata);
            assert.deepEqual(meta.layers[0].meta, expectedTorqueMetadata);

            done();
        });
    });

    ['torque.json', 'json.torque'].forEach(function(format) {
        it("should render a torque tile for valid mapconfig, format=" + format, function(done) {
            var expectedTorqueTileAt_0_0_0 = [
                {
                    x__uint8: 43,
                    y__uint8:43,
                    vals__uint8: [1,1],
                    dates__uint16: [0,1]
                }
            ];

            var testClient = new TestClient(validTorqueMapConfig);
            testClient.getTile(0, 0, 0, {layer: 0, format: format}, function(err, torqueTile) {
                assert.ok(!err);
                assert.deepEqual(torqueTile, expectedTorqueTileAt_0_0_0);
                done();
            });
        });
    });

    it("should fail for undefined layer", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.getTile(0, 0, 0, { layer: undefined }, function(err) {
            assert.ok(err);
            assert.equal(err.message, "No 'mapnik' layers in MapConfig");
            done();
        });
    });

    it("should fails for grid.json format", function(done) {
        var testClient = new TestClient(validTorqueMapConfig);
        testClient.getTile(0, 0, 0, {layer: 0, format: 'grid.json'}, function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unsupported format grid.json");
            done();
        });
    });

    // Test that you cannot write to the database from a torque tile request
    //
    // Test for http://github.com/CartoDB/Windshaft/issues/130
    //
    it("database access is read-only", function(done) {
      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 'SRID=3857;POINT(0 0)'::geometry as g, now() as d,* from " +
                   "test_table_inserter(st_setsrid(st_point(0,0),4326),'write')",
               geom_column: 'g',
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                   '-torque-aggregation-function:\'count(*)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };
        var testClient = new TestClient(mapconfig);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "TorqueRenderer: cannot execute INSERT in a read-only transaction");
            done();
        });
    });

    // See http://github.com/CartoDB/Windshaft/issues/164
    it("gives a 500 on database connection refused", function(done) {

      var mapconfig =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: "select 1 as id, '1970-01-03'::date as d, 'POINT(0 0)'::geometry as the_geom UNION select 2, " +
                   "'1970-01-01'::date, 'POINT(1 1)'::geometry",
               geom_column: 'the_geom',
               cartocss: 'Map { -torque-frame-count:2; -torque-resolution:3; -torque-time-attribute:d; ' +
                   '-torque-aggregation-function:\'count(id)\'; }',
               cartocss_version: '2.0.1'
             } }
        ]
      };

        var testClient = new TestClient(mapconfig);
        testClient.createLayergroup({dbport: 1234567}, function(err) {
            assert.ok(err);
            assert.equal(err.message, "TorqueRenderer: cannot connect to the database");
            done();
        });
    });

    it("checks types for torque-specific styles", function(done) {
      var wrongStyle = ["Map {",
                       "-torque-frame-count:512;",
                       "-torque-animation-duration:30;",
                       "-torque-time-attribute:'cartodb_id';",
                       "-torque-aggregation-function:count(cartodb_id);", //unquoted aggregation function
                       "-torque-resolution:4;",
                       "-torque-data-aggregation:linear;",
                       "}"].join(" ");
      var layergroup =  {
        version: '1.1.0',
        layers: [
           { type: 'torque', options: {
               sql: 'select cartodb_id, the_geom from test_table',
               geom_column: 'the_geom',
               srid: 4326,
               cartocss: wrongStyle
             } }
        ]
      };

        var testClient = new TestClient(layergroup);
        testClient.createLayergroup(function(err) {
            assert.ok(err);
            assert.equal(err.message, "Unexpected type for property '-torque-aggregation-function', expected string");
            done();
        });
    });

    it('query can hold substitution tokens', function(done) {

        var tokens = ['bbox', 'scale_denominator', 'pixel_width', 'pixel_height'].map(function(token) {
            return "!" + token + "! as " + token;
        });

        var sql = 'select *, ' + tokens.join(', ') + ' from test_table';

        var mapConfig = {
            version: '1.1.0',
            layers: [
                {
                    type: 'torque',
                    options: {
                        sql: sql,
                        geom_column: 'the_geom',
                        cartocss: 'Map {' +
                            '-torque-frame-count:2;' +
                            '-torque-resolution:1;' +
                            '-torque-time-attribute:cartodb_id;' +
                            '-torque-aggregation-function:\'count(cartodb_id)\';' +
                            '}',
                        cartocss_version: '2.0.1'
                    }
                }
            ]
        };

        var expectedSubstitutionTokens = [
            {
                bbox: 'ST_MakeEnvelope(0,0,0,0)',
                scale_denominator: '0',
                pixel_width: '1',
                pixel_height: '1'
            },
            {
                bbox: 'ST_MakeEnvelope(-20037508.5,20037508.5,20037508.5,-20037508.5,3857)',
                scale_denominator: 559082268.4151787,
                pixel_width: 156543.03515625,
                pixel_height: 156543.03515625
            }
        ];

        var replaceFn = SubstitutionTokens.replace;
        SubstitutionTokens.replace = function(sql, replaceValues) {
            assert.deepEqual(replaceValues, expectedSubstitutionTokens.shift());
            return replaceFn(sql, replaceValues);
        };

        var testClient = new TestClient(mapConfig);
        testClient.getTile(0, 0, 0, {layer: 0, format: 'torque.json'}, function(err, torqueTile) {
            SubstitutionTokens.replace = replaceFn;

            assert.ok(!err, err);
            assert.deepEqual(torqueTile, [{ x__uint8: 128, y__uint8: 128, vals__uint8: [2,3], dates__uint16: [1,0] }]);

            assert.equal(expectedSubstitutionTokens.length, 0);

            done();
        });
    });
});
<|endoftext|>


<commit_before>"use strict";

import fs from "fs";
import path from "path";

import chai, { expect } from "chai";
import del from "del";
import jwt from "jsonwebtoken";
import restify from "restify";
import sinon from "sinon";
import sinonChai from "sinon-chai";
import stream from "stream";
import supertest from "supertest";

chai.use(sinonChai);

import Application from "../src/application";
import { connection } from "./fixtures";
import Router from "../src/router";

describe("Application", function () {
  let application;

  describe("#map", function () {
    beforeEach(function () {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
    });

    it("gets called with a Router instance", function () {
      application.map(function () {
        expect(this).to.be.an.instanceof(Router);
      });
    });

    it("maps routes to their controller", function (done) {
      application.map(function () {
        this.resource("foo");
      });

      supertest(application.getApp())
        .get("/foos")
        .expect(200)
        .end(done);
    });
  });

  describe("#start", function () {
    const mockRestify = restify.createServer();

    beforeEach(function () {
      sinon.spy(mockRestify, "listen");
      application = new Application({
        app: mockRestify,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: { connection, models: { dir: path.resolve(__dirname, "fixtures/models") }}
      });
    });

    afterEach(function () {
      mockRestify.listen.restore();
    });

    it("starts the application", function () {
      return application.start().then(() => {
        expect(mockRestify.listen).to.have.been.calledWith(3000);
      });
    });
  });

  describe("authentication", function () {
    beforeEach(function () {
      application = new Application({
        authentication: {
          unauthenticated: [/\/resetPassword/]
        },
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });

      application.map(function () {
        this.resource("user");
        this.route("/users/resetPassword", { using: "user:resetPassword", method: "post" });
      });
    });

    it("authenticates users via jwt", function (done) {
      const token = jwt.sign({ foo: "bar" }, "secret");

      supertest(application.getApp())
        .get("/users")
        .set("Authorization", `Bearer ${token}`)
        .expect(200)
        .end(done);
    });

    it("skips 'unauthenticated' routes", function (done) {
      supertest(application.getApp())
        .post("/users/resetPassword")
        .expect(200)
        .end(done);
    });

    it("disables auth if not set by the user", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .expect(200)
        .end(done);
    });

    it("can be enabled by setting to true", function (done) {
      application = new Application({
        authentication: true,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .expect(401)
        .end(done);
    });
  });

  describe("logging", function () {
    let loggingDir, messages, writable;

    beforeEach(function () {
      loggingDir = path.resolve(__dirname, "fixtures/custom-logs");
      messages = [];
      stream.write = message => {
        messages.push(JSON.parse(message));
      };
    });

    afterEach(function () {
      return del([`${loggingDir}/**/*.log`, `!${loggingDir}`]);
    });

    it("allows for a custom directory", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: { dir: loggingDir }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          fs.readdir(loggingDir, (err2, files) => {
            if (err2) { return done(err2); }

            const log = JSON.parse(
              fs.readFileSync(path.join(loggingDir, files.filter(file => file.match(/\.log/))[0])).toString()
            );

            expect(log.res.statusCode).to.eql(200);

            done();
          });
        });
    });

    it("allows for custom request serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            req(req) {
              return { url: req.url }
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].req.url).to.eql("/users");
          expect(messages[0].req).to.not.have.any.keys("httpVersion", "method");
          done();
        });
    });

    it("allows for custom response serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            res(res) {
              return { statusCode: res.statusCode}
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].res.statusCode).to.eql(200);
          expect(messages[0].req).to.not.have.any.keys("headers");
          done();
        });
    });
  });
});
<commit_msg>style(tests): fix lint errors<commit_after>"use strict";

import fs from "fs";
import path from "path";

import chai, { expect } from "chai";
import del from "del";
import jwt from "jsonwebtoken";
import restify from "restify";
import sinon from "sinon";
import sinonChai from "sinon-chai";
import stream from "stream";
import supertest from "supertest";

chai.use(sinonChai);

import Application from "../src/application";
import { connection } from "./fixtures";
import Router from "../src/router";

describe("Application", function () {
  let application;

  describe("#map", function () {
    beforeEach(function () {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
    });

    it("gets called with a Router instance", function () {
      application.map(function () {
        expect(this).to.be.an.instanceof(Router);
      });
    });

    it("maps routes to their controller", function (done) {
      application.map(function () {
        this.resource("foo");
      });

      supertest(application.getApp())
        .get("/foos")
        .expect(200)
        .end(done);
    });
  });

  describe("#start", function () {
    const mockRestify = restify.createServer();

    beforeEach(function () {
      sinon.spy(mockRestify, "listen");
      application = new Application({
        app: mockRestify,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: { connection, models: { dir: path.resolve(__dirname, "fixtures/models") }}
      });
    });

    afterEach(function () {
      mockRestify.listen.restore();
    });

    it("starts the application", function () {
      return application.start().then(() => {
        expect(mockRestify.listen).to.have.been.calledWith(3000);
      });
    });
  });

  describe("authentication", function () {
    beforeEach(function () {
      application = new Application({
        authentication: {
          unauthenticated: [/\/resetPassword/]
        },
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });

      application.map(function () {
        this.resource("user");
        this.route("/users/resetPassword", { using: "user:resetPassword", method: "post" });
      });
    });

    it("authenticates users via jwt", function (done) {
      const token = jwt.sign({ foo: "bar" }, "secret");

      supertest(application.getApp())
        .get("/users")
        .set("Authorization", `Bearer ${token}`)
        .expect(200)
        .end(done);
    });

    it("skips 'unauthenticated' routes", function (done) {
      supertest(application.getApp())
        .post("/users/resetPassword")
        .expect(200)
        .end(done);
    });

    it("disables auth if not set by the user", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });

      supertest(application.getApp())
        .get("/users")
        .expect(200)
        .end(done);
    });

    it("can be enabled by setting to true", function (done) {
      application = new Application({
        authentication: true,
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .expect(401)
        .end(done);
    });
  });

  describe("logging", function () {
    let loggingDir, messages, writable;

    beforeEach(function () {
      loggingDir = path.resolve(__dirname, "fixtures/custom-logs");
      messages = [];
      stream.write = message => {
        messages.push(JSON.parse(message));
      };
    });

    afterEach(function () {
      return del([`${loggingDir}/**/*.log`, `!${loggingDir}`]);
    });

    it("allows for a custom directory", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: { dir: loggingDir }
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          fs.readdir(loggingDir, (err2, files) => {
            if (err2) { return done(err2); }

            const log = JSON.parse(
              fs.readFileSync(path.join(loggingDir, files.filter(file => file.match(/\.log/))[0])).toString()
            );

            expect(log.res.statusCode).to.eql(200);

            done();
          });
        });
    });

    it("allows for custom request serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            req(req) {
              return { url: req.url };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].req.url).to.eql("/users");
          expect(messages[0].req).to.not.have.any.keys("httpVersion", "method");
          done();
        });
    });

    it("allows for custom response serializer", function (done) {
      application = new Application({
        controllers: {
          dir: path.resolve(__dirname, "fixtures", "controllers")
        },
        database: {
          connection,
          models: { dir: path.resolve(__dirname, "fixtures/models") }
        },
        logging: {
          serializers: {
            res(res) {
              return { statusCode: res.statusCode };
            }
          }
        }
      });

      application.logger.addStream({
        type: "stream",
        stream
      });
      application.map(function () {
        this.resource("user");
      });
      supertest(application.getApp())
        .get("/users")
        .end(function (err, res) {
          if (err) { return done(err); }

          expect(messages[0].res.statusCode).to.eql(200);
          expect(messages[0].req).to.not.have.any.keys("headers");
          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>( function() {
	'use strict';

	describe( 'vui.changeTracker', function() {

		var node;

		beforeEach( function () {
			jasmine.addMatchers( d2l.jasmine.matchers );

			node = document.body.appendChild( document.createElement( 'div' ) );
			node.setAttribute( 'data-track-changes', 'true' );

		} );

		afterEach( function() {
			document.body.removeChild( node );
		} );

		describe( 'create', function() {

			var $tracker;

			beforeEach( function () {
				$tracker = $( "

" ).appendTo( node );
			} );

			it( 'binds the input elements using widget method', function() {
				$tracker.vui_changeTracker();
				expect( $tracker.data( 'vui-vui_changeTracker' ) ).toBeDefined();
			} );

		} );

		describe( 'destroy', function() {

			var $tracker;

			beforeEach( function () {
				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();
			} );

			it( 'unbinds input from widget when destroy is called', function() {
				$tracker.vui_changeTracker( 'destroy' );
				expect( $tracker.data( 'vui-vui_changeTracker' ) ).not.toBeDefined();
			} );

		} );

		describe( 'containsChanges', function() {

			var $tracker, $input1, $input2;

			beforeEach( function () {

				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();

				$input1 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

				$input2 = $( "<input class='vui-input' type='text' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

			} );

			it( 'returns false when there are no changes', function() {
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeFalsy();
			} );

			it( 'returns true when there are changes', function() {
				$input1.click();
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeTruthy();
			} );

			it( 'returns false after changed item is removed', function() {
				$input1.click();
				$input1.vui_changeTracking( 'destroy' );
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeFalsy();
			} );

		} );

		describe( 'hasElementChanged', function() {

			var $tracker, $input1, $input2;

			beforeEach( function () {

				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();

				$input1 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

				$input2 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker );

			} );

			it( 'returns false when there are no changes', function() {
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input1.get( 0 ) ) ).toBeFalsy();
			} );

			it( 'returns true when there are changes', function() {
				$input1.click();
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input1.get( 0 ) ) ).toBeTruthy();
			} );

			it( 'returns false when with changes does not have an id', function() {
				$input2.click();
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input2.get( 0 ) ) ).toBeFalsy();
			} );

		} );

		describe( 'isChangesShown', function() {

			var $tracker, $input;

			describe( 'showChanges enabled', function() {

				describe( 'track changes enabled', function() {

					beforeEach( function () {

						$tracker = $( "

" )
							.appendTo( node )
							.vui_changeTracker();

						$input = $( "<input class='vui-input' type='checkbox' />" )
							.appendTo( $tracker )
							.vui_changeTracking();

					} );

					it( 'returns false when there are no changes', function() {
						expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
					} );

					it( 'returns true when there are changes', function() {
						$input.click();
						expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeTruthy();
					} );

				} );

				describe( 'track changes disabled', function() {

					beforeEach( function () {

						node.setAttribute( 'data-track-changes', 'false' );

						$tracker = $( "

" )
							.appendTo( node )
							.vui_changeTracker();

						$input = $( "<input class='vui-input' type='checkbox' />" )
							.appendTo( $tracker )
							.vui_changeTracking();

					} );

					it( 'returns false when there are no changes', function() {
						expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
					} );

					it( 'returns false when there are changes', function() {
						$input.click();
						expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
					} );

				} );

			} );

			describe( 'showChanges disabled', function() {

				beforeEach( function () {

					$tracker = $( "

" )
						.appendTo( node )
						.vui_changeTracker();

					$input = $( "<input class='vui-input' type='checkbox' />" )
						.appendTo( $tracker )
						.vui_changeTracking();

				} );

				it( 'returns false when there are no changes', function() {
					expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
				} );

				it( 'returns false when there are changes', function() {
					$input.click();
					expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
				} );

			} );

		} );

	} );

} )();
<commit_msg>Refactor tests.<commit_after>( function() {
	'use strict';

	describe( 'vui.changeTracker', function() {

		var node;

		beforeEach( function () {
			jasmine.addMatchers( d2l.jasmine.matchers );

			node = document.body.appendChild( document.createElement( 'div' ) );
			node.setAttribute( 'data-track-changes', 'true' );

		} );

		afterEach( function() {
			document.body.removeChild( node );
		} );

		describe( 'create', function() {

			var $tracker;

			beforeEach( function () {
				$tracker = $( "

" ).appendTo( node );
			} );

			it( 'binds the input elements using widget method', function() {
				$tracker.vui_changeTracker();
				expect( $tracker.data( 'vui-vui_changeTracker' ) ).toBeDefined();
			} );

		} );

		describe( 'destroy', function() {

			var $tracker, $input1;

			beforeEach( function () {

				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();

				$input1 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

			} );

			it( 'unbinds input from widget when destroy is called', function() {
				$tracker.vui_changeTracker( 'destroy' );
				expect( $tracker.data( 'vui-vui_changeTracker' ) ).not.toBeDefined();
			} );

			it( 'removes the vui-changed class name from tracker element', function() {
				$input1.click();
				expect( $tracker.get( 0 ) ).toHaveClassName( 'vui-changed' );
				$tracker.vui_changeTracker( 'destroy' );
				expect( $tracker.get( 0 ) ).not.toHaveClassName( 'vui-changed' );
			} );

		} );

		describe( 'containsChanges', function() {

			var $tracker, $input1, $input2;

			beforeEach( function () {

				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();

				$input1 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

				$input2 = $( "<input class='vui-input' type='text' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

			} );

			it( 'returns false when there are no changes', function() {
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeFalsy();
			} );

			it( 'returns true when there are changes', function() {
				$input1.click();
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeTruthy();
			} );

			it( 'returns false after changed item is removed', function() {
				$input1.click();
				$input1.vui_changeTracking( 'destroy' );
				expect( $tracker.vui_changeTracker( 'containsChanges' ) ).toBeFalsy();
			} );

		} );

		describe( 'hasElementChanged', function() {

			var $tracker, $input1, $input2;

			beforeEach( function () {

				$tracker = $( "

" )
					.appendTo( node )
					.vui_changeTracker();

				$input1 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker )
					.vui_changeTracking();

				$input2 = $( "<input class='vui-input' type='checkbox' />" )
					.appendTo( $tracker );

			} );

			it( 'returns false when there are no changes', function() {
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input1.get( 0 ) ) ).toBeFalsy();
			} );

			it( 'returns true when there are changes', function() {
				$input1.click();
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input1.get( 0 ) ) ).toBeTruthy();
			} );

			it( 'returns false when with changes does not have an id', function() {
				$input2.click();
				expect( $tracker.vui_changeTracker( 'hasElementChanged', $input2.get( 0 ) ) ).toBeFalsy();
			} );

		} );

		describe( 'isChangesShown', function() {

			describe( 'not nested', function() {

				var cases = [
					{ trackChanges: true, showChanges: true, expected: true },
					{ trackChanges: false, showChanges: true, expected: false },
					{ trackChanges: true, showChanges: false, expected: false },
					{ trackChanges: false, showChanges: false, expected: false }
				];

				var runSpecs = function( specCase ) {
					describe( 'trackChanges ' + specCase.trackChanges + ' and showChanges ' + specCase.showChanges, function() {

						var $tracker, $input;

						beforeEach( function () {

							if ( !specCase.trackChanges ) {
								node.setAttribute( 'data-track-changes', 'false' );
							}

							$tracker = $( "

" )
								.attr( 'data-show-changes', specCase.showChanges )
								.appendTo( node )
								.vui_changeTracker();

							$input = $( "<input class='vui-input' type='checkbox' />" )
								.appendTo( $tracker )
								.vui_changeTracking();

						} );

						it( 'returns false when there are no changes', function() {
							expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
						} );

						it( 'returns ' + specCase.expected + ' when there are changes', function() {
							$input.click();
							expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBe( specCase.expected );
						} );

					} );
				};

				for( var i=0; i<cases.length; i++ ) {
					runSpecs( cases[i] );
				}

			} );

			describe( 'nested', function() {

				var cases = [
					{ trackChangesOuter: true, trackChangesInner: true, expected: true },
					{ trackChangesOuter: true, trackChangesInner: false, expected: false },
					{ trackChangesOuter: false, trackChangesInner: true, expected: true },
					{ trackChangesOuter: false, trackChangesInner: false, expected: false }
				];

				var runSpecs = function( specCase ) {
					describe( 'outer trackChanges ' + specCase.trackChangesOuter + ' and inner trackChanges ' + specCase.trackChangesInner, function() {

						var $tracker, $input, $innerContainer;

						beforeEach( function () {

							node.setAttribute( 'data-track-changes', specCase.trackChangesOuter );

							$innerContainer = $( "

" )
								.attr( 'data-track-changes', specCase.trackChangesInner )
								.appendTo( node )
								.vui_changeTracker();

							$tracker = $( "

" )
								.attr( 'data-show-changes', specCase.showChanges )
								.appendTo( $innerContainer )
								.vui_changeTracker();

							$input = $( "<input class='vui-input' type='checkbox' />" )
								.appendTo( $tracker )
								.vui_changeTracking();

						} );

						it( 'returns false when there are no changes', function() {
							expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBeFalsy();
						} );

						it( 'returns ' + specCase.expected + ' when there are changes', function() {
							$input.click();
							expect( $tracker.vui_changeTracker( 'isChangeShown' ) ).toBe( specCase.expected );
						} );

					} );
				};

				for( var i=0; i<cases.length; i++ ) {
					runSpecs( cases[i] );
				}

			} );

		} );

	} );

} )();
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var sinon = require('sinon');
var net = require('net');
var sendCommandToSocket = require('../lib/base/communication').sendCommandToSocket;

// Monkey patch to help with debugging Buffer comparison assertions
(function(BufferToString) {
    Buffer.prototype.toString = function(encoding) {
        if (encoding === undefined) {
            var array = [];
            for (var i = 0; i < this.length; i++) {
                var hex = this[i].toString(16);
                if (this[i] < 0x10) {
                    hex = '0' + hex;
                }
                array.push('0x' + hex);
            }
            return '[' + array.join(', ') + ']';
        } else {
            return BufferToString.apply(this, arguments);
        }
    };
})(Buffer.prototype.toString);

describe('Communication Test', function () {
    beforeEach(function() {
        var version = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
        if (version < 4.0) {
            // These tests erroneously fails on old versions of node.js
            this.skip();
        }
    });

    describe('sending a command', function () {

        it('should open a connection to the server', function () {
            var options = {
                server: '127.0.0.1',
                port: 4304
            };
            var socket = new net.Socket();
            var mock = sinon.mock(socket);
            mock.expects('connect').once().withExactArgs(4304, '127.0.0.1');

            sendCommandToSocket(options, socket, function() {});

            mock.verify();
        });

        it('should send a command to the server once connected', function () {
            var options = {
                path: '/some/path',
                command: 2,
                data_len: 8192,
                server: '127.0.0.1',
                port: 4304
            };
            var socket = new net.Socket();
            var mock = sinon.mock(socket);
            sinon.stub(socket, 'connect', function() {
                socket.emit('connect');
            });

            var expect = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0x00, 0x00, 0x00, 0x0b,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x02,   // Type of function call
                0x00, 0x00, 0x00, 0x20,   // Format flags
                0x00, 0x00, 0x20, 0x00,   // Expected size of data
                0x00, 0x00, 0x00, 0x00,   // Offset for read or write
                0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x00
            ]);
            mock.expects('end').once().withExactArgs(expect);

            sendCommandToSocket(options, socket, function() {});

            mock.verify();
        });

        it('should handle parsing of a single response message', function (done) {
            var options = {
                path: '/some/path',
                command: 2,
                data_len: 8192,
                server: '127.0.0.1',
                port: 4304
            };

            var socket = new net.Socket();
            var response = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0x00, 0x00, 0x00, 0x0c,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x0c,   // Type of function call
                0x00, 0x00, 0x00, 0x20,   // Format flags
                0x00, 0x00, 0x00, 0x0c,   // Size of data
                0x00, 0x00, 0x00, 0x00,   // Offset for read or write
                0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x37, 0x2e, 0x38, 0x31, 0x32, 0x35
            ]);
            sinon.stub(socket, 'connect', function() {
                socket.emit('data', response);
                socket.emit('end');
            });

            sendCommandToSocket(options, socket, function(err, messages) {
                assert.equal(err, undefined);
                assert.equal(messages.length, 1);

                assert.equal(messages[0].header.version, 0x00);
                assert.equal(messages[0].header.payload, 0x0c);
                assert.equal(messages[0].header.ret, 0x0c);
                assert.equal(messages[0].header.controlflags, 0x20);
                assert.equal(messages[0].header.size, 0x0c);
                assert.equal(messages[0].header.offset, 0x00);
                assert.equal(messages[0].payload, '     17.8125');
                done();
            });
        });
                done();
            });
        });

    });

});
<commit_msg>Added test for empty messages coming back in response<commit_after>'use strict';

var assert = require('assert');
var sinon = require('sinon');
var net = require('net');
var sendCommandToSocket = require('../lib/base/communication').sendCommandToSocket;

// Monkey patch to help with debugging Buffer comparison assertions
(function(BufferToString) {
    Buffer.prototype.toString = function(encoding) {
        if (encoding === undefined) {
            var array = [];
            for (var i = 0; i < this.length; i++) {
                var hex = this[i].toString(16);
                if (this[i] < 0x10) {
                    hex = '0' + hex;
                }
                array.push('0x' + hex);
            }
            return '[' + array.join(', ') + ']';
        } else {
            return BufferToString.apply(this, arguments);
        }
    };
})(Buffer.prototype.toString);

describe('Communication Test', function () {
    beforeEach(function() {
        var version = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
        if (version < 4.0) {
            // These tests erroneously fails on old versions of node.js
            this.skip();
        }
    });

    describe('sending a command', function () {

        it('should open a connection to the server', function () {
            var options = {
                server: '127.0.0.1',
                port: 4304
            };
            var socket = new net.Socket();
            var mock = sinon.mock(socket);
            mock.expects('connect').once().withExactArgs(4304, '127.0.0.1');

            sendCommandToSocket(options, socket, function() {});

            mock.verify();
        });

        it('should send a command to the server once connected', function () {
            var options = {
                path: '/some/path',
                command: 2,
                data_len: 8192,
                server: '127.0.0.1',
                port: 4304
            };
            var socket = new net.Socket();
            var mock = sinon.mock(socket);
            sinon.stub(socket, 'connect', function() {
                socket.emit('connect');
            });

            var expect = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0x00, 0x00, 0x00, 0x0b,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x02,   // Type of function call
                0x00, 0x00, 0x00, 0x20,   // Format flags
                0x00, 0x00, 0x20, 0x00,   // Expected size of data
                0x00, 0x00, 0x00, 0x00,   // Offset for read or write
                0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x00
            ]);
            mock.expects('end').once().withExactArgs(expect);

            sendCommandToSocket(options, socket, function() {});

            mock.verify();
        });

        it('should handle parsing of a single response message', function (done) {
            var options = {
                path: '/some/path',
                command: 2,
                data_len: 8192,
                server: '127.0.0.1',
                port: 4304
            };

            var socket = new net.Socket();
            var response = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0x00, 0x00, 0x00, 0x0c,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x0c,   // Type of function call
                0x00, 0x00, 0x00, 0x20,   // Format flags
                0x00, 0x00, 0x00, 0x0c,   // Size of data
                0x00, 0x00, 0x00, 0x00,   // Offset for read or write
                0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x37, 0x2e, 0x38, 0x31, 0x32, 0x35
            ]);
            sinon.stub(socket, 'connect', function() {
                socket.emit('data', response);
                socket.emit('end');
            });

            sendCommandToSocket(options, socket, function(err, messages) {
                assert.equal(err, undefined);
                assert.equal(messages.length, 1);

                assert.equal(messages[0].header.version, 0x00);
                assert.equal(messages[0].header.payload, 0x0c);
                assert.equal(messages[0].header.ret, 0x0c);
                assert.equal(messages[0].header.controlflags, 0x20);
                assert.equal(messages[0].header.size, 0x0c);
                assert.equal(messages[0].header.offset, 0x00);
                assert.equal(messages[0].payload, '     17.8125');
                done();
            });
        });

        it('should handle multiple empty messages before a response message', function (done) {
            var options = {
                path: '/some/path',
                command: 2,
                data_len: 8192,
                server: '127.0.0.1',
                port: 4304
            };

            var socket = new net.Socket();
            var empty = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0xff, 0xff, 0xff, 0xff,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x00,   // Type of function call
                0x00, 0x00, 0x00, 0x00,   // Format flags
                0x00, 0x00, 0x00, 0x00,   // Size of data
                0x00, 0x00, 0x00, 0x00    // Offset for read or write
            ]);
            var response = new Buffer([
                0x00, 0x00, 0x00, 0x00,   // Protocol Version
                0x00, 0x00, 0x00, 0x0c,   // Length (in bytes) of payload data
                0x00, 0x00, 0x00, 0x0c,   // Type of function call
                0x00, 0x00, 0x00, 0x20,   // Format flags
                0x00, 0x00, 0x00, 0x0c,   // Size of data
                0x00, 0x00, 0x00, 0x00,   // Offset for read or write
                0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x37, 0x2e, 0x38, 0x31, 0x32, 0x35
            ]);
            sinon.stub(socket, 'connect', function() {
                socket.emit('data', empty);
                socket.emit('data', empty);
                socket.emit('data', response);
                socket.emit('end');
            });

            sendCommandToSocket(options, socket, function(err, messages) {
                assert.equal(err, undefined);
                assert.equal(messages.length, 3);

                assert.equal(messages[0].header.version, 0);
                assert.equal(messages[0].header.payload, -1);
                assert.equal(messages[0].header.ret, 0);
                assert.equal(messages[0].header.controlflags, 0);
                assert.equal(messages[0].header.size, 0);
                assert.equal(messages[0].header.offset, 0);
                assert.equal(messages[0].payload, null);

                assert.equal(messages[2].header.version, 0);
                assert.equal(messages[2].header.payload, 0x0c);
                assert.equal(messages[2].header.ret, 0x0c);
                assert.equal(messages[2].header.controlflags, 0x20);
                assert.equal(messages[2].header.size, 0x0c);
                assert.equal(messages[2].header.offset, 0x00);
                assert.equal(messages[2].payload, '     17.8125');
                done();
            });
        });

    });

});
<|endoftext|>