Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fhellwig committed Sep 26, 2012
1 parent 8ccac84 commit 9b039de
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 48 deletions.
108 changes: 67 additions & 41 deletions README.md
Expand Up @@ -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')`.

Expand All @@ -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:

- `<your-package-base>/config/schema.(js|json)`
- `<your-package-base>/config/config.(js|json)`

### Options
### Options Parameter

These defaults can be changed by passing an options object to the `pkgconfig` function.

Expand All @@ -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

Expand All @@ -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

Expand All @@ -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.
Expand Down
5 changes: 4 additions & 1 deletion 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": [{
Expand All @@ -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",
Expand Down
13 changes: 7 additions & 6 deletions pkgconfig.js
Expand Up @@ -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',
Expand Down Expand Up @@ -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));
Expand Down
4 changes: 4 additions & 0 deletions test/config/config-fail.json
@@ -0,0 +1,4 @@
{
bad
"port": 8080
}
5 changes: 5 additions & 0 deletions test/config/config-invalid.js
@@ -0,0 +1,5 @@
var config = {
port: 99999
};

module.exports = config;
3 changes: 3 additions & 0 deletions test/config/config-json.json
@@ -0,0 +1,3 @@
{
"port": 8080
}
5 changes: 5 additions & 0 deletions test/config/config.js
@@ -0,0 +1,5 @@
var config = {
port: 8080
};

module.exports = config;
13 changes: 13 additions & 0 deletions 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
}
}
}
12 changes: 12 additions & 0 deletions 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
}
}
}
14 changes: 14 additions & 0 deletions 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;
3 changes: 3 additions & 0 deletions test/package.json
@@ -0,0 +1,3 @@
{
"name": "pkgconfig-test"
}
87 changes: 87 additions & 0 deletions 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.');

0 comments on commit 9b039de

Please sign in to comment.