blob: ed079c8a076cbf658cd295f5874be8f10f8e5da5 [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "repr/symbol/version_script_parser.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <map>
#include <sstream>
#include <string>
namespace header_checker {
namespace repr {
using testing::ElementsAre;
using testing::Key;
TEST(VersionScriptParserTest, SmokeTest) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
foo1;
bar1; # var
local:
*;
};
LIBEX_2.0 {
global:
foo2;
bar2; # var
} LIBEX_1.0;
)TESTDATA";
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("foo1"), Key("foo2")));
const ExportedSymbolSet::VarMap &vars = result->GetVars();
EXPECT_THAT(vars, ElementsAre(Key("bar1"), Key("bar2")));
}
TEST(VersionScriptParserTest, ExcludeSymbolVersions) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
foo1;
bar1; # var
local:
*;
};
LIBEX_PRIVATE {
global:
foo2;
bar2; # var
} LIBEX_1.0;
)TESTDATA";
// excluded_symbol_versions = {}
{
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("foo1"), Key("foo2")));
const ExportedSymbolSet::VarMap &vars = result->GetVars();
EXPECT_THAT(vars, ElementsAre(Key("bar1"), Key("bar2")));
}
{
VersionScriptParser parser;
parser.AddExcludedSymbolVersion("*_PRIVATE");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("foo1")));
const ExportedSymbolSet::VarMap &vars = result->GetVars();
EXPECT_THAT(vars, ElementsAre(Key("bar1")));
}
}
TEST(VersionScriptParserTest, VisibilityLabels) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
global_f1;
global_v1; # var
local:
local_f2;
local_v2; # var
global:
global_f3;
global_v3; # var
global:
global_f4;
global_v4; # var
local:
local_f5;
local_v5; # var
local:
local_f6;
local_v6; # var
};
)TESTDATA";
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(
funcs, ElementsAre(Key("global_f1"), Key("global_f3"), Key("global_f4")));
const ExportedSymbolSet::VarMap &vars = result->GetVars();
EXPECT_THAT(
vars, ElementsAre(Key("global_v1"), Key("global_v3"), Key("global_v4")));
}
TEST(VersionScriptParserTest, ParseSymbolTagsIntroduced) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 { # introduced=18
global:
test1; # introduced=19
test2; # introduced=19 introduced-arm64=20
test3; # introduced-arm64=20 introduced=19
test4; # future
test5; # introduced=17
};
)TESTDATA";
{
VersionScriptParser parser;
parser.SetArch("arm64");
parser.SetApiLevel(17);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
// This may be an undefined behavior. ndkstubgen includes it in llndk mode,
// but excludes it in ndk mode.
EXPECT_THAT(funcs, ElementsAre(Key("test5")));
}
{
VersionScriptParser parser;
parser.SetArch("arm64");
parser.SetApiLevel(18);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test5")));
}
{
VersionScriptParser parser;
parser.SetArch("arm64");
parser.SetApiLevel(19);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test5")));
}
{
VersionScriptParser parser;
parser.SetArch("arm");
parser.SetApiLevel(19);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2"), Key("test3"),
Key("test5")));
}
{
VersionScriptParser parser;
parser.SetArch("arm64");
parser.SetApiLevel(20);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2"), Key("test3"),
Key("test5")));
}
{
VersionScriptParser parser;
parser.SetArch("arm64");
parser.SetApiLevel(utils::FUTURE_API_LEVEL);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2"), Key("test3"),
Key("test4"), Key("test5")));
}
}
TEST(VersionScriptParserTest, ParseSymbolTagsArch) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
test1;
test2; # arm arm64
test3; # arm64
test4; # mips
};
)TESTDATA";
{
VersionScriptParser parser;
parser.SetArch("arm");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2")));
}
{
VersionScriptParser parser;
parser.SetArch("arm64");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2"), Key("test3")));
}
{
VersionScriptParser parser;
parser.SetArch("mips");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test4")));
}
}
TEST(VersionScriptParserTest, ExcludeSymbolTags) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 { # exclude-tag-1
global:
test1;
test2; # exclude-tag-2
};
)TESTDATA";
// exclude_symbol_tags = {}
{
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1"), Key("test2")));
}
{
VersionScriptParser parser;
parser.AddExcludedSymbolTag("exclude-tag-1");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_TRUE(funcs.empty());
}
{
VersionScriptParser parser;
parser.AddExcludedSymbolTag("exclude-tag-2");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("test1")));
}
}
TEST(VersionScriptParserTest, IncludeSymbolTags) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
always; # unknown
api34; # introduced=34
api35; # introduced=35
llndk202404; # llndk=202404
llndk202504; # llndk=202504
systemapi; # systemapi
systemapi_llndk; # systemapi llndk
};
)TESTDATA";
{
VersionScriptParser parser;
parser.SetApiLevel(34);
parser.AddModeTag("llndk=202404");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("always"), Key("api34"),
Key("llndk202404"), Key("systemapi_llndk")));
}
{
VersionScriptParser parser;
parser.SetApiLevel(34);
parser.AddModeTag("llndk");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs,
ElementsAre(Key("always"), Key("api34"), Key("llndk202404"),
Key("llndk202504"), Key("systemapi_llndk")));
}
// Include all mode tags
{
VersionScriptParser parser;
parser.SetApiLevel(utils::FUTURE_API_LEVEL);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("always"), Key("api34"), Key("api35"),
Key("llndk202404"), Key("llndk202504"),
Key("systemapi"), Key("systemapi_llndk")));
}
// Exclude all mode tags
{
VersionScriptParser parser;
parser.SetApiLevel(utils::FUTURE_API_LEVEL);
parser.AddModeTag("none");
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("always"), Key("api34"), Key("api35")));
}
}
TEST(VersionScriptParserTest, SetModeTagPolicy) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 { # introduced=36
api36;
api36_llndk202504;
api36_llndk202504; # llndk=202504
llndk202504; # llndk=202504
};
)TESTDATA";
{
VersionScriptParser parser;
parser.SetApiLevel(35);
parser.AddModeTag("llndk=202504");
parser.SetModeTagPolicy(ModeTagPolicy::MatchTagAndApi);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_TRUE(funcs.empty());
}
{
VersionScriptParser parser;
parser.SetApiLevel(35);
parser.AddModeTag("llndk=202504");
parser.SetModeTagPolicy(ModeTagPolicy::MatchTagOnly);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs,
ElementsAre(Key("api36_llndk202504"), Key("llndk202504")));
}
{
VersionScriptParser parser;
parser.SetApiLevel(36);
parser.SetModeTagPolicy(ModeTagPolicy::MatchTagAndApi);
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::FunctionMap &funcs = result->GetFunctions();
EXPECT_THAT(funcs, ElementsAre(Key("api36"), Key("api36_llndk202504"),
Key("llndk202504")));
}
}
TEST(VersionScriptParserTest, ParseExternCpp) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
test1;
extern "C++" {
Test2::test();
Test3::test();
Test4::*;
};
test5;
};
)TESTDATA";
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::NameSet &cpp_symbols =
result->GetDemangledCppSymbols();
EXPECT_THAT(cpp_symbols, ElementsAre("Test2::test()", "Test3::test()"));
const ExportedSymbolSet::GlobPatternSet &cpp_glob_patterns =
result->GetDemangledCppGlobPatterns();
EXPECT_THAT(cpp_glob_patterns, ElementsAre("Test4::*"));
}
TEST(VersionScriptParserTest, ParseGlobPattern) {
static const char testdata[] = R"TESTDATA(
LIBEX_1.0 {
global:
test1*;
test2[Aa];
test3?;
test4;
};
)TESTDATA";
VersionScriptParser parser;
std::istringstream stream(testdata);
std::unique_ptr<ExportedSymbolSet> result(parser.Parse(stream));
ASSERT_TRUE(result);
const ExportedSymbolSet::GlobPatternSet &glob_patterns =
result->GetGlobPatterns();
EXPECT_THAT(glob_patterns, ElementsAre("test1*", "test2[Aa]", "test3?"));
}
} // namespace repr
} // namespace header_checker