<commit_before>var assert = require('assert');
var string = require('../');

describe('String', function() {

    var equal = assert.strictEqual;

    describe('#toString()', function() {
        it('Returns a string representation of the object', function() {
            var toString = string.toString;
            equal(toString(undefined) , '');
            equal(toString(null)      , '');
            equal(toString(NaN)       , '');
            equal(toString(Infinity)  , '');
            equal(toString(123)       , '123');
            equal(toString('123')     , '123');
            equal(toString({})        , '[object Object]');
            equal(toString([])        , '');
        });
    });

    describe('#hashCode()', function() {
        it('Returns a hash code for this string', function() {
            var hashCode = string.hashCode;
            equal(hashCode(undefined) , 0);
            equal(hashCode(null)      , 0);
            equal(hashCode('')        , 0);
            equal(hashCode('abc')     , 96354);
        });
    });

    describe('#isEmpty()', function() {
        it('Checks if a String is empty or null', function() {
            var isEmpty = string.isEmpty;
            equal(isEmpty(undefined) , true);
            equal(isEmpty(null)      , true);
            equal(isEmpty('')        , true);
            equal(isEmpty('\n')      , false);
            equal(isEmpty('aaa')     , false);
        });
    });

    describe('#isBlank()', function() {
        it('Checks if a String is whitespace, empty or null', function() {
            var isBlank = string.isBlank;
            equal(isBlank(undefined) , true);
            equal(isBlank(null)      , true);
            equal(isBlank('')        , true);
            equal(isBlank('\n')      , true);
            equal(isBlank('aaa')     , false);
        });
    });

    describe('#startsWith()', function() {
        it('Check if a String starts with a specified prefix.', function() {
            var startsWith = string.startsWith;
            equal(startsWith(undefined, '*') , false);
            equal(startsWith(null, '*')      , false);
            equal(startsWith('', '*')        , false);
            equal(startsWith('', '')         , true);
            equal(startsWith('abc', 'a')     , true);
            equal(startsWith('abc', 'c')     , false);
        });
    });

    describe('#endsWith()', function() {
        it('Check if a String ends with a specified suffix.', function() {
            var endsWith = string.endsWith;
            equal(endsWith(undefined, '*') , false);
            equal(endsWith(null, '*')      , false);
            equal(endsWith('', '*')        , false);
            equal(endsWith('', '')         , true);
            equal(endsWith('abc', 'a')     , false);
            equal(endsWith('abc', 'c')     , true);
        });
    });

    describe('#before()', function() {
        it('Gets the substring before the first occurrence of a separator', function() {
            var before = string.before;
            equal(before(null, '*')    , '');
            equal(before('', '*')      , '');
            equal(before('abc', 'a')   , '');
            equal(before('abcba', 'b') , 'a');
            equal(before('abc', 'c')   , 'ab');
            equal(before('abc', 'd')   , 'abc');
            equal(before('abc', '')    , '');
            equal(before('abc', null)  , 'abc');
        });
    });

    describe('#beforeLast()', function() {
        it('Gets the substring before the last occurrence of a separator', function() {
            var beforeLast = string.beforeLast;
            equal(beforeLast(null, '*')    , '');
            equal(beforeLast('', '*')      , '');
            equal(beforeLast('abc', 'a')   , '');
            equal(beforeLast('abcba', 'b') , 'abc');
            equal(beforeLast('abc', 'c')   , 'ab');
            equal(beforeLast('abc', 'd')   , 'abc');
            equal(beforeLast('abc', '')    , 'abc');
            equal(beforeLast('abc', null)  , 'abc');
        });
    });

    describe('#after()', function() {
        it('Gets the substring after the first occurrence of a separator', function() {
            var after = string.after;
            equal(after(null, '*')    , '');
            equal(after('', '*')      , '');
            equal(after('*', null)    , '');
            equal(after('abc', 'a')   , 'bc');
            equal(after('abcba', 'b') , 'cba');
            equal(after('abc', 'c')   , '');
            equal(after('abc', 'd')   , '');
            equal(after('abc', '')    , 'abc');
        });
    });

    describe('#afterLast()', function() {
        it('Gets the substring after the last occurrence of a separator', function() {
            var afterLast = string.afterLast;
            equal(afterLast(null, '*')    , '');
            equal(afterLast('', '*')      , '');
            equal(afterLast('*', null)    , '');
            equal(afterLast('abc', 'a')   , 'bc');
            equal(afterLast('abcba', 'b') , 'a');
            equal(afterLast('abc', 'c')   , '');
            equal(afterLast('abc', 'd')   , '');
            equal(afterLast('abc', '')    , '');
        });
    });

    describe('#between()', function() {
        it('Gets the substring between open and close tag', function() {
            var between = string.between;
            equal(between(null, '*')         , '');
            equal(between('abcba', 'a')      , 'bcb');
            equal(between('abcba', 'a', 'c') , 'b');
        });
    });
});
<commit_msg>update tests<commit_after>var assert = require('assert');
var string = require('../');

describe('String', function() {

    var equal = assert.strictEqual;

    describe('#toString()', function() {
        it('Returns a string representation of the object', function() {
            var toString = string.toString;
            equal(toString(undefined) , '');
            equal(toString(null)      , '');
            equal(toString(NaN)       , '');
            equal(toString(Infinity)  , '');
            equal(toString(123)       , '123');
            equal(toString('123')     , '123');
            equal(toString({})        , '[object Object]');
            equal(toString([])        , '');
        });
    });

    describe('#hashCode()', function() {
        it('Returns a hash code for this string', function() {
            var hashCode = string.hashCode;
            equal(hashCode(undefined) , 0);
            equal(hashCode(null)      , 0);
            equal(hashCode('')        , 0);
            equal(hashCode('abc')     , 96354);
        });
    });

    describe('#isEmpty()', function() {
        it('Checks if a String is empty or null', function() {
            var isEmpty = string.isEmpty;
            equal(isEmpty(undefined) , true);
            equal(isEmpty(null)      , true);
            equal(isEmpty('')        , true);
            equal(isEmpty('\n')      , false);
            equal(isEmpty('aaa')     , false);
        });
    });

    describe('#isBlank()', function() {
        it('Checks if a String is whitespace, empty or null', function() {
            var isBlank = string.isBlank;
            equal(isBlank(undefined) , true);
            equal(isBlank(null)      , true);
            equal(isBlank('')        , true);
            equal(isBlank('\n')      , true);
            equal(isBlank('aaa')     , false);
        });
    });

    describe('#startsWith()', function() {
        it('Check if a String starts with a specified prefix.', function() {
            var startsWith = string.startsWith;
            equal(startsWith(undefined, '*') , false);
            equal(startsWith(null, '*')      , false);
            equal(startsWith('', '*')        , false);
            equal(startsWith('', '')         , true);
            equal(startsWith('abc', 'a')     , true);
            equal(startsWith('abc', 'c')     , false);
            equal(startsWith('abc', '')      , true);
        });
    });

    describe('#endsWith()', function() {
        it('Check if a String ends with a specified suffix.', function() {
            var endsWith = string.endsWith;
            equal(endsWith(undefined, '*') , false);
            equal(endsWith(null, '*')      , false);
            equal(endsWith('', '*')        , false);
            equal(endsWith('', '')         , true);
            equal(endsWith('abc', 'a')     , false);
            equal(endsWith('abc', 'c')     , true);
            equal(endsWith('abc', '')      , true);
        });
    });

    describe('#before()', function() {
        it('Gets the substring before the first occurrence of a separator', function() {
            var before = string.before;
            equal(before(null, '*')    , '');
            equal(before('', '*')      , '');
            equal(before('abc', 'a')   , '');
            equal(before('abcba', 'b') , 'a');
            equal(before('abc', 'c')   , 'ab');
            equal(before('abc', 'd')   , 'abc');
            equal(before('abc', '')    , '');
            equal(before('abc', null)  , 'abc');
        });
    });

    describe('#beforeLast()', function() {
        it('Gets the substring before the last occurrence of a separator', function() {
            var beforeLast = string.beforeLast;
            equal(beforeLast(null, '*')    , '');
            equal(beforeLast('', '*')      , '');
            equal(beforeLast('abc', 'a')   , '');
            equal(beforeLast('abcba', 'b') , 'abc');
            equal(beforeLast('abc', 'c')   , 'ab');
            equal(beforeLast('abc', 'd')   , 'abc');
            equal(beforeLast('abc', '')    , 'abc');
            equal(beforeLast('abc', null)  , 'abc');
        });
    });

    describe('#after()', function() {
        it('Gets the substring after the first occurrence of a separator', function() {
            var after = string.after;
            equal(after(null, '*')    , '');
            equal(after('', '*')      , '');
            equal(after('*', null)    , '');
            equal(after('abc', 'a')   , 'bc');
            equal(after('abcba', 'b') , 'cba');
            equal(after('abc', 'c')   , '');
            equal(after('abc', 'd')   , '');
            equal(after('abc', '')    , 'abc');
        });
    });

    describe('#afterLast()', function() {
        it('Gets the substring after the last occurrence of a separator', function() {
            var afterLast = string.afterLast;
            equal(afterLast(null, '*')    , '');
            equal(afterLast('', '*')      , '');
            equal(afterLast('*', null)    , '');
            equal(afterLast('abc', 'a')   , 'bc');
            equal(afterLast('abcba', 'b') , 'a');
            equal(afterLast('abc', 'c')   , '');
            equal(afterLast('abc', 'd')   , '');
            equal(afterLast('abc', '')    , '');
        });
    });

    describe('#between()', function() {
        it('Gets the substring between open and close tag', function() {
            var between = string.between;
            equal(between(null, '*')         , '');
            equal(between('abcba', 'a')      , 'bcb');
            equal(between('abcba', 'a', 'c') , 'b');
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

var test = require('tap').test,
  documentation = require('../'),
  outputMarkdown = require('../lib/output/markdown.js'),
  outputMarkdownAST = require('../lib/output/markdown_ast.js'),
  outputHtml = require('../lib/output/html.js'),
  normalize = require('./normalize'),
  glob = require('glob'),
  path = require('path'),
  fs = require('fs'),
  chdir = require('chdir');

var UPDATE = !!process.env.UPDATE;

function makePOJO(ast) {
  return JSON.parse(JSON.stringify(ast));
}

if (fs.existsSync(path.join(__dirname, '../.git'))) {
  test('git option', function (t) {
    var file = path.join(__dirname, './fixture/simple.input.js');
    documentation([file], { github: true }, function (err, result) {
      t.ifError(err);
      normalize(result);
      var outputfile = file.replace('.input.js', '.output.github.json');
      if (UPDATE) {
        fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
      }
      var expect = require(outputfile);
      t.deepEqual(result, expect);

      outputMarkdown(result, null, function (err, result) {
        t.ifError(err);
        var outputfile = file.replace('.input.js', '.output.github.md');
        if (UPDATE) {
          fs.writeFileSync(outputfile, result, 'utf8');
        }
        var expect = fs.readFileSync(outputfile, 'utf8');
        t.equal(result.toString(), expect, 'markdown output correct');
        t.end();
      });
    });
  });
}

test('external modules option', function (t) {
  documentation([
    path.join(__dirname, 'fixture', 'external.input.js')
  ], {
    external: '(external|external/node_modules/*)'
  }, function (err, result) {
    t.ifError(err);
    normalize(result);
    var outputfile = path.join(__dirname, 'fixture', '_external-deps-included.json');
    if (UPDATE) {
      fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
    }
    var expect = require(outputfile);
    t.deepEqual(result, expect);
    t.end();
  });
});

test('parse', function (tt) {
  glob.sync(path.join(__dirname, 'fixture', '*.input.js')).forEach(function (file) {
    tt.test(file, function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        normalize(result);
        var outputfile = file.replace('.input.js', '.output.json');
        if (UPDATE) {
          fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
        }
        var expect = require(outputfile);
        t.deepEqual(makePOJO(result), expect);
        t.end();
      });
    });
  });
  tt.end();
});

test('bad input', function (tt) {
  glob.sync(path.join(__dirname, 'fixture/bad', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (error, res) {
        t.equal(res, undefined);
        // make error a serializable object
        error = JSON.parse(JSON.stringify(error));
        // remove system-specific path
        delete error.filename;
        delete error.codeFrame;
        var outputfile = file.replace('.input.js', '.output.json');
        if (UPDATE) {
          fs.writeFileSync(outputfile, JSON.stringify(error, null, 2));
        }
        var expect = JSON.parse(fs.readFileSync(outputfile));
        t.deepEqual(error, expect);
        t.end();
      });
    });
  });
  tt.end();
});

