blob: 30cf2f8918b81413227ac65e9aaa1c715cb6fb4b [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// 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.
import {perfetto} from '../gen/protos';
import {buildMetricProtoNamespace} from './metrics';
import {FieldDescriptorProto} from './protos';
// Some shorthands and a convenience function for more readable test proto
// message definitions. The field "optional string foo = 1" now becomes
// "fld(optional, tString, 'foo', 1)".
const optional = FieldDescriptorProto.Label.LABEL_OPTIONAL;
const repeated = FieldDescriptorProto.Label.LABEL_REPEATED;
const tString = FieldDescriptorProto.Type.TYPE_STRING;
const tDouble = FieldDescriptorProto.Type.TYPE_DOUBLE;
const tInt64 = FieldDescriptorProto.Type.TYPE_INT64;
function fld(
label: FieldDescriptorProto.Label,
fieldType: FieldDescriptorProto.Type|string,
name: string,
fieldNumber: number): perfetto.protos.IFieldDescriptorProto {
const type = (typeof fieldType === 'string') ?
FieldDescriptorProto.Type.TYPE_MESSAGE :
fieldType;
const typeName = (typeof fieldType === 'string') ? fieldType : undefined;
return {label, type, name, number: fieldNumber, typeName};
}
test('handles simple proto message', () => {
const descriptor = {
name: '.MyProto',
field: [
fld(optional, tString, 'string_field', 1),
fld(optional, tDouble, 'double_field', 2),
]
};
const namespace = buildMetricProtoNamespace([descriptor]);
const myProto = namespace.lookupType('.MyProto');
const jsonMsg = {string_field: 'hello', double_field: 42.324};
const encoded = myProto.encode(jsonMsg).finish();
const decoded = myProto.decode(encoded);
expect(decoded).toEqual(jsonMsg);
});
test('handles repeated field', () => {
const descriptor = {
name: '.MyProto',
field: [fld(repeated, tString, 'string_field', 1)]
};
const namespace = buildMetricProtoNamespace([descriptor]);
const myProto = namespace.lookupType('.MyProto');
const jsonMsg = {string_field: ['aaa', 'bbb']};
const encoded = myProto.encode(jsonMsg).finish();
const decoded = myProto.decode(encoded);
expect(decoded).toEqual(jsonMsg);
});
test('handles proto message with package', () => {
const descriptor = {
name: '.MyPackage.MyProto',
field: [fld(optional, tString, 'string_field', 1)]
};
const namespace = buildMetricProtoNamespace([descriptor]);
expect(namespace.lookup('MyPackage')).not.toBeNull();
const myProto = namespace.lookupType('.MyPackage.MyProto');
const jsonMsg = {string_field: 'hello'};
const encoded = myProto.encode(jsonMsg).finish();
const decoded = myProto.decode(encoded);
expect(decoded).toEqual(jsonMsg);
});
test('cross links message definitions', () => {
const fooDesc = {
name: '.FooPackage.NestedProto',
field: [fld(optional, tString, 'foo', 1)]
};
const barDesc = {
name: '.BarPackage.NestedProto',
field: [fld(optional, tInt64, 'bar', 1)]
};
const myProtoDesc = {
name: '.MyProto',
field: [
fld(optional, '.FooPackage.NestedProto', 'nested_foo', 1),
fld(repeated, '.BarPackage.NestedProto', 'nested_bar', 2),
]
};
const namespace = buildMetricProtoNamespace([myProtoDesc, fooDesc, barDesc]);
const myProto = namespace.lookupType('.MyProto');
const jsonMsg = {
nested_foo: {foo: 'hello'},
nested_bar: [{bar: 42}, {bar: 43}],
};
const encoded = myProto.encode(jsonMsg).finish();
const decoded = myProto.decode(encoded);
expect(decoded).toEqual(jsonMsg);
});