[LLDB][SBProgress] Add a finalize method (#128966)
This patch adds a finalize method which destroys the underlying RAII SBProgress. My primary motivation for this is so I can write better tests that are non-flaky, but after discussing with @clayborg in my DAP message improvement patch (#124648) this is probably an essential API despite that I originally argued it wasn't.
This commit is contained in:
@@ -12,3 +12,14 @@ and will always send an initial progress update, updates when
|
||||
Progress::Increment() is called, and also will make sure that a progress
|
||||
completed update is reported even if the user doesn't explicitly cause one
|
||||
to be sent.") lldb::SBProgress;
|
||||
|
||||
%feature("docstring",
|
||||
"Finalize the SBProgress, which will cause a progress end event to be emitted. This
|
||||
happens automatically when the SBProcess object is destroyed, but can be done explicitly
|
||||
with Finalize to avoid having to rely on the language semantics for destruction.
|
||||
|
||||
Note once finalized, no further increments will be processed.") lldb::SBProgress::Finalize;
|
||||
|
||||
%feature("docstring",
|
||||
"Increment the progress by a given number of units, optionally with a message. Not all progress events are guaraunteed
|
||||
to be sent, but incrementing to the total will always guarauntee a progress end event being sent.") lldb::SBProcess::Increment;
|
||||
|
||||
@@ -59,6 +59,11 @@ public:
|
||||
|
||||
void Increment(uint64_t amount, const char *description = nullptr);
|
||||
|
||||
/// Explicitly finalize an SBProgress, this can be used to terminate a
|
||||
/// progress on command instead of waiting for a garbage collection or other
|
||||
/// RAII to destroy the contained progress object.
|
||||
void Finalize();
|
||||
|
||||
protected:
|
||||
lldb_private::Progress &ref() const;
|
||||
|
||||
|
||||
@@ -40,10 +40,22 @@ SBProgress::~SBProgress() = default;
|
||||
void SBProgress::Increment(uint64_t amount, const char *description) {
|
||||
LLDB_INSTRUMENT_VA(amount, description);
|
||||
|
||||
if (!m_opaque_up)
|
||||
return;
|
||||
|
||||
std::optional<std::string> description_opt;
|
||||
if (description && description[0])
|
||||
description_opt = description;
|
||||
m_opaque_up->Increment(amount, std::move(description_opt));
|
||||
}
|
||||
|
||||
void SBProgress::Finalize() {
|
||||
// The lldb_private::Progress object is designed to be RAII and send the end
|
||||
// progress event when it gets destroyed. So force our contained object to be
|
||||
// destroyed and send the progress end event. Clearing this object also allows
|
||||
// all other methods to quickly return without doing any work if they are
|
||||
// called after this method.
|
||||
m_opaque_up.reset();
|
||||
}
|
||||
|
||||
lldb_private::Progress &SBProgress::ref() const { return *m_opaque_up; }
|
||||
|
||||
@@ -5,35 +5,6 @@ from lldbsuite.test.lldbtest import *
|
||||
|
||||
|
||||
class SBProgressTestCase(TestBase):
|
||||
def test_with_external_bit_set(self):
|
||||
"""Test SBProgress events are listened to when the external bit is set."""
|
||||
|
||||
progress = lldb.SBProgress("Test SBProgress", "Test progress", self.dbg)
|
||||
listener = lldb.SBListener("Test listener")
|
||||
broadcaster = self.dbg.GetBroadcaster()
|
||||
broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgress)
|
||||
event = lldb.SBEvent()
|
||||
|
||||
expected_string = "Test progress first increment"
|
||||
progress.Increment(1, expected_string)
|
||||
self.assertTrue(listener.PeekAtNextEvent(event))
|
||||
stream = lldb.SBStream()
|
||||
event.GetDescription(stream)
|
||||
self.assertIn(expected_string, stream.GetData())
|
||||
|
||||
def test_without_external_bit_set(self):
|
||||
"""Test SBProgress events are not listened to on the internal progress bit."""
|
||||
|
||||
progress = lldb.SBProgress("Test SBProgress", "Test progress", self.dbg)
|
||||
listener = lldb.SBListener("Test listener")
|
||||
broadcaster = self.dbg.GetBroadcaster()
|
||||
broadcaster.AddListener(listener, lldb.eBroadcastBitProgress)
|
||||
event = lldb.SBEvent()
|
||||
|
||||
expected_string = "Test progress first increment"
|
||||
progress.Increment(1, expected_string)
|
||||
self.assertFalse(listener.PeekAtNextEvent(event))
|
||||
|
||||
def test_with_external_bit_set(self):
|
||||
"""Test SBProgress can handle null events."""
|
||||
|
||||
@@ -65,3 +36,33 @@ class SBProgressTestCase(TestBase):
|
||||
stream = lldb.SBStream()
|
||||
event.GetDescription(stream)
|
||||
self.assertIn("Step 3", stream.GetData())
|
||||
|
||||
def test_progress_finalize_non_deterministic_progress(self):
|
||||
"""Test SBProgress finalize sends the progressEnd event"""
|
||||
|
||||
progress = lldb.SBProgress("Test SBProgress", "Test finalize", self.dbg)
|
||||
listener = lldb.SBListener("Test listener")
|
||||
broadcaster = self.dbg.GetBroadcaster()
|
||||
broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgressCategory)
|
||||
event = lldb.SBEvent()
|
||||
progress.Finalize()
|
||||
self.assertTrue(listener.WaitForEvent(5, event))
|
||||
stream = lldb.SBStream()
|
||||
event.GetDescription(stream)
|
||||
self.assertIn("type = end", stream.GetData())
|
||||
|
||||
def test_progress_finalize_deterministic_progress(self):
|
||||
"""Test SBProgress finalize sends the progressEnd event"""
|
||||
|
||||
progress = lldb.SBProgress("Test SBProgress", "Test finalize", 13, self.dbg)
|
||||
listener = lldb.SBListener("Test listener")
|
||||
broadcaster = self.dbg.GetBroadcaster()
|
||||
broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgressCategory)
|
||||
event = lldb.SBEvent()
|
||||
progress.Finalize()
|
||||
self.assertTrue(listener.WaitForEvent(5, event))
|
||||
stream = lldb.SBStream()
|
||||
event.GetDescription(stream)
|
||||
# Note even for progresses with a total, the total isn't
|
||||
# sent in the end message.
|
||||
self.assertIn("type = end", stream.GetData())
|
||||
|
||||
Reference in New Issue
Block a user