test('html', function (tt) {
  glob.sync(path.join(__dirname, 'fixture/html', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputHtml(result, null, function (err, result) {
          t.ifError(err);
          var clean = result.sort(function (a, b) {
            return a.path > b.path;
          }).filter(function (r) {
            return (!r.path.match(/json$/));
          }).map(function (r) {
            return r.contents;
          }).join('\n');
          var outputfile = file.replace('.input.js', '.output.files');
          if (UPDATE) {
            fs.writeFileSync(outputfile, clean, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.deepEqual(clean, expect);
          t.end();
        });
      });
    });
  });
  tt.end();
});

test('markdown', function (tt) {
  glob.sync(path.join(__dirname, 'fixture', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdown(result, null, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.md');
          if (UPDATE) {
            fs.writeFileSync(outputfile, result, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.equal(result.toString(), expect, 'markdown output correct');
          t.end();
        });
      });
    });

    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdownAST(result, null, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.md.json');
          if (UPDATE) {
            fs.writeFileSync(outputfile, JSON.stringify(result, null, 2), 'utf8');
          }
          var expect = JSON.parse(fs.readFileSync(outputfile, 'utf8'));
          t.deepEqual(result, expect, 'markdown AST output correct');
          t.end();
        });
      });
    });

    tt.test(path.basename(file) + ' custom', function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdown(result, {
          theme: path.join(__dirname, '/misc/')
        }, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.custom.md');
          if (UPDATE) {
            fs.writeFileSync(outputfile, result, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.equal(result.toString(), expect, 'custom output correct');
          t.end();
        });
      });
    });
  });
  tt.end();
});

test('highlightAuto md output', function (t) {
  var file = path.join(__dirname, 'fixture/auto_lang_hljs/multilanguage.input.js'),
    hljsConfig = {hljs: {highlightAuto: true, languages: ['js', 'css', 'html']}};

  documentation(file, null, function (err, result) {
    t.ifError(err);
    outputMarkdown(result, hljsConfig, function (err, result) {
      t.ifError(err);
      var outputfile = file.replace('.input.js', '.output.md');
      if (UPDATE) {
        fs.writeFileSync(outputfile, result, 'utf8');
      }
      var expect = fs.readFileSync(outputfile, 'utf8');
      t.equal(result.toString(), expect, 'recognizes examples in html, css and js');
      t.end();
    });
  });
});

test('multi-file input', function (t) {
  documentation([
    path.join(__dirname, 'fixture', 'simple.input.js'),
    path.join(__dirname, 'fixture', 'simple-two.input.js')
  ], null, function (err, result) {
    t.ifError(err);
    normalize(result);
    var outputfile = path.join(__dirname, 'fixture', '_multi-file-input.json');
    if (UPDATE) {
      fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
    }
    var expect = require(outputfile);
    t.deepEqual(result, expect);
    t.end();
  });
});

test('accepts simple relative paths', function (t) {
  chdir(__dirname, function () {
    documentation('fixture/simple.input.js', null, function (err, data) {
      t.ifError(err);
      t.equal(data.length, 1, 'simple has no dependencies');
      t.end();
    });
  });
});

test('.lint', function (t) {
  chdir(__dirname, function () {
    documentation.lint('fixture/simple.input.js', null, function (err, data) {
      t.ifError(err);
      t.equal(data, '', 'outputs lint information');
      t.end();
    });
  });
});

test('.lint with bad input', function (t) {
  chdir(__dirname, function () {
    documentation.lint('fixture/bad/syntax.input.js', null, function (err, data) {
      t.ok(err, 'returns an error when syntax is incorrect');
      t.end();
    });
  });
});
<commit_msg>Use path.basename(file) consistently<commit_after>'use strict';

var test = require('tap').test,
  documentation = require('../'),
  outputMarkdown = require('../lib/output/markdown.js'),
  outputMarkdownAST = require('../lib/output/markdown_ast.js'),
  outputHtml = require('../lib/output/html.js'),
  normalize = require('./normalize'),
  glob = require('glob'),
  path = require('path'),
  fs = require('fs'),
  chdir = require('chdir');

var UPDATE = !!process.env.UPDATE;

function makePOJO(ast) {
  return JSON.parse(JSON.stringify(ast));
}

if (fs.existsSync(path.join(__dirname, '../.git'))) {
  test('git option', function (t) {
    var file = path.join(__dirname, './fixture/simple.input.js');
    documentation([file], { github: true }, function (err, result) {
      t.ifError(err);
      normalize(result);
      var outputfile = file.replace('.input.js', '.output.github.json');
      if (UPDATE) {
        fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
      }
      var expect = require(outputfile);
      t.deepEqual(result, expect);

      outputMarkdown(result, null, function (err, result) {
        t.ifError(err);
        var outputfile = file.replace('.input.js', '.output.github.md');
        if (UPDATE) {
          fs.writeFileSync(outputfile, result, 'utf8');
        }
        var expect = fs.readFileSync(outputfile, 'utf8');
        t.equal(result.toString(), expect, 'markdown output correct');
        t.end();
      });
    });
  });
}

test('external modules option', function (t) {
  documentation([
    path.join(__dirname, 'fixture', 'external.input.js')
  ], {
    external: '(external|external/node_modules/*)'
  }, function (err, result) {
    t.ifError(err);
    normalize(result);
    var outputfile = path.join(__dirname, 'fixture', '_external-deps-included.json');
    if (UPDATE) {
      fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
    }
    var expect = require(outputfile);
    t.deepEqual(result, expect);
    t.end();
  });
});

test('parse', function (tt) {
  glob.sync(path.join(__dirname, 'fixture', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        normalize(result);
        var outputfile = file.replace('.input.js', '.output.json');
        if (UPDATE) {
          fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
        }
        var expect = require(outputfile);
        t.deepEqual(makePOJO(result), expect);
        t.end();
      });
    });
  });
  tt.end();
});

test('bad input', function (tt) {
  glob.sync(path.join(__dirname, 'fixture/bad', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (error, res) {
        t.equal(res, undefined);
        // make error a serializable object
        error = JSON.parse(JSON.stringify(error));
        // remove system-specific path
        delete error.filename;
        delete error.codeFrame;
        var outputfile = file.replace('.input.js', '.output.json');
        if (UPDATE) {
          fs.writeFileSync(outputfile, JSON.stringify(error, null, 2));
        }
        var expect = JSON.parse(fs.readFileSync(outputfile));
        t.deepEqual(error, expect);
        t.end();
      });
    });
  });
  tt.end();
});

test('html', function (tt) {
  glob.sync(path.join(__dirname, 'fixture/html', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputHtml(result, null, function (err, result) {
          t.ifError(err);
          var clean = result.sort(function (a, b) {
            return a.path > b.path;
          }).filter(function (r) {
            return (!r.path.match(/json$/));
          }).map(function (r) {
            return r.contents;
          }).join('\n');
          var outputfile = file.replace('.input.js', '.output.files');
          if (UPDATE) {
            fs.writeFileSync(outputfile, clean, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.deepEqual(clean, expect);
          t.end();
        });
      });
    });
  });
  tt.end();
});

test('markdown', function (tt) {
  glob.sync(path.join(__dirname, 'fixture', '*.input.js')).forEach(function (file) {
    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdown(result, null, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.md');
          if (UPDATE) {
            fs.writeFileSync(outputfile, result, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.equal(result.toString(), expect, 'markdown output correct');
          t.end();
        });
      });
    });

    tt.test(path.basename(file), function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdownAST(result, null, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.md.json');
          if (UPDATE) {
            fs.writeFileSync(outputfile, JSON.stringify(result, null, 2), 'utf8');
          }
          var expect = JSON.parse(fs.readFileSync(outputfile, 'utf8'));
          t.deepEqual(result, expect, 'markdown AST output correct');
          t.end();
        });
      });
    });

    tt.test(path.basename(file) + ' custom', function (t) {
      documentation([file], null, function (err, result) {
        t.ifError(err);
        outputMarkdown(result, {
          theme: path.join(__dirname, '/misc/')
        }, function (err, result) {
          t.ifError(err);
          var outputfile = file.replace('.input.js', '.output.custom.md');
          if (UPDATE) {
            fs.writeFileSync(outputfile, result, 'utf8');
          }
          var expect = fs.readFileSync(outputfile, 'utf8');
          t.equal(result.toString(), expect, 'custom output correct');
          t.end();
        });
      });
    });
  });
  tt.end();
});

