<commit_before>/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileOverview serving static files, including js and css, and cacheing
 *               and minifying.
 *
 * Terminology Note:
 *    "path" is confusing because paths can be part of URLs and part
 *     of filesystem paths, and static files have both types of paths
 *     associated with them.  Therefore, in this module:
 *
 *      LOCALDIR or LOCALFILE refers to directories or files on the filesystem.
 *
 *      HREF is used to describe things that go in a URL.
 */

import("fileutils.{readFile,readFileBytes}");
import("yuicompressor");
import("stringutils");
import("varz");
import("ejs.EJS");

jimport("java.lang.System.out.println");

//----------------------------------------------------------------
// Content Type Guessing
//----------------------------------------------------------------

var _contentTypes = {
  'gif': 'image/gif',
  'png': 'image/png',
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'css': 'text/css',
  'js': 'application/x-javascript; charset=utf-8',
  'txt': 'text/plain; charset=utf-8',
  'html': 'text/html; charset=utf-8',
  'ico': 'image/x-icon',
  'swf': 'application/x-shockwave-flash',
  'zip': 'application/zip',
  'xml': 'application/xml'
};

var _gzipableTypes = {
  'text/css': true,
  'application/x-javascript': true,
  'text/html; charset=utf-8': true
};

function _guessContentType(path) {
  var ext = path.split('.').pop().toLowerCase();
  return _contentTypes[ext] || _contentTypes['txt'];
}

//----------------------------------------------------------------

function _getCache(name) {
  var m = 'faststatic';
  if (!appjet.cache[m]) {
    appjet.cache[m] = {};
  }
  var c = appjet.cache[m];
  if (!c[name]) {
    c[name] = {};
  }
  return c[name];
}

var _mtimeCheckInterval = 5000; // 5 seconds

function _getMTime(f) {
  var mcache = _getCache('mtimes');
  var now = +(new Date);
  if (appjet.config.devMode ||
      !(mcache[f] && (now - mcache[f].lastCheck < _mtimeCheckInterval))) {
    var jfile = new net.appjet.oui.JarVirtualFile(f);
    if (jfile.exists() && !jfile.isDirectory()) {
      mcache[f] = {
	lastCheck:  now,
	mtime: jfile.lastModified()
      };
    } else {
      mcache[f] = null;
    }
  }
  if (mcache[f]) {
    return +mcache[f].mtime;
  } else {
    return null;
  }
}

function manglePluginPath(localFile, fileType) {
  var prefix = '/static/' + fileType + '/plugins/';
  if (localFile.substring(0, prefix.length) != prefix)
    return localFile;
  var suffix = localFile.substring(prefix.length);
  var plugin = suffix.split('/', 1)[0];
  suffix = suffix.substring(plugin.length + 1);
  return '/plugins/' + plugin + '/static/' + fileType + '/' + suffix;
}

function manglePluginPaths(localFile) {
  for (fmt in {'js':0, 'css':0, 'swf':0, 'html':0, 'img':0, 'zip':0}) {
    localFile = manglePluginPath(localFile, fmt);
  }
  return localFile;
}

function _wrapFile(localFile) {
  return {
    getPath: function() { return localFile; },
    getMTime: function() { return _getMTime(localFile); },
    getContents: function() { return _readFileAndProcess(manglePluginPaths(localFile), 'string'); }
  };
}

function _readFileAndProcess(fileName, type) {
  if (fileName.slice(-8) == "_ejs.css") {
    // run CSS through EJS
    var template = readFile(fileName);
    var ejs = new EJS({text:template, name:fileName});
    var resultString = ejs.render({});
    if (type == 'bytes') {
      return new java.lang.String(resultString).getBytes("UTF-8");
    }
    else {
      return resultString;
    }
  }
  else if (type == 'string') {
    return readFile(fileName);
  }
  else if (type == 'bytes') {
    return readFileBytes(fileName);
  }
}

function _cachedFileBytes(f) {
  var mtime = _getMTime(f);
  if (!mtime) { return null; }
  var fcache = _getCache('file-bytes-cache');
  if (!(fcache[f] && (fcache[f].mtime == mtime))) {
    varz.incrementInt("faststatic-file-bytes-cache-miss");
    var bytes = _readFileAndProcess(f, 'bytes');
    if (bytes) {
      fcache[f] = {mtime: mtime, bytes: bytes};
    };
  }
  if (fcache[f] && fcache[f].bytes) {
    return fcache[f].bytes;
  } else {
    return null;
  }
}

function _shouldGzip(contentType) {
  var userAgent = request.headers["User-Agent"];
  if (! userAgent) return false;
  if (! (/Firefox/.test(userAgent) || /webkit/i.test(userAgent))) return false;
  if (! _gzipableTypes[contentType]) return false;

	return request.acceptsGzip;
}

function _getCachedGzip(original, key) {
  var c = _getCache("gzipped");
  if (! c[key] || ! java.util.Arrays.equals(c[key].original, original)) {
    c[key] = {original: original,
              gzip: stringutils.gzip(original)};
  }
  return c[key].gzip;
}

function _setGzipHeader() {
  response.setHeader("Content-Encoding", "gzip");
}

//----------------------------------------------------------------

/**
 * Function for serving a single static file.
 */
function singleFileServer(localPath, opts) {
  var contentType = _guessContentType(localPath);

  return function() {
    (opts.cache ? response.alwaysCache() : response.neverCache());
    response.setContentType(contentType);
    var bytes = _cachedFileBytes(localPath);
    if (bytes) {
      if (_shouldGzip(contentType)) {
        bytes = _getCachedGzip(bytes, "file:"+localPath);
        _setGzipHeader();
      }
      response.writeBytes(bytes);
      return true;
    } else {
      return false;
    }
  };
}

/**
 * valid opts:
 *   alwaysCache: default false
 */
function directoryServer(localDir, opts) {
  if (stringutils.endsWith(localDir, "/")) {
    localDir = localDir.substr(0, localDir.length-1);
  }
  return function(relpath) {
    if (stringutils.startsWith(relpath, "/")) {
      relpath = relpath.substr(1);
    }
    if (relpath.indexOf('..') != -1) {
      response.forbid();
    }
    (opts.cache ? response.alwaysCache() : response.neverCache());
    var contentType = _guessContentType(relpath);
    response.setContentType(contentType);
    var fullPath = localDir + "/" + relpath;
    var bytes = _cachedFileBytes(fullPath);

    if (bytes) {
      if (_shouldGzip(contentType)) {
        bytes = _getCachedGzip(bytes, "file:"+fullPath);
        _setGzipHeader();
      }
      response.writeBytes(bytes);
      return true;
    } else {
      return false;
    }
  };
}

/**
 * Serves cat files, which are concatenated versions of many files.
 */
function compressedFileServer(opts) {
  var cfcache = _getCache('compressed-files');
  return function() {
    var key = request.path.split('/').slice(-1)[0];
    var contentType = _guessContentType(request.path);
    response.setContentType(contentType);
    response.alwaysCache();
    var data = cfcache[key];
    if (data) {
      if (_shouldGzip(contentType)) {
        data = _getCachedGzip((new java.lang.String(data)).getBytes(response.getCharacterEncoding()), "comp:"+key);
        _setGzipHeader();
        response.writeBytes(data);
      } else {
        response.write(data);
      }
      return true;
    } else {
      return false;
    }
  };
}

function getCompressedFilesKey(type, baseLocalDir, localFileList) {
  if (stringutils.endsWith(baseLocalDir, '/')) {
    baseLocalDir = baseLocalDir.substr(0, baseLocalDir.length-1);
  }

  var fileList = [];
  // convert passed-in file list into list of our file objects
  localFileList.forEach(function(f) {
    if (typeof(f) == 'string') {
      fileList.push(_wrapFile(baseLocalDir+'/'+f));
    } else {
      fileList.push(f);
    }
  });

  // have we seen this exact fileset before?
  var fsId = fileList.map(function(f) { return f.getPath(); }).join('|');
  var fsMTime = Math.max.apply(this,
			       fileList.map(function(f) { return f.getMTime(); }));

  var kdcache = _getCache('fileset-keydata-cache');
  if (!(kdcache[fsId] && (kdcache[fsId].mtime == fsMTime))) {
    //println("cache miss for fileset: "+fsId);
    //println("compressing fileset...");
    kdcache[fsId] = {
      mtime: fsMTime,
      keyString: _compressFilesAndMakeKey(type, fileList)
    };
  }
  return kdcache[fsId].keyString;
}

function _compressFilesAndMakeKey(type, fileList) {
  function _compress(s) {
    if (type == 'css') {
      varz.incrementInt("faststatic-yuicompressor-compressCSS");
      return yuicompressor.compressCSS(s);
    } else if (type == 'js') {
      varz.incrementInt("faststatic-yuicompressor-compressJS");
      return yuicompressor.compressJS(s);
    } else {
      throw Error('Dont know how to compress this filetype: '+type);
    }
  }

  var fullstr = "";
  fileList.forEach(function(f) {
    fullstr += _compress(f.getContents());
  });

  fullstr = _compress(fullstr);

  var key = stringutils.md5(fullstr) + '.' + type;
  var cfcache = _getCache('compressed-files');
  cfcache[key] = fullstr;
  return key;
}

