1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2025-05-02 12:27:08 +01:00

Finish HackMyCore reshaping.

Reintroduce HackMyCore, dropping the interim submodule, and reorganize
and improve tests.
This commit is contained in:
hacksalot
2016-01-29 15:23:57 -05:00
parent e9971eb882
commit 0f65e4c9f3
130 changed files with 5384 additions and 337 deletions

View File

@ -0,0 +1,4 @@
{
"theme": "positive",
"debug": true
}

206
test/scripts/test-api.js Normal file
View File

@ -0,0 +1,206 @@
/**
@module test-api.js
*/
var chai = require('chai')
, expect = chai.expect
, should = chai.should()
, path = require('path')
, _ = require('underscore')
, FRESHResume = require('../../dist/core/fresh-resume')
, FCMD = require( '../../dist/index')
, validator = require('is-my-json-valid')
, EXTEND = require('extend');
chai.config.includeStack = false;
var _sheet;
var opts = {
format: 'FRESH',
prettify: true,
silent: false,
assert: true // Causes validation errors to throw exceptions
};
var opts2 = {
format: 'JRS',
prettify: true,
silent: true
};
var sb = 'test/sandbox/';
var ft = 'node_modules/fresh-test-resumes/src/fresh/';
var tests = [
[ 'new',
[sb + 'new-fresh-resume.json'],
[],
opts,
' (FRESH format)'
],
[ 'new',
[sb + 'new-jrs-resume.json'],
[],
opts2,
' (JRS format)'
],
[
'new',
[sb + 'new-1.json', sb + 'new-2.json', sb + 'new-3.json'],
[],
opts,
' (multiple FRESH resumes)'
],
[ 'new',
[sb + 'new-jrs-1.json', sb + 'new-jrs-2.json', sb + 'new-jrs-3.json'],
[],
opts,
' (multiple JRS resumes)'
],
[ '!new',
[],
[],
opts,
" (when a filename isn't specified)"
],
[ 'validate',
[ft + 'jane-fullstacker.json'],
[],
opts,
' (jane-q-fullstacker|FRESH)'
],
[ 'validate',
[ft + 'johnny-trouble.json'],
[],
opts,
' (johnny-trouble|FRESH)'
],
[ 'validate',
[sb + 'new-fresh-resume.json'],
[],
opts,
' (new-fresh-resume|FRESH)'
],
[ 'validate',
['test/resumes/jrs-0.0.0/richard-hendriks.json'],
[],
opts2,
' (richard-hendriks.json|JRS)'
],
[ 'validate',
['test/resumes/jrs-0.0.0/jane-incomplete.json'],
[],
opts2,
' (jane-incomplete.json|JRS)'
],
[ 'validate',
[sb + 'new-1.json', sb + 'new-jrs-resume.json', sb + 'new-1.json',
sb + 'new-2.json', sb + 'new-3.json'],
[],
opts,
' (5|BOTH)'
],
[ 'analyze',
[ft + 'jane-fullstacker.json'],
[],
opts,
' (jane-q-fullstacker|FRESH)'
],
[ 'analyze',
['test/resumes/jrs-0.0.0/richard-hendriks.json'],
[],
opts2,
' (richard-hendriks|JRS)'
],
[ 'build',
[ ft + 'jane-fullstacker.json', ft + 'override/jane-fullstacker-override.fresh.json' ],
[ sb + 'merged/jane-fullstacker-gamedev.fresh.all'],
opts,
' (jane-q-fullstacker w/ override|FRESH)'
],
[ 'build',
[ ft + 'override/jane-partial-a.json', ft + 'override/jane-partial-b.json',
ft + 'override/jane-partial-c.json' ],
[ sb + 'merged/jane-abc.fresh.all'],
opts,
' (jane merge A + B + C|FRESH)',
function( r ) {
var expected = [
'name','meta','info', 'contact', 'location', 'projects', 'social',
'employment', 'education', 'affiliation', 'service', 'skills',
'samples', 'writing', 'reading', 'speaking', 'recognition',
'references', 'testimonials', 'languages', 'interests',
'extracurricular', 'governance'
];
return Object.keys( _.pick( r, expected ) ).length === expected.length;
}
],
[ '!build',
[ ft + 'jane-fullstacker.json'],
[ sb + 'shouldnt-exist.pdf' ],
EXTEND(true, {}, opts, { theme: 'awesome' }),
' (jane-q-fullstacker + Awesome + PDF|FRESH)'
]
];
describe('Testing API interface', function () {
function run( verb, src, dst, opts, msg, fnTest ) {
msg = msg || '.';
var shouldSucceed = true;
if( verb[0] === '!' ) {
verb = verb.substr(1);
shouldSucceed = false;
}
it( 'The ' + verb.toUpperCase() + ' command should ' + (shouldSucceed ? ' SUCCEED' : ' FAIL') + msg, function () {
function runIt() {
try {
var v = new FCMD.verbs[verb]();
v.on('hmr:error', function(ex) { throw ex; });
var r = v.invoke( src, dst, opts );
if( fnTest )
if( !fnTest( r.sheet ) )
throw "Test: Unexpected API result.";
}
catch(ex) {
console.error(ex);
if( ex.stack || (ex.inner && ex.inner.stack))
console.error( ex.stack || ex.inner.stack );
throw ex;
}
}
if( shouldSucceed )
runIt.should.not.Throw();
else
runIt.should.Throw();
});
}
tests.forEach( function(a) {
run.apply( /* The players of */ null, a );
});
});