test('highlightAuto md output', function (t) {
  var file = path.join(__dirname, 'fixture/auto_lang_hljs/multilanguage.input.js'),
    hljsConfig = {hljs: {highlightAuto: true, languages: ['js', 'css', 'html']}};

  documentation(file, null, function (err, result) {
    t.ifError(err);
    outputMarkdown(result, hljsConfig, function (err, result) {
      t.ifError(err);
      var outputfile = file.replace('.input.js', '.output.md');
      if (UPDATE) {
        fs.writeFileSync(outputfile, result, 'utf8');
      }
      var expect = fs.readFileSync(outputfile, 'utf8');
      t.equal(result.toString(), expect, 'recognizes examples in html, css and js');
      t.end();
    });
  });
});

test('multi-file input', function (t) {
  documentation([
    path.join(__dirname, 'fixture', 'simple.input.js'),
    path.join(__dirname, 'fixture', 'simple-two.input.js')
  ], null, function (err, result) {
    t.ifError(err);
    normalize(result);
    var outputfile = path.join(__dirname, 'fixture', '_multi-file-input.json');
    if (UPDATE) {
      fs.writeFileSync(outputfile, JSON.stringify(result, null, 2));
    }
    var expect = require(outputfile);
    t.deepEqual(result, expect);
    t.end();
  });
});

test('accepts simple relative paths', function (t) {
  chdir(__dirname, function () {
    documentation('fixture/simple.input.js', null, function (err, data) {
      t.ifError(err);
      t.equal(data.length, 1, 'simple has no dependencies');
      t.end();
    });
  });
});

test('.lint', function (t) {
  chdir(__dirname, function () {
    documentation.lint('fixture/simple.input.js', null, function (err, data) {
      t.ifError(err);
      t.equal(data, '', 'outputs lint information');
      t.end();
    });
  });
});

test('.lint with bad input', function (t) {
  chdir(__dirname, function () {
    documentation.lint('fixture/bad/syntax.input.js', null, function (err, data) {
      t.ok(err, 'returns an error when syntax is incorrect');
      t.end();
    });
  });
});
<|endoftext|>


<commit_before>var engine = require("../../engine").engine;
var factories = require("../spec_helper").component_factories;
var task;

describe("Sandbox Security", function(){

    beforeEach(function(){
	waits(500);

	runs(function(){

	    this.identifier = "security" + Math.floor(Math.random() * 100000);

	    this.intake = factories.create_ipc_intake(this.identifier);
	    this.exhaust = factories.create_ipc_exhaust(this.identifier);
	    this.cylinder = (factories.create_ipc_cylinders(1,this.identifier))["1"];
	    this.client = (factories.create_ipc_clients(1,this.identifier))["1"];
	});
    });

    afterEach(function(){
	this.intake.close();
	this.exhaust.close();
	this.cylinder.close();
	this.client.close();
    });

    var getLastEval = function(cb) {
      return cb.mostRecentCall.args[1].getEvaluation();
    }

  xdescribe("getting outside the sandbox", function(){
    it("cannot manipulate the host context", function(){
      var context = "(function(){ var host_date = new Date(); return { foo: function(){ return host_date; } } })";
      var callback = jasmine.createSpy();
      var callback2 = jasmine.createSpy();

      runs(function(){
        task = this.client.createTask();
        task.setContext(context);
        task.setLocals({});
        task.setCode("foo().__proto__.hacked = function(){ return 'YEP!'}; foo().hacked();");
        task.on('eval', callback);
        task.on('eval', function(err, response){
          console.log(response);
        });
        task.run();
      });

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
        var task2 = this.client.createTask();
        task2.setContext("(function(){ return {} })");
        task2.setLocals({});
        task2.setCode("(new Date()).hacked()");
        //task2.on('eval', callback2);
        task2.on('eval', function(){
          console.log(arguments[1]);
        });
        task2.run();
      });

      waitsFor(function(){
	return callback2.callCount > 0;
      });

      runs(function(){
        //console.log(callback2);
	//expect(getLastEval(callback2)).not.toContain("YEP!");
      });

    });
  });

    describe("Function#toString attack", function(){
	it("throws a SecurityError when trying to call '.toString' on a context function", function(){
            var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return { foo: function(){ return 'bar' } } })");
            task.setLocals({});
            task.setCode("foo.toString()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).toContain("SecurityError");
            });

	});
    });

    describe("Function constructor attack",function(){
	it("throws a SecurityError when trying to call an explicit context function's constructor", function(){
            var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return { foo: function(){ } } })");
            task.setLocals({});
            task.setCode("foo.constructor('return process')()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).toContain("ReferenceError");
            });

	});

	xit("throws a SecurityError when trying to call an implicit context function's constructor", function(){
            var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("console.log.constructor('return process')()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).toContain("SecurityError");
            });

	});
    });

    describe("Function caller attack", function(){
	it("throws a TypeError when trying to walk the 'caller chain' from a locally defined & invoked function out of the sandbox", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("(function foo() { foo.caller.caller.toString(); })()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).toContain("TypeError");
            });
	});

	it("throws a TypeError when trying to walk the 'argument caller chain' from a locally defined & invoked function out of the sandbox", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("(function foo() {return [].slice.call(foo.caller.caller.arguments);})()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).toContain("TypeError");
            });
	});
    });

    describe("user-defined hook attacks", function(){
	it("'toJSON' methods cannot walk outside the sandbox", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("(function foo() {return {toJSON:function x(){ return x.caller.name}}})()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(getLastEval(callback)).not.toContain("stringify");
		expect(getLastEval(callback)).toContain("SecurityError");
            });
	});

	it("'toJSON' methods cannot walk outside the sandbox (nested)", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("(function foo() {return {foo:'bar', test: {toJSON:function x(){ return x.caller.name}}}})()");
            task.on('eval', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(JSON.stringify(callback.mostRecentCall.args[1])).toContain("SecurityError");
            });
	});

	xit("'inspect' method cannot walk outside the sandbox", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("console.log({inspect: function x(){ return x.caller.caller.name } })");
            task.on('output', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(callback.mostRecentCall.args[0]).toContain("SecurityError");
            });
	});

	xit("'inspect' method cannot walk outside the sandbox (nested)", function(){
	    var callback = jasmine.createSpy();
            task = this.client.createTask();
            task.setContext("(function(locals){ return {  } })");
            task.setLocals({});
            task.setCode("console.log({foo: 'bar', test: {inspect: function x(){ return x.caller.caller.name } }})");
            task.on('output', callback);
            task.run();

            waitsFor(function(){
		return callback.callCount > 0;
            });

            runs(function(){
		expect(callback.mostRecentCall.args[0]).toContain("SecurityError");
            });
	});

    });

});
<commit_msg>Change tab indentation<commit_after>var engine = require("../../engine").engine;
var factories = require("../spec_helper").component_factories;
var task;

describe("Sandbox Security", function(){

  beforeEach(function(){
    waits(500);

    runs(function(){

      this.identifier = "security" + Math.floor(Math.random() * 100000);

      this.intake = factories.create_ipc_intake(this.identifier);
      this.exhaust = factories.create_ipc_exhaust(this.identifier);
      this.cylinder = (factories.create_ipc_cylinders(1,this.identifier))["1"];
      this.client = (factories.create_ipc_clients(1,this.identifier))["1"];
    });
  });

  afterEach(function(){
    this.intake.close();
    this.exhaust.close();
    this.cylinder.close();
    this.client.close();
  });

  var getLastEval = function(cb) {
    return cb.mostRecentCall.args[1].getEvaluation();
  };

  xdescribe("getting outside the sandbox", function(){
    it("cannot manipulate the host context", function(){
      var context = "(function(){ var host_date = new Date(); return { foo: function(){ return host_date; } } })";
      var callback = jasmine.createSpy();
      var callback2 = jasmine.createSpy();

      runs(function(){
        task = this.client.createTask();
        task.setContext(context);
        task.setLocals({});
        task.setCode("foo().__proto__.hacked = function(){ return 'YEP!'}; foo().hacked();");
        task.on('eval', callback);
        task.on('eval', function(err, response){
          console.log(response);
        });
        task.run();
      });

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
        var task2 = this.client.createTask();
        task2.setContext("(function(){ return {} })");
        task2.setLocals({});
        task2.setCode("(new Date()).hacked()");
        //task2.on('eval', callback2);
        task2.on('eval', function(){
          console.log(arguments[1]);
        });
        task2.run();
      });

      waitsFor(function(){
	return callback2.callCount > 0;
      });

      runs(function(){
        //console.log(callback2);
	//expect(getLastEval(callback2)).not.toContain("YEP!");
      });

    });
  });

  describe("Function#toString attack", function(){
    it("throws a SecurityError when trying to call '.toString' on a context function", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return { foo: function(){ return 'bar' } } })");
      task.setLocals({});
      task.setCode("foo.toString()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).toContain("SecurityError");
      });

    });
  });

  describe("Function constructor attack",function(){
    it("throws a SecurityError when trying to call an explicit context function's constructor", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return { foo: function(){ } } })");
      task.setLocals({});
      task.setCode("foo.constructor('return process')()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).toContain("ReferenceError");
      });

    });

    xit("throws a SecurityError when trying to call an implicit context function's constructor", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("console.log.constructor('return process')()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).toContain("SecurityError");
      });

    });
  });

  describe("Function caller attack", function(){
    it("throws a TypeError when trying to walk the 'caller chain' from a locally defined & invoked function out of the sandbox", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("(function foo() { foo.caller.caller.toString(); })()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).toContain("TypeError");
      });
    });

    it("throws a TypeError when trying to walk the 'argument caller chain' from a locally defined & invoked function out of the sandbox", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("(function foo() {return [].slice.call(foo.caller.caller.arguments);})()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).toContain("TypeError");
      });
    });
  });

  describe("user-defined hook attacks", function(){
    it("'toJSON' methods cannot walk outside the sandbox", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("(function foo() {return {toJSON:function x(){ return x.caller.name}}})()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(getLastEval(callback)).not.toContain("stringify");
	expect(getLastEval(callback)).toContain("SecurityError");
      });
    });

    it("'toJSON' methods cannot walk outside the sandbox (nested)", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("(function foo() {return {foo:'bar', test: {toJSON:function x(){ return x.caller.name}}}})()");
      task.on('eval', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(JSON.stringify(callback.mostRecentCall.args[1])).toContain("SecurityError");
      });
    });

    xit("'inspect' method cannot walk outside the sandbox", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("console.log({inspect: function x(){ return x.caller.caller.name } })");
      task.on('output', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(callback.mostRecentCall.args[0]).toContain("SecurityError");
      });
    });

    xit("'inspect' method cannot walk outside the sandbox (nested)", function(){
      var callback = jasmine.createSpy();
      task = this.client.createTask();
      task.setContext("(function(locals){ return {  } })");
      task.setLocals({});
      task.setCode("console.log({foo: 'bar', test: {inspect: function x(){ return x.caller.caller.name } }})");
      task.on('output', callback);
      task.run();

      waitsFor(function(){
	return callback.callCount > 0;
      });

      runs(function(){
	expect(callback.mostRecentCall.args[0]).toContain("SecurityError");
      });
    });

  });

});
<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

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.
*/
import React, {Component, PropTypes} from 'react';
import Immutable from 'immutable';

