refactor: migrate typescript (#5417)
[hexo.git] / test / scripts / hexo / multi_config_path.ts
blobdd7ad4202ae9cb10ff0912fbd6b09665ae201cdb
1 import pathFn from 'path';
2 import osFn from 'os';
3 import { writeFileSync, rmdirSync, unlinkSync, readFileSync } from 'hexo-fs';
4 import yml from 'js-yaml';
5 import Hexo from '../../../lib/hexo';
6 import multiConfigPath from '../../../lib/hexo/multi_config_path';
8 describe('config flag handling', () => {
9   const hexo = new Hexo(pathFn.join(__dirname, 'test_dir')) as any;
11   const mcp = multiConfigPath(hexo);
12   const base = hexo.base_dir;
14   function ConsoleReader() {
15     this.reader = [];
16     this.d = function(...args) {
17       const type = 'debug';
18       let message = '';
19       for (let i = 0; i < args.length;) {
20         message += args[i];
21         if (++i < args.length) {
22           message += ' ';
23         }
24       }
26       this.reader.push({
27         type,
28         msg: message
29       });
30     }.bind(this);
32     this.i = function(...args) {
33       const type = 'info';
34       let message = '';
35       for (let i = 0; i < args.length;) {
36         message += args[i];
37         if (++i < args.length) {
38           message += ' ';
39         }
40       }
42       this.reader.push({
43         type,
44         msg: message
45       });
46     }.bind(this);
48     this.w = function(...args) {
49       const type = 'warning';
50       let message = '';
51       for (let i = 0; i < args.length;) {
52         message += args[i];
53         if (++i < args.length) {
54           message += ' ';
55         }
56       }
58       this.reader.push({
59         type,
60         msg: message
61       });
62     }.bind(this);
64     this.e = function(...args) {
65       const type = 'error';
66       let message = '';
67       for (let i = 0; i < args.length;) {
68         message += args[i];
69         if (++i < args.length) {
70           message += ' ';
71         }
72       }
74       this.reader.push({
75         type,
76         msg: message
77       });
78     }.bind(this);
79   }
81   hexo.log = new ConsoleReader();
83   const testYaml1 = [
84     'author: foo',
85     'type: dinosaur',
86     'favorites:',
87     '  food: sushi',
88     '  color: purple'
89   ].join('\n');
91   const testYaml2 = [
92     'author: bar',
93     'favorites:',
94     '  food: candy',
95     '  ice_cream: chocolate'
96   ].join('\n');
98   const testJson1 = [
99     '{',
100     '"author": "dinosaur",',
101     '"type": "elephant",',
102     '"favorites": {"food": "burgers"}',
103     '}'
104   ].join('\n');
106   const testJson2 = [
107     '{',
108     '"author": "waldo",',
109     '"favorites": {',
110     '  "food": "ice cream",',
111     '  "ice_cream": "strawberry"',
112     '  }',
113     '}'
114   ].join('\n');
116   const testJson3 = [
117     '{',
118     '"author": "james bond",',
119     '"favorites": {',
120     '  "food": "martini",',
121     '  "ice_cream": "vanilla"',
122     '  }',
123     '}'
124   ].join('\n');
126   before(() => {
127     writeFileSync(base + 'test1.yml', testYaml1);
128     writeFileSync(base + 'test2.yml', testYaml2);
129     writeFileSync(base + 'test1.json', testJson1);
130     writeFileSync(base + 'test2.json', testJson2);
131     // not supported type
132     writeFileSync(base + 'test1.xml', '');
133     writeFileSync('/tmp/test3.json', testJson3);
134   });
136   afterEach(() => {
137     hexo.log.reader = [];
138   });
140   after(() => {
141     rmdirSync(hexo.base_dir);
142     unlinkSync('/tmp/test3.json');
143   });
145   it('no file', () => {
146     mcp(base).should.equal(base + '_config.yml');
147     hexo.log.reader[0].type.should.eql('warning');
148     hexo.log.reader[0].msg.should.eql('No config file entered.');
149   });
151   it('not supported type', () => {
152     mcp(base, 'test1.xml,test1.json').should.equal(base + '_multiconfig.yml');
153     hexo.log.reader[0].type.should.eql('warning');
154     hexo.log.reader[0].msg.should.eql('Config file test1.xml not supported type.');
155   });
157   it('1 file', () => {
158     mcp(base, 'test1.yml').should.eql(
159       pathFn.resolve(base + 'test1.yml'));
161     mcp(base, 'test1.json').should.eql(
162       pathFn.resolve(base + 'test1.json'));
164     mcp(base, '/tmp/test3.json').should.eql('/tmp/test3.json');
165   });
167   it('1 not found file warning', () => {
168     const notFile = 'not_a_file.json';
170     mcp(base, notFile).should.eql(pathFn.join(base, '_config.yml'));
171     hexo.log.reader[0].type.should.eql('warning');
172     hexo.log.reader[0].msg.should.eql('Config file ' + notFile
173       + ' not found, using default.');
174   });
176   it('1 not found file warning absolute', () => {
177     const notFile = '/tmp/not_a_file.json';
179     mcp(base, notFile).should.eql(pathFn.join(base, '_config.yml'));
180     hexo.log.reader[0].type.should.eql('warning');
181     hexo.log.reader[0].msg.should.eql('Config file ' + notFile
182       + ' not found, using default.');
183   });
185   it('combined config output', () => {
186     const combinedPath = pathFn.join(base, '_multiconfig.yml');
188     mcp(base, 'test1.yml').should.not.eql(combinedPath);
189     mcp(base, 'test1.yml,test2.yml').should.eql(combinedPath);
190     mcp(base, 'test1.yml,test1.json').should.eql(combinedPath);
191     mcp(base, 'test1.json,test2.json').should.eql(combinedPath);
192     mcp(base, 'notafile.yml,test1.json').should.eql(combinedPath);
194     hexo.log.reader[0].type.should.eql('info');
195     hexo.log.reader[0].msg.should.eql('Config based on 2 files');
196     hexo.log.reader[6].type.should.eql('warning');
197     hexo.log.reader[6].msg.should.eql('Config file notafile.yml not found.');
198     hexo.log.reader[7].type.should.eql('info');
199     hexo.log.reader[7].msg.should.eql('Config based on 1 files');
200     // because who cares about grammar anyway?
202     mcp(base, 'notafile.yml,alsonotafile.json').should.not.eql(combinedPath);
203     hexo.log.reader[11].type.should.eql('error');
204     hexo.log.reader[11].msg.should.eql('No config files found. Using _config.yml.');
205   });
207   it('combine config output with absolute paths', () => {
208     const combinedPath = pathFn.join(base, '_multiconfig.yml');
210     mcp(base, 'test1.json,/tmp/test3.json').should.eql(combinedPath);
211     hexo.log.reader[0].type.should.eql('info');
212     hexo.log.reader[0].msg.should.eql('Config based on 2 files');
213   });
215   it('2 YAML overwrite', () => {
216     const configFile = mcp(base, 'test1.yml,test2.yml');
217     let config: any = readFileSync(configFile);
218     config = yml.load(config);
220     config.author.should.eql('bar');
221     config.favorites.food.should.eql('candy');
222     config.type.should.eql('dinosaur');
224     config = readFileSync(mcp(base, 'test2.yml,test1.yml'));
225     config = yml.load(config);
227     config.author.should.eql('foo');
228     config.favorites.food.should.eql('sushi');
229     config.type.should.eql('dinosaur');
230   });
232   it('2 JSON overwrite', () => {
233     let config: any = readFileSync(mcp(base, 'test1.json,test2.json'));
234     config = yml.load(config);
236     config.author.should.eql('waldo');
237     config.favorites.food.should.eql('ice cream');
238     config.type.should.eql('elephant');
240     config = readFileSync(mcp(base, 'test2.json,test1.json'));
241     config = yml.load(config);
243     config.author.should.eql('dinosaur');
244     config.favorites.food.should.eql('burgers');
245     config.type.should.eql('elephant');
246   });
248   it('JSON & YAML overwrite', () => {
249     let config: any = readFileSync(mcp(base, 'test1.yml,test1.json'));
250     config = yml.load(config);
252     config.author.should.eql('dinosaur');
253     config.favorites.food.should.eql('burgers');
254     config.type.should.eql('elephant');
256     config = readFileSync(mcp(base, 'test1.json,test1.yml'));
257     config = yml.load(config);
259     config.author.should.eql('foo');
260     config.favorites.food.should.eql('sushi');
261     config.type.should.eql('dinosaur');
262   });
264   it('write multiconfig to specified path', () => {
265     const outputPath = osFn.tmpdir();
266     const combinedPath = pathFn.join(outputPath, '_multiconfig.yml');
268     mcp(base, 'test1.yml', outputPath).should.not.eql(combinedPath);
269     mcp(base, 'test1.yml,test2.yml', outputPath).should.eql(combinedPath);
270     mcp(base, 'test1.yml,test1.json', outputPath).should.eql(combinedPath);
271     mcp(base, 'test1.json,test2.json', outputPath).should.eql(combinedPath);
272     mcp(base, 'notafile.yml,test1.json', outputPath).should.eql(combinedPath);
273     mcp(base, 'notafile.yml,alsonotafile.json', outputPath).should.not.eql(combinedPath);
275     // delete /tmp/_multiconfig.yml
276     unlinkSync(combinedPath);
278     hexo.log.reader[1].type.should.eql('debug');
279     hexo.log.reader[1].msg.should.eql(`Writing _multiconfig.yml to ${combinedPath}`);
280     hexo.log.reader[2].type.should.eql('info');
281     hexo.log.reader[2].msg.should.eql('Config based on 2 files');
282     hexo.log.reader[6].type.should.eql('warning');
283     hexo.log.reader[6].msg.should.eql('Config file notafile.yml not found.');
284     hexo.log.reader[7].type.should.eql('info');
285     hexo.log.reader[7].msg.should.eql('Config based on 1 files');
286     hexo.log.reader[11].type.should.eql('error');
287     hexo.log.reader[11].msg.should.eql('No config files found. Using _config.yml.');
288   });