<commit_msg>No charset on other than text/*<commit_after>/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileOverview serving static files, including js and css, and cacheing
 *               and minifying.
 *
 * Terminology Note:
 *    "path" is confusing because paths can be part of URLs and part
 *     of filesystem paths, and static files have both types of paths
 *     associated with them.  Therefore, in this module:
 *
 *      LOCALDIR or LOCALFILE refers to directories or files on the filesystem.
 *
 *      HREF is used to describe things that go in a URL.
 */

import("fileutils.{readFile,readFileBytes}");
import("yuicompressor");
import("stringutils");
import("varz");
import("ejs.EJS");

jimport("java.lang.System.out.println");

//----------------------------------------------------------------
// Content Type Guessing
//----------------------------------------------------------------

var _contentTypes = {
  'gif': 'image/gif',
  'png': 'image/png',
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'css': 'text/css',
  'js': 'application/x-javascript',
  'txt': 'text/plain; charset=utf-8',
  'html': 'text/html; charset=utf-8',
  'ico': 'image/x-icon',
  'swf': 'application/x-shockwave-flash',
  'zip': 'application/zip',
  'xml': 'application/xml'
};

var _gzipableTypes = {
  'text/css': true,
  'application/x-javascript': true,
  'text/html; charset=utf-8': true
};

function _guessContentType(path) {
  var ext = path.split('.').pop().toLowerCase();
  return _contentTypes[ext] || _contentTypes['txt'];
}

//----------------------------------------------------------------

function _getCache(name) {
  var m = 'faststatic';
  if (!appjet.cache[m]) {
    appjet.cache[m] = {};
  }
  var c = appjet.cache[m];
  if (!c[name]) {
    c[name] = {};
  }
  return c[name];
}

var _mtimeCheckInterval = 5000; // 5 seconds

function _getMTime(f) {
  var mcache = _getCache('mtimes');
  var now = +(new Date);
  if (appjet.config.devMode ||
      !(mcache[f] && (now - mcache[f].lastCheck < _mtimeCheckInterval))) {
    var jfile = new net.appjet.oui.JarVirtualFile(f);
    if (jfile.exists() && !jfile.isDirectory()) {
      mcache[f] = {
	lastCheck:  now,
	mtime: jfile.lastModified()
      };
    } else {
      mcache[f] = null;
    }
  }
  if (mcache[f]) {
    return +mcache[f].mtime;
  } else {
    return null;
  }
}

function manglePluginPath(localFile, fileType) {
  var prefix = '/static/' + fileType + '/plugins/';
  if (localFile.substring(0, prefix.length) != prefix)
    return localFile;
  var suffix = localFile.substring(prefix.length);
  var plugin = suffix.split('/', 1)[0];
  suffix = suffix.substring(plugin.length + 1);
  return '/plugins/' + plugin + '/static/' + fileType + '/' + suffix;
}

function manglePluginPaths(localFile) {
  for (fmt in {'js':0, 'css':0, 'swf':0, 'html':0, 'img':0, 'zip':0}) {
    localFile = manglePluginPath(localFile, fmt);
  }
  return localFile;
}

function _wrapFile(localFile) {
  return {
    getPath: function() { return localFile; },
    getMTime: function() { return _getMTime(localFile); },
    getContents: function() { return _readFileAndProcess(manglePluginPaths(localFile), 'string'); }
  };
}

function _readFileAndProcess(fileName, type) {
  if (fileName.slice(-8) == "_ejs.css") {
    // run CSS through EJS
    var template = readFile(fileName);
    var ejs = new EJS({text:template, name:fileName});
    var resultString = ejs.render({});
    if (type == 'bytes') {
      return new java.lang.String(resultString).getBytes("UTF-8");
    }
    else {
      return resultString;
    }
  }
  else if (type == 'string') {
    return readFile(fileName);
  }
  else if (type == 'bytes') {
    return readFileBytes(fileName);
  }
}

function _cachedFileBytes(f) {
  var mtime = _getMTime(f);
  if (!mtime) { return null; }
  var fcache = _getCache('file-bytes-cache');
  if (!(fcache[f] && (fcache[f].mtime == mtime))) {
    varz.incrementInt("faststatic-file-bytes-cache-miss");
    var bytes = _readFileAndProcess(f, 'bytes');
    if (bytes) {
      fcache[f] = {mtime: mtime, bytes: bytes};
    };
  }
  if (fcache[f] && fcache[f].bytes) {
    return fcache[f].bytes;
  } else {
    return null;
  }
}

function _shouldGzip(contentType) {
  var userAgent = request.headers["User-Agent"];
  if (! userAgent) return false;
  if (! (/Firefox/.test(userAgent) || /webkit/i.test(userAgent))) return false;
  if (! _gzipableTypes[contentType]) return false;

	return request.acceptsGzip;
}

function _getCachedGzip(original, key) {
  var c = _getCache("gzipped");
  if (! c[key] || ! java.util.Arrays.equals(c[key].original, original)) {
    c[key] = {original: original,
              gzip: stringutils.gzip(original)};
  }
  return c[key].gzip;
}

function _setGzipHeader() {
  response.setHeader("Content-Encoding", "gzip");
}

//----------------------------------------------------------------

/**
 * Function for serving a single static file.
 */
function singleFileServer(localPath, opts) {
  var contentType = _guessContentType(localPath);

  return function() {
    (opts.cache ? response.alwaysCache() : response.neverCache());
    response.setContentType(contentType);
    var bytes = _cachedFileBytes(localPath);
    if (bytes) {
      if (_shouldGzip(contentType)) {
        bytes = _getCachedGzip(bytes, "file:"+localPath);
        _setGzipHeader();
      }
      response.writeBytes(bytes);
      return true;
    } else {
      return false;
    }
  };
}

/**
 * valid opts:
 *   alwaysCache: default false
 */
function directoryServer(localDir, opts) {
  if (stringutils.endsWith(localDir, "/")) {
    localDir = localDir.substr(0, localDir.length-1);
  }
  return function(relpath) {
    if (stringutils.startsWith(relpath, "/")) {
      relpath = relpath.substr(1);
    }
    if (relpath.indexOf('..') != -1) {
      response.forbid();
    }
    (opts.cache ? response.alwaysCache() : response.neverCache());
    var contentType = _guessContentType(relpath);
    response.setContentType(contentType);
    var fullPath = localDir + "/" + relpath;
    var bytes = _cachedFileBytes(fullPath);

    if (bytes) {
      if (_shouldGzip(contentType)) {
        bytes = _getCachedGzip(bytes, "file:"+fullPath);
        _setGzipHeader();
      }
      response.writeBytes(bytes);
      return true;
    } else {
      return false;
    }
  };
}

/**
 * Serves cat files, which are concatenated versions of many files.
 */
function compressedFileServer(opts) {
  var cfcache = _getCache('compressed-files');
  return function() {
    var key = request.path.split('/').slice(-1)[0];
    var contentType = _guessContentType(request.path);
    response.setContentType(contentType);
    response.alwaysCache();
    var data = cfcache[key];
    if (data) {
      if (_shouldGzip(contentType)) {
        data = _getCachedGzip((new java.lang.String(data)).getBytes(response.getCharacterEncoding()), "comp:"+key);
        _setGzipHeader();
        response.writeBytes(data);
      } else {
        response.write(data);
      }
      return true;
    } else {
      return false;
    }
  };
}

function getCompressedFilesKey(type, baseLocalDir, localFileList) {
  if (stringutils.endsWith(baseLocalDir, '/')) {
    baseLocalDir = baseLocalDir.substr(0, baseLocalDir.length-1);
  }

  var fileList = [];
  // convert passed-in file list into list of our file objects
  localFileList.forEach(function(f) {
    if (typeof(f) == 'string') {
      fileList.push(_wrapFile(baseLocalDir+'/'+f));
    } else {
      fileList.push(f);
    }
  });

  // have we seen this exact fileset before?
  var fsId = fileList.map(function(f) { return f.getPath(); }).join('|');
  var fsMTime = Math.max.apply(this,
			       fileList.map(function(f) { return f.getMTime(); }));

  var kdcache = _getCache('fileset-keydata-cache');
  if (!(kdcache[fsId] && (kdcache[fsId].mtime == fsMTime))) {
    //println("cache miss for fileset: "+fsId);
    //println("compressing fileset...");
    kdcache[fsId] = {
      mtime: fsMTime,
      keyString: _compressFilesAndMakeKey(type, fileList)
    };
  }
  return kdcache[fsId].keyString;
}

function _compressFilesAndMakeKey(type, fileList) {
  function _compress(s) {
    if (type == 'css') {
      varz.incrementInt("faststatic-yuicompressor-compressCSS");
      return yuicompressor.compressCSS(s);
    } else if (type == 'js') {
      varz.incrementInt("faststatic-yuicompressor-compressJS");
      return yuicompressor.compressJS(s);
    } else {
      throw Error('Dont know how to compress this filetype: '+type);
    }
  }

  var fullstr = "";
  fileList.forEach(function(f) {
    fullstr += _compress(f.getContents());
  });

  fullstr = _compress(fullstr);

  var key = stringutils.md5(fullstr) + '.' + type;
  var cfcache = _getCache('compressed-files');
  cfcache[key] = fullstr;
  return key;
}

<|endoftext|>


<commit_before>var request = require('request');
var cheerio = require('cheerio');
var constants = require('./constants');
var ukrainianCoinsParser = require('./ukrainian-coins-parser');

