// 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 Unit tests for goog.string. */ /** @suppress {extraProvide} */ goog.provide('goog.stringTest'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.functions'); goog.require('goog.object'); goog.require('goog.string'); goog.require('goog.string.Unicode'); goog.require('goog.testing.MockControl'); goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.setTestOnly('goog.stringTest'); var stubs; var mockControl; function setUp() { stubs = new goog.testing.PropertyReplacer(); mockControl = new goog.testing.MockControl(); } function tearDown() { stubs.reset(); mockControl.$tearDown(); } //=== tests for goog.string.collapseWhitespace === function testCollapseWhiteSpace() { var f = goog.string.collapseWhitespace; assertEquals('Leading spaces not stripped', f(' abc'), 'abc'); assertEquals('Trailing spaces not stripped', f('abc '), 'abc'); assertEquals('Wrapping spaces not stripped', f(' abc '), 'abc'); assertEquals( 'All white space chars not stripped', f('\xa0\n\t abc\xa0\n\t '), 'abc'); assertEquals('Spaces not collapsed', f('a b c'), 'a b c'); assertEquals('Tabs not collapsed', f('a\t\t\tb\tc'), 'a b c'); assertEquals( 'All check failed', f(' \ta \t \t\tb\t\n\xa0 c \t\n'), 'a b c'); } function testIsEmpty() { assertTrue(goog.string.isEmpty('')); assertTrue(goog.string.isEmpty(' ')); assertTrue(goog.string.isEmpty(' ')); assertTrue(goog.string.isEmpty(' \t\t\n\xa0 ')); assertFalse(goog.string.isEmpty(' abc \t\xa0')); assertFalse(goog.string.isEmpty(' a b c \t')); assertFalse(goog.string.isEmpty(';')); assertFalse(goog.string.isEmpty(undefined)); assertFalse(goog.string.isEmpty(null)); assertFalse(goog.string.isEmpty({a: 1, b: 2})); } function testIsEmptyOrWhitespace() { assertTrue(goog.string.isEmptyOrWhitespace('')); assertTrue(goog.string.isEmptyOrWhitespace(' ')); assertTrue(goog.string.isEmptyOrWhitespace(' ')); assertTrue(goog.string.isEmptyOrWhitespace(' \t\t\n\xa0 ')); assertFalse(goog.string.isEmptyOrWhitespace(' abc \t\xa0')); assertFalse(goog.string.isEmptyOrWhitespace(' a b c \t')); assertFalse(goog.string.isEmptyOrWhitespace(';')); assertFalse(goog.string.isEmptyOrWhitespace(undefined)); assertFalse(goog.string.isEmptyOrWhitespace(null)); assertFalse(goog.string.isEmptyOrWhitespace({a: 1, b: 2})); } function testIsEmptyString() { assertTrue(goog.string.isEmptyString('')); assertFalse(goog.string.isEmptyString(' ')); assertFalse(goog.string.isEmptyString(' ')); assertFalse(goog.string.isEmptyString(' \t\t\n\xa0 ')); assertFalse(goog.string.isEmptyString(' abc \t\xa0')); assertFalse(goog.string.isEmptyString(' a b c \t')); assertFalse(goog.string.isEmptyString(';')); assertFalse(goog.string.isEmptyString({a: 1, b: 2})); } function testIsEmptySafe() { assertTrue(goog.string.isEmptySafe('')); assertTrue(goog.string.isEmptySafe(' ')); assertTrue(goog.string.isEmptySafe(' ')); assertTrue(goog.string.isEmptySafe(' \t\t\n\xa0 ')); assertFalse(goog.string.isEmptySafe(' abc \t\xa0')); assertFalse(goog.string.isEmptySafe(' a b c \t')); assertFalse(goog.string.isEmptySafe(';')); assertTrue(goog.string.isEmptySafe(undefined)); assertTrue(goog.string.isEmptySafe(null)); assertFalse(goog.string.isEmptySafe({a: 1, b: 2})); } function testIsEmptyOrWhitespaceSafe() { assertTrue(goog.string.isEmptyOrWhitespaceSafe('')); assertTrue(goog.string.isEmptyOrWhitespaceSafe(' ')); assertTrue(goog.string.isEmptyOrWhitespaceSafe(' ')); assertTrue(goog.string.isEmptyOrWhitespaceSafe(' \t\t\n\xa0 ')); assertFalse(goog.string.isEmptyOrWhitespaceSafe(' abc \t\xa0')); assertFalse(goog.string.isEmptyOrWhitespaceSafe(' a b c \t')); assertFalse(goog.string.isEmptyOrWhitespaceSafe(';')); assertTrue(goog.string.isEmptyOrWhitespaceSafe(undefined)); assertTrue(goog.string.isEmptyOrWhitespaceSafe(null)); assertFalse(goog.string.isEmptyOrWhitespaceSafe({a: 1, b: 2})); } //=== tests for goog.string.isAlpha === function testIsAlpha() { assertTrue('"a" should be alpha', goog.string.isAlpha('a')); assertTrue('"n" should be alpha', goog.string.isAlpha('n')); assertTrue('"z" should be alpha', goog.string.isAlpha('z')); assertTrue('"A" should be alpha', goog.string.isAlpha('A')); assertTrue('"N" should be alpha', goog.string.isAlpha('N')); assertTrue('"Z" should be alpha', goog.string.isAlpha('Z')); assertTrue('"aa" should be alpha', goog.string.isAlpha('aa')); assertTrue('null is alpha', goog.string.isAlpha(null)); assertTrue('undefined is alpha', goog.string.isAlpha(undefined)); assertFalse('"aa!" is not alpha', goog.string.isAlpha('aa!s')); assertFalse('"!" is not alpha', goog.string.isAlpha('!')); assertFalse('"0" is not alpha', goog.string.isAlpha('0')); assertFalse('"5" is not alpha', goog.string.isAlpha('5')); } //=== tests for goog.string.isNumeric === function testIsNumeric() { assertTrue('"8" is a numeric string', goog.string.isNumeric('8')); assertTrue('"5" is a numeric string', goog.string.isNumeric('5')); assertTrue('"34" is a numeric string', goog.string.isNumeric('34')); assertTrue('34 is a number', goog.string.isNumeric(34)); assertFalse('"3.14" has a period', goog.string.isNumeric('3.14')); assertFalse('"A" is a letter', goog.string.isNumeric('A')); assertFalse('"!" is punctuation', goog.string.isNumeric('!')); assertFalse('null is not numeric', goog.string.isNumeric(null)); assertFalse('undefined is not numeric', goog.string.isNumeric(undefined)); } //=== tests for tests for goog.string.isAlphaNumeric === function testIsAlphaNumeric() { assertTrue( '"ABCabc" should be alphanumeric', goog.string.isAlphaNumeric('ABCabc')); assertTrue('"123" should be alphanumeric', goog.string.isAlphaNumeric('123')); assertTrue( '"ABCabc123" should be alphanumeric', goog.string.isAlphaNumeric('ABCabc123')); assertTrue('null is alphanumeric', goog.string.isAlphaNumeric(null)); assertTrue( 'undefined is alphanumeric', goog.string.isAlphaNumeric(undefined)); assertFalse( '"123!" should not be alphanumeric', goog.string.isAlphaNumeric('123!')); assertFalse( '" " should not be alphanumeric', goog.string.isAlphaNumeric(' ')); } //== tests for goog.string.isBreakingWhitespace === function testIsBreakingWhitespace() { assertTrue('" " is breaking', goog.string.isBreakingWhitespace(' ')); assertTrue('"\\n" is breaking', goog.string.isBreakingWhitespace('\n')); assertTrue('"\\t" is breaking', goog.string.isBreakingWhitespace('\t')); assertTrue('"\\r" is breaking', goog.string.isBreakingWhitespace('\r')); assertTrue( '"\\r\\n\\t " is breaking', goog.string.isBreakingWhitespace('\r\n\t ')); assertFalse('nbsp is non-breaking', goog.string.isBreakingWhitespace('\xa0')); assertFalse('"a" is non-breaking', goog.string.isBreakingWhitespace('a')); assertFalse( '"a\\r" is non-breaking', goog.string.isBreakingWhitespace('a\r')); } //=== tests for goog.string.isSpace === function testIsSpace() { assertTrue('" " is a space', goog.string.isSpace(' ')); assertFalse('"\\n" is not a space', goog.string.isSpace('\n')); assertFalse('"\\t" is not a space', goog.string.isSpace('\t')); assertFalse( '" " is not a space, it\'s two spaces', goog.string.isSpace(' ')); assertFalse('"a" is not a space', goog.string.isSpace('a')); assertFalse('"3" is not a space', goog.string.isSpace('3')); assertFalse('"#" is not a space', goog.string.isSpace('#')); assertFalse('null is not a space', goog.string.isSpace(null)); assertFalse('nbsp is not a space', goog.string.isSpace('\xa0')); } // === tests for goog.string.stripNewlines === function testStripNewLines() { assertEquals( 'Should replace new lines with spaces', goog.string.stripNewlines('some\nlines\rthat\r\nare\n\nsplit'), 'some lines that are split'); } // === tests for goog.string.canonicalizeNewlines === function testCanonicalizeNewlines() { assertEquals( 'Should replace all types of new line with \\n', goog.string.canonicalizeNewlines('some\nlines\rthat\r\nare\n\nsplit'), 'some\nlines\nthat\nare\n\nsplit'); } // === tests for goog.string.normalizeWhitespace === function testNormalizeWhitespace() { assertEquals( 'All whitespace chars should be replaced with a normal space', goog.string.normalizeWhitespace('\xa0 \n\t \xa0 \n\t'), ' '); } // === tests for goog.string.normalizeSpaces === function testNormalizeSpaces() { assertEquals( 'All whitespace chars should be replaced with a normal space', goog.string.normalizeSpaces('\xa0 \t \xa0 \t'), ' '); } function testCollapseBreakingSpaces() { assertEquals( 'breaking spaces are collapsed', 'a b', goog.string.collapseBreakingSpaces(' \t\r\n a \t\r\n b \t\r\n ')); assertEquals( 'non-breaking spaces are kept', 'a \u00a0\u2000 b', goog.string.collapseBreakingSpaces('a \u00a0\u2000 b')); } /// === tests for goog.string.trim === function testTrim() { assertEquals( 'Should be the same', goog.string.trim('nothing 2 trim'), 'nothing 2 trim'); assertEquals( 'Remove spaces', goog.string.trim(' hello goodbye '), 'hello goodbye'); assertEquals( 'Trim other stuff', goog.string.trim('\n\r\xa0 hi \r\n\xa0'), 'hi'); } /// === tests for goog.string.trimLeft === function testTrimLeft() { var f = goog.string.trimLeft; assertEquals('Should be the same', f('nothing to trim'), 'nothing to trim'); assertEquals('Remove spaces', f(' hello goodbye '), 'hello goodbye '); assertEquals('Trim other stuff', f('\xa0\n\r hi \r\n\xa0'), 'hi \r\n\xa0'); } /// === tests for goog.string.trimRight === function testTrimRight() { var f = goog.string.trimRight; assertEquals('Should be the same', f('nothing to trim'), 'nothing to trim'); assertEquals('Remove spaces', f(' hello goodbye '), ' hello goodbye'); assertEquals('Trim other stuff', f('\n\r\xa0 hi \r\n\xa0'), '\n\r\xa0 hi'); } // === tests for goog.string.startsWith === function testStartsWith() { assertTrue('Should start with \'\'', goog.string.startsWith('abcd', '')); assertTrue('Should start with \'ab\'', goog.string.startsWith('abcd', 'ab')); assertTrue( 'Should start with \'abcd\'', goog.string.startsWith('abcd', 'abcd')); assertFalse( 'Should not start with \'bcd\'', goog.string.startsWith('abcd', 'bcd')); } function testEndsWith() { assertTrue('Should end with \'\'', goog.string.endsWith('abcd', '')); assertTrue('Should end with \'ab\'', goog.string.endsWith('abcd', 'cd')); assertTrue('Should end with \'abcd\'', goog.string.endsWith('abcd', 'abcd')); assertFalse('Should not end \'abc\'', goog.string.endsWith('abcd', 'abc')); assertFalse( 'Should not end \'abcde\'', goog.string.endsWith('abcd', 'abcde')); } // === tests for goog.string.caseInsensitiveStartsWith === function testCaseInsensitiveStartsWith() { assertTrue( 'Should start with \'\'', goog.string.caseInsensitiveStartsWith('abcd', '')); assertTrue( 'Should start with \'ab\'', goog.string.caseInsensitiveStartsWith('abcd', 'Ab')); assertTrue( 'Should start with \'abcd\'', goog.string.caseInsensitiveStartsWith('AbCd', 'abCd')); assertFalse( 'Should not start with \'bcd\'', goog.string.caseInsensitiveStartsWith('ABCD', 'bcd')); } // === tests for goog.string.caseInsensitiveEndsWith === function testCaseInsensitiveEndsWith() { assertTrue( 'Should end with \'\'', goog.string.caseInsensitiveEndsWith('abcd', '')); assertTrue( 'Should end with \'cd\'', goog.string.caseInsensitiveEndsWith('abCD', 'cd')); assertTrue( 'Should end with \'abcd\'', goog.string.caseInsensitiveEndsWith('abcd', 'abCd')); assertFalse( 'Should not end \'abc\'', goog.string.caseInsensitiveEndsWith('aBCd', 'ABc')); assertFalse( 'Should not end \'abcde\'', goog.string.caseInsensitiveEndsWith('ABCD', 'abcde')); } // === tests for goog.string.caseInsensitiveEquals === function testCaseInsensitiveEquals() { function assertCaseInsensitiveEquals(str1, str2) { assertTrue(goog.string.caseInsensitiveEquals(str1, str2)); } function assertCaseInsensitiveNotEquals(str1, str2) { assertFalse(goog.string.caseInsensitiveEquals(str1, str2)); } assertCaseInsensitiveEquals('abc', 'abc'); assertCaseInsensitiveEquals('abc', 'abC'); assertCaseInsensitiveEquals('d,e,F,G', 'd,e,F,G'); assertCaseInsensitiveEquals('ABCD EFGH 1234', 'abcd efgh 1234'); assertCaseInsensitiveEquals('FooBarBaz', 'fOObARbAZ'); assertCaseInsensitiveNotEquals('ABCD EFGH', 'abcd efg'); assertCaseInsensitiveNotEquals('ABC DEFGH', 'ABCD EFGH'); assertCaseInsensitiveNotEquals('FooBarBaz', 'fOObARbAZ '); } // === tests for goog.string.subs === function testSubs() { assertEquals( 'Should be the same', 'nothing to subs', goog.string.subs('nothing to subs')); assertEquals('Should be the same', '1', goog.string.subs('%s', '1')); assertEquals( 'Should be the same', '12true', goog.string.subs('%s%s%s', '1', 2, true)); function f() { fail('This should not be called'); } f.toString = function() { return 'f'; }; assertEquals('Should not call function', 'f', goog.string.subs('%s', f)); // If the string that is to be substituted in contains $& then it will be // usually be replaced with %s, we need to check goog.string.subs, handles // this case. assertEquals( '$& should not be substituted with %s', 'Foo Bar $&', goog.string.subs('Foo %s', 'Bar $&')); assertEquals( '$$ should not be substituted', '_$$_', goog.string.subs('%s', '_$$_')); assertEquals( '$` should not be substituted', '_$`_', goog.string.subs('%s', '_$`_')); assertEquals( '$\' should not be substituted', '_$\'_', goog.string.subs('%s', '_$\'_')); for (var i = 0; i < 99; i += 9) { assertEquals( '$' + i + ' should not be substituted', '_$' + i + '_', goog.string.subs('%s', '_$' + i + '_')); } assertEquals( 'Only the first three "%s" strings should be replaced.', 'test foo test bar test baz test %s test %s test', goog.string.subs( 'test %s test %s test %s test %s test %s test', 'foo', 'bar', 'baz')); } /** * Verifies that if too many arguments are given, they are ignored. * Logic test for bug documented here: http://go/eusxz */ function testSubsTooManyArguments() { assertEquals('one', goog.string.subs('one', 'two', 'three')); assertEquals('onetwo', goog.string.subs('one%s', 'two', 'three')); } // === tests for goog.string.caseInsensitiveCompare === function testCaseInsensitiveCompare() { var f = goog.string.caseInsensitiveCompare; assert('"ABC" should be less than "def"', f('ABC', 'def') == -1); assert('"abc" should be less than "DEF"', f('abc', 'DEF') == -1); assert('"XYZ" should equal "xyz"', f('XYZ', 'xyz') == 0); assert('"XYZ" should be greater than "UVW"', f('xyz', 'UVW') == 1); assert('"XYZ" should be greater than "uvw"', f('XYZ', 'uvw') == 1); } /** * Test cases for goog.string.floatAwareCompare and goog.string.intAwareCompare. * Each comparison in this list is tested to assure that terms[0] < terms[1], * terms[1] > terms[0], and identity tests terms[0] == terms[0] and * terms[1] == terms[1]. * @const {!Array>} */ var NUMERIC_COMPARISON_TEST_CASES = [ ['', '0'], ['2', '10'], ['05', '9'], ['sub', 'substring'], ['photo 7', 'Photo 8'], // Case insensitive for most sorts. ['Mango', 'mango'], // Case sensitive if strings are otherwise identical. ['album 2 photo 20', 'album 10 photo 20'], ['album 7 photo 20', 'album 7 photo 100'] ]; function testFloatAwareCompare() { var comparisons = NUMERIC_COMPARISON_TEST_CASES.concat([['3.14', '3.2']]); for (var i = 0; i < comparisons.length; i++) { var terms = comparisons[i]; assert( terms[0] + ' should be less than ' + terms[1], goog.string.floatAwareCompare(terms[0], terms[1]) < 0); assert( terms[1] + ' should be greater than ' + terms[0], goog.string.floatAwareCompare(terms[1], terms[0]) > 0); assert( terms[0] + ' should be equal to ' + terms[0], goog.string.floatAwareCompare(terms[0], terms[0]) == 0); assert( terms[1] + ' should be equal to ' + terms[1], goog.string.floatAwareCompare(terms[1], terms[1]) == 0); } } function testIntAwareCompare() { var comparisons = NUMERIC_COMPARISON_TEST_CASES.concat([['3.2', '3.14']]); for (var i = 0; i < comparisons.length; i++) { var terms = comparisons[i]; assert( terms[0] + ' should be less than ' + terms[1], goog.string.intAwareCompare(terms[0], terms[1]) < 0); assert( terms[1] + ' should be greater than ' + terms[0], goog.string.intAwareCompare(terms[1], terms[0]) > 0); assert( terms[0] + ' should be equal to ' + terms[0], goog.string.intAwareCompare(terms[0], terms[0]) == 0); assert( terms[1] + ' should be equal to ' + terms[1], goog.string.intAwareCompare(terms[1], terms[1]) == 0); } } // === tests for goog.string.urlEncode && .urlDecode === // NOTE: When test was written it was simply an alias for the built in // 'encodeURICompoent', therefore this test is simply used to make sure that in // the future it doesn't get broken. function testUrlEncodeAndDecode() { var input = '
"hello there," she said, "what is going on here?
'; var output = '%3Cp%3E%22hello%20there%2C%22%20she%20said%2C%20%22what%20is' + '%20going%20on%20here%3F%3C%2Fp%3E'; assertEquals( 'urlEncode vs encodeURIComponent', encodeURIComponent(input), goog.string.urlEncode(input)); assertEquals('urlEncode vs model', goog.string.urlEncode(input), output); assertEquals('urlDecode vs model', goog.string.urlDecode(output), input); assertEquals( 'urlDecode vs urlEncode', goog.string.urlDecode(goog.string.urlEncode(input)), input); assertEquals( 'urlDecode with +s instead of %20s', goog.string.urlDecode(output.replace(/%20/g, '+')), input); } // === tests for goog.string.newLineToBr === function testNewLineToBr() { var str = 'some\nlines\rthat\r\nare\n\nsplit'; var html = 'some