88
test/scripts/test-cli.js Normal file
View File

@ -0,0 +1,88 @@
/**
CLI test routines for HackMyResume.
@module test-cli.js
*/
var chai = require('chai')
, should = chai.should()
, expect = chai.expect
, HMRMAIN = require('../../dist/cli/main')
, CHALK = require('chalk')
, FS = require('fs')
, PATH = require('path')
, PKG = require('../../package.json')
, STRIPCOLOR = require('stripcolorcodes')
, _ = require('underscore');
var gather = '';
var ConsoleLogOrg = console.log;
var ProcessExitOrg = process.exit;
var commandRetVal = 0;
// TODO: use sinon
// Replacement for process.exit()
function MyProcessExit( retVal ) {
commandRetVal = retVal;
}
// TODO: use sinon
// Replacement for console.log
function MyConsoleLog() {
var tx = Array.prototype.slice.call(arguments).join(' ');
gather += STRIPCOLOR( tx );
ConsoleLogOrg.apply(this, arguments);
}
describe('Testing CLI interface', function () {
// HackMyResume CLI stub. Handle a single HMR invocation.
function HackMyResumeStub( argsString ) {
var args = argsString.split(' ');
args.unshift( process.argv[1] );
args.unshift( process.argv[0] );
process.exit = MyProcessExit;
try {
HMRMAIN( args );
}
catch( ex ) {
require('../../dist/cli/error').err( ex, false );
if(ex.stack || (ex.inner && ex.inner.stacl))
console.log(ex.stack || ex.inner.stack);
}
process.exit = ProcessExitOrg;
}
// Run a test through the stub, gathering console.log output into "gather"
// and testing against it.
function run( args, expErr ) {
var title = args;
it( 'Testing: "' + title + '"\n\n', function() {
commandRetVal = 0;
HackMyResumeStub( args );
commandRetVal.should.equal( parseInt(expErr, 10) );
});
}
var lines = FS.readFileSync( PATH.join( __dirname, './test-hmr.txt'), 'utf8').split('\n');
lines.forEach(function(l){
if( l && l.trim() ) {
if(l[0] !== '#') {
var lineInfo = l.split('|');
var errCode = lineInfo[0];
run( lineInfo.length > 1 ? lineInfo[1] : '', errCode );
}
}
});
process.exit = ProcessExitOrg;
});

View File

