Adding mapbox-gl branch

This commit is contained in:
Andreas Hocevar
2015-03-16 18:50:27 +01:00
parent 7985f030fa
commit 57ee7f52fd
3109 changed files with 943365 additions and 0 deletions
@@ -0,0 +1,67 @@
// 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 a class for parsing JSON using eval.
*/
goog.provide('goog.json.EvalJsonProcessor');
goog.require('goog.json');
goog.require('goog.json.Processor');
goog.require('goog.json.Serializer');
/**
* A class that parses and stringifies JSON using eval (as implemented in
* goog.json).
* Adapts {@code goog.json} to the {@code goog.json.Processor} interface.
*
* @param {?goog.json.Replacer=} opt_replacer An optional replacer to use during
* serialization.
* @param {?boolean=} opt_useUnsafeParsing Whether to use goog.json.unsafeParse
* for parsing. Safe parsing is very slow on large strings. On the other
* hand, unsafe parsing uses eval() without checking whether the string is
* valid, so it should only be used if you trust the source of the string.
* @constructor
* @implements {goog.json.Processor}
* @final
*/
goog.json.EvalJsonProcessor = function(opt_replacer, opt_useUnsafeParsing) {
/**
* @type {goog.json.Serializer}
* @private
*/
this.serializer_ = new goog.json.Serializer(opt_replacer);
/**
* @type {function(string): *}
* @private
*/
this.parser_ = opt_useUnsafeParsing ? goog.json.unsafeParse : goog.json.parse;
};
/** @override */
goog.json.EvalJsonProcessor.prototype.stringify = function(object) {
return this.serializer_.serialize(object);
};
/** @override */
goog.json.EvalJsonProcessor.prototype.parse = function(s) {
return this.parser_(s);
};
@@ -0,0 +1,103 @@
// 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 Utility to attempt native JSON processing, falling back to
* goog.json if not available.
*
* This is intended as a drop-in for current users of goog.json who want
* to take advantage of native JSON if present.
*
* @author nnaze@google.com (Nathan Naze)
*/
goog.provide('goog.json.hybrid');
goog.require('goog.asserts');
goog.require('goog.json');
/**
* Attempts to serialize the JSON string natively, falling back to
* {@code goog.json.serialize} if unsuccessful.
* @param {!Object} obj JavaScript object to serialize to JSON.
* @return {string} Resulting JSON string.
*/
goog.json.hybrid.stringify = goog.json.USE_NATIVE_JSON ?
goog.global['JSON']['stringify'] :
function(obj) {
if (goog.global.JSON) {
try {
return goog.global.JSON.stringify(obj);
} catch (e) {
// Native serialization failed. Fall through to retry with
// goog.json.serialize.
}
}
return goog.json.serialize(obj);
};
/**
* Attempts to parse the JSON string natively, falling back to
* the supplied {@code fallbackParser} if unsuccessful.
* @param {string} jsonString JSON string to parse.
* @param {function(string):Object} fallbackParser Fallback JSON parser used
* if native
* @return {!Object} Resulting JSON object.
* @private
*/
goog.json.hybrid.parse_ = function(jsonString, fallbackParser) {
if (goog.global.JSON) {
try {
var obj = goog.global.JSON.parse(jsonString);
goog.asserts.assertObject(obj);
return obj;
} catch (e) {
// Native parse failed. Fall through to retry with goog.json.unsafeParse.
}
}
var obj = fallbackParser(jsonString);
goog.asserts.assert(obj);
return obj;
};
/**
* Attempts to parse the JSON string natively, falling back to
* {@code goog.json.parse} if unsuccessful.
* @param {string} jsonString JSON string to parse.
* @return {!Object} Resulting JSON object.
*/
goog.json.hybrid.parse = goog.json.USE_NATIVE_JSON ?
goog.global['JSON']['parse'] :
function(jsonString) {
return goog.json.hybrid.parse_(jsonString, goog.json.parse);
};
/**
* Attempts to parse the JSON string natively, falling back to
* {@code goog.json.unsafeParse} if unsuccessful.
* @param {string} jsonString JSON string to parse.
* @return {!Object} Resulting JSON object.
*/
goog.json.hybrid.unsafeParse = goog.json.USE_NATIVE_JSON ?
goog.global['JSON']['parse'] :
function(jsonString) {
return goog.json.hybrid.parse_(jsonString, goog.json.unsafeParse);
};
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2013 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.json.hybridTest</title>
<script src="../base.js"></script>
<script>
goog.require('goog.json.hybridTest');
</script>
</head>
<body>
</body>
</html>
@@ -0,0 +1,157 @@
// 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.json.hybrid.
* @author nnaze@google.com (Nathan Naze)
*/
goog.provide('goog.json.hybridTest');
goog.require('goog.json');
goog.require('goog.json.hybrid');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.recordFunction');
goog.require('goog.userAgent');
goog.setTestOnly('goog.json.hybridTest');
var propertyReplacer = new goog.testing.PropertyReplacer();
var jsonParse;
var jsonStringify;
var googJsonParse;
var googJsonUnsafeParse;
var googJsonSerialize;
function isIe7() {
return goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8');
}
function setUp() {
googJsonParse = goog.testing.recordFunction(goog.json.parse);
googJsonUnsafeParse = goog.testing.recordFunction(goog.json.unsafeParse);
googJsonSerialize = goog.testing.recordFunction(goog.json.serialize);
propertyReplacer.set(goog.json, 'parse', googJsonParse);
propertyReplacer.set(goog.json, 'unsafeParse', googJsonUnsafeParse);
propertyReplacer.set(goog.json, 'serialize', googJsonSerialize);
jsonParse = goog.testing.recordFunction(
goog.global.JSON && goog.global.JSON.parse);
jsonStringify = goog.testing.recordFunction(
goog.global.JSON && goog.global.JSON.stringify);
if (goog.global.JSON) {
propertyReplacer.set(goog.global.JSON, 'parse', jsonParse);
propertyReplacer.set(goog.global.JSON, 'stringify', jsonStringify);
}
}
function tearDown() {
propertyReplacer.reset();
}
function parseJson() {
var obj = goog.json.hybrid.parse('{"a": 2}');
assertObjectEquals({'a': 2}, obj);
}
function unsafeParseJson() {
var obj = goog.json.hybrid.unsafeParse('{"a": 2}');
assertObjectEquals({'a': 2}, obj);
}
function serializeJson() {
var str = goog.json.hybrid.stringify({b: 2});
assertEquals('{"b":2}', str);
}
function testUnsafeParseNativeJsonPresent() {
// No native JSON in IE7
if (isIe7()) {
return;
}
unsafeParseJson();
assertEquals(1, jsonParse.getCallCount());
assertEquals(0, googJsonParse.getCallCount());
assertEquals(0, googJsonUnsafeParse.getCallCount());
}
function testParseNativeJsonPresent() {
// No native JSON in IE7
if (isIe7()) {
return;
}
unsafeParseJson();
assertEquals(1, jsonParse.getCallCount());
assertEquals(0, googJsonParse.getCallCount());
assertEquals(0, googJsonUnsafeParse.getCallCount());
}
function testStringifyNativeJsonPresent() {
// No native JSON in IE7
if (isIe7()) {
return;
}
serializeJson();
assertEquals(1, jsonStringify.getCallCount());
assertEquals(0, googJsonSerialize.getCallCount());
}
function testParseNativeJsonAbsent() {
propertyReplacer.set(goog.global, 'JSON', null);
parseJson();
assertEquals(0, jsonParse.getCallCount());
assertEquals(0, jsonStringify.getCallCount());
assertEquals(1, googJsonParse.getCallCount());
assertEquals(0, googJsonUnsafeParse.getCallCount());
}
function testStringifyNativeJsonAbsent() {
propertyReplacer.set(goog.global, 'JSON', null);
serializeJson();
assertEquals(0, jsonStringify.getCallCount());
assertEquals(1, googJsonSerialize.getCallCount());
}
function testParseCurrentBrowserParse() {
parseJson();
assertEquals(isIe7() ? 0 : 1, jsonParse.getCallCount());
assertEquals(isIe7() ? 1 : 0, googJsonParse.getCallCount());
assertEquals(0, googJsonUnsafeParse.getCallCount());
}
function testParseCurrentBrowserUnsafeParse() {
unsafeParseJson();
assertEquals(isIe7() ? 0 : 1, jsonParse.getCallCount());
assertEquals(0, googJsonParse.getCallCount());
assertEquals(isIe7() ? 1 : 0, googJsonUnsafeParse.getCallCount());
}
function testParseCurrentBrowserStringify() {
serializeJson();
assertEquals(isIe7() ? 0 : 1, jsonStringify.getCallCount());
assertEquals(isIe7() ? 1 : 0, googJsonSerialize.getCallCount());
}
@@ -0,0 +1,47 @@
// 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 dihstributed 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 A class that attempts parse/serialize JSON using native JSON,
* falling back to goog.json if necessary.
* @author nnaze@google.com (Nathan Naze)
*/
goog.provide('goog.json.HybridJsonProcessor');
goog.require('goog.json.Processor');
goog.require('goog.json.hybrid');
/**
* Processor form of goog.json.hybrid, which attempts to parse/serialize
* JSON using native JSON methods, falling back to goog.json if not
* available.
* @constructor
* @implements {goog.json.Processor}
* @final
*/
goog.json.HybridJsonProcessor = function() {};
/** @override */
goog.json.HybridJsonProcessor.prototype.stringify =
/** @type {function (*): string} */ (goog.json.hybrid.stringify);
/** @override */
goog.json.HybridJsonProcessor.prototype.parse =
/** @type {function (*): !Object} */ (goog.json.hybrid.parse);
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2013 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.json.HybridJsonProcessor</title>
<script src="../base.js"></script>
<script>
goog.require('goog.json.HybridJsonProcessorTest');
</script>
</head>
<body>
</body>
</html>
@@ -0,0 +1,33 @@
// 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.json.hybrid.
* @author nnaze@google.com (Nathan Naze)
*/
goog.provide('goog.json.HybridJsonProcessorTest');
goog.require('goog.json.HybridJsonProcessor');
goog.require('goog.json.hybrid');
goog.require('goog.testing.jsunit');
goog.setTestOnly('goog.json.HybridJsonProcessorTest');
function testCorrectFunctions() {
var processor = new goog.json.HybridJsonProcessor();
assertEquals(goog.json.hybrid.stringify, processor.stringify);
assertEquals(goog.json.hybrid.parse, processor.parse);
}
@@ -0,0 +1,369 @@
// 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 JSON utility functions.
* @author arv@google.com (Erik Arvidsson)
*/
goog.provide('goog.json');
goog.provide('goog.json.Replacer');
goog.provide('goog.json.Reviver');
goog.provide('goog.json.Serializer');
/**
* @define {boolean} If true, use the native JSON parsing API.
* NOTE(ruilopes): EXPERIMENTAL, handle with care. Setting this to true might
* break your code. The default {@code goog.json.parse} implementation is able
* to handle invalid JSON, such as JSPB.
*/
goog.define('goog.json.USE_NATIVE_JSON', false);
/**
* Tests if a string is an invalid JSON string. This only ensures that we are
* not using any invalid characters
* @param {string} s The string to test.
* @return {boolean} True if the input is a valid JSON string.
*/
goog.json.isValid = function(s) {
// All empty whitespace is not valid.
if (/^\s*$/.test(s)) {
return false;
}
// This is taken from http://www.json.org/json2.js which is released to the
// public domain.
// Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator
// inside strings. We also treat \u2028 and \u2029 as whitespace which they
// are in the RFC but IE and Safari does not match \s to these so we need to
// include them in the reg exps in all places where whitespace is allowed.
// We allowed \x7f inside strings because some tools don't escape it,
// e.g. http://www.json.org/java/org/json/JSONObject.java
// Parsing happens in three stages. In the first stage, we run the text
// against regular expressions that look for non-JSON patterns. We are
// especially concerned with '()' and 'new' because they can cause invocation,
// and '=' because it can cause mutation. But just to be safe, we want to
// reject all unexpected forms.
// We split the first stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace all backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
// Don't make these static since they have the global flag.
var backslashesRe = /\\["\\\/bfnrtu]/g;
var simpleValuesRe =
/"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g;
var remainderRe = /^[\],:{}\s\u2028\u2029]*$/;
return remainderRe.test(s.replace(backslashesRe, '@').
replace(simpleValuesRe, ']').
replace(openBracketsRe, ''));
};
/**
* Parses a JSON string and returns the result. This throws an exception if
* the string is an invalid JSON string.
*
* Note that this is very slow on large strings. If you trust the source of
* the string then you should use unsafeParse instead.
*
* @param {*} s The JSON string to parse.
* @throws Error if s is invalid JSON.
* @return {Object} The object generated from the JSON string, or null.
*/
goog.json.parse = goog.json.USE_NATIVE_JSON ?
/** @type {function(*):Object} */ (goog.global['JSON']['parse']) :
function(s) {
var o = String(s);
if (goog.json.isValid(o)) {
/** @preserveTry */
try {
return /** @type {Object} */ (eval('(' + o + ')'));
} catch (ex) {
}
}
throw Error('Invalid JSON string: ' + o);
};
/**
* Parses a JSON string and returns the result. This uses eval so it is open
* to security issues and it should only be used if you trust the source.
*
* @param {string} s The JSON string to parse.
* @return {Object} The object generated from the JSON string.
*/
goog.json.unsafeParse = goog.json.USE_NATIVE_JSON ?
/** @type {function(string):Object} */ (goog.global['JSON']['parse']) :
function(s) {
return /** @type {Object} */ (eval('(' + s + ')'));
};
/**
* JSON replacer, as defined in Section 15.12.3 of the ES5 spec.
* @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3
*
* TODO(nicksantos): Array should also be a valid replacer.
*
* @typedef {function(this:Object, string, *): *}
*/
goog.json.Replacer;
/**
* JSON reviver, as defined in Section 15.12.2 of the ES5 spec.
* @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3
*
* @typedef {function(this:Object, string, *): *}
*/
goog.json.Reviver;
/**
* Serializes an object or a value to a JSON string.
*
* @param {*} object The object to serialize.
* @param {?goog.json.Replacer=} opt_replacer A replacer function
* called for each (key, value) pair that determines how the value
* should be serialized. By defult, this just returns the value
* and allows default serialization to kick in.
* @throws Error if there are loops in the object graph.
* @return {string} A JSON string representation of the input.
*/
goog.json.serialize = goog.json.USE_NATIVE_JSON ?
/** @type {function(*, ?goog.json.Replacer=):string} */
(goog.global['JSON']['stringify']) :
function(object, opt_replacer) {
// NOTE(nicksantos): Currently, we never use JSON.stringify.
//
// The last time I evaluated this, JSON.stringify had subtle bugs and
// behavior differences on all browsers, and the performance win was not
// large enough to justify all the issues. This may change in the future
// as browser implementations get better.
//
// assertSerialize in json_test contains if branches for the cases
// that fail.
return new goog.json.Serializer(opt_replacer).serialize(object);
};
/**
* Class that is used to serialize JSON objects to a string.
* @param {?goog.json.Replacer=} opt_replacer Replacer.
* @constructor
*/
goog.json.Serializer = function(opt_replacer) {
/**
* @type {goog.json.Replacer|null|undefined}
* @private
*/
this.replacer_ = opt_replacer;
};
/**
* Serializes an object or a value to a JSON string.
*
* @param {*} object The object to serialize.
* @throws Error if there are loops in the object graph.
* @return {string} A JSON string representation of the input.
*/
goog.json.Serializer.prototype.serialize = function(object) {
var sb = [];
this.serializeInternal(object, sb);
return sb.join('');
};
/**
* Serializes a generic value to a JSON string
* @protected
* @param {*} object The object to serialize.
* @param {Array<string>} sb Array used as a string builder.
* @throws Error if there are loops in the object graph.
*/
goog.json.Serializer.prototype.serializeInternal = function(object, sb) {
switch (typeof object) {
case 'string':
this.serializeString_(/** @type {string} */ (object), sb);
break;
case 'number':
this.serializeNumber_(/** @type {number} */ (object), sb);
break;
case 'boolean':
sb.push(object);
break;
case 'undefined':
sb.push('null');
break;
case 'object':
if (object == null) {
sb.push('null');
break;
}
if (goog.isArray(object)) {
this.serializeArray(/** @type {!Array<?>} */ (object), sb);
break;
}
// should we allow new String, new Number and new Boolean to be treated
// as string, number and boolean? Most implementations do not and the
// need is not very big
this.serializeObject_(/** @type {Object} */ (object), sb);
break;
case 'function':
// Skip functions.
// TODO(user) Should we return something here?
break;
default:
throw Error('Unknown type: ' + typeof object);
}
};
/**
* Character mappings used internally for goog.string.quote
* @private
* @type {!Object}
*/
goog.json.Serializer.charToJsonCharCache_ = {
'\"': '\\"',
'\\': '\\\\',
'/': '\\/',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\x0B': '\\u000b' // '\v' is not supported in JScript
};
/**
* Regular expression used to match characters that need to be replaced.
* The S60 browser has a bug where unicode characters are not matched by
* regular expressions. The condition below detects such behaviour and
* adjusts the regular expression accordingly.
* @private
* @type {!RegExp}
*/
goog.json.Serializer.charsToReplace_ = /\uffff/.test('\uffff') ?
/[\\\"\x00-\x1f\x7f-\uffff]/g : /[\\\"\x00-\x1f\x7f-\xff]/g;
/**
* Serializes a string to a JSON string
* @private
* @param {string} s The string to serialize.
* @param {Array<string>} sb Array used as a string builder.
*/
goog.json.Serializer.prototype.serializeString_ = function(s, sb) {
// The official JSON implementation does not work with international
// characters.
sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) {
// caching the result improves performance by a factor 2-3
if (c in goog.json.Serializer.charToJsonCharCache_) {
return goog.json.Serializer.charToJsonCharCache_[c];
}
var cc = c.charCodeAt(0);
var rv = '\\u';
if (cc < 16) {
rv += '000';
} else if (cc < 256) {
rv += '00';
} else if (cc < 4096) { // \u1000
rv += '0';
}
return goog.json.Serializer.charToJsonCharCache_[c] = rv + cc.toString(16);
}), '"');
};
/**
* Serializes a number to a JSON string
* @private
* @param {number} n The number to serialize.
* @param {Array<string>} sb Array used as a string builder.
*/
goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) {
sb.push(isFinite(n) && !isNaN(n) ? n : 'null');
};
/**
* Serializes an array to a JSON string
* @param {Array<string>} arr The array to serialize.
* @param {Array<string>} sb Array used as a string builder.
* @protected
*/
goog.json.Serializer.prototype.serializeArray = function(arr, sb) {
var l = arr.length;
sb.push('[');
var sep = '';
for (var i = 0; i < l; i++) {
sb.push(sep);
var value = arr[i];
this.serializeInternal(
this.replacer_ ? this.replacer_.call(arr, String(i), value) : value,
sb);
sep = ',';
}
sb.push(']');
};
/**
* Serializes an object to a JSON string
* @private
* @param {Object} obj The object to serialize.
* @param {Array<string>} sb Array used as a string builder.
*/
goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) {
sb.push('{');
var sep = '';
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var value = obj[key];
// Skip functions.
// TODO(ptucker) Should we return something for function properties?
if (typeof value != 'function') {
sb.push(sep);
this.serializeString_(key, sb);
sb.push(':');
this.serializeInternal(
this.replacer_ ? this.replacer_.call(obj, key, value) : value,
sb);
sep = ',';
}
}
}
sb.push('}');
};
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2012 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 Performance Tests - goog.json vs JSON</title>
<link rel="stylesheet" type="text/css" href="../testing/performancetable.css"/>
<script src="../base.js"></script>
</head>
<body>
<h1>goog.json and JSON Performance Tests</h1>
<p>
<strong>User-agent:</strong>
<script>document.write(navigator.userAgent);</script>
</p>
<div id="perfTable"></div>
<hr>
<script>
goog.require('goog.jsonPerf');
</script>
</body>
</html>
@@ -0,0 +1,112 @@
// 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 JSON performance tests.
*/
goog.provide('goog.jsonPerf');
goog.require('goog.dom');
goog.require('goog.json');
goog.require('goog.math');
goog.require('goog.string');
goog.require('goog.testing.PerformanceTable');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.jsunit');
goog.setTestOnly('goog.jsonPerf');
var table = new goog.testing.PerformanceTable(
goog.dom.getElement('perfTable'));
var stubs = new goog.testing.PropertyReplacer();
function tearDown() {
stubs.reset();
}
function testSerialize() {
var obj = populateObject({}, 50, 4);
table.run(function() {
var s = JSON.stringify(obj);
}, 'Stringify using JSON.stringify');
table.run(function() {
var s = goog.json.serialize(obj);
}, 'Stringify using goog.json.serialize');
}
function testParse() {
var obj = populateObject({}, 50, 4);
var s = JSON.stringify(obj);
table.run(function() {
var o = JSON.parse(s);
}, 'Parse using JSON.parse');
table.run(function() {
var o = goog.json.parse(s);
}, 'Parse using goog.json.parse');
table.run(function() {
var o = goog.json.unsafeParse(s);
}, 'Parse using goog.json.unsafeParse');
}
/**
* @param {!Object} obj The object to add properties to.
* @param {number} numProperties The number of properties to add.
* @param {number} depth The depth at which to recursively add properties.
* @return {!Object} The object given in obj (for convenience).
*/
function populateObject(obj, numProperties, depth) {
if (depth == 0) {
return randomLiteral();
}
// Make an object with a mix of strings, numbers, arrays, objects, booleans
// nulls as children.
for (var i = 0; i < numProperties; i++) {
var bucket = goog.math.randomInt(3);
switch (bucket) {
case 0:
obj[i] = randomLiteral();
break;
case 1:
obj[i] = populateObject({}, numProperties, depth - 1);
break;
case 2:
obj[i] = populateObject([], numProperties, depth - 1);
break;
}
}
return obj;
}
function randomLiteral() {
var bucket = goog.math.randomInt(3);
switch (bucket) {
case 0:
return goog.string.getRandomString();
case 1:
return Math.random();
case 2:
return Math.random() >= .5;
}
return null;
}
@@ -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.json</title>
<script src="../base.js"></script>
<script>
goog.require('goog.jsonTest');
</script>
</head>
<body>
</body>
</html>
@@ -0,0 +1,563 @@
// 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.jsonTest');
goog.setTestOnly('goog.jsonTest');
goog.require('goog.functions');
goog.require('goog.json');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
function allChars(start, end, opt_allowControlCharacters) {
var sb = [];
for (var i = start; i < end; i++) {
// unicode without the control characters 0x00 - 0x1f
if (opt_allowControlCharacters || i > 0x1f) {
sb.push(String.fromCharCode(i));
}
}
return sb.join('');
}
// serialization
function testStringSerialize() {
assertSerialize('""', '');
// unicode
var str = allChars(0, 10000);
eval(goog.json.serialize(str));
assertSerialize('"true"', 'true');
assertSerialize('"false"', 'false');
assertSerialize('"null"', 'null');
assertSerialize('"0"', '0');
}
function testNullSerialize() {
assertSerialize('null', null);
assertSerialize('null', undefined);
assertSerialize('null', NaN);
assertSerialize('0', 0);
assertSerialize('""', '');
assertSerialize('false', false);
}
function testNullPropertySerialize() {
assertSerialize('{"a":null}', {'a': null});
assertSerialize('{"a":null}', {'a': undefined});
}
function testNumberSerialize() {
assertSerialize('0', 0);
assertSerialize('12345', 12345);
assertSerialize('-12345', -12345);
assertSerialize('0.1', 0.1);
// the leading zero may not be omitted
assertSerialize('0.1', .1);
// no leading +
assertSerialize('1', +1);
// either format is OK
var s = goog.json.serialize(1e50);
assertTrue('1e50',
s == '1e50' || s == '1E50' ||
s == '1e+50' || s == '1E+50');
// either format is OK
s = goog.json.serialize(1e-50);
assertTrue('1e50', s == '1e-50' || s == '1E-50');
// These numbers cannot be represented in JSON
assertSerialize('null', NaN);
assertSerialize('null', Infinity);
assertSerialize('null', -Infinity);
}
function testBooleanSerialize() {
assertSerialize('true', true);
assertSerialize('"true"', 'true');
assertSerialize('false', false);
assertSerialize('"false"', 'false');
}
function testArraySerialize() {
assertSerialize('[]', []);
assertSerialize('[1]', [1]);
assertSerialize('[1,2]', [1, 2]);
assertSerialize('[1,2,3]', [1, 2, 3]);
assertSerialize('[[]]', [[]]);
assertNotEquals('{length:0}', goog.json.serialize({length: 0}), '[]');
}
function testObjectSerialize_emptyObject() {
assertSerialize('{}', {});
}
function testObjectSerialize_oneItem() {
assertSerialize('{"a":"b"}', {a: 'b'});
}
function testObjectSerialize_twoItems() {
assertEquals('{"a":"b","c":"d"}',
goog.json.serialize({a: 'b', c: 'd'}),
'{"a":"b","c":"d"}');
}
function testObjectSerialize_whitespace() {
assertSerialize('{" ":" "}', {' ': ' '});
}
function testSerializeSkipFunction() {
var object = {
s: 'string value',
b: true,
i: 100,
f: function() { var x = 'x'; }
};
assertSerialize('', object.f);
assertSerialize('{"s":"string value","b":true,"i":100}', object);
}
function testObjectSerialize_array() {
assertNotEquals('[0,1]', goog.json.serialize([0, 1]), '{"0":"0","1":"1"}');
}
function testObjectSerialize_recursion() {
if (goog.userAgent.WEBKIT) {
return; // this makes safari 4 crash.
}
var anObject = {};
anObject.thisObject = anObject;
assertThrows('expected recursion exception', function() {
goog.json.serialize(anObject);
});
}
function testObjectSerializeWithHasOwnProperty() {
var object = {'hasOwnProperty': null};
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')) {
assertEquals('{}', goog.json.serialize(object));
} else {
assertEquals('{"hasOwnProperty":null}', goog.json.serialize(object));
}
}
// parsing
function testStringParse() {
assertEquals('Empty string', goog.json.parse('""'), '');
assertEquals('whitespace string', goog.json.parse('" "'), ' ');
// unicode without the control characters 0x00 - 0x1f, 0x7f - 0x9f
var str = allChars(0, 1000);
var jsonString = goog.json.serialize(str);
var a = eval(jsonString);
assertEquals('unicode string', goog.json.parse(jsonString), a);
assertEquals('true as a string', goog.json.parse('"true"'), 'true');
assertEquals('false as a string', goog.json.parse('"false"'), 'false');
assertEquals('null as a string', goog.json.parse('"null"'), 'null');
assertEquals('number as a string', goog.json.parse('"0"'), '0');
}
function testStringUnsafeParse() {
assertEquals('Empty string', goog.json.unsafeParse('""'), '');
assertEquals('whitespace string', goog.json.unsafeParse('" "'), ' ');
// unicode
var str = allChars(0, 1000);
var jsonString = goog.json.serialize(str);
var a = eval(jsonString);
assertEquals('unicode string', goog.json.unsafeParse(jsonString), a);
assertEquals('true as a string', goog.json.unsafeParse('"true"'), 'true');
assertEquals('false as a string', goog.json.unsafeParse('"false"'), 'false');
assertEquals('null as a string', goog.json.unsafeParse('"null"'), 'null');
assertEquals('number as a string', goog.json.unsafeParse('"0"'), '0');
}
function testNullParse() {
assertEquals('null', goog.json.parse(null), null);
assertEquals('null', goog.json.parse('null'), null);
assertNotEquals('0', goog.json.parse('0'), null);
assertNotEquals('""', goog.json.parse('""'), null);
assertNotEquals('false', goog.json.parse('false'), null);
}
function testNullUnsafeParse() {
assertEquals('null', goog.json.unsafeParse(null), null);
assertEquals('null', goog.json.unsafeParse('null'), null);
assertNotEquals('0', goog.json.unsafeParse('0'), null);
assertNotEquals('""', goog.json.unsafeParse('""'), null);
assertNotEquals('false', goog.json.unsafeParse('false'), null);
}
function testNumberParse() {
assertEquals('0', goog.json.parse('0'), 0);
assertEquals('12345', goog.json.parse('12345'), 12345);
assertEquals('-12345', goog.json.parse('-12345'), -12345);
assertEquals('0.1', goog.json.parse('0.1'), 0.1);
// either format is OK
assertEquals(1e50, goog.json.parse('1e50'));
assertEquals(1e50, goog.json.parse('1E50'));
assertEquals(1e50, goog.json.parse('1e+50'));
assertEquals(1e50, goog.json.parse('1E+50'));
// either format is OK
assertEquals(1e-50, goog.json.parse('1e-50'));
assertEquals(1e-50, goog.json.parse('1E-50'));
}
function testNumberUnsafeParse() {
assertEquals('0', goog.json.unsafeParse('0'), 0);
assertEquals('12345', goog.json.unsafeParse('12345'), 12345);
assertEquals('-12345', goog.json.unsafeParse('-12345'), -12345);
assertEquals('0.1', goog.json.unsafeParse('0.1'), 0.1);
// either format is OK
assertEquals(1e50, goog.json.unsafeParse('1e50'));
assertEquals(1e50, goog.json.unsafeParse('1E50'));
assertEquals(1e50, goog.json.unsafeParse('1e+50'));
assertEquals(1e50, goog.json.unsafeParse('1E+50'));
// either format is OK
assertEquals(1e-50, goog.json.unsafeParse('1e-50'));
assertEquals(1e-50, goog.json.unsafeParse('1E-50'));
}
function testBooleanParse() {
assertEquals('true', goog.json.parse('true'), true);
assertEquals('false', goog.json.parse('false'), false);
assertNotEquals('0', goog.json.parse('0'), false);
assertNotEquals('"false"', goog.json.parse('"false"'), false);
assertNotEquals('null', goog.json.parse('null'), false);
assertNotEquals('1', goog.json.parse('1'), true);
assertNotEquals('"true"', goog.json.parse('"true"'), true);
assertNotEquals('{}', goog.json.parse('{}'), true);
assertNotEquals('[]', goog.json.parse('[]'), true);
}
function testBooleanUnsafeParse() {
assertEquals('true', goog.json.unsafeParse('true'), true);
assertEquals('false', goog.json.unsafeParse('false'), false);
assertNotEquals('0', goog.json.unsafeParse('0'), false);
assertNotEquals('"false"', goog.json.unsafeParse('"false"'), false);
assertNotEquals('null', goog.json.unsafeParse('null'), false);
assertNotEquals('1', goog.json.unsafeParse('1'), true);
assertNotEquals('"true"', goog.json.unsafeParse('"true"'), true);
assertNotEquals('{}', goog.json.unsafeParse('{}'), true);
assertNotEquals('[]', goog.json.unsafeParse('[]'), true);
}
function testArrayParse() {
assertArrayEquals([], goog.json.parse('[]'));
assertArrayEquals([1], goog.json.parse('[1]'));
assertArrayEquals([1, 2], goog.json.parse('[1,2]'));
assertArrayEquals([1, 2, 3], goog.json.parse('[1,2,3]'));
assertArrayEquals([[]], goog.json.parse('[[]]'));
// Note that array-holes are not valid json. However, goog.json.parse
// supports them so that clients can reap the security benefits of
// goog.json.parse even if they are using this non-standard format.
assertArrayEquals([1, /* hole */, 3], goog.json.parse('[1,,3]'));
// make sure we do not get an array for something that looks like an array
assertFalse('{length:0}', 'push' in goog.json.parse('{"length":0}'));
}
function testArrayUnsafeParse() {
function arrayEquals(a1, a2) {
if (a1.length != a2.length) {
return false;
}
for (var i = 0; i < a1.length; i++) {
if (a1[i] != a2[i]) {
return false;
}
}
return true;
}
assertTrue('[]', arrayEquals(goog.json.unsafeParse('[]'), []));
assertTrue('[1]', arrayEquals(goog.json.unsafeParse('[1]'), [1]));
assertTrue('[1,2]', arrayEquals(goog.json.unsafeParse('[1,2]'), [1, 2]));
assertTrue('[1,2,3]',
arrayEquals(goog.json.unsafeParse('[1,2,3]'), [1, 2, 3]));
assertTrue('[[]]', arrayEquals(goog.json.unsafeParse('[[]]')[0], []));
// make sure we do not get an array for something that looks like an array
assertFalse('{length:0}', 'push' in goog.json.unsafeParse('{"length":0}'));
}
function testObjectParse() {
function objectEquals(a1, a2) {
for (var key in a1) {
if (a1[key] != a2[key]) {
return false;
}
}
return true;
}
assertTrue('{}', objectEquals(goog.json.parse('{}'), {}));
assertTrue('{"a":"b"}',
objectEquals(goog.json.parse('{"a":"b"}'), {a: 'b'}));
assertTrue('{"a":"b","c":"d"}',
objectEquals(goog.json.parse('{"a":"b","c":"d"}'),
{a: 'b', c: 'd'}));
assertTrue('{" ":" "}',
objectEquals(goog.json.parse('{" ":" "}'), {' ': ' '}));
// make sure we do not get an Object when it is really an array
assertTrue('[0,1]', 'length' in goog.json.parse('[0,1]'));
}
function testObjectUnsafeParse() {
function objectEquals(a1, a2) {
for (var key in a1) {
if (a1[key] != a2[key]) {
return false;
}
}
return true;
}
assertTrue('{}', objectEquals(goog.json.unsafeParse('{}'), {}));
assertTrue('{"a":"b"}',
objectEquals(goog.json.unsafeParse('{"a":"b"}'), {a: 'b'}));
assertTrue('{"a":"b","c":"d"}',
objectEquals(goog.json.unsafeParse('{"a":"b","c":"d"}'),
{a: 'b', c: 'd'}));
assertTrue('{" ":" "}',
objectEquals(goog.json.unsafeParse('{" ":" "}'), {' ': ' '}));
// make sure we do not get an Object when it is really an array
assertTrue('[0,1]', 'length' in goog.json.unsafeParse('[0,1]'));
}
function testForValidJson() {
function error_(msg, s) {
assertThrows(msg + ', Should have raised an exception: ' + s,
goog.partial(goog.json.parse, s));
}
error_('Non closed string', '"dasdas');
error_('undefined is not valid json', 'undefined');
// These numbers cannot be represented in JSON
error_('NaN cannot be presented in JSON', 'NaN');
error_('Infinity cannot be presented in JSON', 'Infinity');
error_('-Infinity cannot be presented in JSON', '-Infinity');
}
function testIsNotValid() {
assertFalse(goog.json.isValid('t'));
assertFalse(goog.json.isValid('r'));
assertFalse(goog.json.isValid('u'));
assertFalse(goog.json.isValid('e'));
assertFalse(goog.json.isValid('f'));
assertFalse(goog.json.isValid('a'));
assertFalse(goog.json.isValid('l'));
assertFalse(goog.json.isValid('s'));
assertFalse(goog.json.isValid('n'));
assertFalse(goog.json.isValid('E'));
assertFalse(goog.json.isValid('+'));
assertFalse(goog.json.isValid('-'));
assertFalse(goog.json.isValid('t++'));
assertFalse(goog.json.isValid('++t'));
assertFalse(goog.json.isValid('t--'));
assertFalse(goog.json.isValid('--t'));
assertFalse(goog.json.isValid('-t'));
assertFalse(goog.json.isValid('+t'));
assertFalse(goog.json.isValid('"\\"')); // "\"
assertFalse(goog.json.isValid('"\\')); // "\
// multiline string using \ at the end is not valid
assertFalse(goog.json.isValid('"a\\\nb"'));
assertFalse(goog.json.isValid('"\n"'));
assertFalse(goog.json.isValid('"\r"'));
assertFalse(goog.json.isValid('"\r\n"'));
// Disallow the unicode newlines
assertFalse(goog.json.isValid('"\u2028"'));
assertFalse(goog.json.isValid('"\u2029"'));
assertFalse(goog.json.isValid(' '));
assertFalse(goog.json.isValid('\n'));
assertFalse(goog.json.isValid('\r'));
assertFalse(goog.json.isValid('\r\n'));
assertFalse(goog.json.isValid('t.r'));
assertFalse(goog.json.isValid('1e'));
assertFalse(goog.json.isValid('1e-'));
assertFalse(goog.json.isValid('1e+'));
assertFalse(goog.json.isValid('1e-'));
assertFalse(goog.json.isValid('"\\\u200D\\"'));
assertFalse(goog.json.isValid('"\\\0\\"'));
assertFalse(goog.json.isValid('"\\\0"'));
assertFalse(goog.json.isValid('"\\0"'));
assertFalse(goog.json.isValid('"\x0c"'));
assertFalse(goog.json.isValid('"\\\u200D\\", alert(\'foo\') //"\n'));
}
function testIsValid() {
assertTrue(goog.json.isValid('\n""\n'));
assertTrue(goog.json.isValid('[1\n,2\r,3\u2028\n,4\u2029]'));
assertTrue(goog.json.isValid('"\x7f"'));
assertTrue(goog.json.isValid('"\x09"'));
// Test tab characters in json.
assertTrue(goog.json.isValid('{"\t":"\t"}'));
}
function testDoNotSerializeProto() {
function F() {};
F.prototype = {
c: 3
};
var obj = new F;
obj.a = 1;
obj.b = 2;
assertEquals('Should not follow the prototype chain',
'{"a":1,"b":2}',
goog.json.serialize(obj));
}
function testEscape() {
var unescaped = '1a*/]';
assertEquals('Should not escape',
'"' + unescaped + '"',
goog.json.serialize(unescaped));
var escaped = '\n\x7f\u1049';
assertEquals('Should escape',
'',
findCommonChar(escaped, goog.json.serialize(escaped)));
assertEquals('Should eval to the same string after escaping',
escaped,
goog.json.parse(goog.json.serialize(escaped)));
}
function testReplacer() {
assertSerialize('[null,null,0]', [, , 0]);
assertSerialize('[0,0,{"x":0}]', [, , {x: 0}], function(k, v) {
if (v === undefined && goog.isArray(this)) {
return 0;
}
return v;
});
assertSerialize('[0,1,2,3]', [0, 0, 0, 0], function(k, v) {
var kNum = Number(k);
if (k && !isNaN(kNum)) {
return kNum;
}
return v;
});
var f = function(k, v) {
return typeof v == 'number' ? v + 1 : v;
};
assertSerialize('{"a":1,"b":{"c":2}}', {'a': 0, 'b': {'c': 1}}, f);
}
function testDateSerialize() {
assertSerialize('{}', new Date(0));
}
function testToJSONSerialize() {
assertSerialize('{}', {toJSON: goog.functions.constant('serialized')});
assertSerialize('{"toJSON":"normal"}', {toJSON: 'normal'});
}
/**
* Asserts that the given object serializes to the given value.
* If the current browser has an implementation of JSON.serialize,
* we make sure our version matches that one.
*/
function assertSerialize(expected, obj, opt_replacer) {
assertEquals(expected, goog.json.serialize(obj, opt_replacer));
// I'm pretty sure that the goog.json.serialize behavior is correct by the ES5
// spec, but JSON.stringify(undefined) is undefined on all browsers.
if (obj === undefined) return;
// Browsers don't serialize undefined properties, but goog.json.serialize does
if (goog.isObject(obj) && ('a' in obj) && obj['a'] === undefined) return;
// Replacers are broken on IE and older versions of firefox.
if (opt_replacer && !goog.userAgent.WEBKIT) return;
// goog.json.serialize does not stringify dates the same way.
if (obj instanceof Date) return;
// goog.json.serialize does not stringify functions the same way.
if (obj instanceof Function) return;
// goog.json.serialize doesn't use the toJSON method.
if (goog.isObject(obj) && goog.isFunction(obj.toJSON)) return;
if (typeof JSON != 'undefined') {
assertEquals(
'goog.json.serialize does not match JSON.stringify',
expected,
JSON.stringify(obj, opt_replacer));
}
}
/**
* @param {string} a
* @param {string} b
* @return {string} any common character between two strings a and b.
*/
function findCommonChar(a, b) {
for (var i = 0; i < b.length; i++) {
if (a.indexOf(b.charAt(i)) >= 0) {
return b.charAt(i);
}
}
return '';
}
@@ -0,0 +1,73 @@
// 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 a class for parsing JSON using the browser's built in
* JSON library.
*/
goog.provide('goog.json.NativeJsonProcessor');
goog.require('goog.asserts');
goog.require('goog.json.Processor');
/**
* A class that parses and stringifies JSON using the browser's built-in JSON
* library, if it is avaliable.
*
* Note that the native JSON api has subtle differences across browsers, so
* use this implementation with care. See json_test#assertSerialize
* for details on the differences from goog.json.
*
* This implementation is signficantly faster than goog.json, at least on
* Chrome. See json_perf.html for a perf test showing the difference.
*
* @param {?goog.json.Replacer=} opt_replacer An optional replacer to use during
* serialization.
* @param {?goog.json.Reviver=} opt_reviver An optional reviver to use during
* parsing.
* @constructor
* @implements {goog.json.Processor}
* @final
*/
goog.json.NativeJsonProcessor = function(opt_replacer, opt_reviver) {
goog.asserts.assert(goog.isDef(goog.global['JSON']), 'JSON not defined');
/**
* @type {goog.json.Replacer|null|undefined}
* @private
*/
this.replacer_ = opt_replacer;
/**
* @type {goog.json.Reviver|null|undefined}
* @private
*/
this.reviver_ = opt_reviver;
};
/** @override */
goog.json.NativeJsonProcessor.prototype.stringify = function(object) {
return goog.global['JSON'].stringify(object, this.replacer_);
};
/** @override */
goog.json.NativeJsonProcessor.prototype.parse = function(s) {
return goog.global['JSON'].parse(s, this.reviver_);
};
@@ -0,0 +1,33 @@
// 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 JSON parsing and serialization.
*/
goog.provide('goog.json.Processor');
goog.require('goog.string.Parser');
goog.require('goog.string.Stringifier');
/**
* An interface for JSON parsing and serialization.
* @interface
* @extends {goog.string.Parser}
* @extends {goog.string.Stringifier}
*/
goog.json.Processor = function() {};
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<!--
Copyright 2012 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.json.Processor
</title>
<script src="../base.js">
</script>
<script>
goog.require('goog.json.processorTest');
</script>
</head>
<body>
</body>
</html>
@@ -0,0 +1,88 @@
// 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.
goog.provide('goog.json.processorTest');
goog.setTestOnly('goog.json.processorTest');
goog.require('goog.json.EvalJsonProcessor');
goog.require('goog.json.NativeJsonProcessor');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
var SUPPORTS_NATIVE_JSON = false;
function setUpPage() {
SUPPORTS_NATIVE_JSON = goog.global['JSON'] &&
!(goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('5.0'));
}
var REPLACER = function(k, v) {
return !!k ? v + 'd' : v;
};
var REVIVER = function(k, v) {
return !!k ? v.substring(0, v.length - 1) : v;
};
// Just sanity check parsing and stringifying.
// Thorough tests are in json_test.html.
function testJsParser() {
var json = '{"a":1,"b":{"c":2}}';
runParsingTest(new goog.json.EvalJsonProcessor(), json, json);
}
function testNativeParser() {
if (!SUPPORTS_NATIVE_JSON) {
return;
}
var json = '{"a":1,"b":{"c":2}}';
runParsingTest(new goog.json.NativeJsonProcessor(), json, json);
}
function testJsParser_withReplacer() {
runParsingTest(new goog.json.EvalJsonProcessor(REPLACER),
'{"a":"foo","b":"goo"}', '{"a":"food","b":"good"}');
}
function testNativeParser_withReplacer() {
if (!SUPPORTS_NATIVE_JSON) {
return;
}
runParsingTest(new goog.json.NativeJsonProcessor(REPLACER),
'{"a":"foo","b":"goo"}', '{"a":"food","b":"good"}');
}
function testNativeParser_withReviver() {
if (!SUPPORTS_NATIVE_JSON) {
return;
}
var json = '{"a":"fod","b":"god"}';
runParsingTest(new goog.json.NativeJsonProcessor(REPLACER, REVIVER),
json, json);
}
function testUnsafeJsParser() {
var json = '{"a":1,"b":{"c":2}}';
runParsingTest(new goog.json.EvalJsonProcessor(null, true), json, json);
}
function testUnsafeJsParser_withReplacer() {
runParsingTest(new goog.json.EvalJsonProcessor(REPLACER, true),
'{"a":"foo","b":"goo"}', '{"a":"food","b":"good"}');
}
function runParsingTest(parser, input, expected) {
assertEquals(expected, parser.stringify(parser.parse(input)));
}