AI 144412: am: CL 144340 Added support to run native tests on the device.
  The tests name must start with 'test_'.
  Tests should return 0 on success, 1 on failure.
  * development/testrunner/test_defs.xml:
  Added new element to represent native tests.
  * development/testrunner/test_defs.py:
  Added handling of the new <test-native> element.
  The testsuite has new IsNative method.
  TestDefinition's iterator is ordered by test names.
  Added GetDescription() method to access the optional description.
  * development/testrunner/runtest.py:
  Print the description next to the test name if applicable
  (runtest_py -l)
  Added a _RunNativeTest method to run a test on the target, report
  the status and clean up the test after the run.
  Added
  Original author: niko

Automated import of CL 144412
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index 243da77..b727270 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -23,6 +23,7 @@
 import glob
 import optparse
 import os
+import re
 from sets import Set
 import sys
 
@@ -58,6 +59,7 @@
 
   def __init__(self):
     # disable logging of timestamp
+    self._root_path = android_build.GetTop()
     logger.SetTimestampLogging(False)  
 
   def _ProcessOptions(self):
@@ -137,8 +139,6 @@
     if self._options.verbose:
       logger.SetVerbose(True)
 
-    self._root_path = android_build.GetTop()
-
     self._known_tests = self._ReadTests()
 
     self._coverage_gen = coverage.CoverageGenerator(
@@ -172,7 +172,7 @@
     """Prints out set of defined tests."""
     print "The following tests are currently defined:"
     for test in self._known_tests:
-      print test.GetName()
+      print "%-15s %s" % (test.GetName(), test.GetDescription())
 
   def _DoBuild(self):
     logger.SilentLog("Building tests...")
@@ -261,6 +261,37 @@
         if coverage_file is not None:
           logger.Log("Coverage report generated at %s" % coverage_file)
 
+  def _RunNativeTest(self, test_suite):
+    """Run the provided *native* test suite.
+
+    The test_suite must contain a build path where the native test files are.
+    Each test's name must start with 'test_' and have a .cc or .cpp extension.
+    A successful test must return 0. Any other value will be considered
+    as an error.
+
+    Args:
+      test_suite: TestSuite to run
+    """
+    # find all test files, convert unicode names to ascii, take the basename
+    # and drop the .cc/.cpp  extension.
+    file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
+    file_list = []
+    for f in map(str, glob.glob(file_pattern)):
+      f = os.path.basename(f)
+      f = re.split(".[cp]+$", f)[0]
+      file_list.append(f)
+
+    for f in file_list:
+      full_path = "/system/bin/%s" % f
+
+      # Run
+      status = self._adb.SendShellCommand("%s >/dev/null 2>&1;echo -n $?" %
+                                          full_path)
+      logger.Log("%s... %s" % (f, status == "0" and "ok" or "failed"))
+
+      # Cleanup
+      self._adb.SendShellCommand("rm %s" % full_path)
+
   def RunTests(self):
     """Main entry method - executes the tests according to command line args."""
     try:
@@ -278,7 +309,10 @@
         self._DoBuild()
 
       for test_suite in self._GetTestsToRun():
-        self._RunTest(test_suite)
+        if test_suite.IsNative():
+          self._RunNativeTest(test_suite)
+        else:
+          self._RunTest(test_suite)
     except KeyboardInterrupt:
       logger.Log("Exiting...")
     except errors.AbortError:
diff --git a/testrunner/test_defs.py b/testrunner/test_defs.py
index 949ad6e..f7a435e 100644
--- a/testrunner/test_defs.py
+++ b/testrunner/test_defs.py
@@ -38,7 +38,14 @@
        [class=""]
        [coverage_target=""]
        [build_path=""]
-       [continuous]
+       [continuous=false]
+       [description=""]
+      />
+     <test-native
+       name=""
+       build_path=""
+       [continuous=false]
+       [description=""]
       />
      <test  ...
    </test-definitions>
@@ -48,13 +55,17 @@
 
   # tag/attribute constants
   _TEST_TAG_NAME = "test"
+  _TEST_NATIVE_TAG_NAME = "test-native"
 
   def __init__(self):
     # dictionary of test name to tests
     self._testname_map = {}
 
   def __iter__(self):
-    return iter(self._testname_map.values())
+    ordered_list = []
+    for k in sorted(self._testname_map):
+      ordered_list.append(self._testname_map[k])
+    return iter(ordered_list)
 
   def Parse(self, file_path):
     """Parse the test suite data from from given file path.
@@ -87,6 +98,12 @@
       test = self._ParseTestSuite(suite_element)
       self._AddTest(test)
 
+    suite_elements = doc.getElementsByTagName(self._TEST_NATIVE_TAG_NAME)
+
+    for suite_element in suite_elements:
+      test = self._ParseNativeTestSuite(suite_element)
+      self._AddTest(test)
+
   def _ParseTestSuite(self, suite_element):
     """Parse the suite element.
     
@@ -96,6 +113,17 @@
     test = TestSuite(suite_element)
     return test
 
+  def _ParseNativeTestSuite(self, suite_element):
+    """Parse the native test element.
+
+    Returns:
+      a TestSuite object, populated with parsed data
+    Raises:
+      ParseError if some required attribute is missing.
+    """
+    test = TestSuite(suite_element, native=True)
+    return test
+
   def _AddTest(self, test):
     """Adds a test to this TestManifest.
     
@@ -129,13 +157,27 @@
   _TARGET_ATTR = "coverage_target"
   _BUILD_ATTR = "build_path"
   _CONTINUOUS_ATTR = "continuous"
+  _DESCRIPTION_ATTR = "description"
 
   _DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
 
-  def __init__(self, suite_element):
-    """Populates this instance's data from given suite xml element."""
+  def __init__(self, suite_element, native=False):
+    """Populates this instance's data from given suite xml element.
+    Raises:
+      ParseError if some required attribute is missing.
+    """
+    self._native = native
     self._name = suite_element.getAttribute(self._NAME_ATTR)
-    self._package = suite_element.getAttribute(self._PKG_ATTR)
+
+    if self._native:
+      # For native runs, _BUILD_ATTR is required
+      if not suite_element.hasAttribute(self._BUILD_ATTR):
+        logger.Log("Error: %s is missing required build_path attribute" %
+                   self._name)
+        raise errors.ParseError
+    else:
+      self._package = suite_element.getAttribute(self._PKG_ATTR)
+
     if suite_element.hasAttribute(self._RUNNER_ATTR):
       self._runner = suite_element.getAttribute(self._RUNNER_ATTR)
     else:
@@ -156,6 +198,10 @@
       self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR)
     else:
       self._continuous = False
