diff --git a/mod_test/nicediff/diff.py b/mod_test/nicediff/diff.py
index b359d499..0b3cfa1c 100644
--- a/mod_test/nicediff/diff.py
+++ b/mod_test/nicediff/diff.py
@@ -1,3 +1,4 @@
+import difflib
import html
import re
from typing import Any, List, Optional, Tuple, Union
@@ -122,11 +123,11 @@ def create_diff_entries(suffix_id: str, id_name: str, events: List[List[object]]
def get_html_diff(test_correct_lines: List[str], test_res_lines: List[str], to_view: bool = True) -> str:
- """Return generated difference in HTML formatted table."""
+ """Return generated difference in HTML formatted table using smart sequence matching."""
# variable to keep count of diff lines noted
number_of_noted_diff_lines = 0
- html = """
+ html_out = """
| n° |
@@ -138,81 +139,84 @@ def get_html_diff(test_correct_lines: List[str], test_res_lines: List[str], to_v
"""
- res_len = len(test_res_lines)
- correct_len = len(test_correct_lines)
-
- if res_len <= correct_len:
- use = res_len
- till = correct_len
-
- else:
- use = correct_len
- till = res_len
-
- for line in range(use):
+ sm = difflib.SequenceMatcher(None, test_res_lines, test_correct_lines)
+
+ for tag, i1, i2, j1, j2 in sm.get_opcodes():
if to_view and number_of_noted_diff_lines >= MAX_NUMBER_OF_LINES_TO_VIEW:
break
-
- if test_correct_lines[line] == test_res_lines[line]:
+
+ if tag == 'equal':
continue
- html += """
+
+ if tag == 'replace':
+ max_len = max(i2 - i1, j2 - j1)
+ for k in range(max_len):
+ if to_view and number_of_noted_diff_lines >= MAX_NUMBER_OF_LINES_TO_VIEW:
+ break
+
+ html_out += """
"""
- actual, expected = _process(test_res_lines[line], test_correct_lines[line], suffix_id=str(line))
-
- html += f"""
+
+ res_idx = i1 + k
+ corr_idx = j1 + k
+
+ res_line = test_res_lines[res_idx] if res_idx < i2 else " "
+ corr_line = test_correct_lines[corr_idx] if corr_idx < j2 else " "
+ line_display = str(res_idx + 1) if res_idx < i2 else ""
+
+ actual, expected = _process(res_line, corr_line, suffix_id=str(res_idx if res_idx < i2 else corr_idx))
+
+ html_out += f"""
- | {line + 1} |
+ {line_display} |
{actual} |
|
{expected} |
"""
- html += """
+ html_out += """
"""
+ number_of_noted_diff_lines += 1
- # increase noted diff line by one
- number_of_noted_diff_lines += 1
-
- # processing remaining lines
- for line in range(use, till):
-
- # stop at 50 lines if test-data for viewing
- if to_view and number_of_noted_diff_lines >= MAX_NUMBER_OF_LINES_TO_VIEW:
- break
-
- html += """
+ elif tag == 'delete':
+ for k in range(i1, i2):
+ if to_view and number_of_noted_diff_lines >= MAX_NUMBER_OF_LINES_TO_VIEW:
+ break
+ html_out += """
"""
-
- if till == res_len:
- output, _ = _process(test_res_lines[line], " ", suffix_id=str(line))
- html += f"""
-
- | {line + 1} |
- {output} |
-
-
- |
- |
-
- """
- else:
- _, output = _process(" ", test_correct_lines[line], suffix_id=str(line))
- html += f"""
-
- | {line + 1} |
- |
-
-
- |
- {output} |
-
- """
-
- html += """
+ output, _ = _process(test_res_lines[k], " ", suffix_id=str(k))
+ html_out += f"""
+
+ | {k + 1} |
+ {output} |
+
+
+ |
+ |
+
"""
+ html_out += """
+
"""
+ number_of_noted_diff_lines += 1
+
+ elif tag == 'insert':
+ for k in range(j1, j2):
+ if to_view and number_of_noted_diff_lines >= MAX_NUMBER_OF_LINES_TO_VIEW:
+ break
+ html_out += """
"""
+ _, output = _process(" ", test_correct_lines[k], suffix_id=str(k))
+ html_out += f"""
+
+ |
+ |
+
+
+ |
+ {output} |
+
"""
+ html_out += """
+
"""
+ number_of_noted_diff_lines += 1
- # increase noted diff line by one
- number_of_noted_diff_lines += 1
-
- return html
+ return html_out