@ -0,0 +1,71 @@
var chai = require('chai')
, expect = chai.expect
, should = chai.should()
, path = require('path')
, _ = require('underscore')
, FRESHResume = require('../../dist/core/fresh-resume')
, validator = require('is-my-json-valid');
chai.config.includeStack = false;
function testResume(opts) {
describe( opts.title + ' (FRESH)', function () {
var _sheet;
it('should open without throwing an exception', function () {
function tryOpen() {
_sheet = new FRESHResume().open( opts.path );
}
tryOpen.should.not.Throw();
});
it('should have one or more of each section', function() {
var newObj = _.pick( _sheet, opts.sections );
expect( Object.keys(newObj).length ).to.equal( opts.sections.length );
});
it('should have a work duration of ' + opts.duration + ' years', function() {
_sheet.computed.numYears.should.equal( opts.duration );
});
it('should save without throwing an exception', function(){
function trySave() {
_sheet.save( 'test/sandbox/' + opts.title + '.json' );
}
trySave.should.not.Throw();
});
it('should not be modified after saving', function() {
var savedSheet = new FRESHResume().open('test/sandbox/' + opts.title + '.json');
_sheet.stringify().should.equal( savedSheet.stringify() );
});
it('should validate against the FRESH resume schema', function() {
var result = _sheet.isValid();
// var schemaJson = require('fresca');
// var validate = validator( schemaJson, { verbose: true } );
// var result = validate( JSON.parse( _sheet.imp.raw ) );
result || console.log("\n\nOops, resume didn't validate. " +
"Validation errors:\n\n", _sheet.imp.validationErrors, "\n\n");
result.should.equal( true );
});
});
}
var sects = [ 'info', 'employment', 'service', 'skills', 'education', 'writing', 'recognition', 'references' ];
testResume({ title: 'jane-q-fullstacker', path: 'node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json', duration: 7, sections: sects });
testResume({ title: 'johnny-trouble-resume', path: 'node_modules/fresh-test-resumes/src/fresh/johnny-trouble.json', duration: 4, sections: sects });
sects = [ 'info', 'contact', 'location' ];
testResume({ title: 'jane-q-fullstacker A', path: 'node_modules/fresh-test-resumes/src/fresh/override/jane-partial-a.json', duration: 0, sections: sects });
sects = [ 'projects', 'social', 'employment', 'education', 'affiliation' ];
testResume({ title: 'jane-q-fullstacker B', path: 'node_modules/fresh-test-resumes/src/fresh/override/jane-partial-b.json', duration: 7, sections: sects });
sects = [ 'service', 'skills', 'samples', 'writing', 'reading', 'speaking', 'recognition', 'references', 'testimonials', 'languages', 'interests', 'extracurricular', 'governance' ];
testResume({ title: 'jane-q-fullstacker C', path: 'node_modules/fresh-test-resumes/src/fresh/override/jane-partial-c.json', duration: 0, sections: sects });

33
test/scripts/test-hmr.txt Normal file
View File

@ -0,0 +1,33 @@
0|
0|--help
0|-h
0|--debug
0|-d
5|notacommand
8|new
0|new test/sandbox/cli-test/new-empty-resume.auto.json
0|new test/sandbox/cli-test/new-empty-resume.jrs.json -f jrs
0|new test/sandbox/cli-test/new-empty-resume.fresh.json -f fresh
3|analyze
14|analyze doesnt-exist.json
3|convert
7|convert doesnt-exist.json
3|validate
14|validate doesnt-exist.json
0|validate node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json
3|peek
14|peek doesnt-exist.json
14|peek doesnt-exist.json not.a.path
0|peek test/resumes/jrs-0.0.0/richard-hendriks.json work[0]
0|peek node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json employment.history[1]
0|peek node_modules/fresh-test-resumes/src/fresh/johnny-trouble.json skills.sets
3|build
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.html
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.pdf
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.md
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.txt
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.yml
0|build node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json test/sandbox/cli-test/jane/resume.json
14|build doesnt-exist.json
14|build doesnt-exist.json -t not-a-theme
14|build doesnt-exist.json -t node_modules/not-a-theme

View File