+    if suite_element.hasAttribute(self._DESCRIPTION_ATTR):
+      self._description = suite_element.getAttribute(self._DESCRIPTION_ATTR)
+    else:
+      self._description = ""
 
   def GetName(self):
     return self._name
@@ -184,6 +230,13 @@
     """Returns true if test is flagged as being part of the continuous tests"""  
     return self._continuous
 
+  def IsNative(self):
+    """Returns true if test is a native one."""
+    return self._native
+
+  def GetDescription(self):
+    return self._description
+
 def Parse(file_path):
   """Parses out a TestDefinitions from given path to xml file.
 
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index d186af4..9007a11 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -17,32 +17,65 @@
 <!-- 
 This file contains standard test definitions for the Android platform
           
-Tests are defined by <test> tags with the following attributes
+Java tests are defined by <test> tags and native ones (C/C++) are defined by
+<test-native> tags.
 
-name package [class runner build_path coverage_target continuous]
+JAVA/application tests:
+=======================
+  The java <test> element has the following attributes
 
-Where:
-name: Self-descriptive name used to uniquely identify the test
-build_path: File system path, relative to Android build root, to this package's
-   Android.mk file. If omitted, build/sync step for this test will be skipped
-package: Android application package that contains the tests
-class: Optional. Fully qualified Java test class to run. 
-runner: Fully qualified InstrumentationTestRunner to execute. If omitted, 
-   will default to android.test.InstrumentationTestRunner
-coverage_target: Build name of Android package this test targets - these targets
-   are defined in the coverage_targets.xml file.  Used as basis for code
-   coverage metrics. If omitted, code coverage will not be supported for this
-   test
-continuous: Optional boolean. Default is false. Set to true if tests are known
-   to be reliable, and should be included in a continuous test system. false if
-   they are under development.
+  name package [class runner build_path coverage_target continuous description]
 
-These attributes map to the following commands:  
-(if class is defined)
-    adb shell am instrument -w <package>/<runner>
-(else)
-    adb shell am instrument -w -e class <class> <package>/<runner>
+  Where:
+  name: Self-descriptive name used to uniquely identify the test
+  build_path: File system path, relative to Android build root, to this
+    package's Android.mk file. If omitted, build/sync step for this test will
+    be skipped.
+  package: Android application package that contains the tests
+  class: Optional. Fully qualified Java test class to run. 
+  runner: Fully qualified InstrumentationTestRunner to execute. If omitted, 
+     will default to android.test.InstrumentationTestRunner.
+  coverage_target: Build name of Android package this test targets - these
+    targets are defined in the coverage_targets.xml file.  Used as basis for
+    code coverage metrics. If omitted, code coverage will not be supported for
+    this test.
+  continuous: Optional boolean. Default is false. Set to true if tests are known
+    to be reliable, and should be included in a continuous test system. false if
+    they are under development.
 
+  description: Optional string. Default is empty. Short description (typically 
+     less than 60 characters) about this test.
+
+  These attributes map to the following commands:  
+  (if class is defined)
+      adb shell am instrument -w <package>/<runner>
+  (else)
+      adb shell am instrument -w -e class <class> <package>/<runner>
+
+Native tests:
+=============
+  The <test-native> element has the following attributes
+
+  name build_path [continuous description]
+
+  Where:
+  name: Self-descriptive name used to uniquely identify the test
+  build_path: File system path, relative to Android build root, to this
+     package's Android.mk file. By convention the name of a test starts with
+     'test_'.
+  continuous: Optional boolean. Default is false. Set to true if tests are known
+     to be reliable, and should be included in a continuous test system.
+     false if they are under development.
+  description: Optional string. Default is empty. Short description (typically
+     less than 60 characters) about this test.
+
+  These attributes map to the following commands:
+    make <build_path>/Android.mk
+    adb sync
+    for test_prog in <tests built>; do
+      adb shell "/system/bin/${test_prog} >/dev/null 2>&1;echo \$?"
+      adb shell "rm /system/bin/${test_prog}"
+    done
 -->
 
 <test-definitions version="1">
@@ -223,4 +256,10 @@
     coverage_target="Settings" />
 -->
 
+<!--  native tests  -->
+<test-native name="libstdcpp"
+    build_path="system/extras/tests/bionic/libstdc++"
+    description="Bionic libstdc++." />
+
+
 </test-definitions>