Skip to content

Commit c58ebb5

Browse files
HanSur94claude
andcommitted
Fix Octave compatibility in Companion NotificationCenterPane
PR #180 introduced MATLAB-only classdef syntax that breaks the Octave test suite: the class fails to load, taking test_notification_center_pane down with it. - Property type-constraint `IsAttached logical = false` (Octave classdef has no inline type validation) -> plain default + comment. - `Event.empty` property defaults and method assignments (no ClassName.empty in Octave) -> `[]`, which behaves identically under isempty / numel / indexing / concatenation in every use here. - Comma-list expansion over classdef object arrays ([events.Severity], [events.StartTime]) and arrayfun over them (Octave supports neither) -> explicit index loops, matching the pane's existing text-filter loop. Also drops Event.empty from the test double (StubEventStore) and the test's empty-case assertion. Verified 18/18 pass in both Octave 7+ (octave-cli) and MATLAB R2020b+; mlint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2a191c0 commit c58ebb5

3 files changed

Lines changed: 33 additions & 12 deletions

File tree

libs/FastSenseCompanion/NotificationCenterPane.m

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
end
3636

3737
properties (SetAccess = private)
38-
IsAttached logical = false
38+
IsAttached = false % logical flag (no type-constraint syntax — Octave-incompatible)
3939
end
4040

4141
properties (Access = private)
@@ -48,7 +48,7 @@
4848
hLastUpdateLbl_ = [] % "Updated: HH:MM:SS" label
4949
hPopoutBtn_ = [] % pop-out icon uibutton
5050
Companion_ = [] % FastSenseCompanion handle (or [])
51-
LastGoodEvents_ = Event.empty % last successfully-read unacked set (survives detach)
51+
LastGoodEvents_ = [] % last successfully-read unacked set (survives detach)
5252
LastIds_ = {} % cellstr of LastGoodEvents_ ids (diff key)
5353
Listeners_ = {} % addlistener handles; deleted on teardown
5454
IsStale_ = false % true when the last EventStore read failed
@@ -69,7 +69,7 @@
6969
end
7070
obj.ThemeStruct_ = themeStruct;
7171
obj.IsAttached = false;
72-
obj.LastGoodEvents_ = Event.empty;
72+
obj.LastGoodEvents_ = [];
7373
obj.LastIds_ = {};
7474
obj.Listeners_ = {};
7575
obj.IsStale_ = false;
@@ -232,14 +232,14 @@ function refresh(obj, eventStore)
232232
% (stale) marker; never clear the inbox and never uialert.
233233
if ~obj.IsAttached; return; end
234234
if isempty(eventStore) || ~isvalid(eventStore)
235-
obj.LastGoodEvents_ = Event.empty;
235+
obj.LastGoodEvents_ = [];
236236
obj.LastIds_ = {};
237237
obj.IsStale_ = false;
238238
obj.applyFilterAndRender_();
239239
obj.setUpdatedLabel_(datetime('now'), false);
240240
return;
241241
end
242-
allEvents = Event.empty;
242+
allEvents = [];
243243
readOk = true;
244244
try
245245
allEvents = eventStore.getEvents();
@@ -353,7 +353,13 @@ function applyFilterAndRender_(obj)
353353
otherwise, wanted = [];
354354
end
355355
if ~isempty(wanted)
356-
events = events([events.Severity] == wanted);
356+
% Explicit loop (Octave can't comma-list-expand [events.Severity]
357+
% over a classdef object array) — mirrors the text filter below.
358+
sevMask = false(1, numel(events));
359+
for i = 1:numel(events)
360+
sevMask(i) = (events(i).Severity == wanted);
361+
end
362+
events = events(sevMask);
357363
end
358364
end
359365
% Free-text filter over SensorName + ThresholdLabel (case-insensitive).
@@ -640,7 +646,7 @@ function ackForTest_(obj, eventId)
640646
% An event is unacked iff AckedAt is empty OR all-NaN (mirrors
641647
% Event.computeDisplayState). Empty input returns an empty Event array.
642648
if isempty(allEvents)
643-
evs = Event.empty;
649+
evs = [];
644650
return;
645651
end
646652
mask = false(1, numel(allEvents));
@@ -654,7 +660,13 @@ function ackForTest_(obj, eventId)
654660
function evs = sortNewestFirst_(events)
655661
%SORTNEWESTFIRST_ Order events by StartTime, newest first.
656662
if numel(events) > 1
657-
[~, ord] = sort([events.StartTime], 'descend');
663+
% Explicit loop (Octave can't comma-list-expand [events.StartTime]
664+
% over a classdef object array).
665+
starts = zeros(1, numel(events));
666+
for i = 1:numel(events)
667+
starts(i) = events(i).StartTime;
668+
end
669+
[~, ord] = sort(starts, 'descend');
658670
evs = events(ord);
659671
else
660672
evs = events;
@@ -666,7 +678,12 @@ function ackForTest_(obj, eventId)
666678
if isempty(events)
667679
s = 0;
668680
else
669-
s = max([events.Severity]);
681+
% Explicit loop (Octave can't comma-list-expand [events.Severity]).
682+
sevs = zeros(1, numel(events));
683+
for i = 1:numel(events)
684+
sevs(i) = events(i).Severity;
685+
end
686+
s = max(sevs);
670687
end
671688
end
672689

@@ -675,7 +692,11 @@ function ackForTest_(obj, eventId)
675692
if isempty(events)
676693
ids = {};
677694
else
678-
ids = arrayfun(@(e) e.Id, events, 'UniformOutput', false);
695+
% Explicit loop (Octave can't arrayfun over a classdef object array).
696+
ids = cell(1, numel(events));
697+
for i = 1:numel(events)
698+
ids{i} = events(i).Id;
699+
end
679700
end
680701
end
681702

tests/StubEventStore.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
% See also EventStore, Event, NotificationCenterPane, CaptureNotificationService.
2323

2424
properties
25-
Events_ = Event.empty % Event array; configure in test setup
25+
Events_ = [] % Event array (configure in test setup); [] not Event.empty for Octave parity
2626
AckedIds_ = {} % cellstr: each eventId passed to acknowledgeEvent, in call order
2727
ThrowOnAck_ = false % when true, acknowledgeEvent throws EventStore:unknownEventId
2828
ThrowOnGet_ = false % when true, getEvents throws (exercises the stale path)

tests/test_notification_center_pane.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function test_notification_center_pane()
4343

4444
% 4. maxSeverity_.
4545
n = n + 1; check(NotificationCenterPane.maxSeverity_([e1 e2]) == 3, 'maxSeverity_([3 2]) should be 3');
46-
n = n + 1; check(NotificationCenterPane.maxSeverity_(Event.empty) == 0, 'maxSeverity_(empty) should be 0');
46+
n = n + 1; check(NotificationCenterPane.maxSeverity_([]) == 0, 'maxSeverity_(empty) should be 0');
4747

4848
% 5. diffIds_ — order-insensitive set comparison.
4949
n = n + 1; check(~NotificationCenterPane.diffIds_({'a', 'b'}, {'b', 'a'}), ...

0 commit comments

Comments
 (0)