import classNames from 'classnames';
import provide from 'react-redux-provide';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import ProviderHelpers from 'common/ProviderHelpers';
import PromiseWrapper from 'views/components/Document/PromiseWrapper';
import Header from 'views/pages/explore/dialect/header';
import PageHeader from 'views/pages/explore/dialect/page-header';
import SearchBar from 'views/pages/explore/dialect/search-bar';

import Paper from 'material-ui/lib/paper';
import RaisedButton from 'material-ui/lib/raised-button';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import FlatButton from 'material-ui/lib/flat-button';
import CircularProgress from 'material-ui/lib/circular-progress';
import IconMenu from 'material-ui/lib/menus/icon-menu';
import IconButton from 'material-ui/lib/icon-button';
import MenuItem from 'material-ui/lib/menus/menu-item';
import NavigationExpandMoreIcon from 'material-ui/lib/svg-icons/navigation/expand-more';

import EditableComponent, {EditableComponentHelper} from 'views/components/Editor/EditableComponent';

import StatsPanel from 'views/components/Dashboard/StatsPanel';
import Link from 'views/components/Document/Link';
import AuthorizationFilter from 'views/components/Document/AuthorizationFilter';

/**
* Learn portion of the dialect portal
*/
@provide
export default class DialectLearn extends Component {

  static propTypes = {
    properties: PropTypes.object.isRequired,
    navigateTo: PropTypes.func.isRequired,
    windowPath: PropTypes.string.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    pushWindowPath: PropTypes.func.isRequired,
    fetchDialect2: PropTypes.func.isRequired,
    updateDialect2: PropTypes.func.isRequired,
    computeDialect2: PropTypes.object.isRequired,
    computePortal: PropTypes.object.isRequired,
    updatePortal: PropTypes.func.isRequired,
    fetchPortal: PropTypes.func.isRequired,
    fetchDialectStats: PropTypes.func.isRequired,
    computeDialectStats: PropTypes.object.isRequired,
    fetchCharacters: PropTypes.func.isRequired,
    computeCharacters: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    routeParams: PropTypes.object.isRequired
  };

  constructor(props, context){
    super(props, context);

    //this._handlePhrasesDataRequest = this._handlePhrasesDataRequest.bind(this);
    //this._handleWordsDataRequest = this._handleWordsDataRequest.bind(this);

    // Bind methods to 'this'
    ['_onNavigateRequest'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  _onNavigateRequest(path) {
    const destination = this.props.navigateTo(path);
    const newPathArray = this.props.splitWindowPath.slice();

    newPathArray.push(destination.path);

    this.props.pushWindowPath('/' + newPathArray.join('/'));
  }

  fetchData(newProps) {
    newProps.fetchDialect2(newProps.routeParams.dialect_path);
    newProps.fetchPortal(newProps.routeParams.dialect_path + '/Portal');
    newProps.fetchDialectStats(newProps.routeParams.dialect_path, {'dialectPath': newProps.routeParams.dialect_path, 'docTypes': ["words","phrases","songs","stories"]});
    newProps.fetchCharacters(newProps.routeParams.dialect_path + '/Alphabet');
  }

  // Fetch data on initial render
  componentDidMount() {
    this.fetchData(this.props);
  }

  // Refetch data on URL change
  componentWillReceiveProps(nextProps) {
    if (nextProps.windowPath !== this.props.windowPath) {
      this.fetchData(nextProps);
    }
  }

  _onCharAudioTouchTap(charAudioId) {
	  document.getElementById(charAudioId).play();
  }

  render() {

    const computeEntities = Immutable.fromJS([{
      'id': this.props.routeParams.dialect_path,
      'entity': this.props.computeDialect2
    }, {
      'id': this.props.routeParams.dialect_path + '/Portal',
      'entity': this.props.computePortal
    }])

    const computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.props.routeParams.dialect_path);
    const computePortal = ProviderHelpers.getEntry(this.props.computePortal, this.props.routeParams.dialect_path + '/Portal');
    const computeDialectStats = ProviderHelpers.getEntry(this.props.computeDialectStats, this.props.routeParams.dialect_path);

    const isSection = this.props.routeParams.area === 'sections';

    const { updatePortal, computeLogin, computeDocument, computeCharacters } = this.props;

    //let dialect = computeDialect2.response;

    let characters = computeCharacters.response;

    let circularProgress = <CircularProgress mode="indeterminate" size={3} />;

    return <PromiseWrapper computeEntities={computeEntities}>

            <PageHeader title="Language Area" portalLogo={selectn('response.contextParameters.portal.fv-portal:logo.path', computePortal)} dialectName={selectn('response.title', computeDialect2)} />

              {(() => {
                if (selectn("isConnected", computeLogin) || selectn('response.properties.fv-portal:greeting', computePortal) || selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal)) {
                  return

                    <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                      <EditableComponentHelper className="fv-portal-greeting" isSection={isSection} computeEntity={computePortal} updateEntity={updatePortal} property="fv-portal:greeting" entity={selectn('response', computePortal)} />
                    </AuthorizationFilter>

                    {(selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal)) ?
                     <audio id="portalFeaturedAudio" src={ConfGlobal.baseURL + selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal).path} controls />
                    : ''}

;
                }
              })()}

            <Toolbar>

              <ToolbarGroup firstChild={true} float="left">
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'words')} label={(selectn('response.words.total', computeDialectStats) == undefined) ? "Words (0)" : "Words (" + selectn('response.words.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'phrases')} label={(selectn('response.phrases.total', computeDialectStats) == undefined) ? "Phrases (0)" : "Phrases (" + selectn('response.phrases.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'stories')} label={(selectn('response.stories.total', computeDialectStats) == undefined) ? "Stories (0)" : "Stories (" + selectn('response.stories.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'songs')} label={(selectn('response.songs.total', computeDialectStats) == undefined) ? "Songs (0)" : "Songs (" + selectn('response.songs.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
              </ToolbarGroup>

              <ToolbarGroup float="right">
                <SearchBar />
              </ToolbarGroup>

            </Toolbar>

About our Language

                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                  <EditableComponent computeEntity={computeDialect2} updateEntity={this.props.updateDialect2} property="dc:description" />
                </AuthorizationFilter>

                    {(() => {
                      if (characters && characters.entries) {
                        return <Paper style={{padding: '25px', marginBottom: '20px'}} zDepth={2}>

Our Alphabet

                          {characters.entries.map((char, i) =>

                              {char.title}

                              {(char.contextParameters.character.related_audio[0]) ?

                                  <audio id={'charAudio' + char.uid}  src={ConfGlobal.baseURL + char.contextParameters.character.related_audio[0].path} />

                              : ''}

                          )}
                        </Paper>;
                      }
                    })()}

                  {(() => {
                    if (selectn('response.contextParameters.dialect.keyboards', computeDialect2)) {
                      return <Paper style={{padding: '25px', marginBottom: '20px'}} zDepth={2}>

Our Keyboards

                        {(selectn('response.contextParameters.dialect.keyboards', computeDialect2) || []).map((keyboardLink, i) =>
                          <Link key={i} data={keyboardLink} showDescription={true} />
                        )}
                      </Paper>;
                    }
                  })()}

Dashboard

                {(selectn('response', computeDialectStats)) ?

		                <StatsPanel data={selectn('response', computeDialectStats)} docType="words" headerText="Words" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="phrases" headerText="Phrases" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="songs" headerText="Songs" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="stories" headerText="Stories" />

                : circularProgress}

Contact Information

                  <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                    <EditableComponent computeEntity={computeDialect2} updateEntity={this.props.updateDialect2} property="fvdialect:contact_information" />
                  </AuthorizationFilter>

        </PromiseWrapper>;
  }
}<commit_msg>Don't show keyboards and alphabet if empty<commit_after>/*
Copyright 2016 First People's Cultural Council

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.
*/
import React, {Component, PropTypes} from 'react';
import Immutable from 'immutable';

import classNames from 'classnames';
import provide from 'react-redux-provide';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import ProviderHelpers from 'common/ProviderHelpers';
import PromiseWrapper from 'views/components/Document/PromiseWrapper';
import Header from 'views/pages/explore/dialect/header';
import PageHeader from 'views/pages/explore/dialect/page-header';
import SearchBar from 'views/pages/explore/dialect/search-bar';

import Paper from 'material-ui/lib/paper';
import RaisedButton from 'material-ui/lib/raised-button';
import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import FlatButton from 'material-ui/lib/flat-button';
import CircularProgress from 'material-ui/lib/circular-progress';
import IconMenu from 'material-ui/lib/menus/icon-menu';
import IconButton from 'material-ui/lib/icon-button';
import MenuItem from 'material-ui/lib/menus/menu-item';
import NavigationExpandMoreIcon from 'material-ui/lib/svg-icons/navigation/expand-more';

import EditableComponent, {EditableComponentHelper} from 'views/components/Editor/EditableComponent';

import StatsPanel from 'views/components/Dashboard/StatsPanel';
import Link from 'views/components/Document/Link';
import AuthorizationFilter from 'views/components/Document/AuthorizationFilter';

/**
* Learn portion of the dialect portal
*/
@provide
export default class DialectLearn extends Component {

