summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-01-28 18:39:44 +0100
committerSamy Pessé <samypesse@gmail.com>2016-01-28 18:39:44 +0100
commit4b465bedea94688a9adfb9136c9d2970d5496274 (patch)
tree7e29cc10d07b86d86239bd1cd59fab7996b412ce
parent461ef2c68e9086bd77f0a25d57956ebf60308f7c (diff)
downloadgitbook-4b465bedea94688a9adfb9136c9d2970d5496274.zip
gitbook-4b465bedea94688a9adfb9136c9d2970d5496274.tar.gz
gitbook-4b465bedea94688a9adfb9136c9d2970d5496274.tar.bz2
Fix tests for languages parsing
-rw-r--r--lib/backbone/file.js3
-rw-r--r--lib/backbone/page.js7
-rw-r--r--lib/book.js14
-rw-r--r--lib/config/index.js30
-rw-r--r--lib/fs/index.js7
-rw-r--r--lib/fs/node.js23
-rw-r--r--lib/generators/json.js3
-rw-r--r--lib/output.js13
-rw-r--r--lib/utils/promise.js12
-rw-r--r--package.json2
-rw-r--r--test/1-config.js50
-rw-r--r--test/4-langs.js31
-rw-r--r--test/6-parse.js25
-rw-r--r--test/mock.js2
14 files changed, 168 insertions, 54 deletions
diff --git a/lib/backbone/file.js b/lib/backbone/file.js
index 34cf066..a58063c 100644
--- a/lib/backbone/file.js
+++ b/lib/backbone/file.js
@@ -1,3 +1,4 @@
+var _ = require('lodash');
function BackboneFile(book) {
if (!(this instanceof BackboneFile)) return new BackboneFile(book);
@@ -8,6 +9,8 @@ function BackboneFile(book) {
// Filename in the book
this.filename = '';
this.parser;
+
+ _.bindAll(this);
}
// Type of the backbone file
diff --git a/lib/backbone/page.js b/lib/backbone/page.js
index 33bd636..a17e413 100644
--- a/lib/backbone/page.js
+++ b/lib/backbone/page.js
@@ -1,3 +1,4 @@
+var path = require('path');
/*
A page represent a parsable file in the book (Markdown, Asciidoc, etc)
@@ -11,8 +12,12 @@ function Page(book, filename) {
}
// Return the filename of the page with another extension
+// "README.md" -> "README.html"
Page.prototype.withExtension = function(ext) {
- return
+ return path.join(
+ path.dirname(this.filename),
+ path.basename(this.filename, path.extname(this.filename)) + ext
+ );
};
diff --git a/lib/book.js b/lib/book.js
index c211adf..477283f 100644
--- a/lib/book.js
+++ b/lib/book.js
@@ -50,7 +50,6 @@ function Book(opts) {
this.ignore.addPattern([
// Skip Git stuff
'.git/',
- '.gitignore',
// Skip OS X meta data
'.DS_Store',
@@ -62,12 +61,7 @@ function Book(opts) {
'_book',
'*.pdf',
'*.epub',
- '*.mobi',
-
- // Skip config files
- '.ignore',
- '.bookignore',
- 'book.json'
+ '*.mobi'
]);
// Create a logger for the book
@@ -124,7 +118,7 @@ Book.prototype.isFileInScope = function(filename) {
Book.prototype.parseIgnoreRules = function() {
var that = this;
- return Promise.series([
+ return Promise.serie([
'.ignore',
'.gitignore',
'.bookignore'
@@ -132,6 +126,8 @@ Book.prototype.parseIgnoreRules = function() {
return that.readFile(filename)
.then(function(content) {
that.ignore.addPattern(content.toString().split(/\r?\n/));
+ }, function() {
+ return Promise();
});
});
};
@@ -158,7 +154,7 @@ Book.prototype.parse = function() {
that.log.info.ln('Parsing multilingual book, with', that.langs.count(), 'languages');
// Create a new book for each language and parse it
- return Promise.serial(that.langs.list(), function(lang) {
+ return Promise.serie(that.langs.list(), function(lang) {
that.log.debug.ln('Preparing book for language', lang.id);
var langBook = new Book({
fs: that.fs,
diff --git a/lib/config/index.js b/lib/config/index.js
index 267f650..7734392 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -1,9 +1,15 @@
-var Q = require('q');
var _ = require('lodash');
var semver = require('semver');
var gitbook = require('../gitbook');
var configDefault = require('./default');
+var Promise = require('../utils/promise');
+
+// Config files to tested (sorted)
+var CONFIG_FILES = [
+ 'book.js',
+ 'book.json'
+];
/*
Config is an interface for the book's configuration stored in "book.json" (or "book.js")
@@ -13,6 +19,7 @@ function Config(book, baseConfig) {
this.book = book;
this.fs = book.fs;
this.log = book.log;
+ this.filename = null;
this.replace(baseConfig || {});
}
@@ -22,11 +29,17 @@ function Config(book, baseConfig) {
Config.prototype.load = function() {
var that = this;
- this.log.debug.ln('loading configuration');
- return this.fs.loadAsObject(this.book.resolve('book'))
- .fail(function(err) {
- if (err.code != 'MODULE_NOT_FOUND') throw(err);
- else return Q({});
+ this.log.info.ln('loading configuration');
+
+ // Try all potential configuration file
+ return Promise.some(CONFIG_FILES, function(filename) {
+ that.log.debug.ln('try loading configuration from', filename);
+
+ return that.fs.loadAsObject(that.book.resolve(filename))
+ .fail(function(err) {
+ if (err.code != 'MODULE_NOT_FOUND') throw(err);
+ else return Promise(false);
+ });
})
.then(function(_config) {
return that.replace(_config);
@@ -86,6 +99,11 @@ Config.prototype.replace = function(options) {
});
};
+// Return true if book has a configuration file
+Config.prototype.exists = function() {
+ return Boolean(this.filename);
+};
+
// Return path to a structure file
// Strip the extension by default
Config.prototype.getStructure = function(name, dontStripExt) {
diff --git a/lib/fs/index.js b/lib/fs/index.js
index 1961b07..7b8fc46 100644
--- a/lib/fs/index.js
+++ b/lib/fs/index.js
@@ -1,9 +1,10 @@
-var Q = require('q');
var _ = require('lodash');
var path = require('path');
var Buffer = require('buffer').Buffer;
var destroy = require('destroy');
+var Promise = require('../utils/promise');
+
/*
A filesystem is an interface to read/write files
GitBook can works with a virtual filesystem, for example in the browser.
@@ -73,7 +74,7 @@ FS.prototype.listAllFiles = function(folder) {
});
}
});
- }, Q([]));
+ }, Promise([]));
});
};
@@ -88,7 +89,7 @@ FS.prototype.readAsString = function(filename) {
// Write a stream to a file and returns a promise
FS.prototype.writeStream = function(filename, stream) {
var bufs = [];
- var d = Q.defer();
+ var d = Promise.defer();
var cleanup = function() {
destroy(stream);
diff --git a/lib/fs/node.js b/lib/fs/node.js
index 0c470d7..28383cf 100644
--- a/lib/fs/node.js
+++ b/lib/fs/node.js
@@ -1,9 +1,10 @@
-var Q = require('q');
var _ = require('lodash');
var util = require('util');
var path = require('path');
var fs = require('fs');
+var mkdirp = require('mkdirp');
+var Promise = require('../utils/promise');
var BaseFS = require('./');
function NodeFS() {
@@ -13,7 +14,7 @@ util.inherits(NodeFS, BaseFS);
// Check if a file exists, run a Promise(true) if that's the case, Promise(false) otherwise
NodeFS.prototype.exists = function(filename) {
- var d = Q.defer();
+ var d = Promise.defer();
fs.exists(filename, function(exists) {
d.resolve(exists);
@@ -24,17 +25,25 @@ NodeFS.prototype.exists = function(filename) {
// Read a file and returns a promise with the content as a buffer
NodeFS.prototype.read = function(filename) {
- return Q.nfcall(fs.readFile, filename);
+ return Promise.nfcall(fs.readFile, filename);
};
// Write a file and returns a promise
NodeFS.prototype.write = function(filename, buffer) {
- return Q.nfcall(fs.writeFile, filename, buffer);
+ var folder = path.dirname(filename);
+ return Promise()
+ .then(function() {
+ if (!folder) return;
+ return Promise.nfcall(mkdirp, folder);
+ })
+ .then(function() {
+ return Promise.nfcall(fs.writeFile, filename, buffer);
+ });
};
// List files in a directory
NodeFS.prototype.readdir = function(folder) {
- return Q.nfcall(fs.readdir, folder)
+ return Promise.nfcall(fs.readdir, folder)
.then(function(files) {
return _.chain(files)
.map(function(file) {
@@ -51,7 +60,7 @@ NodeFS.prototype.readdir = function(folder) {
// Load a JSON/JS file
NodeFS.prototype.loadAsObject = function(filename) {
- return Q()
+ return Promise()
.then(function() {
var jsFile;
@@ -64,7 +73,7 @@ NodeFS.prototype.loadAsObject = function(filename) {
return require(jsFile);
}
catch(err) {
- return Q.reject(err);
+ return Promise.reject(err);
}
});
};
diff --git a/lib/generators/json.js b/lib/generators/json.js
index 820574b..19182bc 100644
--- a/lib/generators/json.js
+++ b/lib/generators/json.js
@@ -8,9 +8,10 @@ util.inherits(JSONGenerator, Generator);
// Write a page (parsable file)
Generator.prototype.writePage = function(page) {
+ var json = {};
- return this.output.writeFile(page.withExtension('.json'));
+ return this.output.writeFile(page.withExtension('.json'), JSON.stringify(json, null, 4));
};
diff --git a/lib/output.js b/lib/output.js
index d09f29d..c22e8de 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -1,3 +1,5 @@
+var Ignore = require('ignore');
+
var Promise = require('./utils/promise');
var generators = require('./generators');
var PluginsManager = require('./plugins');
@@ -9,6 +11,17 @@ function Output(book, type) {
this.type = type;
this.plugins = new PluginsManager(book);
this.generator = new generators[type](this, type);
+
+ // Files to ignore in output
+ this.ignore = Ignore();
+ this.ignore.addPattern([
+ '.gitignore',
+ '.ignore',
+ '.bookignore',
+
+ // The configuration file should not be copied in the output
+ this.book.config.filename
+ ]);
}
// Write a file to the output folder
diff --git a/lib/utils/promise.js b/lib/utils/promise.js
index c25b349..82f4a60 100644
--- a/lib/utils/promise.js
+++ b/lib/utils/promise.js
@@ -21,6 +21,18 @@ function serie(arr, iter, base) {
}, []);
}
+// Iter over an array and return first result (not null)
+function some(arr, iter) {
+ return _.reduce(arr, function(prev, elem, i) {
+ return prev.then(function(val) {
+ if (val) return val;
+
+ return iter(elem, i);
+ });
+ }, Q());
+}
+
module.exports = Q;
module.exports.reduce = reduce;
module.exports.serie = serie;
+module.exports.some = some;
diff --git a/package.json b/package.json
index 14f9f24..7129e73 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"lodash": "3.10.1",
"graceful-fs": "3.0.5",
"resolve": "0.6.3",
- "fs-extra": "0.16.5",
+ "mkdirp": "0.5.1",
"fstream-ignore": "1.0.2",
"gitbook-parsers": "0.8.9",
"gitbook-plugin-highlight": "1.0.3",
diff --git a/test/1-config.js b/test/1-config.js
index 474ffea..3ec76ca 100644
--- a/test/1-config.js
+++ b/test/1-config.js
@@ -2,38 +2,56 @@ var mock = require('./mock');
describe('Config', function() {
- describe('config.load()', function() {
- it('should not fail if no configuration file', function() {
+ describe('No configuration', function() {
+ var book;
+
+ before(function() {
return mock.setupDefaultBook()
- .then(function(book) {
+ .then(function(_book) {
+ book = _book;
return book.prepareConfig();
});
});
- it('should load from a JSON file', function() {
+ it('should signal that configuration is not defined', function() {
+ book.config.exists().should.not.be.ok();
+ });
+ });
+
+ describe('JSON file', function() {
+ var book;
+
+ before(function() {
return mock.setupDefaultBook({
'book.json': { title: 'Hello World' }
})
- .then(function(book) {
- return book.prepareConfig()
- .then(function() {
- book.config.get('title', '').should.equal('Hello World');
- });
+ .then(function(_book) {
+ book = _book;
+ return book.prepareConfig();
});
});
- it('should load from a JS file', function() {
+ it('should correctly extend configuration', function() {
+ book.config.get('title', '').should.equal('Hello World');
+ });
+ });
+
+ describe('JS file', function() {
+ var book;
+
+ before(function() {
return mock.setupDefaultBook({
'book.js': 'module.exports = { title: "Hello World" };'
})
- .then(function(book) {
- return book.prepareConfig()
- .then(function() {
- book.config.get('title', '').should.equal('Hello World');
- });
+ .then(function(_book) {
+ book = _book;
+ return book.prepareConfig();
});
});
- });
+ it('should correctly extend configuration', function() {
+ book.config.get('title', '').should.equal('Hello World');
+ });
+ });
});
diff --git a/test/4-langs.js b/test/4-langs.js
index 599cb43..dbde992 100644
--- a/test/4-langs.js
+++ b/test/4-langs.js
@@ -18,18 +18,29 @@ describe('Langs', function() {
});
});
- it('should parse languages list', function() {
- return mock.setupDefaultBook({
- 'LANGS.md': '# Languages\n\n'
- + '* [en](./en)\n'
- + '* [fr](./fr)\n\n'
- })
- .then(function(book) {
- return book.langs.load()
- .then(function() {
- book.langs.count().should.equal(2);
+ describe('Non-empty languages list', function() {
+ var book;
+
+ before(function() {
+ return mock.setupDefaultBook({
+ 'LANGS.md': '# Languages\n\n'
+ + '* [en](./en)\n'
+ + '* [fr](./fr)\n\n'
+ })
+ .then(function(_book) {
+ book = _book;
+
+ return book.langs.load();
});
});
+
+ it('should correctly count languages', function() {
+ book.langs.count().should.equal(2);
+ });
+
+ it('should correctly define book as multilingual', function() {
+ book.isMultilingual().should.equal(true);
+ });
});
});
diff --git a/test/6-parse.js b/test/6-parse.js
index 422744d..a575720 100644
--- a/test/6-parse.js
+++ b/test/6-parse.js
@@ -18,5 +18,30 @@ describe('Parsing', function() {
return book.parse().should.be.rejected;
});
});
+
+
+ describe('Multilingual book', function() {
+ var book;
+
+ before(function() {
+ return mock.setupBook({
+ 'LANGS.md': '# Languages\n\n'
+ + '* [English](./en)\n'
+ + '* [French](./fr)\n\n',
+ 'en/README.md': '# English',
+ 'en/SUMMARY.md': '# Summary',
+ 'fr/README.md': '# French',
+ 'fr/SUMMARY.md': '# Summary'
+ })
+ .then(function(_book) {
+ book = _book;
+ return book.parse();
+ });
+ });
+
+ it('should list language books', function() {
+
+ });
+ });
});
diff --git a/test/mock.js b/test/mock.js
index f562fa9..919a992 100644
--- a/test/mock.js
+++ b/test/mock.js
@@ -35,11 +35,13 @@ function setupFS(fs, rootFolder, files) {
// Setup a mock book for testing using a map of files
function setupBook(files, opts) {
opts = opts || {};
+ opts.log = function() { };
return Q.nfcall(tmp.dir.bind(tmp)).get(0)
.then(function(folder) {
opts.fs = fs;
opts.root = folder;
+
return setupFS(fs, folder, files);
})
.then(function(fs) {