Adding mapbox-gl branch
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
// Copyright 2013 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.string.Const');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for compile-time-constant strings.
|
||||
*
|
||||
* Const is a wrapper for strings that can only be created from program
|
||||
* constants (i.e., string literals). This property relies on a custom Closure
|
||||
* compiler check that {@code goog.string.Const.from} is only invoked on
|
||||
* compile-time-constant expressions.
|
||||
*
|
||||
* Const is useful in APIs whose correct and secure use requires that certain
|
||||
* arguments are not attacker controlled: Compile-time constants are inherently
|
||||
* under the control of the application and not under control of external
|
||||
* attackers, and hence are safe to use in such contexts.
|
||||
*
|
||||
* Instances of this type must be created via its factory method
|
||||
* {@code goog.string.Const.from} and not by invoking its constructor. The
|
||||
* constructor intentionally takes no parameters and the type is immutable;
|
||||
* hence only a default instance corresponding to the empty string can be
|
||||
* obtained via constructor invocation.
|
||||
*
|
||||
* @see goog.string.Const#from
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.string.Const = function() {
|
||||
/**
|
||||
* The wrapped value of this Const object. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.string.Const#unwrap
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ =
|
||||
goog.string.Const.TYPE_MARKER_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.string.Const.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Const's value a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security-relevant that an object's type is
|
||||
* indeed {@code goog.string.Const}, use {@code goog.string.Const.unwrap}
|
||||
* instead of this method.
|
||||
*
|
||||
* @see goog.string.Const#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.string.Const.prototype.getTypedStringValue = function() {
|
||||
return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a debug-string representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped inside an object of this type,
|
||||
* use {@code goog.string.Const.unwrap}.
|
||||
*
|
||||
* @see goog.string.Const#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.string.Const.prototype.toString = function() {
|
||||
return 'Const{' +
|
||||
this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ +
|
||||
'}';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed an instance
|
||||
* of {@code goog.string.Const}, and returns its value.
|
||||
* @param {!goog.string.Const} stringConst The object to extract from.
|
||||
* @return {string} The Const object's contained string, unless the run-time
|
||||
* type check fails. In that case, {@code unwrap} returns an innocuous
|
||||
* string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.string.Const.unwrap = function(stringConst) {
|
||||
// Perform additional run-time type-checking to ensure that stringConst is
|
||||
// indeed an instance of the expected type. This provides some additional
|
||||
// protection against security bugs due to application code that disables type
|
||||
// checks.
|
||||
if (stringConst instanceof goog.string.Const &&
|
||||
stringConst.constructor === goog.string.Const &&
|
||||
stringConst.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ ===
|
||||
goog.string.Const.TYPE_MARKER_) {
|
||||
return stringConst.
|
||||
stringConstValueWithSecurityContract__googStringSecurityPrivate_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type Const, got \'' +
|
||||
stringConst + '\'');
|
||||
return 'type_error:Const';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Const object from a compile-time constant string.
|
||||
*
|
||||
* It is illegal to invoke this function on an expression whose
|
||||
* compile-time-contant value cannot be determined by the Closure compiler.
|
||||
*
|
||||
* Correct invocations include,
|
||||
* <pre>
|
||||
* var s = goog.string.Const.from('hello');
|
||||
* var t = goog.string.Const.from('hello' + 'world');
|
||||
* </pre>
|
||||
*
|
||||
* In contrast, the following are illegal:
|
||||
* <pre>
|
||||
* var s = goog.string.Const.from(getHello());
|
||||
* var t = goog.string.Const.from('hello' + world);
|
||||
* </pre>
|
||||
*
|
||||
* TODO(user): Compile-time checks that this function is only called
|
||||
* with compile-time constant expressions.
|
||||
*
|
||||
* @param {string} s A constant string from which to create a Const.
|
||||
* @return {!goog.string.Const} A Const object initialized to stringConst.
|
||||
*/
|
||||
goog.string.Const.from = function(s) {
|
||||
return goog.string.Const.create__googStringSecurityPrivate_(s);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the Const type, used to implement additional run-time
|
||||
* type checking.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.Const.TYPE_MARKER_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to create Const instances.
|
||||
* @param {string} s The string to initialize the Const object with.
|
||||
* @return {!goog.string.Const} The initialized Const object.
|
||||
* @private
|
||||
*/
|
||||
goog.string.Const.create__googStringSecurityPrivate_ = function(s) {
|
||||
var stringConst = new goog.string.Const();
|
||||
stringConst.stringConstValueWithSecurityContract__googStringSecurityPrivate_ =
|
||||
s;
|
||||
return stringConst;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Unit Tests - goog.string</title>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.string.constTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Unit tests for goog.string.Const.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.constTest');
|
||||
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
goog.setTestOnly('goog.string.constTest');
|
||||
|
||||
|
||||
|
||||
function testConst() {
|
||||
var constString = goog.string.Const.from('blah');
|
||||
var extracted = goog.string.Const.unwrap(constString);
|
||||
assertEquals('blah', extracted);
|
||||
assertEquals('blah', constString.getTypedStringValue());
|
||||
assertEquals('Const{blah}', String(constString));
|
||||
|
||||
// Interface marker is present.
|
||||
assertTrue(constString.implementsGoogStringTypedString);
|
||||
}
|
||||
|
||||
|
||||
/** @suppress {checkTypes} */
|
||||
function testUnwrap() {
|
||||
var evil = {};
|
||||
evil.constStringValueWithSecurityContract__googStringSecurityPrivate_ =
|
||||
'evil';
|
||||
evil.CONST_STRING_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ = {};
|
||||
|
||||
var exception = assertThrows(function() {
|
||||
goog.string.Const.unwrap(evil);
|
||||
});
|
||||
assertTrue(exception.message.indexOf('expected object of type Const') > 0);
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
// Copyright 2008 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Utility function for linkifying text.
|
||||
* @author bolinfest@google.com (Michael Bolin)
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.linkify');
|
||||
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* Takes a string of plain text and linkifies URLs and email addresses. For a
|
||||
* URL (unless opt_attributes is specified), the target of the link will be
|
||||
* _blank and it will have a rel=nofollow attribute applied to it so that links
|
||||
* created by linkify will not be of interest to search engines.
|
||||
* @param {string} text Plain text.
|
||||
* @param {Object<string, string>=} opt_attributes Attributes to add to all
|
||||
* links created. Default are rel=nofollow and target=_blank. To clear
|
||||
* those default attributes set rel='' and target=''.
|
||||
* @return {string} HTML Linkified HTML text. Any text that is not part of a
|
||||
* link will be HTML-escaped.
|
||||
*/
|
||||
goog.string.linkify.linkifyPlainText = function(text, opt_attributes) {
|
||||
// This shortcut makes linkifyPlainText ~10x faster if text doesn't contain
|
||||
// URLs or email addresses and adds insignificant performance penalty if it
|
||||
// does.
|
||||
if (text.indexOf('@') == -1 &&
|
||||
text.indexOf('://') == -1 &&
|
||||
text.indexOf('www.') == -1 &&
|
||||
text.indexOf('Www.') == -1 &&
|
||||
text.indexOf('WWW.') == -1) {
|
||||
return goog.string.htmlEscape(text);
|
||||
}
|
||||
|
||||
var attributesMap = opt_attributes || {};
|
||||
// Set default options.
|
||||
if (!('rel' in attributesMap)) {
|
||||
attributesMap['rel'] = 'nofollow';
|
||||
}
|
||||
if (!('target' in attributesMap)) {
|
||||
attributesMap['target'] = '_blank';
|
||||
}
|
||||
// Creates attributes string from options.
|
||||
var attributesArray = [];
|
||||
for (var key in attributesMap) {
|
||||
if (attributesMap.hasOwnProperty(key) && attributesMap[key]) {
|
||||
attributesArray.push(
|
||||
goog.string.htmlEscape(key), '="',
|
||||
goog.string.htmlEscape(attributesMap[key]), '" ');
|
||||
}
|
||||
}
|
||||
var attributes = attributesArray.join('');
|
||||
|
||||
return text.replace(
|
||||
goog.string.linkify.FIND_LINKS_RE_,
|
||||
function(part, before, original, email, protocol) {
|
||||
var output = [goog.string.htmlEscape(before)];
|
||||
if (!original) {
|
||||
return output[0];
|
||||
}
|
||||
output.push('<a ', attributes, 'href="');
|
||||
/** @type {string} */
|
||||
var linkText;
|
||||
/** @type {string} */
|
||||
var afterLink;
|
||||
if (email) {
|
||||
output.push('mailto:');
|
||||
linkText = email;
|
||||
afterLink = '';
|
||||
} else {
|
||||
// This is a full url link.
|
||||
if (!protocol) {
|
||||
output.push('http://');
|
||||
}
|
||||
var splitEndingPunctuation =
|
||||
original.match(goog.string.linkify.ENDS_WITH_PUNCTUATION_RE_);
|
||||
// An open paren in the link will often be matched with a close paren
|
||||
// at the end, so skip cutting off ending punctuation if there's an
|
||||
// open paren. For example:
|
||||
// http://en.wikipedia.org/wiki/Titanic_(1997_film)
|
||||
if (splitEndingPunctuation && !goog.string.contains(original, '(')) {
|
||||
linkText = splitEndingPunctuation[1];
|
||||
afterLink = splitEndingPunctuation[2];
|
||||
} else {
|
||||
linkText = original;
|
||||
afterLink = '';
|
||||
}
|
||||
}
|
||||
linkText = goog.string.htmlEscape(linkText);
|
||||
afterLink = goog.string.htmlEscape(afterLink);
|
||||
output.push(linkText, '">', linkText, '</a>', afterLink);
|
||||
return output.join('');
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the first URI in text.
|
||||
* @param {string} text Plain text.
|
||||
* @return {string} The first URL, or an empty string if not found.
|
||||
*/
|
||||
goog.string.linkify.findFirstUrl = function(text) {
|
||||
var link = text.match(goog.string.linkify.URL_);
|
||||
return link != null ? link[0] : '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the first email address in text.
|
||||
* @param {string} text Plain text.
|
||||
* @return {string} The first email address, or an empty string if not found.
|
||||
*/
|
||||
goog.string.linkify.findFirstEmail = function(text) {
|
||||
var email = text.match(goog.string.linkify.EMAIL_);
|
||||
return email != null ? email[0] : '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* If a series of these characters is at the end of a url, it will be considered
|
||||
* punctuation and not part of the url.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.ENDING_PUNCTUATION_CHARS_ = ':;,\\.?>\\]\\)!';
|
||||
|
||||
|
||||
/**
|
||||
* @type {!RegExp}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.ENDS_WITH_PUNCTUATION_RE_ = new RegExp(
|
||||
'^(.*?)([' + goog.string.linkify.ENDING_PUNCTUATION_CHARS_ + ']+)$');
|
||||
|
||||
|
||||
/**
|
||||
* Set of characters to be put into a regex character set ("[...]"), used to
|
||||
* match against a url hostname and everything after it. It includes
|
||||
* "#-@", which represents the characters "#$%&'()*+,-./0123456789:;<=>?@".
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.ACCEPTABLE_URL_CHARS_ = '\\w~#-@!\\[\\]';
|
||||
|
||||
|
||||
/**
|
||||
* List of all protocols patterns recognized in urls (mailto is handled in email
|
||||
* matching).
|
||||
* @type {!Array<string>}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.RECOGNIZED_PROTOCOLS_ = ['https?', 'ftp'];
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern that matches the beginning of an url.
|
||||
* Contains a catching group to capture the scheme.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.PROTOCOL_START_ =
|
||||
'(' + goog.string.linkify.RECOGNIZED_PROTOCOLS_.join('|') + ')://';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern that matches the beginning of a typical
|
||||
* http url without the http:// scheme.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.WWW_START_ = 'www\\.';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern that matches an url.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.URL_ =
|
||||
'(?:' + goog.string.linkify.PROTOCOL_START_ + '|' +
|
||||
goog.string.linkify.WWW_START_ + ')\\w[' +
|
||||
goog.string.linkify.ACCEPTABLE_URL_CHARS_ + ']*';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern that matches a top level domain.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.TOP_LEVEL_DOMAIN_ =
|
||||
'(?:com|org|net|edu|gov' +
|
||||
// from http://www.iana.org/gtld/gtld.htm
|
||||
'|aero|biz|cat|coop|info|int|jobs|mobi|museum|name|pro|travel' +
|
||||
'|arpa|asia|xxx' +
|
||||
// a two letter country code
|
||||
'|[a-z][a-z])\\b';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern that matches an email.
|
||||
* Contains a catching group to capture the email without the optional "mailto:"
|
||||
* prefix.
|
||||
* @type {string}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.EMAIL_ =
|
||||
'(?:mailto:)?([\\w.+-]+@[A-Za-z0-9.-]+\\.' +
|
||||
goog.string.linkify.TOP_LEVEL_DOMAIN_ + ')';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to match all the links (url or email) in a string.
|
||||
* First match is text before first link, might be empty string.
|
||||
* Second match is the original text that should be replaced by a link.
|
||||
* Third match is the email address in the case of an email.
|
||||
* Fourth match is the scheme of the url if specified.
|
||||
* @type {!RegExp}
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.string.linkify.FIND_LINKS_RE_ = new RegExp(
|
||||
// Match everything including newlines.
|
||||
'([\\S\\s]*?)(' +
|
||||
// Match email after a word break.
|
||||
'\\b' + goog.string.linkify.EMAIL_ + '|' +
|
||||
// Match url after a workd break.
|
||||
'\\b' + goog.string.linkify.URL_ + '|$)',
|
||||
'gi');
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.string.linkify
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.string.linkifyTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,455 @@
|
||||
// Copyright 2008 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.string.linkifyTest');
|
||||
goog.setTestOnly('goog.string.linkifyTest');
|
||||
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.linkify');
|
||||
goog.require('goog.testing.dom');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
var div = document.createElement('div');
|
||||
|
||||
function assertLinkify(comment, input, expected) {
|
||||
assertEquals(
|
||||
comment, expected,
|
||||
goog.string.linkify.linkifyPlainText(input, {rel: '', target: ''}));
|
||||
}
|
||||
|
||||
function testContainsNoLink() {
|
||||
assertLinkify(
|
||||
'Text does not contain any links',
|
||||
'Text with no links in it.',
|
||||
'Text with no links in it.');
|
||||
}
|
||||
|
||||
function testContainsALink() {
|
||||
assertLinkify(
|
||||
'Text only contains a link',
|
||||
'http://www.google.com/',
|
||||
'<a href="http://www.google.com/">http://www.google.com/<\/a>');
|
||||
}
|
||||
|
||||
function testStartsWithALink() {
|
||||
assertLinkify(
|
||||
'Text starts with a link',
|
||||
'http://www.google.com/ is a well known search engine',
|
||||
'<a href="http://www.google.com/">http://www.google.com/<\/a>' +
|
||||
' is a well known search engine');
|
||||
}
|
||||
|
||||
function testEndsWithALink() {
|
||||
assertLinkify(
|
||||
'Text ends with a link',
|
||||
'Look at this search engine: http://www.google.com/',
|
||||
'Look at this search engine: ' +
|
||||
'<a href="http://www.google.com/">http://www.google.com/<\/a>');
|
||||
}
|
||||
|
||||
function testContainsOnlyEmail() {
|
||||
assertLinkify(
|
||||
'Text only contains an email address',
|
||||
'bolinfest@google.com',
|
||||
'<a href="mailto:bolinfest@google.com">bolinfest@google.com<\/a>');
|
||||
}
|
||||
|
||||
function testStartsWithAnEmail() {
|
||||
assertLinkify(
|
||||
'Text starts with an email address',
|
||||
'bolinfest@google.com wrote this test.',
|
||||
'<a href="mailto:bolinfest@google.com">bolinfest@google.com<\/a>' +
|
||||
' wrote this test.');
|
||||
}
|
||||
|
||||
function testEndsWithAnEmail() {
|
||||
assertLinkify(
|
||||
'Text ends with an email address',
|
||||
'This test was written by bolinfest@google.com.',
|
||||
'This test was written by ' +
|
||||
'<a href="mailto:bolinfest@google.com">bolinfest@google.com<\/a>.');
|
||||
}
|
||||
|
||||
function testUrlWithPortNumber() {
|
||||
assertLinkify(
|
||||
'URL with a port number',
|
||||
'http://www.google.com:80/',
|
||||
'<a href="http://www.google.com:80/">http://www.google.com:80/<\/a>');
|
||||
}
|
||||
|
||||
function testUrlWithUserPasswordAndPortNumber() {
|
||||
assertLinkify(
|
||||
'URL with a user, a password and a port number',
|
||||
'http://lascap:p4ssw0rd@google.com:80/s?q=a&hl=en',
|
||||
'<a href="http://lascap:p4ssw0rd@google.com:80/s?q=a&hl=en">' +
|
||||
'http://lascap:p4ssw0rd@google.com:80/s?q=a&hl=en<\/a>');
|
||||
}
|
||||
|
||||
function testUrlWithUnderscore() {
|
||||
assertLinkify(
|
||||
'URL with an underscore',
|
||||
'http://www_foo.google.com/',
|
||||
'<a href="http://www_foo.google.com/">http://www_foo.google.com/<\/a>');
|
||||
}
|
||||
|
||||
function testInternalUrlWithoutDomain() {
|
||||
assertLinkify(
|
||||
'Internal URL without a proper domain',
|
||||
'http://tracker/1068594',
|
||||
'<a href="http://tracker/1068594">http://tracker/1068594<\/a>');
|
||||
}
|
||||
|
||||
function testInternalUrlOneChar() {
|
||||
assertLinkify(
|
||||
'Internal URL with a one char domain',
|
||||
'http://b',
|
||||
'<a href="http://b">http://b<\/a>');
|
||||
}
|
||||
|
||||
function testSecureInternalUrlWithoutDomain() {
|
||||
assertLinkify(
|
||||
'Secure Internal URL without a proper domain',
|
||||
'https://review/6594805',
|
||||
'<a href="https://review/6594805">https://review/6594805<\/a>');
|
||||
}
|
||||
|
||||
function testTwoUrls() {
|
||||
assertLinkify(
|
||||
'Text with two URLs in it',
|
||||
'I use both http://www.google.com and http://yahoo.com, don\'t you?',
|
||||
'I use both <a href="http://www.google.com">http://www.google.com<\/a> ' +
|
||||
'and <a href="http://yahoo.com">http://yahoo.com<\/a>, ' +
|
||||
goog.string.htmlEscape('don\'t you?'));
|
||||
}
|
||||
|
||||
function testGetParams() {
|
||||
assertLinkify(
|
||||
'URL with GET params',
|
||||
'http://google.com/?a=b&c=d&e=f',
|
||||
'<a href="http://google.com/?a=b&c=d&e=f">' +
|
||||
'http://google.com/?a=b&c=d&e=f<\/a>');
|
||||
}
|
||||
|
||||
function testGoogleCache() {
|
||||
assertLinkify(
|
||||
'Google search result from cache',
|
||||
'http://66.102.7.104/search?q=cache:I4LoMT6euUUJ:' +
|
||||
'www.google.com/intl/en/help/features.html+google+cache&hl=en',
|
||||
'<a href="http://66.102.7.104/search?q=cache:I4LoMT6euUUJ:' +
|
||||
'www.google.com/intl/en/help/features.html+google+cache&hl=en">' +
|
||||
'http://66.102.7.104/search?q=cache:I4LoMT6euUUJ:' +
|
||||
'www.google.com/intl/en/help/features.html+google+cache&hl=en' +
|
||||
'<\/a>');
|
||||
}
|
||||
|
||||
function testUrlWithoutHttp() {
|
||||
assertLinkify(
|
||||
'URL without http protocol',
|
||||
'It\'s faster to type www.google.com without the http:// in front.',
|
||||
goog.string.htmlEscape('It\'s faster to type ') +
|
||||
'<a href="http://www.google.com">www.google.com' +
|
||||
'<\/a> without the http:// in front.');
|
||||
}
|
||||
|
||||
function testUrlWithCapitalsWithoutHttp() {
|
||||
assertLinkify(
|
||||
'URL with capital letters without http protocol',
|
||||
'It\'s faster to type Www.google.com without the http:// in front.',
|
||||
goog.string.htmlEscape('It\'s faster to type ') +
|
||||
'<a href="http://Www.google.com">Www.google.com' +
|
||||
'<\/a> without the http:// in front.');
|
||||
}
|
||||
|
||||
function testUrlHashBang() {
|
||||
assertLinkify(
|
||||
'URL with #!',
|
||||
'Another test URL: ' +
|
||||
'https://www.google.com/testurls/#!/page',
|
||||
'Another test URL: ' +
|
||||
'<a href="https://www.google.com/testurls/#!/page">' +
|
||||
'https://www.google.com/testurls/#!/page<\/a>');
|
||||
}
|
||||
|
||||
function testTextLooksLikeUrlWithoutHttp() {
|
||||
assertLinkify(
|
||||
'Text looks like an url but is not',
|
||||
'This showww.is just great: www.is',
|
||||
'This showww.is just great: <a href="http://www.is">www.is<\/a>');
|
||||
}
|
||||
|
||||
function testEmailWithSubdomain() {
|
||||
assertLinkify(
|
||||
'Email with a subdomain',
|
||||
'Send mail to bolinfest@groups.google.com.',
|
||||
'Send mail to <a href="mailto:bolinfest@groups.google.com">' +
|
||||
'bolinfest@groups.google.com<\/a>.');
|
||||
}
|
||||
|
||||
function testEmailWithHyphen() {
|
||||
assertLinkify(
|
||||
'Email with a hyphen in the domain name',
|
||||
'Send mail to bolinfest@google-groups.com.',
|
||||
'Send mail to <a href="mailto:bolinfest@google-groups.com">' +
|
||||
'bolinfest@google-groups.com<\/a>.');
|
||||
}
|
||||
|
||||
function testEmailUsernameWithSpecialChars() {
|
||||
assertLinkify(
|
||||
'Email with a hyphen, period, and + in the user name',
|
||||
'Send mail to bolin-fest+for.um@google.com',
|
||||
'Send mail to <a href="mailto:bolin-fest+for.um@google.com">' +
|
||||
'bolin-fest+for.um@google.com<\/a>');
|
||||
}
|
||||
|
||||
function testEmailWithUnderscoreInvalid() {
|
||||
assertLinkify(
|
||||
'Email with an underscore in the domain name, which is invalid',
|
||||
'Do not email bolinfest@google_groups.com.',
|
||||
'Do not email bolinfest@google_groups.com.');
|
||||
}
|
||||
|
||||
function testUrlNotHttp() {
|
||||
assertLinkify(
|
||||
'Url using unusual scheme',
|
||||
'Looking for some goodies: ftp://ftp.google.com/goodstuff/',
|
||||
'Looking for some goodies: ' +
|
||||
'<a href="ftp://ftp.google.com/goodstuff/">' +
|
||||
'ftp://ftp.google.com/goodstuff/<\/a>');
|
||||
}
|
||||
|
||||
function testJsInjection() {
|
||||
assertLinkify(
|
||||
'Text includes some javascript',
|
||||
'Welcome in hell <script>alert(\'this is hell\')<\/script>',
|
||||
goog.string.htmlEscape(
|
||||
'Welcome in hell <script>alert(\'this is hell\')<\/script>'));
|
||||
}
|
||||
|
||||
function testJsInjectionDotIsBlind() {
|
||||
assertLinkify(
|
||||
'Javascript injection using regex . blindness to newline chars',
|
||||
'<script>malicious_code()<\/script>\nVery nice url: www.google.com',
|
||||
'<script>malicious_code()</script>\nVery nice url: ' +
|
||||
'<a href="http://www.google.com">www.google.com<\/a>');
|
||||
}
|
||||
|
||||
function testJsInjectionWithUnicodeLineReturn() {
|
||||
assertLinkify(
|
||||
'Javascript injection using regex . blindness to newline chars with a ' +
|
||||
'unicode newline character.',
|
||||
'<script>malicious_code()<\/script>\u2029Vanilla text',
|
||||
'<script>malicious_code()</script>\u2029Vanilla text');
|
||||
}
|
||||
|
||||
function testJsInjectionWithIgnorableNonTagChar() {
|
||||
assertLinkify(
|
||||
'Angle brackets are normalized even when followed by an ignorable ' +
|
||||
'non-tag character.',
|
||||
'<\u0000img onerror=alert(1337) src=\n>',
|
||||
'<�img onerror=alert(1337) src=\n>');
|
||||
}
|
||||
|
||||
function testJsInjectionWithTextarea() {
|
||||
assertLinkify(
|
||||
'Putting the result in a textarea can\'t cause other textarea text to ' +
|
||||
'be treated as tag content.',
|
||||
'</textarea',
|
||||
'</textarea');
|
||||
}
|
||||
|
||||
function testJsInjectionWithNewlineConversion() {
|
||||
assertLinkify(
|
||||
'Any newline conversion and whitespace normalization won\'t cause tag ' +
|
||||
'parts to be recombined.',
|
||||
'<<br>script<br>>alert(1337)<<br>/<br>script<br>>',
|
||||
'<<br>script<br>>alert(1337)<<br>/<' +
|
||||
'br>script<br>>');
|
||||
}
|
||||
|
||||
function testNoProtocolBlacklisting() {
|
||||
assertLinkify(
|
||||
'No protocol blacklisting.',
|
||||
'Click: jscript:alert%281337%29\nClick: JSscript:alert%281337%29\n' +
|
||||
'Click: VBscript:alert%281337%29\nClick: Script:alert%281337%29\n' +
|
||||
'Click: flavascript:alert%281337%29',
|
||||
'Click: jscript:alert%281337%29\nClick: JSscript:alert%281337%29\n' +
|
||||
'Click: VBscript:alert%281337%29\nClick: Script:alert%281337%29\n' +
|
||||
'Click: flavascript:alert%281337%29');
|
||||
}
|
||||
|
||||
function testProtocolWhitelistingEffective() {
|
||||
assertLinkify(
|
||||
'Protocol whitelisting is effective.',
|
||||
'Click httpscript:alert%281337%29\nClick mailtoscript:alert%281337%29\n' +
|
||||
'Click j\u00A0avascript:alert%281337%29\n' +
|
||||
'Click \u00A0javascript:alert%281337%29',
|
||||
'Click httpscript:alert%281337%29\nClick mailtoscript:alert%281337%29\n' +
|
||||
'Click j\u00A0avascript:alert%281337%29\n' +
|
||||
'Click \u00A0javascript:alert%281337%29');
|
||||
}
|
||||
|
||||
function testLinkifyNoOptions() {
|
||||
div.innerHTML = goog.string.linkify.linkifyPlainText('http://www.google.com');
|
||||
goog.testing.dom.assertHtmlContentsMatch(
|
||||
'<a href="http://www.google.com" target="_blank" rel="nofollow">' +
|
||||
'http://www.google.com<\/a>',
|
||||
div, true /* opt_strictAttributes */);
|
||||
}
|
||||
|
||||
function testLinkifyOptionsNoAttributes() {
|
||||
div.innerHTML = goog.string.linkify.linkifyPlainText(
|
||||
'The link for www.google.com is located somewhere in ' +
|
||||
'https://www.google.fr/?hl=en, you should find it easily.',
|
||||
{rel: '', target: ''});
|
||||
goog.testing.dom.assertHtmlContentsMatch(
|
||||
'The link for <a href="http://www.google.com">www.google.com<\/a> is ' +
|
||||
'located somewhere in ' +
|
||||
'<a href="https://www.google.fr/?hl=en">https://www.google.fr/?hl=en' +
|
||||
'<\/a>, you should find it easily.',
|
||||
div, true /* opt_strictAttributes */);
|
||||
}
|
||||
|
||||
function testLinkifyOptionsClassName() {
|
||||
div.innerHTML = goog.string.linkify.linkifyPlainText(
|
||||
'Attribute with <class> name www.w3c.org.',
|
||||
{'class': 'link-added'});
|
||||
goog.testing.dom.assertHtmlContentsMatch(
|
||||
'Attribute with <class> name <a href="http://www.w3c.org" ' +
|
||||
'target="_blank" rel="nofollow" class="link-added">www.w3c.org<\/a>.',
|
||||
div, true /* opt_strictAttributes */);
|
||||
}
|
||||
|
||||
function testFindFirstUrlNoScheme() {
|
||||
assertEquals('www.google.com', goog.string.linkify.findFirstUrl(
|
||||
'www.google.com'));
|
||||
}
|
||||
|
||||
function testFindFirstUrlNoSchemeWithText() {
|
||||
assertEquals('www.google.com', goog.string.linkify.findFirstUrl(
|
||||
'prefix www.google.com something'));
|
||||
}
|
||||
|
||||
function testFindFirstUrlScheme() {
|
||||
assertEquals('http://www.google.com', goog.string.linkify.findFirstUrl(
|
||||
'http://www.google.com'));
|
||||
}
|
||||
|
||||
function testFindFirstUrlSchemeWithText() {
|
||||
assertEquals('http://www.google.com', goog.string.linkify.findFirstUrl(
|
||||
'prefix http://www.google.com something'));
|
||||
}
|
||||
|
||||
function testFindFirstUrlNoUrl() {
|
||||
assertEquals('', goog.string.linkify.findFirstUrl(
|
||||
'ygvtfr676 5v68fk uygbt85F^&%^&I%FVvc .'));
|
||||
}
|
||||
|
||||
function testFindFirstEmailNoScheme() {
|
||||
assertEquals('fake@google.com', goog.string.linkify.findFirstEmail(
|
||||
'fake@google.com'));
|
||||
}
|
||||
|
||||
function testFindFirstEmailNoSchemeWithText() {
|
||||
assertEquals('fake@google.com', goog.string.linkify.findFirstEmail(
|
||||
'prefix fake@google.com something'));
|
||||
}
|
||||
|
||||
function testFindFirstEmailScheme() {
|
||||
assertEquals('mailto:fake@google.com', goog.string.linkify.findFirstEmail(
|
||||
'mailto:fake@google.com'));
|
||||
}
|
||||
|
||||
function testFindFirstEmailSchemeWithText() {
|
||||
assertEquals('mailto:fake@google.com', goog.string.linkify.findFirstEmail(
|
||||
'prefix mailto:fake@google.com something'));
|
||||
}
|
||||
|
||||
function testFindFirstEmailNoUrl() {
|
||||
assertEquals('', goog.string.linkify.findFirstEmail(
|
||||
'ygvtfr676 5v68fk uygbt85F^&%^&I%FVvc .'));
|
||||
}
|
||||
|
||||
function testContainsPunctuation_parens() {
|
||||
assertLinkify(
|
||||
'Link contains parens, but does not end with them',
|
||||
'www.google.com/abc(v1).html',
|
||||
'<a href="http://www.google.com/abc(v1).html">' +
|
||||
'www.google.com/abc(v1).html<\/a>');
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation() {
|
||||
assertLinkify(
|
||||
'Link ends with punctuation',
|
||||
'Have you seen www.google.com? It\'s awesome.',
|
||||
'Have you seen <a href="http://www.google.com">www.google.com<\/a>?' +
|
||||
goog.string.htmlEscape(' It\'s awesome.'));
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation_closeParen() {
|
||||
assertLinkify(
|
||||
'Link inside parentheses',
|
||||
'(For more info see www.googl.com)',
|
||||
'(For more info see <a href="http://www.googl.com">www.googl.com<\/a>)');
|
||||
assertLinkify(
|
||||
'Parentheses inside link',
|
||||
'http://en.wikipedia.org/wiki/Titanic_(1997_film)',
|
||||
'<a href="http://en.wikipedia.org/wiki/Titanic_(1997_film)">' +
|
||||
'http://en.wikipedia.org/wiki/Titanic_(1997_film)<\/a>');
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation_openParen() {
|
||||
assertLinkify(
|
||||
'Link followed by open parenthesis',
|
||||
'www.google.com(',
|
||||
'<a href="http://www.google.com(">www.google.com(<\/a>');
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation_angles() {
|
||||
assertLinkify(
|
||||
'Link inside angled brackets',
|
||||
'Here is a bibliography entry <http://www.google.com/>',
|
||||
'Here is a bibliography entry <<a href="http://www.google.com/">' +
|
||||
'http://www.google.com/<\/a>>');
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation_closingPairThenSingle() {
|
||||
assertLinkify(
|
||||
'Link followed by closing punctuation pair then singular punctuation',
|
||||
'Here is a bibliography entry <http://www.google.com/>, PTAL.',
|
||||
'Here is a bibliography entry <<a href="http://www.google.com/">' +
|
||||
'http://www.google.com/<\/a>>, PTAL.');
|
||||
}
|
||||
|
||||
function testEndsWithPunctuation_ellipses() {
|
||||
assertLinkify(
|
||||
'Link followed by three dots',
|
||||
'just look it up on www.google.com...',
|
||||
'just look it up on <a href="http://www.google.com">www.google.com' +
|
||||
'<\/a>...');
|
||||
}
|
||||
|
||||
function testBracketsInUrl() {
|
||||
assertLinkify(
|
||||
'Link containing brackets',
|
||||
'before http://google.com/details?answer[0]=42 after',
|
||||
'before <a href="http://google.com/details?answer[0]=42">' +
|
||||
'http://google.com/details?answer[0]=42<\/a> after');
|
||||
}
|
||||
|
||||
function testUrlWithExclamation() {
|
||||
assertLinkify(
|
||||
'URL with exclamation points',
|
||||
'This is awesome www.google.com!',
|
||||
'This is awesome <a href="http://www.google.com">www.google.com<\/a>!');
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Utilities for string newlines.
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Namespace for string utilities
|
||||
*/
|
||||
goog.provide('goog.string.newlines');
|
||||
goog.provide('goog.string.newlines.Line');
|
||||
|
||||
goog.require('goog.array');
|
||||
|
||||
|
||||
/**
|
||||
* Splits a string into lines, properly handling universal newlines.
|
||||
* @param {string} str String to split.
|
||||
* @param {boolean=} opt_keepNewlines Whether to keep the newlines in the
|
||||
* resulting strings. Defaults to false.
|
||||
* @return {!Array<string>} String split into lines.
|
||||
*/
|
||||
goog.string.newlines.splitLines = function(str, opt_keepNewlines) {
|
||||
var lines = goog.string.newlines.getLines(str);
|
||||
return goog.array.map(lines, function(line) {
|
||||
return opt_keepNewlines ? line.getFullLine() : line.getContent();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Line metadata class that records the start/end indicies of lines
|
||||
* in a string. Can be used to implement common newline use cases such as
|
||||
* splitLines() or determining line/column of an index in a string.
|
||||
* Also implements methods to get line contents.
|
||||
*
|
||||
* Indexes are expressed as string indicies into string.substring(), inclusive
|
||||
* at the start, exclusive at the end.
|
||||
*
|
||||
* Create an array of these with goog.string.newlines.getLines().
|
||||
* @param {string} string The original string.
|
||||
* @param {number} startLineIndex The index of the start of the line.
|
||||
* @param {number} endContentIndex The index of the end of the line, excluding
|
||||
* newlines.
|
||||
* @param {number} endLineIndex The index of the end of the line, index
|
||||
* newlines.
|
||||
* @constructor
|
||||
* @struct
|
||||
* @final
|
||||
*/
|
||||
goog.string.newlines.Line = function(string, startLineIndex,
|
||||
endContentIndex, endLineIndex) {
|
||||
/**
|
||||
* The original string.
|
||||
* @type {string}
|
||||
*/
|
||||
this.string = string;
|
||||
|
||||
/**
|
||||
* Index of the start of the line.
|
||||
* @type {number}
|
||||
*/
|
||||
this.startLineIndex = startLineIndex;
|
||||
|
||||
/**
|
||||
* Index of the end of the line, excluding any newline characters.
|
||||
* Index is the first character after the line, suitable for
|
||||
* String.substring().
|
||||
* @type {number}
|
||||
*/
|
||||
this.endContentIndex = endContentIndex;
|
||||
|
||||
/**
|
||||
* Index of the end of the line, excluding any newline characters.
|
||||
* Index is the first character after the line, suitable for
|
||||
* String.substring().
|
||||
* @type {number}
|
||||
*/
|
||||
|
||||
this.endLineIndex = endLineIndex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The content of the line, excluding any newline characters.
|
||||
*/
|
||||
goog.string.newlines.Line.prototype.getContent = function() {
|
||||
return this.string.substring(this.startLineIndex, this.endContentIndex);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The full line, including any newline characters.
|
||||
*/
|
||||
goog.string.newlines.Line.prototype.getFullLine = function() {
|
||||
return this.string.substring(this.startLineIndex, this.endLineIndex);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The newline characters, if any ('\n', \r', '\r\n', '', etc).
|
||||
*/
|
||||
goog.string.newlines.Line.prototype.getNewline = function() {
|
||||
return this.string.substring(this.endContentIndex, this.endLineIndex);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Splits a string into an array of line metadata.
|
||||
* @param {string} str String to split.
|
||||
* @return {!Array<!goog.string.newlines.Line>} Array of line metadata.
|
||||
*/
|
||||
goog.string.newlines.getLines = function(str) {
|
||||
// We use the constructor because literals are evaluated only once in
|
||||
// < ES 3.1.
|
||||
// See http://www.mail-archive.com/es-discuss@mozilla.org/msg01796.html
|
||||
var re = RegExp('\r\n|\r|\n', 'g');
|
||||
var sliceIndex = 0;
|
||||
var result;
|
||||
var lines = [];
|
||||
|
||||
while (result = re.exec(str)) {
|
||||
var line = new goog.string.newlines.Line(
|
||||
str, sliceIndex, result.index, result.index + result[0].length);
|
||||
lines.push(line);
|
||||
|
||||
// remember where to start the slice from
|
||||
sliceIndex = re.lastIndex;
|
||||
}
|
||||
|
||||
// If the string does not end with a newline, add the last line.
|
||||
if (sliceIndex < str.length) {
|
||||
var line = new goog.string.newlines.Line(
|
||||
str, sliceIndex, str.length, str.length);
|
||||
lines.push(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Unit Tests - goog.string</title>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.string.newlinesTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Unit tests for goog.string.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.newlinesTest');
|
||||
|
||||
goog.require('goog.string.newlines');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
goog.setTestOnly('goog.string.newlinesTest');
|
||||
|
||||
// test for goog.string.splitLines
|
||||
function testSplitLines() {
|
||||
|
||||
/**
|
||||
* @param {!Array<string>} expected
|
||||
* @param {string} string
|
||||
* @param {boolean=} opt_keepNewlines
|
||||
*/
|
||||
function assertSplitLines(expected, string, opt_keepNewlines) {
|
||||
var keepNewlines = opt_keepNewlines || false;
|
||||
var lines = goog.string.newlines.splitLines(string, keepNewlines);
|
||||
assertElementsEquals(expected, lines);
|
||||
}
|
||||
|
||||
// Test values borrowed from Python's splitlines. http://goo.gl/iwawx
|
||||
assertSplitLines(['abc', 'def', '', 'ghi'], 'abc\ndef\n\rghi');
|
||||
assertSplitLines(['abc', 'def', '', 'ghi'], 'abc\ndef\n\r\nghi');
|
||||
assertSplitLines(['abc', 'def', 'ghi'], 'abc\ndef\r\nghi');
|
||||
assertSplitLines(['abc', 'def', 'ghi'], 'abc\ndef\r\nghi\n');
|
||||
assertSplitLines(['abc', 'def', 'ghi', ''], 'abc\ndef\r\nghi\n\r');
|
||||
assertSplitLines(['', 'abc', 'def', 'ghi', ''], '\nabc\ndef\r\nghi\n\r');
|
||||
assertSplitLines(['', 'abc', 'def', 'ghi', ''], '\nabc\ndef\r\nghi\n\r');
|
||||
assertSplitLines(['\n', 'abc\n', 'def\r\n', 'ghi\n', '\r'],
|
||||
'\nabc\ndef\r\nghi\n\r', true);
|
||||
assertSplitLines(['', 'abc', 'def', 'ghi', ''], '\nabc\ndef\r\nghi\n\r');
|
||||
assertSplitLines(['\n', 'abc\n', 'def\r\n', 'ghi\n', '\r'],
|
||||
'\nabc\ndef\r\nghi\n\r', true);
|
||||
}
|
||||
|
||||
function testGetLines() {
|
||||
var lines = goog.string.newlines.getLines('abc\ndef\n\rghi');
|
||||
|
||||
assertEquals(4, lines.length);
|
||||
|
||||
assertEquals(0, lines[0].startLineIndex);
|
||||
assertEquals(3, lines[0].endContentIndex);
|
||||
assertEquals(4, lines[0].endLineIndex);
|
||||
assertEquals('abc', lines[0].getContent());
|
||||
assertEquals('abc\n', lines[0].getFullLine());
|
||||
assertEquals('\n', lines[0].getNewline());
|
||||
|
||||
assertEquals(4, lines[1].startLineIndex);
|
||||
assertEquals(7, lines[1].endContentIndex);
|
||||
assertEquals(8, lines[1].endLineIndex);
|
||||
assertEquals('def', lines[1].getContent());
|
||||
assertEquals('def\n', lines[1].getFullLine());
|
||||
assertEquals('\n', lines[1].getNewline());
|
||||
|
||||
assertEquals(8, lines[2].startLineIndex);
|
||||
assertEquals(8, lines[2].endContentIndex);
|
||||
assertEquals(9, lines[2].endLineIndex);
|
||||
assertEquals('', lines[2].getContent());
|
||||
assertEquals('\r', lines[2].getFullLine());
|
||||
assertEquals('\r', lines[2].getNewline());
|
||||
|
||||
assertEquals(9, lines[3].startLineIndex);
|
||||
assertEquals(12, lines[3].endContentIndex);
|
||||
assertEquals(12, lines[3].endLineIndex);
|
||||
assertEquals('ghi', lines[3].getContent());
|
||||
assertEquals('ghi', lines[3].getFullLine());
|
||||
assertEquals('', lines[3].getNewline());
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Defines an interface for parsing strings into objects.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.Parser');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface for parsing strings into objects.
|
||||
* @interface
|
||||
*/
|
||||
goog.string.Parser = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Parses a string into an object and returns the result.
|
||||
* Agnostic to the format of string and object.
|
||||
*
|
||||
* @param {string} s The string to parse.
|
||||
* @return {*} The object generated from the string.
|
||||
*/
|
||||
goog.string.Parser.prototype.parse;
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Utilities for dealing with POSIX path strings. Based on
|
||||
* Python's os.path and posixpath.
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.path');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* Returns the final component of a pathname.
|
||||
* See http://docs.python.org/library/os.path.html#os.path.basename
|
||||
* @param {string} path A pathname.
|
||||
* @return {string} path The final component of a pathname, i.e. everything
|
||||
* after the final slash.
|
||||
*/
|
||||
goog.string.path.baseName = function(path) {
|
||||
var i = path.lastIndexOf('/') + 1;
|
||||
return path.slice(i);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Alias to goog.string.path.baseName.
|
||||
* @param {string} path A pathname.
|
||||
* @return {string} path The final component of a pathname.
|
||||
* @deprecated Use goog.string.path.baseName.
|
||||
*/
|
||||
goog.string.path.basename = goog.string.path.baseName;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the directory component of a pathname.
|
||||
* See http://docs.python.org/library/os.path.html#os.path.dirname
|
||||
* @param {string} path A pathname.
|
||||
* @return {string} The directory component of a pathname, i.e. everything
|
||||
* leading up to the final slash.
|
||||
*/
|
||||
goog.string.path.dirname = function(path) {
|
||||
var i = path.lastIndexOf('/') + 1;
|
||||
var head = path.slice(0, i);
|
||||
// If the path isn't all forward slashes, trim the trailing slashes.
|
||||
if (!/^\/+$/.test(head)) {
|
||||
head = head.replace(/\/+$/, '');
|
||||
}
|
||||
return head;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the extension part of a pathname.
|
||||
* @param {string} path The path name to process.
|
||||
* @return {string} The extension if any, otherwise the empty string.
|
||||
*/
|
||||
goog.string.path.extension = function(path) {
|
||||
var separator = '.';
|
||||
// Combining all adjacent periods in the basename to a single period.
|
||||
var baseName = goog.string.path.baseName(path).replace(/\.+/g, separator);
|
||||
var separatorIndex = baseName.lastIndexOf(separator);
|
||||
return separatorIndex <= 0 ? '' : baseName.substr(separatorIndex + 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Joins one or more path components (e.g. 'foo/' and 'bar' make 'foo/bar').
|
||||
* An absolute component will discard all previous component.
|
||||
* See http://docs.python.org/library/os.path.html#os.path.join
|
||||
* @param {...string} var_args One of more path components.
|
||||
* @return {string} The path components joined.
|
||||
*/
|
||||
goog.string.path.join = function(var_args) {
|
||||
var path = arguments[0];
|
||||
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var arg = arguments[i];
|
||||
if (goog.string.startsWith(arg, '/')) {
|
||||
path = arg;
|
||||
} else if (path == '' || goog.string.endsWith(path, '/')) {
|
||||
path += arg;
|
||||
} else {
|
||||
path += '/' + arg;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes a pathname by collapsing duplicate separators, parent directory
|
||||
* references ('..'), and current directory references ('.').
|
||||
* See http://docs.python.org/library/os.path.html#os.path.normpath
|
||||
* @param {string} path One or more path components.
|
||||
* @return {string} The path after normalization.
|
||||
*/
|
||||
goog.string.path.normalizePath = function(path) {
|
||||
if (path == '') {
|
||||
return '.';
|
||||
}
|
||||
|
||||
var initialSlashes = '';
|
||||
// POSIX will keep two slashes, but three or more will be collapsed to one.
|
||||
if (goog.string.startsWith(path, '/')) {
|
||||
initialSlashes = '/';
|
||||
if (goog.string.startsWith(path, '//') &&
|
||||
!goog.string.startsWith(path, '///')) {
|
||||
initialSlashes = '//';
|
||||
}
|
||||
}
|
||||
|
||||
var parts = path.split('/');
|
||||
var newParts = [];
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var part = parts[i];
|
||||
|
||||
// '' and '.' don't change the directory, ignore.
|
||||
if (part == '' || part == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// A '..' should pop a directory unless this is not an absolute path and
|
||||
// we're at the root, or we've travelled upwards relatively in the last
|
||||
// iteration.
|
||||
if (part != '..' ||
|
||||
(!initialSlashes && !newParts.length) ||
|
||||
goog.array.peek(newParts) == '..') {
|
||||
newParts.push(part);
|
||||
} else {
|
||||
newParts.pop();
|
||||
}
|
||||
}
|
||||
|
||||
var returnPath = initialSlashes + newParts.join('/');
|
||||
return returnPath || '.';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Splits a pathname into "dirname" and "baseName" components, where "baseName"
|
||||
* is everything after the final slash. Either part may return an empty string.
|
||||
* See http://docs.python.org/library/os.path.html#os.path.split
|
||||
* @param {string} path A pathname.
|
||||
* @return {!Array<string>} An array of [dirname, basename].
|
||||
*/
|
||||
goog.string.path.split = function(path) {
|
||||
var head = goog.string.path.dirname(path);
|
||||
var tail = goog.string.path.baseName(path);
|
||||
return [head, tail];
|
||||
};
|
||||
|
||||
// TODO(nnaze): Implement other useful functions from os.path
|
||||
@@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<title>
|
||||
Closure Unit Tests - goog.string.path
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.string.pathTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2010 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.string.pathTest');
|
||||
goog.setTestOnly('goog.string.pathTest');
|
||||
|
||||
goog.require('goog.string.path');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// Some test data comes from Python's posixpath tests.
|
||||
// See http://svn.python.org/view/python/trunk/Lib/test/test_posixpath.py
|
||||
|
||||
function testBasename() {
|
||||
assertEquals('bar', goog.string.path.baseName('/foo/bar'));
|
||||
assertEquals('', goog.string.path.baseName('/'));
|
||||
assertEquals('foo', goog.string.path.baseName('foo'));
|
||||
assertEquals('foo', goog.string.path.baseName('////foo'));
|
||||
assertEquals('bar', goog.string.path.baseName('//foo//bar'));
|
||||
}
|
||||
|
||||
function testDirname() {
|
||||
assertEquals('/foo', goog.string.path.dirname('/foo/bar'));
|
||||
assertEquals('/', goog.string.path.dirname('/'));
|
||||
assertEquals('', goog.string.path.dirname('foo'));
|
||||
assertEquals('////', goog.string.path.dirname('////foo'));
|
||||
assertEquals('//foo', goog.string.path.dirname('//foo//bar'));
|
||||
}
|
||||
|
||||
function testJoin() {
|
||||
assertEquals('/bar/baz',
|
||||
goog.string.path.join('/foo', 'bar', '/bar', 'baz'));
|
||||
assertEquals('/foo/bar/baz',
|
||||
goog.string.path.join('/foo', 'bar', 'baz'));
|
||||
assertEquals('/foo/bar/baz',
|
||||
goog.string.path.join('/foo/', 'bar', 'baz'));
|
||||
assertEquals('/foo/bar/baz/',
|
||||
goog.string.path.join('/foo/', 'bar/', 'baz/'));
|
||||
}
|
||||
|
||||
function testNormalizePath() {
|
||||
assertEquals('.', goog.string.path.normalizePath(''));
|
||||
assertEquals('.', goog.string.path.normalizePath('./'));
|
||||
assertEquals('/', goog.string.path.normalizePath('/'));
|
||||
assertEquals('//', goog.string.path.normalizePath('//'));
|
||||
assertEquals('/', goog.string.path.normalizePath('///'));
|
||||
assertEquals('/foo/bar',
|
||||
goog.string.path.normalizePath('///foo/.//bar//'));
|
||||
assertEquals('/foo/baz',
|
||||
goog.string.path.normalizePath('///foo/.//bar//.//..//.//baz'));
|
||||
assertEquals('/foo/bar',
|
||||
goog.string.path.normalizePath('///..//./foo/.//bar'));
|
||||
assertEquals('../../cat/dog',
|
||||
goog.string.path.normalizePath('../../cat/dog/'));
|
||||
assertEquals('../dog',
|
||||
goog.string.path.normalizePath('../cat/../dog/'));
|
||||
assertEquals('/cat/dog',
|
||||
goog.string.path.normalizePath('/../cat/dog/'));
|
||||
assertEquals('/dog',
|
||||
goog.string.path.normalizePath('/../cat/../dog'));
|
||||
assertEquals('/dog',
|
||||
goog.string.path.normalizePath('/../../../dog'));
|
||||
}
|
||||
|
||||
function testSplit() {
|
||||
assertArrayEquals(['/foo', 'bar'], goog.string.path.split('/foo/bar'));
|
||||
assertArrayEquals(['/', ''], goog.string.path.split('/'));
|
||||
assertArrayEquals(['', 'foo'], goog.string.path.split('foo'));
|
||||
assertArrayEquals(['////', 'foo'], goog.string.path.split('////foo'));
|
||||
assertArrayEquals(['//foo', 'bar'], goog.string.path.split('//foo//bar'));
|
||||
}
|
||||
|
||||
function testExtension() {
|
||||
assertEquals('jpg', goog.string.path.extension('././foo/bar/baz.jpg'));
|
||||
assertEquals('jpg', goog.string.path.extension('././foo bar/baz.jpg'));
|
||||
assertEquals('jpg', goog.string.path.extension(
|
||||
'foo/bar/baz/blah blah.jpg'));
|
||||
assertEquals('', goog.string.path.extension('../../foo/bar/baz baz'));
|
||||
assertEquals('', goog.string.path.extension('../../foo bar/baz baz'));
|
||||
assertEquals('', goog.string.path.extension('foo/bar/.'));
|
||||
assertEquals('', goog.string.path.extension(' '));
|
||||
assertEquals('', goog.string.path.extension(''));
|
||||
assertEquals('', goog.string.path.extension('/home/username/.bashrc'));
|
||||
|
||||
// Tests cases taken from python os.path.splitext().
|
||||
assertEquals('bar', goog.string.path.extension('foo.bar'));
|
||||
assertEquals('bar', goog.string.path.extension('foo.boo.bar'));
|
||||
assertEquals('bar', goog.string.path.extension('foo.boo.biff.bar'));
|
||||
assertEquals('rc', goog.string.path.extension('.csh.rc'));
|
||||
assertEquals('', goog.string.path.extension('nodots'));
|
||||
assertEquals('', goog.string.path.extension('.cshrc'));
|
||||
assertEquals('', goog.string.path.extension('...manydots'));
|
||||
assertEquals('ext', goog.string.path.extension('...manydots.ext'));
|
||||
assertEquals('', goog.string.path.extension('.'));
|
||||
assertEquals('', goog.string.path.extension('..'));
|
||||
assertEquals('', goog.string.path.extension('........'));
|
||||
assertEquals('', goog.string.path.extension(''));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Closure Unit Tests - goog.string</title>
|
||||
<script src="../base.js"></script>
|
||||
<script>
|
||||
goog.require('goog.stringTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
// Copyright 2006 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Utility for fast string concatenation.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.StringBuffer');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Utility class to facilitate string concatenation.
|
||||
*
|
||||
* @param {*=} opt_a1 Optional first initial item to append.
|
||||
* @param {...*} var_args Other initial items to
|
||||
* append, e.g., new goog.string.StringBuffer('foo', 'bar').
|
||||
* @constructor
|
||||
*/
|
||||
goog.string.StringBuffer = function(opt_a1, var_args) {
|
||||
if (opt_a1 != null) {
|
||||
this.append.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Internal buffer for the string to be concatenated.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.buffer_ = '';
|
||||
|
||||
|
||||
/**
|
||||
* Sets the contents of the string buffer object, replacing what's currently
|
||||
* there.
|
||||
*
|
||||
* @param {*} s String to set.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.set = function(s) {
|
||||
this.buffer_ = '' + s;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Appends one or more items to the buffer.
|
||||
*
|
||||
* Calling this with null, undefined, or empty arguments is an error.
|
||||
*
|
||||
* @param {*} a1 Required first string.
|
||||
* @param {*=} opt_a2 Optional second string.
|
||||
* @param {...*} var_args Other items to append,
|
||||
* e.g., sb.append('foo', 'bar', 'baz').
|
||||
* @return {!goog.string.StringBuffer} This same StringBuffer object.
|
||||
* @suppress {duplicate}
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
|
||||
// Use a1 directly to avoid arguments instantiation for single-arg case.
|
||||
this.buffer_ += a1;
|
||||
if (opt_a2 != null) { // second argument is undefined (null == undefined)
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
this.buffer_ += arguments[i];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the internal buffer.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.clear = function() {
|
||||
this.buffer_ = '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} the length of the current contents of the buffer.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.getLength = function() {
|
||||
return this.buffer_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The concatenated string.
|
||||
* @override
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.toString = function() {
|
||||
return this.buffer_;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.string.StringBuffer
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.string.StringBufferTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2006 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.string.StringBufferTest');
|
||||
goog.setTestOnly('goog.string.StringBufferTest');
|
||||
|
||||
goog.require('goog.string.StringBuffer');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testStringBuffer() {
|
||||
var sb = new goog.string.StringBuffer();
|
||||
sb.append('Four score');
|
||||
sb.append(' ');
|
||||
sb.append('and seven years ago.');
|
||||
assertEquals('Test 1', 'Four score and seven years ago.', sb.toString());
|
||||
|
||||
sb.clear();
|
||||
assertEquals('Test 2', '', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer('Four score ');
|
||||
sb.append('and seven years ago.');
|
||||
assertEquals('Test 3', 'Four score and seven years ago.', sb.toString());
|
||||
|
||||
// can pass in non-Strings?
|
||||
sb = new goog.string.StringBuffer(1);
|
||||
sb.append(2);
|
||||
assertEquals('Test 4', '12', sb.toString());
|
||||
}
|
||||
|
||||
|
||||
function testStringBufferSet() {
|
||||
var sb = new goog.string.StringBuffer('foo');
|
||||
sb.set('bar');
|
||||
assertEquals('Test 1', 'bar', sb.toString());
|
||||
}
|
||||
|
||||
|
||||
function testStringBufferMultiAppend() {
|
||||
var sb = new goog.string.StringBuffer('hey', 'foo');
|
||||
sb.append('bar', 'baz');
|
||||
assertEquals('Test 1', 'heyfoobarbaz', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer();
|
||||
sb.append(1, 2);
|
||||
// should not add up to '3'
|
||||
assertEquals('Test 2', '12', sb.toString());
|
||||
}
|
||||
|
||||
|
||||
function testStringBufferToString() {
|
||||
var sb = new goog.string.StringBuffer('foo', 'bar');
|
||||
assertEquals('Test 1', 'foobar', sb.toString());
|
||||
}
|
||||
|
||||
|
||||
function testStringBufferWithFalseFirstArgument() {
|
||||
var sb = new goog.string.StringBuffer(0, 'more');
|
||||
assertEquals('Test 1', '0more', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer(false, 'more');
|
||||
assertEquals('Test 2', 'falsemore', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer('', 'more');
|
||||
assertEquals('Test 3', 'more', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer(null, 'more');
|
||||
assertEquals('Test 4', '', sb.toString());
|
||||
|
||||
sb = new goog.string.StringBuffer(undefined, 'more');
|
||||
assertEquals('Test 5', '', sb.toString());
|
||||
}
|
||||
|
||||
|
||||
function testStringBufferGetLength() {
|
||||
var sb = new goog.string.StringBuffer();
|
||||
assertEquals(0, sb.getLength());
|
||||
|
||||
sb.append('foo');
|
||||
assertEquals(3, sb.getLength());
|
||||
|
||||
sb.append('baroo');
|
||||
assertEquals(8, sb.getLength());
|
||||
|
||||
sb.clear();
|
||||
assertEquals(0, sb.getLength());
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
// Copyright 2008 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Implementation of sprintf-like, python-%-operator-like,
|
||||
* .NET-String.Format-like functionality. Uses JS string's replace method to
|
||||
* extract format specifiers and sends those specifiers to a handler function,
|
||||
* which then, based on conversion type part of the specifier, calls the
|
||||
* appropriate function to handle the specific conversion.
|
||||
* For specific functionality implemented, look at formatRe below, or look
|
||||
* at the tests.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.format');
|
||||
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* Performs sprintf-like conversion, ie. puts the values in a template.
|
||||
* DO NOT use it instead of built-in conversions in simple cases such as
|
||||
* 'Cost: %.2f' as it would introduce unneccessary latency oposed to
|
||||
* 'Cost: ' + cost.toFixed(2).
|
||||
* @param {string} formatString Template string containing % specifiers.
|
||||
* @param {...string|number} var_args Values formatString is to be filled with.
|
||||
* @return {string} Formatted string.
|
||||
*/
|
||||
goog.string.format = function(formatString, var_args) {
|
||||
|
||||
// Convert the arguments to an array (MDC recommended way).
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
// Try to get the template.
|
||||
var template = args.shift();
|
||||
if (typeof template == 'undefined') {
|
||||
throw Error('[goog.string.format] Template required');
|
||||
}
|
||||
|
||||
// This re is used for matching, it also defines what is supported.
|
||||
var formatRe = /%([0\-\ \+]*)(\d+)?(\.(\d+))?([%sfdiu])/g;
|
||||
|
||||
/**
|
||||
* Chooses which conversion function to call based on type conversion
|
||||
* specifier.
|
||||
* @param {string} match Contains the re matched string.
|
||||
* @param {string} flags Formatting flags.
|
||||
* @param {string} width Replacement string minimum width.
|
||||
* @param {string} dotp Matched precision including a dot.
|
||||
* @param {string} precision Specifies floating point precision.
|
||||
* @param {string} type Type conversion specifier.
|
||||
* @param {string} offset Matching location in the original string.
|
||||
* @param {string} wholeString Has the actualString being searched.
|
||||
* @return {string} Formatted parameter.
|
||||
*/
|
||||
function replacerDemuxer(match,
|
||||
flags,
|
||||
width,
|
||||
dotp,
|
||||
precision,
|
||||
type,
|
||||
offset,
|
||||
wholeString) {
|
||||
|
||||
// The % is too simple and doesn't take an argument.
|
||||
if (type == '%') {
|
||||
return '%';
|
||||
}
|
||||
|
||||
// Try to get the actual value from parent function.
|
||||
var value = args.shift();
|
||||
|
||||
// If we didn't get any arguments, fail.
|
||||
if (typeof value == 'undefined') {
|
||||
throw Error('[goog.string.format] Not enough arguments');
|
||||
}
|
||||
|
||||
// Patch the value argument to the beginning of our type specific call.
|
||||
arguments[0] = value;
|
||||
|
||||
return goog.string.format.demuxes_[type].apply(null, arguments);
|
||||
|
||||
}
|
||||
|
||||
return template.replace(formatRe, replacerDemuxer);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Contains various conversion functions (to be filled in later on).
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.string.format.demuxes_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Processes %s conversion specifier.
|
||||
* @param {string} value Contains the formatRe matched string.
|
||||
* @param {string} flags Formatting flags.
|
||||
* @param {string} width Replacement string minimum width.
|
||||
* @param {string} dotp Matched precision including a dot.
|
||||
* @param {string} precision Specifies floating point precision.
|
||||
* @param {string} type Type conversion specifier.
|
||||
* @param {string} offset Matching location in the original string.
|
||||
* @param {string} wholeString Has the actualString being searched.
|
||||
* @return {string} Replacement string.
|
||||
*/
|
||||
goog.string.format.demuxes_['s'] = function(value,
|
||||
flags,
|
||||
width,
|
||||
dotp,
|
||||
precision,
|
||||
type,
|
||||
offset,
|
||||
wholeString) {
|
||||
var replacement = value;
|
||||
// If no padding is necessary we're done.
|
||||
// The check for '' is necessary because Firefox incorrectly provides the
|
||||
// empty string instead of undefined for non-participating capture groups,
|
||||
// and isNaN('') == false.
|
||||
if (isNaN(width) || width == '' || replacement.length >= width) {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
// Otherwise we should find out where to put spaces.
|
||||
if (flags.indexOf('-', 0) > -1) {
|
||||
replacement =
|
||||
replacement + goog.string.repeat(' ', width - replacement.length);
|
||||
} else {
|
||||
replacement =
|
||||
goog.string.repeat(' ', width - replacement.length) + replacement;
|
||||
}
|
||||
return replacement;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Processes %f conversion specifier.
|
||||
* @param {number} value Contains the formatRe matched string.
|
||||
* @param {string} flags Formatting flags.
|
||||
* @param {string} width Replacement string minimum width.
|
||||
* @param {string} dotp Matched precision including a dot.
|
||||
* @param {string} precision Specifies floating point precision.
|
||||
* @param {string} type Type conversion specifier.
|
||||
* @param {string} offset Matching location in the original string.
|
||||
* @param {string} wholeString Has the actualString being searched.
|
||||
* @return {string} Replacement string.
|
||||
*/
|
||||
goog.string.format.demuxes_['f'] = function(value,
|
||||
flags,
|
||||
width,
|
||||
dotp,
|
||||
precision,
|
||||
type,
|
||||
offset,
|
||||
wholeString) {
|
||||
|
||||
var replacement = value.toString();
|
||||
|
||||
// The check for '' is necessary because Firefox incorrectly provides the
|
||||
// empty string instead of undefined for non-participating capture groups,
|
||||
// and isNaN('') == false.
|
||||
if (!(isNaN(precision) || precision == '')) {
|
||||
replacement = value.toFixed(precision);
|
||||
}
|
||||
|
||||
// Generates sign string that will be attached to the replacement.
|
||||
var sign;
|
||||
if (value < 0) {
|
||||
sign = '-';
|
||||
} else if (flags.indexOf('+') >= 0) {
|
||||
sign = '+';
|
||||
} else if (flags.indexOf(' ') >= 0) {
|
||||
sign = ' ';
|
||||
} else {
|
||||
sign = '';
|
||||
}
|
||||
|
||||
if (value >= 0) {
|
||||
replacement = sign + replacement;
|
||||
}
|
||||
|
||||
// If no padding is neccessary we're done.
|
||||
if (isNaN(width) || replacement.length >= width) {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
// We need a clean signless replacement to start with
|
||||
replacement = isNaN(precision) ?
|
||||
Math.abs(value).toString() :
|
||||
Math.abs(value).toFixed(precision);
|
||||
|
||||
var padCount = width - replacement.length - sign.length;
|
||||
|
||||
// Find out which side to pad, and if it's left side, then which character to
|
||||
// pad, and set the sign on the left and padding in the middle.
|
||||
if (flags.indexOf('-', 0) >= 0) {
|
||||
replacement = sign + replacement + goog.string.repeat(' ', padCount);
|
||||
} else {
|
||||
// Decides which character to pad.
|
||||
var paddingChar = (flags.indexOf('0', 0) >= 0) ? '0' : ' ';
|
||||
replacement =
|
||||
sign + goog.string.repeat(paddingChar, padCount) + replacement;
|
||||
}
|
||||
|
||||
return replacement;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Processes %d conversion specifier.
|
||||
* @param {string} value Contains the formatRe matched string.
|
||||
* @param {string} flags Formatting flags.
|
||||
* @param {string} width Replacement string minimum width.
|
||||
* @param {string} dotp Matched precision including a dot.
|
||||
* @param {string} precision Specifies floating point precision.
|
||||
* @param {string} type Type conversion specifier.
|
||||
* @param {string} offset Matching location in the original string.
|
||||
* @param {string} wholeString Has the actualString being searched.
|
||||
* @return {string} Replacement string.
|
||||
*/
|
||||
goog.string.format.demuxes_['d'] = function(value,
|
||||
flags,
|
||||
width,
|
||||
dotp,
|
||||
precision,
|
||||
type,
|
||||
offset,
|
||||
wholeString) {
|
||||
return goog.string.format.demuxes_['f'](
|
||||
parseInt(value, 10) /* value */,
|
||||
flags, width, dotp, 0 /* precision */,
|
||||
type, offset, wholeString);
|
||||
};
|
||||
|
||||
|
||||
// These are additional aliases, for integer conversion.
|
||||
goog.string.format.demuxes_['i'] = goog.string.format.demuxes_['d'];
|
||||
goog.string.format.demuxes_['u'] = goog.string.format.demuxes_['d'];
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.string.format
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.string.formatTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright 2008 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.string.formatTest');
|
||||
goog.setTestOnly('goog.string.formatTest');
|
||||
|
||||
goog.require('goog.string.format');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// The discussion on naming this functionality is going on.
|
||||
var f = goog.string.format;
|
||||
|
||||
function testImmediateFormatSpecifier() {
|
||||
assertEquals('Empty String', '', f(''));
|
||||
assertEquals('Immediate Value', 'Immediate Value', f('Immediate Value'));
|
||||
}
|
||||
|
||||
function testPercentSign() {
|
||||
assertEquals('%', '%', f('%'));
|
||||
assertEquals('%%', '%', f('%%'));
|
||||
assertEquals('%%%', '%%', f('%%%'));
|
||||
assertEquals('%%%%', '%%', f('%%%%'));
|
||||
|
||||
assertEquals('width of the percent sign ???', '%%', f('%345%%-67.987%'));
|
||||
}
|
||||
|
||||
function testStringConversionSpecifier() {
|
||||
assertEquals('%s', 'abc', f('%s', 'abc'));
|
||||
assertEquals('%2s', 'abc', f('%2s', 'abc'));
|
||||
assertEquals('%6s', ' abc', f('%6s', 'abc'));
|
||||
assertEquals('%-6s', 'abc ', f('%-6s', 'abc'));
|
||||
}
|
||||
|
||||
function testFloatConversionSpecifier() {
|
||||
assertEquals('%f', '123', f('%f', 123));
|
||||
assertEquals('%f', '0.1', f('%f', 0.1));
|
||||
assertEquals('%f', '123.456', f('%f', 123.456));
|
||||
|
||||
// Precisions, paddings and other flags are handled on a flag to flag basis.
|
||||
|
||||
}
|
||||
|
||||
function testAliasedConversionSpecifiers() {
|
||||
assertEquals('%i vs. %d', f('%i', 123), f('%d', 123));
|
||||
assertEquals('%u vs. %d', f('%u', 123), f('%d', 123));
|
||||
}
|
||||
|
||||
function testIntegerConversion() {
|
||||
assertEquals('%d', '0', f('%d', 0));
|
||||
|
||||
assertEquals('%d', '123', f('%d', 123));
|
||||
assertEquals('%d', '0', f('%d', 0.1));
|
||||
assertEquals('%d', '0', f('%d', 0.9));
|
||||
assertEquals('%d', '123', f('%d', 123.456));
|
||||
|
||||
assertEquals('%d', '-1', f('%d', -1));
|
||||
assertEquals('%d', '0', f('%d', -0.1));
|
||||
assertEquals('%d', '0', f('%d', -0.9));
|
||||
assertEquals('%d', '-123', f('%d', -123.456));
|
||||
|
||||
// Precisions, paddings and other flags are handled on a flag to flag basis.
|
||||
|
||||
}
|
||||
|
||||
function testSpaceFlag() {
|
||||
assertEquals('zero %+d ', ' 0', f('% d', 0));
|
||||
|
||||
assertEquals('positive % d ', ' 123', f('% d', 123));
|
||||
assertEquals('negative % d ', '-123', f('% d', -123));
|
||||
|
||||
assertEquals('positive % 3d', ' 123', f('% 3d', 123));
|
||||
assertEquals('negative % 3d', '-123', f('% 3d', -123));
|
||||
|
||||
assertEquals('positive % 4d', ' 123', f('% 4d', 123));
|
||||
assertEquals('negative % 4d', '-123', f('% 4d', -123));
|
||||
|
||||
assertEquals('positive % 6d', ' 123', f('% 6d', 123));
|
||||
assertEquals('negative % 6d', '- 123', f('% 6d', -123));
|
||||
|
||||
assertEquals('positive % f ', ' 123.456', f('% f', 123.456));
|
||||
assertEquals('negative % f ', '-123.456', f('% f', -123.456));
|
||||
|
||||
assertEquals('positive % .2f ', ' 123.46', f('% .2f', 123.456));
|
||||
assertEquals('negative % .2f ', '-123.46', f('% .2f', -123.456));
|
||||
|
||||
assertEquals('positive % 6.2f', ' 123.46', f('% 6.2f', 123.456));
|
||||
assertEquals('negative % 6.2f', '-123.46', f('% 6.2f', -123.456));
|
||||
|
||||
assertEquals('positive % 7.2f', ' 123.46', f('% 7.2f', 123.456));
|
||||
assertEquals('negative % 7.2f', '-123.46', f('% 7.2f', -123.456));
|
||||
|
||||
assertEquals('positive % 10.2f', ' 123.46', f('% 10.2f', 123.456));
|
||||
assertEquals('negative % 10.2f', '- 123.46', f('% 10.2f', -123.456));
|
||||
|
||||
assertEquals('string % s ', 'abc', f('% s', 'abc'));
|
||||
assertEquals('string % 3s', 'abc', f('% 3s', 'abc'));
|
||||
assertEquals('string % 4s', ' abc', f('% 4s', 'abc'));
|
||||
assertEquals('string % 6s', ' abc', f('% 6s', 'abc'));
|
||||
}
|
||||
|
||||
function testPlusFlag() {
|
||||
assertEquals('zero %+d ', '+0', f('%+d', 0));
|
||||
|
||||
assertEquals('positive %+d ', '+123', f('%+d', 123));
|
||||
assertEquals('negative %+d ', '-123', f('%+d', -123));
|
||||
|
||||
assertEquals('positive %+3d', '+123', f('%+3d', 123));
|
||||
assertEquals('negative %+3d', '-123', f('%+3d', -123));
|
||||
|
||||
assertEquals('positive %+4d', '+123', f('%+4d', 123));
|
||||
assertEquals('negative %+4d', '-123', f('%+4d', -123));
|
||||
|
||||
assertEquals('positive %+6d', '+ 123', f('%+6d', 123));
|
||||
assertEquals('negative %+6d', '- 123', f('%+6d', -123));
|
||||
|
||||
assertEquals('positive %+f ', '+123.456', f('%+f', 123.456));
|
||||
assertEquals('negative %+f ', '-123.456', f('%+f', -123.456));
|
||||
|
||||
assertEquals('positive %+.2f ', '+123.46', f('%+.2f', 123.456));
|
||||
assertEquals('negative %+.2f ', '-123.46', f('%+.2f', -123.456));
|
||||
|
||||
assertEquals('positive %+6.2f', '+123.46', f('%+6.2f', 123.456));
|
||||
assertEquals('negative %+6.2f', '-123.46', f('%+6.2f', -123.456));
|
||||
|
||||
assertEquals('positive %+7.2f', '+123.46', f('%+7.2f', 123.456));
|
||||
assertEquals('negative %+7.2f', '-123.46', f('%+7.2f', -123.456));
|
||||
|
||||
assertEquals('positive %+10.2f', '+ 123.46', f('%+10.2f', 123.456));
|
||||
assertEquals('negative %+10.2f', '- 123.46', f('%+10.2f', -123.456));
|
||||
|
||||
assertEquals('string %+s ', 'abc', f('%+s', 'abc'));
|
||||
assertEquals('string %+3s', 'abc', f('%+3s', 'abc'));
|
||||
assertEquals('string %+4s', ' abc', f('%+4s', 'abc'));
|
||||
assertEquals('string %+6s', ' abc', f('%+6s', 'abc'));
|
||||
}
|
||||
|
||||
function testPrecision() {
|
||||
assertEquals('%.5d', '0', f('%.5d', 0));
|
||||
|
||||
assertEquals('%d', '123', f('%d', 123.456));
|
||||
assertEquals('%.2d', '123', f('%.2d', 123.456));
|
||||
|
||||
assertEquals('%f', '123.456', f('%f', 123.456));
|
||||
assertEquals('%.2f', '123.46', f('%.2f', 123.456));
|
||||
|
||||
assertEquals('%.3f', '123.456', f('%.3f', 123.456));
|
||||
assertEquals('%.6f', '123.456000', f('%.6f', 123.456));
|
||||
assertEquals('%1.2f', '123.46', f('%1.2f', 123.456));
|
||||
assertEquals('%7.2f', ' 123.46', f('%7.2f', 123.456));
|
||||
|
||||
assertEquals('%5.6f', '123.456000', f('%5.6f', 123.456));
|
||||
assertEquals('%11.6f', ' 123.456000', f('%11.6f', 123.456));
|
||||
|
||||
assertEquals('%07.2f', '0123.46', f('%07.2f', 123.456));
|
||||
assertEquals('%+7.2f', '+123.46', f('%+7.2f', 123.456));
|
||||
}
|
||||
|
||||
function testZeroFlag() {
|
||||
assertEquals('%0s', 'abc', f('%0s', 'abc'));
|
||||
assertEquals('%02s', 'abc', f('%02s', 'abc'));
|
||||
assertEquals('%06s', ' abc', f('%06s', 'abc'));
|
||||
|
||||
assertEquals('%0d', '123', f('%0d', 123));
|
||||
assertEquals('%0d', '-123', f('%0d', -123));
|
||||
assertEquals('%06d', '000123', f('%06d', 123));
|
||||
assertEquals('%06d', '-00123', f('%06d', -123));
|
||||
assertEquals('%010d', '0000000123', f('%010d', 123));
|
||||
assertEquals('%010d', '-000000123', f('%010d', -123));
|
||||
}
|
||||
|
||||
function testFlagMinus() {
|
||||
assertEquals('%-s', 'abc', f('%-s', 'abc'));
|
||||
assertEquals('%-2s', 'abc', f('%-2s', 'abc'));
|
||||
assertEquals('%-6s', 'abc ', f('%-6s', 'abc'));
|
||||
|
||||
assertEquals('%-d', '123', f('%-d', 123));
|
||||
assertEquals('%-d', '-123', f('%-d', -123));
|
||||
assertEquals('%-2d', '123', f('%-2d', 123));
|
||||
assertEquals('%-2d', '-123', f('%-2d', -123));
|
||||
assertEquals('%-4d', '123 ', f('%-4d', 123));
|
||||
assertEquals('%-4d', '-123', f('%-4d', -123));
|
||||
|
||||
assertEquals('%-d', '123', f('%-0d', 123));
|
||||
assertEquals('%-d', '-123', f('%-0d', -123));
|
||||
assertEquals('%-4d', '123 ', f('%-04d', 123));
|
||||
assertEquals('%-4d', '-123', f('%-04d', -123));
|
||||
}
|
||||
|
||||
function testExceptions() {
|
||||
var e = assertThrows(goog.partial(f, '%f%f', 123.456));
|
||||
assertEquals('[goog.string.format] Not enough arguments', e.message);
|
||||
|
||||
e = assertThrows(f);
|
||||
assertEquals('[goog.string.format] Template required', e.message);
|
||||
}
|
||||
|
||||
function testNonParticipatingGroupHandling() {
|
||||
// Firefox supplies empty string instead of undefined for non-participating
|
||||
// capture groups. This can trigger bad behavior if a demuxer only checks
|
||||
// isNaN(val) and not also val == ''. Check for regressions.
|
||||
var format = '%s %d %i %u';
|
||||
var expected = '1 2 3 4';
|
||||
// Good types
|
||||
assertEquals(expected, goog.string.format(format, 1, '2', '3', '4'));
|
||||
// Bad types
|
||||
assertEquals(expected, goog.string.format(format, '1', 2, 3, 4));
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Defines an interface for serializing objects into strings.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.Stringifier');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface for serializing objects into strings.
|
||||
* @interface
|
||||
*/
|
||||
goog.string.Stringifier = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes an object or a value to a string.
|
||||
* Agnostic to the particular format of object and string.
|
||||
*
|
||||
* @param {*} object The object to stringify.
|
||||
* @return {string} A string representation of the input.
|
||||
*/
|
||||
goog.string.Stringifier.prototype.stringify;
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2013 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.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for strings that conform to a data type or language.
|
||||
*
|
||||
* Implementations of this interface are wrappers for strings, and typically
|
||||
* associate a type contract with the wrapped string. Concrete implementations
|
||||
* of this interface may choose to implement additional run-time type checking,
|
||||
* see for example {@code goog.html.SafeHtml}. If available, client code that
|
||||
* needs to ensure type membership of an object should use the type's function
|
||||
* to assert type membership, such as {@code goog.html.SafeHtml.unwrap}.
|
||||
* @interface
|
||||
*/
|
||||
goog.string.TypedString = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Interface marker of the TypedString interface.
|
||||
*
|
||||
* This property can be used to determine at runtime whether or not an object
|
||||
* implements this interface. All implementations of this interface set this
|
||||
* property to {@code true}.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.string.TypedString.prototype.implementsGoogStringTypedString;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves this wrapped string's value.
|
||||
* @return {!string} The wrapped string's value.
|
||||
*/
|
||||
goog.string.TypedString.prototype.getTypedStringValue;
|
||||
Reference in New Issue
Block a user