  static propTypes = {
    properties: PropTypes.object.isRequired,
    navigateTo: PropTypes.func.isRequired,
    windowPath: PropTypes.string.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    pushWindowPath: PropTypes.func.isRequired,
    fetchDialect2: PropTypes.func.isRequired,
    updateDialect2: PropTypes.func.isRequired,
    computeDialect2: PropTypes.object.isRequired,
    computePortal: PropTypes.object.isRequired,
    updatePortal: PropTypes.func.isRequired,
    fetchPortal: PropTypes.func.isRequired,
    fetchDialectStats: PropTypes.func.isRequired,
    computeDialectStats: PropTypes.object.isRequired,
    fetchCharacters: PropTypes.func.isRequired,
    computeCharacters: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    routeParams: PropTypes.object.isRequired
  };

  constructor(props, context){
    super(props, context);

    //this._handlePhrasesDataRequest = this._handlePhrasesDataRequest.bind(this);
    //this._handleWordsDataRequest = this._handleWordsDataRequest.bind(this);

    // Bind methods to 'this'
    ['_onNavigateRequest'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  _onNavigateRequest(path) {
    const destination = this.props.navigateTo(path);
    const newPathArray = this.props.splitWindowPath.slice();

    newPathArray.push(destination.path);

    this.props.pushWindowPath('/' + newPathArray.join('/'));
  }

  fetchData(newProps) {
    newProps.fetchDialect2(newProps.routeParams.dialect_path);
    newProps.fetchPortal(newProps.routeParams.dialect_path + '/Portal');
    newProps.fetchDialectStats(newProps.routeParams.dialect_path, {'dialectPath': newProps.routeParams.dialect_path, 'docTypes': ["words","phrases","songs","stories"]});
    newProps.fetchCharacters(newProps.routeParams.dialect_path + '/Alphabet');
  }

  // Fetch data on initial render
  componentDidMount() {
    this.fetchData(this.props);
  }

  // Refetch data on URL change
  componentWillReceiveProps(nextProps) {
    if (nextProps.windowPath !== this.props.windowPath) {
      this.fetchData(nextProps);
    }
  }

  _onCharAudioTouchTap(charAudioId) {
	  document.getElementById(charAudioId).play();
  }

  render() {

    const computeEntities = Immutable.fromJS([{
      'id': this.props.routeParams.dialect_path,
      'entity': this.props.computeDialect2
    }, {
      'id': this.props.routeParams.dialect_path + '/Portal',
      'entity': this.props.computePortal
    }])

    const computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.props.routeParams.dialect_path);
    const computePortal = ProviderHelpers.getEntry(this.props.computePortal, this.props.routeParams.dialect_path + '/Portal');
    const computeDialectStats = ProviderHelpers.getEntry(this.props.computeDialectStats, this.props.routeParams.dialect_path);

    const isSection = this.props.routeParams.area === 'sections';

    const { updatePortal, computeLogin, computeDocument, computeCharacters } = this.props;

    //let dialect = computeDialect2.response;

    let characters = computeCharacters.response;

    let circularProgress = <CircularProgress mode="indeterminate" size={3} />;

    return <PromiseWrapper computeEntities={computeEntities}>

            <PageHeader title="Language Area" portalLogo={selectn('response.contextParameters.portal.fv-portal:logo.path', computePortal)} dialectName={selectn('response.title', computeDialect2)} />

              {(() => {
                if (selectn("isConnected", computeLogin) || selectn('response.properties.fv-portal:greeting', computePortal) || selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal)) {
                  return

                    <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                      <EditableComponentHelper className="fv-portal-greeting" isSection={isSection} computeEntity={computePortal} updateEntity={updatePortal} property="fv-portal:greeting" entity={selectn('response', computePortal)} />
                    </AuthorizationFilter>

                    {(selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal)) ?
                     <audio id="portalFeaturedAudio" src={ConfGlobal.baseURL + selectn('response.contextParameters.portal.fv-portal:featured_audio', computePortal).path} controls />
                    : ''}

;
                }
              })()}

            <Toolbar>

              <ToolbarGroup firstChild={true} float="left">
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'words')} label={(selectn('response.words.total', computeDialectStats) == undefined) ? "Words (0)" : "Words (" + selectn('response.words.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'phrases')} label={(selectn('response.phrases.total', computeDialectStats) == undefined) ? "Phrases (0)" : "Phrases (" + selectn('response.phrases.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'stories')} label={(selectn('response.stories.total', computeDialectStats) == undefined) ? "Stories (0)" : "Stories (" + selectn('response.stories.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
                <FlatButton onTouchTap={this._onNavigateRequest.bind(this, 'songs')} label={(selectn('response.songs.total', computeDialectStats) == undefined) ? "Songs (0)" : "Songs (" + selectn('response.songs.total', computeDialectStats) + ")"} /> <ToolbarSeparator />
              </ToolbarGroup>

              <ToolbarGroup float="right">
                <SearchBar />
              </ToolbarGroup>

            </Toolbar>

About our Language

                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                  <EditableComponent computeEntity={computeDialect2} updateEntity={this.props.updateDialect2} property="dc:description" />
                </AuthorizationFilter>

                    {(() => {
                      if (selectn('characters.entries.length', characters) > 0) {
                        return <Paper style={{padding: '25px', marginBottom: '20px'}} zDepth={2}>

Our Alphabet

                          {characters.entries.map((char, i) =>

                              {char.title}

                              {(char.contextParameters.character.related_audio[0]) ?

                                  <audio id={'charAudio' + char.uid}  src={ConfGlobal.baseURL + char.contextParameters.character.related_audio[0].path} />

                              : ''}

                          )}
                        </Paper>;
                      }
                    })()}

                  {(() => {
                    if (selectn('response.contextParameters.dialect.keyboards.length', computeDialect2) > 0) {
                      return <Paper style={{padding: '25px', marginBottom: '20px'}} zDepth={2}>

Our Keyboards

                        {(selectn('response.contextParameters.dialect.keyboards', computeDialect2) || []).map((keyboardLink, i) =>
                          <Link key={i} data={keyboardLink} showDescription={true} />
                        )}
                      </Paper>;
                    }
                  })()}

Dashboard

                {(selectn('response', computeDialectStats)) ?

		                <StatsPanel data={selectn('response', computeDialectStats)} docType="words" headerText="Words" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="phrases" headerText="Phrases" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="songs" headerText="Songs" />
		                <StatsPanel data={selectn('response', computeDialectStats)} docType="stories" headerText="Stories" />

                : circularProgress}

Contact Information

                  <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeDialect2)}} renderPartial={true}>
                    <EditableComponent computeEntity={computeDialect2} updateEntity={this.props.updateDialect2} property="fvdialect:contact_information" />
                  </AuthorizationFilter>

        </PromiseWrapper>;
  }
}<|endoftext|>


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

    var DIR                 = process.cwd() + '/',
        main                = require(DIR + 'lib/server/main'),

        Util                = main.util,

        CloudFunc           = main.cloudfunc,
        HTMLDIR             = main.HTMLDIR,
        files               = main.files,

        TEMPLATEPATH        = HTMLDIR + 'file.html',
        LINK_TEMPLATE_PATH  = HTMLDIR + 'link.html',
        PATHTEMPLATE_PATH   = HTMLDIR + 'path.html',
        EXPECT_PATH         = DIR + 'test/expect.html',

        Files               = [TEMPLATEPATH, PATHTEMPLATE_PATH, LINK_TEMPLATE_PATH, EXPECT_PATH],

        JSON_Files = {
            path  : "/etc/X11/",
            files : [{
                name: "applnk",
                size: "dir",
                uid : 0,
                mode: "40755"
            }, {
                name: "prefdm",
                size: 1328,
                uid : 0,
                mode: "100755"
            }]
        },

        Expect =
            '
'           +
                ''                           +
                ''                                                       +
                ''+
                    ''                         +
                ''                                            +
                    '/'                             +
                    ''                           +
                        'etc'                                                   +
                    '/X11/'                                                 +
                ''                                                       +
            '
'                                                             +
            '
'                                              +
                ''                                 +
                '"name reduce-text"'                    +
                '"size reduce-text"'                    +
                '"owner reduce-text"'                  +
                '"mode reduce-text"'                    +
            '
';

    files.read(Files, 'utf-8', function(errors, files) {
        var i, n, template, pathTemplate, linkTemplate, expect, result;

        if (errors)
            Util.log(errors);
        else {
            Util.time('CloudFunc.buildFromJSON');

            template        = files[TEMPLATEPATH];
            pathTemplate    = files[PATHTEMPLATE_PATH];
            linkTemplate    = files[LINK_TEMPLATE_PATH];
            expect          = files[EXPECT_PATH];

            result          = CloudFunc.buildFromJSON(JSON_FILES, template, pathTemplate, linkTemplate);

            Expect          += expect;

            n = Expect.length;
            for (i = 0; i < n; i++)
                if (result[i] !== Expect[i]){
                    Util.log('Error in char number: ' + i    + '\n' +
                                'Expect: ' + Expect.substr(i)  + '\n' +
                                'Result: ' + result.substr(i) );
                    break;
                }

                if (i === n)
                    console.log('CloudFunc.buildFromJSON: OK');

            Util.timeEnd('CloudFunc.buildFromJSON');
        }
    });

})();
<commit_msg>chore(test) add " "<commit_after>(function() {
    'use strict';

    var DIR                 = process.cwd() + '/',
        main                = require(DIR + 'lib/server/main'),

        Util                = main.util,

        CloudFunc           = main.cloudfunc,
        HTMLDIR             = main.HTMLDIR,
        files               = main.files,

        TEMPLATEPATH        = HTMLDIR + 'file.html',
        LINK_TEMPLATE_PATH  = HTMLDIR + 'link.html',
        PATHTEMPLATE_PATH   = HTMLDIR + 'path.html',
        EXPECT_PATH         = DIR + 'test/expect.html',

        Files               = [TEMPLATEPATH, PATHTEMPLATE_PATH, LINK_TEMPLATE_PATH, EXPECT_PATH],

        JSON_Files = {
            path  : "/etc/X11/",
            files : [{
                name: "applnk",
                size: "dir",
                uid : 0,
                mode: "40755"
            }, {
                name: "prefdm",
                size: 1328,
                uid : 0,
                mode: "100755"
            }]
        },

        Expect =
            '
'           +
                ''                           +
                ''                                                       +
                ''+
                    ''                         +
                ''                                            +
                    '/'                             +
                    ''                           +
                        'etc'                                                   +
                    '/X11/'                                                 +
                ''                                                       +
            '
'                                                             +
            '
'                                              +
                ''                                 +
                '"name reduce-text"'                    +
                '"size reduce-text"'                    +
                '"owner reduce-text"'                  +
                '"mode reduce-text"'                    +
            '
';

    files.read(Files, 'utf-8', function(errors, files) {
        var i, n, template, pathTemplate, linkTemplate, expect, result;

        if (errors)
            Util.log(errors);
        else {
            Util.time('CloudFunc.buildFromJSON');

            template        = files[TEMPLATEPATH];
            pathTemplate    = files[PATHTEMPLATE_PATH];
            linkTemplate    = files[LINK_TEMPLATE_PATH];
            expect          = files[EXPECT_PATH];

            result          = CloudFunc.buildFromJSON(JSON_FILES, template, pathTemplate, linkTemplate);

            Expect          += expect;

            n = Expect.length;
            for (i = 0; i < n; i++)
                if (result[i] !== Expect[i]) {
                    Util.log('Error in char number: ' + i    + '\n' +
                                'Expect: ' + Expect.substr(i)  + '\n' +
                                'Result: ' + result.substr(i) );
                    break;
                }

                if (i === n)
                    console.log('CloudFunc.buildFromJSON: OK');

            Util.timeEnd('CloudFunc.buildFromJSON');
        }
    });

})();
<|endoftext|>


