blob: 77c4886936fee14b9dbfaed48a1907feb4bd75b9 [file] [log] [blame]
// 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 event delivery using PbEventMixin.
library event_test;
import 'package:protobuf/protobuf.dart'
show GeneratedMessage, Extension, ExtensionRegistry, PbFieldType;
import 'package:protobuf/protobuf.dart';
import 'package:protobuf/src/protobuf/mixins/event_mixin.dart'
show PbEventMixin, PbFieldChange;
import 'package:test/test.dart' show test, expect;
import 'mock_util.dart' show MockMessage, mockInfo;
class Rec extends MockMessage with PbEventMixin {
@override
BuilderInfo get info_ => _info;
static final _info = mockInfo('Rec', () => Rec());
@override
Rec createEmptyInstance() => Rec();
}
Extension comment = Extension('Rec', 'comment', 6, PbFieldType.OS);
void main() {
test('Events are sent when setting and clearing a non-repeated field', () {
var log = makeLog();
var r = Rec();
r.changes.listen((List<PbFieldChange> changes) {
log.add(changes);
});
r.val = 123;
r.deliverChanges();
checkLogOnce(log, [1, 42, 123]);
r.val = 456;
r.deliverChanges();
checkLogOnce(log, [1, 123, 456]);
r.val = 456; // no change
r.deliverChanges();
checkLog(log, []);
r.clearField(1);
r.deliverChanges();
checkLogOnce(log, [1, 456, 42]);
r.clearField(1); // no change
r.deliverChanges();
checkLog(log, []);
});
test('Events are sent when creating and clearing a repeated field', () {
var log = makeLog();
var r = Rec();
r.changes.listen((List<PbFieldChange> changes) {
log.add(changes);
});
// Accessing a repeated field replaces the default,
// read-only [] with a mutable [],
// which counts as a change.
var list = r.int32s;
r.deliverChanges();
checkLogOnce(log, [4, [], []]);
// No event yet for modifying a repeated field.
list.add(123);
r.deliverChanges();
checkLog(log, []);
r.clearField(4);
r.deliverChanges();
checkLogOnce(log, [
4,
[123],
[]
]);
});
test('Events are sent when clearing multiple fields', () {
var log = makeLog();
var r = Rec()
..val = 123
..str = 'hello'
..child = Rec()
..int32s.add(456);
r.changes.listen((List<PbFieldChange> changes) {
// verify that we are not called until all fields are cleared
checkHasAllFields(r, false);
log.add(changes);
});
r.clear();
r.deliverChanges();
checkLog(log, [
[
[1, 123, 42],
[2, 'hello', ''],
[3, '<msg>', '<msg>'],
[
4,
[456],
[]
]
]
]);
});
test('Events are sent when merging from another protobuf', () {
var log = makeLog();
var src = Rec()
..val = 123
..str = 'hello'
..child = Rec()
..int32s.add(456);
var dest = Rec();
dest.changes.listen((List<PbFieldChange> changes) {
checkHasAllFields(dest, true);
log.add(changes);
});
dest.mergeFromMessage(src);
dest.deliverChanges();
checkLog(log, [
[
[1, 42, 123],
[2, '', 'hello'],
[3, '<msg>', '<msg>'],
[
4,
[],
[456]
]
]
]);
});
test('Events are sent when merging JSON', () {
var log = makeLog();
var r = Rec();
r.changes.listen((List<PbFieldChange> changes) {
// verify that we are not called until all fields are set
checkHasAllFields(r, true);
log.add(changes);
});
r.mergeFromJson('{"1": 123, "2": "hello", "3": {}, "4": [456]}');
// The changes should not include the repeated message.
r.deliverChanges();
checkLog(log, [
[
[1, 42, 123],
[2, '', 'hello'],
[3, '<msg>', '<msg>'],
[
4,
[],
[456]
]
]
]);
});
test('Events are sent when merging binary', () {
var log = makeLog();
var bytes = (Rec()
..val = 123
..str = 'hello'
..child = Rec()
..int32s.add(456))
.writeToBuffer();
var r = Rec();
r.changes.listen((List<PbFieldChange> changes) {
// verify that we are not called until all fields are set
checkHasAllFields(r, true);
log.add(changes);
});
r.mergeFromBuffer(bytes);
// The changes should not include the repeated message.
r.deliverChanges();
checkLog(log, [
[
[1, 42, 123],
[2, '', 'hello'],
[3, '<msg>', '<msg>'],
[
4,
[],
[456]
]
]
]);
});
test('Events are sent for extensions', () {
var log = makeLog();
var r = Rec();
r.changes.listen((List<PbFieldChange> changes) {
log.add(changes);
});
final tag = comment.tagNumber;
void setComment(String value) {
r.setExtension(comment, value);
expect(r.getExtension(comment), value);
r.deliverChanges();
checkLogOnce(log, [tag, '', value]);
}
void clear(String expected) {
r.clear();
r.deliverChanges();
checkLogOnce(log, [tag, expected, '']);
}
setComment('hello');
clear('hello');
setComment('hello');
r.setField(6, 'hi');
r.deliverChanges();
checkLogOnce(log, [tag, 'hello', 'hi']);
clear('hi');
setComment('hello');
r.clearExtension(comment);
r.deliverChanges();
checkLogOnce(log, [tag, 'hello', '']);
setComment('hello');
r.clearField(comment.tagNumber);
r.deliverChanges();
checkLogOnce(log, [tag, 'hello', '']);
var registry = ExtensionRegistry()..add(comment);
r.mergeFromJson('{"$tag": "hello"}', registry);
expect(r.getExtension(comment), 'hello');
r.deliverChanges();
checkLogOnce(log, [tag, '', 'hello']);
clear('hello');
var src = Rec()..setExtension(comment, 'hello');
r.mergeFromMessage(src);
expect(r.getExtension(comment), 'hello');
r.deliverChanges();
checkLogOnce(log, [tag, '', 'hello']);
clear('hello');
var bytes = src.writeToBuffer();
r.mergeFromBuffer(bytes, registry);
expect(r.getExtension(comment), 'hello');
r.deliverChanges();
checkLogOnce(log, [tag, '', 'hello']);
clear('hello');
});
}
List<List<PbFieldChange>> makeLog() => <List<PbFieldChange>>[];
void checkLogOnce(List<List<PbFieldChange>> log, List expectedEntry) =>
checkLog(log, [
[expectedEntry]
]);
void checkLog(List<List<PbFieldChange>> log, List<List<List>> expected) {
var actual = <List<List>>[];
for (var list in log) {
var tuples = <List>[];
for (var item in list) {
tuples.add(toTuple(item));
}
actual.add(tuples);
}
log.clear();
expect(actual, expected);
}
void checkHasAllFields(Rec r, bool expected) {
expect(r.hasField(1), expected);
expect(r.hasField(2), expected);
expect(r.hasField(3), expected);
expect(r.hasField(4), expected);
}
List toTuple(PbFieldChange fc) {
dynamic fixValue(v) {
if (v is GeneratedMessage) {
return '<msg>';
}
return v;
}
return [fc.tag, fixValue(fc.oldValue), fixValue(fc.newValue)];
}