diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fe6ad4..d5fe327 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [4.0.2] - 2024-08-16
+
+### Fixed
+- #51: Don't start (and stop) the ObjectScript and Python monitors if there are no ObjectScript/Python routines being tracked respectively, fixes error from trying to start/stop the %Monitor.System.LineByLine with no routines
+
+
## [4.0.1] - 2024-08-16
### Fixed
diff --git a/cls/TestCoverage/Manager.cls b/cls/TestCoverage/Manager.cls
index 938a4e1..6e28cf7 100644
--- a/cls/TestCoverage/Manager.cls
+++ b/cls/TestCoverage/Manager.cls
@@ -528,10 +528,10 @@ Method EndCoverageTracking(pTestSuite As %String = "", pTestClass As %String = "
Set tSC = $$$OK
Try {
If ((..CoverageTargets '= "") || (..PyCoverageTargets '= "")) {
- // Pause the monitor.
- Set tSC = ..Monitor.Pause()
- Do ##class(TestCoverage.Utils.LineByLineMonitor).PyStop()
- If $$$ISERR(tSC) {
+ if (..Monitor.Started) {
+ // Pause the monitor.
+ Set tSC = ..Monitor.Pause()
+ If $$$ISERR(tSC) {
If $System.Status.GetErrorCodes(tSC) = $$$MonitorNotRunning {
// Not really an error, and nothing to do in this case.
Set tSC = $$$OK
@@ -540,6 +540,11 @@ Method EndCoverageTracking(pTestSuite As %String = "", pTestClass As %String = "
$$$ThrowStatus(tSC)
}
}
+ }
+
+ if (..Monitor.PyStarted) {
+ Do ##class(TestCoverage.Utils.LineByLineMonitor).PyStop()
+ }
Set tTarget = $ListBuild($$$TestPathAllTests) // detail = 0
If (pTestSuite '= "") {
@@ -719,7 +724,12 @@ ClassMethod OnAfterAllTests(manager As TestCoverage.Manager, dir As %String, ByR
Do manager.ListenerManager.BroadCastToAll(tObj)
}
}
- Do manager.Monitor.Stop()
+ if (manager.Monitor.Started) {
+ Do manager.Monitor.Stop()
+ }
+ if (manager.Monitor.PyStarted) {
+ Do manager.Monitor.PyStop()
+ }
} Catch e {
Set tSC = e.AsStatus()
}
diff --git a/cls/TestCoverage/Utils/LineByLineMonitor.cls b/cls/TestCoverage/Utils/LineByLineMonitor.cls
index 1c63e13..1e335d5 100644
--- a/cls/TestCoverage/Utils/LineByLineMonitor.cls
+++ b/cls/TestCoverage/Utils/LineByLineMonitor.cls
@@ -8,11 +8,20 @@ Class TestCoverage.Utils.LineByLineMonitor Extends %Monitor.System.LineByLine
/// True if the line-by-line monitor has been started.
Property Started As %Boolean [ Calculated, Private, ReadOnly ];
+/// True if the Python trace has been set
+Property PyStarted As %Boolean [ Calculated, Private, ReadOnly ];
+
Method StartedGet() As %Boolean [ CodeMode = expression ]
{
$zu(84,8)
}
+Method PyStartedGet() As %Boolean [ Language = python ]
+{
+ import sys
+ return sys.gettrace() is not None
+}
+
/// True if the line-by-line monitor is paused
Property Paused As %Boolean [ Calculated, Private, ReadOnly ];
@@ -30,6 +39,8 @@ Property LastMetricList As %List [ Private ];
Property LastProcessList As %List [ Private ];
+Property LastPythonList As %List [ Private ];
+
/// This callback method is invoked by the %Close method to
/// provide notification that the current object is being closed.
///
@@ -98,20 +109,22 @@ Method StartWithScope(pRoutineList As %List, pPyClasses As %List, pMetricList As
Set tSC = $$$OK
Try {
Set ..PythonClassList = pPyClasses
- Set tDifferentScope = (..LastRoutineList '= pRoutineList) || (..LastMetricList '= pMetricList) || (..LastProcessList '= pProcessList)
- If tDifferentScope && ..Started {
+ Set tDifferentScope = (..LastRoutineList '= pRoutineList) || (..LastMetricList '= pMetricList) || (..LastProcessList '= pProcessList) || (..LastPythonList '= pPyClasses)
+ If tDifferentScope && (..Started || ..PyStarted) {
// If we need to track different routines/metrics/processes, need to stop the monitor before restarting with the new context.
- Do ..Stop()
- Do ..PyStop()
+ If (..Started) {
+ Do ..Stop()
+ }
+ Do ..PyStop() // setting the trace to None can and should always be done
Set ..LastRoutineList = pRoutineList
Set ..LastMetricList = pMetricList
Set ..LastProcessList = pProcessList
+ Set ..LastPythonList = pPyClasses
}
- If '..Started {
- Do ..PyClearCounters()
+ // take care of starting the ObjectScript Monitor
+ If ('..Started && $ListLength(pRoutineList) '= 0) {
Set tSC = ..Start(pRoutineList, pMetricList, pProcessList)
- Do ..PyStartWithScope(pPyClasses)
If $System.Status.Equals(tSC,$$$ERRORCODE($$$MonitorMemoryAlloc)) {
// Construct a more helpful error message.
Set tSC = $$$EMBEDSC(..CheckAvailableMemory($ListLength(pProcessList),$ListLength(pRoutineList),1),tSC)
@@ -119,12 +132,20 @@ Method StartWithScope(pRoutineList As %List, pPyClasses As %List, pMetricList As
$$$ThrowOnError(tSC)
} Else {
// If the monitor was already running, clear the counters.
- Set tSC = ..ClearCounters()
- $$$ThrowOnError(tSC)
- If ..Paused {
- $$$ThrowOnError(..Resume())
- Do ..PyStartWithScope(pPyClasses)
+ if (..Started) {
+ Set tSC = ..ClearCounters()
+ $$$ThrowOnError(tSC)
}
+ If (..Paused && $ListLength(pRoutineList) '= 0){
+ $$$ThrowOnError(..Resume())
+ }
+ }
+
+ If ('..PyStarted && $ListLength(pPyClasses) '= 0) {
+ // whether we're resuming or restarting, we either way want to clear counters
+ // since StoreIntCoverage should have already
+ Do ..PyClearCounters()
+ Do ..PyStartWithScope(pPyClasses)
}
} Catch e {
Set tSC = e.AsStatus()
diff --git a/module.xml b/module.xml
index 5540c9e..3b9f9ec 100644
--- a/module.xml
+++ b/module.xml
@@ -2,7 +2,7 @@
TestCoverage
- 4.0.1
+ 4.0.2
Run your typical ObjectScript %UnitTest tests and see which lines of your code are executed. Includes Cobertura-style reporting for use in continuous integration tools.
module