blob: 656c59d46a45e34a7e9b723ed117af801447f429 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: implementation_imports
import 'dart:convert' show Utf8Decoder;
import 'dart:typed_data';
import 'package:fidl_fuchsia_diagnostics_stream/fidl_async.dart';
import 'package:fidl_fuchsia_diagnostics/fidl_async.dart';
import 'package:test/test.dart';
import 'package:fuchsia_diagnostic_streams/src/internal/header.dart';
import 'package:fuchsia_diagnostic_streams/src/write.dart';
/// assert that buffer contains the serialized record.
void assertRecord(Record record, ByteData buffer) {
var header = Header(buffer.getUint64(0, Endian.little));
var timestamp = buffer.getInt64(8, Endian.little);
expect(header.size, equals(buffer.lengthInBytes));
expect(header.type, equals(9)); // log type
List<Argument> arguments = [];
var offset = 16;
while (offset < buffer.lengthInBytes) {
var parseResult = parseArgument(buffer, offset);
arguments.add(parseResult.argument);
offset = parseResult.nextOffset;
}
var foundRecord = Record(
timestamp: timestamp,
severity: Severity(header.severity),
arguments: arguments);
expect(foundRecord, equals(record));
}
class _ArgParseResult {
final Argument argument;
final int nextOffset;
_ArgParseResult({this.argument, this.nextOffset});
}
/// parses an argument starting at the given offset. Returns the found
/// argument and offset of the next entry.
_ArgParseResult parseArgument(ByteData buffer, int offset) {
final header = Header(buffer.getUint64(offset, Endian.little));
// Assume inline string reference for argument name. Last 15 bits are length.
final nameLen = header.nameRef & 0x7fff;
final padLen = (8 - (nameLen % 8)) % 8;
final name =
Utf8Decoder().convert(buffer.buffer.asInt8List(offset + 8, nameLen));
final valuePos = offset + 8 + nameLen + padLen;
Value value;
var curOffset = valuePos;
switch (header.type) {
case tracingFormatI64Type:
value = Value.withSignedInt(buffer.getInt64(valuePos, Endian.little));
curOffset += 8;
break;
case tracingFormatU64Type: // unsigned int
value = Value.withUnsignedInt(buffer.getUint64(valuePos, Endian.little));
curOffset += 8;
break;
case tracingFormatF64Type: // floating point
value = Value.withFloating(buffer.getFloat64(valuePos, Endian.little));
curOffset += 8;
break;
case tracingFormatStringType: // string
// Assume inline string reference for value. Last 15 bits are length.
final valLen = header.value & 0x7fff;
final padLen = (8 - (valLen % 8)) % 8;
final str =
Utf8Decoder().convert(buffer.buffer.asInt8List(valuePos, valLen));
value = Value.withText(str);
curOffset += valLen + padLen;
break;
default:
fail('Unrecognized header type ${header.type}');
}
expect(header.size, equals(curOffset - offset));
return _ArgParseResult(
argument: Argument(name: name, value: value), nextOffset: curOffset);
}
void testWriteRecord(Record record) {
final bytes = ByteData(1024);
final recordLen = writeRecord(bytes, record);
assertRecord(record, bytes.buffer.asByteData(0, recordLen));
expect(recordLen % 8, equals(0));
}
void testWriteArgument(Argument argument) {
final bytes = ByteData(1024);
final argLen = writeArgument(bytes, 0, argument);
final argResult = parseArgument(bytes, 0);
expect(argResult.argument, equals(argument));
expect(argResult.nextOffset, equals(argLen));
expect(argLen % 8, equals(0));
}
void main() {
const int _testTimestamp = 23;
group('write record tests', () {
test('no arguments', () {
testWriteRecord(Record(
timestamp: _testTimestamp, severity: Severity.warn, arguments: []));
});
test('single argument', () {
testWriteRecord(Record(
timestamp: _testTimestamp,
severity: Severity.info,
arguments: [
Argument(name: 'int-arg', value: Value.withSignedInt(2902))
]));
});
test('multiple arguments', () {
final arguments = [
Argument(name: '', value: Value.withText('')),
Argument(name: 'arg-1', value: Value.withSignedInt(23)),
Argument(name: 'arg-2', value: Value.withUnsignedInt(10)),
Argument(name: 'arg-3', value: Value.withFloating(0.1)),
Argument(name: 'arg-4', value: Value.withText('text'))
];
testWriteRecord(Record(
timestamp: _testTimestamp,
severity: Severity.error,
arguments: arguments));
});
});
group('write argument tests', () {
test('signed int', () {
testWriteArgument(
Argument(name: 'signed-arg', value: Value.withSignedInt(12)));
testWriteArgument(
Argument(name: 'signed-arg', value: Value.withSignedInt(-12)));
});
test('unsigned int', () {
testWriteArgument(
Argument(name: 'unsigned-arg', value: Value.withUnsignedInt(999)));
});
test('floating point', () {
testWriteArgument(
Argument(name: 'floating-arg', value: Value.withFloating(140.15)));
});
test('text', () {
testWriteArgument(
Argument(name: 'text-arg', value: Value.withText('arg-value')));
testWriteArgument(Argument(name: 'text-arg', value: Value.withText('')));
});
});
}