Audio VTS: Create utility lib

Move code that can be reuse between audio tests of the HIDL interface in
an utility library.

Test: run vts tests
Test: vts-tradefed run vts --module VtsHalAudioV2_0Target
Bug: 35700978

Change-Id: Ia930ad2b0a3ca31628b2cb767b265d54b210756b
Signed-off-by: Kevin Rocard <krocard@google.com>
diff --git a/audio/2.0/vts/functional/Android.bp b/audio/2.0/vts/functional/Android.bp
index d72fb2c..daae738 100644
--- a/audio/2.0/vts/functional/Android.bp
+++ b/audio/2.0/vts/functional/Android.bp
@@ -18,8 +18,7 @@
     name: "VtsHalAudioV2_0TargetTest",
     defaults: ["hidl_defaults"],
     srcs: ["AudioPrimaryHidlHalTest.cpp",
-           "ValidateAudioConfiguration.cpp",
-           "utility/ValidateXml.cpp"],
+           "ValidateAudioConfiguration.cpp"],
     shared_libs: [
         "libbase",
         "liblog",
@@ -30,6 +29,7 @@
         "libxml2",
         "android.hardware.audio@2.0",
         "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common.test.utility",
     ],
     static_libs: ["VtsHalHidlTargetTestBase"],
     cflags: [
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index 27479ff..eec2b10 100644
--- a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -21,9 +21,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <limits>
-#include <list>
 #include <string>
-#include <type_traits>
 #include <vector>
 
 #include <VtsHalHidlTargetTestBase.h>
@@ -37,6 +35,8 @@
 #include <android/hardware/audio/common/2.0/types.h>
 
 #include "utility/AssertOk.h"
+#include "utility/Documentation.h"
+#include "utility/EnvironmentTearDown.h"
 #include "utility/PrettyPrintAudioTypes.h"
 #include "utility/ReturnIn.h"
 
@@ -59,8 +59,7 @@
 using ::android::hardware::audio::V2_0::IStream;
 using ::android::hardware::audio::V2_0::IStreamIn;
 using ::android::hardware::audio::V2_0::TimeSpec;
-using ReadParameters =
-    ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
 using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
 using ::android::hardware::audio::V2_0::IStreamOut;
 using ::android::hardware::audio::V2_0::IStreamOutCallback;
@@ -81,61 +80,8 @@
 using ::android::hardware::audio::common::V2_0::AudioSource;
 using ::android::hardware::audio::common::V2_0::ThreadInfo;
 
-using utility::returnIn;
+using namespace ::android::hardware::audio::common::test::utility;
 
-const char* getTestName() {
-    return ::testing::UnitTest::GetInstance()->current_test_info()->name();
-}
-
-namespace doc {
-/** Document the current test case.
- * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test
- * will output:
- *   <testcase name="debugDump" status="run" time="6"
- *             classname="AudioPrimaryHidlTest"
-               description="Dump the state of the hal." />
- * see
- https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
- */
-void test(const std::string& testCaseDocumentation) {
-    ::testing::Test::RecordProperty("description", testCaseDocumentation);
-}
-
-/** Document why a test was not fully run. Usually due to an optional feature
- * not implemented. */
-void partialTest(const std::string& reason) {
-    LOG(INFO) << "Test " << getTestName() << " partially run: " << reason;
-    ::testing::Test::RecordProperty("partialyRunTest", reason);
-}
-
-/** Add a note to the test. */
-void note(const std::string& note) {
-    LOG(INFO) << "Test " << getTestName() << " noted: " << note;
-    ::testing::Test::RecordProperty("note", note);
-}
-}
-
-// Register callback for static object destruction
-// Avoid destroying static objects after main return.
-// Post main return destruction leads to incorrect gtest timing measurements as
-// well as harder
-// debuging if anything goes wrong during destruction.
-class Environment : public ::testing::Environment {
-   public:
-    using TearDownFunc = std::function<void()>;
-    void registerTearDown(TearDownFunc&& tearDown) {
-        tearDowns.push_back(std::move(tearDown));
-    }
-
-   private:
-    void TearDown() override {
-        // Call the tear downs in reverse order of insertion
-        for (auto& tearDown : tearDowns) {
-            tearDown();
-        }
-    }
-    std::list<TearDownFunc> tearDowns;
-};
 // Instance to register global tearDown
 static Environment* environment;
 
@@ -1402,6 +1348,5 @@
     ::testing::AddGlobalTestEnvironment(environment);
     ::testing::InitGoogleTest(&argc, argv);
     int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
     return status;
 }
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h
deleted file mode 100644
index 4c8440e..0000000
--- a/audio/2.0/vts/functional/utility/AssertOk.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 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 <algorithm>
-#include <vector>
-
-#include <hidl/Status.h>
-
-namespace detail {
-
-// This is a detail namespace, thus it is OK to import a class as nobody else is
-// allowed to use it
-using ::android::hardware::Return;
-using ::android::hardware::audio::V2_0::Result;
-
-template <class T>
-inline ::testing::AssertionResult assertIsOk(const char* expr,
-                                             const Return<T>& ret) {
-    return ::testing::AssertionResult(ret.isOk())
-           << "Expected: " << expr
-           << "\n to be an OK Return but it is not: " << ret.description();
-}
-
-// Call continuation if the provided result isOk
-template <class T, class Continuation>
-inline ::testing::AssertionResult continueIfIsOk(const char* expr,
-                                                 const Return<T>& ret,
-                                                 Continuation continuation) {
-    auto isOkStatus = assertIsOk(expr, ret);
-    return !isOkStatus ? isOkStatus : continuation();
-}
-
-// Expect two equal Results
-inline ::testing::AssertionResult assertResult(const char* e_expr,
-                                               const char* r_expr,
-                                               Result expected, Result result) {
-    return ::testing::AssertionResult(expected == result)
-           << "Value of: " << r_expr
-           << "\n  Actual: " << ::testing::PrintToString(result)
-           << "\nExpected: " << e_expr
-           << "\nWhich is: " << ::testing::PrintToString(expected);
-}
-
-// Expect two equal Results one being wrapped in an OK Return
-inline ::testing::AssertionResult assertResult(const char* e_expr,
-                                               const char* r_expr,
-                                               Result expected,
-                                               const Return<Result>& ret) {
-    return continueIfIsOk(r_expr, ret, [&] {
-        return assertResult(e_expr, r_expr, expected, Result{ret});
-    });
-}
-
-// Expect a Result to be part of a list of Results
-inline ::testing::AssertionResult assertResult(
-    const char* e_expr, const char* r_expr, const std::vector<Result>& expected,
-    Result result) {
-    if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
-        return ::testing::AssertionSuccess();  // result is in expected
-    }
-    return ::testing::AssertionFailure()
-           << "Value of: " << r_expr
-           << "\n  Actual: " << ::testing::PrintToString(result)
-           << "\nExpected one of: " << e_expr
-           << "\n       Which is: " << ::testing::PrintToString(expected);
-}
-
-// Expect a Result wrapped in an OK Return to be part of a list of Results
-inline ::testing::AssertionResult assertResult(
-    const char* e_expr, const char* r_expr, const std::vector<Result>& expected,
-    const Return<Result>& ret) {
-    return continueIfIsOk(r_expr, ret, [&] {
-        return assertResult(e_expr, r_expr, expected, Result{ret});
-    });
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr,
-                                           const Return<void>& ret) {
-    return assertIsOk(expr, ret);
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr, Result result) {
-    return ::testing::AssertionResult(result == Result::OK)
-           << "Expected success: " << expr
-           << "\nActual: " << ::testing::PrintToString(result);
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr,
-                                           const Return<Result>& ret) {
-    return continueIfIsOk(expr, ret,
-                          [&] { return assertOk(expr, Result{ret}); });
-}
-}
-
-#define ASSERT_IS_OK(ret) ASSERT_PRED_FORMAT1(detail::assertIsOk, ret)
-#define EXPECT_IS_OK(ret) EXPECT_PRED_FORMAT1(detail::assertIsOk, ret)
-
-// Test anything provided is and contains only OK
-#define ASSERT_OK(ret) ASSERT_PRED_FORMAT1(detail::assertOk, ret)
-#define EXPECT_OK(ret) EXPECT_PRED_FORMAT1(detail::assertOk, ret)
-
-#define ASSERT_RESULT(expected, ret) \
-    ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
-#define EXPECT_RESULT(expected, ret) \
-    EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
deleted file mode 100644
index 025cd1c..0000000
--- a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 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 <type_traits>
-
-/** @file Use HIDL generated toString methods to pretty print gtest errors */
-
-namespace detail {
-
-// Print the value of an enum as hex
-template <class Enum>
-inline void printUnderlyingValue(Enum value, ::std::ostream* os) {
-    *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")";
-}
-
-} // namespace detail
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-
-inline void PrintTo(const Result& result, ::std::ostream* os) {
-    *os << toString(result);
-    detail::printUnderlyingValue(result, os);
-}
-
-} // namespace V2_0
-namespace common {
-namespace V2_0 {
-
-inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
-    *os << toString(config);
-}
-
-inline void PrintTo(const AudioDevice& device, ::std::ostream* os) {
-    *os << toString(device);
-    detail::printUnderlyingValue(device, os);
-}
-
-inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) {
-    *os << toString(channelMask);
-    detail::printUnderlyingValue(channelMask, os);
-}
-
-} // namespace V2_0
-} // namespace common
-} // namespace audio
-} // namespace hardware
-} // namespace android
diff --git a/audio/2.0/vts/functional/utility/ReturnIn.h b/audio/2.0/vts/functional/utility/ReturnIn.h
deleted file mode 100644
index bb2389a..0000000
--- a/audio/2.0/vts/functional/utility/ReturnIn.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 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 <tuple>
-
-namespace utility {
-
-namespace detail {
-// Helper class to generate the HIDL synchronous callback
-template <class... ResultStore>
-class ReturnIn {
- public:
-    // Provide to the constructor the variables where the output parameters must be copied
-    // TODO: take pointers to match google output parameter style ?
-    ReturnIn(ResultStore&... ts) : results(ts...) {}
-    // Synchronous callback
-    template <class... Results>
-    void operator() (Results&&...results) {
-        set(std::forward<Results>(results)...);
-    }
- private:
-    // Recursively set all output parameters
-    template <class Head, class... Tail>
-    void set(Head&& head, Tail&&... tail) {
-        std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results)
-                  = std::forward<Head>(head);
-        set(tail...);
-    }
-    // Trivial case
-    void set() {}
-
-    // All variables to set are stored here
-    std::tuple<ResultStore&...> results;
-};
-} // namespace detail
-
-// Generate the HIDL synchronous callback with a copy policy
-// Input: the variables (lvalue reference) where to save the return values
-// Output: the callback to provide to a HIDL call with a synchronous callback
-// The output parameters *will be copied* do not use this function if you have
-// a zero copy policy
-template <class... ResultStore>
-detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) { return {ts...};}
-
-}
diff --git a/audio/2.0/vts/functional/utility/ValidateXml.cpp b/audio/2.0/vts/functional/utility/ValidateXml.cpp
deleted file mode 100644
index 2fb828e..0000000
--- a/audio/2.0/vts/functional/utility/ValidateXml.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "ValidateAudioConfig"
-#include <utils/Log.h>
-
-#define LIBXML_SCHEMAS_ENABLED
-#include <libxml/xmlschemastypes.h>
-#define LIBXML_XINCLUDE_ENABLED
-#include <libxml/xinclude.h>
-
-#include <memory>
-#include <string>
-
-#include "ValidateXml.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace test {
-
-/** Map libxml2 structures to their corresponding deleters. */
-template <class T>
-constexpr void (*xmlDeleter)(T* t);
-template <>
-constexpr auto xmlDeleter<xmlSchema> = xmlSchemaFree;
-template <>
-constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
-template <>
-constexpr auto xmlDeleter<xmlSchemaParserCtxt> = xmlSchemaFreeParserCtxt;
-template <>
-constexpr auto xmlDeleter<xmlSchemaValidCtxt> = xmlSchemaFreeValidCtxt;
-
-/** @return a unique_ptr with the correct deleter for the libxml2 object. */
-template <class T>
-constexpr auto make_xmlUnique(T* t) {
-    // Wrap deleter in lambda to enable empty base optimization
-    auto deleter = [](T* t) { xmlDeleter<T>(t); };
-    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
-}
-
-/** Class that handles libxml2 initialization and cleanup. NOT THREAD SAFE*/
-struct Libxml2Global {
-    Libxml2Global() {
-        xmlLineNumbersDefault(1);  // Better error message
-        xmlSetGenericErrorFunc(this, errorCb);
-    }
-    ~Libxml2Global() {
-        // TODO: check if all those cleanup are needed
-        xmlSetGenericErrorFunc(nullptr, nullptr);
-        xmlSchemaCleanupTypes();
-        xmlCleanupParser();
-        xmlCleanupThreads();
-    }
-
-    const std::string& getErrors() { return errors; }
-
-   private:
-    static void errorCb(void* ctxt, const char* msg, ...) {
-        auto* self = static_cast<Libxml2Global*>(ctxt);
-        va_list args;
-        va_start(args, msg);
-
-        char* formatedMsg;
-        if (vasprintf(&formatedMsg, msg, args) >= 0) {
-            LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", formatedMsg);
-            self->errors += "Error: ";
-            self->errors += formatedMsg;
-        }
-        free(formatedMsg);
-
-        va_end(args);
-    }
-    std::string errors;
-};
-
-::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
-                                       const char* xmlFilePath, const char* xsdFilePath) {
-    Libxml2Global libxml2;
-
-    auto context = [&]() {
-        return std::string() + "    While validating: " + xmlFilePathExpr +
-               "\n          Which is: " + xmlFilePath + "\nAgainst the schema: " + xsdFilePathExpr +
-               "\n          Which is: " + xsdFilePath + "Libxml2 errors\n" + libxml2.getErrors();
-    };
-
-    auto schemaParserCtxt = make_xmlUnique(xmlSchemaNewParserCtxt(xsdFilePath));
-    auto schema = make_xmlUnique(xmlSchemaParse(schemaParserCtxt.get()));
-    if (schema == nullptr) {
-        return ::testing::AssertionFailure() << "Failed to parse schema (xsd)\n" << context();
-    }
-
-    auto doc = make_xmlUnique(xmlReadFile(xmlFilePath, nullptr, 0));
-    if (doc == nullptr) {
-        return ::testing::AssertionFailure() << "Failed to parse xml\n" << context();
-    }
-
-    if (xmlXIncludeProcess(doc.get()) == -1) {
-        return ::testing::AssertionFailure() << "Failed to resolve xincludes in xml\n" << context();
-    }
-
-    auto schemaCtxt = make_xmlUnique(xmlSchemaNewValidCtxt(schema.get()));
-    int ret = xmlSchemaValidateDoc(schemaCtxt.get(), doc.get());
-    if (ret > 0) {
-        return ::testing::AssertionFailure() << "xml is not valid according to the xsd.\n"
-                                             << context();
-    }
-    if (ret < 0) {
-        return ::testing::AssertionFailure() << "Internal or API error\n" << context();
-    }
-
-    return ::testing::AssertionSuccess();
-}
-
-}  // namespace test
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/vts/functional/utility/ValidateXml.h b/audio/2.0/vts/functional/utility/ValidateXml.h
deleted file mode 100644
index edb09bf..0000000
--- a/audio/2.0/vts/functional/utility/ValidateXml.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_TEST_VALIDATEXML
-#define ANDROID_HARDWARE_AUDIO_TEST_VALIDATEXML
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace test {
-
-/** Validate the provided XmlFile with the provided xsdFile.
- * Intended to use with ASSERT_PRED_FORMAT2 as such:
- *   ASSERT_PRED_FORMAT2(validateXml, pathToXml, pathToXsd);
- * See ASSERT_VALID_XML for a helper macro.
- */
-::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
-                                       const char* xmlFilePath, const char* xsdPathName);
-
-/** Helper gtest ASSERT to test xml validity against an xsd. */
-#define ASSERT_VALID_XML(xmlFilePath, xsdFilePath) \
-    ASSERT_PRED_FORMAT2(::android::hardware::audio::test::validateXml, xmlFilePath, xsdFilePath)
-
-}  // namespace test
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_TEST_VALIDATEXML