Merge "Add support for relative package paths."
diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp
index 1b2979d..5f022c8 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -170,20 +170,23 @@
     return mIsEvaluated;
 }
 
-LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value) {
+LiteralConstantExpression::LiteralConstantExpression(
+    ScalarType::Kind kind, uint64_t value, const std::string& expr) {
+
+    CHECK(!expr.empty());
     CHECK(isSupported(kind));
     mTrivialDescription = true;
-    mExpr = std::to_string(value);
+    mExpr = expr;
     mValueKind = kind;
     mValue = value;
     mIsEvaluated = true;
 }
 
-LiteralConstantExpression::LiteralConstantExpression(const std::string& value) {
+LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value)
+  : LiteralConstantExpression(kind, value, std::to_string(value)) {}
+
+LiteralConstantExpression* LiteralConstantExpression::tryParse(const std::string& value) {
     CHECK(!value.empty());
-    mIsEvaluated = true;
-    mTrivialDescription = true;
-    mExpr = value;
 
     bool isLong = false, isUnsigned = false;
     bool isHex = (value[0] == '0' && value.length() > 1 && (value[1] == 'x' || value[1] == 'X'));
@@ -197,39 +200,50 @@
     }
     std::string newVal(value.begin(), rbegin.base());
     CHECK(!newVal.empty());
-    bool parseOK = base::ParseUint(newVal, &mValue);
-    CHECK(parseOK) << "Could not parse as integer: " << value;
+
+    uint64_t rawValue = 0;
+
+    bool parseOK = base::ParseUint(newVal, &rawValue);
+    if (!parseOK) {
+        return nullptr;
+    }
+
+    ScalarType::Kind kind;
 
     // guess literal type.
     if(isLong) {
         if(isUnsigned) // ul
-            mValueKind = SK(UINT64);
+            kind = SK(UINT64);
         else // l
-            mValueKind = SK(INT64);
+            kind = SK(INT64);
     } else { // no l suffix
         if(isUnsigned) { // u
-            if(mValue <= UINT32_MAX)
-                mValueKind = SK(UINT32);
+            if(rawValue <= UINT32_MAX)
+                kind = SK(UINT32);
             else
-                mValueKind = SK(UINT64);
+                kind = SK(UINT64);
         } else { // no suffix
             if(isHex) {
-                if(mValue <= INT32_MAX) // mValue always >= 0
-                    mValueKind = SK(INT32);
-                else if(mValue <= UINT32_MAX)
-                    mValueKind = SK(UINT32);
-                else if(mValue <= INT64_MAX) // mValue always >= 0
-                    mValueKind = SK(INT64);
-                else if(mValue <= UINT64_MAX)
-                    mValueKind = SK(UINT64);
-            } else {
-                if(mValue <= INT32_MAX) // mValue always >= 0
-                    mValueKind = SK(INT32);
+                if(rawValue <= INT32_MAX) // rawValue always >= 0
+                    kind = SK(INT32);
+                else if(rawValue <= UINT32_MAX)
+                    kind = SK(UINT32);
+                else if(rawValue <= INT64_MAX) // rawValue always >= 0
+                    kind = SK(INT64);
+                else if(rawValue <= UINT64_MAX)
+                    kind = SK(UINT64);
                 else
-                    mValueKind = SK(INT64);
+                    return nullptr;
+            } else {
+                if(rawValue <= INT32_MAX) // rawValue always >= 0
+                    kind = SK(INT32);
+                else
+                    kind = SK(INT64);
             }
         }
     }
+
+    return new LiteralConstantExpression(kind, rawValue, value);
 }
 
 void LiteralConstantExpression::evaluate() {
diff --git a/ConstantExpression.h b/ConstantExpression.h
index 0dc9693..9784885 100644
--- a/ConstantExpression.h
+++ b/ConstantExpression.h
@@ -156,9 +156,13 @@
 
 struct LiteralConstantExpression : public ConstantExpression {
     LiteralConstantExpression(ScalarType::Kind kind, uint64_t value);
-    LiteralConstantExpression(const std::string& value);
     void evaluate() override;
     std::vector<const ConstantExpression*> getConstantExpressions() const override;
+
+    static LiteralConstantExpression* tryParse(const std::string& value);
+
+private:
+    LiteralConstantExpression(ScalarType::Kind kind, uint64_t value, const std::string& expr);
 };
 
 struct UnaryConstantExpression : public ConstantExpression {
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index e1d472f..f872e43 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -693,7 +693,15 @@
     ;
 
 const_expr
-    : INTEGER                   { $$ = new LiteralConstantExpression($1); }
+    : INTEGER                   {
+          $$ = LiteralConstantExpression::tryParse($1);
+
+          if ($$ == nullptr) {
+              std::cerr << "ERROR: Could not parse literal: "
+                        << $1 << " at " << @1 << ".\n";
+              YYERROR;
+          }
+      }
     | fqname
       {
           if(!$1->isValidValueName()) {
@@ -894,6 +902,7 @@
 
 enum_storage_type
     : ':' fqtype { $$ = $2; }
+    | /* empty */ { $$ = nullptr; }
     ;
 
 opt_comma
@@ -904,8 +913,18 @@
 named_enum_declaration
     : ENUM valid_type_name enum_storage_type
       {
+          auto storageType = $3;
+
+          if (storageType == nullptr) {
+              std::cerr << "ERROR: Must explicitly specify enum storage type for "
+                        << $2 << " at " << @2 << "\n";
+              ast->addSyntaxError();
+              storageType = new Reference<Type>(
+                  new ScalarType(ScalarType::KIND_INT64, *scope), convertYYLoc(@2));
+          }
+
           EnumType* enumType = new EnumType(
-              $2, ast->makeFullName($2, *scope), convertYYLoc(@2), *$3, *scope);
+              $2, ast->makeFullName($2, *scope), convertYYLoc(@2), *storageType, *scope);
           enterScope(ast, scope, enumType);
       }
       enum_declaration_body
diff --git a/test/error_test/Android.bp b/test/error_test/Android.bp
index 899f99c..e06c6d7 100644
--- a/test/error_test/Android.bp
+++ b/test/error_test/Android.bp
@@ -7,6 +7,7 @@
     out: ["TODO_b_37575883.cpp"],
     srcs: [
         "bad_character/1.0/IFoo.hal",
+        "enum_storage/1.0/IFoo.hal",
         "enum_unique_field_names/1.0/IFoo.hal",
         "enum_unique_field_names_extends/1.0/IFoo.hal",
         "interface_extends_only_interface/1.0/IFoo.hal",
diff --git a/test/error_test/enum_storage/1.0/IFoo.hal b/test/error_test/enum_storage/1.0/IFoo.hal
new file mode 100644
index 0000000..68f17c9
--- /dev/null
+++ b/test/error_test/enum_storage/1.0/IFoo.hal
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+package test.bad_character@1.0;
+
+interface IFoo {
+
+    enum A /* missing storage */ {
+    };
+
+};
+
diff --git a/test/error_test/hidl_error_test.sh b/test/error_test/hidl_error_test.sh
index cde1e81..92d0efe 100755
--- a/test/error_test/hidl_error_test.sh
+++ b/test/error_test/hidl_error_test.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 if [ $# -ne 1 ]; then
-    echo "hidl_errr_test.sh hidl-gen_path"
+    echo "usage: hidl_error_test.sh hidl-gen_path"
     exit 1
 fi
 
diff --git a/test/run_all_device_tests.sh b/test/run_all_device_tests.sh
new file mode 100755
index 0000000..3ae7614
--- /dev/null
+++ b/test/run_all_device_tests.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+function run() {
+    local FAILED_TESTS=()
+
+    # Tests directly relevant to HIDL infrustructure but aren't
+    # located in system/tools/hidl
+    local RELATED_RUNTIME_TESTS=(\
+        libhidl_test \
+    )
+
+    local RUN_TIME_TESTS=(\
+        libhidl-gen-utils_test \
+    )
+    RUN_TIME_TESTS+=(${RELATED_RUNTIME_TESTS[@]})
+
+    local SCRIPT_TESTS=(\
+        hidl_test\
+        hidl_test_java\
+    )
+
+    $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode -j \
+        ${RUN_TIME_TESTS[*]} ${SCRIPT_TESTS[*]} || return
+
+    adb sync || return
+
+    local BITNESS=("nativetest" "nativetest64")
+
+    for test in ${RUN_TIME_TESTS[@]}; do
+        for bits in ${BITNESS[@]}; do
+            echo $bits $test
+            adb shell /data/$bits/$test/$test ||
+                FAILED_TESTS+=("$bits:$test")
+        done
+    done
+
+    for test in ${SCRIPT_TESTS[@]}; do
+        echo $test
+        adb shell /data/nativetest64/$test ||
+            FAILED_TESTS+=("$test")
+    done
+
+    echo
+    echo ===== SUMMARY =====
+    echo
+    if [ ${#FAILED_TESTS[@]} -gt 0 ]; then
+        for failed in ${FAILED_TESTS[@]}; do
+            echo "FAILED TEST: $failed"
+        done
+    else
+        echo "SUCCESS"
+    fi
+}
+
+run
\ No newline at end of file