<commit_before>QUnit.config.testTimeout = 10000;

QUnit.test("No syntax errors - test", function( assert ) {
  assert.equal(parse({main: ['1|"    Hello World !"']}, "main").error_cnt, 0, "Hello world");
  assert.equal(parse({main: ['1|5->A:Lbl 1:A:Dsz A:Goto 1:"      Ignition !"']}, "main").error_cnt, 0, "Dsz parse test");
  assert.equal(parse({main: ['1|Goto 1:Lbl 1:"Done."']}, "main").error_cnt, 0, "Label declared after goto using it.");
  assert.equal(parse({main: ['1|Int(Ran#*100+1)->R']}, "main").error_cnt, 0, "Int(Ran#) affected to a var");
  assert.equal(parse({main: ['1|5->A:If A>0:Then "A > 0":IfEnd']}, "main").error_cnt, 0, "If...Then..IfEnd");
  assert.equal(parse({main: ['1|1->A:0->B:A And B:A Or B:A Xor B:Not A']}, "main").error_cnt, 0, "And/Or/Xor/Not");
  assert.equal(parse({main: ['1|Mcl:2->θ:3->r:5rθ:']}, "main").error_cnt, 0, "Rho / Theta");
  assert.equal(parse({main: ['1|Dim List 1:8->Dim List 1:Seq(X, X, 0, 5, 1->List 1:List 1[4]:File2']}, "main").error_cnt, 0, "List Syntax Elmt");
  assert.equal(parse({main: ['1|RanInt#(3,5):']}, "main").error_cnt, 0, "RanInt");
  assert.equal(parse({main: ['1|For 1->A To 10:Next:']}, "main").error_cnt, 0, "For/Next");
  assert.equal(parse({main: ['1|AxesOn:AxesOff:ClrGraph:']}, "main").error_cnt, 0, "AxesOn, AxesOff, ClrGraph");
  assert.equal(parse({main: ['1|SortA(List 1:SortA(List 1):']}, "main").error_cnt, 0, "SortA(, SortA()");
});

QUnit.test("Syntax errors - test", function( assert ) {
  assert.notEqual(parse({main: ['1|Gato 1:Lbl 1:"Done."']}, "main").error_cnt, 0, "Uncorrectly named 'Goto' instruction");
  assert.notEqual(parse({main: ['1|5->A:If A>0 Then "A > 0" IfEnd']}, "main").error_cnt, 0, "If...Then..IfEnd (mono line)");
});

QUnit.test("jsccRun - test", function( assert ) {
  var testsToRun = [{
      name: 'A-1 test',
      srcCode: `
        5->A
        A-1
      `,
      answer: 4
    },
    {
      name: '-A test',
      srcCode: `
        5->A
        -A
      `,
      answer: -5
    },
    {
      name: 'Dsz special meaning',
      srcCode: `
        10->A
        Lbl 1
        Ran#
        Dsz A
        Goto 1
        A
      `,
      answer: 0
    },
    {
      name: 'Multiple variable assignment',
      srcCode: `
        Mcl
        3->B~F
        5->C~E
        A+B+C+D+E+F+G
      `,
      answer: 21
    },
    {
      name: 'Int() test',
      srcCode: `
        Int(3.14159265359)
      `,
      answer: 3
    },
    {
      name: 'Cos 0 test',
      srcCode: `
        Deg
        cos 0
      `,
      answer: 1
    },
    {
      name: 'Cos 60 test',
      srcCode: `
        Deg
        cos 60
      `,
      answer: 0.5
    },
    {
      name: 'Cos 45 test',
      srcCode: `
        Deg
        cos 45
      `,
      answer: 0.707106781186548
    },
    {
      name: '2AB test',
      srcCode: `
        2->A
        3->B
        2AB
      `,
      answer: 12
    },
    {
      name: 'A(expr) test',
      srcCode: `
        2->A
        A(5+3)
      `,
      answer: 16
    },
    {
      name: '(expr)(expr) test',
      srcCode: `
        (2*3)(5+3)
      `,
      answer: 48
    },
    {
      name: '5 + 3 = 8 ?',
      srcCode: `
        5+3
      `,
      answer: 8
    },
    {
      name: 'Do / LpWhile test',
      srcCode: `
        1->A
        Do
        A+1->A
        LpWhile A<=5
        A
      `,
      answer: 6
    },
    {
      name: 'While / WhileEnd test',
      srcCode: `
        1->A
        While A<=5
        A+1->A
        WhileEnd
        A
      `,
      answer: 6
    },
    {
      name: 'Simulate Xor',
      srcCode: `
        1->A
        1->B
        (Not A And B) Or (A And Not B)
      `,
      answer: 0
    },
    {
      name: 'Rho Theta',
      srcCode: `
        Mcl
        2->θ
        3->r
        5rθ
      `,
      answer: 30
    },
    {
      name: 'List: test Seq',
      srcCode: `
         Seq(X, X, 0, 5, 1->List 1
         Seq(3*X, X, 0, 5, 1)->List 2
         Seq(X*X, X, 0, 5, 1->List 3
         List 1[6]*List 2[6]*List 3[6]
       `,
      answer: 1875
    },
    {
      name: 'List: init lists',
      srcCode: `
       {1,2,3,4}->List 1
       {1,2,3,5->List 2
       List 2[4]
       `,
      answer: 5
    },
    {
      name: 'List: 5->List 1[1]',
      srcCode: `
       5->List 1[1]
       List 1[1]
       `,
      answer: 5
    },
    {
      name: 'List: 4->List 1[1',
      srcCode: `
       4->List 1[1
       List 1[1]
       `,
      answer: 4
    },
    {
      name: 'List: init lists (1 elem)',
      srcCode: `
       {68}->List 1
       List 1[1]
       `,
      answer: 68
    },
    {
      name: 'List: dim list',
      srcCode: `
        7→Dim List 1
        5->Dim List 2
        3->Dim List 3
        Dim List 1
       `,
      answer: 7
    },
    {
      name: 'List: Dim list Ans',
      srcCode: `
        {1,2,3,4,5,6,7,8,9,10,11,12}
        Dim List Ans
       `,
      answer: 12
    },
    {
      name: 'List: File test',
      srcCode: `
       File1
       {5,6,7,8}->List 1
       File2
       {1,2,3,4}->List 1
       File1
       List 1[3]
       `,
      answer: 7
    },
    {
      name: 'List: Increase by one & Name of list in a var',
      srcCode: `
       5->Z
       ClrList Z
       For 1 -> I To 10
         I﹣Z -> List Z[I]
       Next
       List Z[10]
       `,
       answer: 5
    },
    {
      name: 'List: read List Ans',
      srcCode: `
       {1,2,3,4,5}->List 1
       List 1
       List Ans[3]
       `,
       answer: 3
    },
    {
      name: 'List: evaluate List Ans, copy List Ans',
      srcCode: `
        {1,2,3}
        List Ans
        List Ans->List 1
        List 1[3]
       `,
       answer: 3
    },
    {
      name: 'List: copy list',
      srcCode: `
       {1,2,3,4,5}->List 1
       List 1->List 2
       List 2[4]
       `,
       answer: 4
    },
    {
      name: 'List: Min(list)',
      srcCode: `
       ClrList
       {1,2,3,4,5}->List 1
       Min(List 1)
       `,
       answer: 1
    },
    {
      name: 'List: Max(list)',
      srcCode: `
       ClrList
       {1,2,3,4,5}->List 1
       Max(List 1)
       `,
       answer: 5
    },
    {
      name: 'List: SortA(list) elt 1',
      srcCode: `
       {1,-3,56,4}->List 1
       SortA(List 1)
       List 1[1]
       `,
       answer: -3
    },
    {
      name: 'List: SortA(list) elt 4',
      srcCode: `
       {1,-3,56,4}->List 1
       SortA(List 1)
       List 1[4]
       `,
       answer: 56
    },
    {
      name: 'List: SortD(list) elt 1',
      srcCode: `
       {12,-5,48,4}->List 1
       SortD(List 1)
       List 1[1]
       `,
       answer: 48
    },
    {
      name: 'List: SortD(list) elt 4',
      srcCode: `
       {12,-5,48,4}->List 1
       SortD(List 1)
       List 1[4]
       `,
       answer: -5
    },
    {
      name: 'List: Sum list',
      srcCode: `
       Sum {15,10,8,8,7}
       `,
       answer: 48
    },
    {
      name: 'List: Prod list',
      srcCode: `
       Prod {3,5,7,11,13}
       `,
       answer: 15015
    },
    {
      name: 'List: Mean list',
      srcCode: `
       Mean({15,10,8,8,7})
       `,
       answer: 9.6
    },
    {
      name: 'List: Median odd list',
      srcCode: `
       Median({10,8,7,15,8})
       `,
       answer: 8
    },
    {
      name: 'List: Median even list',
      srcCode: `
       Median({4,2,1,3})
       `,
       answer: 2.5
    },
    {
      name: 'List: Median even list',
      srcCode: `
       Median({4,2,1,3})
       `,
       answer: 2.5
    },
    {
      name: 'List: Fill',
      srcCode: `
       10->Dim List 1
       Fill(1.234, List 1)
       List 1[10]
       `,
       answer: 1.234
    },
    {
      name: 'List: Augment()',
      srcCode: `
       Augment({1,2,3,4},{5,6,7})
       List Ans[7]
       `,
       answer: 7
    },
    {
      name: 'List: Augment(',
      srcCode: `
       Augment({1,2,3,4},{5,6,7}->List 1
       List 1[7]
       `,
       answer: 7
    },
    {
      name: 'List: Cuml',
      srcCode: `
       Cuml {15,10,8,8,7}
       List Ans[5]
       `,
       answer: 48
    },
    {
      name: 'List: Percent',
      srcCode: `
       Percent {5,13,12,2,8}
       List Ans[2]
       `,
       answer: 32.5
    },
    {
      name: 'List: ?List',
      srcCode: `
       ?List {5,13,12,2,8}
       List Ans[3]
       `,
       answer: -10
    },
    {
      name: 'List: RanInt < max',
      srcCode: `
       RanInt#(3,7,5)
       List Ans[5]<=7
       `,
      answer: 1
    },
    {
      name: 'List RanInt > min',
      srcCode: `
       RanInt#(3,7,5)
       List Ans[5]>=3
       `,
      answer: 1
    },
    {
      name: 'List: RanList# < max',
      srcCode: `
       RanList#(5)
       List Ans[5]<1
       `,
      answer: 1
    },
    {
      name: 'List RanList# > min',
      srcCode: `
       RanList#(5)
       List Ans[5]>0
       `,
      answer: 1
    },
    {
      name: 'RanInt: < max',
      srcCode: `
       RanInt#(3,7)<=7
       `,
      answer: 1
    },
    {
      name: 'RanInt: > min',
      srcCode: `
       RanInt#(3,7)>=3
       `,
      answer: 1
    },
    {
      name: 'For/Next',
      srcCode: `
       1->B
       For 1->A To 9 Step 2
         B*A->B
       Next
       B
       `,
      answer: 945
    },
    {
      name: 'For/Next with Break',
      srcCode: `
       1->B
       For 1->A To 9 Step 2
         B*A->B
         A>5=>Break
       Next
       B
       `,
      answer: 105
    },
    {
      name: 'MOD',
      srcCode: `
       6->A
       MOD(A-2,3)
       `,
      answer: 1
  }];

  assert.expect(testsToRun.length * 2);
  var done = assert.async(testsToRun.length);

  var runTest = function() {
    if (testsToRun.length > 0) {
      test = testsToRun.shift();
      // jsccRun is asynchronous
      jsccRun(test.srcCode, function(errorCode, msg, programs) {
        assert.equal(errorCode, 0, test.name + ", exit success");
        assert.equal(getLastAnswer(), test.answer, test.name + ", expected value of " + test.answer);
        done();
        runTest(); // run next test
      });
    }
  }

  runTest();
});
<commit_msg>Add unit test for matrix<commit_after>QUnit.config.testTimeout = 10000;