@ -0,0 +1,69 @@
var chai = require('chai')
, expect = chai.expect
, should = chai.should()
, path = require('path')
, _ = require('underscore')
, JRSResume = require('../../dist/core/jrs-resume')
, validator = require('is-my-json-valid');
chai.config.includeStack = false;
function testResume( opts ) {
describe( opts.title + ' (JRS)', function() {
opts.isValid = opts.isValid !== false;
var _sheet;
it('should open without throwing an exception', function () {
var that = this;
function tryOpen() {
_sheet = new JRSResume().open(
path.normalize( path.join( __dirname, '/../resumes/jrs-0.0.0/' + opts.title + '.json' ) ) )
}
tryOpen.should.not.Throw();
});
it('should have one or more of each section', function() {
var newObj = _.pick( _sheet, opts.sections );
expect( Object.keys(newObj).length ).to.equal( opts.sections.length );
});
it('should have a work duration of ' + opts.duration + ' years', function() {
_sheet.basics.computed.numYears.should.equal( opts.duration );
});
it('should save without throwing an exception', function() {
var that = this;
function trySave() {
_sheet.save( 'test/sandbox/' + opts.title + '.json' );
}
trySave.should.not.Throw();
});
it('should not be modified after saving', function() {
var savedSheet = new JRSResume().open( 'test/sandbox/' + opts.title + '.json' );
_sheet.stringify().should.equal( savedSheet.stringify() );
});
it('should ' + (opts.isValid ? '' : 'NOT ') + 'validate against the JSON Resume schema', function() {
var result = _sheet.isValid();
// var schemaJson = require('../src/core/resume.json');
// var validate = validator( schemaJson, { verbose: true } );
// var result = validate( JSON.parse( _sheet.imp.raw ) );
result || console.log("\n\nOops, resume didn't validate. " +
"Validation errors:\n\n", _sheet.imp.validationErrors, "\n\n");
result.should.equal( opts.isValid );
});
});
}
var sects = [ 'basics', 'work', 'volunteer', 'skills', 'education', 'publications', 'awards', 'references' ];
testResume({ title: 'jane-q-fullstacker', duration: 7, sections: sects });
testResume({ title: 'jane-incomplete', duration: 0, sections: _.without(sects, 'awards', 'work') });
testResume({ title: 'richard-hendriks', duration: 1, sections: sects });
testResume({ title: 'empty', duration: 0, sections: [], isValid: false });

150
test/scripts/test-output.js Normal file
View File

@ -0,0 +1,150 @@
/**
CLI test routines for HackMyResume.
@module test-cli.js
*/
var chai = require('chai')
, should = chai.should()
, expect = chai.expect
, HMRMAIN = require('../../dist/cli/main')
, CHALK = require('chalk')
, FS = require('fs')
, PATH = require('path')
, PKG = require('../../package.json')
, STRIPCOLOR = require('stripcolorcodes')
, _ = require('underscore');
var gather = '';
var ConsoleLogOrg = console.log;
var ProcessExitOrg = process.exit;
var commandRetVal = 0;
// TODO: use sinon
// Replacement for process.exit()
function MyProcessExit( retVal ) {
commandRetVal = retVal;
}
// TODO: use sinon
// Replacement for console.log
function MyConsoleLog() {
var tx = Array.prototype.slice.call(arguments).join(' ');
gather += STRIPCOLOR( tx );
ConsoleLogOrg.apply(this, arguments);
}
describe('Testing Ouput interface', function () {
// HackMyResume CLI stub. Handle a single HMR invocation.
function HackMyResumeOutputStub( args ) {
console.log = MyConsoleLog;
process.exit = MyProcessExit;
CHALK.enabled = false;
try {
args.unshift( process.argv[1] );
args.unshift( process.argv[0] );
HMRMAIN( args );
}
catch( ex ) {
console.error(ex);
require('../../dist/cli/error').err( ex, false );
}
CHALK.enabled = true;
//process.exit = ProcessExitOrg;
console.log = ConsoleLogOrg;
}
// Run a test through the stub, gathering console.log output into "gather"
// and testing against it.
function run( title, args, tests ) {
it( title, function() {
gather = '';
HackMyResumeOutputStub( args );
expect(
_.all( tests, function(t) {
return gather.indexOf(t) > -1;
})
).to.equal(true);
});
}
var title = '*** HackMyResume v' + PKG.version + ' ***';
var feedMe = 'Please feed me a resume in FRESH or JSON Resume format.';
var manPage = FS.readFileSync( PATH.resolve( __dirname, '../../src/cli/use.txt' ), 'utf8');
run('HMR should output a help string when no command is specified',
[], [ title, 'Please give me a command (BUILD, ANALYZE, VALIDATE, CONVERT, NEW, or PEEK).' ]);
run('BUILD should output a tip when no source is specified',
['build'], [ title, feedMe ]);
run('VALIDATE should output a tip when no source is specified',
['validate'], [ title, feedMe ]);
run('ANALYZE should output a tip when no source is specified',
['analyze'], [ title, feedMe ]);
run('BUILD should display an error on a broken resume',
['build',
'node_modules/fresh-test-resumes/src/fresh/johnny-trouble.broken.json',
'-t', 'modern'
], [ title, 'Error: Invalid or corrupt JSON on line' ]);
run('CONVERT should output a tip when no source is specified',
['convert'], [ title, feedMe ]);
run('NEW should output a tip when no source is specified',
['new'], [ title, 'Please specify the filename of the resume to create.' ]);
// This will cause the HELP doc to be emitted, followed by an "unknown option --help"
// error in the log, based on the way we're calling into HMR. As long as the test
// passes, any extraneous error messages can be ignored here.
run('HMR should output help doc with --help',
['--help'], [ manPage ]);
run('HMR should accept raw JSON via --options',
[
'build',
'node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json',
'to',
'test/sandbox/temp/janeq-1.all',
'-o',
"{ theme: 'compact', debug: true, pdf: 'wkhtmltopdf' }"],
[ 'Applying COMPACT theme (', '(with wkhtmltopdf)'] );
run('HMR should accept a JSON settings file via --options',
[
'build',
'node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json',
'to',
'test/sandbox/temp/janeq-2.all',
'--options',
"test/scripts/hmr-options.json"],
[ 'Applying POSITIVE theme'] );
run('Explicit command line options should override --options',
[
'build',
'node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json',
'to',
'test/sandbox/temp/janeq-3.all',
'--options',
"test/hmr-options.json",
"-t",
"modern"
],
[ 'Applying MODERN theme'] );
});

