Home | History | Annotate | Download | only in lshal
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "Lshal"
     18 #include <android-base/logging.h>
     19 
     20 #include <sstream>
     21 #include <string>
     22 #include <thread>
     23 #include <vector>
     24 
     25 #include <gtest/gtest.h>
     26 #include <gmock/gmock.h>
     27 #include <android/hardware/tests/baz/1.0/IQuux.h>
     28 #include <hidl/HidlTransportSupport.h>
     29 #include <vintf/parse_xml.h>
     30 
     31 #include "ListCommand.h"
     32 #include "Lshal.h"
     33 
     34 #define NELEMS(array)   static_cast<int>(sizeof(array) / sizeof(array[0]))
     35 
     36 using namespace testing;
     37 
     38 using ::android::hidl::base::V1_0::DebugInfo;
     39 using ::android::hidl::base::V1_0::IBase;
     40 using ::android::hidl::manager::V1_0::IServiceManager;
     41 using ::android::hidl::manager::V1_0::IServiceNotification;
     42 using ::android::hardware::hidl_array;
     43 using ::android::hardware::hidl_death_recipient;
     44 using ::android::hardware::hidl_handle;
     45 using ::android::hardware::hidl_string;
     46 using ::android::hardware::hidl_vec;
     47 
     48 using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
     49 
     50 using hidl_hash = hidl_array<uint8_t, 32>;
     51 
     52 namespace android {
     53 namespace hardware {
     54 namespace tests {
     55 namespace baz {
     56 namespace V1_0 {
     57 namespace implementation {
     58 struct Quux : android::hardware::tests::baz::V1_0::IQuux {
     59     ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
     60         const native_handle_t *handle = hh.getNativeHandle();
     61         if (handle->numFds < 1) {
     62             return Void();
     63         }
     64         int fd = handle->data[0];
     65         std::string content{descriptor};
     66         for (const auto &option : options) {
     67             content += "\n";
     68             content += option.c_str();
     69         }
     70         ssize_t written = write(fd, content.c_str(), content.size());
     71         if (written != (ssize_t)content.size()) {
     72             LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
     73                     << content.size() << " bytes, errno = " << errno;
     74         }
     75         return Void();
     76     }
     77 };
     78 
     79 } // namespace implementation
     80 } // namespace V1_0
     81 } // namespace baz
     82 } // namespace tests
     83 } // namespace hardware
     84 
     85 namespace lshal {
     86 
     87 class MockServiceManager : public IServiceManager {
     88 public:
     89     template<typename T>
     90     using R = ::android::hardware::Return<T>;
     91     using String = const hidl_string&;
     92     ~MockServiceManager() = default;
     93 
     94 #define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
     95 
     96     MOCK_METHOD2(get, R<sp<IBase>>(String, String));
     97     MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
     98     MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
     99     MOCK_METHOD_CB(list);
    100     MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
    101     MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
    102     MOCK_METHOD_CB(debugDump);
    103     MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
    104     MOCK_METHOD_CB(interfaceChain);
    105     MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
    106     MOCK_METHOD_CB(interfaceDescriptor);
    107     MOCK_METHOD_CB(getHashChain);
    108     MOCK_METHOD0(setHalInstrumentation, R<void>());
    109     MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
    110     MOCK_METHOD0(ping, R<void>());
    111     MOCK_METHOD_CB(getDebugInfo);
    112     MOCK_METHOD0(notifySyspropsChanged, R<void>());
    113     MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
    114 
    115 };
    116 
    117 class DebugTest : public ::testing::Test {
    118 public:
    119     void SetUp() override {
    120         using ::android::hardware::tests::baz::V1_0::IQuux;
    121         using ::android::hardware::tests::baz::V1_0::implementation::Quux;
    122 
    123         err.str("");
    124         out.str("");
    125         serviceManager = new testing::NiceMock<MockServiceManager>();
    126         ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
    127             [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
    128                 if (iface == IQuux::descriptor && inst == "default")
    129                     return new Quux();
    130                 return nullptr;
    131             }));
    132 
    133         lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
    134     }
    135     void TearDown() override {}
    136 
    137     std::stringstream err;
    138     std::stringstream out;
    139     sp<MockServiceManager> serviceManager;
    140 
    141     std::unique_ptr<Lshal> lshal;
    142 };
    143 
    144 static Arg createArg(const std::vector<const char*>& args) {
    145     return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
    146 }
    147 
    148 template<typename T>
    149 static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
    150     return lshal->main(createArg(args));
    151 }
    152 
    153 TEST_F(DebugTest, Debug) {
    154     EXPECT_EQ(0u, callMain(lshal, {
    155         "lshal", "debug", "android.hardware.tests.baz (at) 1.0::IQuux/default", "foo", "bar"
    156     }));
    157     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz (at) 1.0::IQuux\nfoo\nbar"));
    158     EXPECT_THAT(err.str(), IsEmpty());
    159 }
    160 
    161 TEST_F(DebugTest, Debug2) {
    162     EXPECT_EQ(0u, callMain(lshal, {
    163         "lshal", "debug", "android.hardware.tests.baz (at) 1.0::IQuux", "baz", "quux"
    164     }));
    165     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz (at) 1.0::IQuux\nbaz\nquux"));
    166     EXPECT_THAT(err.str(), IsEmpty());
    167 }
    168 
    169 TEST_F(DebugTest, Debug3) {
    170     EXPECT_NE(0u, callMain(lshal, {
    171         "lshal", "debug", "android.hardware.tests.doesnotexist (at) 1.0::IDoesNotExist",
    172     }));
    173     EXPECT_THAT(err.str(), HasSubstr("does not exist"));
    174 }
    175 
    176 class MockLshal : public Lshal {
    177 public:
    178     MockLshal() {}
    179     ~MockLshal() = default;
    180     MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
    181     MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
    182 };
    183 
    184 // expose protected fields and methods for ListCommand
    185 class MockListCommand : public ListCommand {
    186 public:
    187     MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
    188 
    189     Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
    190     Status main(const Arg& arg) { return ListCommand::main(arg); }
    191     void forEachTable(const std::function<void(Table &)> &f) {
    192         return ListCommand::forEachTable(f);
    193     }
    194     void forEachTable(const std::function<void(const Table &)> &f) const {
    195         return ListCommand::forEachTable(f);
    196     }
    197     Status fetch() { return ListCommand::fetch(); }
    198     void dumpVintf(const NullableOStream<std::ostream>& out) {
    199         return ListCommand::dumpVintf(out);
    200     }
    201     void internalPostprocess() { ListCommand::postprocess(); }
    202     const PidInfo* getPidInfoCached(pid_t serverPid) {
    203         return ListCommand::getPidInfoCached(serverPid);
    204     }
    205 
    206     MOCK_METHOD0(postprocess, void());
    207     MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
    208     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
    209     MOCK_METHOD1(getPartition, Partition(pid_t));
    210 };
    211 
    212 class ListParseArgsTest : public ::testing::Test {
    213 public:
    214     void SetUp() override {
    215         mockLshal = std::make_unique<NiceMock<MockLshal>>();
    216         mockList = std::make_unique<MockListCommand>(mockLshal.get());
    217         // ListCommand::parseArgs should parse arguments from the second element
    218         optind = 1;
    219     }
    220     std::unique_ptr<MockLshal> mockLshal;
    221     std::unique_ptr<MockListCommand> mockList;
    222     std::stringstream output;
    223 };
    224 
    225 TEST_F(ListParseArgsTest, Args) {
    226     EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
    227     mockList->forEachTable([](const Table& table) {
    228         EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
    229                                    TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
    230                   table.getSelectedColumns());
    231     });
    232 }
    233 
    234 TEST_F(ListParseArgsTest, Cmds) {
    235     EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
    236     mockList->forEachTable([](const Table& table) {
    237         EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
    238                 << "should not print server PID with -m";
    239         EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
    240                 << "should not print client PIDs with -m";
    241         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
    242                 << "should print server cmd with -m";
    243         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
    244                 << "should print client cmds with -m";
    245     });
    246 }
    247 
    248 TEST_F(ListParseArgsTest, DebugAndNeat) {
    249     ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
    250     EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
    251     EXPECT_THAT(output.str(), StrNe(""));
    252 }
    253 
    254 /// Fetch Test
    255 
    256 // A set of deterministic functions to generate fake debug infos.
    257 static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
    258 static std::vector<pid_t> getClients(pid_t serverId) {
    259     return {serverId + 1, serverId + 3};
    260 }
    261 static PidInfo getPidInfoFromId(pid_t serverId) {
    262     PidInfo info;
    263     info.refPids[getPtr(serverId)] = getClients(serverId);
    264     info.threadUsage = 10 + serverId;
    265     info.threadCount = 20 + serverId;
    266     return info;
    267 }
    268 static std::string getInterfaceName(pid_t serverId) {
    269     return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
    270 }
    271 static std::string getInstanceName(pid_t serverId) {
    272     return std::to_string(serverId);
    273 }
    274 static pid_t getIdFromInstanceName(const hidl_string& instance) {
    275     return atoi(instance.c_str());
    276 }
    277 static std::string getFqInstanceName(pid_t serverId) {
    278     return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
    279 }
    280 static std::string getCmdlineFromId(pid_t serverId) {
    281     if (serverId == NO_PID) return "";
    282     return "command_line_" + std::to_string(serverId);
    283 }
    284 static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
    285 static hidl_hash getHashFromId(pid_t serverId) {
    286     hidl_hash hash;
    287     bool isReleased = getIsReleasedFromId(serverId);
    288     for (size_t i = 0; i < hash.size(); ++i) {
    289         hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
    290     }
    291     return hash;
    292 }
    293 
    294 // Fake service returned by mocked IServiceManager::get.
    295 class TestService : public IBase {
    296 public:
    297     TestService(pid_t id) : mId(id) {}
    298     hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
    299         cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
    300         return hardware::Void();
    301     }
    302     hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
    303         cb({getInterfaceName(mId), IBase::descriptor});
    304         return hardware::Void();
    305     }
    306     hardware::Return<void> getHashChain(getHashChain_cb cb) override {
    307         cb({getHashFromId(mId), getHashFromId(0xff)});
    308         return hardware::Void();
    309     }
    310 private:
    311     pid_t mId;
    312 };
    313 
    314 class ListTest : public ::testing::Test {
    315 public:
    316     void SetUp() override {
    317         initMockServiceManager();
    318         lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
    319         initMockList();
    320     }
    321 
    322     void initMockList() {
    323         mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
    324         ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
    325             [](pid_t serverPid, PidInfo* info) {
    326                 *info = getPidInfoFromId(serverPid);
    327                 return true;
    328             }));
    329         ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
    330         ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
    331             mockList->internalPostprocess();
    332             size_t i = 0;
    333             mockList->forEachTable([&](Table& table) {
    334                 table.setDescription("[fake description " + std::to_string(i++) + "]");
    335             });
    336         }));
    337         ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
    338     }
    339 
    340     void initMockServiceManager() {
    341         serviceManager = new testing::NiceMock<MockServiceManager>();
    342         passthruManager = new testing::NiceMock<MockServiceManager>();
    343         using A = DebugInfo::Architecture;
    344         ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
    345             [] (IServiceManager::list_cb cb) {
    346                 cb({ getFqInstanceName(1), getFqInstanceName(2) });
    347                 return hardware::Void();
    348             }));
    349 
    350         ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
    351             [&](const hidl_string&, const hidl_string& instance) {
    352                 int id = getIdFromInstanceName(instance);
    353                 return sp<IBase>(new TestService(id));
    354             }));
    355 
    356         ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
    357             [] (IServiceManager::debugDump_cb cb) {
    358                 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
    359                                       getClients(3), A::IS_32BIT},
    360                     InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
    361                                       getClients(4), A::IS_32BIT}});
    362                 return hardware::Void();
    363             }));
    364 
    365         ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
    366             [] (IServiceManager::debugDump_cb cb) {
    367                 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
    368                                       getClients(5), A::IS_32BIT},
    369                     InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
    370                                       getClients(6), A::IS_32BIT}});
    371                 return hardware::Void();
    372             }));
    373     }
    374 
    375     std::stringstream err;
    376     std::stringstream out;
    377     std::unique_ptr<Lshal> lshal;
    378     std::unique_ptr<MockListCommand> mockList;
    379     sp<MockServiceManager> serviceManager;
    380     sp<MockServiceManager> passthruManager;
    381 };
    382 
    383 TEST_F(ListTest, GetPidInfoCached) {
    384     EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
    385 
    386     EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
    387     EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
    388 }
    389 
    390 TEST_F(ListTest, Fetch) {
    391     EXPECT_EQ(0u, mockList->fetch());
    392     std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
    393                                           "passthrough", "passthrough", "passthrough"}};
    394     std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
    395     int id = 1;
    396     mockList->forEachTable([&](const Table& table) {
    397         ASSERT_EQ(2u, table.size());
    398         for (const auto& entry : table) {
    399             const auto& transport = transports[id - 1];
    400             TableEntry expected{
    401                 .interfaceName = getFqInstanceName(id),
    402                 .transport = transport,
    403                 .serverPid = transport == "hwbinder" ? id : NO_PID,
    404                 .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
    405                 .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
    406                 .serverCmdline = {},
    407                 .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
    408                 .clientPids = getClients(id),
    409                 .clientCmdlines = {},
    410                 .arch = archs[id - 1],
    411             };
    412             EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
    413 
    414             ++id;
    415         }
    416     });
    417 
    418 }
    419 
    420 TEST_F(ListTest, DumpVintf) {
    421     const std::string expected =
    422         "<!-- \n"
    423         "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
    424         "-->\n"
    425         "<manifest version=\"1.0\" type=\"device\">\n"
    426         "    <hal format=\"hidl\">\n"
    427         "        <name>a.h.foo1</name>\n"
    428         "        <transport>hwbinder</transport>\n"
    429         "        <version>1.0</version>\n"
    430         "        <interface>\n"
    431         "            <name>IFoo</name>\n"
    432         "            <instance>1</instance>\n"
    433         "        </interface>\n"
    434         "    </hal>\n"
    435         "    <hal format=\"hidl\">\n"
    436         "        <name>a.h.foo2</name>\n"
    437         "        <transport>hwbinder</transport>\n"
    438         "        <version>2.0</version>\n"
    439         "        <interface>\n"
    440         "            <name>IFoo</name>\n"
    441         "            <instance>2</instance>\n"
    442         "        </interface>\n"
    443         "    </hal>\n"
    444         "    <hal format=\"hidl\">\n"
    445         "        <name>a.h.foo3</name>\n"
    446         "        <transport arch=\"32\">passthrough</transport>\n"
    447         "        <version>3.0</version>\n"
    448         "        <interface>\n"
    449         "            <name>IFoo</name>\n"
    450         "            <instance>3</instance>\n"
    451         "        </interface>\n"
    452         "    </hal>\n"
    453         "    <hal format=\"hidl\">\n"
    454         "        <name>a.h.foo4</name>\n"
    455         "        <transport arch=\"32\">passthrough</transport>\n"
    456         "        <version>4.0</version>\n"
    457         "        <interface>\n"
    458         "            <name>IFoo</name>\n"
    459         "            <instance>4</instance>\n"
    460         "        </interface>\n"
    461         "    </hal>\n"
    462         "    <hal format=\"hidl\">\n"
    463         "        <name>a.h.foo5</name>\n"
    464         "        <transport arch=\"32\">passthrough</transport>\n"
    465         "        <version>5.0</version>\n"
    466         "    </hal>\n"
    467         "    <hal format=\"hidl\">\n"
    468         "        <name>a.h.foo6</name>\n"
    469         "        <transport arch=\"32\">passthrough</transport>\n"
    470         "        <version>6.0</version>\n"
    471         "    </hal>\n"
    472         "</manifest>\n";
    473 
    474     optind = 1; // mimic Lshal::parseArg()
    475     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
    476     EXPECT_EQ(expected, out.str());
    477     EXPECT_EQ("", err.str());
    478 
    479     vintf::HalManifest m;
    480     EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
    481         << "--init-vintf does not emit valid HAL manifest: "
    482         << vintf::gHalManifestConverter.lastError();
    483 }
    484 
    485 // test default columns
    486 TEST_F(ListTest, DumpDefault) {
    487     const std::string expected =
    488         "[fake description 0]\n"
    489         "R Interface            Thread Use Server Clients\n"
    490         "  a.h.foo1 (at) 1.0::IFoo/1 11/21      1      2 4\n"
    491         "Y a.h.foo2 (at) 2.0::IFoo/2 12/22      2      3 5\n"
    492         "\n"
    493         "[fake description 1]\n"
    494         "R Interface            Thread Use Server Clients\n"
    495         "  a.h.foo3 (at) 3.0::IFoo/3 N/A        N/A    4 6\n"
    496         "  a.h.foo4 (at) 4.0::IFoo/4 N/A        N/A    5 7\n"
    497         "\n"
    498         "[fake description 2]\n"
    499         "R Interface            Thread Use Server Clients\n"
    500         "  a.h.foo5 (at) 5.0::IFoo/5 N/A        N/A    6 8\n"
    501         "  a.h.foo6 (at) 6.0::IFoo/6 N/A        N/A    7 9\n"
    502         "\n";
    503 
    504     optind = 1; // mimic Lshal::parseArg()
    505     EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
    506     EXPECT_EQ(expected, out.str());
    507     EXPECT_EQ("", err.str());
    508 }
    509 
    510 TEST_F(ListTest, DumpHash) {
    511     const std::string expected =
    512         "[fake description 0]\n"
    513         "Interface            R Hash\n"
    514         "a.h.foo1 (at) 1.0::IFoo/1   0000000000000000000000000000000000000000000000000000000000000000\n"
    515         "a.h.foo2 (at) 2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
    516         "\n"
    517         "[fake description 1]\n"
    518         "Interface            R Hash\n"
    519         "a.h.foo3 (at) 3.0::IFoo/3   \n"
    520         "a.h.foo4 (at) 4.0::IFoo/4   \n"
    521         "\n"
    522         "[fake description 2]\n"
    523         "Interface            R Hash\n"
    524         "a.h.foo5 (at) 5.0::IFoo/5   \n"
    525         "a.h.foo6 (at) 6.0::IFoo/6   \n"
    526         "\n";
    527 
    528     optind = 1; // mimic Lshal::parseArg()
    529     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
    530     EXPECT_EQ(expected, out.str());
    531     EXPECT_EQ("", err.str());
    532 }
    533 
    534 TEST_F(ListTest, Dump) {
    535     const std::string expected =
    536         "[fake description 0]\n"
    537         "Interface            Transport Arch Thread Use Server PTR              Clients\n"
    538         "a.h.foo1 (at) 1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
    539         "a.h.foo2 (at) 2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
    540         "\n"
    541         "[fake description 1]\n"
    542         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
    543         "a.h.foo3 (at) 3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
    544         "a.h.foo4 (at) 4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
    545         "\n"
    546         "[fake description 2]\n"
    547         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
    548         "a.h.foo5 (at) 5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
    549         "a.h.foo6 (at) 6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
    550         "\n";
    551 
    552     optind = 1; // mimic Lshal::parseArg()
    553     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
    554     EXPECT_EQ(expected, out.str());
    555     EXPECT_EQ("", err.str());
    556 }
    557 
    558 TEST_F(ListTest, DumpCmdline) {
    559     const std::string expected =
    560         "[fake description 0]\n"
    561         "Interface            Transport Arch Thread Use Server CMD     PTR              Clients CMD\n"
    562         "a.h.foo1 (at) 1.0::IFoo/1 hwbinder  64   11/21      command_line_1 0000000000002711 command_line_2;command_line_4\n"
    563         "a.h.foo2 (at) 2.0::IFoo/2 hwbinder  64   12/22      command_line_2 0000000000002712 command_line_3;command_line_5\n"
    564         "\n"
    565         "[fake description 1]\n"
    566         "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
    567         "a.h.foo3 (at) 3.0::IFoo/3 passthrough 32   N/A                   N/A command_line_4;command_line_6\n"
    568         "a.h.foo4 (at) 4.0::IFoo/4 passthrough 32   N/A                   N/A command_line_5;command_line_7\n"
    569         "\n"
    570         "[fake description 2]\n"
    571         "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
    572         "a.h.foo5 (at) 5.0::IFoo/5 passthrough 32   N/A                   N/A command_line_6;command_line_8\n"
    573         "a.h.foo6 (at) 6.0::IFoo/6 passthrough 32   N/A                   N/A command_line_7;command_line_9\n"
    574         "\n";
    575 
    576     optind = 1; // mimic Lshal::parseArg()
    577     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
    578     EXPECT_EQ(expected, out.str());
    579     EXPECT_EQ("", err.str());
    580 }
    581 
    582 TEST_F(ListTest, DumpNeat) {
    583     const std::string expected =
    584         "a.h.foo1 (at) 1.0::IFoo/1 11/21 1   2 4\n"
    585         "a.h.foo2 (at) 2.0::IFoo/2 12/22 2   3 5\n"
    586         "a.h.foo3 (at) 3.0::IFoo/3 N/A   N/A 4 6\n"
    587         "a.h.foo4 (at) 4.0::IFoo/4 N/A   N/A 5 7\n"
    588         "a.h.foo5 (at) 5.0::IFoo/5 N/A   N/A 6 8\n"
    589         "a.h.foo6 (at) 6.0::IFoo/6 N/A   N/A 7 9\n";
    590 
    591     optind = 1; // mimic Lshal::parseArg()
    592     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
    593     EXPECT_EQ(expected, out.str());
    594     EXPECT_EQ("", err.str());
    595 }
    596 
    597 class HelpTest : public ::testing::Test {
    598 public:
    599     void SetUp() override {
    600         lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
    601                                         new MockServiceManager() /* passthruManager */);
    602     }
    603 
    604     std::stringstream err;
    605     std::stringstream out;
    606     std::unique_ptr<Lshal> lshal;
    607 };
    608 
    609 TEST_F(HelpTest, GlobalUsage) {
    610     (void)callMain(lshal, {"lshal", "--help"}); // ignore return
    611     std::string errStr = err.str();
    612     EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
    613         << "`lshal --help` does not contain global usage";
    614     EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
    615         << "`lshal --help` does not contain usage for 'list' command";
    616     EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
    617         << "`lshal --help` does not contain usage for 'debug' command";
    618     EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
    619         << "`lshal --help` does not contain usage for 'help' command";
    620 
    621     err.str("");
    622     (void)callMain(lshal, {"lshal", "help"}); // ignore return
    623     EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
    624 
    625     err.str("");
    626     EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
    627     EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
    628     EXPECT_THAT(err.str(), EndsWith(errStr))
    629             << "`lshal --unknown-option` should have the same output as `lshal --help`";
    630     EXPECT_EQ("", out.str());
    631 }
    632 
    633 TEST_F(HelpTest, UnknownOptionList1) {
    634     (void)callMain(lshal, {"lshal", "help", "list"});
    635     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
    636         << "`lshal help list` does not contain usage for 'list' command";
    637 }
    638 
    639 TEST_F(HelpTest, UnknownOptionList2) {
    640     EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
    641     EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
    642     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
    643         << "`lshal list --unknown-option` does not contain usage for 'list' command";
    644     EXPECT_EQ("", out.str());
    645 }
    646 
    647 TEST_F(HelpTest, UnknownOptionHelp1) {
    648     (void)callMain(lshal, {"lshal", "help", "help"});
    649     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
    650         << "`lshal help help` does not contain usage for 'help' command";
    651 }
    652 
    653 TEST_F(HelpTest, UnknownOptionHelp2) {
    654     (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
    655     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
    656         << "`lshal help --unknown-option` does not contain usage for 'help' command";
    657     EXPECT_EQ("", out.str());
    658 }
    659 
    660 } // namespace lshal
    661 } // namespace android
    662 
    663 int main(int argc, char **argv) {
    664     ::testing::InitGoogleMock(&argc, argv);
    665     return RUN_ALL_TESTS();
    666 }
    667