407 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			407 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
| // Protocol Buffers - Google's data interchange format
 | |
| // Copyright 2008 Google Inc.  All rights reserved.
 | |
| // https://developers.google.com/protocol-buffers/
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //     * Redistributions of source code must retain the above copyright
 | |
| // notice, this list of conditions and the following disclaimer.
 | |
| //     * Redistributions in binary form must reproduce the above
 | |
| // copyright notice, this list of conditions and the following disclaimer
 | |
| // in the documentation and/or other materials provided with the
 | |
| // distribution.
 | |
| //     * Neither the name of Google Inc. nor the names of its
 | |
| // contributors may be used to endorse or promote products derived from
 | |
| // this software without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| goog.require('goog.testing.asserts');
 | |
| goog.require('goog.userAgent');
 | |
| 
 | |
| // CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
 | |
| goog.require('proto.jspb.test.MapValueEnum');
 | |
| goog.require('proto.jspb.test.MapValueMessage');
 | |
| goog.require('proto.jspb.test.TestMapFields');
 | |
| goog.require('proto.jspb.test.TestMapFieldsOptionalKeys');
 | |
| goog.require('proto.jspb.test.MapEntryOptionalKeysStringKey');
 | |
| goog.require('proto.jspb.test.MapEntryOptionalKeysInt32Key');
 | |
| goog.require('proto.jspb.test.MapEntryOptionalKeysInt64Key');
 | |
| goog.require('proto.jspb.test.MapEntryOptionalKeysBoolKey');
 | |
| 
 | |
| // CommonJS-LoadFromFile: test_pb proto.jspb.test
 | |
| goog.require('proto.jspb.test.MapValueMessageNoBinary');
 | |
| goog.require('proto.jspb.test.TestMapFieldsNoBinary');
 | |
| 
 | |
| /**
 | |
|  * Helper: check that the given map has exactly this set of (sorted) entries.
 | |
|  * @param {!jspb.Map} map
 | |
|  * @param {!Array<!Array<?>>} entries
 | |
|  */
 | |
