diff --git a/fixtures/holidays/tower.jpg b/fixtures/holidays/tower.jpg deleted file mode 100644 index 9fcfa3c..0000000 Binary files a/fixtures/holidays/tower.jpg and /dev/null differ diff --git a/fixtures/home/desk.jpg b/fixtures/home/desk.jpg deleted file mode 100644 index 1674918..0000000 Binary files a/fixtures/home/desk.jpg and /dev/null differ diff --git a/fixtures/home/fruit.jpg b/fixtures/home/fruit.jpg deleted file mode 100644 index 0b956e9..0000000 Binary files a/fixtures/home/fruit.jpg and /dev/null differ diff --git a/src/website/website.js b/src/website/website.js index 069fdeb..9760e7b 100644 --- a/src/website/website.js +++ b/src/website/website.js @@ -34,7 +34,6 @@ exports.build = function (rootAlbum, opts, callback) { function galleryModel (rootAlbum, opts) { return { home: rootAlbum, - css: opts.css ? path.basename(opts.css) : null, title: opts.title, footer: opts.footer, thumbSize: opts.thumbSize, diff --git a/fixtures/bad-encoding.xmp b/test-fixtures/bad-encoding.xmp similarity index 100% rename from fixtures/bad-encoding.xmp rename to test-fixtures/bad-encoding.xmp diff --git a/fixtures/holidays/beach.jpg b/test-fixtures/photo.jpg similarity index 100% rename from fixtures/holidays/beach.jpg rename to test-fixtures/photo.jpg diff --git a/test-fixtures/video.mp4 b/test-fixtures/video.mp4 new file mode 100644 index 0000000..f9fce2d Binary files /dev/null and b/test-fixtures/video.mp4 differ 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 => {