blob: a49d014eb37d82144c98cebb9b00fa6c7dc206de [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.
package codegen
import (
"testing"
"github.com/google/go-cmp/cmp"
fidl "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen"
)
func TestDerivesToString(t *testing.T) {
cases := []struct {
input derives
expected string
}{
{0, ""},
{derivesDebug, "#[derive(Debug)]"},
{derivesPartialOrd, "#[derive(PartialOrd)]"},
{derivesHash | derivesAsBytes, "#[derive(Hash, zerocopy::AsBytes)]"},
}
for _, ex := range cases {
actual := ex.input.String()
if actual != ex.expected {
t.Errorf("%d: expected '%s', actual '%s'", ex.input, ex.expected, actual)
}
}
}
func TestBuildPaddingMarkersWithoutFlattening(t *testing.T) {
type testCase struct {
name string
in fidl.Struct
out []PaddingMarker
}
testCases := []testCase{
{
name: "empty",
in: fidl.Struct{},
out: nil,
},
{
name: "no padding 8-bytes",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 8,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 4,
Padding: 0,
},
},
},
},
out: nil,
},
{
name: "no padding 4-bytes",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 4,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 2,
Padding: 0,
},
},
},
},
out: nil,
},
{
name: "no padding 2-bytes",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 2,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 1,
Padding: 0,
},
},
},
},
out: nil,
},
{
name: "no padding 1-byte",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 1,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
},
},
out: nil,
},
{
name: "8-byte struct with 2 bytes of padding at end",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 8,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 4,
Padding: 2,
},
},
},
},
out: []PaddingMarker{
{
Type: "u64",
Offset: 0,
Mask: "0xffff000000000000u64",
},
},
},
{
name: "4-byte struct with 1 byte of padding at end",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 4,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 2,
Padding: 1,
},
},
},
},
out: []PaddingMarker{
{
Type: "u32",
Offset: 0,
Mask: "0xff000000u32",
},
},
},
{
name: "2-byte struct with 1 byte padding at end",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 2,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 1,
},
},
},
},
out: []PaddingMarker{
{
Type: "u16",
Offset: 0,
Mask: "0xff00u16",
},
},
},
{
name: "padding at end of 8-byte chunk, before next chunk",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 16,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 4,
Padding: 2,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 8,
Padding: 0,
},
},
},
},
out: []PaddingMarker{
{
Type: "u64",
Offset: 0,
Mask: "0xffff000000000000u64",
},
},
},
{
name: "padding in middle of 4-byte block",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 4,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 1,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 2,
Padding: 0,
},
},
},
},
out: []PaddingMarker{
{
Type: "u32",
Offset: 0,
Mask: "0x0000ff00u32",
},
},
},
{
name: "8 byte mask with non-zero offset",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 16,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 8,
Padding: 4,
},
},
},
},
out: []PaddingMarker{
{
Type: "u64",
Offset: 8,
Mask: "0xffffffff00000000u64",
},
},
},
{
name: "4 byte mask with non-zero offset",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 12,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 8,
Padding: 2,
},
},
},
},
out: []PaddingMarker{
{
Type: "u32",
Offset: 8,
Mask: "0xffff0000u32",
},
},
},
{
name: "2 byte mask with non-zero offset",
in: fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 10,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
},
{
FieldShapeV1: fidl.FieldShape{
Offset: 8,
Padding: 1,
},
},
},
},
out: []PaddingMarker{
{
Type: "u16",
Offset: 8,
Mask: "0xff00u16",
},
},
},
}
for _, testCase := range testCases {
c := compiler{}
out := c.buildPaddingMarkers(testCase.in, false)
if diff := cmp.Diff(testCase.out, out); diff != "" {
t.Errorf("%s:\nexpected != actual (-want +got)\n%s", testCase.name, diff)
}
}
}
func TestBuildPaddingMarkersFlatteningStruct(t *testing.T) {
var innerStructIdentifier fidl.EncodedCompoundIdentifier = "abcd"
innerStruct := fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 4,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 3,
},
},
},
}
input := fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 8,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 4,
},
Type: fidl.Type{
Kind: fidl.IdentifierType,
Identifier: innerStructIdentifier,
},
},
},
}
resourceness := fidl.IsValueType
c := compiler{
decls: map[fidl.EncodedCompoundIdentifier]fidl.DeclInfo{
innerStructIdentifier: {Type: fidl.StructDeclType, Resourceness: &resourceness},
},
structs: map[fidl.EncodedCompoundIdentifier]fidl.Struct{
innerStructIdentifier: innerStruct,
},
library: fidl.LibraryIdentifier{""},
}
out := c.buildPaddingMarkers(input, true)
expected := []PaddingMarker{
{
Type: "u64",
Offset: 0,
Mask: "0xffffffffffffff00u64",
},
}
if diff := cmp.Diff(expected, out); diff != "" {
t.Errorf("expected != actual (-want +got)\n%s", diff)
}
}
func TestBuildPaddingMarkersFlatteningArray(t *testing.T) {
var innerStructIdentifier fidl.EncodedCompoundIdentifier = "abcd"
innerStruct := fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 4,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 3,
},
},
},
}
count := 3
input := fidl.Struct{
TypeShapeV1: fidl.TypeShape{
InlineSize: 12,
},
Members: []fidl.StructMember{
{
FieldShapeV1: fidl.FieldShape{
Offset: 0,
Padding: 0,
},
Type: fidl.Type{
Kind: fidl.ArrayType,
ElementCount: &count,
ElementType: &fidl.Type{
Kind: fidl.IdentifierType,
Identifier: innerStructIdentifier,
},
},
},
},
}
resourceness := fidl.IsValueType
c := compiler{
decls: map[fidl.EncodedCompoundIdentifier]fidl.DeclInfo{
innerStructIdentifier: {Type: fidl.StructDeclType, Resourceness: &resourceness},
},
structs: map[fidl.EncodedCompoundIdentifier]fidl.Struct{
innerStructIdentifier: innerStruct,
},
library: fidl.LibraryIdentifier{""},
}
out := c.buildPaddingMarkers(input, true)
expected := []PaddingMarker{
{
Type: "u64",
Offset: 0,
Mask: "0xffffff00ffffff00u64",
},
{
Type: "u32",
Offset: 8,
Mask: "0xffffff00u32",
},
}
if diff := cmp.Diff(expected, out); diff != "" {
t.Errorf("expected != actual (-want +got)\n%s", diff)
}
}