From 9b039de382d93c6fb3f0cb5a80a1aff904a74281 Mon Sep 17 00:00:00 2001 From: Frank Hellwig Date: Wed, 26 Sep 2012 14:06:43 -0400 Subject: [PATCH] Add tests --- README.md | 108 +++++++++++++++++++++------------- package.json | 5 +- pkgconfig.js | 13 ++-- test/config/config-fail.json | 4 ++ test/config/config-invalid.js | 5 ++ test/config/config-json.json | 3 + test/config/config.js | 5 ++ test/config/schema-fail.json | 13 ++++ test/config/schema-json.json | 12 ++++ test/config/schema.js | 14 +++++ test/package.json | 3 + test/test.js | 87 +++++++++++++++++++++++++++ 12 files changed, 224 insertions(+), 48 deletions(-) create mode 100644 test/config/config-fail.json create mode 100644 test/config/config-invalid.js create mode 100644 test/config/config-json.json create mode 100644 test/config/config.js create mode 100644 test/config/schema-fail.json create mode 100644 test/config/schema-json.json create mode 100644 test/config/schema.js create mode 100644 test/package.json create mode 100644 test/test.js diff --git a/README.md b/README.md index 821851f..b624ba7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Create a `config` directory in the top-level directory of your Node.js applicati This section describes the pkgconfig function, the default values, the options object, and environment variables. -### Function +### Configuration Function Require pkgconfig and call the function returned from `require('pkgconfig')`. @@ -51,14 +51,14 @@ This reads the `config.json` configuration file and validates it against the `sc Returns a configuration object. Throws an exception if there is an error reading the schema or configuration file or if the configuration data does not validate against the schema. -### Defaults +### Default Values Be default, pkgconfig looks for the following schema and a configuration files: - `/config/schema.(js|json)` - `/config/config.(js|json)` -### Options +### Options Parameter These defaults can be changed by passing an options object to the `pkgconfig` function. @@ -73,17 +73,36 @@ var options = { var config = pkgconfig(options); ``` -Either one of these properties can be a JavaScript object or the pathname to a file (with or without an extension). If an options property is not specified, it falls back to the default value. +#### Notes: -If it is a pathname, then it is resolved against the requiring package's base directory unless the pathname begins with a dot (i.e., `./` or `../`) in which case it is resolved against the current working directory. +1. Either one of these properties can be a JavaScript object or the pathname to a file (with or without an extension). If an options property is not specified, it falls back to the default value. +2. If it is a pathname, then it is resolved against the requiring package's base directory unless the pathname begins with a dot (i.e., `./` or `../`) in which case it is resolved against the current working directory. +3. If the options parameter is a string instead of an object, then it is used as the `config` option filename and the `schema` option defaults to its default value. -### Environment +### Environment Variables -The `PKGCONFIG_FILE` environment variable overrides the default configuration file pathname and any pathname specified in the options object. The `PKGCONFIG_FILE` environment variable has no effect on the schema file location since this should not be user-configurable. +The following two environment variables change the default config option. -### Extensions +1. The `NODE_CONFIG_DIR` environment variable changes the default config directory unless explicitly specified by the options. +2. The `NODE_ENV` environment variable changes the default config filename (basename) unless explicitly specified by the options. -Both `.js` and `.json` files are valid schema and configuration file extensions and are tried in that order if no extension is specified. If a JavaScript file is used for either the schema or the configuration file, then the object must be exported using the `module.exports` variable. +#### Notes: + +1. The environment variables only effect the default config option. If this option is explicitly specified in the options object, then the environment variables are not used. +2. The environment variables have no effect on the schema file location since this must not be user-configurable. + +The following code snippet summarizes how the environment variables are used. Again, note how they only effect the configuration file, and not the schema file. + +```javascript +var DEFAULT_SCHEMA = path.join('config', 'schema'); +var CONFIG_DIR = process.env['NODE_CONFIG_DIR'] || 'config' +var CONFIG_ENV = process.env['NODE_ENV'] || 'config' +var DEFAULT_CONFIG = path.join(CONFIG_DIR, CONFIG_ENV); +``` + +### Filename Extensions + +Both `.js` and `.json` files are valid schema and configuration file extensions and are tried in that order if the schema or config filename (after resolution) does not identify a file. If a JavaScript file is used for either the schema or the configuration file, then the object must be exported using the `module.exports` variable. ## Example @@ -93,29 +112,32 @@ configuration file that is valid against the schema. ### Sample schema.json file This is a sample JSON schema file that requires a port number having a range of -one to 65,535 and having a default value of 80. The pkgconfig utility uses the -[JSV](https://github.com/garycourt/JSV) JSON Schema Validator. - - { - "properties": { - "port": { - "description": "The web server port number.", - "type": "integer", - "required": true, - "minimum": 1, - "maximum": 65535, - "default": 80 - } +one to 65,535 and having a default value of 80. + +```json +{ + "properties": { + "port": { + "description": "The web server port number.", + "type": "integer", + "required": true, + "minimum": 1, + "maximum": 65535, + "default": 80 } } +} +``` ### Sample config.json file This is a sample JSON configuration file that specifies the port as being 8080. - { - "port": 8080 - } +```json +{ + "port": 8080 +} +``` ### Alternate file format @@ -124,28 +146,32 @@ JavaScript files can be used instead of JSON files by simple setting the A `schema.js` file can be used instead of the `schema.json` file. - var schema = { - properties: { - port: { - description: 'The web server port number.', - type: 'integer', - required: true, - minimum: 1, - maximum: 65535, - default: 80 - } +```javascript +var schema = { + properties: { + port: { + description: 'The web server port number.', + type: 'integer', + required: true, + minimum: 1, + maximum: 65535, + default: 80 } - }; + } +}; - module.exports = schema; +module.exports = schema; +``` A `config.js` file can be used instead of the `config.json` file. - var config = { - port: 8080 - }; +```javascript +var config = { + port: 8080 +}; - module.exports = config; +module.exports = config; +``` Beyond notational convenience, this also allows for nested constructs or code that evaluates the environment at runtime. diff --git a/package.json b/package.json index 900acf2..63e3a15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pkgconfig", - "version": "0.0.3", + "version": "0.0.4", "description": "Reads and validates JSON configuration files for Node.js packages.", "keywords": ["config","json","schema"], "licenses": [{ @@ -13,6 +13,9 @@ "url": "git://github.com/fhellwig/pkgconfig.git" }, "main": "./pkgconfig.js", + "scripts": { + "test": "node ./test/test.js" + }, "dependencies": { "findpkg": "0.0.x", "jsvutil": "0.0.x", diff --git a/pkgconfig.js b/pkgconfig.js index d0df8d8..f11a3da 100644 --- a/pkgconfig.js +++ b/pkgconfig.js @@ -27,9 +27,9 @@ var jsvutil = require('jsvutil'); var strformat = require('strformat'); var DEFAULT_SCHEMA = path.join('config', 'schema'); -var DEFAULT_CONFIG = path.join('config', 'config'); - -var PKGCONFIG_FILE = process.env['PKGCONFIG_FILE']; +var CONFIG_DIR = process.env['NODE_CONFIG_DIR'] || 'config' +var CONFIG_ENV = process.env['NODE_ENV'] || 'config' +var DEFAULT_CONFIG = path.join(CONFIG_DIR, CONFIG_ENV); var OPTIONS_SCHEMA = { type: 'object', @@ -102,11 +102,12 @@ function readFile(pathname) { function pkgconfig(options) { if (typeof options === 'undefined') { options = {}; + } else if (typeof options === 'string') { + options = {config: options}; + } else if (typeof options !== 'object') { + throw new TypeError('options must be an object or a string'); } options = jsvutil.validate(options, OPTIONS_SCHEMA); - if (PKGCONFIG_FILE) { - options.config = PKGCONFIG_FILE; - } var pkginfo = findpkg(module.parent); if (typeof options.schema === 'string') { options.schema = readFile(pkginfo.resolve(options.schema)); diff --git a/test/config/config-fail.json b/test/config/config-fail.json new file mode 100644 index 0000000..03d7901 --- /dev/null +++ b/test/config/config-fail.json @@ -0,0 +1,4 @@ +{ + bad + "port": 8080 +} diff --git a/test/config/config-invalid.js b/test/config/config-invalid.js new file mode 100644 index 0000000..6eb90cc --- /dev/null +++ b/test/config/config-invalid.js @@ -0,0 +1,5 @@ +var config = { + port: 99999 +}; + +module.exports = config; diff --git a/test/config/config-json.json b/test/config/config-json.json new file mode 100644 index 0000000..6a08d24 --- /dev/null +++ b/test/config/config-json.json @@ -0,0 +1,3 @@ +{ + "port": 8080 +} diff --git a/test/config/config.js b/test/config/config.js new file mode 100644 index 0000000..72a0e68 --- /dev/null +++ b/test/config/config.js @@ -0,0 +1,5 @@ +var config = { + port: 8080 +}; + +module.exports = config; diff --git a/test/config/schema-fail.json b/test/config/schema-fail.json new file mode 100644 index 0000000..9695003 --- /dev/null +++ b/test/config/schema-fail.json @@ -0,0 +1,13 @@ +{ + bad + "properties": { + "port": { + "description": "The web server port number.", + "type": "integer", + "required": true, + "minimum": 1, + "maximum": 65535, + "default": 80 + } + } +} diff --git a/test/config/schema-json.json b/test/config/schema-json.json new file mode 100644 index 0000000..52dd9f1 --- /dev/null +++ b/test/config/schema-json.json @@ -0,0 +1,12 @@ +{ + "properties": { + "port": { + "description": "The web server port number.", + "type": "integer", + "required": true, + "minimum": 1, + "maximum": 65535, + "default": 80 + } + } +} diff --git a/test/config/schema.js b/test/config/schema.js new file mode 100644 index 0000000..516ad79 --- /dev/null +++ b/test/config/schema.js @@ -0,0 +1,14 @@ +var schema = { + properties: { + port: { + description: 'The web server port number.', + type: 'integer', + required: true, + minimum: 1, + maximum: 65535, + default: 80 + } + } +}; + +module.exports = schema; diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..1208464 --- /dev/null +++ b/test/package.json @@ -0,0 +1,3 @@ +{ + "name": "pkgconfig-test" +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..6cc4759 --- /dev/null +++ b/test/test.js @@ -0,0 +1,87 @@ +var assert = require('assert'); +var pkgconfig = require('../pkgconfig.js'); + +// Test normal defaults. +var config = pkgconfig(); +assert.deepEqual(config, { port: 8080 }); + +// Test good JSON options object. +pkgconfig({ + schema: 'config/schema-json.json', + config: 'config/config-json.json' +}); + +// Test bad JSON schema. +assert.throws(function () { + pkgconfig({ + schema: 'config/schema-fail.json', + config: 'config/config-json.json' + }); +}, SyntaxError); + +// Test bad JSON config. +assert.throws(function () { + pkgconfig({ + schema: 'config/schema-json.json', + config: 'config/config-fail.json' + }); +}, SyntaxError); + +// Test invalid range. +assert.throws(function () { + pkgconfig('config/config-invalid'); +}, /ValidationError/); + +// Test invalid options. +assert.throws(function () { + pkgconfig(5); +}, TypeError); + +// Test valid config file string option. +pkgconfig('config/config'); + +// Test invalid config file string option. +assert.throws(function () { + pkgconfig('not/found'); +}, Error); + +// Test valid inline options. +pkgconfig({ + schema: { + properties: { + port: { + description: 'The web server port number.', + type: 'integer', + required: true, + minimum: 1, + maximum: 65535, + default: 80 + } + } + }, + config: { + port: 8080 + } +}); + +// Test invalid inline options. +assert.throws(function () { + pkgconfig({ + schema: { + properties: { + port: { + description: 'The web server port number.', + type: 'integer', + required: true, + minimum: 1, + maximum: 65535 + } + } + }, + config: { + badport: 8080 + } + }); +}, /ValidationError/); + +console.log('All tests passed successfully.');