diff --git a/.travis.yml b/.travis.yml index 318df40..5923031 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ language: node_js node_js: - "6.2" +script: npm run-script test:travis diff --git a/CHANGELOG b/CHANGELOG index 9c2d9df..3f00409 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ 2016-07-08 +- <@sthzg> added coveralls integration +- <@sthzg> added coverage by running npm run test:covarage +- <@sthzg> added basic set of unit tests for utils.js - <@stylesuxx> added immutable Message and Package records 2016-07-07 diff --git a/package.json b/package.json index 4f22fcc..d313db4 100644 --- a/package.json +++ b/package.json @@ -30,15 +30,21 @@ "devDependencies": { "chai": "^3.5.0", "contrib-subgen-yoburger-bbq": "0.0.2", + "coveralls": "^2.11.9", "fs-extra": "^0.30.0", "generator-yoburger": "0.0.3", + "istanbul": "^0.4.4", "mocha": "^2.5.3", + "mocha-lcov-reporter": "^1.2.0", + "mock-fs": "^3.9.0", "yeoman-assert": "^2.2.1", "yeoman-test": "^1.4.0" }, "scripts": { "test": "mocha", "test:watch": "mocha -w", + "test:coverage": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha --report lcovonly && rm -rf ./coverage", + "test:travis": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", "release:major": "npm version prerelease && git push --follow-tags && npm publish --tag poc", "release:minor": "npm version prerelease && git push --follow-tags && npm publish --tag poc", "release:patch": "npm version prerelease && git push --follow-tags && npm publish --tag poc" diff --git a/test/_helpers/index.js b/test/_helpers/index.js index cf22cba..7a05ce7 100644 --- a/test/_helpers/index.js +++ b/test/_helpers/index.js @@ -42,9 +42,44 @@ function moveDefaultFiles(dir, includeSubgenextJson = false, includeExtgen = fal } +const buildPkgJson = (name='', version='1.0.0') => { return {name, version} }; + + +const mockedDirsForSearchPaths = { + structure: { + '/tmp/searchPath1': { + 'sp1dir1': { + 'generators': { + 'hello': {} + }, + 'package.json': JSON.stringify(buildPkgJson('sp1dir1', '1.0.0')) + }, + 'sp1dir2': {}, + 'sp1dir3': {} + }, + '/tmp/searchPath2': { + 'contrib-subgen-sp1dir-hello': { + 'package.json': JSON.stringify(buildPkgJson('hello')) + }, + 'contrib-subgen-sp1dir-bye': { + 'package.json': JSON.stringify(buildPkgJson('bye')) + }, + 'sp2dir3': {}, + }, + '/tmp/searchPath3': {} + }, + roots: [ + '/tmp/searchPath1', + '/tmp/searchPath2', + '/tmp/searchPath3' + ] +}; + + module.exports = { genPath, nodeModDir, resourcesDir, + mockedDirsForSearchPaths, moveDefaultFiles }; diff --git a/test/utils/utilsTest.js b/test/utils/utilsTest.js index ad9a93a..0bbc2a1 100644 --- a/test/utils/utilsTest.js +++ b/test/utils/utilsTest.js @@ -1 +1,163 @@ 'use strict'; + +const after = require('mocha').after; +const before = require('mocha').before; +const describe = require('mocha').describe; +const it = require('mocha').it; + +const chai = require('chai').assert; +const fs = require('fs'); +const mockfs = require('mock-fs'); +const path = require('path'); +const tHelpers = require('../_helpers'); +const utils = require('../../utils/utils'); + + +describe('getInstalledPkgPaths()', () => { + describe('with mocked file system', function () { + before(function() { + mockfs(tHelpers.mockedDirsForSearchPaths.structure); + }); + + it('returns expected number of directories from the fs', function () { + const res = utils.getInstalledPkgPaths(tHelpers.mockedDirsForSearchPaths.roots); + chai.isOk(res.length === 6, 'Expected number of dirs to be 6') + }); + + after(function() { + mockfs.restore(); + }); + }); +}); + + +describe('populatePkgStoreFromPaths()', () => { + describe('with mocked file system', function () { + before(function() { + mockfs(tHelpers.mockedDirsForSearchPaths.structure); + this.pkgPaths = utils.getInstalledPkgPaths(tHelpers.mockedDirsForSearchPaths.roots); + }); + + it('returns expected number of directories from the fs', function () { + const res = utils.populatePkgStoreFromPaths(this.pkgPaths); + chai.isOk(res.length === 6, 'Expected number of entries to be 6'); + chai.isOk( + res.every(x => typeof x.path === 'string' && x.path !== ''), + 'Expected all items to have a non-empty path prop' + ); + }); + + after(function() { + mockfs.restore(); + }); + }); +}); + + +describe('getPkgInfo()', () => { + describe('with mocked file system', function () { + before(function () { + mockfs(tHelpers.mockedDirsForSearchPaths.structure); + const pkgPaths = utils.getInstalledPkgPaths(tHelpers.mockedDirsForSearchPaths.roots); + this.store = utils.populatePkgStoreFromPaths(pkgPaths); + }); + + it('returns data from package.json', function () { + const pkgQ = utils.getPkgInfo('sp1dir1', this.store); + chai.equal(pkgQ.hasError, false); + chai.equal(pkgQ.data.getIn(['pkg', 'version']), '1.0.0'); + chai.equal(pkgQ.data.getIn(['pkg', 'name']), 'sp1dir1'); + chai.equal(pkgQ.data.getIn(['pkg', 'path']), '/tmp/searchPath1/sp1dir1'); + }); + + it('returns data for a matching substring with exact=fasle', function () { + const pkgQ = utils.getPkgInfo('sp1', this.store, false); + chai.equal(pkgQ.data.getIn(['pkg', 'name']), 'sp1dir1'); + }); + + it('returns an error if pkg can\'t be found', function () { + const pkgQ = utils.getPkgInfo('xyz', this.store); + chai.equal(pkgQ.hasError, true); + }); + + after(function () { + mockfs.restore(); + }); + }); +}); + + +describe('buildPrefixRegexps()', () => { + it('returns expected regexps', function () { + let regexps = utils.buildPrefixRegexps(['contrib-subgen-', 'subgen-'], 'foobar'); + chai.equal(regexps.length, 2); + chai.equal(regexps[0], '/^contrib-subgen-foobar-/'); + chai.equal(regexps[1], '/^subgen-foobar-/'); + }); + + it('returns expected basename for subgen-foobar-helloworld', function () { + let bn = utils.getSubgenBaseName('foobar', ['contrib-subgen-', 'subgen-'], 'subgen-foobar-helloworld'); + chai.equal(bn, 'helloworld'); + }); +}); + + +describe('getSubgenBaseName()', () => { + it('returns expected basename for contrib-subgen-foobar-helloworld', function () { + let bn = utils.getSubgenBaseName('foobar', ['contrib-subgen-', 'subgen-'], 'contrib-subgen-foobar-helloworld'); + chai.equal(bn, 'helloworld'); + }); + + it('returns expected basename for subgen-foobar-helloworld', function () { + let bn = utils.getSubgenBaseName('foobar', ['contrib-subgen-', 'subgen-'], 'subgen-foobar-helloworld'); + chai.equal(bn, 'helloworld'); + }); +}); + + +describe('checkActivationState()', () => { + describe('with mocked file system', function () { + before(function () { + mockfs(tHelpers.mockedDirsForSearchPaths.structure); + const pkgPaths = utils.getInstalledPkgPaths(tHelpers.mockedDirsForSearchPaths.roots); + this.store = utils.populatePkgStoreFromPaths(pkgPaths); + }); + + it('reports activated subgen', function () { + const hostPkgQ = utils.getPkgInfo('sp1dir1', this.store); + const resQ = utils.checkActivationState(hostPkgQ.data.get('pkg'), 'hello'); + chai.ok(resQ.data.get('result')); + }); + + it('reports deactivated', function () { + const hostPkgQ = utils.getPkgInfo('sp1dir1', this.store); + const resQ = utils.checkActivationState(hostPkgQ.data.get('pkg'), 'nonExistent'); + chai.notOk(resQ.data.get('result')); + }); + + after(function () { + mockfs.restore(); + }); + }); +}); + + +describe('findExternalSubgens()', () => { + describe('with mocked file system', function () { + before(function () { + this.prefixes = require('../../utils/constants').SUBGEN_PREFIX_PATTERNS; + mockfs(tHelpers.mockedDirsForSearchPaths.structure); + const pkgPaths = utils.getInstalledPkgPaths(tHelpers.mockedDirsForSearchPaths.roots); + this.store = utils.populatePkgStoreFromPaths(pkgPaths); + }); + + it('finds packages that qualify as external subgens', function () { + const resQ = utils.findExternalSubgens(this.prefixes, 'sp1dir', this.store); + chai.equal(resQ.data.get('results').size, 2); + }); + + after(function () { + mockfs.restore(); + }); + }); +}); diff --git a/utils/utils.js b/utils/utils.js index cf3e5d6..27bc836 100644 --- a/utils/utils.js +++ b/utils/utils.js @@ -1,5 +1,6 @@ 'use strict'; +var readFileSync = require('fs').readFileSync; var existsSync = require('fs').existsSync; var globby = require('globby'); var path = require('path'); @@ -87,9 +88,10 @@ function getPkgInfo(pkgName, installed, exact=true) { }); return buildSuccess({ pkg: pkg }); - } - return buildError(`${pkgName} not found in installed packages.`); + } else { + return buildError(`${pkgName} not found in installed packages.`); + } } @@ -112,6 +114,7 @@ function buildPrefixRegexps(patterns, host) { * @returns {string|void|XML|*} */ function getSubgenBaseName(host, patterns, pkgName) { + // TODO gh_issue 13, return Success or Error record const sorted = sortCharArrByLength(patterns); const regexps = buildPrefixRegexps(sorted, host); const prefix = regexps.find(regex => regex.exec(pkgName) !== null); @@ -188,7 +191,7 @@ function findExternalSubgens(prefixes, host, installed) { * @returns {*} */ function loadPkgJsonFromPkgPath(dir) { - return require(path.join(dir, 'package.json')); + return JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8')); } @@ -206,10 +209,12 @@ function sortCharArrByLength(arr, desc=true) { module.exports = { + buildPrefixRegexps, checkActivationState, checkPkgExists, getPkgInfo, getInstalledPkgPaths, + getSubgenBaseName, findExternalSubgens, populatePkgStoreFromPaths };