mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-20 01:26:14 +00:00
View parity mismatches as diff (#98)
This commit is contained in:
@@ -3,5 +3,6 @@ certs/
|
||||
default/
|
||||
dns/
|
||||
interactions/
|
||||
parity_mismatches/
|
||||
patterns.json
|
||||
settings.json
|
||||
|
||||
@@ -131,4 +131,15 @@ func TestStaticWeb(t *testing.T) {
|
||||
!strings.Contains(res.Header.Get("Content-Type"), "text/javascript") {
|
||||
t.Errorf("JS: Expected javascript content type, got %s", res.Header.Get("Content-Type"))
|
||||
}
|
||||
|
||||
// 3. Test diff.min.js
|
||||
res, err = http.Get(ts.URL + "/web/js/diff.min.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Errorf("Diff JS: Expected status OK, got %v", res.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,7 @@ func (s *Server) performMirror(r *http.Request) *mirrorResponseRecorder {
|
||||
return recorder
|
||||
}
|
||||
|
||||
// checkParity compares local response with upstream response.
|
||||
func (s *Server) checkParity(req *http.Request, local, upstream *mirrorResponseRecorder) {
|
||||
if local.status == 0 {
|
||||
local.status = 200
|
||||
@@ -324,7 +325,10 @@ func (s *Server) checkParity(req *http.Request, local, upstream *mirrorResponseR
|
||||
}
|
||||
|
||||
// Basic body comparison (could be improved with XML semantic diff)
|
||||
if !bytes.Equal(local.body.Bytes(), upstream.body.Bytes()) {
|
||||
localBody := local.body.Bytes()
|
||||
upstreamBody := upstream.body.Bytes()
|
||||
|
||||
if !bytes.Equal(localBody, upstreamBody) {
|
||||
mismatch = true
|
||||
|
||||
reasons = append(reasons, "Body content mismatch")
|
||||
|
||||
@@ -7,7 +7,25 @@ button { padding: 5px 10px; cursor: pointer; }
|
||||
.summary-box { margin-top: 20px; padding: 15px; border: 1px solid #aaa; background-color: #f9f9f9; }
|
||||
pre { background-color: #eee; padding: 10px; overflow-x: auto; font-size: 12px; }
|
||||
.diff-container { display: flex; gap: 10px; }
|
||||
.diff-pane { flex: 1; min-width: 0; }
|
||||
.diff-pane pre {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px;
|
||||
font-size: 0.85em;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.diff-added {
|
||||
background-color: #e6ffed !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.diff-removed {
|
||||
background-color: #ffeef0 !important;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.config-header { font-weight: bold; margin-bottom: 5px; display: block; }
|
||||
|
||||
/* Tabs */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<title>AfterTouch (SoundTouch Toolkit)</title>
|
||||
<link rel="icon" href="/media/favicon-braille.svg" type="image/svg+xml"/>
|
||||
<link rel="stylesheet" href="/web/css/style.css"/>
|
||||
<script src="/web/js/diff.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AfterTouch</h1>
|
||||
@@ -1405,13 +1406,6 @@
|
||||
></div>
|
||||
<pre
|
||||
id="diff-local-body"
|
||||
style="
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px;
|
||||
font-size: 0.85em;
|
||||
overflow-x: auto;
|
||||
"
|
||||
></pre>
|
||||
</div>
|
||||
<div class="diff-pane">
|
||||
@@ -1430,13 +1424,6 @@
|
||||
></div>
|
||||
<pre
|
||||
id="diff-upstream-body"
|
||||
style="
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px;
|
||||
font-size: 0.85em;
|
||||
overflow-x: auto;
|
||||
"
|
||||
></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -1021,8 +1021,39 @@ function viewParityMismatch(m) {
|
||||
document.getElementById("diff-local-meta").innerText = `Status: ${m.local.status}`;
|
||||
document.getElementById("diff-upstream-meta").innerText = `Status: ${m.upstream.status}`;
|
||||
|
||||
document.getElementById("diff-local-body").innerText = formatXML(m.local.body,);
|
||||
document.getElementById("diff-upstream-body").innerText = formatXML(m.upstream.body,);
|
||||
const localCT = (m.local.headers && m.local.headers["Content-Type"]) ? m.local.headers["Content-Type"][0] : "";
|
||||
const upstreamCT = (m.upstream.headers && m.upstream.headers["Content-Type"]) ? m.upstream.headers["Content-Type"][0] : "";
|
||||
|
||||
const localBody = formatBody(m.local.body, localCT);
|
||||
const upstreamBody = formatBody(m.upstream.body, upstreamCT);
|
||||
|
||||
if (typeof Diff !== 'undefined') {
|
||||
const diff = Diff.diffChars(localBody, upstreamBody);
|
||||
const localEl = document.getElementById("diff-local-body");
|
||||
const upstreamEl = document.getElementById("diff-upstream-body");
|
||||
|
||||
localEl.innerHTML = "";
|
||||
upstreamEl.innerHTML = "";
|
||||
|
||||
diff.forEach((part) => {
|
||||
const span = document.createElement('span');
|
||||
if (part.added) {
|
||||
span.className = 'diff-added';
|
||||
span.innerText = part.value;
|
||||
upstreamEl.appendChild(span);
|
||||
} else if (part.removed) {
|
||||
span.className = 'diff-removed';
|
||||
span.innerText = part.value;
|
||||
localEl.appendChild(span);
|
||||
} else {
|
||||
localEl.appendChild(document.createTextNode(part.value));
|
||||
upstreamEl.appendChild(document.createTextNode(part.value));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
document.getElementById("diff-local-body").innerText = localBody;
|
||||
document.getElementById("diff-upstream-body").innerText = upstreamBody;
|
||||
}
|
||||
|
||||
document.getElementById("parity-diff-view").style.display = "block";
|
||||
document
|
||||
@@ -1030,6 +1061,28 @@ function viewParityMismatch(m) {
|
||||
.scrollIntoView({behavior: "smooth"});
|
||||
}
|
||||
|
||||
function formatBody(body, contentType) {
|
||||
if (!body) return "";
|
||||
contentType = (contentType || "").toLowerCase();
|
||||
if (contentType.includes("json")) {
|
||||
return formatJSON(body);
|
||||
}
|
||||
if (contentType.includes("xml")) {
|
||||
return formatXML(body);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
function formatJSON(json) {
|
||||
if (!json) return "";
|
||||
try {
|
||||
const obj = typeof json === "string" ? JSON.parse(json) : json;
|
||||
return JSON.stringify(obj, null, 2);
|
||||
} catch (e) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
function formatXML(xml) {
|
||||
if (!xml) return "";
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user