blob: 2c29b9e01e78b073ddac62c9a76a2d670bcf7269 [file] [log] [blame]
// Copyright 2014 The Chromium OS 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 "chromeos-dbus-bindings/dbus_signature.h"
#include <map>
#include <string>
#include <dbus/dbus-protocol.h>
#include <gtest/gtest.h>
using std::map;
using std::string;
using testing::Test;
using testing::TestWithParam;
namespace chromeos_dbus_bindings {
using Direction = DBusType::Direction;
using Receiver = DBusType::Receiver;
namespace {
// Failing signatures.
const char kEmptySignature[] = "";
const char kEmptyDictSignature[] = "a{}";
const char kMissingArraryParameterSignature[] = "a";
const char kMissingArraryParameterInnerSignature[] = "a{sa}i";
const char kOrphanDictSignature[] = "a{s{i}}";
const char kTooFewDictMembersSignature[] = "a{s}";
const char kTooManyDictMembersSignature[] = "a{sa{i}u}";
const char kUnclosedDictOuterSignature[] = "a{s";
const char kUnclosedDictInnerSignature[] = "a{a{u}";
const char kUnexpectedCloseSignature[] = "a}i{";
const char kUnknownSignature[] = "al";
// Signature for protobuf type
const char kMyProtobufClassName[] = "MyProtobufClass";
} // namespace
TEST(DBusSignatureTest, ParseFailures) {
DBusSignature signature;
for (const auto& failing_string :
{kEmptySignature, kEmptyDictSignature, kMissingArraryParameterSignature,
kMissingArraryParameterInnerSignature, kOrphanDictSignature,
kTooFewDictMembersSignature, kTooManyDictMembersSignature,
kUnclosedDictOuterSignature, kUnclosedDictInnerSignature,
kUnexpectedCloseSignature, kUnknownSignature}) {
EXPECT_FALSE(signature.Parse(failing_string))
<< "Expected signature " << failing_string
<< " to fail but it succeeded";
}
}
TEST(DBusSignatureTest, ParseSuccesses) {
DBusSignature signature;
const map<string, string> parse_values{
// Simple types.
{DBUS_TYPE_BOOLEAN_AS_STRING, "bool"},
{DBUS_TYPE_BYTE_AS_STRING, "uint8_t"},
{DBUS_TYPE_DOUBLE_AS_STRING, "double"},
{DBUS_TYPE_OBJECT_PATH_AS_STRING, "dbus::ObjectPath"},
{DBUS_TYPE_INT16_AS_STRING, "int16_t"},
{DBUS_TYPE_INT32_AS_STRING, "int32_t"},
{DBUS_TYPE_INT64_AS_STRING, "int64_t"},
{DBUS_TYPE_STRING_AS_STRING, "std::string"},
{DBUS_TYPE_UINT16_AS_STRING, "uint16_t"},
{DBUS_TYPE_UINT32_AS_STRING, "uint32_t"},
{DBUS_TYPE_UINT64_AS_STRING, "uint64_t"},
{DBUS_TYPE_VARIANT_AS_STRING, "brillo::Any"},
// Complex types.
{"ab", "std::vector<bool>"},
{"ay", "std::vector<uint8_t>"},
{"aay", "std::vector<std::vector<uint8_t>>"},
{"ao", "std::vector<dbus::ObjectPath>"},
{"a{oa{sa{sv}}}",
"std::map<dbus::ObjectPath, std::map<std::string, "
"brillo::VariantDictionary>>"},
{"a{os}", "std::map<dbus::ObjectPath, std::string>"},
{"as", "std::vector<std::string>"},
{"a{ss}", "std::map<std::string, std::string>"},
{"a{sa{ss}}",
"std::map<std::string, std::map<std::string, "
"std::string>>"},
{"a{sa{sv}}", "std::map<std::string, brillo::VariantDictionary>"},
{"a{sv}", "brillo::VariantDictionary"},
{"a{sv}Garbage", "brillo::VariantDictionary"},
{"at", "std::vector<uint64_t>"},
{"a{iv}", "std::map<int32_t, brillo::Any>"},
{"(ib)", "std::tuple<int32_t, bool>"},
{"(ibs)", "std::tuple<int32_t, bool, std::string>"},
};
for (const auto& parse_test : parse_values) {
auto type = signature.Parse(parse_test.first);
EXPECT_TRUE(type) << "Expected signature " << parse_test.first
<< " to succeed but it failed.";
string output = type->GetBaseType(Direction::kAppend);
EXPECT_EQ(parse_test.second, output)
<< "Expected typename for " << parse_test.first << " to be "
<< parse_test.second << " but instead it was " << output;
output = type->GetBaseType(Direction::kExtract);
EXPECT_EQ(parse_test.second, output)
<< "Expected typename for " << parse_test.first << " to be "
<< parse_test.second << " but instead it was " << output;
}
}
// Scalar types should not have reference behavior when used as in-args, and
// should just produce the base type as their in-arg type.
TEST(DBusSignatureTest, ScalarTypes) {
DBusSignature signature;
const std::vector<string> parse_values{
DBUS_TYPE_BOOLEAN_AS_STRING, DBUS_TYPE_BYTE_AS_STRING,
DBUS_TYPE_DOUBLE_AS_STRING, DBUS_TYPE_INT16_AS_STRING,
DBUS_TYPE_INT32_AS_STRING, DBUS_TYPE_INT64_AS_STRING,
DBUS_TYPE_UINT16_AS_STRING, DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT64_AS_STRING,
};
for (const auto& parse_test : parse_values) {
auto type = signature.Parse(parse_test);
EXPECT_TRUE(type);
EXPECT_EQ(type->GetBaseType(Direction::kExtract),
type->GetInArgType(Receiver::kAdaptor));
EXPECT_EQ(type->GetBaseType(Direction::kAppend),
type->GetInArgType(Receiver::kProxy));
}
}
// Non-scalar types should have const reference behavior when used as in-args.
// The references should not be nested.
TEST(DBusSignatureTest, NonScalarTypes) {
DBusSignature signature;
const map<string, string> parse_values{
{"o", "const dbus::ObjectPath&"},
{"s", "const std::string&"},
{"v", "const brillo::Any&"},
{"ab", "const std::vector<bool>&"},
{"ay", "const std::vector<uint8_t>&"},
{"aay", "const std::vector<std::vector<uint8_t>>&"},
{"ao", "const std::vector<dbus::ObjectPath>&"},
{"a{oa{sa{sv}}}",
"const std::map<dbus::ObjectPath, std::map<"
"std::string, brillo::VariantDictionary>>&"},
{"a{os}", "const std::map<dbus::ObjectPath, std::string>&"},
{"as", "const std::vector<std::string>&"},
{"a{ss}", "const std::map<std::string, std::string>&"},
{"a{sa{ss}}",
"const std::map<std::string, std::map<std::string, "
"std::string>>&"},
{"a{sa{sv}}",
"const std::map<std::string, "
"brillo::VariantDictionary>&"},
{"a{sv}", "const brillo::VariantDictionary&"},
{"at", "const std::vector<uint64_t>&"},
{"a{iv}", "const std::map<int32_t, brillo::Any>&"},
{"(ib)", "const std::tuple<int32_t, bool>&"},
{"(ibs)", "const std::tuple<int32_t, bool, std::string>&"},
};
for (const auto& parse_test : parse_values) {
auto type = signature.Parse(parse_test.first);
EXPECT_TRUE(type);
EXPECT_EQ(parse_test.second, type->GetInArgType(Receiver::kAdaptor));
EXPECT_EQ(parse_test.second, type->GetInArgType(Receiver::kProxy));
}
}
// Out-args should be pointers, but only at the top level.
TEST(DBusSignatureTest, OutArgTypes) {
DBusSignature signature;
const map<string, string> parse_values{
{"b", "bool*"},
{"y", "uint8_t*"},
{"i", "int32_t*"},
{"t", "uint64_t*"},
{"o", "dbus::ObjectPath*"},
{"s", "std::string*"},
{"v", "brillo::Any*"},
{"ab", "std::vector<bool>*"},
{"ay", "std::vector<uint8_t>*"},
{"aay", "std::vector<std::vector<uint8_t>>*"},
{"ao", "std::vector<dbus::ObjectPath>*"},
{"a{oa{sa{sv}}}",
"std::map<dbus::ObjectPath, std::map<"
"std::string, brillo::VariantDictionary>>*"},
{"a{os}", "std::map<dbus::ObjectPath, std::string>*"},
{"as", "std::vector<std::string>*"},
{"a{ss}", "std::map<std::string, std::string>*"},
{"a{sa{ss}}",
"std::map<std::string, std::map<std::string, "
"std::string>>*"},
{"a{sa{sv}}",
"std::map<std::string, "
"brillo::VariantDictionary>*"},
{"a{sv}", "brillo::VariantDictionary*"},
{"at", "std::vector<uint64_t>*"},
{"a{iv}", "std::map<int32_t, brillo::Any>*"},
{"(ib)", "std::tuple<int32_t, bool>*"},
{"(ibs)", "std::tuple<int32_t, bool, std::string>*"},
};
for (const auto& parse_test : parse_values) {
auto type = signature.Parse(parse_test.first);
EXPECT_TRUE(type);
EXPECT_EQ(parse_test.second, type->GetOutArgType(Receiver::kAdaptor));
EXPECT_EQ(parse_test.second, type->GetOutArgType(Receiver::kProxy));
}
}
// Test to ensure that file descriptors at varying levels of depth do
// not produce valid types.
TEST(DBusSignatureTest, IsValidPropertyType) {
DBusSignature signature;
const std::vector<string> valid_property_types{
"b", "y", "i", "t", "o", "s",
"v", "ab", "ay", "aay", "ao", "a{oa{sa{sv}}}",
"a{os}", "as", "a{ss}", "a{sa{ss}}", "a{sa{sv}}", "a{sv}",
"at", "a{iv}", "(ib)", "(ibs)",
};
for (const auto& parse_test : valid_property_types) {
auto type = signature.Parse(parse_test);
EXPECT_TRUE(type);
EXPECT_TRUE(type->IsValidPropertyType());
}
const std::vector<string> invalid_property_types{
"h", "ah", "aah", "a{sh}", "a{ia{oh}}", "a{hi}", "(sih)", "a(ta{sh})",
};
for (const auto& parse_test : invalid_property_types) {
auto type = signature.Parse(parse_test);
EXPECT_TRUE(type);
EXPECT_FALSE(type->IsValidPropertyType());
}
}
TEST(DBusSignatureTest, FileDescriptors) {
DBusSignature signature;
auto type = signature.Parse(DBUS_TYPE_UNIX_FD_AS_STRING);
EXPECT_TRUE(type);
// for_extraction does matter now.
EXPECT_EQ("brillo::dbus_utils::FileDescriptor",
type->GetBaseType(Direction::kAppend));
EXPECT_EQ("base::ScopedFD", type->GetBaseType(Direction::kExtract));
// for_adaptor propagates as a different for_extraction as well.
EXPECT_EQ("const brillo::dbus_utils::FileDescriptor&",
type->GetInArgType(Receiver::kProxy));
EXPECT_EQ("const base::ScopedFD&", type->GetInArgType(Receiver::kAdaptor));
EXPECT_EQ("base::ScopedFD*", type->GetOutArgType(Receiver::kProxy));
EXPECT_EQ("brillo::dbus_utils::FileDescriptor*",
type->GetOutArgType(Receiver::kAdaptor));
// Check that more involved types are correct as well.
type = signature.Parse("ah");
EXPECT_EQ("std::vector<brillo::dbus_utils::FileDescriptor>",
type->GetBaseType(Direction::kAppend));
EXPECT_EQ("std::vector<base::ScopedFD>",
type->GetBaseType(Direction::kExtract));
type = signature.Parse("a{ih}");
EXPECT_EQ("std::map<int32_t, brillo::dbus_utils::FileDescriptor>",
type->GetBaseType(Direction::kAppend));
EXPECT_EQ("std::map<int32_t, base::ScopedFD>",
type->GetBaseType(Direction::kExtract));
type = signature.Parse("(ih)");
EXPECT_EQ("std::tuple<int32_t, brillo::dbus_utils::FileDescriptor>",
type->GetBaseType(Direction::kAppend));
EXPECT_EQ("std::tuple<int32_t, base::ScopedFD>",
type->GetBaseType(Direction::kExtract));
}
TEST(DBusSignatureTest, Protobufs) {
DBusSignature signature;
auto type = signature.Parse(string(kProtobufType) + kMyProtobufClassName);
EXPECT_TRUE(type);
EXPECT_EQ("MyProtobufClass", type->GetBaseType(Direction::kAppend));
EXPECT_EQ("MyProtobufClass", type->GetBaseType(Direction::kExtract));
EXPECT_EQ("const MyProtobufClass&", type->GetInArgType(Receiver::kAdaptor));
EXPECT_EQ("const MyProtobufClass&", type->GetInArgType(Receiver::kProxy));
EXPECT_EQ("MyProtobufClass*", type->GetOutArgType(Receiver::kAdaptor));
EXPECT_EQ("MyProtobufClass*", type->GetOutArgType(Receiver::kProxy));
}
} // namespace chromeos_dbus_bindings