Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
package-lock.json
# private: contains the bot account name and password
wiki configuration.js
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ wiki.edit_data(function(entity) {
```


### Tests

Unit tests of the tool functions are put in [test/](https://github.com/kanasimi/wikibot/tree/master/test) and run with the [node:test](https://nodejs.org/api/test.html) runner. They do not contact any wiki.

```bash
npm install
npm test
# with a coverage report:
npm run test:coverage
```

The tests need `wiki configuration.js`; it is created from `wiki configuration.sample.js` automatically when missing.


## Screenshot
Screenshot of [WPCHECK.js](https://github.com/kanasimi/wikibot/blob/master/routine/20151002.WPCHECK.js) (fix_16 only):

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"url" : "https://github.com/kanasimi/wikibot.git"
},

"scripts" : {
"test" : "node --test test/",
"test:coverage" : "node --test --experimental-test-coverage test/"
},

"devDependencies" : {
},
"dependencies" : {
Expand Down
10 changes: 9 additions & 1 deletion replace/replace_tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -1668,7 +1668,7 @@ function text_processor_for_exturlusage(wikitext, page_data) {
// .all_link_pattern
// [\/]: 避免 https://web.archive.org/web/000000/http://www.example.com/
// TODO: flag: 'ig'
const PATTERN_url = new RegExp('(^|\W)' + CeL.to_RegExp_pattern(move_from_link), 'g');
const PATTERN_url = new RegExp('(^|\\W)' + CeL.to_RegExp_pattern(move_from_link), 'g');
// console.trace(PATTERN_url);
wikitext = wikitext.replace(PATTERN_url, function (all, prefix) {
changed = true;
Expand Down Expand Up @@ -3550,6 +3550,14 @@ module.exports = {
replace: replace_tool__replace,
remove_duplicated_display_text,

// tool functions
convert_special_move_to,
unshift_move_configuration,
normalize_page_title_token,
remove_slash_tail,
text_processor_for_search,
text_processor_for_exturlusage,

// for move
parse_move_pairs_from_page,
// parse_move_pairs_from_link,
Expand Down
29 changes: 29 additions & 0 deletions test/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @name Common setup for unit tests.
* @fileoverview Loads the CeJS wiki library the same way the bot scripts do,
* without contacting any wiki. "wiki configuration.js" is
* required by "wiki loader.js"; create it from the sample when
* the working copy does not have one yet.
*/

'use strict';

const node_fs = require('fs');
const path = require('path');

const base_directory = path.join(__dirname, '..');
const configuration_file = path.join(base_directory, 'wiki configuration.js');

if (!node_fs.existsSync(configuration_file)) {
node_fs.copyFileSync(path.join(base_directory,
'wiki configuration.sample.js'), configuration_file);
}

globalThis.no_task_date_warning = true;

require(path.join(base_directory, 'wiki loader.js'));

module.exports = {
base_directory,
CeL: globalThis.CeL
};
192 changes: 192 additions & 0 deletions test/replace_tool.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* @name Unit tests of replace/replace_tool.js tool functions.
*/

'use strict';

const { describe, it } = require('node:test');
const assert = require('node:assert');

const { CeL } = require('./helper.js');
const replace_tool = require('../replace/replace_tool.js');

describe('remove_slash_tail', () => {
const { remove_slash_tail } = replace_tool;

it('removes the tail slash of a domain only URL', () => {
assert.strictEqual(remove_slash_tail('http://www.example.com/'),
'http://www.example.com');
assert.strictEqual(remove_slash_tail('https://www.example.com/'),
'https://www.example.com');
});

it('keeps the tail slash of an URL with path', () => {
assert.strictEqual(remove_slash_tail('http://www.example.com/path/'),
'http://www.example.com/path/');
});

it('keeps URLs without tail slash', () => {
assert.strictEqual(remove_slash_tail('http://www.example.com'),
'http://www.example.com');
assert.strictEqual(remove_slash_tail('http://www.example.com/path'),
'http://www.example.com/path');
});
});

describe('convert_special_move_to', () => {
const { convert_special_move_to } = replace_tool;

it('converts the special keywords to their symbols', () => {
assert.strictEqual(convert_special_move_to('DELETE_PAGE'),
globalThis.DELETE_PAGE);
assert.strictEqual(convert_special_move_to('REDIRECT_TARGET'),
globalThis.REDIRECT_TARGET);
});

it('keeps other move targets', () => {
assert.strictEqual(convert_special_move_to('subst:'), 'subst:');
assert.strictEqual(convert_special_move_to('Page title'), 'Page title');
assert.strictEqual(convert_special_move_to(undefined), undefined);
});

it('converts .move_to_link of a configuration object in place', () => {
const configuration = { move_to_link: 'DELETE_PAGE', extra: 1 };
assert.strictEqual(convert_special_move_to(configuration),
configuration);
assert.strictEqual(configuration.move_to_link, globalThis.DELETE_PAGE);
assert.strictEqual(configuration.extra, 1);
});
});

describe('unshift_move_configuration', () => {
const { unshift_move_configuration } = replace_tool;

it('returns the original configuration when there is nothing to unshift',
() => {
const move_configuration = { from: 'to' };
assert.strictEqual(unshift_move_configuration(
move_configuration, undefined), move_configuration);
});

it('prepends the items to an {Object} configuration', () => {
assert.deepStrictEqual(unshift_move_configuration({ b: '2' },
{ a: '1' }), { a: '1', b: '2' });
});

it('lets the original configuration overwrite the unshifted items', () => {
assert.deepStrictEqual(unshift_move_configuration({ a: 'new' },
{ a: 'old' }), { a: 'new' });
});

it('prepends the items as pairs to an {Array} configuration', () => {
assert.deepStrictEqual(unshift_move_configuration([['b', '2']],
{ a: '1' }), [['a', '1'], ['b', '2']]);
});
});

describe('normalize_page_title_token', () => {
const { normalize_page_title_token } = replace_tool;

it('trims the title', () => {
assert.strictEqual(normalize_page_title_token(' Page title \n'),
'Page title');
});

it('unifies the small ヶ to the normal ケ', () => {
assert.strictEqual(normalize_page_title_token('鎌ヶ谷スタジアム'),
'鎌ケ谷スタジアム');
});

it('accepts a parsed token instead of a string', () => {
const token = CeL.wiki.parser('鎌ヶ谷市').parse();
assert.strictEqual(normalize_page_title_token(token), '鎌ケ谷市');
});
});

describe('text_processor_for_search', () => {
const { text_processor_for_search } = replace_tool;

it('replaces .replace_from with .move_to_link', () => {
const task_configuration = {
replace_from: /old/g,
move_to_link: 'new'
};
assert.strictEqual(text_processor_for_search.call(task_configuration,
'an old old text'), 'an new new text');
});
});

describe('text_processor_for_exturlusage', () => {
const { text_processor_for_exturlusage } = replace_tool;

it('replaces the external link in wikitext', () => {
const task_configuration = {
move_from_link: 'http://old.example.com',
move_to_link: 'https://new.example.com'
};
assert.strictEqual(text_processor_for_exturlusage.call(
task_configuration, 'see [http://old.example.com/page here]'),
'see [https://new.example.com/page here]');
});

it('returns a falsy value when there is nothing changed', () => {
const task_configuration = {
move_from_link: 'http://old.example.com',
move_to_link: 'https://new.example.com'
};
assert.ok(!text_processor_for_exturlusage.call(task_configuration,
'see [http://other.example.com/page here]'));
});

it('does not generate a double slash', () => {
const task_configuration = {
move_from_link: 'http://old.example.com/path/',
move_to_link: 'https://new.example.com/path'
};
assert.strictEqual(text_processor_for_exturlusage.call(
task_configuration, 'http://old.example.com/path/page'),
'https://new.example.com/path/page');
});

it('accepts .move_to_url as the replacement of .move_to_link', () => {
const task_configuration = {
move_from_link: 'http://old.example.com',
move_to_url: 'https://new.example.com'
};
assert.strictEqual(text_processor_for_exturlusage.call(
task_configuration, 'http://old.example.com/page'),
'https://new.example.com/page');
});
});

describe('remove_duplicated_display_text', () => {
const { remove_duplicated_display_text } = replace_tool;

function link_token_of(wikitext) {
const parsed = CeL.wiki.parser(wikitext).parse();
let link_token;
parsed.each('link', token => {
link_token = token;
});
assert.ok(link_token, 'got the link token of ' + wikitext);
return link_token;
}

it('removes the displayed text same as the page title', () => {
const token = link_token_of('[[Page title|Page title]]');
remove_duplicated_display_text(token);
assert.strictEqual(token.toString(), '[[Page title]]');
});

it('keeps a different displayed text', () => {
const token = link_token_of('[[Page title|other text]]');
remove_duplicated_display_text(token);
assert.strictEqual(token.toString(), '[[Page title|other text]]');
});

it('keeps the displayed text with styles', () => {
const token = link_token_of("[[Page title|'''Page title''']]");
remove_duplicated_display_text(token);
assert.strictEqual(token.toString(), "[[Page title|'''Page title''']]");
});
});
Loading