From 9f3f2667039f8166a1763de9e3c9f95534dbe5d6 Mon Sep 17 00:00:00 2001 From: "vitaliy.vlasuk" Date: Tue, 13 Sep 2016 10:40:58 +0300 Subject: [PATCH 1/9] Added write functionality --- src/PropertiesReader.js | 32 +++++++++++++++ test/writerTest.js | 87 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 test/writerTest.js diff --git a/src/PropertiesReader.js b/src/PropertiesReader.js index 880d969..5645bef 100644 --- a/src/PropertiesReader.js +++ b/src/PropertiesReader.js @@ -272,6 +272,38 @@ return this; }; + /** + * Stringify properties array + */ + PropertiesReader.prototype._stringifyProperties = function() { + var lines = []; + var section = null; + this.each(function (key, value) { + var tokens = key.split("."); + if (tokens.length > 1) { + if (section !== tokens[0]) { + section = tokens[0]; + lines.push("[" + section + "]"); + } + key = tokens[1]; + } else { + section = null; + } + lines.push(key + "=" + value); + }); + return lines; + }; + + /** + * Write properties into the file + * + * @param {String} destFile + * @param {function} error callback + */ + PropertiesReader.prototype.save = function(destFile, fail) { + fs.writeFile(destFile, this._stringifyProperties().join("\n"), fail); + }; + PropertiesReader.builder = function(sourceFile) { return new PropertiesReader(sourceFile); }; diff --git a/test/writerTest.js b/test/writerTest.js new file mode 100644 index 0000000..1927b06 --- /dev/null +++ b/test/writerTest.js @@ -0,0 +1,87 @@ + +var Assertions = require('unit-test').Assertions; +var Sinon = require('unit-test').Sinon; +var TestCase = require('unit-test').TestCase; +var FileSystem = require('fs'); +var propertiesReader = require('../src/PropertiesReader.js'); +var properties; + +function tempFile (content) { + tempFile.nextName = (tempFile.nextName || 0) + 1; + tempFile.files.push(__dirname + '/temp_file_' + tempFile.nextName + '.properties'); + FileSystem.writeFileSync(tempFile.files[tempFile.files.length - 1], content, 'utf-8'); +} + +function givenFilePropertiesReader (content) { + tempFile(content); + properties = propertiesReader(tempFile.files[tempFile.files.length - 1]); + return properties; +} + +module.exports = new TestCase("Writer", { + + setUp: function () { + tempFile.files = tempFile.files || []; + tempFile.dirs = tempFile.dirs || []; + }, + + tearDown: function () { + while (tempFile.files && tempFile.files.length) { + var filePath = tempFile.files.pop(); + try { + FileSystem.unlink(filePath); + } + catch (e) { + } + } + while (tempFile.dirs && tempFile.dirs.length) { + var dirPath = tempFile.dirs.pop(); + try { + FileSystem.rmdirSync(dirPath); + } + catch (e) { + } + } + }, + + 'test Able to stringify properties': function () { + var inputContent = 'property=Value'; + givenFilePropertiesReader(inputContent); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals(1, propertiesStringsArray.length, 'Output file has 1 line'); + Assertions.assertEquals(inputContent, propertiesStringsArray[0], 'Input and output content are the same.'); + }, + + 'test Able to stringify properties with section': function () { + var inputContent = '[main]\nproperty=Value'; + givenFilePropertiesReader(inputContent); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals(2, propertiesStringsArray.length, 'Output file has 2 lines'); + Assertions.assertEquals(inputContent, propertiesStringsArray.join('\n'), 'Input and output content are the same.'); + }, + + 'test Able to stringify properties with the few sections': function () { + var inputContent = 'property1=Value1\n[main]\nproperty2=Value2\n[second]\nproperty3=Value3\n[main]\nproperty4=Value4'; + givenFilePropertiesReader(inputContent); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals(7, propertiesStringsArray.length, 'Output file has 7 lines'); + Assertions.assertEquals(inputContent, propertiesStringsArray.join('\n'), 'Input and output content are the same.'); + }, + + 'test Able to stringify properties after set': function () { + var inputContent = 'property=Value'; + givenFilePropertiesReader(inputContent); + properties.set('property', 'xxx'); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals('property=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes.'); + }, + + 'test Able to stringify properties after set with sections': function () { + var inputContent = '[main]\nproperty=Value'; + givenFilePropertiesReader(inputContent); + properties.set('main.property', 'xxx'); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals('[main]\nproperty=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes.'); + } + +}); From 32c7c2ff208fc549ea87bbd51f77e85a369b00ec Mon Sep 17 00:00:00 2001 From: "vitaliy.vlasuk" Date: Tue, 13 Sep 2016 10:48:21 +0300 Subject: [PATCH 2/9] Added function description --- src/PropertiesReader.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PropertiesReader.js b/src/PropertiesReader.js index 5645bef..43488ba 100644 --- a/src/PropertiesReader.js +++ b/src/PropertiesReader.js @@ -273,7 +273,8 @@ }; /** - * Stringify properties array + * Stringify properties + * @returns {array} array of stringified properties */ PropertiesReader.prototype._stringifyProperties = function() { var lines = []; From 8170cb44578d7f914f489e968e50ef838c0d7923 Mon Sep 17 00:00:00 2001 From: "vitaliy.vlasuk" Date: Tue, 13 Sep 2016 11:19:26 +0300 Subject: [PATCH 3/9] Fixed keys with more than one dot --- src/PropertiesReader.js | 44 ++++++++++++++++++++--------------------- test/writerTest.js | 8 ++++++++ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/PropertiesReader.js b/src/PropertiesReader.js index 43488ba..9cf07f3 100644 --- a/src/PropertiesReader.js +++ b/src/PropertiesReader.js @@ -273,27 +273,27 @@ }; /** - * Stringify properties - * @returns {array} array of stringified properties - */ - PropertiesReader.prototype._stringifyProperties = function() { - var lines = []; - var section = null; - this.each(function (key, value) { - var tokens = key.split("."); - if (tokens.length > 1) { - if (section !== tokens[0]) { - section = tokens[0]; - lines.push("[" + section + "]"); - } - key = tokens[1]; - } else { - section = null; - } - lines.push(key + "=" + value); - }); - return lines; - }; + * Stringify properties + * @returns {array} array of stringified properties + */ + PropertiesReader.prototype._stringifyProperties = function() { + var lines = []; + var section = null; + this.each(function (key, value) { + var tokens = key.split('.'); + if (tokens.length > 1) { + if (section !== tokens[0]) { + section = tokens[0]; + lines.push('[' + section + ']'); + } + key = tokens.slice(1).join('.'); + } else { + section = null; + } + lines.push(key + '=' + value); + }); + return lines; + }; /** * Write properties into the file @@ -302,7 +302,7 @@ * @param {function} error callback */ PropertiesReader.prototype.save = function(destFile, fail) { - fs.writeFile(destFile, this._stringifyProperties().join("\n"), fail); + fs.writeFile(destFile, this._stringifyProperties().join('\n'), fail); }; PropertiesReader.builder = function(sourceFile) { diff --git a/test/writerTest.js b/test/writerTest.js index 1927b06..303a1e6 100644 --- a/test/writerTest.js +++ b/test/writerTest.js @@ -82,6 +82,14 @@ module.exports = new TestCase("Writer", { properties.set('main.property', 'xxx'); var propertiesStringsArray = properties._stringifyProperties(); Assertions.assertEquals('[main]\nproperty=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes.'); + }, + + 'test Able to stringify properties after set with sections and dots': function () { + var inputContent = '[main]\nproperty.one=Value'; + givenFilePropertiesReader(inputContent); + properties.set('main.property.one', 'xxx'); + var propertiesStringsArray = properties._stringifyProperties(); + Assertions.assertEquals('[main]\nproperty.one=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes with key with dot.'); } }); From 41c2486bbe0ef7b7005eb1913436a8710d3a4817 Mon Sep 17 00:00:00 2001 From: droopert Date: Wed, 12 Jun 2019 18:03:24 -0500 Subject: [PATCH 4/9] fixes empty string getting parsed as zero --- src/PropertiesReader.js | 2 +- test/readerTest.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/PropertiesReader.js b/src/PropertiesReader.js index d576794..0ae48a8 100644 --- a/src/PropertiesReader.js +++ b/src/PropertiesReader.js @@ -103,7 +103,7 @@ */ PropertiesReader.prototype._parsed = function(value) { var parsedValue = value; - if (value !== null && !isNaN(value)) { + if (value !== null && value !== '' && !isNaN(value)) { parsedValue = +value; } else if (value === 'true' || value === 'false') { diff --git a/test/readerTest.js b/test/readerTest.js index f3e446a..6d72622 100644 --- a/test/readerTest.js +++ b/test/readerTest.js @@ -115,6 +115,11 @@ module.exports = new TestCase("Reader", { Assertions.assertEquals(0.1, properties.get('d'), 'creates float'); }, + 'test Correctly handles values that are nothing but whitespace': function () { + givenFilePropertiesReader('a = \n'); + Assertions.assertEquals('', properties.getRaw('a'), 'Whitespace is handled as an empty string'); + }, + 'test Allows access to non-parsed values': function () { givenFilePropertiesReader( 'a = 123\n' + From 587b002d0120b86e16d110f7a64a79060c360b46 Mon Sep 17 00:00:00 2001 From: Steve King Date: Thu, 13 Jun 2019 06:47:47 +0100 Subject: [PATCH 5/9] Switch to yarn package management --- package-lock.json | 164 ---------------------------------------------- yarn.lock | 126 +++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 164 deletions(-) delete mode 100644 package-lock.json create mode 100644 yarn.lock diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index c413c62..0000000 --- a/package-lock.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "name": "properties-reader", - "version": "0.0.16", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "dev": true, - "requires": { - "samsam": "1.3.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lolex": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", - "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==", - "dev": true - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "nise": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.3.tgz", - "integrity": "sha512-v1J/FLUB9PfGqZLGDBhQqODkbLotP0WtLo9R4EJY2PPu5f5Xg4o0rA8FDlmrjFSv9vBBKcfnOSpfYYuu5RTHqg==", - "dev": true, - "requires": { - "@sinonjs/formatio": "2.0.0", - "just-extend": "1.1.27", - "lolex": "2.3.2", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" - } - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "readdir": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/readdir/-/readdir-0.0.13.tgz", - "integrity": "sha1-TdAC0/MNwRr+O7F3rY6ZCU9/Yt0=", - "dev": true, - "requires": { - "q": "1.0.1" - }, - "dependencies": { - "q": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.0.1.tgz", - "integrity": "sha1-EYcq7t7okmgRCxCnGESP+xARKhQ=", - "dev": true - } - } - }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", - "dev": true - }, - "sinon": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", - "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", - "dev": true, - "requires": { - "@sinonjs/formatio": "2.0.0", - "diff": "3.5.0", - "lodash.get": "4.4.2", - "lolex": "2.3.2", - "nise": "1.3.3", - "supports-color": "5.4.0", - "type-detect": "4.0.8" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "unit-test": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/unit-test/-/unit-test-0.0.9.tgz", - "integrity": "sha1-wsONIstDI9qAngbVbsRHOirakjc=", - "dev": true, - "requires": { - "q": "1.5.1", - "readdir": "0.0.13", - "sinon": "4.5.0" - } - } - } -} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..35402ce --- /dev/null +++ b/yarn.lock @@ -0,0 +1,126 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@sinonjs/commons@^1", "@sinonjs/commons@^1.0.2", "@sinonjs/commons@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78" + dependencies: + type-detect "4.0.8" + +"@sinonjs/formatio@^3.1.0", "@sinonjs/formatio@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.1.tgz#52310f2f9bcbc67bdac18c94ad4901b95fde267e" + dependencies: + "@sinonjs/commons" "^1" + "@sinonjs/samsam" "^3.1.0" + +"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.1.tgz#e88c53fbd9d91ad9f0f2b0140c16c7c107fe0d07" + dependencies: + "@sinonjs/commons" "^1.0.2" + array-from "^2.1.1" + lodash "^4.17.11" + +"@sinonjs/text-encoding@^0.7.1": + version "0.7.1" + resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" + +array-from@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" + +diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +just-extend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" + +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + +lolex@^4.0.1, lolex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.1.0.tgz#ecdd7b86539391d8237947a3419aa8ac975f0fe1" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +nise@^1.4.10: + version "1.5.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.0.tgz#d03ea0e6c1b75c638015aa3585eddc132949a50d" + dependencies: + "@sinonjs/formatio" "^3.1.0" + "@sinonjs/text-encoding" "^0.7.1" + just-extend "^4.0.2" + lolex "^4.1.0" + path-to-regexp "^1.7.0" + +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + +q@^1.0.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +q@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.0.1.tgz#11872aeedee89268110b10a718448ffb10112a14" + +readdir@: + version "0.1.0" + resolved "https://registry.yarnpkg.com/readdir/-/readdir-0.1.0.tgz#1b587f2c629fc93f8c86d5afd42d172293401a12" + dependencies: + q "~1.0.1" + +sinon@: + version "7.3.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28" + dependencies: + "@sinonjs/commons" "^1.4.0" + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/samsam" "^3.3.1" + diff "^3.5.0" + lolex "^4.0.1" + nise "^1.4.10" + supports-color "^5.5.0" + +supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + +unit-test@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/unit-test/-/unit-test-0.0.9.tgz#c2c38d22cb4323da809e06d56ec4473a2ada9237" + dependencies: + q "^1.0.1" + readdir "" + sinon "" From 262021f6f5ac1a33b0e874988e3e847085569637 Mon Sep 17 00:00:00 2001 From: Steve King Date: Mon, 17 Jun 2019 07:52:07 +0100 Subject: [PATCH 6/9] Switch to yarn package management, use mocha for tests --- .gitignore | 5 +- .npmignore | 3 - package.json | 7 +- test/bind-to-server.spec.js | 54 +++ test/bindToServerTest.js | 69 ---- test/reader.spec.js | 204 +++++++++++ test/readerTest.js | 252 ------------- test/runner.js | 2 - test/section.spec.js | 95 +++++ test/sectionTest.js | 93 ----- test/utils/bdd.js | 6 + test/utils/remove-temp-fs.js | 9 + test/utils/temporary-file.js | 31 ++ test/writer.spec.js | 86 +++++ test/writerTest.js | 95 ----- yarn.lock | 687 ++++++++++++++++++++++++++++++++++- 16 files changed, 1161 insertions(+), 537 deletions(-) delete mode 100644 .npmignore create mode 100644 test/bind-to-server.spec.js delete mode 100644 test/bindToServerTest.js create mode 100644 test/reader.spec.js delete mode 100644 test/readerTest.js delete mode 100644 test/runner.js create mode 100644 test/section.spec.js delete mode 100644 test/sectionTest.js create mode 100644 test/utils/bdd.js create mode 100644 test/utils/remove-temp-fs.js create mode 100644 test/utils/temporary-file.js create mode 100644 test/writer.spec.js delete mode 100644 test/writerTest.js diff --git a/.gitignore b/.gitignore index 932d4cd..3f2f466 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -*.iml -node_modules \ No newline at end of file +.idea/ + +node_modules/ diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 6fc5c20..0000000 --- a/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/* -.idea/* -*.iml diff --git a/package.json b/package.json index 2735a01..bb1cccb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "mkdirp": "~0.5.1" }, "devDependencies": { - "unit-test": "*" + "expect.js": "^0.3.1", + "mocha": "^6.1.4", + "rimraf": "^2.6.3", + "sinon": "^7.3.2" }, "keywords": [ "properties", @@ -36,7 +39,7 @@ "src/**/*.js" ], "scripts": { - "test": "node test/runner.js" + "test": "mocha ./test/*.spec.js" }, "license": "MIT" } diff --git a/test/bind-to-server.spec.js b/test/bind-to-server.spec.js new file mode 100644 index 0000000..29ab934 --- /dev/null +++ b/test/bind-to-server.spec.js @@ -0,0 +1,54 @@ +const expect = require('expect.js'); +const {spy} = require('sinon'); + +describe('bind-to-server', () => { + + let properties; + + const tempFile = require('./utils/temporary-file'); + const {givenFilePropertiesReader} = require('./utils/bdd'); + + function givenTheProperties (content) { + return properties = givenFilePropertiesReader(content); + } + + beforeEach(() => { + }); + + afterEach(() => tempFile.tearDown()); + + it('test Creates directories when necessary - absolute paths', () => { + const dirPath = tempFile.pushDir('/tmp/' + Math.floor(Math.random() * 1e10).toString(16)); + const app = {set: spy()}; + + givenTheProperties(` + + some.property.dir = ${ dirPath } + + foo.bar = A Value + + `).bindToExpress(app, null, true); + + expect(require('fs').statSync(dirPath).isDirectory()).to.be.ok(); + }); + + it('test Creates directories when necessary - relative paths', () => { + const dirName = Math.floor(Math.random() * 1e10).toString(16); + const dirBase = process.cwd(); + const dirPath = tempFile.pushDir(dirBase + '/' + dirName); + const app = {set: spy()}; + + givenTheProperties(` + + some.property.dir = ${ dirName } + + foo.bar = A Value + + `).bindToExpress(app, dirBase, true); + + expect(require('fs').statSync(dirPath).isDirectory()).to.be.ok(); + }); + + +}); + diff --git a/test/bindToServerTest.js b/test/bindToServerTest.js deleted file mode 100644 index 311fbca..0000000 --- a/test/bindToServerTest.js +++ /dev/null @@ -1,69 +0,0 @@ - -var Assertions = require('unit-test').Assertions, - Sinon = require('unit-test').Sinon, - TestCase = require('unit-test').TestCase, - FileSystem = require('fs'), - noOp = function () {}, - propertiesReader = require('../src/PropertiesReader.js'), - properties; - -function tempFile(content) { - tempFile.nextName = (tempFile.nextName || 0) + 1; - tempFile.files.push(__dirname + '/temp_file_' + tempFile.nextName + '.properties'); - FileSystem.writeFileSync(tempFile.files[tempFile.files.length - 1], content, 'utf-8'); -} - -tempFile.pushDir = function (path) { - tempFile.dirs.push(path); - return path; -}; - -function givenFilePropertiesReader(content) { - tempFile(content); - properties = propertiesReader(tempFile.files[tempFile.files.length - 1]); - return properties; -} - -module.exports = new TestCase("Bind properties to a server", { - - setUp: function() { - tempFile.files = tempFile.files || []; - tempFile.dirs = tempFile.dirs || []; - }, - - tearDown: function() { - while(tempFile.files && tempFile.files.length) { - var filePath = tempFile.files.pop(); - try { - FileSystem.unlink(filePath, noOp); - } - catch(e) {} - } - while(tempFile.dirs && tempFile.dirs.length) { - var dirPath = tempFile.dirs.pop(); - try { - FileSystem.rmdirSync(dirPath); - } - catch(e) {} - } - }, - - 'test Creates directories when necessary - absolute paths': function () { - var dirPath = tempFile.pushDir('/tmp/' + Math.floor(Math.random() * 1e10).toString(16)); - var app = {set: Sinon.spy()}; - givenFilePropertiesReader('\n\nsome.property.dir=' + dirPath + '\n\nfoo.bar = A Value').bindToExpress(app, null, true); - - Assertions.assert(require('fs').statSync(dirPath).isDirectory(), 'Should have created the absolute path directory'); - }, - - 'test Creates directories when necessary - relative paths': function () { - var dirName = Math.floor(Math.random() * 1e10).toString(16); - var dirBase = process.cwd(); - var dirPath = tempFile.pushDir(dirBase + '/' + dirName); - var app = {set: Sinon.spy()}; - - givenFilePropertiesReader('\n\nsome.property.dir=' + dirName + '\n\nfoo.bar = A Value').bindToExpress(app, dirBase, true); - - Assertions.assert(require('fs').statSync(dirPath).isDirectory(), 'Should have created the relative path directory'); - } -}); diff --git a/test/reader.spec.js b/test/reader.spec.js new file mode 100644 index 0000000..bcb2d33 --- /dev/null +++ b/test/reader.spec.js @@ -0,0 +1,204 @@ +const expect = require('expect.js'); +const {spy} = require('sinon'); + +describe('Reader', () => { + + let properties; + + const tempFile = require('./utils/temporary-file'); + const {givenFilePropertiesReader} = require('./utils/bdd'); + + function givenTheProperties (content) { + return properties = givenFilePropertiesReader(content); + } + + beforeEach(() => { + }); + + afterEach(() => tempFile.tearDown()); + + it('test Able to read from a file', () => { + givenTheProperties('some.property=Value'); + expect(properties.get('some.property')).to.be('Value'); + }); + + it('test Merges multiple files', () => { + givenTheProperties('some.property=Value'); + + tempFile('[section]\nsome.property=Another Value'); + properties.append(tempFile.files[tempFile.files.length - 1]); + + expect(properties.get('section.some.property')).to.be('Another Value'); + expect(properties.get('some.property')).to.be('Value'); + }); + + it('test Runs a function across all items in the reader', () => { + givenTheProperties( + 'a = 123\n' + + 'b = true\n' + ); + + assertionsFor(spy(), properties, (s, c) => properties.each(s)); + assertionsFor(spy(), {a: 'bcd'}, (s, c) => properties.each(s, c)); + + function assertionsFor (theSpy, theContext, run) { + run(theSpy, theContext); + + expect(theSpy.callCount).to.be(2); + expect(theSpy.calledWith('a', '123')).to.be.ok(); + expect(theSpy.calledWith('b', 'true')).to.be.ok(); + expect(theSpy.alwaysCalledOn(theContext)).to.be.ok(); + } + }); + + it('test Attempts type coercion', () => { + givenTheProperties( + 'a = 123\n' + + 'b = true\n' + + 'c = false\n' + + 'd = 0.1'); + expect(properties.get('b')).to.be(true); + expect(properties.get('c')).to.be(false); + expect(properties.get('a')).to.be(123); + expect(properties.get('d')).to.be(0.1); + }); + + it('test Correctly handles values that are nothing but whitespace', () => { + givenTheProperties('a = \n'); + expect(properties.getRaw('a')).to.be(''); + }); + + it('test Allows access to non-parsed values', () => { + givenTheProperties(` + a = 123 + b = true + c = false + d = 0.1 + `); + expect(properties.getRaw('b')).to.be('true'); + expect(properties.getRaw('c')).to.be('false'); + expect(properties.getRaw('a')).to.be('123'); + expect(properties.getRaw('d')).to.be('0.1'); + }); + + it('test Properties are trimmed when parsed', () => { + givenTheProperties(` + some.property =Value + foo.bar = A Value`); + + expect(properties.get('some.property')).to.be('Value'); + expect(properties.get('foo.bar')).to.be('A Value'); + }); + + it('test Blank lines are ignored', () => { + givenTheProperties('\n\nsome.property=Value\n\nfoo.bar = A Value'); + + expect(properties.length).to.be(2); + }); + + it('test Properties can be read back via their dot notation names', () => { + givenTheProperties('\n\nsome.property=Value\n\nfoo.bar = A Value'); + + expect(properties.path().some.property).to.be('Value'); + expect(properties.path().foo.bar).to.be('A Value'); + }); + + it('test Sets properties into an app', () => { + const app = {set: spy()}; + givenTheProperties(` + some.property=Value + foo.bar = A Value`).bindToExpress(app); + + expect(app.set.withArgs('properties', properties).calledOnce).to.be.ok(); + expect(app.set.withArgs('some.property', 'Value').calledOnce).to.be.ok(); + expect(app.set.withArgs('foo.bar', 'A Value').calledOnce).to.be.ok(); + }); + + it('test Permits escaped new line characters', () => { + givenTheProperties('\n\nsome.property= Multi\\n Line \\nString \nfoo.bar = A Value'); + + // parsed access modifies the new line characters + expect(properties.get('foo.bar')).to.be('A Value'); + expect(properties.get('some.property')).to.be('Multi\n Line \nString'); + + // raw access does not modify the new line characters + expect(properties.getRaw('some.property')).to.be('Multi\\n Line \\nString'); + expect(properties.path().some.property).to.be('Multi\\n Line \\nString'); + }); + + it('test Returns null when getting a missing property', () => { + givenTheProperties('prop = value'); + + // parsed access modifies the new line characters + expect(properties.get('prop')).to.be('value'); + expect(properties.get('missing')).to.be(null); + }); + + it('test getByRoot when getting a bunch of objects', () => { + givenTheProperties(` + root.sect.a = 1 + root.sect.b = bar + root.path.b = true + root.path.c = false + root.path.d = 0.1 + `); + + expect(properties.getByRoot('root.path').b).to.be(true); + expect(properties.getByRoot('root.path').c).to.be(false); + + expect(properties.getByRoot('root.sect')).to.eql( + { + a: 1, + b: 'bar' + } + ); + }); + + it('test getByRoot when names are sub strings', () => { + givenTheProperties(` + + root.sect.a = 1 + root.section.b = bar + root.sect.c = false + root.section.d = 0.1 + + `); + + expect(properties.getByRoot('root.sect')).to.eql({ + a: 1, + c: false + }); + }); + + it('test getAllProperties returns properties map', () => { + givenTheProperties(` + + root.a.b = Hello + some.thing = Else + + `); + + expect(properties.getAllProperties()).to.eql({ + 'root.a.b': "Hello", + 'some.thing': 'Else' + }); + }); + + it('test getAllProperties is immutable', () => { + givenTheProperties(` + + root.a.b = Hello + some.thing = Else + + `); + + const all = properties.getAllProperties(); + all['root.a.b'] = 'New Value'; + + expect(properties.getAllProperties()).to.eql({ + 'root.a.b': "Hello", + 'some.thing': 'Else' + }); + }); + +}); diff --git a/test/readerTest.js b/test/readerTest.js deleted file mode 100644 index 6d72622..0000000 --- a/test/readerTest.js +++ /dev/null @@ -1,252 +0,0 @@ - -var Assertions = require('unit-test').Assertions; -var Sinon = require('unit-test').Sinon; -var TestCase = require('unit-test').TestCase; -var FileSystem = require('fs'); -var noOp = function () {}; -var propertiesReader = require('../src/PropertiesReader.js'); -var properties; - -function same (actual, expected) { - if (actual === expected) return true; - if (Array.isArray(actual)) - return Array.isArray(expected) && - actual.every(function (value, index) { return same(value, expected[index]); }) && - expected.every(function (value, index) { return same(actual[index], value); }); - if (actual && typeof actual === "object") - return (expected && typeof expected === "object") && - Object.keys(actual).every(function (key) { return same(actual[key], expected[key]); }) && - Object.keys(expected).every(function (key) { return same(actual[key], expected[key]); }); - - if (actual != expected) { - throw "Expected " + actual + " to be " + expected; - } - - return actual == expected; -} - -function tempFile (content) { - tempFile.nextName = (tempFile.nextName || 0) + 1; - tempFile.files.push(__dirname + '/temp_file_' + tempFile.nextName + '.properties'); - FileSystem.writeFileSync(tempFile.files[tempFile.files.length - 1], content, 'utf-8'); -} - -tempFile.pushDir = function (path) { - tempFile.dirs.push(path); - return path; -}; - -function givenFilePropertiesReader (content) { - tempFile(content); - properties = propertiesReader(tempFile.files[tempFile.files.length - 1]); - return properties; -} - -module.exports = new TestCase("Reader", { - - setUp: function () { - tempFile.files = tempFile.files || []; - tempFile.dirs = tempFile.dirs || []; - }, - - tearDown: function () { - while (tempFile.files && tempFile.files.length) { - var filePath = tempFile.files.pop(); - try { - FileSystem.unlink(filePath, noOp); - } - catch (e) { - } - } - while (tempFile.dirs && tempFile.dirs.length) { - var dirPath = tempFile.dirs.pop(); - try { - FileSystem.rmdirSync(dirPath); - } - catch (e) { - } - } - }, - - 'test Able to read from a file': function () { - givenFilePropertiesReader('some.property=Value'); - Assertions.assertEquals('Value', properties.get('some.property'), 'Values are read into the properties object'); - }, - - 'test Merges multiple files': function () { - givenFilePropertiesReader('some.property=Value'); - - tempFile('[section]\nsome.property=Another Value'); - properties.append(tempFile.files[tempFile.files.length - 1]); - - Assertions.assertEquals('Another Value', properties.get('section.some.property'), 'Uses sections in any of the appended content'); - Assertions.assertEquals('Value', properties.get('some.property'), 'Values are read into the properties object'); - }, - - 'test Runs a function across all items in the reader': function () { - givenFilePropertiesReader( - 'a = 123\n' + - 'b = true\n' - ); - var spy, scope = {some: 'thing'}; - - properties.each(spy = Sinon.spy()); - - Assertions.assertEquals(2, spy.callCount, 'Called for each item'); - Assertions.assert(spy.calledWith('a', '123')); - Assertions.assert(spy.calledWith('b', 'true')); - Assertions.assert(spy.alwaysCalledOn(properties)); - - properties.each(spy = Sinon.spy(), scope); - - Assertions.assertEquals(2, spy.callCount, 'Called for each item'); - Assertions.assert(spy.alwaysCalledOn(scope)); - }, - - 'test Attempts type coercion': function () { - givenFilePropertiesReader( - 'a = 123\n' + - 'b = true\n' + - 'c = false\n' + - 'd = 0.1'); - Assertions.assertEquals(true, properties.get('b'), 'creates boolean true'); - Assertions.assertEquals(false, properties.get('c'), 'creates boolean false'); - Assertions.assertEquals(123, properties.get('a'), 'creates integer'); - Assertions.assertEquals(0.1, properties.get('d'), 'creates float'); - }, - - 'test Correctly handles values that are nothing but whitespace': function () { - givenFilePropertiesReader('a = \n'); - Assertions.assertEquals('', properties.getRaw('a'), 'Whitespace is handled as an empty string'); - }, - - 'test Allows access to non-parsed values': function () { - givenFilePropertiesReader( - 'a = 123\n' + - 'b = true\n' + - 'c = false\n' + - 'd = 0.1'); - Assertions.assertEquals('true', properties.getRaw('b'), 'creates boolean true'); - Assertions.assertEquals('false', properties.getRaw('c'), 'creates boolean false'); - Assertions.assertEquals('123', properties.getRaw('a'), 'creates integer'); - Assertions.assertEquals('0.1', properties.getRaw('d'), 'creates float'); - }, - - 'test Properties are trimmed when parsed': function () { - givenFilePropertiesReader('some.property =Value \nfoo.bar = A Value'); - - Assertions.assertEquals(properties.get('some.property'), 'Value', 'Values are read into the properties object'); - Assertions.assertEquals(properties.get('foo.bar'), 'A Value', 'Values are trimmed as they are read into the properties object'); - }, - - 'test Blank lines are ignored': function () { - givenFilePropertiesReader('\n\nsome.property=Value\n\nfoo.bar = A Value'); - - Assertions.assertEquals(properties.length, 2, 'Blank lines are not stored as properties'); - }, - - 'test Properties can be read back via their dot notation names': function () { - givenFilePropertiesReader('\n\nsome.property=Value\n\nfoo.bar = A Value'); - - Assertions.assertEquals(properties.path().some.property, 'Value', 'Read back along dot notation paths some.property'); - Assertions.assertEquals(properties.path().foo.bar, 'A Value', 'Read back along dot notation paths foo.bar'); - }, - - 'test Sets properties into an app': function () { - var app = {set: Sinon.spy()}; - var properties = givenFilePropertiesReader('\n\nsome.property=Value\n\nfoo.bar = A Value').bindToExpress(app); - - Assertions.assert(app.set.withArgs('properties', properties).calledOnce, 'The complete properties object should be set as "properties"'); - Assertions.assert(app.set.withArgs('some.property', 'Value').calledOnce, 'Sets all properties'); - Assertions.assert(app.set.withArgs('foo.bar', 'A Value').calledOnce, 'Sets all properties'); - }, - - 'test Permits escaped new line characters': function () { - var properties = givenFilePropertiesReader('\n\nsome.property= Multi\\n Line \\nString \nfoo.bar = A Value'); - - // parsed access modifies the new line characters - Assertions.assertEquals(properties.get('foo.bar'), 'A Value', 'Sets all properties'); - Assertions.assertEquals(properties.get('some.property'), 'Multi\n Line \nString', 'Sets all properties'); - - // raw access does not modify the new line characters - Assertions.assertEquals(properties.getRaw('some.property'), 'Multi\\n Line \\nString', 'Sets all properties'); - Assertions.assertEquals(properties.path().some.property, 'Multi\\n Line \\nString', 'Sets all properties'); - }, - - 'test Returns null when getting a missing property': function () { - var properties = givenFilePropertiesReader('prop = value'); - - // parsed access modifies the new line characters - Assertions.assertEquals(properties.get('prop'), 'value', 'Gets values that are present'); - Assertions.assertEquals(properties.get('missing'), null, 'Gets null for values that are missing'); - }, - - 'test getByRoot when getting a bunch of objects': function () { - givenFilePropertiesReader( - 'root.sect.a = 1\n' + - 'root.sect.b = bar\n' + - 'root.path.b = true\n' + - 'root.path.c = false\n' + - 'root.path.d = 0.1'); - - Assertions.assertEquals(true, properties.getByRoot('root.path').b, "fetch an object of the right type"); - Assertions.assertEquals(false, properties.getByRoot('root.path').c, "fetch an object of the right type"); - - Assertions.assert(same( - properties.getByRoot('root.sect'), - { - a: 1, - b: 'bar' - } - ), "fetch an entire object"); - }, - - 'test getByRoot when names are sub strings': function () { - givenFilePropertiesReader( - 'root.sect.a = 1\n' + - 'root.section.b = bar\n' + - 'root.sect.c = false\n' + - 'root.section.d = 0.1'); - - Assertions.assert(same( - properties.getByRoot('root.sect'), - { - a: 1, - c: false - } - ), "fetch an entire object"); - }, - - 'test getAllProperties returns properties map': function () { - givenFilePropertiesReader('\ - root.a.b = Hello\n\ - some.thing = Else\n\ - '); - - Assertions.assert(same( - properties.getAllProperties(), - { - 'root.a.b': "Hello", - 'some.thing': 'Else' - } - ), "fetch an entire object"); - }, - - 'test getAllProperties is immutable': function () { - givenFilePropertiesReader('\ - root.a.b = Hello\n\ - some.thing = Else\n\ - '); - - var allProperties = properties.getAllProperties(); - allProperties['root.a.b'] = 'New Value'; - - Assertions.assert(same( - properties.getAllProperties(), - { - 'root.a.b': "Hello", - 'some.thing': 'Else' - } - ), "properties remain unchanged"); - } -}); diff --git a/test/runner.js b/test/runner.js deleted file mode 100644 index e7f89cf..0000000 --- a/test/runner.js +++ /dev/null @@ -1,2 +0,0 @@ - -require('unit-test').Suite.paths(__dirname, ['**Test.js']); diff --git a/test/section.spec.js b/test/section.spec.js new file mode 100644 index 0000000..b7e1b96 --- /dev/null +++ b/test/section.spec.js @@ -0,0 +1,95 @@ +const expect = require('expect.js'); + +describe('section', () => { + + let properties; + + const tempFile = require('./utils/temporary-file'); + const {givenFilePropertiesReader} = require('./utils/bdd'); + + function givenTheProperties (content) { + return properties = givenFilePropertiesReader(content); + } + + beforeEach(() => { + }); + + afterEach(() => tempFile.tearDown()); + + it('test Able to read URLs as part of a section', () => { + givenTheProperties(` +[foo] +base.api.url=http://blah.com + +[trade] +base.api.url=http://google.com + +[another] +thing = 123 + `); + + expect(properties.get('foo.base.api.url')).to.be('http://blah.com'); + expect(properties.get('trade.base.api.url')).to.be('http://google.com'); + expect(properties.get('another.thing')).to.be(123); + }); + + it('test Able to read file with sections that are already properties', () => { + givenTheProperties(` + some = thing + section = value + + [section] + sub = property + `); + + expect(properties.get('section')).to.be('value'); + expect(properties.get('section.sub')).to.be('property'); + expect(properties.path().section).to.eql({'': 'value', 'sub': 'property'}); + }); + + it('test Ignores comment blocks', () => { + givenTheProperties(` + + some = thing + + # section = value + section = another value + + `); + + expect(properties.get('section')).to.be('another value'); + }); + + it('test Able to read from a file with sections', () => { + givenTheProperties(` + some.property = Value + + [section] + another.property = Something + + [blah] + another.property = Something Else + + `); + + expect(properties.get('some.property')).to.be('Value'); + expect(properties.get('section.another.property')).to.be('Something'); + expect(properties.path().blah.another.property).to.be('Something Else'); + }); + + it('test Able use section names with white space', () => { + givenTheProperties(` + + some.property = Value + + [submodule foo] + another.property = Something + + [some thing in here] + another.property = Something Else + + `); + expect(properties.path()['submodule foo'].another.property).to.be('Something'); + }); + +}); diff --git a/test/sectionTest.js b/test/sectionTest.js deleted file mode 100644 index 43499c5..0000000 --- a/test/sectionTest.js +++ /dev/null @@ -1,93 +0,0 @@ -var Assertions = require('unit-test').Assertions, - Sinon = require('unit-test').Sinon, - TestCase = require('unit-test').TestCase, - FileSystem = require('fs'), - noOp = function () {}, - propertiesReader = require('../src/PropertiesReader.js'), - properties; - -function tempFile(content) { - tempFile.nextName = (tempFile.nextName || 0) + 1; - (tempFile.files = tempFile.files || []).push(__dirname + '/temp_file_' + tempFile.nextName + '.properties'); - FileSystem.writeFileSync(tempFile.files[tempFile.files.length - 1], content, 'utf-8'); -} - -function givenFilePropertiesReader(content) { - tempFile(content); - properties = propertiesReader(tempFile.files[tempFile.files.length - 1]); -} - -module.exports = new TestCase("Section", { - - setUp: function() { - }, - - tearDown: function() { - while (tempFile.files && tempFile.files.length) { - var filePath = tempFile.files.pop(); - try { - FileSystem.unlink(filePath, noOp); - } - catch (e) { - } - } - }, - - 'test Able to read URLs as part of a section': function () { - givenFilePropertiesReader(` -[foo] -base.api.url=http://blah.com - -[trade] -base.api.url=http://google.com - -[another] -thing = 123 - `); - - Assertions.assertEquals(properties.get('foo.base.api.url'), 'http://blah.com', 'url in first section'); - Assertions.assertEquals(properties.get('trade.base.api.url'), 'http://google.com', 'url in second section'); - Assertions.assertEquals(properties.get('another.thing'), 123, 'number in third section'); - }, - - 'test Able to read file with sections that are already properties': function () { - givenFilePropertiesReader([ - 'some = thing', - 'section = value', - '[section]', - 'sub = property' - ].join('\n')); - - Assertions.assertEquals(properties.get('section'), 'value', 'give precedence to the name'); - Assertions.assertEquals(properties.get('section.sub'), 'property', 'gets the child property'); - Assertions.assert(Sinon.match({'': 'value', 'sub': 'property'}).test(properties.path().section), - 'gets an object with the empty string property equal to outer section value'); - }, - - 'test Ignores comment blocks': function () { - givenFilePropertiesReader([ - 'some = thing', - ' # section = value', - 'section = another value' - ].join('\n')); - - Assertions.assertEquals(properties.get('section'), 'another value', 'ignores the comment'); - }, - - 'test Able to read from a file with sections': function() { - givenFilePropertiesReader('some.property = Value\n\n' + - '[section]\n another.property = Something\n\n' + - '[blah]\n another.property = Something Else'); - - Assertions.assertEquals(properties.get('some.property'), 'Value', 'Values are read into the properties object'); - Assertions.assertEquals(properties.get('section.another.property'), 'Something', 'Values are read into the properties object'); - Assertions.assertEquals(properties.path().blah.another.property, 'Something Else', 'Values are read into the properties object'); - }, - - 'test Able use section names with white space': function() { - givenFilePropertiesReader('some.property = Value\n\n' + - '[submodule foo]\n another.property = Something\n\n' + - '[some thing in here]\n another.property = Something Else'); - Assertions.assertEquals(properties.path()['submodule foo'].another.property, 'Something', 'Values are read into the properties object'); - } -}); diff --git a/test/utils/bdd.js b/test/utils/bdd.js new file mode 100644 index 0000000..b77eb8f --- /dev/null +++ b/test/utils/bdd.js @@ -0,0 +1,6 @@ +const propertiesReader = require('../../src/PropertiesReader.js'); +const tempFile = require('./temporary-file'); + +module.exports.givenFilePropertiesReader = function givenFilePropertiesReader (content) { + return propertiesReader(tempFile(content)); +}; diff --git a/test/utils/remove-temp-fs.js b/test/utils/remove-temp-fs.js new file mode 100644 index 0000000..b770c45 --- /dev/null +++ b/test/utils/remove-temp-fs.js @@ -0,0 +1,9 @@ + +const rm = require('rimraf').sync; + +module.exports = function removeTempFs (container) { + container.splice(0, container.length).forEach(file => { + rm(file); + }); + +}; diff --git a/test/utils/temporary-file.js b/test/utils/temporary-file.js new file mode 100644 index 0000000..ac4d244 --- /dev/null +++ b/test/utils/temporary-file.js @@ -0,0 +1,31 @@ + +const FileSystem = require('fs'); +const removeTempFs = require('./remove-temp-fs'); + +module.exports = tempFile; + +tempFile.nextName = 0; + +tempFile.files = []; + +tempFile.dirs = []; + +tempFile.tearDown = function () { + removeTempFs(tempFile.files); + removeTempFs(tempFile.dirs); +}; + +tempFile.pushDir = function (path) { + tempFile.dirs.push(path); + return path; +}; + + +function tempFile (content) { + const filePath = `${ __dirname }/temp_file_${ tempFile.nextName++ }.properties`; + + tempFile.files.push(filePath); + FileSystem.writeFileSync(filePath, content, 'utf-8'); + + return filePath; +} diff --git a/test/writer.spec.js b/test/writer.spec.js new file mode 100644 index 0000000..356515b --- /dev/null +++ b/test/writer.spec.js @@ -0,0 +1,86 @@ +const expect = require('expect.js'); + +describe('writer', () => { + + let properties; + + const tempFile = require('./utils/temporary-file'); + const {givenFilePropertiesReader} = require('./utils/bdd'); + + function givenTheProperties (content) { + return properties = givenFilePropertiesReader(content); + } + + beforeEach(() => { + }); + + afterEach(() => tempFile.tearDown()); + + it('test Able to stringify properties', () => { + givenTheProperties(` + property = Value + `); + + const propertiesStringsArray = properties._stringifyProperties(); + expect(propertiesStringsArray).to.have.length(1); + expect(propertiesStringsArray).to.eql(['property=Value']); + }); + + it('test Able to stringify properties with section', () => { + givenTheProperties(` + [main] + property=Value + `); + + const propertiesStringsArray = properties._stringifyProperties(); + expect(propertiesStringsArray).to.have.length(2); + expect(propertiesStringsArray).to.eql(['[main]', 'property=Value']); + }); + + it( 'test Able to stringify properties with the few sections', () => { + const inputContent = ` + +property1=Value1 + +[main] +property2=Value2 + +[second] +property3=Value3 + +[main] +property4=Value4 + + `; + givenTheProperties(inputContent); + + const propertiesStringsArray = properties._stringifyProperties(); + expect(propertiesStringsArray).to.have.length(7); + expect(propertiesStringsArray).to.eql(inputContent.trim().split('\n').filter(Boolean)); + }); + + it( 'test Able to stringify properties after set', () => { + givenTheProperties('property=Value'); + + properties.set('property', 'xxx'); + + expect(properties._stringifyProperties()).to.eql(['property=xxx']); + }); + + it( 'test Able to stringify properties after set with sections', () => { + givenTheProperties('[main]\nproperty=Value'); + + properties.set('main.property', 'xxx'); + expect(properties._stringifyProperties()).to.eql(['[main]', 'property=xxx']); + }); + + it( 'test Able to stringify properties after set with sections and dots', () => { + givenTheProperties('[main]\nproperty.one=Value'); + + properties.set('main.property.one', 'xxx'); + + expect(properties._stringifyProperties()).to.eql(['[main]', 'property.one=xxx']); + }); + + +}); diff --git a/test/writerTest.js b/test/writerTest.js deleted file mode 100644 index 303a1e6..0000000 --- a/test/writerTest.js +++ /dev/null @@ -1,95 +0,0 @@ - -var Assertions = require('unit-test').Assertions; -var Sinon = require('unit-test').Sinon; -var TestCase = require('unit-test').TestCase; -var FileSystem = require('fs'); -var propertiesReader = require('../src/PropertiesReader.js'); -var properties; - -function tempFile (content) { - tempFile.nextName = (tempFile.nextName || 0) + 1; - tempFile.files.push(__dirname + '/temp_file_' + tempFile.nextName + '.properties'); - FileSystem.writeFileSync(tempFile.files[tempFile.files.length - 1], content, 'utf-8'); -} - -function givenFilePropertiesReader (content) { - tempFile(content); - properties = propertiesReader(tempFile.files[tempFile.files.length - 1]); - return properties; -} - -module.exports = new TestCase("Writer", { - - setUp: function () { - tempFile.files = tempFile.files || []; - tempFile.dirs = tempFile.dirs || []; - }, - - tearDown: function () { - while (tempFile.files && tempFile.files.length) { - var filePath = tempFile.files.pop(); - try { - FileSystem.unlink(filePath); - } - catch (e) { - } - } - while (tempFile.dirs && tempFile.dirs.length) { - var dirPath = tempFile.dirs.pop(); - try { - FileSystem.rmdirSync(dirPath); - } - catch (e) { - } - } - }, - - 'test Able to stringify properties': function () { - var inputContent = 'property=Value'; - givenFilePropertiesReader(inputContent); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals(1, propertiesStringsArray.length, 'Output file has 1 line'); - Assertions.assertEquals(inputContent, propertiesStringsArray[0], 'Input and output content are the same.'); - }, - - 'test Able to stringify properties with section': function () { - var inputContent = '[main]\nproperty=Value'; - givenFilePropertiesReader(inputContent); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals(2, propertiesStringsArray.length, 'Output file has 2 lines'); - Assertions.assertEquals(inputContent, propertiesStringsArray.join('\n'), 'Input and output content are the same.'); - }, - - 'test Able to stringify properties with the few sections': function () { - var inputContent = 'property1=Value1\n[main]\nproperty2=Value2\n[second]\nproperty3=Value3\n[main]\nproperty4=Value4'; - givenFilePropertiesReader(inputContent); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals(7, propertiesStringsArray.length, 'Output file has 7 lines'); - Assertions.assertEquals(inputContent, propertiesStringsArray.join('\n'), 'Input and output content are the same.'); - }, - - 'test Able to stringify properties after set': function () { - var inputContent = 'property=Value'; - givenFilePropertiesReader(inputContent); - properties.set('property', 'xxx'); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals('property=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes.'); - }, - - 'test Able to stringify properties after set with sections': function () { - var inputContent = '[main]\nproperty=Value'; - givenFilePropertiesReader(inputContent); - properties.set('main.property', 'xxx'); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals('[main]\nproperty=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes.'); - }, - - 'test Able to stringify properties after set with sections and dots': function () { - var inputContent = '[main]\nproperty.one=Value'; - givenFilePropertiesReader(inputContent); - properties.set('main.property.one', 'xxx'); - var propertiesStringsArray = properties._stringifyProperties(); - Assertions.assertEquals('[main]\nproperty.one=xxx', propertiesStringsArray.join('\n'), 'Output content inludes changes with key with dot.'); - } - -}); diff --git a/yarn.lock b/yarn.lock index 35402ce..60a958e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,44 +27,425 @@ version "0.7.1" resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + array-from@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" -diff@^3.5.0: +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + +chalk@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + dependencies: + object-keys "^1.0.12" + +diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + +end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +es-abstract@^1.5.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expect.js@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/expect.js/-/expect.js-0.3.1.tgz#b0a59a0d2eff5437544ebf0ceaa6015841d09b5b" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + dependencies: + is-buffer "~2.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + +is-buffer@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + dependencies: + has-symbols "^1.0.0" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + just-extend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + dependencies: + invert-kv "^2.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + lodash@^4.17.11: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + lolex@^4.0.1, lolex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.1.0.tgz#ecdd7b86539391d8237947a3419aa8ac975f0fe1" +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + dependencies: + p-defer "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +mocha@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640" + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" + minimatch "3.0.4" + mkdirp "0.5.1" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.2.2" + yargs-parser "13.0.0" + yargs-unparser "1.5.0" + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + nise@^1.4.10: version "1.5.0" resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.0.tgz#d03ea0e6c1b75c638015aa3585eddc132949a50d" @@ -75,27 +456,151 @@ nise@^1.4.10: lolex "^4.1.0" path-to-regexp "^1.7.0" +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" dependencies: isarray "0.0.1" -q@^1.0.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" -q@~1.0.1: +require-main-filename@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.0.1.tgz#11872aeedee89268110b10a718448ffb10112a14" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -readdir@: - version "0.1.0" - resolved "https://registry.yarnpkg.com/readdir/-/readdir-0.1.0.tgz#1b587f2c629fc93f8c86d5afd42d172293401a12" +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + +rimraf@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + dependencies: + glob "^7.1.3" + +semver@^5.5.0, semver@^5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: - q "~1.0.1" + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -sinon@: +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +sinon@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28" dependencies: @@ -107,7 +612,66 @@ sinon@: nise "^1.4.10" supports-color "^5.5.0" -supports-color@^5.5.0: +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + dependencies: + ansi-regex "^4.1.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" dependencies: @@ -117,10 +681,95 @@ type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" -unit-test@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/unit-test/-/unit-test-0.0.9.tgz#c2c38d22cb4323da809e06d56ec4473a2ada9237" +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + +yargs-parser@13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" + dependencies: + flat "^4.1.0" + lodash "^4.17.11" + yargs "^12.0.5" + +yargs@13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" dependencies: - q "^1.0.1" - readdir "" - sinon "" + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" From 5fc89dec6e677e3ae9d9d4685543987c7aa2ed67 Mon Sep 17 00:00:00 2001 From: Steve King Date: Mon, 17 Jun 2019 08:21:40 +0100 Subject: [PATCH 7/9] Add travis build configuration --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0520b66 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: node_js + +node_js: + - "8" + +install: + - yarn install + +script: + - yarn test + +branches: + only: + - master + From 889902202dfb2a550df7f94f770b1c5e42ab5638 Mon Sep 17 00:00:00 2001 From: Steve King Date: Mon, 17 Jun 2019 08:23:02 +0100 Subject: [PATCH 8/9] Rename all tests to remove the `test ` prefix --- test/bind-to-server.spec.js | 4 ++-- test/reader.spec.js | 32 ++++++++++++++++---------------- test/section.spec.js | 10 +++++----- test/writer.spec.js | 12 ++++++------ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/bind-to-server.spec.js b/test/bind-to-server.spec.js index 29ab934..a67ada0 100644 --- a/test/bind-to-server.spec.js +++ b/test/bind-to-server.spec.js @@ -17,7 +17,7 @@ describe('bind-to-server', () => { afterEach(() => tempFile.tearDown()); - it('test Creates directories when necessary - absolute paths', () => { + it('Creates directories when necessary - absolute paths', () => { const dirPath = tempFile.pushDir('/tmp/' + Math.floor(Math.random() * 1e10).toString(16)); const app = {set: spy()}; @@ -32,7 +32,7 @@ describe('bind-to-server', () => { expect(require('fs').statSync(dirPath).isDirectory()).to.be.ok(); }); - it('test Creates directories when necessary - relative paths', () => { + it('Creates directories when necessary - relative paths', () => { const dirName = Math.floor(Math.random() * 1e10).toString(16); const dirBase = process.cwd(); const dirPath = tempFile.pushDir(dirBase + '/' + dirName); diff --git a/test/reader.spec.js b/test/reader.spec.js index bcb2d33..9c73745 100644 --- a/test/reader.spec.js +++ b/test/reader.spec.js @@ -17,12 +17,12 @@ describe('Reader', () => { afterEach(() => tempFile.tearDown()); - it('test Able to read from a file', () => { + it('Able to read from a file', () => { givenTheProperties('some.property=Value'); expect(properties.get('some.property')).to.be('Value'); }); - it('test Merges multiple files', () => { + it('Merges multiple files', () => { givenTheProperties('some.property=Value'); tempFile('[section]\nsome.property=Another Value'); @@ -32,7 +32,7 @@ describe('Reader', () => { expect(properties.get('some.property')).to.be('Value'); }); - it('test Runs a function across all items in the reader', () => { + it('Runs a function across all items in the reader', () => { givenTheProperties( 'a = 123\n' + 'b = true\n' @@ -51,7 +51,7 @@ describe('Reader', () => { } }); - it('test Attempts type coercion', () => { + it('Attempts type coercion', () => { givenTheProperties( 'a = 123\n' + 'b = true\n' + @@ -63,12 +63,12 @@ describe('Reader', () => { expect(properties.get('d')).to.be(0.1); }); - it('test Correctly handles values that are nothing but whitespace', () => { + it('Correctly handles values that are nothing but whitespace', () => { givenTheProperties('a = \n'); expect(properties.getRaw('a')).to.be(''); }); - it('test Allows access to non-parsed values', () => { + it('Allows access to non-parsed values', () => { givenTheProperties(` a = 123 b = true @@ -81,7 +81,7 @@ describe('Reader', () => { expect(properties.getRaw('d')).to.be('0.1'); }); - it('test Properties are trimmed when parsed', () => { + it('Properties are trimmed when parsed', () => { givenTheProperties(` some.property =Value foo.bar = A Value`); @@ -90,20 +90,20 @@ describe('Reader', () => { expect(properties.get('foo.bar')).to.be('A Value'); }); - it('test Blank lines are ignored', () => { + it('Blank lines are ignored', () => { givenTheProperties('\n\nsome.property=Value\n\nfoo.bar = A Value'); expect(properties.length).to.be(2); }); - it('test Properties can be read back via their dot notation names', () => { + it('Properties can be read back via their dot notation names', () => { givenTheProperties('\n\nsome.property=Value\n\nfoo.bar = A Value'); expect(properties.path().some.property).to.be('Value'); expect(properties.path().foo.bar).to.be('A Value'); }); - it('test Sets properties into an app', () => { + it('Sets properties into an app', () => { const app = {set: spy()}; givenTheProperties(` some.property=Value @@ -114,7 +114,7 @@ describe('Reader', () => { expect(app.set.withArgs('foo.bar', 'A Value').calledOnce).to.be.ok(); }); - it('test Permits escaped new line characters', () => { + it('Permits escaped new line characters', () => { givenTheProperties('\n\nsome.property= Multi\\n Line \\nString \nfoo.bar = A Value'); // parsed access modifies the new line characters @@ -126,7 +126,7 @@ describe('Reader', () => { expect(properties.path().some.property).to.be('Multi\\n Line \\nString'); }); - it('test Returns null when getting a missing property', () => { + it('Returns null when getting a missing property', () => { givenTheProperties('prop = value'); // parsed access modifies the new line characters @@ -134,7 +134,7 @@ describe('Reader', () => { expect(properties.get('missing')).to.be(null); }); - it('test getByRoot when getting a bunch of objects', () => { + it('getByRoot when getting a bunch of objects', () => { givenTheProperties(` root.sect.a = 1 root.sect.b = bar @@ -154,7 +154,7 @@ describe('Reader', () => { ); }); - it('test getByRoot when names are sub strings', () => { + it('getByRoot when names are sub strings', () => { givenTheProperties(` root.sect.a = 1 @@ -170,7 +170,7 @@ describe('Reader', () => { }); }); - it('test getAllProperties returns properties map', () => { + it('getAllProperties returns properties map', () => { givenTheProperties(` root.a.b = Hello @@ -184,7 +184,7 @@ describe('Reader', () => { }); }); - it('test getAllProperties is immutable', () => { + it('getAllProperties is immutable', () => { givenTheProperties(` root.a.b = Hello diff --git a/test/section.spec.js b/test/section.spec.js index b7e1b96..4ca572a 100644 --- a/test/section.spec.js +++ b/test/section.spec.js @@ -16,7 +16,7 @@ describe('section', () => { afterEach(() => tempFile.tearDown()); - it('test Able to read URLs as part of a section', () => { + it('Able to read URLs as part of a section', () => { givenTheProperties(` [foo] base.api.url=http://blah.com @@ -33,7 +33,7 @@ thing = 123 expect(properties.get('another.thing')).to.be(123); }); - it('test Able to read file with sections that are already properties', () => { + it('Able to read file with sections that are already properties', () => { givenTheProperties(` some = thing section = value @@ -47,7 +47,7 @@ thing = 123 expect(properties.path().section).to.eql({'': 'value', 'sub': 'property'}); }); - it('test Ignores comment blocks', () => { + it('Ignores comment blocks', () => { givenTheProperties(` some = thing @@ -60,7 +60,7 @@ thing = 123 expect(properties.get('section')).to.be('another value'); }); - it('test Able to read from a file with sections', () => { + it('Able to read from a file with sections', () => { givenTheProperties(` some.property = Value @@ -77,7 +77,7 @@ thing = 123 expect(properties.path().blah.another.property).to.be('Something Else'); }); - it('test Able use section names with white space', () => { + it('Able use section names with white space', () => { givenTheProperties(` some.property = Value diff --git a/test/writer.spec.js b/test/writer.spec.js index 356515b..f9f003d 100644 --- a/test/writer.spec.js +++ b/test/writer.spec.js @@ -16,7 +16,7 @@ describe('writer', () => { afterEach(() => tempFile.tearDown()); - it('test Able to stringify properties', () => { + it('Able to stringify properties', () => { givenTheProperties(` property = Value `); @@ -26,7 +26,7 @@ describe('writer', () => { expect(propertiesStringsArray).to.eql(['property=Value']); }); - it('test Able to stringify properties with section', () => { + it('Able to stringify properties with section', () => { givenTheProperties(` [main] property=Value @@ -37,7 +37,7 @@ describe('writer', () => { expect(propertiesStringsArray).to.eql(['[main]', 'property=Value']); }); - it( 'test Able to stringify properties with the few sections', () => { + it( 'Able to stringify properties with the few sections', () => { const inputContent = ` property1=Value1 @@ -59,7 +59,7 @@ property4=Value4 expect(propertiesStringsArray).to.eql(inputContent.trim().split('\n').filter(Boolean)); }); - it( 'test Able to stringify properties after set', () => { + it( 'Able to stringify properties after set', () => { givenTheProperties('property=Value'); properties.set('property', 'xxx'); @@ -67,14 +67,14 @@ property4=Value4 expect(properties._stringifyProperties()).to.eql(['property=xxx']); }); - it( 'test Able to stringify properties after set with sections', () => { + it( 'Able to stringify properties after set with sections', () => { givenTheProperties('[main]\nproperty=Value'); properties.set('main.property', 'xxx'); expect(properties._stringifyProperties()).to.eql(['[main]', 'property=xxx']); }); - it( 'test Able to stringify properties after set with sections and dots', () => { + it( 'Able to stringify properties after set with sections and dots', () => { givenTheProperties('[main]\nproperty.one=Value'); properties.set('main.property.one', 'xxx'); From 0fa721648e6caebd1296c99b147e686f93126bbf Mon Sep 17 00:00:00 2001 From: Steve King Date: Mon, 17 Jun 2019 09:13:48 +0100 Subject: [PATCH 9/9] Change writer tests so they only refer to the actually saved properties --- .editorconfig | 14 + package.json | 4 + src/PropertiesReader.js | 644 ++++++++++++++++++----------------- test/utils/remove-temp-fs.js | 1 + test/utils/temporary-file.js | 30 +- test/writer.spec.js | 52 +-- yarn.lock | 4 + 7 files changed, 415 insertions(+), 334 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e8cb6a2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 3 +trim_trailing_whitespace = true + +[*.json] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/package.json b/package.json index bb1cccb..d117504 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "mkdirp": "~0.5.1" }, "devDependencies": { + "@kwsites/file-exists": "^1.0.0", "expect.js": "^0.3.1", "mocha": "^6.1.4", "rimraf": "^2.6.3", @@ -41,5 +42,8 @@ "scripts": { "test": "mocha ./test/*.spec.js" }, + "engines": { + "node": ">=6" + }, "license": "MIT" } diff --git a/src/PropertiesReader.js b/src/PropertiesReader.js index 99fff55..1c58c25 100644 --- a/src/PropertiesReader.js +++ b/src/PropertiesReader.js @@ -1,313 +1,335 @@ -(function() { - - "use strict"; - - var fs = require('fs'); - - /** - * - * @param {String} sourceFile - * @constructor - * @name {PropertiesReader} - */ - function PropertiesReader(sourceFile) { - this._properties = {}; - this._propertiesExpanded = {}; - this.append(sourceFile); - } - - /** - * @type {String} The name of a section that should be prefixed on an property as it is added - * @ignore - */ - PropertiesReader.prototype._section = ''; - - /** - * Gets the number of properties that have been read into this PropertiesReader. - * - * @name PropertiesReader#length - * @type {Number} - */ - Object.defineProperty(PropertiesReader.prototype, 'length', { - configurable: false, - enumerable: false, - get: function() { - return Object.keys(this._properties).length; - }, - set: function() { - throw new Error("Cannot set length of PropertiesReader properties"); - } - }); - - /** - * Append a file to the properties into the PropertiesReader - * @param {string} sourceFile - * @return {PropertiesReader} this instance - */ - PropertiesReader.prototype.append = function (sourceFile) { - if (sourceFile) { - this.read(fs.readFileSync(sourceFile, 'utf-8')); - } - return this; - }; - - /** - * Reads any string input into the PropertiesReader - * - * @param {String} input - * @return {PropertiesReader} this instance - */ - PropertiesReader.prototype.read = function(input) { - delete this._section; - ('' + input).split('\n').forEach(this._readLine, this); - return this; - }; - - /** - * Used as a processor for the array of input lines when reading from a source file - * @param {String} propertyString - */ - PropertiesReader.prototype._readLine = function(propertyString) { - if (!!(propertyString = propertyString.trim())) { - var section = /^\[([^=]+)\]$/.exec(propertyString); - var property = !section && /^([^#=]+)(={0,1})(.*)$/.exec(propertyString); - - if (section) { - this._section = section[1]; +"use strict"; + +var fs = require('fs'); + +/** + * + * @param {String} sourceFile + * @constructor + * @name {PropertiesReader} + */ +function PropertiesReader (sourceFile) { + this._properties = {}; + this._propertiesExpanded = {}; + this.append(sourceFile); +} + +/** + * @type {String} The name of a section that should be prefixed on an property as it is added + * @ignore + */ +PropertiesReader.prototype._section = ''; + +/** + * Gets the number of properties that have been read into this PropertiesReader. + * + * @name PropertiesReader#length + * @type {Number} + */ +Object.defineProperty(PropertiesReader.prototype, 'length', { + configurable: false, + enumerable: false, + get: function () { + return Object.keys(this._properties).length; + }, + set: function () { + throw new Error("Cannot set length of PropertiesReader properties"); + } +}); + +/** + * Append a file to the properties into the PropertiesReader + * @param {string} sourceFile + * @return {PropertiesReader} this instance + */ +PropertiesReader.prototype.append = function (sourceFile) { + if (sourceFile) { + this.read(fs.readFileSync(sourceFile, 'utf-8')); + } + return this; +}; + +/** + * Reads any string input into the PropertiesReader + * + * @param {String} input + * @return {PropertiesReader} this instance + */ +PropertiesReader.prototype.read = function (input) { + delete this._section; + ('' + input).split('\n').forEach(this._readLine, this); + return this; +}; + +/** + * Used as a processor for the array of input lines when reading from a source file + * @param {String} propertyString + */ +PropertiesReader.prototype._readLine = function (propertyString) { + if (!!(propertyString = propertyString.trim())) { + var section = /^\[([^=]+)]$/.exec(propertyString); + var property = !section && /^([^#=]+)(={0,1})(.*)$/.exec(propertyString); + + if (section) { + this._section = section[1]; + } + else if (property) { + section = this._section ? this._section + '.' : ''; + this.set(section + property[1].trim(), property[3].trim()); + } + } +}; + +/** + * Calls the supplied function for each property + * + * @param {Function} fn + * @param {Object} scope + * @return {PropertiesReader} + */ +PropertiesReader.prototype.each = function (fn, scope) { + for (var key in this._properties) { + if (this._properties.hasOwnProperty(key)) { + fn.call(scope || this, key, this._properties[key]); + } + } + return this; +}; + +/** + * Given the supplied raw value, returns the parsed value + */ +PropertiesReader.prototype._parsed = function (value) { + var parsedValue = value; + if (value !== null && value !== '' && !isNaN(value)) { + parsedValue = +value; + } + else if (value === 'true' || value === 'false') { + parsedValue = (value === 'true'); + } + else if (typeof value === "string") { + var replacements = {'\\n': '\n', '\\r': '\r', '\\t': '\t'}; + parsedValue = value.replace(/\\[nrt]/g, function (key) { + return replacements[key]; + }); + } + + return parsedValue; +}; + +/** + * Gets a single property value based on the full string key. When the property is not found in the + * PropertiesReader, the return value will be null. + * + * @param {String} key + * @return {*} + */ +PropertiesReader.prototype.get = function (key) { + return this._parsed(this.getRaw(key)); +}; + +/** + * Gets the string representation as it was read from the properties file without coercions for type recognition. + * + * @param {string} key + * @returns {string} + */ +PropertiesReader.prototype.getRaw = function (key) { + return this._properties.hasOwnProperty(key) ? this._properties[key] : null; +}; + +/** + * Sets the supplied key in the properties store with the supplied value, the value can be any string representation + * that would be valid in a properties file (eg: true and false or numbers are converted to their real values). + * + * @param {String} key + * @param {String} value + * @return {PropertiesReader} + */ +PropertiesReader.prototype.set = function (key, value) { + var parsedValue = ('' + value).trim(); + + this._properties[key] = parsedValue; + + var expanded = key.split('.'); + var source = this._propertiesExpanded; + + while (expanded.length > 1) { + var step = expanded.shift(); + if (expanded.length >= 1 && typeof source[step] === 'string') { + source[step] = {'': source[step]}; + } + source = (source[step] = source[step] || {}); + } + + if (typeof parsedValue === 'string' && typeof source[expanded[0]] === 'object') { + source[expanded[0]][''] = parsedValue; + } + else { + source[expanded[0]] = parsedValue; + } + + return this; +}; + +/** + * Gets the object that represents the exploded properties. + * + * Note that this object is currently mutable without the option to persist or interrogate changes. + * + * @return {*} + */ +PropertiesReader.prototype.path = function () { + return this._propertiesExpanded; +}; + +/** + * Gets the object that represents all properties. + * + * @returns {Object} + */ +PropertiesReader.prototype.getAllProperties = function () { + var properties = {}; + this.each(function (key, value) { + properties[key] = value; + }); + return properties; +}; + +/** + * Creates and returns a new PropertiesReader based on the values in this instance. + * @return {PropertiesReader} + */ +PropertiesReader.prototype.clone = function () { + var propertiesReader = new PropertiesReader(null); + this.each(propertiesReader.set, propertiesReader); + + return propertiesReader; +}; + +/** + * Return a json from a root properties + * @param root + * @returns {{}} + */ +PropertiesReader.prototype.getByRoot = function (root) { + var keys = Object.keys(this._properties); + var outObj = {}; + + for (var i = 0, prefixLength = String(root).length; i < keys.length; i++) { + var key = keys[i]; + + if (key.indexOf(root) === 0 && key.charAt(prefixLength) === '.') { + outObj[key.substr(prefixLength + 1)] = this.get(key); + } + } + + return outObj; +}; + +/** + * Binds the current properties object and all values in it to the supplied express app. + * + * @param {Object} app The express app (or any object that has a `set` function) + * @param {String} [basePath] The absolute prefix to use for all path properties - defaults to the cwd. + * @param {Boolean} [makePaths=false] When true will attempt to create the directory structure to any path property + */ +PropertiesReader.prototype.bindToExpress = function (app, basePath, makePaths) { + var Path = require('path'); + + if (!/\/$/.test(basePath = basePath || process.cwd())) { + basePath += '/'; + } + + this.each(function (key, value) { + if (value && /\.(path|dir)$/.test(key)) { + value = Path.join(basePath, Path.relative(basePath, value)); + this.set(key, value); + + try { + var directoryPath = /dir$/.test(key) ? value : Path.dirname(value); + if (makePaths) { + require('mkdirp').sync(directoryPath); } - else if (property) { - section = this._section ? this._section + '.' : ''; - this.set(section + property[1].trim(), property[3].trim()); + else if (!fs.statSync(directoryPath).isDirectory()) { + throw new Error("Path is not a directory that already exists"); } - } - }; - - /** - * Calls the supplied function for each property - * - * @param {Function} fn - * @param {Object} scope - * @return {PropertiesReader} - */ - PropertiesReader.prototype.each = function(fn, scope) { - for (var key in this._properties) { - if (this._properties.hasOwnProperty(key)) { - fn.call(scope || this, key, this._properties[key]); - } - } - return this; - }; - - /** - * Given the supplied raw value, returns the parsed value - */ - PropertiesReader.prototype._parsed = function(value) { - var parsedValue = value; - if (value !== null && value !== '' && !isNaN(value)) { - parsedValue = +value; - } - else if (value === 'true' || value === 'false') { - parsedValue = (value === 'true'); - } - else if (typeof value === "string") { - var replacements = {'\\n': '\n', '\\r': '\r', '\\t': '\t'}; - parsedValue = value.replace(/\\[nrt]/g, function (key) { - return replacements[key]; - }); - } - - return parsedValue; - }; - - /** - * Gets a single property value based on the full string key. When the property is not found in the - * PropertiesReader, the return value will be null. - * - * @param {String} key - * @return {*} - */ - PropertiesReader.prototype.get = function(key) { - return this._parsed(this.getRaw(key)); - }; - - /** - * Gets the string representation as it was read from the properties file without coercions for type recognition. - * - * @param {string} key - * @returns {string} - */ - PropertiesReader.prototype.getRaw = function(key) { - return this._properties.hasOwnProperty(key) ? this._properties[key] : null; - }; - - /** - * Sets the supplied key in the properties store with the supplied value, the value can be any string representation - * that would be valid in a properties file (eg: true and false or numbers are converted to their real values). - * - * @param {String} key - * @param {String} value - * @return {PropertiesReader} - */ - PropertiesReader.prototype.set = function(key, value) { - var parsedValue = ('' + value).trim(); - - this._properties[key] = parsedValue; - - var expanded = key.split('.'); - var source = this._propertiesExpanded; - while (expanded.length > 1) { - var step = expanded.shift(); - if (expanded.length >= 1 && typeof source[step] === 'string') { - source[step] = {'':source[step]}; - } - source = (source[step] = source[step] || {}); - } - if (typeof parsedValue === 'string' && typeof source[expanded[0]] === 'object') { - source[expanded[0]][''] = parsedValue; - } - else { - source[expanded[0]] = parsedValue; - } - - return this; - }; - - /** - * Gets the object that represents the exploded properties. - * - * Note that this object is currently mutable without the option to persist or interrogate changes. - * - * @return {*} - */ - PropertiesReader.prototype.path = function() { - return this._propertiesExpanded; - }; - - /** - * Gets the object that represents all properties. - * - * @returns {Object} - */ - PropertiesReader.prototype.getAllProperties = function() { - var properties = {}; - this.each(function (key, value) { - properties[key] = value; - }); - return properties; - }; - - /** - * Creates and returns a new PropertiesReader based on the values in this instance. - * @return {PropertiesReader} - */ - PropertiesReader.prototype.clone = function() { - var propertiesReader = new PropertiesReader(null); - this.each(propertiesReader.set, propertiesReader); - - return propertiesReader; - }; - - /** - * Return a json from a root properties - * @param root - * @returns {{}} - */ - PropertiesReader.prototype.getByRoot = function(root){ - var keys = Object.keys(this._properties); - var outObj = {}; - - for (var i = 0, prefixLength = String(root).length; i < keys.length; i++) { - var key = keys[i]; - - if (key.indexOf(root) === 0 && key.charAt(prefixLength) === '.') { - outObj[key.substr(prefixLength + 1)] = this.get(key); - } - } - - return outObj; - }; - - /** - * Binds the current properties object and all values in it to the supplied express app. - * - * @param {Object} app The express app (or any object that has a `set` function) - * @param {String} [basePath] The absolute prefix to use for all path properties - defaults to the cwd. - * @param {Boolean} [makePaths=false] When true will attempt to create the directory structure to any path property - */ - PropertiesReader.prototype.bindToExpress = function(app, basePath, makePaths) { - var Path = require('path'); - - if (!/\/$/.test(basePath = basePath || process.cwd())) { - basePath += '/'; - } - - this.each(function (key, value) { - if (value && /\.(path|dir)$/.test(key)) { - value = Path.join(basePath, Path.relative(basePath, value)); - this.set(key, value); - - try { - var directoryPath = /dir$/.test(key) ? value : Path.dirname(value); - if (makePaths) { - require('mkdirp').sync(directoryPath); - } - else if (!fs.statSync(directoryPath).isDirectory()) { - throw new Error("Path is not a directory that already exists"); - } - } - catch (e) { - throw new Error("Unable to create directory " + value); - } - } - - app.set(key, this.get(key)); - - if(/^browser\./.test(key)) { - app.locals[key.substr(8)] = this.get(key); - } - }, this); - - app.set('properties', this); - - return this; - }; - - /** - * Stringify properties - * @returns {array} array of stringified properties - */ - PropertiesReader.prototype._stringifyProperties = function() { - var lines = []; - var section = null; - this.each(function (key, value) { - var tokens = key.split('.'); - if (tokens.length > 1) { - if (section !== tokens[0]) { - section = tokens[0]; - lines.push('[' + section + ']'); - } - key = tokens.slice(1).join('.'); - } else { - section = null; - } - lines.push(key + '=' + value); - }); - return lines; - }; - - /** - * Write properties into the file - * - * @param {String} destFile - * @param {function} error callback - */ - PropertiesReader.prototype.save = function(destFile, fail) { - fs.writeFile(destFile, this._stringifyProperties().join('\n'), fail); - }; - - PropertiesReader.builder = function(sourceFile) { - return new PropertiesReader(sourceFile); - }; - - module.exports = PropertiesReader.builder; -}()); + } + catch (e) { + throw new Error("Unable to create directory " + value); + } + } + + app.set(key, this.get(key)); + + if (/^browser\./.test(key)) { + app.locals[key.substr(8)] = this.get(key); + } + }, this); + + app.set('properties', this); + + return this; +}; + +/** + * Stringify properties + * + * @returns {string[]} array of stringified properties + */ +PropertiesReader.prototype._stringifyProperties = function () { + var lines = []; + var section = null; + this.each(function (key, value) { + var tokens = key.split('.'); + if (tokens.length > 1) { + if (section !== tokens[0]) { + section = tokens[0]; + lines.push('[' + section + ']'); + } + key = tokens.slice(1).join('.'); + } + else { + section = null; + } + + lines.push(key + '=' + value); + }); + return lines; +}; + +/** + * Write properties into the file + * + * @param {String} destFile + * @param {function} onComplete callback + */ +PropertiesReader.prototype.save = function (destFile, onComplete) { + var content = this._stringifyProperties().join('\n'); + var onDone = new Promise((done, fail) => { + fs.writeFile(destFile, content, (err) => { + if (err) { + return fail(err); + } + + done(content); + }); + }); + + if (typeof onComplete === 'function') { + if (onComplete.length > 1) { + onDone.then(onComplete.bind(null, null), onComplete.bind(null)); + } + else { + onDone.then(onComplete) + } + } + + return onDone; +}; + +PropertiesReader.builder = function (sourceFile) { + return new PropertiesReader(sourceFile); +}; + +module.exports = PropertiesReader.builder; diff --git a/test/utils/remove-temp-fs.js b/test/utils/remove-temp-fs.js index b770c45..68c1959 100644 --- a/test/utils/remove-temp-fs.js +++ b/test/utils/remove-temp-fs.js @@ -2,6 +2,7 @@ const rm = require('rimraf').sync; module.exports = function removeTempFs (container) { + container.splice(0, container.length).forEach(file => { rm(file); }); diff --git a/test/utils/temporary-file.js b/test/utils/temporary-file.js index ac4d244..c952530 100644 --- a/test/utils/temporary-file.js +++ b/test/utils/temporary-file.js @@ -1,5 +1,6 @@ const FileSystem = require('fs'); +const {exists} = require('@kwsites/file-exists'); const removeTempFs = require('./remove-temp-fs'); module.exports = tempFile; @@ -20,11 +21,36 @@ tempFile.pushDir = function (path) { return path; }; +/** + * Add a single-file path to be monitored for removal by the `tempFile`. Note that monitored files + * must be removed by including the `tempfile.tearDown()` call in the test `afterEach` + */ +tempFile.pushFile = function (filePath) { + if (!filePath) { + filePath = `${ __dirname }/temp_file_${ tempFile.nextName++ }.properties`; + } + + tempFile.files.push(filePath); + return filePath; +}; + +/** + * Reads a single-file into an array, excluding any blank lines. Requires that the file is + * already monitored for removal by the `tempFile`. + */ +tempFile.readFile = function (filePath) { + if (!tempFile.files.includes(filePath) || ! exists(filePath)) { + return []; + } + + return FileSystem.readFileSync(filePath, 'utf-8') + .split('\n') + .filter(line => !!line.trim()); +}; function tempFile (content) { - const filePath = `${ __dirname }/temp_file_${ tempFile.nextName++ }.properties`; + const filePath = tempFile.pushFile(); - tempFile.files.push(filePath); FileSystem.writeFileSync(filePath, content, 'utf-8'); return filePath; diff --git a/test/writer.spec.js b/test/writer.spec.js index f9f003d..70349db 100644 --- a/test/writer.spec.js +++ b/test/writer.spec.js @@ -3,6 +3,7 @@ const expect = require('expect.js'); describe('writer', () => { let properties; + let theSavedProperties; const tempFile = require('./utils/temporary-file'); const {givenFilePropertiesReader} = require('./utils/bdd'); @@ -11,33 +12,39 @@ describe('writer', () => { return properties = givenFilePropertiesReader(content); } - beforeEach(() => { - }); + async function givenThePropertiesAreSaved () { + const filePath = tempFile.pushFile(); + await properties.save(filePath); + return theSavedProperties = tempFile.readFile(filePath); + } - afterEach(() => tempFile.tearDown()); + afterEach(() => { + tempFile.tearDown(); + properties = theSavedProperties = undefined; + }); - it('Able to stringify properties', () => { + it('Able to stringify properties', async () => { givenTheProperties(` property = Value `); - const propertiesStringsArray = properties._stringifyProperties(); - expect(propertiesStringsArray).to.have.length(1); - expect(propertiesStringsArray).to.eql(['property=Value']); + await givenThePropertiesAreSaved(); + expect(theSavedProperties).to.have.length(1); + expect(theSavedProperties).to.eql(['property=Value']); }); - it('Able to stringify properties with section', () => { + it('Able to stringify properties with section', async () => { givenTheProperties(` [main] property=Value `); - const propertiesStringsArray = properties._stringifyProperties(); - expect(propertiesStringsArray).to.have.length(2); - expect(propertiesStringsArray).to.eql(['[main]', 'property=Value']); + await givenThePropertiesAreSaved(); + expect(theSavedProperties).to.have.length(2); + expect(theSavedProperties).to.eql(['[main]', 'property=Value']); }); - it( 'Able to stringify properties with the few sections', () => { + it('Able to stringify properties with the few sections', async () => { const inputContent = ` property1=Value1 @@ -54,32 +61,35 @@ property4=Value4 `; givenTheProperties(inputContent); - const propertiesStringsArray = properties._stringifyProperties(); - expect(propertiesStringsArray).to.have.length(7); - expect(propertiesStringsArray).to.eql(inputContent.trim().split('\n').filter(Boolean)); + await givenThePropertiesAreSaved(); + expect(theSavedProperties).to.have.length(7); + expect(theSavedProperties).to.eql(inputContent.trim().split('\n').filter(Boolean)); }); - it( 'Able to stringify properties after set', () => { + it('Able to stringify properties after set', async () => { givenTheProperties('property=Value'); properties.set('property', 'xxx'); + await givenThePropertiesAreSaved(); - expect(properties._stringifyProperties()).to.eql(['property=xxx']); + expect(theSavedProperties).to.eql(['property=xxx']); }); - it( 'Able to stringify properties after set with sections', () => { + it('Able to stringify properties after set with sections', async () => { givenTheProperties('[main]\nproperty=Value'); properties.set('main.property', 'xxx'); - expect(properties._stringifyProperties()).to.eql(['[main]', 'property=xxx']); + await givenThePropertiesAreSaved(); + expect(theSavedProperties).to.eql(['[main]', 'property=xxx']); }); - it( 'Able to stringify properties after set with sections and dots', () => { + it('Able to stringify properties after set with sections and dots', async () => { givenTheProperties('[main]\nproperty.one=Value'); properties.set('main.property.one', 'xxx'); + await givenThePropertiesAreSaved(); - expect(properties._stringifyProperties()).to.eql(['[main]', 'property.one=xxx']); + expect(theSavedProperties).to.eql(['[main]', 'property.one=xxx']); }); diff --git a/yarn.lock b/yarn.lock index 60a958e..cd3fb9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"@kwsites/file-exists@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.0.0.tgz#4bd9b8476ab98383845608535c1869a6fed64469" + "@sinonjs/commons@^1", "@sinonjs/commons@^1.0.2", "@sinonjs/commons@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.4.0.tgz#7b3ec2d96af481d7a0321252e7b1c94724ec5a78"