QUnit.test("No syntax errors - test", function( assert ) {
  assert.equal(parse({main: ['1|"    Hello World !"']}, "main").error_cnt, 0, "Hello world");
  assert.equal(parse({main: ['1|5->A:Lbl 1:A:Dsz A:Goto 1:"      Ignition !"']}, "main").error_cnt, 0, "Dsz parse test");
  assert.equal(parse({main: ['1|Goto 1:Lbl 1:"Done."']}, "main").error_cnt, 0, "Label declared after goto using it.");
  assert.equal(parse({main: ['1|Int(Ran#*100+1)->R']}, "main").error_cnt, 0, "Int(Ran#) affected to a var");
  assert.equal(parse({main: ['1|5->A:If A>0:Then "A > 0":IfEnd']}, "main").error_cnt, 0, "If...Then..IfEnd");
  assert.equal(parse({main: ['1|1->A:0->B:A And B:A Or B:A Xor B:Not A']}, "main").error_cnt, 0, "And/Or/Xor/Not");
  assert.equal(parse({main: ['1|Mcl:2->θ:3->r:5rθ:']}, "main").error_cnt, 0, "Rho / Theta");
  assert.equal(parse({main: ['1|Dim List 1:8->Dim List 1:Seq(X, X, 0, 5, 1->List 1:List 1[4]:File2']}, "main").error_cnt, 0, "List Syntax Elmt");
  assert.equal(parse({main: ['1|RanInt#(3,5):']}, "main").error_cnt, 0, "RanInt");
  assert.equal(parse({main: ['1|For 1->A To 10:Next:']}, "main").error_cnt, 0, "For/Next");
  assert.equal(parse({main: ['1|AxesOn:AxesOff:ClrGraph:']}, "main").error_cnt, 0, "AxesOn, AxesOff, ClrGraph");
  assert.equal(parse({main: ['1|SortA(List 1:SortA(List 1):']}, "main").error_cnt, 0, "SortA(, SortA()");
});

QUnit.test("Syntax errors - test", function( assert ) {
  assert.notEqual(parse({main: ['1|Gato 1:Lbl 1:"Done."']}, "main").error_cnt, 0, "Uncorrectly named 'Goto' instruction");
  assert.notEqual(parse({main: ['1|5->A:If A>0 Then "A > 0" IfEnd']}, "main").error_cnt, 0, "If...Then..IfEnd (mono line)");
});

