Return<T>::description() provide more descriptive text than numbers

Test: libhidl_test
Change-Id: Ib7c591f261bb335b9fe348dd2fb0695a94bdf468
diff --git a/Android.bp b/Android.bp
index 59edb20..ae04548 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,7 +37,7 @@
         "libutils",
         "libcutils",
     ],
-    static_libs: ["libgtest"],
+    static_libs: ["libgtest", "libgmock"],
 
     cflags: [
         "-O0",
diff --git a/base/Status.cpp b/base/Status.cpp
index e7320a8..449aff3 100644
--- a/base/Status.cpp
+++ b/base/Status.cpp
@@ -13,15 +13,71 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #define LOG_TAG "HidlStatus"
+#include <android-base/logging.h>
 
 #include <hidl/Status.h>
 
-#include <android-base/logging.h>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
 
+static std::string statusToString(status_t s) {
+    const std::unordered_map<status_t, std::string> statusStrings{{
+        #define STATUS_TO_STRING_PAIR(STATUS) {STATUS, #STATUS}
+        STATUS_TO_STRING_PAIR(OK),
+        STATUS_TO_STRING_PAIR(UNKNOWN_ERROR),
+        STATUS_TO_STRING_PAIR(NO_MEMORY),
+        STATUS_TO_STRING_PAIR(INVALID_OPERATION),
+        STATUS_TO_STRING_PAIR(BAD_VALUE),
+        STATUS_TO_STRING_PAIR(BAD_TYPE),
+        STATUS_TO_STRING_PAIR(NAME_NOT_FOUND),
+        STATUS_TO_STRING_PAIR(PERMISSION_DENIED),
+        STATUS_TO_STRING_PAIR(NO_INIT),
+        STATUS_TO_STRING_PAIR(ALREADY_EXISTS),
+        STATUS_TO_STRING_PAIR(DEAD_OBJECT),
+        STATUS_TO_STRING_PAIR(FAILED_TRANSACTION),
+        STATUS_TO_STRING_PAIR(BAD_INDEX),
+        STATUS_TO_STRING_PAIR(NOT_ENOUGH_DATA),
+        STATUS_TO_STRING_PAIR(WOULD_BLOCK),
+        STATUS_TO_STRING_PAIR(TIMED_OUT),
+        STATUS_TO_STRING_PAIR(UNKNOWN_TRANSACTION),
+        STATUS_TO_STRING_PAIR(FDS_NOT_ALLOWED),
+        STATUS_TO_STRING_PAIR(UNEXPECTED_NULL)
+    }};
+    auto it = statusStrings.find(s);
+    if (it != statusStrings.end()) {
+        return it->second;
+    }
+    std::string str = std::to_string(s);
+    char *err = strerror(-s);
+    if (err != NULL) {
+        str.append(1, ' ').append(err);
+    }
+    return str;
+}
+
+static std::string exceptionToString(int32_t ex) {
+    const std::unordered_map<int32_t, std::string> exceptionStrings{{
+        #define EXCEPTION_TO_STRING_PAIR(EXCEPTION) {Status::Exception::EXCEPTION, #EXCEPTION}
+        EXCEPTION_TO_STRING_PAIR(EX_NONE),
+        EXCEPTION_TO_STRING_PAIR(EX_SECURITY),
+        EXCEPTION_TO_STRING_PAIR(EX_BAD_PARCELABLE),
+        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_ARGUMENT),
+        EXCEPTION_TO_STRING_PAIR(EX_NULL_POINTER),
+        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_STATE),
+        EXCEPTION_TO_STRING_PAIR(EX_NETWORK_MAIN_THREAD),
+        EXCEPTION_TO_STRING_PAIR(EX_UNSUPPORTED_OPERATION),
+        EXCEPTION_TO_STRING_PAIR(EX_SERVICE_SPECIFIC),
+        EXCEPTION_TO_STRING_PAIR(EX_HAS_REPLY_HEADER),
+        EXCEPTION_TO_STRING_PAIR(EX_TRANSACTION_FAILED)
+    }};
+    auto it = exceptionStrings.find(ex);
+    return it == exceptionStrings.end() ? std::to_string(ex) : it->second;
+}
+
 Status Status::ok() {
     return Status();
 }
@@ -86,11 +142,11 @@
     if (s.exceptionCode() == Status::EX_NONE) {
         stream << "No error";
     } else {
-        stream << "Status(" << s.exceptionCode() << "): '";
+        stream << "Status(" << exceptionToString(s.exceptionCode()) << "): '";
         if (s.exceptionCode() == Status::EX_SERVICE_SPECIFIC) {
             stream << s.serviceSpecificErrorCode() << ": ";
         } else if (s.exceptionCode() == Status::EX_TRANSACTION_FAILED) {
-            stream << s.transactionError() << ": ";
+            stream << statusToString(s.transactionError()) << ": ";
         }
         stream << s.exceptionMessage() << "'";
     }
diff --git a/test_main.cpp b/test_main.cpp
index 27d62a0..b799f6e 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -17,8 +17,10 @@
 #define LOG_TAG "LibHidlTest"
 
 #include <android-base/logging.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
 #include <hidl/TaskRunner.h>
 #include <vector>
 
@@ -344,6 +346,33 @@
     ret.isOk();
 }
 
+std::string toString(const ::android::hardware::Status &s) {
+    using ::android::hardware::operator<<;
+    std::ostringstream oss;
+    oss << s;
+    return oss.str();
+}
+
+TEST_F(LibHidlTest, StatusStringTest) {
+    using namespace ::android;
+    using ::android::hardware::Status;
+    using ::testing::HasSubstr;
+
+    EXPECT_EQ(toString(Status::ok()), "No error");
+
+    EXPECT_THAT(toString(Status::fromStatusT(DEAD_OBJECT)), HasSubstr("DEAD_OBJECT"));
+
+    EXPECT_THAT(toString(Status::fromStatusT(-EBUSY)), HasSubstr("busy"));
+
+    auto s = toString(Status::fromServiceSpecificError(20));
+    EXPECT_THAT(s, HasSubstr("EX_SERVICE_SPECIFIC"));
+    EXPECT_THAT(s, HasSubstr("20"));
+
+    EXPECT_THAT(toString(Status::fromExceptionCode(Status::EX_NULL_POINTER)),
+            HasSubstr("EX_NULL_POINTER"));
+
+}
+
 int main(int argc, char **argv) {
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();