var COIN_ID_REG_EXP = /coin_id=(\d+)$/;

function getСategories () {
  return getPage(constants.urls.SEARCH_URL)
    .then(ukrainianCoinsParser.parseСategories);
}

function getList () {
  return getPage(constants.urls.LIST_URL)
    .then(ukrainianCoinsParser.parseList);
}

function getDetails (id) {
  return getPage(constants.urls.DETAILS_URL + id)
    .then(ukrainianCoinsParser.parseDetails);
}

function getPage (url) {
  return new Promise(function(resolve, reject) {
      request(url, function (error, response, body) {
        if (!error && response.statusCode == 200) {
          resolve(cheerio.load(body));
        } else {
          reject();
        }
      });
  });
}

module.exports = {
  getСategories: getСategories,
  getList: getList,
  getDetails: getDetails
};
<commit_msg>Implement getListWithDetails<commit_after>var request = require('request');
var cheerio = require('cheerio');
var constants = require('./constants');
var ukrainianCoinsParser = require('./ukrainian-coins-parser');

var COIN_ID_REG_EXP = /coin_id=(\d+)$/;

function getСategories () {
  return getPage(constants.urls.SEARCH_URL)
    .then(ukrainianCoinsParser.parseСategories);
}

function getList () {
  return getPage(constants.urls.LIST_URL)
    .then(ukrainianCoinsParser.parseList);
}

function getDetails (id) {
  return getPage(constants.urls.DETAILS_URL + id)
    .then(ukrainianCoinsParser.parseDetails);
}

function getListWithDetails () {
  return getList().then(function(coins) {
    return coins.slice(0, 2).reduce(function(result, coin) {
      return Promise.all([result, getDetails(coin.id)]).then(function(resultAndCurrentItem) {
        return resultAndCurrentItem[0].concat(resultAndCurrentItem[1]);
      });
    }, Promise.resolve([]));
  });
}

function getPage (url) {
  return new Promise(function(resolve, reject) {
      request(url, function (error, response, body) {
        if (!error && response.statusCode == 200) {
          resolve(cheerio.load(body));
        } else {
          reject();
        }
      });
  });
}

module.exports = {
  getСategories: getСategories,
  getList: getList,
  getDetails: getDetails,
  getListWithDetails: getListWithDetails
};
<|endoftext|>


<commit_before>
var Class = require('better-js-class');
var cps = require('cps');
var $U = require('underscore');

var DB = require('./db.js');

module.exports = function() {
    var Model = {
        OPTIMISTIC_LOCK_EXCEPTION: 'optimistic_lock_exception'
    };

    var Row  = Class({
        _init: function(data, cfg) {
            this._table = cfg.table;
            this._data = data;
        },

        getId: function() {
            return this._data[this._table.getIdFieldName()];
        },

        _getVersion: function() {
            return this._data[this._table.getVersionFieldName()];
        },

        _nextVersion: function() {
            return this._data[this._table.getVersionFieldName()] + 1;
        },

        _updateLocalData: function(dto) {
            for (var k in dto) {
                var v = dto[k];
                this._data[k] = v;
            }
        },

        _refineDtoForUpdate: function(dto) {

            var res = {};

            for (var k in dto) {
                if (this._table._hasUpdatableField(k)) {
                    res[k] = dto[k];
                }
            }

            var d = new Date();
            res[this._table.getUpdatedFieldName()] = d;

            return res;
        },

        updateWithoutOptimisticLock: function(conn, dto, cb) {
            this._update(conn, dto, null, cb);
        },

        update: function(conn, dto, cb) {
            var me = this;

            dto['version'] = this._nextVersion();
            var cond = DB.format('version = ?', [this._getVersion()]);

            cps.seq([
                function(_, cb) {
                    me._update(conn, dto, cond, cb);
                },
                function(res, cb) {
                    if (res.changedRows === 0) {
                        throw new Error(Model.OPTIMISTIC_LOCK_EXCEPTION);
                    } else {
                        cb(null, res);
                    }
                }
            ], cb);
        },

        _update: function(conn, dto, conditions, cb) {
            var me = this;

            // dto[this._table.getUpdatedFieldName()] = new Date();
            dto = this._refineDtoForUpdate(dto);

            var l = [
                ' update ', this._table.getName(), ' set '
            ];

            var first = true;
            for (var k in dto) {
                var v = dto[k];
                if (first) {
                    first = false;
                } else {
                    l.push(', ');
                }
                l.push(
                    ' ', k, ' = ', conn.escape(v)
                );
            }

            l.push(
                ' where ', this._table.getIdFieldName(), ' = ', this.getId()
            );

            l.push(
                ' and ', conditions
            );

            l.push(' ; ');

            var q = l.join('');

            // console.log(q);

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    me._updateLocalData(dto);
                    cb(null, res);
                }
            ], cb);
        },

        get: function(fieldName) {
            return this._data[fieldName]
        },

        linksTo: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupLinksToMap(name);
            if (cfg) {
                return cps.seq([
                    function(_, cb) {
                        cfg.table.findById(conn, me.get(cfg.key), cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, res);
                    }
                ], cb);
            } else {
                throw new Error('no linksTo: ' + name + ' defined on: ' + this._table.getName());
            }
        },

        linkedBy: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupLinkedByMap(name);
            if (cfg) {
                return cps.seq([
                    function(_, cb) {
                        cfg.table.find(conn, cfg.table.baseQuery('where ' + cfg.key + ' = ?', [me.getId()]), cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, me._data[cfg.name]);
                    }
                ], cb);
            } else {
                throw new Error('no linkedBy: ' + name + ' defined on: ' + this._table.getName());
            }
        },

        relatesTo: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupRelatesToMap(name);
            if (cfg) {
                return cps.seq([
                    function(_, cb) {
                        var _q = 'select t.* from ' +
                                cfg.table.getName()  + ' t, ' +
                                cfg.through.getName() + ' r where ' +
                                'r.' + cfg['leftKey'] + ' = ? and ' +
                                'r.' + cfg['rightKey'] + ' = t.' + cfg.table.getIdFieldName()
                            ;
                        var q = DB.format(_q, [me.getId()]);
                        cfg.table.find(conn, q, cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, me._data[cfg.name]);
                    }
                ], cb);
            } else {
                throw new Error('no relatesTo: ' + name + ' defined on: ' + this._table.getName());
            }
        }
    });

    var Table = Class({
        _init: function(cfg) {
            this._name = cfg.name;
            this._idFieldName = cfg.idFieldName || 'id';
            this._versionFieldName = cfg.versionFieldName || 'version';
            this._createdFieldName = cfg.createdFieldName || 'date_created';
            this._updatedFieldName = cfg.updatedFieldName || 'last_updated';

            this._rowClass = cfg['rowClass'];
            // this._schema = cfg['schema'];
            this._db = cfg['db'];

            this._linksToMap = {};
            this._linkedByMap = {};
            this._relatesToMap = {};
        },

        getName: function() {
            return this._name;
        },

        getIdFieldName: function() {
            return this._idFieldName;
        },

        getVersionFieldName: function() {
            return this._versionFieldName;
        },

        getCreatedFieldName: function() {
            return this._createdFieldName;
        },

        getUpdatedFieldName: function() {
            return this._updatedFieldName;
        },

        _hasUpdatableField: function(field) {
            if (field == this.getIdFieldName()) {
                return false;
            }
            if (field == this.getCreatedFieldName()) {
                return false;
            }
            var schema = this._db._schema[this.getName()];
            return $U.contains(schema, field);
        },

        _refineDto: function(dto, autoId) {
            autoId = (autoId === undefined)? true: autoId;
            var res = {};

            var schema = this._db._schema[this.getName()];
            $U.each(schema, function(field) {
                res[field] = dto[field];
            });

            if (autoId) {
                delete res[this.getIdFieldName()];
            }

            return res;
        },

        _refineDtoForCreate: function(dto) {
            var res = this._refineDto(dto);

            var d = new Date();
            res[this.getCreatedFieldName()] = d;
            res[this.getUpdatedFieldName()] = d;
            res[this.getVersionFieldName()] = 0;

            return res;
        },

        create: function(conn, dto, cb) {
            dto = this._refineDtoForCreate(dto);
            this._create(conn, dto, cb);
        },

        _create: function(conn, dto, cb) {
            var me = this;

            var l = [
                ' insert into ' + this.getName() + ' set '
            ];

            var first = true;

            $U.each(dto, function(v, k) {
                if (first) {
                    first = false;
                } else {
                    l.push(', ');
                }
                l.push(
                    ' ', k, ' = ', conn.escape(v)
                );
            });

            l.push(' ; ');

            var q = l.join('');

            // console.log(q);

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    dto[me._idFieldName] = res.insertId;
                    cb(null, new me._rowClass(dto));
                }
            ], cb);
        },

        clone: function(conn, dto, cb) {
            dto = this._refineDto(dto, false);
            this._create(conn, dto, cb);
        },

        baseQuery: function(str, bindings) {
            var q = ' select * from ' + this.getName() + ' ';
            var further;

            if (str != null) {
                if (bindings == null) {
                    further = str;
                } else {
                    further = DB.format(str, bindings);
                }
            }

            if (further != null) {
                q += further;
            }
            return q;
        },

        findById: function(conn, id, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, me.baseQuery('where ' + me.getIdFieldName() + ' = ? ', [id]), cb);
                },
                function(res) {
                    cb(null, res[0])
                }
            ], cb);
        },

        lockById: function(conn, id, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, me.baseQuery('where ' + me.getIdFieldName() + ' = ? for update', [id]), cb);
                },
                function(res) {
                    cb(null, res[0])
                }
            ], cb);
        },

        findAll: function(conn, cb) {
            this.find(conn, this.baseQuery(), cb);
        },

        find: function(conn, q, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    cb(null, $U.map(res, function(o) {
                        return new me._rowClass(o);
                    }));
                }
            ], cb);
        },

        linksTo: function(cfg) {
            this._linksToMap[cfg.name] = {
                table: cfg.table,
                key: cfg.key
            };
            return this;
        },

        linkedBy: function(cfg) {
            this._linkedByMap[cfg.name] = {
                table: cfg.table,
                key: cfg.key
            };
            return this;
        },

        relatesTo: function(cfg) {
            this._relatesToMap[cfg.name] = {
                table: cfg.table,
                through: cfg.through,
                leftKey: cfg.leftKey,
                rightKey: cfg.rightKey
            };
            return this;
        },

        _lookupLinksToMap: function(name) {
            var cfg = this._linksToMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        _lookupLinkedByMap: function(name) {
            var cfg = this._linkedByMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        _lookupRelatesToMap: function(name) {
            var cfg = this._relatesToMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        findFirst: function(conn, q, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, q, cb);
                },
                function(res, cb) {
                    cb(null, res[0]);
                }
            ], cb);
        }
    });

    $U.extend(Model, {
        Row: Row,
        Table: Table
    });

    return Model;
}();
<commit_msg>* fix the inclusion loop problem among models.<commit_after>
var Class = require('better-js-class');
var cps = require('cps');
var $U = require('underscore');

