From 7dd714c957e1ce63fbef695ca344fc18ad35df26 Mon Sep 17 00:00:00 2001 From: Romain Date: Sat, 16 Jun 2018 18:26:17 +0200 Subject: [PATCH] refactor(tests): dynamically generate test folders to check more edge cases --- fixtures/holidays/tower.jpg | Bin 8618 -> 0 bytes fixtures/home/desk.jpg | Bin 8832 -> 0 bytes fixtures/home/fruit.jpg | Bin 9725 -> 0 bytes src/website/website.js | 1 - {fixtures => test-fixtures}/bad-encoding.xmp | 0 .../beach.jpg => test-fixtures/photo.jpg | Bin test-fixtures/video.mp4 | Bin 0 -> 28324 bytes test/components/exiftool/integration.spec.js | 32 ++++--- test/components/index/index.spec.js | 85 +++++++++++++++--- test/fixtures.js | 18 ++++ test/input/picasa.spec.js | 9 +- test/log.js | 2 +- test/themes/theme.spec.js | 18 +--- 13 files changed, 120 insertions(+), 45 deletions(-) delete mode 100644 fixtures/holidays/tower.jpg delete mode 100644 fixtures/home/desk.jpg delete mode 100644 fixtures/home/fruit.jpg rename {fixtures => test-fixtures}/bad-encoding.xmp (100%) rename fixtures/holidays/beach.jpg => test-fixtures/photo.jpg (100%) create mode 100644 test-fixtures/video.mp4 diff --git a/fixtures/holidays/tower.jpg b/fixtures/holidays/tower.jpg deleted file mode 100644 index 9fcfa3cdf0e91b60b19f1631cdb0285bc751d83a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8618 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 diff --git a/fixtures/home/desk.jpg b/fixtures/home/desk.jpg deleted file mode 100644 index 1674918e85d3397cf63dd09a79938f09b1dbf042..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8832 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 literal 0 HcmV?d00001 diff --git a/test/components/exiftool/integration.spec.js b/test/components/exiftool/integration.spec.js index f55e774..e414ce2 100644 --- a/test/components/exiftool/integration.spec.js +++ b/test/components/exiftool/integration.spec.js @@ -1,35 +1,39 @@ -const exiftool = require('../../../src/components/exiftool/parallel') const path = require('path') -const readdir = require('readdir-enhanced') const should = require('should/as-function') - -// Find all test photos -const folder = path.join(__dirname, '..', '..', '..', 'fixtures') -const files = readdir.sync(folder, { - filter: stats => stats.isFile() && path.extname(stats.path) === '.jpg', - deep: true -}) +const fixtures = require('../../fixtures') +const exiftool = require('../../../src/components/exiftool/parallel') describe('exiftool', function () { this.slow(1000) this.timeout(1000) + it('processes all files', (done) => { + // generate some photos in a temp folder + const image = fixtures.fromDisk('photo.jpg') + const structure = {} + for (let i = 0; i < 10; ++i) { + structure[`IMG_00${i}.jpg`] = image + } + const tmpdir = fixtures.createTempStructure(structure) + // process them in batch const processed = [] - const stream = exiftool.parse(folder, files) + const stream = exiftool.parse(tmpdir, Object.keys(structure)) stream.on('data', entry => { + // should be the deserialized JSON output from exiftool processed.push(entry.SourceFile) }).on('end', () => { - files.sort() - processed.sort() - should(processed).eql(files) + const expected = Object.keys(structure).sort() + should(processed.sort()).eql(expected) done() }) }) + it('can process badly encoded fields', (done) => { // here we test with an XMP file because it's easier to see what's wrong // but the problem will more likely be with a badly encoded XMP section inside a JPG file // note: use to edit if required, to avoid converting it to UTF - const stream = exiftool.parse(folder, ['bad-encoding.xmp']) + const testFixtures = path.join(__dirname, '..', '..', '..', 'test-fixtures') + const stream = exiftool.parse(testFixtures, ['bad-encoding.xmp']) const processed = [] stream.on('data', entry => { processed.push(entry.SourceFile) diff --git a/test/components/index/index.spec.js b/test/components/index/index.spec.js index 362f510..11fda91 100644 --- a/test/components/index/index.spec.js +++ b/test/components/index/index.spec.js @@ -1,28 +1,44 @@ -const Index = require('../../../src/components/index/index') -const fs = require('fs-extra') +const fs = require('fs') const path = require('path') const should = require('should/as-function') +const Index = require('../../../src/components/index/index') +const fixtures = require('../../fixtures') describe('Index', function () { this.slow(1000) this.timeout(1000) - it('indexes the fixtures', (done) => { - fs.removeSync('thumbsup.db') - const index = new Index('thumbsup.db') - const fixtures = path.join(__dirname, '..', '..', '..', 'fixtures') - const emitter = index.update(fixtures) + var tmpdir = null + + before(() => { + const image = fixtures.fromDisk('photo.jpg') + tmpdir = fixtures.createTempStructure({ + 'input/london/IMG_0001.jpg': image, + 'input/newyork/IMG_0002.jpg': image + }) + }) + + it('indexes a folder', (done) => { + const index = new Index(path.join(tmpdir, 'thumbsup.db')) + const emitter = index.update(path.join(tmpdir, 'input')) const emitted = [] + var processed = 0 + var stats = null + emitter.on('progress', () => ++processed) emitter.on('file', meta => emitted.push(meta)) - emitter.on('done', () => { + emitter.on('stats', s => { stats = s }) + emitter.on('done', result => { + // check stats + should(result.count).eql(2) + should(stats).eql({unchanged: 0, added: 2, modified: 0, deleted: 0, total: 2}) // check all files were indexed const paths = emitted.map(e => e.path).sort() should(paths).eql([ - 'holidays/beach.jpg', - 'holidays/tower.jpg', - 'home/desk.jpg', - 'home/fruit.jpg' + 'london/IMG_0001.jpg', + 'newyork/IMG_0002.jpg' ]) + // check all files were sent to exiftool + should(processed).eql(2) // check the path matches the SourceFile property const sourceFiles = emitted.map(e => e.metadata.SourceFile).sort() should(paths).eql(sourceFiles) @@ -30,8 +46,49 @@ describe('Index', function () { }) }) - it('vacuums the database', () => { - const index = new Index('thumbsup.db') + it('can re-index with no changes', (done) => { + const index = new Index(path.join(tmpdir, 'thumbsup.db')) + const emitter = index.update(path.join(tmpdir, 'input')) + var emitted = 0 + var processed = 0 + var stats = null + emitter.on('progress', () => ++processed) + emitter.on('file', () => ++emitted) + emitter.on('stats', s => { stats = s }) + emitter.on('done', result => { + // check stats + should(result.count).eql(2) + should(stats).eql({unchanged: 2, added: 0, modified: 0, deleted: 0, total: 2}) + // all files are emitted, but they were not processed again + should(emitted).eql(2) + should(processed).eql(0) + done() + }) + }) + + it('can un-index a deleted file', (done) => { + fs.unlinkSync(path.join(tmpdir, 'input/newyork/IMG_0002.jpg')) + const index = new Index(path.join(tmpdir, 'thumbsup.db')) + const emitter = index.update(path.join(tmpdir, 'input')) + var emitted = 0 + var processed = 0 + var stats = null + emitter.on('progress', () => ++processed) + emitter.on('file', () => ++emitted) + emitter.on('stats', s => { stats = s }) + emitter.on('done', result => { + // check stats + should(result.count).eql(1) + should(stats).eql({unchanged: 1, added: 0, modified: 0, deleted: 1, total: 1}) + // the remaining file was emitted + should(emitted).eql(1) + should(processed).eql(0) + done() + }) + }) + + it('can vacuum the database', () => { + const index = new Index(path.join(tmpdir, 'thumbsup.db')) index.vacuum() }) }) diff --git a/test/fixtures.js b/test/fixtures.js index 4a73cef..2038adb 100644 --- a/test/fixtures.js +++ b/test/fixtures.js @@ -1,4 +1,8 @@ +const _ = require('lodash') +const fs = require('fs-extra') const moment = require('moment') +const path = require('path') +const tmp = require('tmp') const File = require('../src/model/file') const Metadata = require('../src/model/metadata') @@ -46,3 +50,17 @@ exports.video = function (opts) { opts.mimeType = 'video/mp4' return exports.file(opts) } + +exports.fromDisk = function (filename) { + const filepath = path.join(__dirname, '..', 'test-fixtures', filename) + return fs.readFileSync(filepath) +} + +exports.createTempStructure = function (files) { + const tmpdir = tmp.dirSync({unsafeCleanup: true}).name + _.each(files, (content, filepath) => { + fs.ensureFileSync(`${tmpdir}/${filepath}`) + fs.writeFileSync(`${tmpdir}/${filepath}`, content) + }) + return tmpdir +} diff --git a/test/input/picasa.spec.js b/test/input/picasa.spec.js index c3ee822..1055370 100644 --- a/test/input/picasa.spec.js +++ b/test/input/picasa.spec.js @@ -1,5 +1,4 @@ const should = require('should/as-function') -const mock = require('mock-fs') const Picasa = require('../../src/input/picasa.js') const PICASA_INI = ` @@ -13,9 +12,17 @@ keywords=beach,sunset ` describe('Picasa', function () { + // we require "mock-fs" inside the tests, otherwise it also affects other tests + var mock = null + + beforeEach(function () { + mock = require('mock-fs') + }) + afterEach(function () { mock.restore() }) + it('reads album metadata', function () { mock({ 'holidays/picasa.ini': PICASA_INI diff --git a/test/log.js b/test/log.js index ca14573..b6d0fb1 100644 --- a/test/log.js +++ b/test/log.js @@ -34,6 +34,6 @@ debug.assertNotContains = function (expected) { return message.includes(expected) }) if (matches.length > 0) { - throw new Error(`Expected log not to contain: ${expected}`) + throw new Error(`Expected log not to contain: ${expected}, but contained at least: ${matches[0]}`) } } diff --git a/test/themes/theme.spec.js b/test/themes/theme.spec.js index 1b51e3a..8e5ef1c 100644 --- a/test/themes/theme.spec.js +++ b/test/themes/theme.spec.js @@ -1,7 +1,6 @@ -const _ = require('lodash') const fs = require('fs-extra') const should = require('should/as-function') -const tmp = require('tmp') +const fixtures = require('../fixtures') const Theme = require('../../src/website/theme') describe('Theme', () => { @@ -125,7 +124,7 @@ describe('Theme', () => { it('loads all helpers', testEnd => { // because helpers use require(...) we cannot use a mock filesystem - const tmpdir = createTempStructure({ + const tmpdir = fixtures.createTempStructure({ 'theme/theme.less': '', 'theme/album.hbs': 'Partial says {{hello "world"}}', 'theme/helpers/hello.js': 'module.exports = args => "hello " + args' @@ -141,7 +140,7 @@ describe('Theme', () => { it('loads require() statements relative to the theme folder', testEnd => { // because helpers use require(...) we cannot use a mock filesystem - const tmpdir = createTempStructure({ + const tmpdir = fixtures.createTempStructure({ 'theme/theme.less': '', 'theme/album.hbs': 'Partial says {{hello "world"}}', 'theme/node_modules/foo/package.json': '{"name": "foo", "main": "index.js"}', @@ -162,7 +161,7 @@ describe('Theme', () => { it('copies public files', testEnd => { // fs.copy() doesn't seem compatible with mock-fs either - const tmpdir = createTempStructure({ + const tmpdir = fixtures.createTempStructure({ 'theme/theme.less': '', 'theme/album.hbs': '', 'theme/public/logo.jpg': 'LOGO' @@ -177,15 +176,6 @@ describe('Theme', () => { }) }) -function createTempStructure (files) { - const tmpdir = tmp.dirSync({unsafeCleanup: true}).name - _.each(files, (content, filepath) => { - fs.ensureFileSync(`${tmpdir}/${filepath}`) - fs.writeFileSync(`${tmpdir}/${filepath}`, content) - }) - return tmpdir -} - function renderTheme (theme, album, next) { theme.validateStructure() theme.prepare(err => {