blob: 2e2888aff398d6d0a6216caf21938b0343e720ed [file] [log] [blame]
// Copyright 2016 The Chromium 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 formatter
import (
"mojom/mojom_parser/lexer"
"mojom/mojom_parser/mojom"
"testing"
)
func checkEq(t *testing.T, expected, actual interface{}) {
if expected != actual {
t.Fatalf("Failed check: Expected (%q), Actual (%q)", expected, actual)
}
}
// Utility function to allow the printer object's initialization to get
// more complicated over time without having to modify these tests.
func getNewPrinter() *printer {
return newPrinter()
}
func TestWriteModuleNamespace(t *testing.T) {
m := mojom.NewModuleNamespace("hello.world", nil)
p := getNewPrinter()
p.writeModuleNamespace(m)
checkEq(t, "module hello.world;\n", p.result())
}
func TestWriteModuleNamespaceNil(t *testing.T) {
p := getNewPrinter()
p.writeModuleNamespace(nil)
checkEq(t, "", p.result())
}
func TestWriteModuleNamespaceEmpty(t *testing.T) {
m := mojom.NewModuleNamespace("", nil)
p := getNewPrinter()
p.writeModuleNamespace(m)
checkEq(t, "", p.result())
}
func TestWriteLiteralValue(t *testing.T) {
testCases := []struct {
expected string
value mojom.LiteralValue
}{
// TODO(azani): Make sure the escaping behavior assumed here is what the
// parser does.
{"\"hello \\n world\"", mojom.MakeStringLiteralValue("hello \n world", &lexer.Token{Text: "\"hello \\n world\""})},
{"true", mojom.MakeBoolLiteralValue(true, &lexer.Token{Text: "true"})},
{"false", mojom.MakeBoolLiteralValue(false, &lexer.Token{Text: "false"})},
{"10", mojom.MakeInt8LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeInt16LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeInt32LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeInt64LiteralValue(10, &lexer.Token{Text: "10"})},
{"-10", mojom.MakeInt64LiteralValue(-10, &lexer.Token{Text: "10"})},
{"0x10", mojom.MakeInt64LiteralValue(0x10, &lexer.Token{Text: "0x10"})},
{"10", mojom.MakeUint8LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeUint16LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeUint32LiteralValue(10, &lexer.Token{Text: "10"})},
{"10", mojom.MakeUint64LiteralValue(10, &lexer.Token{Text: "10"})},
{"10.5", mojom.MakeDoubleLiteralValue(10.5, &lexer.Token{Text: "10.5"})},
{"10.5", mojom.MakeFloatLiteralValue(10.5, &lexer.Token{Text: "10.5"})},
{"default", mojom.MakeDefaultLiteral(&lexer.Token{Text: "default"})},
}
for _, testCase := range testCases {
p := getNewPrinter()
p.writeValueRef(testCase.value)
checkEq(t, testCase.expected, p.result())
}
}
func TestWriteAttribute(t *testing.T) {
a := mojom.NewMojomAttribute("key", nil, mojom.MakeUint64LiteralValue(10, &lexer.Token{Text: "10"}))
p := getNewPrinter()
p.writeAttribute(&a)
checkEq(t, "key=10", p.result())
}
func TestWriteAttributes(t *testing.T) {
attrs := mojom.NewAttributes(lexer.Token{})
attrs.List = append(attrs.List, mojom.NewMojomAttribute("key1", nil, mojom.MakeUint64LiteralValue(10, &lexer.Token{Text: "10"})))
attrs.List = append(attrs.List, mojom.NewMojomAttribute("key2", nil, mojom.MakeUint64LiteralValue(20, &lexer.Token{Text: "20"})))
p := getNewPrinter()
p.writeAttributes(attrs)
expected := "[key1=10,\n key2=20]\n"
checkEq(t, expected, p.result())
}
func TestWriteAttributesSingleLine(t *testing.T) {
attrs := mojom.NewAttributes(lexer.Token{})
attrs.List = append(attrs.List, mojom.NewMojomAttribute("key1", nil, mojom.MakeUint64LiteralValue(10, &lexer.Token{Text: "10"})))
attrs.List = append(attrs.List, mojom.NewMojomAttribute("key2", nil, mojom.MakeUint64LiteralValue(20, &lexer.Token{Text: "20"})))
p := getNewPrinter()
p.writeAttributesSingleLine(attrs)
expected := "[key1=10, key2=20] "
checkEq(t, expected, p.result())
}
func TestWriteImportedFiles(t *testing.T) {
imports := []*mojom.ImportedFile{
mojom.NewImportedFile("foo2.mojom", nil),
mojom.NewImportedFile("foo1.mojom", nil),
}
p := getNewPrinter()
p.writeImportedFiles(imports)
expected := "import \"foo1.mojom\";\nimport \"foo2.mojom\";\n"
checkEq(t, expected, p.result())
}
func TestWriteImportedFilesBlocks(t *testing.T) {
imports := []*mojom.ImportedFile{
mojom.NewImportedFile("foo4.mojom", nil),
mojom.NewImportedFile("foo3.mojom", nil),
mojom.NewImportedFile("foo2.mojom", nil),
mojom.NewImportedFile("foo1.mojom", nil),
}
c := imports[2].NewAttachedComments()
c.Above = append(c.Above, lexer.Token{Kind: lexer.EmptyLine})
p := getNewPrinter()
p.writeImportedFiles(imports)
expected := `import "foo3.mojom";
import "foo4.mojom";
import "foo1.mojom";
import "foo2.mojom";
`
checkEq(t, expected, p.result())
}
func TestWriteSingleLineComment(t *testing.T) {
commentText := "// Hello world."
token := lexer.Token{Kind: lexer.SingleLineComment, Text: commentText}
p := getNewPrinter()
p.writeSingleLineComment(token)
checkEq(t, commentText, p.result())
}
func TestWriteSingleLineCommentAddSpace(t *testing.T) {
commentText := "//Hello world."
token := lexer.Token{Kind: lexer.SingleLineComment, Text: commentText}
p := getNewPrinter()
p.writeSingleLineComment(token)
checkEq(t, "// Hello world.", p.result())
}
func TestWriteMultilineComments(t *testing.T) {
commentText := `/*
* Some comment.
* More comments.
* Even more comments.
* And after a space.
*/`
token := lexer.Token{Kind: lexer.MultiLineComment, Text: commentText}
p := getNewPrinter()
p.writeMultiLineComment(token)
checkEq(t, commentText, p.result())
}
func TestWriteMultilineCommentsWrapping(t *testing.T) {
commentText := `/*
* Some comment more words and even more words and even more words and more words more words.
* More comments.
* Even more comments.
* And after a space.
*/`
expected := `/*
* Some comment more words and even more words and even more words and more
* words more words.
* More comments.
* Even more comments.
* And after a space.
*/`
token := lexer.Token{Kind: lexer.MultiLineComment, Text: commentText}
p := getNewPrinter()
p.writeMultiLineComment(token)
checkEq(t, expected, p.result())
}
func cppComment(line int, c string) (t lexer.Token) {
t.Kind = lexer.SingleLineComment
t.Text = "// " + c
t.LineNo = line
return
}
func cComment(line int, c string) (t lexer.Token) {
t.Kind = lexer.MultiLineComment
t.Text = "/* " + c + " */"
t.LineNo = line
return
}
func TestWriteComments(t *testing.T) {
comments := []lexer.Token{
cppComment(0, "block 1 line 1"),
cppComment(1, "block 1 line 2"),
cppComment(2, "block 1 line 3"),
lexer.Token{Kind: lexer.EmptyLine},
cComment(10, "block 2 line 1\nblock 2 line 2\nblock 2 line 3"),
lexer.Token{Kind: lexer.EmptyLine},
cppComment(20, "block 3 line 1"),
cppComment(21, "block 3 line 2"),
cppComment(22, "block 3 line 3"),
}
p := getNewPrinter()
p.writeCommentBlocks(comments, true)
expected := `// block 1 line 1
// block 1 line 2
// block 1 line 3
/* block 2 line 1
block 2 line 2
block 2 line 3 */
// block 3 line 1
// block 3 line 2
// block 3 line 3
`
checkEq(t, expected, p.result())
}
func TestWriteTypeRefBuiltIns(t *testing.T) {
testCases := []string{
"string",
"handle",
"handle<message_pipe>",
"handle<data_pipe_consumer>",
"handle<data_pipe_producer>",
"handle<shared_buffer>",
"string?",
"handle?",
"handle<message_pipe>?",
"handle<data_pipe_consumer>?",
"handle<data_pipe_producer>?",
"handle<shared_buffer>?",
"bool",
"int8",
"int16",
"int32",
"int64",
"uint8",
"uint16",
"uint32",
"uint64",
}
for _, testCase := range testCases {
p := getNewPrinter()
p.writeTypeRef(mojom.BuiltInType(testCase))
checkEq(t, testCase, p.result())
}
}
func TestWriteTypeRefCompositesAndUserDefined(t *testing.T) {
testCases := []struct {
typeRef mojom.TypeRef
expected string
}{
{mojom.NewArrayTypeRef(mojom.BuiltInType("int8"), -1, false), "array<int8>"},
{mojom.NewArrayTypeRef(mojom.BuiltInType("int8"), 10, false), "array<int8, 10>"},
{mojom.NewArrayTypeRef(mojom.BuiltInType("int8"), -1, true), "array<int8>?"},
{mojom.NewArrayTypeRef(mojom.BuiltInType("int8"), 10, true), "array<int8, 10>?"},
{mojom.NewMapTypeRef(mojom.BuiltInType("int8"), mojom.BuiltInType("int16"), false),
"map<int8, int16>"},
{mojom.NewMapTypeRef(mojom.BuiltInType("int8"), mojom.BuiltInType("int16"), true),
"map<int8, int16>?"},
{mojom.NewUserTypeRef("Foo", false, false, nil, lexer.Token{}), "Foo"},
{mojom.NewUserTypeRef("Foo", true, false, nil, lexer.Token{}), "Foo?"},
{mojom.NewUserTypeRef("Foo", false, true, nil, lexer.Token{}), "Foo&"},
{mojom.NewUserTypeRef("Foo", true, true, nil, lexer.Token{}), "Foo&?"},
{mojom.NewArrayTypeRef(mojom.NewUserTypeRef("Foo", false, false, nil, lexer.Token{}), -1, false), "array<Foo>"},
{mojom.NewMapTypeRef(
mojom.NewUserTypeRef("Foo", false, false, nil, lexer.Token{}),
mojom.NewUserTypeRef("Bar", false, false, nil, lexer.Token{}), false),
"map<Foo, Bar>"},
}
for _, testCase := range testCases {
p := getNewPrinter()
p.writeTypeRef(testCase.typeRef)
checkEq(t, testCase.expected, p.result())
}
}
func TestWriteUserValueRef(t *testing.T) {
userValueRef := mojom.NewUserValueRef(mojom.AssigneeSpec{}, "identifier", nil, lexer.Token{})
p := getNewPrinter()
p.writeValueRef(userValueRef)
checkEq(t, "identifier", p.result())
}
func TestWriteStructField(t *testing.T) {
structField := mojom.NewStructField(
mojom.DeclDataWithOrdinal("", nil, lexer.Token{Text: "field1"}, nil, 5),
mojom.BuiltInType("int8"),
mojom.MakeInt8LiteralValue(10, &lexer.Token{Text: "10"}))
p := getNewPrinter()
p.writeDeclaredObject(structField)
checkEq(t, "int8 field1@5 = 10;", p.result())
}
func TestWriteMojomStruct(t *testing.T) {
declData := mojom.DeclData("", nil, lexer.Token{Text: "FooStruct"}, nil)
mojomStruct := mojom.NewMojomStruct(declData)
mojomStruct.InitAsScope(mojom.NewTestFileScope("test.scope"))
mojomStruct.AddField(mojom.NewStructField(
mojom.DeclData("field1", nil, lexer.Token{Text: "field1"}, nil),
mojom.BuiltInType("int8"),
mojom.MakeInt8LiteralValue(10, &lexer.Token{Text: "10"})))
mojomStruct.AddField(mojom.NewStructField(
mojom.DeclData("field2", nil, lexer.Token{Text: "field2"}, nil),
mojom.BuiltInType("string"),
nil))
expected := `struct FooStruct {
int8 field1 = 10;
string field2;
};`
p := getNewPrinter()
p.writeDeclaredObject(mojomStruct)
checkEq(t, expected, p.result())
}
func TestWriteMojomStructEmpty(t *testing.T) {
declData := mojom.DeclData("", nil, lexer.Token{Text: "FooStruct"}, nil)
mojomStruct := mojom.NewMojomStruct(declData)
expected := "struct FooStruct {};"
p := getNewPrinter()
p.writeDeclaredObject(mojomStruct)
checkEq(t, expected, p.result())
}
func TestWriteUnionField(t *testing.T) {
unionField := &mojom.UnionField{FieldType: mojom.BuiltInType("int8")}
unionField.DeclarationData = mojom.DeclDataWithOrdinal("field1", nil, lexer.Token{Text: "field1"}, nil, 5)
p := getNewPrinter()
p.writeUnionField(unionField)
checkEq(t, "int8 field1@5;", p.result())
}
func TestWriteMojomUnion(t *testing.T) {
declData := mojom.DeclData("", nil, lexer.Token{Text: "FooUnion"}, nil)
mojomUnion := mojom.NewMojomUnion(declData)
mojomUnion.AddField(
mojom.DeclDataWithOrdinal("field1", nil, lexer.Token{Text: "field1"}, nil, 5),
mojom.BuiltInType("int8"))
mojomUnion.AddField(
mojom.DeclData("field2", nil, lexer.Token{Text: "field2"}, nil),
mojom.BuiltInType("string"))
expected := `union FooUnion {
int8 field1@5;
string field2;
};`
p := getNewPrinter()
p.writeDeclaredObject(mojomUnion)
checkEq(t, expected, p.result())
}
func TestWriteMojomEnum(t *testing.T) {
declData := mojom.DeclData("", nil, lexer.Token{Text: "FooEnum"}, nil)
mojomEnum := mojom.NewMojomEnum(declData)
mojomEnum.AddEnumValue(
mojom.DeclData("VAL1", nil, lexer.Token{Text: "VAL1"}, nil),
nil)
mojomEnum.AddEnumValue(
mojom.DeclData("VAL2", nil, lexer.Token{Text: "VAL2"}, nil),
mojom.MakeInt32LiteralValue(10, &lexer.Token{Text: "10"}))
expected := `enum FooEnum {
VAL1,
VAL2 = 10,
};`
p := getNewPrinter()
p.writeDeclaredObject(mojomEnum)
checkEq(t, expected, p.result())
}
func TestWriteUserDefinedConstant(t *testing.T) {
declData := mojom.DeclData("", nil, lexer.Token{Text: "const_foo"}, nil)
constant := mojom.NewUserDefinedConstant(
declData,
mojom.BuiltInType("int8"),
mojom.MakeInt8LiteralValue(10, &lexer.Token{Text: "10"}))
p := getNewPrinter()
p.writeDeclaredObject(constant)
checkEq(t, "const int8 const_foo = 10;", p.result())
}
func TestWriteMojomMethod(t *testing.T) {
params := mojom.NewMojomStruct(mojom.DeclTestData("dummy"))
params.InitAsScope(mojom.NewTestFileScope("test.scope"))
params.AddField(mojom.NewStructField(mojom.DeclTestData("param1"), mojom.SimpleTypeInt8, nil))
params.AddField(mojom.NewStructField(mojom.DeclTestData("param2"), mojom.SimpleTypeInt16, nil))
responseParams := mojom.NewMojomStruct(mojom.DeclTestData("dummy"))
responseParams.InitAsScope(mojom.NewTestFileScope("test.scope"))
responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("rparam1"), mojom.SimpleTypeInt32, nil))
responseParams.AddField(mojom.NewStructField(mojom.DeclTestData("rparam2"), mojom.SimpleTypeInt64, nil))
mojomMethod := mojom.NewMojomMethod(mojom.DeclTestData("method_foo"), params, responseParams)
p := getNewPrinter()
p.writeDeclaredObject(mojomMethod)
checkEq(t, "method_foo(int8 param1, int16 param2) => (int32 rparam1, int64 rparam2);", p.result())
}