var DB = require('./db.js');

module.exports = function() {
    var Model = {
        OPTIMISTIC_LOCK_EXCEPTION: 'optimistic_lock_exception'
    };

    var Row  = Class({
        _init: function(data, cfg) {
            this._table = cfg.table;
            this._data = data;
        },

        getId: function() {
            return this._data[this._table.getIdFieldName()];
        },

        _getVersion: function() {
            return this._data[this._table.getVersionFieldName()];
        },

        _nextVersion: function() {
            return this._data[this._table.getVersionFieldName()] + 1;
        },

        _updateLocalData: function(dto) {
            for (var k in dto) {
                var v = dto[k];
                this._data[k] = v;
            }
        },

        _refineDtoForUpdate: function(dto) {

            var res = {};

            for (var k in dto) {
                if (this._table._hasUpdatableField(k)) {
                    res[k] = dto[k];
                }
            }

            var d = new Date();
            res[this._table.getUpdatedFieldName()] = d;

            return res;
        },

        updateWithoutOptimisticLock: function(conn, dto, cb) {
            this._update(conn, dto, null, cb);
        },

        update: function(conn, dto, cb) {
            var me = this;

            dto['version'] = this._nextVersion();
            var cond = DB.format('version = ?', [this._getVersion()]);

            cps.seq([
                function(_, cb) {
                    me._update(conn, dto, cond, cb);
                },
                function(res, cb) {
                    if (res.changedRows === 0) {
                        throw new Error(Model.OPTIMISTIC_LOCK_EXCEPTION);
                    } else {
                        cb(null, res);
                    }
                }
            ], cb);
        },

        _update: function(conn, dto, conditions, cb) {
            var me = this;

            // dto[this._table.getUpdatedFieldName()] = new Date();
            dto = this._refineDtoForUpdate(dto);

            var l = [
                ' update ', this._table.getName(), ' set '
            ];

            var first = true;
            for (var k in dto) {
                var v = dto[k];
                if (first) {
                    first = false;
                } else {
                    l.push(', ');
                }
                l.push(
                    ' ', k, ' = ', conn.escape(v)
                );
            }

            l.push(
                ' where ', this._table.getIdFieldName(), ' = ', this.getId()
            );

            l.push(
                ' and ', conditions
            );

            l.push(' ; ');

            var q = l.join('');

            // console.log(q);

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    me._updateLocalData(dto);
                    cb(null, res);
                }
            ], cb);
        },

        get: function(fieldName) {
            return this._data[fieldName]
        },

        linksTo: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupLinksToMap(name);

            if (cfg) {
                var otherTable = cfg.table.Table;
                return cps.seq([
                    function(_, cb) {
                        otherTable.findById(conn, me.get(cfg.key), cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, res);
                    }
                ], cb);
            } else {
                throw new Error('no linksTo: ' + name + ' defined on: ' + this._table.getName());
            }
        },

        linkedBy: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupLinkedByMap(name);

            if (cfg) {
                var otherTable = cfg.table.Table;
                return cps.seq([
                    function(_, cb) {
                        otherTable.find(conn, cfg.table.baseQuery('where ' + cfg.key + ' = ?', [me.getId()]), cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, me._data[cfg.name]);
                    }
                ], cb);
            } else {
                throw new Error('no linkedBy: ' + name + ' defined on: ' + this._table.getName());
            }
        },

        relatesTo: function(conn, name, cb) {
            var me = this;

            var cfg = this._table._lookupRelatesToMap(name);
            if (cfg) {
                var otherTable = cfg.table.Table;
                var throughTable = cfg.through.Table;

                return cps.seq([
                    function(_, cb) {
                        var _q = 'select t.* from ' +
                                otherTable.getName()  + ' t, ' +
                                throughTable.getName() + ' r where ' +
                                'r.' + cfg['leftKey'] + ' = ? and ' +
                                'r.' + cfg['rightKey'] + ' = t.' + otherTable.getIdFieldName()
                            ;
                        var q = DB.format(_q, [me.getId()]);
                        otherTable.find(conn, q, cb);
                    },
                    function(res, cb) {
                        me._data[cfg.name] = res;
                        cb(null, me._data[cfg.name]);
                    }
                ], cb);
            } else {
                throw new Error('no relatesTo: ' + name + ' defined on: ' + this._table.getName());
            }
        }
    });

    var Table = Class({
        _init: function(cfg) {
            this._name = cfg.name;
            this._idFieldName = cfg.idFieldName || 'id';
            this._versionFieldName = cfg.versionFieldName || 'version';
            this._createdFieldName = cfg.createdFieldName || 'date_created';
            this._updatedFieldName = cfg.updatedFieldName || 'last_updated';

            this._rowClass = cfg['rowClass'];
            // this._schema = cfg['schema'];
            this._db = cfg['db'];

            this._linksToMap = {};
            this._linkedByMap = {};
            this._relatesToMap = {};
        },

        getName: function() {
            return this._name;
        },

        getIdFieldName: function() {
            return this._idFieldName;
        },

        getVersionFieldName: function() {
            return this._versionFieldName;
        },

        getCreatedFieldName: function() {
            return this._createdFieldName;
        },

        getUpdatedFieldName: function() {
            return this._updatedFieldName;
        },

        _hasUpdatableField: function(field) {
            if (field == this.getIdFieldName()) {
                return false;
            }
            if (field == this.getCreatedFieldName()) {
                return false;
            }
            var schema = this._db._schema[this.getName()];
            return $U.contains(schema, field);
        },

        _refineDto: function(dto, autoId) {
            autoId = (autoId === undefined)? true: autoId;
            var res = {};

            var schema = this._db._schema[this.getName()];
            $U.each(schema, function(field) {
                res[field] = dto[field];
            });

            if (autoId) {
                delete res[this.getIdFieldName()];
            }

            return res;
        },

        _refineDtoForCreate: function(dto) {
            var res = this._refineDto(dto);

            var d = new Date();
            res[this.getCreatedFieldName()] = d;
            res[this.getUpdatedFieldName()] = d;
            res[this.getVersionFieldName()] = 0;

            return res;
        },

        create: function(conn, dto, cb) {
            dto = this._refineDtoForCreate(dto);
            this._create(conn, dto, cb);
        },

        _create: function(conn, dto, cb) {
            var me = this;

            var l = [
                ' insert into ' + this.getName() + ' set '
            ];

            var first = true;

            $U.each(dto, function(v, k) {
                if (first) {
                    first = false;
                } else {
                    l.push(', ');
                }
                l.push(
                    ' ', k, ' = ', conn.escape(v)
                );
            });

            l.push(' ; ');

            var q = l.join('');

            // console.log(q);

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    dto[me._idFieldName] = res.insertId;
                    cb(null, new me._rowClass(dto));
                }
            ], cb);
        },

        clone: function(conn, dto, cb) {
            dto = this._refineDto(dto, false);
            this._create(conn, dto, cb);
        },

        baseQuery: function(str, bindings) {
            var q = ' select * from ' + this.getName() + ' ';
            var further;

            if (str != null) {
                if (bindings == null) {
                    further = str;
                } else {
                    further = DB.format(str, bindings);
                }
            }

            if (further != null) {
                q += further;
            }
            return q;
        },

        findById: function(conn, id, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, me.baseQuery('where ' + me.getIdFieldName() + ' = ? ', [id]), cb);
                },
                function(res) {
                    cb(null, res[0])
                }
            ], cb);
        },

        lockById: function(conn, id, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, me.baseQuery('where ' + me.getIdFieldName() + ' = ? for update', [id]), cb);
                },
                function(res) {
                    cb(null, res[0])
                }
            ], cb);
        },

        findAll: function(conn, cb) {
            this.find(conn, this.baseQuery(), cb);
        },

        find: function(conn, q, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    conn.query(q, cb);
                },
                function(res, cb) {
                    cb(null, $U.map(res, function(o) {
                        return new me._rowClass(o);
                    }));
                }
            ], cb);
        },

        linksTo: function(cfg) {
            this._linksToMap[cfg.name] = {
                table: cfg.table,
                key: cfg.key
            };
            return this;
        },

        linkedBy: function(cfg) {
            this._linkedByMap[cfg.name] = {
                table: cfg.table,
                key: cfg.key
            };
            return this;
        },

        relatesTo: function(cfg) {
            this._relatesToMap[cfg.name] = {
                table: cfg.table,
                through: cfg.through,
                leftKey: cfg.leftKey,
                rightKey: cfg.rightKey
            };
            return this;
        },

        _lookupLinksToMap: function(name) {
            var cfg = this._linksToMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        _lookupLinkedByMap: function(name) {
            var cfg = this._linkedByMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        _lookupRelatesToMap: function(name) {
            var cfg = this._relatesToMap[name];
            if (cfg) {
                cfg.name = name;
            }
            return cfg;
        },

        findFirst: function(conn, q, cb) {
            var me = this;

            cps.seq([
                function(_, cb) {
                    me.find(conn, q, cb);
                },
                function(res, cb) {
                    cb(null, res[0]);
                }
            ], cb);
        }
    });

    $U.extend(Model, {
        Row: Row,
        Table: Table
    });

    return Model;
}();
<|endoftext|>