| function checkMapEquals(map, entries) {
 | |
|   var arr = map.toArray();
 | |
|   assertEquals(arr.length, entries.length);
 | |
|   for (var i = 0; i < arr.length; i++) {
 | |
|     assertElementsEquals(arr[i], entries[i]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Converts an ES6 iterator to an array.
 | |
|  * @template T
 | |
|  * @param {!Iterator<T>} iter an iterator
 | |
|  * @return {!Array<T>}
 | |
|  */
 | |
| function toArray(iter) {
 | |
|   var arr = [];
 | |
|   while (true) {
 | |
|     var val = iter.next();
 | |
|     if (val.done) {
 | |
|       break;
 | |
|     }
 | |
|     arr.push(val.value);
 | |
|   }
 | |
|   return arr;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Helper: generate test methods for this TestMapFields class.
 | |
|  * @param {?} msgInfo
 | |
|  * @param {?} submessageCtor
 | |
|  * @param {string} suffix
 | |
|  */
 | |
| function makeTests(msgInfo, submessageCtor, suffix) {
 | |
|   /**
 | |
|    * Helper: fill all maps on a TestMapFields.
 | |
|    * @param {?} msg
 | |
|    */
 | |
|   var fillMapFields = function(msg) {
 | |
|     msg.getMapStringStringMap().set('asdf', 'jkl;').set('key 2', 'hello world');
 | |
|     msg.getMapStringInt32Map().set('a', 1).set('b', -2);
 | |
|     msg.getMapStringInt64Map().set('c', 0x100000000).set('d', 0x200000000);
 | |
|     msg.getMapStringBoolMap().set('e', true).set('f', false);
 | |
|     msg.getMapStringDoubleMap().set('g', 3.14159).set('h', 2.71828);
 | |
|     msg.getMapStringEnumMap()
 | |
|         .set('i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR)
 | |
|         .set('j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ);
 | |
|     msg.getMapStringMsgMap()
 | |
|         .set('k', new submessageCtor())
 | |
|         .set('l', new submessageCtor());
 | |
|     msg.getMapStringMsgMap().get('k').setFoo(42);
 | |
|     msg.getMapStringMsgMap().get('l').setFoo(84);
 | |
|     msg.getMapInt32StringMap().set(-1, 'a').set(42, 'b');
 | |
|     msg.getMapInt64StringMap().set(0x123456789abc, 'c').set(0xcba987654321, 'd');
 | |
|     msg.getMapBoolStringMap().set(false, 'e').set(true, 'f');
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|    * Helper: check all maps on a TestMapFields.
 | |
|    * @param {?} msg
 | |
|    */
 | |
|   var checkMapFields = function(msg) {
 | |
|     checkMapEquals(msg.getMapStringStringMap(), [
 | |
|           ['asdf', 'jkl;'],
 | |
|           ['key 2', 'hello world']
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapStringInt32Map(), [
 | |
|           ['a', 1],
 | |
|           ['b', -2]
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapStringInt64Map(), [
 | |
|           ['c', 0x100000000],
 | |
|           ['d', 0x200000000]
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapStringBoolMap(), [
 | |
|           ['e', true],
 | |
|           ['f', false]
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapStringDoubleMap(), [
 | |
|           ['g', 3.14159],
 | |
|           ['h', 2.71828]
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapStringEnumMap(), [
 | |
|           ['i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR],
 | |
|           ['j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ]
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapInt32StringMap(), [
 | |
|           [-1, 'a'],
 | |
|           [42, 'b']
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapInt64StringMap(), [
 | |
|           [0x123456789abc, 'c'],
 | |
|           [0xcba987654321, 'd']
 | |
|     ]);
 | |
|     checkMapEquals(msg.getMapBoolStringMap(), [
 | |
|           [false, 'e'],
 | |
|           [true, 'f']
 | |
|     ]);
 | |
| 
 | |
|     assertEquals(msg.getMapStringMsgMap().getLength(), 2);
 | |
|     assertEquals(msg.getMapStringMsgMap().get('k').getFoo(), 42);
 | |
|     assertEquals(msg.getMapStringMsgMap().get('l').getFoo(), 84);
 | |
| 
 | |
|     var entries = toArray(msg.getMapStringMsgMap().entries());
 | |
|     assertEquals(entries.length, 2);
 | |
|     entries.forEach(function(entry) {
 | |
|       var key = entry[0];
 | |
|       var val = entry[1];
 | |
|       assert(val === msg.getMapStringMsgMap().get(key));
 | |
|     });
 | |
| 
 | |
|     msg.getMapStringMsgMap().forEach(function(val, key) {
 | |
|       assert(val === msg.getMapStringMsgMap().get(key));
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   it('testMapStringStringField' + suffix, function() {
 | |
|     var msg = new msgInfo.constructor();
 | |
|     assertEquals(msg.getMapStringStringMap().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringInt32Map().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringInt64Map().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringBoolMap().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringDoubleMap().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringEnumMap().getLength(), 0);
 | |
|     assertEquals(msg.getMapStringMsgMap().getLength(), 0);
 | |
| 
 | |
|     // Re-create to clear out any internally-cached wrappers, etc.
 | |
|     msg = new msgInfo.constructor();
 | |
|     var m = msg.getMapStringStringMap();
 | |
|     assertEquals(m.has('asdf'), false);
 | |
|     assertEquals(m.get('asdf'), undefined);
 | |
|     m.set('asdf', 'hello world');
 | |
|     assertEquals(m.has('asdf'), true);
 | |
|     assertEquals(m.get('asdf'), 'hello world');
 | |
|     m.set('jkl;', 'key 2');
 | |
|     assertEquals(m.has('jkl;'), true);
 | |
|     assertEquals(m.get('jkl;'), 'key 2');
 | |
|     assertEquals(m.getLength(), 2);
 | |
|     var it = m.entries();
 | |
|     assertElementsEquals(it.next().value, ['asdf', 'hello world']);
 | |
|     assertElementsEquals(it.next().value, ['jkl;', 'key 2']);
 | |
|     assertEquals(it.next().done, true);
 | |
|     checkMapEquals(m, [
 | |
|         ['asdf', 'hello world'],
 | |
|         ['jkl;', 'key 2']
 | |
|     ]);
 | |
|     m.del('jkl;');
 | |
|     assertEquals(m.has('jkl;'), false);
 | |
|     assertEquals(m.get('jkl;'), undefined);
 | |
|     assertEquals(m.getLength(), 1);
 | |
|     it = m.keys();
 | |
|     assertEquals(it.next().value, 'asdf');
 | |
|     assertEquals(it.next().done, true);
 | |
|     it = m.values();
 | |
|     assertEquals(it.next().value, 'hello world');
 | |
|     assertEquals(it.next().done, true);
 | |
| 
 | |
|     var count = 0;
 | |
|     m.forEach(function(value, key, map) {
 | |
|       assertEquals(map, m);
 | |
|       assertEquals(key, 'asdf');
 | |
|       assertEquals(value, 'hello world');
 | |
|       count++;
 | |
|     });
 | |
|     assertEquals(count, 1);
 | |
| 
 | |
|     m.clear();
 | |
|     assertEquals(m.getLength(), 0);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests operations on maps with all key and value types.
 | |
|    */
 | |
|   it('testAllMapTypes' + suffix, function() {
 | |
|     var msg = new msgInfo.constructor();
 | |
|     fillMapFields(msg);
 | |
|     checkMapFields(msg);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   if (msgInfo.deserializeBinary) {
 | |
|     /**
 | |
|      * Tests serialization and deserialization in binary format.
 | |
|      */
 | |
|     it('testBinaryFormat' + suffix, function() {
 | |
|       if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) {
 | |
|         // IE8/9 currently doesn't support binary format because they lack
 | |
|         // TypedArray.
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       // Check that the format is correct.
 | |
|       var msg = new msgInfo.constructor();
 | |
|       msg.getMapStringStringMap().set('A', 'a');
 | |
|       var serialized = msg.serializeBinary();
 | |
|       var expectedSerialized = [
 | |
|           0x0a, 0x6, // field 1 (map_string_string), delimited, length 6
 | |
|           0x0a, 0x1, // field 1 in submessage (key), delimited, length 1
 | |
|           0x41,      // ASCII 'A'
 | |
|           0x12, 0x1, // field 2 in submessage (value), delimited, length 1
 | |
|           0x61       // ASCII 'a'
 | |
|       ];
 | |
|       assertEquals(serialized.length, expectedSerialized.length);
 | |
|       for (var i = 0; i < serialized.length; i++) {
 | |
|         assertEquals(serialized[i], expectedSerialized[i]);
 | |
|       }
 | |
| 
 | |
|       // Check that all map fields successfully round-trip.
 | |
|       msg = new msgInfo.constructor();
 | |
|       fillMapFields(msg);
 | |
|       serialized = msg.serializeBinary();
 | |
|       var decoded = msgInfo.deserializeBinary(serialized);
 | |
|       checkMapFields(decoded);
 | |
|     });
 | |
|     /**
 | |
|      * Tests deserialization of undefined map keys go to default values in binary format.
 | |
|      */
 | |
|     it('testMapDeserializationForUndefinedKeys', function() {
 | |
|       var testMessageOptionalKeys = new proto.jspb.test.TestMapFieldsOptionalKeys();
 | |
|       var mapEntryStringKey = new proto.jspb.test.MapEntryOptionalKeysStringKey();
 | |
|       mapEntryStringKey.setValue("a");
 | |
|       testMessageOptionalKeys.setMapStringString(mapEntryStringKey);
 | |
|       var mapEntryInt32Key = new proto.jspb.test.MapEntryOptionalKeysInt32Key();
 | |
|       mapEntryInt32Key.setValue("b");
 | |
|       testMessageOptionalKeys.setMapInt32String(mapEntryInt32Key);
 | |
|       var mapEntryInt64Key = new proto.jspb.test.MapEntryOptionalKeysInt64Key();
 | |
|       mapEntryInt64Key.setValue("c");
 | |
|       testMessageOptionalKeys.setMapInt64String(mapEntryInt64Key);
 | |
|       var mapEntryBoolKey = new proto.jspb.test.MapEntryOptionalKeysBoolKey();
 | |
|       mapEntryBoolKey.setValue("d");
 | |
|       testMessageOptionalKeys.setMapBoolString(mapEntryBoolKey);
 | |
|       var deserializedMessage = msgInfo.deserializeBinary(
 | |
|         testMessageOptionalKeys.serializeBinary()
 | |
|        );
 | |
|       checkMapEquals(deserializedMessage.getMapStringStringMap(), [
 | |
|         ['', 'a']
 | |
|       ]);
 | |
|       checkMapEquals(deserializedMessage.getMapInt32StringMap(), [
 | |
|         [0, 'b']
 | |
|       ]);
 | |
|       checkMapEquals(deserializedMessage.getMapInt64StringMap(), [
 | |
|         [0, 'c']
 | |
|       ]);
 | |
|       checkMapEquals(deserializedMessage.getMapBoolStringMap(), [
 | |
|         [false, 'd']
 | |
|       ]);
 | |
|     });
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Exercises the lazy map<->underlying array sync.
 | |
|    */
 | |
|   it('testLazyMapSync' + suffix, function() {
 | |
|     // Start with a JSPB array containing a few map entries.
 | |
|     var entries = [
 | |
|         ['a', 'entry 1'],
 | |
|         ['c', 'entry 2'],
 | |
|         ['b', 'entry 3']
 | |
|     ];
 | |
|     var msg = new msgInfo.constructor([entries]);
 | |
|     assertEquals(entries.length, 3);
 | |
|     assertEquals(entries[0][0], 'a');
 | |
|     assertEquals(entries[1][0], 'c');
 | |
|     assertEquals(entries[2][0], 'b');
 | |
|     msg.getMapStringStringMap().del('a');
 | |
|     assertEquals(entries.length, 3);  // not yet sync'd
 | |
|     msg.toArray();                // force a sync
 | |
|     assertEquals(entries.length, 2);
 | |
|     assertEquals(entries[0][0], 'b'); // now in sorted order
 | |
|     assertEquals(entries[1][0], 'c');
 | |
| 
 | |
|     var a = msg.toArray();
 | |
|     assertEquals(a[0], entries);  // retains original reference
 | |
|   });
 | |
| 
 | |
|   /**
 | |
|    * Returns IteratorIterables for entries(), keys() and values().
 | |
|    */
 | |
|   it('testIteratorIterables' + suffix, function() {
 | |
|     var msg = new msgInfo.constructor();
 | |
|     var m = msg.getMapStringStringMap();
 | |
|     m.set('key1', 'value1');
 | |
|     m.set('key2', 'value2');
 | |
|     var entryIterator = m.entries();
 | |
|     assertElementsEquals(entryIterator.next().value, ['key1', 'value1']);
 | |
|     assertElementsEquals(entryIterator.next().value, ['key2', 'value2']);
 | |
|     assertEquals(entryIterator.next().done, true);
 | |
| 
 | |
|     try {
 | |
|       var entryIterable = m.entries()[Symbol.iterator]();
 | |
|       assertElementsEquals(entryIterable.next().value, ['key1', 'value1']);
 | |
|       assertElementsEquals(entryIterable.next().value, ['key2', 'value2']);
 | |
|       assertEquals(entryIterable.next().done, true);
 | |
|     } catch (err) {
 | |
|       // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
 | |
|       // undefined in some environment.
 | |
|       if (err.name != 'TypeError' && err.name != 'ReferenceError') {
 | |
|         throw err;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     var keyIterator = m.keys();
 | |
|     assertEquals(keyIterator.next().value, 'key1');
 | |
|     assertEquals(keyIterator.next().value, 'key2');
 | |
|     assertEquals(keyIterator.next().done, true);
 | |
| 
 | |
|     try {
 | |
|       var keyIterable = m.keys()[Symbol.iterator]();
 | |
|       assertEquals(keyIterable.next().value, 'key1');
 | |
|       assertEquals(keyIterable.next().value, 'key2');
 | |
|       assertEquals(keyIterable.next().done, true);
 | |
|     } catch (err) {
 | |
|       // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
 | |
|       // undefined in some environment.
 | |
|       if (err.name != 'TypeError' && err.name != 'ReferenceError') {
 | |
|         throw err;
 | |
|       }
 | |
|     }
 | |
|     var valueIterator = m.values();
 | |
|     assertEquals(valueIterator.next().value, 'value1');
 | |
|     assertEquals(valueIterator.next().value, 'value2');
 | |
|     assertEquals(valueIterator.next().done, true);
 | |
| 
 | |
|     try {
 | |
|       var valueIterable = m.values()[Symbol.iterator]();
 | |
|       assertEquals(valueIterable.next().value, 'value1');
 | |
|       assertEquals(valueIterable.next().value, 'value2');
 | |
|       assertEquals(valueIterable.next().done, true);
 | |
|     } catch (err) {
 | |
|       // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
 | |
|       // undefined in some environment.
 | |
|       if (err.name != 'TypeError' && err.name != 'ReferenceError') {
 | |
|         throw err;
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| describe('mapsTest', function() {
 | |
|   makeTests(
 | |
|       {
 | |
|         constructor: proto.jspb.test.TestMapFields,
 | |
|         deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary
 | |
|       },
 | |
|       proto.jspb.test.MapValueMessage, '_Binary');
 | |
|   makeTests(
 | |
|       {
 | |
|         constructor: proto.jspb.test.TestMapFieldsNoBinary,
 | |
|         deserializeBinary: null
 | |
|       },
 | |
|       proto.jspb.test.MapValueMessageNoBinary, '_NoBinary');
 | |
| });
 |