Repository: ARMmbed/greentea

Issue:
mbedgt crash with float division by zero
Hi

Here is my command:
mbedgt -V -v -t NUCLEO_F401RE-ARM,NUCLEO_F401RE-GCC_ARM,NUCLEO_F401RE-IAR,NUCLEO_F410RB-ARM,NUCLEO_F410RB-GCC_ARM,NUCLEO_F410RB-IAR,NUCLEO_F411RE-ARM,NUCLEO_F411RE-GCC_ARM,NUCLEO_F411RE-IAR --report-html=/c/xxx.html

It has crashed:

...
mbedgt: all tests finished!
mbedgt: shuffle seed: 0.3680156551
mbedgt: exporting to HTML file 
mbedgt: unexpected error:
	float division by zero
Traceback (most recent call last):
  File "C:\Python27\Scripts\mbedgt-script.py", line 11, in <module>
    load_entry_point('mbed-greentea==1.2.6', 'console_scripts', 'mbedgt')()
  File "c:\python27\lib\site-packages\mbed_greentea\mbed_greentea_cli.py", line 401, in main
    cli_ret = main_cli(opts, args)
  File "c:\python27\lib\site-packages\mbed_greentea\mbed_greentea_cli.py", line 1050, in main_cli
    html_report = exporter_html(test_report)
  File "c:\python27\lib\site-packages\mbed_greentea\mbed_report_api.py", line 747, in exporter_html
    int((test_results['single_test_passes']*100.0)/test_results['single_test_count']),
ZeroDivisionError: float division by zero



Discussion:

Patch:
diff --git a/mbed_greentea/mbed_report_api.py b/mbed_greentea/mbed_report_api.py
index da3f0d9..82acb5c 100644
--- a/mbed_greentea/mbed_report_api.py
+++ b/mbed_greentea/mbed_report_api.py
@@ -38,6 +38,13 @@ def exporter_json(test_result_ext, test_suite_properties=None):
     @details This is a machine friendly format
     """
     import json
+    for target in test_result_ext.values():
+        for suite in target.values():
+            try:
+                suite["single_test_output"] = suite["single_test_output"]\
+                                              .decode("unicode_escape")
+            except KeyError:
+                pass
     return json.dumps(test_result_ext, indent=4)
 
 
@@ -211,7 +218,10 @@ def exporter_testcase_junit(test_result_ext, test_suite_properties=None):
                 test_cases.append(tc)
 
             ts_name = target_name
-            test_build_properties = test_suite_properties[target_name] if target_name in test_suite_properties else None
+            if test_suite_properties and target_name in test_suite_properties:
+                test_build_properties = test_suite_properties[target_name] 
+            else:
+                test_build_properties = None
             ts = TestSuite(ts_name, test_cases, properties=test_build_properties)
             test_suites.append(ts)
 
@@ -584,7 +594,9 @@ def get_result_overlay_dropdowns(result_div_id, test_results):
     result_output_div_id = "%s_output" % result_div_id
     result_output_dropdown = get_dropdown_html(result_output_div_id,
                                                "Test Output",
-                                               test_results['single_test_output'].rstrip("\n"),
+                                               test_results['single_test_output']
+                                               .decode("unicode-escape")
+                                               .rstrip("\n"),
                                                output_text=True)
 
     # Add a dropdown for the testcases if they are present
@@ -740,10 +752,14 @@ def exporter_html(test_result_ext, test_suite_properties=None):
                     test_results['single_test_count'] += 1
 
                 result_class = get_result_colour_class(test_results['single_test_result'])
+                try:
+                    percent_pass = int((test_results['single_test_passes']*100.0)/test_results['single_test_count'])
+                except ZeroDivisionError:
+                    percent_pass = 100
                 this_row += result_cell_template % (result_class,
                                                     result_div_id,
                                                     test_results['single_test_result'],
-                                                    int((test_results['single_test_passes']*100.0)/test_results['single_test_count']),
+                                                    percent_pass,
                                                     test_results['single_test_passes'],
                                                     test_results['single_test_count'],
                                                     result_overlay)


Test patch:
diff --git a/test/report_api.py b/test/report_api.py
new file mode 100644
index 0000000..122e26e
--- /dev/null
+++ b/test/report_api.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+"""
+mbed SDK
+Copyright (c) 2017 ARM Limited
+
+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.
+"""
+
+import unittest
+from mock import patch
+
+from mbed_greentea.mbed_report_api import exporter_html, \
+    exporter_memory_metrics_csv, exporter_testcase_junit, \
+    exporter_testcase_text, exporter_text, exporter_json
+
+
+class ReportEmitting(unittest.TestCase):
+
+
+    report_fns =  [exporter_html, exporter_memory_metrics_csv,
+                   exporter_testcase_junit, exporter_testcase_text,
+                   exporter_text, exporter_json]
+    def test_report_zero_tests(self):
+        test_data = {}
+        for report_fn in self.report_fns:
+            report_fn(test_data)
+
+    def test_report_zero_testcases(self):
+        test_data = {
+            'k64f-gcc_arm': {
+                'garbage_test_suite' :{
+                    u'single_test_result': u'NOT_RAN',
+                    u'elapsed_time': 0.0,
+                    u'build_path': u'N/A',
+                    u'build_path_abs': u'N/A',
+                    u'copy_method': u'N/A',
+                    u'image_path': u'N/A',
+                    u'single_test_output': b'N/A',
+                    u'platform_name': u'k64f',
+                    u'test_bin_name': u'N/A',
+                    u'testcase_result': {},
+                }
+            }
+        }
+        for report_fn in self.report_fns:
+            report_fn(test_data)