tests: Port fixMarkup() test to jasmine
Based on https://bugzilla.gnome.org/show_bug.cgi?id=783738 from Sam Spilsbury. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3164>
This commit is contained in:
parent
ab4ca87ee9
commit
847b927367
@ -24,6 +24,7 @@ unit_tests = [
|
||||
'injectionManager',
|
||||
'insertSorted',
|
||||
'jsParse',
|
||||
'markup',
|
||||
]
|
||||
|
||||
foreach test : unit_tests
|
||||
@ -42,7 +43,6 @@ foreach test : unit_tests
|
||||
endforeach
|
||||
|
||||
legacy_tests = [
|
||||
'markup',
|
||||
'params',
|
||||
'signalTracker',
|
||||
'url',
|
||||
|
@ -1,150 +1,216 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
// Test cases for MessageList markup parsing
|
||||
|
||||
const JsUnit = imports.jsUnit;
|
||||
import Pango from 'gi://Pango';
|
||||
|
||||
import 'resource:///org/gnome/shell/ui/environment.js';
|
||||
import {fixMarkup} from 'resource:///org/gnome/shell/misc/util.js';
|
||||
|
||||
/**
|
||||
* Assert that `input`, assumed to be markup, gets "fixed" to `output`,
|
||||
* which is valid markup. If `output` is null, `input` is expected to
|
||||
* convert to itself
|
||||
*
|
||||
* @param {string} input the input
|
||||
* @param {string} output the output
|
||||
*/
|
||||
function assertConverts(input, output) {
|
||||
if (!output)
|
||||
output = input;
|
||||
let fixed = fixMarkup(input, true);
|
||||
JsUnit.assertEquals(output, fixed);
|
||||
describe('fixMarkup()', () => {
|
||||
function convertAndEscape(text) {
|
||||
return {
|
||||
converted: fixMarkup(text, true),
|
||||
escaped: fixMarkup(text, false),
|
||||
};
|
||||
}
|
||||
|
||||
let parsed = false;
|
||||
beforeAll(() => {
|
||||
jasmine.addMatchers({
|
||||
toParseCorrectlyAndMatch: () => {
|
||||
function isMarkupValid(markup) {
|
||||
try {
|
||||
Pango.parse_markup(fixed, -1, '');
|
||||
parsed = true;
|
||||
} catch (e) {}
|
||||
JsUnit.assertEquals(true, parsed);
|
||||
}
|
||||
Pango.parse_markup(markup, -1, '');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
compare: (actual, expected) => {
|
||||
if (!expected)
|
||||
expected = actual;
|
||||
|
||||
/**
|
||||
* Assert that `input`, assumed to be plain text, gets escaped to `output`,
|
||||
* which is valid markup.
|
||||
*
|
||||
* @param {string} input the input
|
||||
* @param {string} output the output
|
||||
*/
|
||||
function assertEscapes(input, output) {
|
||||
let fixed = fixMarkup(input, false);
|
||||
JsUnit.assertEquals(output, fixed);
|
||||
return {
|
||||
pass: isMarkupValid(actual) && actual === expected,
|
||||
message: `Expected "${actual}" to parse correctly and equal "${expected}"`,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
let parsed = false;
|
||||
try {
|
||||
Pango.parse_markup(fixed, -1, '');
|
||||
parsed = true;
|
||||
} catch (e) {}
|
||||
JsUnit.assertEquals(true, parsed);
|
||||
}
|
||||
it('does not do anything on no markup', () => {
|
||||
const text = 'foo';
|
||||
const result = convertAndEscape(text);
|
||||
expect(result.converted).toParseCorrectlyAndMatch(text);
|
||||
expect(result.escaped).toParseCorrectlyAndMatch(text);
|
||||
});
|
||||
|
||||
it('converts and escapes bold markup', () => {
|
||||
const text = '<b>foo</b>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>foo</b>');
|
||||
});
|
||||
|
||||
it('converts and escapes italic markup', () => {
|
||||
const text = 'something <i>foo</i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('something <i>foo</i>');
|
||||
});
|
||||
|
||||
// CORRECT MARKUP
|
||||
it('converts and escapes underlined markup', () => {
|
||||
const text = '<u>foo</u> something';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('<u>foo</u> something');
|
||||
});
|
||||
|
||||
assertConverts('foo');
|
||||
assertEscapes('foo', 'foo');
|
||||
it('converts and escapes non-nested bold italic and underline markup', () => {
|
||||
const text = '<b>bold</b> <i>italic <u>and underlined</u></i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>bold</b> <i>italic <u>and underlined</u></i>');
|
||||
});
|
||||
|
||||
assertConverts('<b>foo</b>');
|
||||
assertEscapes('<b>foo</b>', '<b>foo</b>');
|
||||
it('converts and escapes ampersands', () => {
|
||||
const text = 'this & that';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('this &amp; that');
|
||||
});
|
||||
|
||||
assertConverts('something <i>foo</i>');
|
||||
assertEscapes('something <i>foo</i>', 'something <i>foo</i>');
|
||||
it('converts and escapes <', () => {
|
||||
const text = 'this < that';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('this &lt; that');
|
||||
});
|
||||
|
||||
assertConverts('<u>foo</u> something');
|
||||
assertEscapes('<u>foo</u> something', '<u>foo</u> something');
|
||||
it('converts and escapes >', () => {
|
||||
const text = 'this < that > the other';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('this &lt; that &gt; the other');
|
||||
});
|
||||
|
||||
assertConverts('<b>bold</b> <i>italic <u>and underlined</u></i>');
|
||||
assertEscapes('<b>bold</b> <i>italic <u>and underlined</u></i>', '<b>bold</b> <i>italic <u>and underlined</u></i>');
|
||||
it('converts and escapes HTML markup inside escaped tags', () => {
|
||||
const text = 'this <<i>that</i>>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('this &lt;<i>that</i>&gt;');
|
||||
});
|
||||
|
||||
assertConverts('this & that');
|
||||
assertEscapes('this & that', 'this &amp; that');
|
||||
it('converts and escapes angle brackets within HTML markup', () => {
|
||||
const text = '<b>this</b> > <i>that</i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>this</b> > <i>that</i>');
|
||||
});
|
||||
|
||||
assertConverts('this < that');
|
||||
assertEscapes('this < that', 'this &lt; that');
|
||||
it('converts and escapes markup whilst still keeping an unrecognized entity', () => {
|
||||
const text = '<b>smile</b> ☺!';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch();
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>smile</b> &#9786;!');
|
||||
});
|
||||
|
||||
assertConverts('this < that > the other');
|
||||
assertEscapes('this < that > the other', 'this &lt; that &gt; the other');
|
||||
it('converts and escapes markup and a stray ampersand', () => {
|
||||
const text = '<b>this</b> & <i>that</i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>this</b> & <i>that</i>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>this</b> & <i>that</i>');
|
||||
});
|
||||
|
||||
assertConverts('this <<i>that</i>>');
|
||||
assertEscapes('this <<i>that</i>>', 'this &lt;<i>that</i>&gt;');
|
||||
it('converts and escapes a stray <', () => {
|
||||
const text = 'this < that';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('this < that');
|
||||
expect(escaped).toParseCorrectlyAndMatch('this < that');
|
||||
});
|
||||
|
||||
assertConverts('<b>this</b> > <i>that</i>');
|
||||
assertEscapes('<b>this</b> > <i>that</i>', '<b>this</b> > <i>that</i>');
|
||||
it('converts and escapes markup with a stray <', () => {
|
||||
const text = '<b>this</b> < <i>that</i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>this</b> < <i>that</i>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>this</b> < <i>that</i>');
|
||||
});
|
||||
|
||||
it('converts and escapes stray less than and greater than characters that do not form tags', () => {
|
||||
const text = 'this < that > the other';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('this < that > the other');
|
||||
expect(escaped).toParseCorrectlyAndMatch('this < that > the other');
|
||||
});
|
||||
|
||||
it('converts and escapes stray less than and greater than characters next to HTML markup tags', () => {
|
||||
const text = 'this <<i>that</i>>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('this <<i>that</i>>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('this <<i>that</i>>');
|
||||
});
|
||||
|
||||
// PARTIALLY CORRECT MARKUP
|
||||
// correct bits are kept, incorrect bits are escaped
|
||||
it('converts and escapes angle brackets around unknown tags', () => {
|
||||
const text = '<unknown>tag</unknown>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<unknown>tag</unknown>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<unknown>tag</unknown>');
|
||||
});
|
||||
|
||||
// unrecognized entity
|
||||
assertConverts('<b>smile</b> ☺!', '<b>smile</b> &#9786;!');
|
||||
assertEscapes('<b>smile</b> ☺!', '<b>smile</b> &#9786;!');
|
||||
it('converts and escapes angle brackets around unknown tags where the first letter might otherwise be valid HTML markup', () => {
|
||||
const text = '<bunknown>tag</bunknown>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<bunknown>tag</bunknown>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<bunknown>tag</bunknown>');
|
||||
});
|
||||
|
||||
// stray '&'; this is really a bug, but it's easier to do it this way
|
||||
assertConverts('<b>this</b> & <i>that</i>', '<b>this</b> & <i>that</i>');
|
||||
assertEscapes('<b>this</b> & <i>that</i>', '<b>this</b> & <i>that</i>');
|
||||
it('converts good tags but escapes bad tags', () => {
|
||||
const text = '<i>known</i> and <unknown>tag</unknown>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<i>known</i> and <unknown>tag</unknown>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<i>known</i> and <unknown>tag</unknown>');
|
||||
});
|
||||
|
||||
// likewise with stray '<'
|
||||
assertConverts('this < that', 'this < that');
|
||||
assertEscapes('this < that', 'this < that');
|
||||
it('completely escapes mismatched tags where the mismatch is at the beginning', () => {
|
||||
const text = '<b>in<i>com</i>plete';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>in<i>com</i>plete');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>in<i>com</i>plete');
|
||||
});
|
||||
|
||||
assertConverts('<b>this</b> < <i>that</i>', '<b>this</b> < <i>that</i>');
|
||||
assertEscapes('<b>this</b> < <i>that</i>', '<b>this</b> < <i>that</i>');
|
||||
it('completely escapes mismatched tags where the mismatch is at the end', () => {
|
||||
const text = 'in<i>com</i>plete</b>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('in<i>com</i>plete</b>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('in<i>com</i>plete</b>');
|
||||
});
|
||||
|
||||
assertConverts('this < that > the other', 'this < that > the other');
|
||||
assertEscapes('this < that > the other', 'this < that > the other');
|
||||
it('escapes all tags where there are attributes', () => {
|
||||
const text = '<b>good</b> and <b style=\'bad\'>bad</b>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>good</b> and <b style='bad'>bad</b>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>good</b> and <b style='bad'>bad</b>');
|
||||
});
|
||||
it('escapes all tags where syntax is invalid', () => {
|
||||
const text = '<b>unrecognized</b stuff>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>unrecognized</b stuff>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>unrecognized</b stuff>');
|
||||
});
|
||||
|
||||
assertConverts('this <<i>that</i>>', 'this <<i>that</i>>');
|
||||
assertEscapes('this <<i>that</i>>', 'this <<i>that</i>>');
|
||||
it('escapes completely mismatched tags', () => {
|
||||
const text = '<b>mismatched</i>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>mismatched</i>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>mismatched</i>');
|
||||
});
|
||||
|
||||
// unknown tags
|
||||
assertConverts('<unknown>tag</unknown>', '<unknown>tag</unknown>');
|
||||
assertEscapes('<unknown>tag</unknown>', '<unknown>tag</unknown>');
|
||||
|
||||
// make sure we check beyond the first letter
|
||||
assertConverts('<bunknown>tag</bunknown>', '<bunknown>tag</bunknown>');
|
||||
assertEscapes('<bunknown>tag</bunknown>', '<bunknown>tag</bunknown>');
|
||||
|
||||
// with mix of good and bad, we keep the good and escape the bad
|
||||
assertConverts('<i>known</i> and <unknown>tag</unknown>', '<i>known</i> and <unknown>tag</unknown>');
|
||||
assertEscapes('<i>known</i> and <unknown>tag</unknown>', '<i>known</i> and <unknown>tag</unknown>');
|
||||
|
||||
|
||||
|
||||
// FULLY INCORRECT MARKUP
|
||||
// (fall back to escaping the whole thing)
|
||||
|
||||
// tags not matched up
|
||||
assertConverts('<b>in<i>com</i>plete', '<b>in<i>com</i>plete');
|
||||
assertEscapes('<b>in<i>com</i>plete', '<b>in<i>com</i>plete');
|
||||
|
||||
assertConverts('in<i>com</i>plete</b>', 'in<i>com</i>plete</b>');
|
||||
assertEscapes('in<i>com</i>plete</b>', 'in<i>com</i>plete</b>');
|
||||
|
||||
// we don't support attributes, and it's too complicated to try
|
||||
// to escape both start and end tags, so we just treat it as bad
|
||||
assertConverts('<b>good</b> and <b style=\'bad\'>bad</b>', '<b>good</b> and <b style='bad'>bad</b>');
|
||||
assertEscapes('<b>good</b> and <b style=\'bad\'>bad</b>', '<b>good</b> and <b style='bad'>bad</b>');
|
||||
|
||||
// this is just syntactically invalid
|
||||
assertConverts('<b>unrecognized</b stuff>', '<b>unrecognized</b stuff>');
|
||||
assertEscapes('<b>unrecognized</b stuff>', '<b>unrecognized</b stuff>');
|
||||
|
||||
// mismatched tags
|
||||
assertConverts('<b>mismatched</i>', '<b>mismatched</i>');
|
||||
assertEscapes('<b>mismatched</i>', '<b>mismatched</i>');
|
||||
|
||||
assertConverts('<b>mismatched/unknown</bunknown>', '<b>mismatched/unknown</bunknown>');
|
||||
assertEscapes('<b>mismatched/unknown</bunknown>', '<b>mismatched/unknown</bunknown>');
|
||||
it('escapes mismatched tags where the first character is mismatched', () => {
|
||||
const text = '<b>mismatched/unknown</bunknown>';
|
||||
const {converted, escaped} = convertAndEscape(text);
|
||||
expect(converted).toParseCorrectlyAndMatch('<b>mismatched/unknown</bunknown>');
|
||||
expect(escaped).toParseCorrectlyAndMatch('<b>mismatched/unknown</bunknown>');
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user