blob: 84715528c12d8d1051bb989d9463a8c016d96bd2 [file] [log] [blame]
// Copyright 2018 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.
#include "tools/fidl/fidlc/src/diagnostics.h"
#include "tools/fidl/fidlc/tests/test_library.h"
#define BORINGSSL_NO_CXX
#include <gtest/gtest.h>
#include <openssl/sha.h>
#include <re2/re2.h>
namespace fidlc {
namespace {
uint64_t FakeMethodHasher(std::string_view selector) {
if (selector.find("HashesToZero") != std::string_view::npos)
return 0;
if (selector.find("Clash") != std::string_view::npos)
return 456789;
return Sha256MethodHasher(selector);
}
TEST(OrdinalsTests, BadOrdinalCannotBeZero) {
TestLibrary library(R"FIDL(
library example;
protocol Special {
ThisOneHashesToZero() -> (struct { i int64; });
};
)FIDL");
library.method_hasher() = FakeMethodHasher;
library.ExpectFail(ErrGeneratedZeroValueOrdinal);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, BadClashingOrdinalValues) {
TestLibrary library(R"FIDL(
library example;
using zx;
protocol Special {
ClashOne(struct { s string; b bool; }) -> (struct { i int32; });
ClashTwo(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
};
)FIDL");
library.method_hasher() = FakeMethodHasher;
library.UseLibraryZx();
library.ExpectFail(ErrDuplicateMethodOrdinal, "example.fidl:7:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, BadClashingOrdinalValuesWithAttribute) {
TestLibrary library(R"FIDL(
library example;
using zx;
protocol Special {
@selector("ClashOne")
foo(struct { s string; b bool; }) -> (struct { i int32; });
@selector("ClashTwo")
bar(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
};
)FIDL");
library.method_hasher() = FakeMethodHasher;
library.UseLibraryZx();
library.ExpectFail(ErrDuplicateMethodOrdinal, "example.fidl:8:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, BadClashingOrdinalBadSelector) {
TestLibrary library;
library.AddFile("bad/fi-0081.test.fidl");
library.ExpectFail(ErrDuplicateMethodOrdinal, "bad/fi-0081.test.fidl:7:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, GoodAttributeResolvesClashes) {
TestLibrary library(R"FIDL(
library example;
using zx;
protocol Special {
@selector("SomethingElse")
ClashOne(struct { s string; b bool; }) -> (struct { i int32; });
ClashTwo(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
};
)FIDL");
library.method_hasher() = FakeMethodHasher;
library.UseLibraryZx();
ASSERT_COMPILED(library);
}
TEST(OrdinalsTests, GoodOrdinalValueIsSha256) {
TestLibrary library(R"FIDL(
library a.b.c;
protocol protocol {
selector(struct {
s string;
b bool;
}) -> (struct {
i int32;
});
};
)FIDL");
ASSERT_COMPILED(library);
const char hash_name64[] = "a.b.c/protocol.selector";
uint8_t digest64[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const uint8_t*>(hash_name64), strlen(hash_name64), digest64);
uint64_t expected_hash64 = *(reinterpret_cast<uint64_t*>(digest64)) & 0x7fffffffffffffff;
const Protocol* iface = library.LookupProtocol("protocol");
uint64_t actual_hash64 = iface->methods[0].ordinal;
ASSERT_EQ(actual_hash64, expected_hash64) << "Expected 64bits hash is not correct";
}
TEST(OrdinalsTests, GoodSelectorWithFullPath) {
TestLibrary library(R"FIDL(
library not.important;
protocol at {
@selector("a.b.c/protocol.selector")
all();
};
)FIDL");
ASSERT_COMPILED(library);
const char hash_name64[] = "a.b.c/protocol.selector";
uint8_t digest64[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const uint8_t*>(hash_name64), strlen(hash_name64), digest64);
uint64_t expected_hash64 = *(reinterpret_cast<uint64_t*>(digest64)) & 0x7fffffffffffffff;
const Protocol* iface = library.LookupProtocol("at");
uint64_t actual_hash64 = iface->methods[0].ordinal;
ASSERT_EQ(actual_hash64, expected_hash64) << "Expected 64bits hash is not correct";
}
TEST(OrdinalsTests, BadSelectorValueWrongFormat) {
TestLibrary library;
library.AddFile("bad/fi-0082.test.fidl");
library.ExpectFail(ErrInvalidSelectorValue);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, BadSelectorValueNotString) {
TestLibrary library(R"FIDL(
library not.important;
protocol at {
// should be a string
@selector(true)
all();
};
)FIDL");
library.ExpectFail(ErrTypeCannotBeConvertedToType, "true", "bool", "string");
library.ExpectFail(ErrCouldNotResolveAttributeArg);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, GoodSelectorValueReferencesConst) {
TestLibrary library(R"FIDL(
library not.important;
protocol at {
@selector(SEL)
all();
};
const SEL string = "a.b.c/protocol.selector";
)FIDL");
ASSERT_COMPILED(library);
}
TEST(OrdinalsTests, BadSelectorValueReferencesNonexistent) {
TestLibrary library(R"FIDL(
library not.important;
protocol at {
@selector(nonexistent)
all();
};
)FIDL");
library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'not.important'");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, GoodOrdinalValueIsFirst64BitsOfSha256) {
TestLibrary library(R"FIDL(
library a.b.c;
protocol protocol {
s0();
s1();
s2();
s3();
s4();
s5();
s6();
s7();
s8();
s9();
s10();
s11();
s12();
s13();
s14();
s15();
s16();
s17();
s18();
s19();
s20();
s21();
s22();
s23();
s24();
s25();
s26();
s27();
s28();
s29();
s30();
s31();
};
)FIDL");
ASSERT_COMPILED(library);
const Protocol* iface = library.LookupProtocol("protocol");
// The expected ordinals were generated by the following Python code:
//
// import hashlib
// for i in range(32):
// fqn = f"a.b.c/protocol.s{i}"
// hash = hashlib.sha256(fqn.encode()).digest()
// print(hash[7::-1].hex())
//
EXPECT_EQ(iface->methods[0].ordinal, 0x3b1625372e15f1aeu);
EXPECT_EQ(iface->methods[1].ordinal, 0x4199e504fa71b5a4u);
EXPECT_EQ(iface->methods[2].ordinal, 0x247ca8a890628135u);
EXPECT_EQ(iface->methods[3].ordinal, 0x64f7c02cfffb7846u);
EXPECT_EQ(iface->methods[4].ordinal, 0x20d3f06c598f0cc3u);
EXPECT_EQ(iface->methods[5].ordinal, 0x1ce13806085dac7au);
EXPECT_EQ(iface->methods[6].ordinal, 0x09e1d4b200770defu);
EXPECT_EQ(iface->methods[7].ordinal, 0x53df65d26411d8eeu);
EXPECT_EQ(iface->methods[8].ordinal, 0x690c3617405590c7u);
EXPECT_EQ(iface->methods[9].ordinal, 0x4ff9ef5fb170f550u);
EXPECT_EQ(iface->methods[10].ordinal, 0x1542d4c21d8a6c00u);
EXPECT_EQ(iface->methods[11].ordinal, 0x564e9e47f7418e0fu);
EXPECT_EQ(iface->methods[12].ordinal, 0x29681e66f3506231u);
EXPECT_EQ(iface->methods[13].ordinal, 0x5ee63b26268f7760u);
EXPECT_EQ(iface->methods[14].ordinal, 0x256950edf00aac63u);
EXPECT_EQ(iface->methods[15].ordinal, 0x6b21c0ff1aa02896u);
EXPECT_EQ(iface->methods[16].ordinal, 0x5a54f3dca00089e9u);
EXPECT_EQ(iface->methods[17].ordinal, 0x772476706fa4be0eu);
EXPECT_EQ(iface->methods[18].ordinal, 0x294e338bf71a773bu);
EXPECT_EQ(iface->methods[19].ordinal, 0x5a6aa228cfb68d16u);
EXPECT_EQ(iface->methods[20].ordinal, 0x55a09c6b033f3f98u);
EXPECT_EQ(iface->methods[21].ordinal, 0x1192d5b856d22cd8u);
EXPECT_EQ(iface->methods[22].ordinal, 0x2e68bdea28f9ce7bu);
EXPECT_EQ(iface->methods[23].ordinal, 0x4c8ebf26900e4451u);
EXPECT_EQ(iface->methods[24].ordinal, 0x3df0dbe9378c4fd3u);
EXPECT_EQ(iface->methods[25].ordinal, 0x087268657bb0cad1u);
EXPECT_EQ(iface->methods[26].ordinal, 0x0aee6ad161a90ae1u);
EXPECT_EQ(iface->methods[27].ordinal, 0x44e6f2282baf727au);
EXPECT_EQ(iface->methods[28].ordinal, 0x3e8984f57ab5830du);
EXPECT_EQ(iface->methods[29].ordinal, 0x696f9f73a5cabd21u);
EXPECT_EQ(iface->methods[30].ordinal, 0x327d7b0d2389e054u);
EXPECT_EQ(iface->methods[31].ordinal, 0x54fd307bb5bfab2du);
}
TEST(OrdinalsTests, GoodHackToRenameFuchsiaIoToFuchsiaIoOneNoSelector) {
TestLibrary library;
library.AddFile("bad/fi-0083.test.fidl");
library.ExpectFail(ErrFuchsiaIoExplicitOrdinals);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(OrdinalsTests, GoodHackToRenameFuchsiaIoToFuchsiaIoOneHasSelector) {
TestLibrary library(R"FIDL(
library fuchsia.io;
protocol SomeProtocol {
@selector("fuchsia.io1/Node.Open")
SomeMethod();
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(OrdinalsTests, WrongComposedMethodDoesNotGetGeneratedOrdinal) {
TestLibrary library(R"FIDL(
library example;
protocol Node {
SomeMethod(struct { id Id; });
};
protocol Directory {
compose Node;
Unlink();
};
protocol DirectoryAdmin {
compose Directory;
};
)FIDL");
library.ExpectFail(ErrNameNotFound, "Id", "library 'example'");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
} // namespace
} // namespace fidlc