UNPKG

learnyounode

Version:

Learn You The Node.js For Much Win! An intro to Node.js via a set of self-guided workshops.

200 lines (152 loc) 5.42 kB
const fs = require('fs') , path = require('path') , util = require('util') , files = require('../filtered_ls/file-list') , chalk = require('chalk') function validateModule (modFile, callback) { var exercise = this , __ = this.__ , __n = this.__n , dir = this._testDir , mod , error = new Error('testing') , returned = false , _callback = callback , callbackUsed try { mod = require(modFile) } catch (e) { exercise.emit('fail', __('fail.loadError', {message: e.message, path: path.basename(modFile)})) return callback(null, false) } callback = function () { returned = true _callback.apply(this, arguments) } function modFileError (txt) { exercise.emit('fail', __('fail.mod._base', {path: path.basename(modFile), message: txt})) callback (null, false) } //---- Check that our module file is `module.exports = function () {}` if (typeof mod != 'function') return modFileError(__('fail.mod.no_export', {method: chalk.bold(__('fail.mod.singleFunction'))})) exercise.emit('pass', __('pass.singleFunction')) //---- Check that the function exported takes 3 arguments if (mod.length < 3) return modFileError(__n('fail.mod.arguments', mod.length, {three: chalk.bold(__('fail.mod.arguments_three')), callback: chalk.bold(__('fail.mod.arguments_callback'))})) exercise.emit('pass', __n('pass.arguments', mod.length)) //---- Mock `fs.readdir` and check that an error bubbles back up through the cb fs.$readdir = fs.readdir fs.readdir = function (dir, callback) { callback(error) } function noerr () { modFileError(__('fail.mod.missing_error')) } callbackUsed = false try { mod('/foo/bar/', 'wheee', function (err) { if (err !== error) return noerr() callbackUsed = true }) } catch (e) { noerr() } if (callbackUsed) exercise.emit('pass', __('pass.error')) //---- Check whether the callback is used at all setTimeout(function () { if (returned) return if (!callbackUsed) return modFileError(__('fail.mod.missing_callback')) exercise.emit('pass', __('pass.callback')) // replace the mock readdir fs.readdir = fs.$readdir callbackUsed = false try { mod(dir, 'md', function (err, list) { if (err) { return modFileError(__('fail.mod.callback_error', {error: util.inspect(err)})) } //---- Check that we got the correct number of elements if (arguments.length < 2) { return modFileError(__n('fail.mod.callback_arguments', arguments.length)) } exercise.emit('pass', __('pass.callback_arguments')) //---- Check that we got an Array as the second argument if (!Array.isArray(list)) { return modFileError(__('fail.mod.missing_array_argument')) } exercise.emit('pass', __('pass.array_argument')) var exp = files.filter(function (f) { return (/\.md$/).test(f) }) , noDotExp = files.filter(function(f) { return (/md$/).test(f) }) , i //---- Check for `ext` instead of `.ext` if (noDotExp.length === list.length) { return modFileError(__('fail.mod.dotExt')) } //---- Check that we got the expected number of elements in the Array if (exp.length !== list.length) { return modFileError(__('fail.mod.array_wrong_size')) } exercise.emit('pass', __('pass.array_size')) callbackUsed = true //---- Check that the elements are exactly the same as expected (ignoring order) exp.sort() list.sort() for (i = 0; i < exp.length; i++) { if (list[i] !== exp[i]) { return modFileError(__('fail.mod.array_comparison')) } } exercise.emit('pass', __('pass.final')) //WIN!! callback() }) } catch (e) { return modFileError(__('fail.mod.unexpected', {error: util.inspect(e)})) } setTimeout(function () { if (returned) return if (!callbackUsed) return modFileError(__('fail.mod.timeout')) }, 300) }, 300) } // find any modules that are required by the submission program function requires (exercise) { // rule out these 4 things var main = path.resolve(process.cwd(), exercise.args[0]) , exec = require.resolve('workshopper-wrappedexec/exec-wrap') , wrap1 = require.resolve('../my_first_io/wrap') , wrap2 = require.resolve('./wrap-requires') return exercise.wrapData.requires.filter(function (m) { return m != main && m != exec && m != wrap1 && m != wrap2 }) } function verifyModuleUsed (callback) { var required = requires(this) if (required.length === 0) { this.emit('fail', this.__('fail.missing_module')) return callback(null, false) } validateModule.call(this, required[0], callback) } function verify (callback) { var usedSync = false , usedAsync = false Object.keys(this.wrapData.fsCalls).forEach(function (m) { if (/Sync$/.test(m)) { usedSync = true this.emit('fail', this.__('fail.sync', {method: 'fs.' + m + '()'})) } else { usedAsync = true this.emit('pass', this.__('pass.async', {method: 'fs.' + m + '()'})) } }.bind(this)) verifyModuleUsed.call(this, callback) } module.exports = verify