// Copyright 2016 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.html.safeHtmlFormatterTest');
goog.setTestOnly('goog.html.safeHtmlFormatterTest');
goog.require('goog.html.SafeHtml');
goog.require('goog.html.SafeHtmlFormatter');
goog.require('goog.string');
goog.require('goog.testing.jsunit');
function testFormat() {
var formatter = new goog.html.SafeHtmlFormatter();
assertSameHtml('a <bold> statement',
formatter.format(goog.string.subs('a %s%s %s',
formatter.startTag('b', {'class': 'bold'}),
formatter.endTag('b'),
formatter.text('statement'))));
}
function testFormatWithGetMsg() {
var formatter = new goog.html.SafeHtmlFormatter();
assertSameHtml('a <bold> statement',
formatter.format(goog.getMsg('a {$startBold}{$endBold} {$type}', {
'startBold': formatter.startTag('b', {'class': 'bold'}),
'endBold': formatter.endTag('b'),
'type': formatter.text('statement')
})));
}
function testFormatWithText() {
var formatter = new goog.html.SafeHtmlFormatter();
// Escapes format.
assertSameHtml('dinner <3', formatter.format('dinner <3'));
// Escapes .text().
assertSameHtml('dinner <3', formatter.format(formatter.text('dinner <3')));
}
function testFormatWithSafeHtml() {
var formatter = new goog.html.SafeHtmlFormatter();
assertSameHtml('User input: abc', formatter.format('User input: ' +
formatter.safeHtml(goog.html.SafeHtml.create('b', {}, 'abc'))));
}
function testFormatWithInternalMarkers() {
var formatter = new goog.html.SafeHtmlFormatter();
// Immunity against something looking like our marker.
assertSameHtml('{SafeHtmlFormatter:abc}',
formatter.format('{SafeHtmlFormatter:abc}'));
assertSameHtml('{SafeHtmlFormatter:
}',
formatter.format('{SafeHtmlFormatter:' + formatter.startTag('br') + '}'));
// If an attacker steals our random marker and we format his input using
// .text() then we will get back his input (the random marker), not the tag.
var br = formatter.startTag('br');
var attackerInput = br;
assertSameHtml(goog.string.htmlEscape(attackerInput) + '
',
formatter.format(formatter.text(attackerInput) + br));
}
function testInvalidTag() {
assertThrows(function() {
formatter.startTag('a onclick="alert(1);"');
});
assertThrows(function() {
formatter.startTag('a', {'onclick': 'alert(1);'});
});
assertThrows(function() {
formatter.startTag('script');
});
assertThrows(function() {
formatter.endTag('script');
});
}
function testFormatBalancingTags() {
var formatter = new goog.html.SafeHtmlFormatter();
// Void tags are OK.
formatter.format(formatter.startTag('br'));
// Balanced tags are OK.
formatter.format(formatter.startTag('b') + formatter.endTag('b'));
// Order of calling startTag and endTag doesn't matter.
var endTag = formatter.endTag('b');
var startTag = formatter.startTag('b');
formatter.format(startTag + endTag);
// Unbalanced tags throw.
assertThrows(function() {
formatter.format(formatter.endTag('b') + formatter.startTag('b'));
});
// Unclosed tags throw.
assertThrows(function() {
formatter.format(formatter.startTag('b'));
});
// Unopened tags throw.
assertThrows(function() {
formatter.format(formatter.endTag('b'));
});
}
function assertSameHtml(expected, html) {
assertEquals(expected, goog.html.SafeHtml.unwrap(html));
}