| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // Tests for GeneratedMessage methods. |
| |
| import 'package:fixnum/fixnum.dart' show Int64; |
| import 'package:protobuf/protobuf.dart'; |
| import 'package:protobuf/src/protobuf/internal.dart'; |
| import 'package:test/test.dart' show Matcher, expect, isA, test, throwsA; |
| |
| import 'mock_util.dart' show MockMessage, mockEmptyInfo, mockInfo; |
| |
| class Rec extends MockMessage { |
| @override |
| BuilderInfo get info_ => _info; |
| static final _info = mockInfo('Rec', Rec.new); |
| |
| @override |
| Rec createEmptyInstance() => Rec(); |
| } |
| |
| class EmptyRec extends MockMessage { |
| @override |
| BuilderInfo get info_ => _info; |
| static final _info = mockEmptyInfo('EmptyRec', EmptyRec.new); |
| |
| @override |
| EmptyRec createEmptyInstance() => EmptyRec(); |
| } |
| |
| class Ext extends MockMessage { |
| @override |
| BuilderInfo get info_ => _info; |
| static final _info = mockInfo('Ext', Ext.new); |
| |
| @override |
| Ext createEmptyInstance() => Ext(); |
| |
| static final Extension<int> count = Extension( |
| 'Rec', |
| 'count', |
| 101, |
| PbFieldType.O3, |
| ); |
| |
| static final Extension<String> items = Extension.repeated( |
| 'Rec', |
| 'items', |
| 102, |
| PbFieldType.PS, |
| check: (value) => value is String, |
| ); |
| |
| static final Extension<List<int>> data = Extension( |
| 'Rec', |
| 'data', |
| 103, |
| PbFieldType.OY, |
| ); |
| } |
| |
| Matcher throwsError(String expectedMessage) => throwsA( |
| isA<ArgumentError>().having((p0) => p0.message, 'message', expectedMessage), |
| ); |
| |
| void main() { |
| final recProto = |
| Rec() |
| ..val = 123 |
| ..str = 'a\n\r\t"\\b' |
| ..bytes = [0, 1, 2, 127, 128, 255] |
| ..child = (Rec()..val = 456) |
| ..int32s.addAll([1, 2, 3]) |
| ..int64 = Int64.MAX_VALUE |
| ..stringMap['key "1"'] = '''value\n1''' |
| ..stringMap['key 2'] = 'value 2'; |
| |
| test('getField with invalid tag throws exception', () { |
| final r = Rec(); |
| expect(() { |
| r.getField(123); |
| }, throwsError('tag 123 not defined in Rec')); |
| }); |
| |
| test('getDefaultForField with invalid tag throws exception', () { |
| final r = Rec(); |
| expect(() { |
| r.getDefaultForField(123); |
| }, throwsError('tag 123 not defined in Rec')); |
| }); |
| |
| test('operator== and hashCode works for frozen message', () { |
| final a = |
| Rec() |
| ..val = 123 |
| ..int32s.addAll([1, 2, 3]) |
| ..freeze(); |
| final b = |
| Rec() |
| ..val = 123 |
| ..int32s.addAll([1, 2, 3]); |
| |
| expect(a.hashCode, b.hashCode); |
| expect(a == b, true); |
| expect(b == a, true); |
| }); |
| |
| test('isFrozen works', () { |
| final a = |
| Rec() |
| ..val = 123 |
| ..int32s.addAll([1, 2, 3]) |
| ..child = (Rec()..val = 100); |
| expect(a.isFrozen, false); |
| a.child.freeze(); |
| expect(a.child.isFrozen, true); |
| expect(a.isFrozen, false); |
| a.freeze(); |
| expect(a.isFrozen, true); |
| }); |
| |
| test('operator== and hashCode work for a simple record', () { |
| final a = Rec(); |
| expect(a == a, true); |
| |
| final b = Rec(); |
| expect(a.info_ == b.info_, true, reason: 'BuilderInfo should be the same'); |
| expect(a == b, true); |
| expect(a.hashCode, b.hashCode); |
| |
| a.val = 123; |
| expect(a == b, false); |
| b.val = 123; |
| expect(a == b, true); |
| expect(a.hashCode, b.hashCode); |
| |
| a.child = Rec(); |
| expect(a == b, false); |
| b.child = Rec(); |
| expect(a == b, true); |
| expect(a.hashCode, b.hashCode); |
| }); |
| |
| test('toTextFormatString works', () { |
| expect(recProto.toTextFormat(), _expectedTextProto); |
| }); |
| |
| test('toTextFormatString handles unknown JSON data', () { |
| final a = Rec(); |
| a.mergeFromJson( |
| '''{"1": 123, "2": "hello", "9": 456, "10": "UnknownFieldValue", ''' |
| '''"11": {"1": 999, "2": {"1": 1000, "2": "ab\\\\c\\""}}, "13": "''' |
| // [bytes] in JSON are base64 encoded and we are not able to decode them |
| // since we don't know if it's a string or bytes. |
| '''AAECh/8="}''', |
| ); |
| expect(a.toTextFormat(), _textFormatProtoWithUnknownJsonFields); |
| }); |
| |
| test('toTextFormatString handles unknown fields', () { |
| final buffer = recProto.writeToBuffer(); |
| final emptyRec = EmptyRec()..mergeFromBuffer(buffer); |
| expect(emptyRec.toTextFormat(), _textFormatProtoWithUnknownFields); |
| }); |
| |
| test('toTextFormatString handles extensions fields', () { |
| final a = |
| Rec() |
| ..val = 42 |
| ..setExtension(Ext.count, 123) |
| ..addExtension(Ext.items, 'a') |
| ..addExtension(Ext.items, 'b"c') |
| ..setExtension(Ext.data, [0, 1, 2, 127, 128, 255]); |
| |
| expect(a.toTextFormat(), _expectedTextProtoWithExtensions); |
| }); |
| } |
| |
| const _expectedTextProto = ''' |
| val: 123 |
| str: "a\\n\r\t\\"\\\\b" |
| child { |
| val: 456 |
| } |
| int32s: 1 |
| int32s: 2 |
| int32s: 3 |
| int64: 9223372036854775807 |
| string_map { |
| key: "key \\"1\\"" |
| value: "value\\n1" |
| } |
| string_map { |
| key: "key 2" |
| value: "value 2" |
| } |
| bytes: "\\000\\001\\002\\177\\200\\377" |
| '''; |
| |
| const _expectedTextProtoWithExtensions = ''' |
| val: 42 |
| [count]: 123 |
| [items]: "a" |
| [items]: "b\\"c" |
| [data]: "\\000\\001\\002\\177\\200\\377" |
| '''; |
| |
| const _textFormatProtoWithUnknownFields = ''' |
| 1: 123 |
| 2: "a\\n\\r\\t\\"\\\\b" |
| 3: { |
| 1: 456 |
| } |
| 4: 1 |
| 4: 2 |
| 4: 3 |
| 5: 9223372036854775807 |
| 8: { |
| 1: "key \\"1\\"" |
| 2: "value\\n1" |
| } |
| 8: { |
| 1: "key 2" |
| 2: "value 2" |
| } |
| 12: "\\000\\001\\002\\177\\200\\377" |
| '''; |
| |
| const _textFormatProtoWithUnknownJsonFields = ''' |
| val: 123 |
| str: "hello" |
| 9: 456 |
| 10: "UnknownFieldValue" |
| 11 { |
| 1: 999 |
| 2 { |
| 1: 1000 |
| 2: "ab\\\\c\\"" |
| } |
| } |
| 13: "AAECh/8=" |
| '''; |