View File

@ -0,0 +1,86 @@
var chai = require('chai')
, expect = chai.expect
, should = chai.should()
, path = require('path')
, _ = require('underscore')
, FRESHResume = require('../../dist/core/fresh-resume')
, HMR = require( '../../dist/index')
, validator = require('is-my-json-valid')
, READFILES = require('recursive-readdir-sync')
, fileContains = require('../../dist/utils/file-contains')
, FS = require('fs')
, CHALK = require('chalk');
chai.config.includeStack = true;
function genThemes( title, src, fmt ) {
describe('Testing themes against ' + title.toUpperCase() + ' resume ' + '(' + fmt + ')' , function () {
var _sheet;
function genTheme( fmt, src, themeName, themeLoc, testTitle ) {
themeLoc = themeLoc || themeName;
testTitle = themeName.toUpperCase() + ' theme (' + fmt + ') should generate without throwing an exception';
it( testTitle, function () {
function tryOpen() {
//var src = ['node_modules/jane-q-fullstacker/resume/jane-resume.json'];
var dst = ['test/sandbox/' + fmt + '/' + title + '/' + themeName + '/resume.all'];
var opts = {
theme: themeLoc,
format: fmt,
prettify: true,
silent: false,
css: 'embed',
debug: true
};
try {
var v = new HMR.verbs.build();
v.invoke( src, dst, opts );
}
catch(ex) {
console.error( ex );
console.error( ex.stack );
throw ex;
}
}
tryOpen.should.not.Throw();
});
}
genTheme(fmt, src, 'hello-world');
genTheme(fmt, src, 'compact');
genTheme(fmt, src, 'modern');
genTheme(fmt, src, 'underscore');
genTheme(fmt, src, 'awesome');
genTheme(fmt, src, 'positive');
genTheme(fmt, src, 'jsonresume-theme-boilerplate', 'node_modules/jsonresume-theme-boilerplate' );
genTheme(fmt, src, 'jsonresume-theme-sceptile', 'node_modules/jsonresume-theme-sceptile' );
genTheme(fmt, src, 'jsonresume-theme-modern', 'node_modules/jsonresume-theme-modern' );
genTheme(fmt, src, 'jsonresume-theme-classy', 'node_modules/jsonresume-theme-classy' );
});
}
function folderContains( needle, haystack ) {
return _.some( READFILES( path.normalize( path.join(__dirname, haystack))), function( absPath ) {
if( FS.lstatSync( absPath ).isFile() ) {
if( fileContains( absPath, needle ) ) {
console.error('Found invalid metadata in ' + absPath);
return true;
}
}
});
}
genThemes( 'jane-q-fullstacker', ['node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json'], 'FRESH' );
genThemes( 'johnny-trouble', ['node_modules/fresh-test-resumes/src/fresh/johnny-trouble.json'], 'FRESH' );
genThemes( 'richard-hendriks', ['test/resumes/jrs-0.0.0/richard-hendriks.json'], 'JRS' );
describe('Verifying generated theme files...', function() {
it('Generated files should not contain ICE.', function() {
expect( folderContains('@@@@', '../sandbox') ).to.be.false;
});
});