Move script outputs handling to collect_from_script

To simplify the logic, `collect_from_script` should take
the responsiblity to parse script outputs to suite name
and test case description.

Also define new Error class ScriptOutputError for
error handling.

Signed-off-by: Pengyu Lv <pengyu.lv@arm.com>
diff --git a/tests/scripts/check_test_cases.py b/tests/scripts/check_test_cases.py
index 5cac960..39bf73c 100755
--- a/tests/scripts/check_test_cases.py
+++ b/tests/scripts/check_test_cases.py
@@ -16,6 +16,23 @@
 import subprocess
 import sys
 
+class ScriptOutputError(ValueError):
+    """A kind of ValueError that indicates we found
+    the script doesn't list test cases in an expected
+    pattern.
+    """
+
+    @property
+    def script_name(self):
+        return super().args[0]
+
+    @property
+    def idx(self):
+        return super().args[1]
+
+    @property
+    def line(self):
+        return super().args[2]
 
 class Results:
     """Store file and line information about errors or warnings in test suites."""
@@ -86,19 +103,27 @@
                                            data_file_name, line_number, line)
                 in_paragraph = True
 
-    def collect_from_script(self, file_name):
+    def collect_from_script(self, script_name):
         """Collect the test cases in a script by calling its listing test cases
 option"""
         descriptions = self.new_per_file_state() # pylint: disable=assignment-from-none
-        listed = subprocess.check_output(['sh', file_name, '--list-test-cases'])
+        listed = subprocess.check_output(['sh', script_name, '--list-test-cases'])
         # Assume test file is responsible for printing identical format of
         # test case description between --list-test-cases and its OUTCOME.CSV
         #
         # idx indicates the number of test case since there is no line number
         # in the script for each test case.
-        for idx, description in enumerate(listed.splitlines()):
+        for idx, line in enumerate(listed.splitlines()):
+            # We are expecting the script to list the test cases in
+            # `<suite_name>;<description>` pattern.
+            script_outputs = line.split(b';', 1)
+            if len(script_outputs) == 2:
+                suite_name, description = script_outputs
+            else:
+                raise ScriptOutputError(script_name, idx, line.decode("utf-8"))
+
             self.process_test_case(descriptions,
-                                   file_name,
+                                   suite_name.decode('utf-8'),
                                    idx,
                                    description.rstrip())
 
@@ -137,14 +162,8 @@
     def process_test_case(self, _per_file_state,
                           file_name, _line_number, description):
         """Record an available test case."""
-        if file_name.endswith('.data'):
-            base_name = re.sub(r'\.[^.]*$', '', re.sub(r'.*/', '', file_name))
-            key = ';'.join([base_name, description.decode('utf-8')])
-        else:
-            # For test cases defined in scripts (i.e. ssl-op.sh and compat.sh),
-            # we need the script to list the suite name, and use the outputs
-            # as keys directly.
-            key = description.decode('utf-8')
+        base_name = re.sub(r'\.[^.]*$', '', re.sub(r'.*/', '', file_name))
+        key = ';'.join([base_name, description.decode('utf-8')])
         self.descriptions.add(key)
 
 def collect_available_test_cases():
@@ -172,15 +191,6 @@
         """Check test case descriptions for errors."""
         results = self.results
         seen = per_file_state
-        if not file_name.endswith('.data'):
-            script_output = description.split(b';', 1)
-            if len(script_output) == 2:
-                description = script_output[1]
-            else:
-                results.error(file_name, line_number,
-                              '"{}" should be listed in '
-                              '"<suite>;<description>" format',
-                              description.decode('ascii'))
         if description in seen:
             results.error(file_name, line_number,
                           'Duplicate description (also line {})',
@@ -217,7 +227,12 @@
         return
     results = Results(options)
     checker = DescriptionChecker(results)
-    checker.walk_all()
+    try:
+        checker.walk_all()
+    except ScriptOutputError as e:
+        results.error(e.script_name, e.idx,
+                      '"{}" should be listed as "<suite_name>;<description>"',
+                      e.line)
     if (results.warnings or results.errors) and not options.quiet:
         sys.stderr.write('{}: {} errors, {} warnings\n'
                          .format(sys.argv[0], results.errors, results.warnings))