diff --git a/libs/FastSenseCompanion/NotificationCenterPane.m b/libs/FastSenseCompanion/NotificationCenterPane.m index 05c2d935..4222708a 100644 --- a/libs/FastSenseCompanion/NotificationCenterPane.m +++ b/libs/FastSenseCompanion/NotificationCenterPane.m @@ -35,7 +35,7 @@ end properties (SetAccess = private) - IsAttached logical = false + IsAttached = false % logical flag (no type-constraint syntax — Octave-incompatible) end properties (Access = private) @@ -48,7 +48,7 @@ hLastUpdateLbl_ = [] % "Updated: HH:MM:SS" label hPopoutBtn_ = [] % pop-out icon uibutton Companion_ = [] % FastSenseCompanion handle (or []) - LastGoodEvents_ = Event.empty % last successfully-read unacked set (survives detach) + LastGoodEvents_ = [] % last successfully-read unacked set (survives detach) LastIds_ = {} % cellstr of LastGoodEvents_ ids (diff key) Listeners_ = {} % addlistener handles; deleted on teardown IsStale_ = false % true when the last EventStore read failed @@ -69,7 +69,7 @@ end obj.ThemeStruct_ = themeStruct; obj.IsAttached = false; - obj.LastGoodEvents_ = Event.empty; + obj.LastGoodEvents_ = []; obj.LastIds_ = {}; obj.Listeners_ = {}; obj.IsStale_ = false; @@ -232,14 +232,14 @@ function refresh(obj, eventStore) % (stale) marker; never clear the inbox and never uialert. if ~obj.IsAttached; return; end if isempty(eventStore) || ~isvalid(eventStore) - obj.LastGoodEvents_ = Event.empty; + obj.LastGoodEvents_ = []; obj.LastIds_ = {}; obj.IsStale_ = false; obj.applyFilterAndRender_(); obj.setUpdatedLabel_(datetime('now'), false); return; end - allEvents = Event.empty; + allEvents = []; readOk = true; try allEvents = eventStore.getEvents(); @@ -353,7 +353,13 @@ function applyFilterAndRender_(obj) otherwise, wanted = []; end if ~isempty(wanted) - events = events([events.Severity] == wanted); + % Explicit loop (Octave can't comma-list-expand [events.Severity] + % over a classdef object array) — mirrors the text filter below. + sevMask = false(1, numel(events)); + for i = 1:numel(events) + sevMask(i) = (events(i).Severity == wanted); + end + events = events(sevMask); end end % Free-text filter over SensorName + ThresholdLabel (case-insensitive). @@ -640,7 +646,7 @@ function ackForTest_(obj, eventId) % An event is unacked iff AckedAt is empty OR all-NaN (mirrors % Event.computeDisplayState). Empty input returns an empty Event array. if isempty(allEvents) - evs = Event.empty; + evs = []; return; end mask = false(1, numel(allEvents)); @@ -654,7 +660,13 @@ function ackForTest_(obj, eventId) function evs = sortNewestFirst_(events) %SORTNEWESTFIRST_ Order events by StartTime, newest first. if numel(events) > 1 - [~, ord] = sort([events.StartTime], 'descend'); + % Explicit loop (Octave can't comma-list-expand [events.StartTime] + % over a classdef object array). + starts = zeros(1, numel(events)); + for i = 1:numel(events) + starts(i) = events(i).StartTime; + end + [~, ord] = sort(starts, 'descend'); evs = events(ord); else evs = events; @@ -666,7 +678,12 @@ function ackForTest_(obj, eventId) if isempty(events) s = 0; else - s = max([events.Severity]); + % Explicit loop (Octave can't comma-list-expand [events.Severity]). + sevs = zeros(1, numel(events)); + for i = 1:numel(events) + sevs(i) = events(i).Severity; + end + s = max(sevs); end end @@ -675,7 +692,11 @@ function ackForTest_(obj, eventId) if isempty(events) ids = {}; else - ids = arrayfun(@(e) e.Id, events, 'UniformOutput', false); + % Explicit loop (Octave can't arrayfun over a classdef object array). + ids = cell(1, numel(events)); + for i = 1:numel(events) + ids{i} = events(i).Id; + end end end diff --git a/tests/StubEventStore.m b/tests/StubEventStore.m index 4bb2ce3f..38cc2b43 100644 --- a/tests/StubEventStore.m +++ b/tests/StubEventStore.m @@ -22,7 +22,7 @@ % See also EventStore, Event, NotificationCenterPane, CaptureNotificationService. properties - Events_ = Event.empty % Event array; configure in test setup + Events_ = [] % Event array (configure in test setup); [] not Event.empty for Octave parity AckedIds_ = {} % cellstr: each eventId passed to acknowledgeEvent, in call order ThrowOnAck_ = false % when true, acknowledgeEvent throws EventStore:unknownEventId ThrowOnGet_ = false % when true, getEvents throws (exercises the stale path) diff --git a/tests/suite/TestFastSenseCompanionPlantLogToolbar.m b/tests/suite/TestFastSenseCompanionPlantLogToolbar.m index f03f4a8a..2811eff2 100644 --- a/tests/suite/TestFastSenseCompanionPlantLogToolbar.m +++ b/tests/suite/TestFastSenseCompanionPlantLogToolbar.m @@ -114,19 +114,20 @@ function cleanupAll(testCase) end function g = findToolbarGrid_(testCase, c) %#ok - % After v3.1 Plant Log + v4.0 Wiki Browser merges, the - % Companion toolbar is a 1x9 grid: - % {110, 110, 110, 130, 70, 90, 70, '1x', 36} + % After v3.1 Plant Log + v4.0 Wiki Browser + v4.0 Phase 1040 + % notification bell, the Companion toolbar is a 1x10 grid: + % {110, 110, 110, 130, 70, 90, 70, 70, '1x', 36} fig = c.getFigForTest_(); grids = findobj(fig, 'Type', 'uigridlayout'); g = []; for i = 1:numel(grids) - if numel(grids(i).ColumnWidth) == 9 + if numel(grids(i).ColumnWidth) == 10 cw = grids(i).ColumnWidth; if iscell(cw) && isequal(cw{1}, 110) && isequal(cw{2}, 110) && ... isequal(cw{3}, 110) && isequal(cw{4}, 130) && ... isequal(cw{5}, 70) && isequal(cw{6}, 90) && ... - isequal(cw{7}, 70) && isequal(cw{9}, 36) + isequal(cw{7}, 70) && isequal(cw{8}, 70) && ... + isequal(cw{10}, 36) g = grids(i); return; end @@ -139,22 +140,23 @@ function cleanupAll(testCase) methods (Test) function testToolbarGridIs1x5(testCase) - % v3.1 Plant Log + v4.0 Wiki Browser merged: toolbar grew from - % 1x4 to 1x9. - % col 1 = Events (110) - % col 2 = Live (110) - % col 3 = Tags (110, v4.0 quick task 260519-bs4) - % col 4 = Plant Log (130, v3.1 Phase 1033 PLOG-INT-03) - % col 5 = Tile ( 70, v4.0 S0Y-01) - % col 6 = Close all ( 90, v4.0 S0Y-02) - % col 7 = Wiki ( 70, v4.0 Phase 1034) - % col 8 = flex spacer - % col 9 = gear ( 36) + % v3.1 Plant Log + v4.0 Wiki Browser + Phase 1040 bell: toolbar + % grew from 1x4 to 1x10. + % col 1 = Events (110) + % col 2 = Live (110) + % col 3 = Tags (110, v4.0 quick task 260519-bs4) + % col 4 = Plant Log (130, v3.1 Phase 1033 PLOG-INT-03) + % col 5 = Tile ( 70, v4.0 S0Y-01) + % col 6 = Close all ( 90, v4.0 S0Y-02) + % col 7 = Wiki ( 70, v4.0 Phase 1034) + % col 8 = Bell ( 70, v4.0 Phase 1040 notification center) + % col 9 = flex spacer + % col 10 = gear ( 36) d1 = testCase.makeEngine_('A'); c = testCase.makeCompanion_({d1}); g = testCase.findToolbarGrid_(c); testCase.verifyNotEmpty(g, ... - 'toolbar grid (1x8 with ColumnWidth {110 110 110 130 70 90 ''1x'' 36}) must exist'); + 'toolbar grid (1x10 with ColumnWidth {110 110 110 130 70 90 70 70 ''1x'' 36}) must exist'); cw = g.ColumnWidth; testCase.verifyEqual(cw{1}, 110, 'ColumnWidth{1} (Events)'); testCase.verifyEqual(cw{2}, 110, 'ColumnWidth{2} (Live)'); @@ -163,8 +165,9 @@ function testToolbarGridIs1x5(testCase) testCase.verifyEqual(cw{5}, 70, 'ColumnWidth{5} (Tile, v4.0)'); testCase.verifyEqual(cw{6}, 90, 'ColumnWidth{6} (Close all, v4.0)'); testCase.verifyEqual(cw{7}, 70, 'ColumnWidth{7} (Wiki, v4.0 Phase 1034)'); - testCase.verifyEqual(cw{8}, '1x', 'ColumnWidth{8} flex spacer'); - testCase.verifyEqual(cw{9}, 36, 'ColumnWidth{9} (gear)'); + testCase.verifyEqual(cw{8}, 70, 'ColumnWidth{8} (Bell, v4.0 Phase 1040)'); + testCase.verifyEqual(cw{9}, '1x', 'ColumnWidth{9} flex spacer'); + testCase.verifyEqual(cw{10}, 36, 'ColumnWidth{10} (gear)'); end function testPlantLogButtonExists(testCase) @@ -211,13 +214,13 @@ function testPlantLogButtonDisabledWithoutDashboards(testCase) end function testSettingsButtonMovedToCol5(testCase) - % After v3.1 + v4.0 merge, gear lives at col 8 (1x8 grid). + % After v3.1 + v4.0 + Phase 1040 bell, gear lives at col 10 (1x10 grid). d1 = testCase.makeEngine_('A'); c = testCase.makeCompanion_({d1}); gear = findobj(c.getFigForTest_(), 'Tooltip', 'Companion settings'); testCase.verifyNotEmpty(gear); - testCase.verifyEqual(gear.Layout.Column, 9, ... - 'settings gear must be at col 9 (1x9 grid post-v3.1+Wiki-Browser merge)'); + testCase.verifyEqual(gear.Layout.Column, 10, ... + 'settings gear must be at col 10 (1x10 grid post-Phase-1040 bell)'); end function testFindObjResolvesViaTag(testCase) diff --git a/tests/test_notification_center_pane.m b/tests/test_notification_center_pane.m index 2ff007ea..c00750f2 100644 --- a/tests/test_notification_center_pane.m +++ b/tests/test_notification_center_pane.m @@ -43,7 +43,7 @@ function test_notification_center_pane() % 4. maxSeverity_. n = n + 1; check(NotificationCenterPane.maxSeverity_([e1 e2]) == 3, 'maxSeverity_([3 2]) should be 3'); - n = n + 1; check(NotificationCenterPane.maxSeverity_(Event.empty) == 0, 'maxSeverity_(empty) should be 0'); + n = n + 1; check(NotificationCenterPane.maxSeverity_([]) == 0, 'maxSeverity_(empty) should be 0'); % 5. diffIds_ — order-insensitive set comparison. n = n + 1; check(~NotificationCenterPane.diffIds_({'a', 'b'}, {'b', 'a'}), ...