diff --git a/monitoring/uss_qualifier/reports/sequence_view.py b/monitoring/uss_qualifier/reports/sequence_view.py
index 40c19c774d..cac51471c7 100644
--- a/monitoring/uss_qualifier/reports/sequence_view.py
+++ b/monitoring/uss_qualifier/reports/sequence_view.py
@@ -3,6 +3,7 @@
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
+import html
from typing import List, Dict, Optional, Iterator
from implicitdict import ImplicitDict
@@ -190,7 +191,9 @@ def append_notes(new_notes):
events.append(
Event(
note=NoteEvent(
- key=k, message=v.message, timestamp=v.timestamp.datetime
+ key=html.escape(k),
+ message=html.escape(v.message),
+ timestamp=v.timestamp.datetime,
),
event_index=event_index,
)
@@ -270,8 +273,8 @@ def append_notes(new_notes):
events.append(
Event(
note=NoteEvent(
- key=key,
- message=note.message,
+ key=html.escape(key),
+ message=html.escape(note.message),
timestamp=note.timestamp.datetime,
)
)
diff --git a/monitoring/uss_qualifier/reports/templates/sequence_view/scenario.html b/monitoring/uss_qualifier/reports/templates/sequence_view/scenario.html
index c2fafc2f73..8a14ea7946 100644
--- a/monitoring/uss_qualifier/reports/templates/sequence_view/scenario.html
+++ b/monitoring/uss_qualifier/reports/templates/sequence_view/scenario.html
@@ -155,7 +155,7 @@
{{ test_scenario.type }}
{% elif event.type == EventType.Note %}
📓 |
- {{ event.note.key }}: {{ event.note.value }}
+ {{ event.note.key }} : {{ event.note.message }}
|
{% else %}
??? | Render error: unknown EventType '{{ event.type }}' |
diff --git a/monitoring/uss_qualifier/reports/tested_requirements.py b/monitoring/uss_qualifier/reports/tested_requirements.py
index 6749d2f4ae..23e97e6dec 100644
--- a/monitoring/uss_qualifier/reports/tested_requirements.py
+++ b/monitoring/uss_qualifier/reports/tested_requirements.py
@@ -1,5 +1,7 @@
import os
from dataclasses import dataclass
+import re
+from functools import cmp_to_key
from typing import List, Union, Dict, Set, Optional
from implicitdict import ImplicitDict, StringBasedDateTime
@@ -265,10 +267,70 @@ def print_datetime(t: Optional[StringBasedDateTime]) -> Optional[str]:
)
+def _split_strings_numbers(s: str) -> List[Union[int, str]]:
+ digits = "0123456789"
+ current_number = ""
+ current_string = ""
+ parts = []
+ for si in s:
+ if si in digits:
+ if current_string:
+ parts.append(current_string)
+ current_string = ""
+ current_number += si
+ else:
+ if current_number:
+ parts.append(int(current_number))
+ current_number = ""
+ current_string += si
+ if current_number:
+ parts.append(int(current_number))
+ elif current_string:
+ parts.append(current_string)
+ return parts
+
+
+def _requirement_id_parts(req_id: str):
+ old_parts = req_id.split(".")
+ parts = []
+ for p in old_parts:
+ parts.extend(p.split(","))
+ old_parts = parts
+ parts = []
+ for p in old_parts:
+ parts.extend(_split_strings_numbers(p))
+ return parts
+
+
+def _compare_requirement_ids(r1: TestedRequirement, r2: TestedRequirement) -> int:
+ parts1 = _requirement_id_parts(r1.id)
+ parts2 = _requirement_id_parts(r2.id)
+ i = 0
+ while i < min(len(parts1), len(parts2)):
+ p1 = parts1[i]
+ p2 = parts2[i]
+ if p1 == p2:
+ i += 1
+ continue
+ if isinstance(p1, int):
+ if isinstance(p2, int):
+ return -1 if p1 < p2 else 1
+ else:
+ return -1
+ else:
+ if isinstance(p2, int):
+ return 1
+ else:
+ return -1 if p1 < p2 else 1
+ if i == len(parts1) and i == len(parts2):
+ return 0
+ return -1 if len(parts1) < len(parts2) else 1
+
+
def _sort_breakdown(breakdown: TestedBreakdown) -> None:
breakdown.packages.sort(key=lambda p: p.id)
for package in breakdown.packages:
- package.requirements.sort(key=lambda r: r.id)
+ package.requirements.sort(key=cmp_to_key(_compare_requirement_ids))
for requirement in package.requirements:
requirement.scenarios.sort(key=lambda s: s.name)