text: import datetime
  import os
  import sys
  from typing import Callable, Dict
  from junitparser import Failure, Error, Skipped, TestCase, TestSuite  # type: ignore
  from ...testpath import TestPath, FilePathNormalizer
  
  
  class CaseEvent:
      EVENT_TYPE = "case"
      TEST_SKIPPED = 2
      TEST_PASSED = 1
      TEST_FAILED = 0
  
      # function that computes TestPath from a test case
      # The 3rd argument is the report file path
      TestPathBuilder = Callable[[TestCase, TestSuite, str], TestPath]
  
      @staticmethod
      def default_path_builder(file_path_normalizer: FilePathNormalizer) -> TestPathBuilder:
          """
          Obtains a default TestPathBuilder that uses a base directory to relativize the file name
          """
  
          def f(case: TestCase, suite: TestSuite, report_file: str) -> TestPath:
              classname = case._elem.attrib.get(
                  "classname") or suite._elem.attrib.get("classname")
              filepath = case._elem.attrib.get(
                  "file") or suite._elem.attrib.get("filepath")
              if filepath:
                  filepath = file_path_normalizer.relativize(filepath)
  
              test_path = []
              if filepath:
                  test_path.append({"type": "file", "name": filepath})
              if classname:
                  test_path.append({"type": "class", "name": classname})
              if case.name:
                  test_path.append(
                      {"type": "testcase", "name": case._elem.attrib.get("name")})
              return test_path
  
          return f
  
      @classmethod
      def from_case_and_suite(cls, path_builder: TestPathBuilder, case: TestCase, suite: TestSuite, report_file: str, data: Dict = None) -> Dict:
          "Builds a JSON representation of CaseEvent from JUnitPaser objects"
  
          # TODO: reconsider the initial value of the status.
          status = CaseEvent.TEST_PASSED
          for r in case.result:
              if any(isinstance(r, s) for s in (Failure, Error)):
                  status = CaseEvent.TEST_FAILED
                  break
              elif isinstance(r, Skipped):
                  status = CaseEvent.TEST_SKIPPED
  
          def path_canonicalizer(test_path: TestPath) -> TestPath:
              if sys.platform == "win32":
                  for p in test_path:
                      p['name'] = p['name'].replace("\\", "/")
  
              return test_path
  
          return CaseEvent.create(
              path_canonicalizer(path_builder(
                  case, suite, report_file)), case.time, status,
              case._elem.attrib.get("system-out"),
              case._elem.attrib.get("system-err"),
              suite.timestamp, data)
  
      @classmethod
      def create(cls, test_path: TestPath, duration_secs: float, status,
                 stdout: str = None, stderr: str = None, timestamp: str = None, data: Dict = None) -> Dict:
          """
          Builds a JSON representation of CaseEvent from arbitrary set of values
  
          status:    TEST_FAILED or TEST_PASSED
          timestamp: ISO-8601 formatted date
          data:      arbitrary data to be submitted to the server. reserved for future enhancement.
          """
          return {
              "type": cls.EVENT_TYPE,
              "testPath": test_path,
              "duration": duration_secs,
              "status": status,
              "stdout": stdout or "",
              "stderr": stderr or "",
              "created_at": timestamp or datetime.datetime.now(datetime.timezone.utc).isoformat(),
              "data": data
          }
  