From b2f3b566c0c0edd41b0314fcbf516a3d7876e14b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 29 Jan 2023 17:54:14 +0100 Subject: Fix concurrent edit, tests --- diff.cpp | 12 +++++++++--- diff.h | 2 ++ html/whiteboard.js | 19 ++++++++++++++++++- tests/test-diff.cpp | 32 ++++++++++++++++++++++++++++++++ whiteboard.cpp | 12 +++++++----- 5 files changed, 68 insertions(+), 9 deletions(-) diff --git a/diff.cpp b/diff.cpp index ea9b04e..85d3167 100644 --- a/diff.cpp +++ b/diff.cpp @@ -21,9 +21,10 @@ std::string Diff::apply(const std::string& old_version) const { std::string result{old_version}; - result.erase(m_pos0, m_pos1 - m_pos0); - - result.insert(m_pos0, m_data); + if (m_pos0 <= m_pos1 && m_pos1 <= old_version.size()) { + result.erase(m_pos0, m_pos1 - m_pos0); + result.insert(m_pos0, m_data); + } return result; } @@ -143,6 +144,11 @@ void Diff::create(const std::string& xml) create(ptree); } +bool Diff::empty() const +{ + return m_pos0 == m_pos1 && m_data.empty(); +} + boost::property_tree::ptree Diff::get_structure() const { pt::ptree ptree; diff --git a/diff.h b/diff.h index 09d0936..5c2c335 100644 --- a/diff.h +++ b/diff.h @@ -19,6 +19,8 @@ public: std::string apply(const std::string& old_version) const; + bool empty() const; + boost::property_tree::ptree get_structure() const; std::string get_xml() const; diff --git a/html/whiteboard.js b/html/whiteboard.js index a6dc089..b11dc96 100644 --- a/html/whiteboard.js +++ b/html/whiteboard.js @@ -4,6 +4,7 @@ function init() { } var revision; +var modify_in_progress = 0; var baseline = ""; // data contents relating to revision, acknowledged by server var baseline_candidate = ""; // will become baseline, after ack by server @@ -51,7 +52,7 @@ function on_getfile(data, rev, pos) function on_getdiff(diff, rev, pos) { if (rev != revision + 1) - alert("Revision skipped: " + rev + " after " + revision); + console.log("Revision skipped on diff receive: " + rev + " after " + revision); var board = document.getElementById("board"); @@ -95,8 +96,12 @@ function on_version(version) function on_modify_ack(rev) { + if (rev != revision + 1) + console.log("Revision skipped on published local change: " + rev + " after " + revision); + revision = rev; baseline = baseline_candidate; + modify_in_progress = 0; } function on_message(e) { @@ -228,6 +233,13 @@ function redirect_to_new_page() // local change done function on_input() { + if (modify_in_progress == 1) { + console.log("Deferring on_input handler by 100ms"); + setTimeout(function(){on_input();}, 100); // re-try after 100ms + return; + } + modify_in_progress = 1; + var parser = new DOMParser(); var xmlDocument = parser.parseFromString("", "text/xml"); @@ -243,6 +255,11 @@ function on_input() baseline_candidate = document.getElementById("board").value; + if (baseline == baseline_candidate) { + modify_in_progress = 0; + return; + } + var revisionElement = xmlDocument.createElement("baserev"); revisionElement.appendChild(document.createTextNode(revision)); requestElement.appendChild(revisionElement); diff --git a/tests/test-diff.cpp b/tests/test-diff.cpp index 1625716..d09c58e 100644 --- a/tests/test-diff.cpp +++ b/tests/test-diff.cpp @@ -147,6 +147,38 @@ TEST_F(DiffTest, constructor) Diff d{"baaaab", "baab"}; EXPECT_EQ(d.get_xml(), "13"); } + { + Diff d{"baaaab", "baaaaaaab"}; + EXPECT_EQ(d.get_xml(), "11aaa"); + } +} + +TEST_F(DiffTest, empty) +{ + { + Diff d; + EXPECT_TRUE(d.empty()); + } + + { + Diff d{"13"}; + EXPECT_FALSE(d.empty()); + } + + { + Diff d{"11"}; + EXPECT_TRUE(d.empty()); + } + + { + Diff d{"11abc"}; + EXPECT_FALSE(d.empty()); + } + + { + Diff d{"00"}; + EXPECT_TRUE(d.empty()); + } } TEST_F(DiffTest, diff_create) diff --git a/whiteboard.cpp b/whiteboard.cpp index fcfdca8..8736726 100644 --- a/whiteboard.cpp +++ b/whiteboard.cpp @@ -167,12 +167,14 @@ std::string Whiteboard::handle_request(Whiteboard::connection& c, const std::str pt::ptree ptree; ptree.put_child("diff", xml.get_child("request.diff")); Diff d{ptree}; - std::string data {m_storage->getDocument(id)}; - data = d.apply(data); + if (!d.empty()) { + std::string data {m_storage->getDocument(id)}; + data = d.apply(data); - m_storage->setDocument(id, data); - m_registry.setId(c, id); - notify_other_connections_diff(c, id, d); + m_storage->setDocument(id, data); + m_registry.setId(c, id); + notify_other_connections_diff(c, id, d); + } int pos {xml.get("request.pos")}; if (m_storage->getCursorPos(id) != pos) { -- cgit v1.2.3