QUnit.test("jsccRun - test", function( assert ) {
  var testsToRun = [{
      name: 'A-1 test',
      srcCode: `
        5->A
        A-1
      `,
      answer: 4
    },
    {
      name: '-A test',
      srcCode: `
        5->A
        -A
      `,
      answer: -5
    },
    {
      name: 'Dsz special meaning',
      srcCode: `
        10->A
        Lbl 1
        Ran#
        Dsz A
        Goto 1
        A
      `,
      answer: 0
    },
    {
      name: 'Multiple variable assignment',
      srcCode: `
        Mcl
        3->B~F
        5->C~E
        A+B+C+D+E+F+G
      `,
      answer: 21
    },
    {
      name: 'Int() test',
      srcCode: `
        Int(3.14159265359)
      `,
      answer: 3
    },
    {
      name: 'Cos 0 test',
      srcCode: `
        Deg
        cos 0
      `,
      answer: 1
    },
    {
      name: 'Cos 60 test',
      srcCode: `
        Deg
        cos 60
      `,
      answer: 0.5
    },
    {
      name: 'Cos 45 test',
      srcCode: `
        Deg
        cos 45
      `,
      answer: 0.707106781186548
    },
    {
      name: '2AB test',
      srcCode: `
        2->A
        3->B
        2AB
      `,
      answer: 12
    },
    {
      name: 'A(expr) test',
      srcCode: `
        2->A
        A(5+3)
      `,
      answer: 16
    },
    {
      name: '(expr)(expr) test',
      srcCode: `
        (2*3)(5+3)
      `,
      answer: 48
    },
    {
      name: '5 + 3 = 8 ?',
      srcCode: `
        5+3
      `,
      answer: 8
    },
    {
      name: 'Do / LpWhile test',
      srcCode: `
        1->A
        Do
        A+1->A
        LpWhile A<=5
        A
      `,
      answer: 6
    },
    {
      name: 'While / WhileEnd test',
      srcCode: `
        1->A
        While A<=5
        A+1->A
        WhileEnd
        A
      `,
      answer: 6
    },
    {
      name: 'Simulate Xor',
      srcCode: `
        1->A
        1->B
        (Not A And B) Or (A And Not B)
      `,
      answer: 0
    },
    {
      name: 'Rho Theta',
      srcCode: `
        Mcl
        2->θ
        3->r
        5rθ
      `,
      answer: 30
    },
    {
      name: 'List: test Seq',
      srcCode: `
         Seq(X, X, 0, 5, 1->List 1
         Seq(3*X, X, 0, 5, 1)->List 2
         Seq(X*X, X, 0, 5, 1->List 3
         List 1[6]*List 2[6]*List 3[6]
       `,
      answer: 1875
    },
    {
      name: 'List: init lists',
      srcCode: `
       {1,2,3,4}->List 1
       {1,2,3,5->List 2
       List 2[4]
       `,
      answer: 5
    },
    {
      name: 'List: 5->List 1[1]',
      srcCode: `
       5->List 1[1]
       List 1[1]
       `,
      answer: 5
    },
    {
      name: 'List: 4->List 1[1',
      srcCode: `
       4->List 1[1
       List 1[1]
       `,
      answer: 4
    },
    {
      name: 'List: init lists (1 elem)',
      srcCode: `
       {68}->List 1
       List 1[1]
       `,
      answer: 68
    },
    {
      name: 'List: dim list',
      srcCode: `
        7→Dim List 1
        5->Dim List 2
        3->Dim List 3
        Dim List 1
       `,
      answer: 7
    },
    {
      name: 'List: Dim list Ans',
      srcCode: `
        {1,2,3,4,5,6,7,8,9,10,11,12}
        Dim List Ans
       `,
      answer: 12
    },
    {
      name: 'List: File test',
      srcCode: `
       File1
       {5,6,7,8}->List 1
       File2
       {1,2,3,4}->List 1
       File1
       List 1[3]
       `,
      answer: 7
    },
    {
      name: 'List: Increase by one & Name of list in a var',
      srcCode: `
       5->Z
       ClrList Z
       For 1 -> I To 10
         I﹣Z -> List Z[I]
       Next
       List Z[10]
       `,
       answer: 5
    },
    {
      name: 'List: read List Ans',
      srcCode: `
       {1,2,3,4,5}->List 1
       List 1
       List Ans[3]
       `,
       answer: 3
    },
    {
      name: 'List: evaluate List Ans, copy List Ans',
      srcCode: `
        {1,2,3}
        List Ans
        List Ans->List 1
        List 1[3]
       `,
       answer: 3
    },
    {
      name: 'List: copy list',
      srcCode: `
       {1,2,3,4,5}->List 1
       List 1->List 2
       List 2[4]
       `,
       answer: 4
    },
    {
      name: 'List: Min(list)',
      srcCode: `
       ClrList
       {1,2,3,4,5}->List 1
       Min(List 1)
       `,
       answer: 1
    },
    {
      name: 'List: Max(list)',
      srcCode: `
       ClrList
       {1,2,3,4,5}->List 1
       Max(List 1)
       `,
       answer: 5
    },
    {
      name: 'List: SortA(list) elt 1',
      srcCode: `
       {1,-3,56,4}->List 1
       SortA(List 1)
       List 1[1]
       `,
       answer: -3
    },
    {
      name: 'List: SortA(list) elt 4',
      srcCode: `
       {1,-3,56,4}->List 1
       SortA(List 1)
       List 1[4]
       `,
       answer: 56
    },
    {
      name: 'List: SortD(list) elt 1',
      srcCode: `
       {12,-5,48,4}->List 1
       SortD(List 1)
       List 1[1]
       `,
       answer: 48
    },
    {
      name: 'List: SortD(list) elt 4',
      srcCode: `
       {12,-5,48,4}->List 1
       SortD(List 1)
       List 1[4]
       `,
       answer: -5
    },
    {
      name: 'List: Sum list',
      srcCode: `
       Sum {15,10,8,8,7}
       `,
       answer: 48
    },
    {
      name: 'List: Prod list',
      srcCode: `
       Prod {3,5,7,11,13}
       `,
       answer: 15015
    },
    {
      name: 'List: Mean list',
      srcCode: `
       Mean({15,10,8,8,7})
       `,
       answer: 9.6
    },
    {
      name: 'List: Median odd list',
      srcCode: `
       Median({10,8,7,15,8})
       `,
       answer: 8
    },
    {
      name: 'List: Median even list',
      srcCode: `
       Median({4,2,1,3})
       `,
       answer: 2.5
    },
    {
      name: 'List: Median even list',
      srcCode: `
       Median({4,2,1,3})
       `,
       answer: 2.5
    },
    {
      name: 'List: Fill',
      srcCode: `
       10->Dim List 1
       Fill(1.234, List 1)
       List 1[10]
       `,
       answer: 1.234
    },
    {
      name: 'List: Augment()',
      srcCode: `
       Augment({1,2,3,4},{5,6,7})
       List Ans[7]
       `,
       answer: 7
    },
    {
      name: 'List: Augment(',
      srcCode: `
       Augment({1,2,3,4},{5,6,7}->List 1
       List 1[7]
       `,
       answer: 7
    },
    {
      name: 'List: Cuml',
      srcCode: `
       Cuml {15,10,8,8,7}
       List Ans[5]
       `,
       answer: 48
    },
    {
      name: 'List: Percent',
      srcCode: `
       Percent {5,13,12,2,8}
       List Ans[2]
       `,
       answer: 32.5
    },
    {
      name: 'List: ?List',
      srcCode: `
       ?List {5,13,12,2,8}
       List Ans[3]
       `,
       answer: -10
    },
    {
      name: 'List: RanInt < max',
      srcCode: `
       RanInt#(3,7,5)
       List Ans[5]<=7
       `,
      answer: 1
    },
    {
      name: 'List RanInt > min',
      srcCode: `
       RanInt#(3,7,5)
       List Ans[5]>=3
       `,
      answer: 1
    },
    {
      name: 'List: RanList# < max',
      srcCode: `
       RanList#(5)
       List Ans[5]<1
       `,
      answer: 1
    },
    {
      name: 'List RanList# > min',
      srcCode: `
       RanList#(5)
       List Ans[5]>0
       `,
      answer: 1
    },
    {
      name: 'RanInt: < max',
      srcCode: `
       RanInt#(3,7)<=7
       `,
      answer: 1
    },
    {
      name: 'RanInt: > min',
      srcCode: `
       RanInt#(3,7)>=3
       `,
      answer: 1
    },
    {
      name: 'For/Next',
      srcCode: `
       1->B
       For 1->A To 9 Step 2
         B*A->B
       Next
       B
       `,
      answer: 945
    },
    {
      name: 'For/Next with Break',
      srcCode: `
       1->B
       For 1->A To 9 Step 2
         B*A->B
         A>5=>Break
       Next
       B
       `,
      answer: 105
    },
    {
      name: 'MOD',
      srcCode: `
       6->A
       MOD(A-2,3)
       `,
      answer: 1
    },
    {
      name: 'Init Mat and get nb of columns',
      srcCode: `
       [[1,2,3,4][5,6,7,8]]->Mat A
       Dim Mat A
       List Ans[2]
       `,
      answer: 4
    },
    {
      name: 'Init Mat and get nb of rows',
      srcCode: `
       [[1,2,3,4][5,6,7,8]]->Mat A
       Dim Mat A
       List Ans[1]
       `,
      answer: 2
    },
    {
      name: 'Init Mat and get elem from Mat Ans',
      srcCode: `
       [[1,2,3][4,5,6][7,8,9]]
       Mat Ans[2,3]
       `,
      answer: 6
    },
    {
      name: 'Init Mat by dim',
      srcCode: `
       {3,5}->Dim Mat A
       5->Mat A[2,3]
       Mat A[2,3]
       `,
      answer: 5
    },
    {
      name: 'Init Mat and copy to antoher Mat',
      srcCode: `
       [[1,2,3][4,5,6][7,8,9]]->Mat A
       Mat A->Mat B
       Mat B[3,1]
       `,
      answer: 7
  }];

  assert.expect(testsToRun.length * 2);
  var done = assert.async(testsToRun.length);

  var runTest = function() {
    if (testsToRun.length > 0) {
      test = testsToRun.shift();
      // jsccRun is asynchronous
      jsccRun(test.srcCode, function(errorCode, msg, programs) {
        assert.equal(errorCode, 0, test.name + ", exit success");
        assert.equal(getLastAnswer(), test.answer, test.name + ", expected value of " + test.answer);
        done();
        runTest(); // run next test
      });
    }
  }

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


<commit_before>var should = require('chai').should();
var expect = require('chai').expect;
var nunjucksdate = require('../index');
var getFilter = nunjucksdate;
var dateStringTest = 'Dec 25, 1995';

// Nunjucks environment
var nunjucks = require('nunjucks');
var env = new nunjucks.Environment();
var renderNunjucks = function(filter) {
    return env.renderString('{{ myDate| '+ ((filter) ? filter : 'date') +' }}', { "myDate": dateStringTest });
};

describe('#getFilter - 1st case - specified string.\n Uses default date format.', function() {
  it('converts  ' + dateStringTest + '  to 1995', function() {
    getFilter(dateStringTest).should.equal('1995');
  });
});

describe('#getFilter - 2nd case - specified string & meridiem=true.\n Uses default date format.', function() {
  it('converts  ' + dateStringTest + '  to 1995', function() {
    getFilter(dateStringTest, true).should.equal('1995');
  });
});

describe('#getFilter - 3rd case - specified string, format, & meridiem=true', function() {
  it('converts ' + dateStringTest + ' to 12-25-1995 a.m. ', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY a',true).should.equal('12-25-1995 a.m.');
  });
});

describe('#getFilter - 4th case - specified string & format', function() {

  it('converts  ' + dateStringTest + '  to 12-25-1995', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY').should.equal('12-25-1995');
  });

  it('converts ' + dateStringTest + ' to 12-25-1995 am', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY a').should.equal('12-25-1995 am');
  });
});

describe('#setDefaultFormat', function() {
  it('sets default format to MMMM Do YYYY, h:mm:ss a', function() {
    nunjucksdate.setDefaultFormat('MMMM Do YYYY, h:mm:ss a').should.equal('MMMM Do YYYY, h:mm:ss a');
  });
});

describe('#install', function() {
  it('installs this plugin using default filter name of "date"', function() {
    nunjucksdate.install(env);
    console.log("\t The result is", renderNunjucks());
    expect(renderNunjucks()).to.be.a('string').and.equal('December 25th 1995, 12:00:00 am');
  });

  it('installs this plugin using custom filter name', function() {
    var filterName = 'customDate';
    nunjucksdate.install(env, filterName);
    console.log("\t The result is", renderNunjucks(filterName));
    expect(renderNunjucks(filterName)).to.be.a('string').and.equal('December 25th 1995, 12:00:00 am');
  });
});<commit_msg>Test: Changed date test string to ISO format<commit_after>var should = require('chai').should();
var expect = require('chai').expect;
var nunjucksdate = require('../index');
var getFilter = nunjucksdate;
var dateStringTest = '1995-12-25';

// Nunjucks environment
var nunjucks = require('nunjucks');
var env = new nunjucks.Environment();
var renderNunjucks = function(filter) {
    return env.renderString('{{ myDate| '+ ((filter) ? filter : 'date') +' }}', { "myDate": dateStringTest });
};

describe('#getFilter - 1st case - specified string.\n Uses default date format.', function() {
  it('converts  ' + dateStringTest + '  to 1995', function() {
    getFilter(dateStringTest).should.equal('1995');
  });
});

describe('#getFilter - 2nd case - specified string & meridiem=true.\n Uses default date format.', function() {
  it('converts  ' + dateStringTest + '  to 1995', function() {
    getFilter(dateStringTest, true).should.equal('1995');
  });
});

describe('#getFilter - 3rd case - specified string, format, & meridiem=true', function() {
  it('converts ' + dateStringTest + ' to 12-25-1995 a.m. ', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY a',true).should.equal('12-25-1995 a.m.');
  });
});

describe('#getFilter - 4th case - specified string & format', function() {

  it('converts  ' + dateStringTest + '  to 12-25-1995', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY').should.equal('12-25-1995');
  });

  it('converts ' + dateStringTest + ' to 12-25-1995 am', function() {
    getFilter(dateStringTest, 'MM-DD-YYYY a').should.equal('12-25-1995 am');
  });
});

describe('#setDefaultFormat', function() {
  it('sets default format to MMMM Do YYYY, h:mm:ss a', function() {
    nunjucksdate.setDefaultFormat('MMMM Do YYYY, h:mm:ss a').should.equal('MMMM Do YYYY, h:mm:ss a');
  });
});

describe('#install', function() {
  it('installs this plugin using default filter name of "date"', function() {
    nunjucksdate.install(env);
    console.log("\t The result is", renderNunjucks());
    expect(renderNunjucks()).to.be.a('string').and.equal('December 25th 1995, 12:00:00 am');
  });

  it('installs this plugin using custom filter name', function() {
    var filterName = 'customDate';
    nunjucksdate.install(env, filterName);
    console.log("\t The result is", renderNunjucks(filterName));
    expect(renderNunjucks(filterName)).to.be.a('string').and.equal('December 25th 1995, 12:00:00 am');
  });
});<|endoftext|>