Skip to content

Commit

Permalink
#20: add more utility tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nkrusch committed Jan 14, 2021
1 parent b7651d5 commit 5b64716
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 27 deletions.
72 changes: 56 additions & 16 deletions cli/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,35 @@ const path = require('path');

class Utilities {

constructor() {

}

/**
* Given some string value, generate another string
* from it, such that the generated string can be
* used as a directory name. This function will
* normalize the input and remove special characters.
*
* @param name - suggested directory name
* @param defaultName - value to return if
* no characters in name can be used
* @return {string} directory name
*/
generateDirectoryName(name, defaultName = 'extension-1') {
return ((name || '').toLowerCase()
.replace(/[\W_]+/g, ' ')
.replace(/ /g, '-')
.replace(/-$/, '')) || defaultName;
.replace(/[\W_]+/g, ' ')
.replace(/ /g, '-')
.replace(/-$/, '')) || defaultName;
};

/**
* Replace string interpolation expressions in
* a content string.
*
* @param content - string with placeholder values,
* @example "sample ${key}"
* @param vars - dictionary of <K,V> pairs
* @example { key : "value" }
* @return {string} -
* @example "sample value"
*/
replaceVars(content, vars) {
let temp = content.toString();

Expand Down Expand Up @@ -83,19 +101,41 @@ class Utilities {
return JSON.stringify(JSON.parse(this.readAndReplaceTextFile(path, vars)), null, 4);
}

keyReplace(src, target) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (Array.isArray(src[key])) {
target[key] = src[key];
/**
* Given two objects
* - add all keys from parent to child
* - override parent keys with child keys
*
* in other words: a union of child and
* parent with child values overriding
* all shared keys.
*
* This operation happens in place and
* result will be stored in parent object.
*
* @example
* let child = {a:1, b:5, c:{x:1}}
* let parent = {b:8, c:{y:9}}
* // expected result (parent):
* // {a:1, b:8, c:{x:1, y:9}}
*
* @param child - source object
* @param parent - parent object
*/
keyReplace(child, parent) {
for (let key in child) {
if (!child.hasOwnProperty(key)) continue;
if (Array.isArray(child[key])) {
parent[key] = child[key];
continue;
}
if (typeof src[key] !== 'object') {
target[key] = src[key];
if (typeof child[key] !== 'object') {
parent[key] = child[key];
continue;
}
if (!target[key]) target[key] = {};
this.keyReplace(src[key], target[key]);
if (!parent[key]) parent[key] = {};
this.keyReplace(child[key], parent[key]);
}
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"utility"
],
"scripts": {
"test": "nyc mocha ./test/**/*.js --colors",
"test": "nyc mocha ./test/*.test.js --colors",
"test:report": "npm run test -- nyc report",
"test:travis" : "npm run test && nyc report --reporter=text-lcov | coveralls"
},
Expand Down
13 changes: 13 additions & 0 deletions test/cli-create.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// TODO: how to require this without running the command?
// const BuildScript = require('../cli/xt-build');

// const expect = require('chai').expect;

describe('create command', () => {

// placeholder; replace this with actual test
// it('...(dummy test)', async () => {
// expect(true).to.equal(true);
// });

});
88 changes: 78 additions & 10 deletions test/cli-utililities.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,91 @@ describe('Test utility functions', () => {

describe('generateDirectoryName...', () => {

it('...returns lowercase name without special characters', async () => {
expect(Utilities.generateDirectoryName('Hello World')).to.equal('hello-world');
expect(Utilities.generateDirectoryName('Hello World!!!')).to.equal('hello-world');
expect(Utilities.generateDirectoryName('MyAwesome#@Thing')).to.equal('myawesome-thing');
expect(Utilities.generateDirectoryName('````', 'foobar')).to.equal('foobar');
it('...returns lowercase name', async () => {
expect(Utilities.generateDirectoryName('HELLO WORLD'))
.to.equal('hello-world');
expect(Utilities.generateDirectoryName('my app name'))
.to.equal('my-app-name');
expect(Utilities.generateDirectoryName('APP-APP'))
.to.equal('app-app');
expect(Utilities.generateDirectoryName('test789'))
.to.equal('test789');
});

it('...returns default name on fallthrough', async () => {
expect(Utilities.generateDirectoryName('', 'foobar')).to.equal('foobar');
expect(Utilities.generateDirectoryName(null).length).to.be.greaterThan(0);
it('...replaces special characters with hyphen', async () => {
expect(Utilities.generateDirectoryName('MyAwesome#@Thing'))
.to.equal('myawesome-thing');
expect(Utilities.generateDirectoryName('````', 'xyz'))
.to.equal('xyz');
});

it('...removes trailing hyphen', async () => {
expect(Utilities.generateDirectoryName('Hello World!!!'))
.to.equal('hello-world');
expect(Utilities.generateDirectoryName('awesom-o app#$%%'))
.to.equal('awesom-o-app');
});

it('...returns default name instead of empty string', async () => {
expect(Utilities.generateDirectoryName('', 'foobar'))
.to.equal('foobar');
expect(Utilities.generateDirectoryName(null).length)
.to.be.greaterThan(0);
});
});

describe('replaceVars', () => {
it('...replaces string interpolation with actual values', async () => {
expect(Utilities.replaceVars('test ${x} ${y}', {x: '1', y: 'z'})).to.equal('test 1 z');
it('...replaces one variable', async () => {
expect(Utilities.replaceVars(
'your ${myVar}?', {myVar: 'name'}))
.to.equal('your name?');
});
it('...replace two variables', async () => {
expect(Utilities.replaceVars(
'test ${x} ${y}', {x: '1', y: 'z'}))
.to.equal('test 1 z');
});
it('...ignores non-matching keys', async () => {
expect(Utilities.replaceVars(
'no ${match} for this', {}))
.to.equal('no ${match} for this');
});
it('...returns input if it contains no variables', async () => {
expect(Utilities.replaceVars(
'return me', {me: 'test'}))
.to.equal('return me');
});
it('...interpolation syntax must match', async () => {
expect(Utilities.replaceVars(
'return {me}', {me: 'test'}))
.to.equal('return {me}');
expect(Utilities.replaceVars(
'return $me2', {me2: 'test'}))
.to.equal('return $me2');
});
});

describe('keyReplace', () => {
it('...simple override', async () => {
let b = {x: 10};
Utilities.keyReplace({x: 8}, b);
expect(b.x).to.equal(8);
});
it('...performs union', async () => {
let b = {y: 10};
Utilities.keyReplace({x: 8}, b);
expect(b).to.have.keys(['x', 'y']);
});
it('...replaces array', async () => {
let b = {arr: [1, 2, 3]};
Utilities.keyReplace({arr: [1, 2]}, b);
expect(b.arr).to.have.length(2);
});
it('...replaces nested properties', async () => {
let b = {c: {d: 8, e: 10}};
Utilities.keyReplace({c: {e: 11}}, b);
expect(b.c.d).to.equal(8);
expect(b.c.e).to.equal(11);
});
});
});

0 comments on commit 5b64716

Please sign in to comment.