<commit_before>describe('cli parser', function () {
    var _ = require('lodash'),
        sinon = require('sinon'),
        newman = require('../../'),
        commander = require('commander'),
        newmanCLI,

        /**
         * Wrap newmanCLI callback to extract options passed to sinon `newman` stub.
         *
         * @param {String[]} argv - Argument vector.
         * @param {String} command - Newman command name, used for `sinon` result lookup.
         * @param {Function} callback - The callback function invoked on the completion of commander parsing.
         */
        cli = (argv, command, callback) => {
            newmanCLI(argv, (err) => {
                callback(err, _.get(newman, [command, 'lastCall', 'returnValue']));
            });
        };

    beforeEach(function () {
        // removes all listeners assigned previously to avoid exceeding MaxListeners.
        commander.removeAllListeners();

        // delete require cache to use program instance for consecutive runs.
        delete require.cache[require.resolve('../../bin/newman')];
        newmanCLI = require('../../bin/newman');
    });

    describe('Run Command', function () {
        // stub `newman.run`, directly return options passed to `newman.run` in newmanCLI.
        before(function () {
            sinon.stub(newman, 'run').callsFake((options) => {
                return options;
            });
        });

        // restore original `newman.run` function.
        after(function () {
            newman.run.restore();
        });

        it('should pass default options correctly', function (done) {
            cli('node newman.js run collection.json'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;

                    // explicitly match object to track addition/deletion of properties.
                    expect(opts).to.eql({
                        collection: 'collection.json',
                        reporters: ['cli'],
                        delayRequest: 0,
                        globalVar: [],
                        folder: [],
                        color: 'auto',
                        timeout: 0,
                        timeoutRequest: 0,
                        timeoutScript: 0,
                        reporterOptions: {},
                        reporter: { cli: {} }
                    });

                    done();
                });
        });

        it('should handle standard run command (run collection.json and -e)', function (done) {
            cli('node newman.js run myCollection.json --environment env.json -n 2'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts).to.be.ok;
                    expect(opts.iterationCount, 'should have iterationCount of 2').to.equal(2);
                    expect(opts.collection).to.equal('myCollection.json');
                    expect(opts.environment).to.equal('env.json');

                    done();
                });
        });

        it('should throw an error for invalid --iteration-count values', function (done) {
            cli('node newman.js run myCollection.json -n -3.14'.split(' '), 'run', function (err) {
                expect(err).to.have.property('message', 'The value must be a positive integer.');

                done();
            });
        });

        describe('--global-var', function () {
            // test for 'should throw an error for missing --global-var values' has been moved to
            // cli/run-options.test.js since commander throws custom error in case of argument
            //  mismatch and that is better handled through exec and stderr check.
            it('should handle --global-var values without an `=`', function (done) {
                cli('node newman.js run myCollection.json --global-var foo'.split(' '), 'run', function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts.globalVar).to.eql([
                        { key: 'foo', value: undefined }
                    ]);

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

        describe('--color', function () {
            it('should have color `auto` by default', function (done) {
                cli('node newman.js run myCollection.json'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('auto');
                        done();
                    });
            });

            it('should have color enabled with `--color on`', function (done) {
                cli('node newman.js run myCollection.json --color on'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('on');
                        done();
                    });
            });

            it('should have color disabled with `--color off`', function (done) {
                cli('node newman.js run myCollection.json --color off'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('off');
                        done();
                    });
            });

            it('should throw an error for invalid --color values', function (done) {
                cli('node newman.js run myCollection.json --color --disable-unicode'.split(' '), 'run', function (err) {
                    expect(err).to.have.property('message',
                        'invalid value `--disable-unicode` for --color. Expected: auto|on|off');

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

        it('should load all arguments (except reporters)', function (done) {
            cli(('node newman.js run ' +
                'myCollection.json ' +
                '-e myEnv.json ' +
                '-g myGlobals.json ' +
                '-d path/to/csv.csv ' +
                '--folder myFolder ' +
                '--export-environment exported_env.json ' +
                '--export-globals exported_glob.json ' +
                '--postman-api-key POSTMAN_API_KEY ' +
                '--reporter-cli-no-summary ' +
                '--iteration-count 23 ' +
                '--reporters json ' +
                '--global-var foo=bar --global-var alpha==beta= ' +
                '--color off ' +
                '--delay-request 12000 ' +
                '--timeout 10000 ' +
                '--timeout-request 5000 ' +
                '--timeout-script 5000 ' +
                '--ignore-redirects ' +
                '--bail ' +
                '--suppress-exit-code ' +
                '-k').split(' '), 'run', function (err, opts) {
                expect(err).to.be.null;

                expect(opts).to.be.ok;
                expect(opts.collection).to.equal('myCollection.json');
                expect(opts.environment).to.equal('myEnv.json');
                expect(opts.folder).to.eql(['myFolder']);
                expect(opts.exportEnvironment).to.equal('exported_env.json');
                expect(opts.iterationData).to.equal('path/to/csv.csv');
                expect(opts.globals).to.equal('myGlobals.json');
                expect(opts.exportGlobals).to.equal('exported_glob.json');
                expect(opts.postmanApiKey).to.equal('POSTMAN_API_KEY');
                expect(opts.delayRequest, 'should have delayRequest of 12000').to.equal(12000);
                expect(opts.timeout, 'should have timeout of 10000').to.equal(10000);
                expect(opts.timeoutRequest, 'should have timeoutRequest of 5000').to.equal(5000);
                expect(opts.timeoutScript, 'should have timeoutScript of 5000').to.equal(5000);
                expect(opts.ignoreRedirects, 'should have ignoreRedirects to be true').to.equal(true);
                expect(opts.insecure, 'shoudl have insecure to be true').to.equal(true);

                expect(opts.color).to.equal('off');

                expect(opts.reporters).to.contain('json');
                expect(opts.reporters).to.not.contain('junit');

                expect(opts.globalVar).to.eql([
                    { key: 'foo', value: 'bar' },
                    { key: 'alpha', value: '=beta=' }
                ]);

                expect(opts.bail, 'should have bail to be true').to.equal(true);
                expect(opts.suppressExitCode, 'should have suppressExitCode to be true').to.equal(true);

                done();
            });
        });

        it('should load all arguments (including reporters)', function (done) {
            cli(('node newman.js run ' +
                'myCollection.json ' +
                '-e myEnv.json ' +
                '-g myGlobals.json ' +
                '-d /path/to/csv.csv ' +
                '--folder myFolder ' +
                '--disable-unicode ' +
                '--export-environment exported_env.json ' +
                '--export-globals exported_glob.json ' +
                '--reporter-cli-no-summary ' +
                '--reporter-cli-no-success-assertions ' +
                '--iteration-count 23 ' +
                '--reporters json ' +
                '--color on ' +
                '--delay-request 12000 ' +
                '--timeout 10000 ' +
                '--timeout-request 5000 ' +
                '--timeout-script 5000 ' +
                '--ignore-redirects ' +
                '-k ' +
                '--bail folder,failure ' +
                '--global-var foo=bar --global-var alpha==beta= ' +
                '--reporter-json-output ./omg.txt ' +
                '--reporter-use everything').split(' '), 'run', function (err, opts) {
                expect(err).to.be.null;

                expect(opts).to.be.ok;
                expect(opts.collection).to.equal('myCollection.json');
                expect(opts.environment).to.equal('myEnv.json');
                expect(opts.folder).to.eql(['myFolder']);
                expect(opts.disableUnicode, 'should have disableUnicode to be true').to.equal(true);

                expect(opts.exportEnvironment).to.equal('exported_env.json');
                expect(opts.iterationData).to.equal('/path/to/csv.csv');
                expect(opts.globals).to.equal('myGlobals.json');

                expect(opts.exportGlobals).to.equal('exported_glob.json');
                expect(opts.delayRequest, 'should have delayRequest of 12000').to.equal(12000);
                expect(opts.timeout, 'should have timeout of 10000').to.equal(10000);
                expect(opts.timeoutRequest, 'should have timeoutRequest of 5000').to.equal(5000);
                expect(opts.timeoutScript, 'should have timeoutScript of 5000').to.equal(5000);
                expect(opts.ignoreRedirects, 'should have ignoreRedirects to be true').to.equal(true);
                expect(opts.insecure, 'should have insecure to be true').to.equal(true);

                expect(opts.globalVar).to.eql([
                    { key: 'foo', value: 'bar' },
                    { key: 'alpha', value: '=beta=' }
                ]);
                expect(opts.bail).to.eql([
                    'folder',
                    'failure'
                ]);

                expect(opts.color).to.equal('on');

                expect(opts.reporters).to.contain('json');
                expect(opts.reporters).to.not.contain('verbose');
                expect(opts.reporters).to.not.contain('junit');

                // Generic reporter options
                expect(opts.reporterOptions).to.be.ok;
                expect(opts.reporterOptions.use).to.equal('everything');
                expect(opts.reporterOptions.cliNoSuccessAssertions
                    , 'should have cliNoSuccessAssertions to be true').to.equal(true);

                // Individual reporter options
                expect(opts.reporter).to.be.ok;

                // Validate JSON reporter configuration
                expect(opts.reporter.json).to.be.ok;
                expect(opts.reporter.json.output).to.equal('./omg.txt');
                expect(opts.reporter.json.use).to.equal('everything');

                done();
            });
        });

        it('should turn off newman banner if --reporter-cli-no-banner is set', function (done) {
            cli('node newman.js run myCollection.json --reporter-cli-no-banner'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts).to.be.ok;
                    expect(opts.reporter.cli.noBanner, 'should have noBanner to be true').to.equal(true);

                    done();
                });
        });
    });
});
<commit_msg>Update CLI unit test<commit_after>describe('cli parser', function () {
    var _ = require('lodash'),
        sinon = require('sinon'),
        newman = require('../../'),
        commander = require('commander'),
        newmanCLI,

        /**
         * Wrap newmanCLI callback to extract options passed to sinon `newman` stub.
         *
         * @param {String[]} argv - Argument vector.
         * @param {String} command - Newman command name, used for `sinon` result lookup.
         * @param {Function} callback - The callback function invoked on the completion of commander parsing.
         */
        cli = (argv, command, callback) => {
            newmanCLI(argv, (err) => {
                callback(err, _.get(newman, [command, 'lastCall', 'returnValue']));
            });
        };

    beforeEach(function () {
        // removes all listeners assigned previously to avoid exceeding MaxListeners.
        commander.removeAllListeners();

        // delete require cache to use program instance for consecutive runs.
        delete require.cache[require.resolve('../../bin/newman')];
        newmanCLI = require('../../bin/newman');
    });

    describe('Run Command', function () {
        // stub `newman.run`, directly return options passed to `newman.run` in newmanCLI.
        before(function () {
            sinon.stub(newman, 'run').callsFake((options) => {
                return options;
            });
        });

        // restore original `newman.run` function.
        after(function () {
            newman.run.restore();
        });

        it('should pass default options correctly', function (done) {
            cli('node newman.js run collection.json'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;

                    // explicitly match object to track addition/deletion of properties.
                    expect(opts).to.eql({
                        collection: 'collection.json',
                        reporters: ['cli'],
                        delayRequest: 0,
                        globalVar: [],
                        folder: [],
                        color: 'auto',
                        timeout: 0,
                        timeoutRequest: 0,
                        timeoutScript: 0,
                        reporterOptions: {},
                        reporter: { cli: {} }
                    });

                    done();
                });
        });

        it('should handle standard run command (run collection.json and -e)', function (done) {
            cli('node newman.js run myCollection.json --environment env.json -n 2'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts).to.be.ok;
                    expect(opts.iterationCount, 'should have iterationCount of 2').to.equal(2);
                    expect(opts.collection).to.equal('myCollection.json');
                    expect(opts.environment).to.equal('env.json');

                    done();
                });
        });

        it('should throw an error for invalid --iteration-count values', function (done) {
            cli('node newman.js run myCollection.json -n -3.14'.split(' '), 'run', function (err) {
                expect(err).to.have.property('message', 'The value must be a positive integer.');

                done();
            });
        });

        describe('--global-var', function () {
            // test for 'should throw an error for missing --global-var values' has been moved to
            // cli/run-options.test.js since commander throws custom error in case of argument
            //  mismatch and that is better handled through exec and stderr check.
            it('should handle --global-var values without an `=`', function (done) {
                cli('node newman.js run myCollection.json --global-var foo'.split(' '), 'run', function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts.globalVar).to.eql([
                        { key: 'foo', value: undefined }
                    ]);

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

        describe('--color', function () {
            it('should have color `auto` by default', function (done) {
                cli('node newman.js run myCollection.json'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('auto');
                        done();
                    });
            });

            it('should have color enabled with `--color on`', function (done) {
                cli('node newman.js run myCollection.json --color on'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('on');
                        done();
                    });
            });

            it('should have color disabled with `--color off`', function (done) {
                cli('node newman.js run myCollection.json --color off'.split(' '), 'run',
                    function (err, opts) {
                        expect(err).to.be.null;
                        expect(opts.color).to.equal('off');
                        done();
                    });
            });

            it('should throw an error for invalid --color values', function (done) {
                cli('node newman.js run myCollection.json --color --disable-unicode'.split(' '), 'run', function (err) {
                    expect(err).to.have.property('message',
                        'invalid value `--disable-unicode` for --color. Expected: auto|on|off');

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

        it('should load all arguments (except reporters)', function (done) {
            cli(('node newman.js run ' +
                'myCollection.json ' +
                '-e myEnv.json ' +
                '-g myGlobals.json ' +
                '-d path/to/csv.csv ' +
                '--folder myFolder ' +
                '--export-environment exported_env.json ' +
                '--export-globals exported_glob.json ' +
                '--postman-api-key POSTMAN_API_KEY ' +
                '--reporter-cli-no-summary ' +
                '--iteration-count 23 ' +
                '--reporters json ' +
                '--global-var foo=bar --global-var alpha==beta= ' +
                '--color off ' +
                '--delay-request 12000 ' +
                '--timeout 10000 ' +
                '--timeout-request 5000 ' +
                '--timeout-script 5000 ' +
                '--ignore-redirects ' +
                '--bail ' +
                '--suppress-exit-code ' +
                '-k').split(' '), 'run', function (err, opts) {
                expect(err).to.be.null;

                expect(opts).to.be.ok;
                expect(opts.collection).to.equal('myCollection.json');
                expect(opts.environment).to.equal('myEnv.json');
                expect(opts.folder).to.eql(['myFolder']);
                expect(opts.exportEnvironment).to.equal('exported_env.json');
                expect(opts.iterationData).to.equal('path/to/csv.csv');
                expect(opts.globals).to.equal('myGlobals.json');
                expect(opts.exportGlobals).to.equal('exported_glob.json');
                expect(opts.postmanApiKey).to.equal('POSTMAN_API_KEY');
                expect(opts.delayRequest, 'should have delayRequest of 12000').to.equal(12000);
                expect(opts.timeout, 'should have timeout of 10000').to.equal(10000);
                expect(opts.timeoutRequest, 'should have timeoutRequest of 5000').to.equal(5000);
                expect(opts.timeoutScript, 'should have timeoutScript of 5000').to.equal(5000);
                expect(opts.ignoreRedirects, 'should have ignoreRedirects to be true').to.equal(true);
                expect(opts.insecure, 'shoudl have insecure to be true').to.equal(true);

                expect(opts.color).to.equal('off');

                expect(opts.reporters).to.contain('json');
                expect(opts.reporters).to.not.contain('junit');

                expect(opts.globalVar).to.eql([
                    { key: 'foo', value: 'bar' },
                    { key: 'alpha', value: '=beta=' }
                ]);

                expect(opts.bail, 'should have bail to be true').to.equal(true);
                expect(opts.suppressExitCode, 'should have suppressExitCode to be true').to.equal(true);

                done();
            });
        });

        it('should load all arguments (including reporters)', function (done) {
            cli(('node newman.js run ' +
                'myCollection.json ' +
                '-e myEnv.json ' +
                '-g myGlobals.json ' +
                '-d /path/to/csv.csv ' +
                '--folder myFolder1 ' +
                '--folder myFolder2 ' +
                '--disable-unicode ' +
                '--export-environment exported_env.json ' +
                '--export-globals exported_glob.json ' +
                '--reporter-cli-no-summary ' +
                '--reporter-cli-no-success-assertions ' +
                '--iteration-count 23 ' +
                '--reporters json ' +
                '--color on ' +
                '--delay-request 12000 ' +
                '--timeout 10000 ' +
                '--timeout-request 5000 ' +
                '--timeout-script 5000 ' +
                '--ignore-redirects ' +
                '-k ' +
                '--bail folder,failure ' +
                '--global-var foo=bar --global-var alpha==beta= ' +
                '--reporter-json-output ./omg.txt ' +
                '--reporter-use everything').split(' '), 'run', function (err, opts) {
                expect(err).to.be.null;

                expect(opts).to.be.ok;
                expect(opts.collection).to.equal('myCollection.json');
                expect(opts.environment).to.equal('myEnv.json');
                expect(opts.folder).to.eql(['myFolder1', 'myFolder2']);
                expect(opts.disableUnicode, 'should have disableUnicode to be true').to.equal(true);

                expect(opts.exportEnvironment).to.equal('exported_env.json');
                expect(opts.iterationData).to.equal('/path/to/csv.csv');
                expect(opts.globals).to.equal('myGlobals.json');

                expect(opts.exportGlobals).to.equal('exported_glob.json');
                expect(opts.delayRequest, 'should have delayRequest of 12000').to.equal(12000);
                expect(opts.timeout, 'should have timeout of 10000').to.equal(10000);
                expect(opts.timeoutRequest, 'should have timeoutRequest of 5000').to.equal(5000);
                expect(opts.timeoutScript, 'should have timeoutScript of 5000').to.equal(5000);
                expect(opts.ignoreRedirects, 'should have ignoreRedirects to be true').to.equal(true);
                expect(opts.insecure, 'should have insecure to be true').to.equal(true);

                expect(opts.globalVar).to.eql([
                    { key: 'foo', value: 'bar' },
                    { key: 'alpha', value: '=beta=' }
                ]);
                expect(opts.bail).to.eql([
                    'folder',
                    'failure'
                ]);

                expect(opts.color).to.equal('on');

                expect(opts.reporters).to.contain('json');
                expect(opts.reporters).to.not.contain('verbose');
                expect(opts.reporters).to.not.contain('junit');

                // Generic reporter options
                expect(opts.reporterOptions).to.be.ok;
                expect(opts.reporterOptions.use).to.equal('everything');
                expect(opts.reporterOptions.cliNoSuccessAssertions
                    , 'should have cliNoSuccessAssertions to be true').to.equal(true);

                // Individual reporter options
                expect(opts.reporter).to.be.ok;

                // Validate JSON reporter configuration
                expect(opts.reporter.json).to.be.ok;
                expect(opts.reporter.json.output).to.equal('./omg.txt');
                expect(opts.reporter.json.use).to.equal('everything');

                done();
            });
        });

        it('should turn off newman banner if --reporter-cli-no-banner is set', function (done) {
            cli('node newman.js run myCollection.json --reporter-cli-no-banner'.split(' '), 'run',
                function (err, opts) {
                    expect(err).to.be.null;
                    expect(opts).to.be.ok;
                    expect(opts.reporter.cli.noBanner, 'should have noBanner to be true').to.equal(true);

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


<commit_before>var Store = require('../../../../store')

module.exports = function(title, beforeFn, afterFn, storeConf){
  describe(title + ': Nested Set', function(){
    var store

    before(beforeFn)
    after(function(next){
      afterFn(next, store)
    })

    before(function(){
      store = new Store(storeConf)

      store.Model('Folder', function(){
        this.nestedSet()
      })
    })

    it('returns only the first level', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(0)
          folders[1].children.length.should.be.equal(0)
        })
      })
    })

    it('returns the first level and all its children', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withChildren().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
        })
      })
    })

    it('returns the first level and all nested children', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(1)
          folders[1].children[1].children[0].children.length.should.be.equal(1)
        })
      })
    })

    it('returns the first level and all nested children, but only until depth 1', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren(1).exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(0)
        })
      })
    })

    it('returns the first level and all nested children, but only until depth 2', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren(2).exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(1)
          folders[1].children[1].children[0].children.length.should.be.equal(0)
        })
      })
    })

    it('adds a new child element', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(4).exec(function(folder){
          var originalRgt = folder.rgt

          folder.children.add({
            name: 'B1.1'
          })

          return folder.save(function(){
            return Folder.find(3).withAllChildren(2).exec(function(folder){
              folder.children[0].name.should.be.equal('B1')
              folder.children[0].lft.should.be.equal(folder.lft + 1)
              folder.children[0].rgt.should.be.equal(folder.children[0].lft + 3)

              folder.children[0].children[0].name.should.be.equal('B1.1')
              folder.children[0].children[0].lft.should.be.equal(folder.children[0].lft + 1)
              folder.children[0].children[0].rgt.should.be.equal(folder.children[0].rgt - 1)

              originalRgt.should.not.be.equal(folder.rgt)
            })
          })
        })
      })
    })

    it('adds a new child and sibling element', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){
          var originalRgt = folder.rgt

          folder.children.add({
            name: 'B2.1.2'
          })

          return folder.save(function(){
            return Folder.find(5).withAllChildren().exec(function(folder){
              folder.children[0].name.should.be.equal('B2.1')
              folder.children[0].lft.should.be.equal(folder.lft + 1)
              folder.children[0].rgt.should.be.equal(folder.children[0].lft + 5)

              folder.children[0].children.length.should.be.equal(2)

              folder.children[0].children[0].name.should.be.equal('B2.1.1')
              folder.children[0].children[0].lft.should.be.equal(folder.children[0].lft + 1)
              folder.children[0].children[0].rgt.should.be.equal(folder.children[0].children[0].lft + 1)

              folder.children[0].children[1].name.should.be.equal('B2.1.2')
              folder.children[0].children[1].lft.should.be.equal(folder.children[0].lft + 3)
              folder.children[0].children[1].rgt.should.be.equal(folder.children[0].children[1].lft + 1)

              originalRgt.should.not.be.equal(folder.rgt)
            })
          })
        })
      })
    })

    it('moves an  element "up"', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(1).exec(function(folder){ // => A
          folder.moveToChildOf(3) // => B

          return folder.save(function(){
            return Folder.find(3).withAllChildren(2).order('lft').exec(function(folder){
              folder.children.length.should.be.equal(3)

              folder.children[2].name.should.be.equal('A')
              folder.children[2].lft.should.not.be.equal(0)
              folder.children[2].rgt.should.not.be.equal(3)
              folder.children[2].depth.should.be.equal(1)
            })
          })
        })
      })
    })

    it('moves an  element "down"', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.moveToChildOf(4) // => B1

          return folder.save(function(){
            return Folder.find(4).withAllChildren().order('lft').exec(function(folder){
              folder.children.length.should.be.equal(2)

              folder.children[1].name.should.be.equal('B2.1')
              folder.children[1].children.length.should.be.equal(2)
            })
          })
        })
      })
    })

    it('deletes a node (and its child nodes)', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(1).exec(function(folder){ // => A
          return folder.destroy(function(){
            return Folder.order('lft').exec(function(folders){
              folders.length.should.be.equal(7)

              folders[0].name.should.be.equal('B')
              folders[0].lft.should.be.equal(0)
              folders[0].rgt.should.be.equal(13)
            })
          })
        })
      })
    })

    it('moves an element to the root node', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 3

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(5)
              folders[4].id.should.be.equal(6)
              folders[5].id.should.be.equal(7)
              folders[6].id.should.be.equal(9)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(1)
              folders[4].depth.should.be.equal(1)
              folders[5].depth.should.be.equal(2)
              folders[6].depth.should.be.equal(2)
            })
          })
        })
      })
    })

    it('moves an  element to parent=0', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 0

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(5)
              folders[4].id.should.be.equal(6)
              folders[5].id.should.be.equal(7)
              folders[6].id.should.be.equal(9)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(1)
              folders[4].depth.should.be.equal(0)
              folders[5].depth.should.be.equal(1)
              folders[6].depth.should.be.equal(1)

              folders[0].lft.should.be.equal(0)
              folders[1].lft.should.be.equal(1)
              folders[2].lft.should.be.equal(2)
              folders[3].lft.should.be.equal(5)
              folders[4].lft.should.be.equal(8)
              folders[5].lft.should.be.equal(9)
              folders[6].lft.should.be.equal(11)

              folders[0].rgt.should.be.equal(7)
              folders[1].rgt.should.be.equal(4)
              folders[2].rgt.should.be.equal(3)
              folders[3].rgt.should.be.equal(6)
              folders[4].rgt.should.be.equal(13)
              folders[5].rgt.should.be.equal(10)
              folders[6].rgt.should.be.equal(12)
            })
          })
        })
      })
    })

    it('moves an  element to parent=8 and then parent=0', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 8

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(6)
              folders[4].id.should.be.equal(7)
              folders[5].id.should.be.equal(9)
              folders[6].id.should.be.equal(5)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(3)
              folders[4].depth.should.be.equal(4)
              folders[5].depth.should.be.equal(4)
              folders[6].depth.should.be.equal(1)

              folder = folders[3] // => B2.1
              folder.parent_id = 0

              return folder.save(function(){
                return Folder.order('lft').exec(function(folders){
                  console.log(folders)
                  folders[0].id.should.be.equal(3)
                  folders[1].id.should.be.equal(4)
                  folders[2].id.should.be.equal(8)
                  folders[3].id.should.be.equal(5)
                  folders[4].id.should.be.equal(6)
                  folders[5].id.should.be.equal(7)
                  folders[6].id.should.be.equal(9)

                  folders[0].depth.should.be.equal(0)
                  folders[1].depth.should.be.equal(1)
                  folders[2].depth.should.be.equal(2)
                  folders[3].depth.should.be.equal(1)
                  folders[4].depth.should.be.equal(0)
                  folders[5].depth.should.be.equal(1)
                  folders[6].depth.should.be.equal(1)

                  folders[0].lft.should.be.equal(0)
                  folders[1].lft.should.be.equal(1)
                  folders[2].lft.should.be.equal(2)
                  folders[3].lft.should.be.equal(5)
                  folders[4].lft.should.be.equal(8)
                  folders[5].lft.should.be.equal(9)
                  folders[6].lft.should.be.equal(11)

                  folders[0].rgt.should.be.equal(7)
                  folders[1].rgt.should.be.equal(4)
                  folders[2].rgt.should.be.equal(3)
                  folders[3].rgt.should.be.equal(6)
                  folders[4].rgt.should.be.equal(13)
                  folders[5].rgt.should.be.equal(10)
                  folders[6].rgt.should.be.equal(12)
                })
              })
            })
          })
        })
      })
    })
  })
}
<commit_msg>remove test log<commit_after>var Store = require('../../../../store')

module.exports = function(title, beforeFn, afterFn, storeConf){
  describe(title + ': Nested Set', function(){
    var store

    before(beforeFn)
    after(function(next){
      afterFn(next, store)
    })

    before(function(){
      store = new Store(storeConf)

      store.Model('Folder', function(){
        this.nestedSet()
      })
    })

    it('returns only the first level', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(0)
          folders[1].children.length.should.be.equal(0)
        })
      })
    })

    it('returns the first level and all its children', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withChildren().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
        })
      })
    })

    it('returns the first level and all nested children', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren().exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(1)
          folders[1].children[1].children[0].children.length.should.be.equal(1)
        })
      })
    })

    it('returns the first level and all nested children, but only until depth 1', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren(1).exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(0)
        })
      })
    })

    it('returns the first level and all nested children, but only until depth 2', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.rootOnly().withAllChildren(2).exec(function(folders){
          folders.length.should.be.equal(2)

          folders[0].children.length.should.be.equal(1)
          folders[1].children.length.should.be.equal(2)
          folders[1].children[1].children.length.should.be.equal(1)
          folders[1].children[1].children[0].children.length.should.be.equal(0)
        })
      })
    })

    it('adds a new child element', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(4).exec(function(folder){
          var originalRgt = folder.rgt

          folder.children.add({
            name: 'B1.1'
          })

          return folder.save(function(){
            return Folder.find(3).withAllChildren(2).exec(function(folder){
              folder.children[0].name.should.be.equal('B1')
              folder.children[0].lft.should.be.equal(folder.lft + 1)
              folder.children[0].rgt.should.be.equal(folder.children[0].lft + 3)

              folder.children[0].children[0].name.should.be.equal('B1.1')
              folder.children[0].children[0].lft.should.be.equal(folder.children[0].lft + 1)
              folder.children[0].children[0].rgt.should.be.equal(folder.children[0].rgt - 1)

              originalRgt.should.not.be.equal(folder.rgt)
            })
          })
        })
      })
    })

    it('adds a new child and sibling element', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){
          var originalRgt = folder.rgt

          folder.children.add({
            name: 'B2.1.2'
          })

          return folder.save(function(){
            return Folder.find(5).withAllChildren().exec(function(folder){
              folder.children[0].name.should.be.equal('B2.1')
              folder.children[0].lft.should.be.equal(folder.lft + 1)
              folder.children[0].rgt.should.be.equal(folder.children[0].lft + 5)

              folder.children[0].children.length.should.be.equal(2)

              folder.children[0].children[0].name.should.be.equal('B2.1.1')
              folder.children[0].children[0].lft.should.be.equal(folder.children[0].lft + 1)
              folder.children[0].children[0].rgt.should.be.equal(folder.children[0].children[0].lft + 1)

              folder.children[0].children[1].name.should.be.equal('B2.1.2')
              folder.children[0].children[1].lft.should.be.equal(folder.children[0].lft + 3)
              folder.children[0].children[1].rgt.should.be.equal(folder.children[0].children[1].lft + 1)

              originalRgt.should.not.be.equal(folder.rgt)
            })
          })
        })
      })
    })

    it('moves an  element "up"', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(1).exec(function(folder){ // => A
          folder.moveToChildOf(3) // => B

          return folder.save(function(){
            return Folder.find(3).withAllChildren(2).order('lft').exec(function(folder){
              folder.children.length.should.be.equal(3)

              folder.children[2].name.should.be.equal('A')
              folder.children[2].lft.should.not.be.equal(0)
              folder.children[2].rgt.should.not.be.equal(3)
              folder.children[2].depth.should.be.equal(1)
            })
          })
        })
      })
    })

    it('moves an  element "down"', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.moveToChildOf(4) // => B1

          return folder.save(function(){
            return Folder.find(4).withAllChildren().order('lft').exec(function(folder){
              folder.children.length.should.be.equal(2)

              folder.children[1].name.should.be.equal('B2.1')
              folder.children[1].children.length.should.be.equal(2)
            })
          })
        })
      })
    })

    it('deletes a node (and its child nodes)', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(1).exec(function(folder){ // => A
          return folder.destroy(function(){
            return Folder.order('lft').exec(function(folders){
              folders.length.should.be.equal(7)

              folders[0].name.should.be.equal('B')
              folders[0].lft.should.be.equal(0)
              folders[0].rgt.should.be.equal(13)
            })
          })
        })
      })
    })

    it('moves an element to the root node', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 3

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(5)
              folders[4].id.should.be.equal(6)
              folders[5].id.should.be.equal(7)
              folders[6].id.should.be.equal(9)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(1)
              folders[4].depth.should.be.equal(1)
              folders[5].depth.should.be.equal(2)
              folders[6].depth.should.be.equal(2)
            })
          })
        })
      })
    })

    it('moves an  element to parent=0', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 0

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(5)
              folders[4].id.should.be.equal(6)
              folders[5].id.should.be.equal(7)
              folders[6].id.should.be.equal(9)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(1)
              folders[4].depth.should.be.equal(0)
              folders[5].depth.should.be.equal(1)
              folders[6].depth.should.be.equal(1)

              folders[0].lft.should.be.equal(0)
              folders[1].lft.should.be.equal(1)
              folders[2].lft.should.be.equal(2)
              folders[3].lft.should.be.equal(5)
              folders[4].lft.should.be.equal(8)
              folders[5].lft.should.be.equal(9)
              folders[6].lft.should.be.equal(11)

              folders[0].rgt.should.be.equal(7)
              folders[1].rgt.should.be.equal(4)
              folders[2].rgt.should.be.equal(3)
              folders[3].rgt.should.be.equal(6)
              folders[4].rgt.should.be.equal(13)
              folders[5].rgt.should.be.equal(10)
              folders[6].rgt.should.be.equal(12)
            })
          })
        })
      })
    })

    it('moves an  element to parent=8 and then parent=0', function(){
      return store.ready(function(){
        var Folder = store.Model('Folder')
        return Folder.find(6).exec(function(folder){ // => B2.1
          folder.parent_id = 8

          return folder.save(function(){
            return Folder.order('lft').exec(function(folders){
              folders[0].id.should.be.equal(3)
              folders[1].id.should.be.equal(4)
              folders[2].id.should.be.equal(8)
              folders[3].id.should.be.equal(6)
              folders[4].id.should.be.equal(7)
              folders[5].id.should.be.equal(9)
              folders[6].id.should.be.equal(5)

              folders[0].depth.should.be.equal(0)
              folders[1].depth.should.be.equal(1)
              folders[2].depth.should.be.equal(2)
              folders[3].depth.should.be.equal(3)
              folders[4].depth.should.be.equal(4)
              folders[5].depth.should.be.equal(4)
              folders[6].depth.should.be.equal(1)

              folder = folders[3] // => B2.1
              folder.parent_id = 0

              return folder.save(function(){
                return Folder.order('lft').exec(function(folders){
                  folders[0].id.should.be.equal(3)
                  folders[1].id.should.be.equal(4)
                  folders[2].id.should.be.equal(8)
                  folders[3].id.should.be.equal(5)
                  folders[4].id.should.be.equal(6)
                  folders[5].id.should.be.equal(7)
                  folders[6].id.should.be.equal(9)

                  folders[0].depth.should.be.equal(0)
                  folders[1].depth.should.be.equal(1)
                  folders[2].depth.should.be.equal(2)
                  folders[3].depth.should.be.equal(1)
                  folders[4].depth.should.be.equal(0)
                  folders[5].depth.should.be.equal(1)
                  folders[6].depth.should.be.equal(1)

                  folders[0].lft.should.be.equal(0)
                  folders[1].lft.should.be.equal(1)
                  folders[2].lft.should.be.equal(2)
                  folders[3].lft.should.be.equal(5)
                  folders[4].lft.should.be.equal(8)
                  folders[5].lft.should.be.equal(9)
                  folders[6].lft.should.be.equal(11)

                  folders[0].rgt.should.be.equal(7)
                  folders[1].rgt.should.be.equal(4)
                  folders[2].rgt.should.be.equal(3)
                  folders[3].rgt.should.be.equal(6)
                  folders[4].rgt.should.be.equal(13)
                  folders[5].rgt.should.be.equal(10)
                  folders[6].rgt.should.be.equal(12)
                })
              })
            })
          })
        })
      })
    })
  })
}
<|endoftext|>