From 53d1a6196865d3b1c76f63dd5589d08b72e5eab6 Mon Sep 17 00:00:00 2001
From: Tim Johns <59954029+timjohns-mw@users.noreply.github.com>
Date: Wed, 22 Jul 2026 11:51:44 +0100
Subject: [PATCH 1/7] Add FailOnSpecificWarningsPlugin
---
.../testext.type.File/plugins.type.File.xml | 2 +
.../1.type.DIR_SIGNIFIER.xml | 2 +
...ilOnSpecificWarningsPlugin.m.type.File.xml | 6 +
.../tests.type.File/plugins.type.File.xml | 2 +
.../1.type.DIR_SIGNIFIER.xml | 2 +
...SpecificWarningsPluginTest.m.type.File.xml | 6 +
...-4f83-a71c-6f87186394b7.type.Reference.xml | 2 +
...-4769-936a-dcd20d2644e4.type.Reference.xml | 2 +
.../plugins/FailOnSpecificWarningsPlugin.m | 202 ++++++++++++++++++
.../FailOnSpecificWarningsPluginTest.m | 96 +++++++++
.../fixtures/TargetWarningSharedFixture.m | 8 +
.../ExpectedTargetWarningScenarioTest.m | 12 ++
.../scenarioTests/SecondWarningScenarioTest.m | 9 +
.../SharedFixtureWarningScenarioTest.m | 8 +
.../scenarioTests/TargetWarningScenarioTest.m | 9 +
.../TestClassSetupWarningScenarioTest.m | 14 ++
.../TestClassTeardownWarningScenarioTest.m | 14 ++
.../UnrelatedWarningScenarioTest.m | 9 +
.../scenarioTests/WarningFreeScenarioTest.m | 7 +
19 files changed, 412 insertions(+)
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File.xml
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/FailOnSpecificWarningsPlugin.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/plugins.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/plugins.type.File/FailOnSpecificWarningsPluginTest.m.type.File.xml
create mode 100644 resources/project/Root.type.ProjectPath/6d5d1258-7d50-4f83-a71c-6f87186394b7.type.Reference.xml
create mode 100644 resources/project/Root.type.ProjectPath/d54dd5af-6a8b-4769-936a-dcd20d2644e4.type.Reference.xml
create mode 100644 tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
create mode 100644 tests/plugins/FailOnSpecificWarningsPluginTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
create mode 100644 tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
diff --git a/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/FailOnSpecificWarningsPlugin.m.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/FailOnSpecificWarningsPlugin.m.type.File.xml
new file mode 100644
index 0000000..99772b4
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testext.type.File/plugins.type.File/FailOnSpecificWarningsPlugin.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tests.type.File/plugins.type.File.xml b/resources/project/Root.type.Files/tests.type.File/plugins.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/plugins.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tests.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml b/resources/project/Root.type.Files/tests.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/plugins.type.File/1.type.DIR_SIGNIFIER.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tests.type.File/plugins.type.File/FailOnSpecificWarningsPluginTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/plugins.type.File/FailOnSpecificWarningsPluginTest.m.type.File.xml
new file mode 100644
index 0000000..378b613
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/plugins.type.File/FailOnSpecificWarningsPluginTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.ProjectPath/6d5d1258-7d50-4f83-a71c-6f87186394b7.type.Reference.xml b/resources/project/Root.type.ProjectPath/6d5d1258-7d50-4f83-a71c-6f87186394b7.type.Reference.xml
new file mode 100644
index 0000000..686e785
--- /dev/null
+++ b/resources/project/Root.type.ProjectPath/6d5d1258-7d50-4f83-a71c-6f87186394b7.type.Reference.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.ProjectPath/d54dd5af-6a8b-4769-936a-dcd20d2644e4.type.Reference.xml b/resources/project/Root.type.ProjectPath/d54dd5af-6a8b-4769-936a-dcd20d2644e4.type.Reference.xml
new file mode 100644
index 0000000..42196be
--- /dev/null
+++ b/resources/project/Root.type.ProjectPath/d54dd5af-6a8b-4769-936a-dcd20d2644e4.type.Reference.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m b/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
new file mode 100644
index 0000000..c6e4052
--- /dev/null
+++ b/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
@@ -0,0 +1,202 @@
+classdef FailOnSpecificWarningsPlugin < matlab.unittest.plugins.QualifyingPlugin & ...
+ matlab.unittest.plugins.Parallelizable
+ %FailOnSpecificWarningsPlugin Fail tests that issue specified warnings.
+ % plugin = FailOnSpecificWarningsPlugin(identifiers) creates a plugin
+ % that fails tests only when a warning with one of the specified
+ % identifiers is issued.
+
+ properties (SetAccess=immutable)
+ WarningIdentifiers string
+ end
+
+ properties (Access=private)
+ Logger
+ LocalWarnings
+ TestClassSetupWarnings
+ SharedTestFixtureWarningsStack
+ end
+
+ methods
+ function plugin = FailOnSpecificWarningsPlugin(identifiers)
+ arguments
+ identifiers {mustBeText}
+ end
+
+ identifiers = string(identifiers);
+ identifiers = identifiers(:).';
+ validateWarningIdentifiers(identifiers);
+
+ plugin.WarningIdentifiers = identifiers;
+ end
+ end
+
+ methods (Hidden, Sealed)
+ function tf = supportsParallelThreadPool_(~)
+ tf = true;
+ end
+ end
+
+ methods (Hidden, Access=protected)
+ function runTestSuite(plugin, pluginData)
+ import matlab.unittest.internal.ExpectedWarningsNotifier
+ import matlab.unittest.internal.constraints.WarningLogger
+
+ plugin.Logger = WarningLogger;
+ plugin.resetSharedTestFixtureWarningsStack;
+
+ expectedWarningsListener = ExpectedWarningsNotifier.createExpectedWarningsListener( ...
+ @plugin.recordExpectedWarning); %#ok
+
+ runTestSuite@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ end
+
+ function fixture = createSharedTestFixture(plugin, pluginData)
+ fixture = createSharedTestFixture@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ plugin.initializeSharedFixtureWarningStackForNewSharedTestFixture;
+ end
+
+ function setupSharedTestFixture(plugin, pluginData)
+ plugin.startLoggingWarnings;
+ cleanup = matlab.unittest.internal.Teardownable;
+ cleanup.addTeardown(@()plugin.stopLoggingWarningsInSharedTestFixtureSetup);
+ setupSharedTestFixture@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ end
+
+ function teardownSharedTestFixture(plugin, pluginData)
+ setupWarnings = plugin.peekSharedTestFixtureWarningsStack;
+ plugin.popSharedTestFixtureWarningsStack;
+
+ plugin.startLoggingWarnings;
+ teardownSharedTestFixture@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ teardownWarnings = plugin.stopLoggingWarnings;
+
+ plugin.assertWarningFree(pluginData, [setupWarnings, teardownWarnings]);
+ end
+
+ function setupTestClass(plugin, pluginData)
+ plugin.startLoggingWarnings;
+ cleanup = matlab.unittest.internal.Teardownable;
+ cleanup.addTeardown(@()plugin.stopLoggingWarningsInTestClassSetup);
+ setupTestClass@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ end
+
+ function teardownTestClass(plugin, pluginData)
+ plugin.startLoggingWarnings;
+ teardownTestClass@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ teardownWarnings = plugin.stopLoggingWarnings;
+
+ warnings = [plugin.TestClassSetupWarnings, teardownWarnings];
+ plugin.verifyWarningFree(pluginData, warnings);
+ end
+
+ function setupTestMethod(plugin, pluginData)
+ plugin.startLoggingWarnings;
+ setupTestMethod@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ end
+
+ function teardownTestMethod(plugin, pluginData)
+ teardownTestMethod@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
+ plugin.verifyWarningFree(pluginData, plugin.stopLoggingWarnings);
+ end
+ end
+
+ methods (Access=private)
+ function startLoggingWarnings(plugin)
+ import matlab.internal.diagnostic.Warning
+
+ plugin.LocalWarnings = Warning.empty;
+ plugin.Logger.clear;
+ plugin.Logger.start;
+ end
+
+ function warnings = stopLoggingWarnings(plugin)
+ plugin.Logger.stop;
+ plugin.makeWarningsLocal;
+ plugin.keepOnlySpecifiedWarnings;
+ warnings = plugin.LocalWarnings;
+ end
+
+ function stopLoggingWarningsInSharedTestFixtureSetup(plugin)
+ warnings = plugin.stopLoggingWarnings;
+ plugin.replaceArrayAtTopOfSharedFixtureStack(warnings);
+ end
+
+ function stopLoggingWarningsInTestClassSetup(plugin)
+ plugin.TestClassSetupWarnings = plugin.stopLoggingWarnings;
+ end
+
+ function recordExpectedWarning(plugin, expectedWarnings)
+ plugin.makeWarningsLocal;
+ plugin.removeExpectedWarningsFromLocalWarnings(expectedWarnings);
+ end
+
+ function makeWarningsLocal(plugin)
+ plugin.LocalWarnings = [plugin.LocalWarnings, plugin.Logger.Warnings];
+ plugin.Logger.clear;
+ end
+
+ function removeExpectedWarningsFromLocalWarnings(plugin, expectedWarnings)
+ plugin.LocalWarnings(ismember(plugin.LocalWarnings, expectedWarnings)) = [];
+ end
+
+ function keepOnlySpecifiedWarnings(plugin)
+ identifiers = string({plugin.LocalWarnings.identifier});
+ plugin.LocalWarnings(~ismember(identifiers, plugin.WarningIdentifiers)) = [];
+ end
+
+ function assertWarningFree(plugin, pluginData, warnings)
+ import matlab.unittest.internal.plugins.IsWarningFree
+ import matlab.unittest.internal.plugins.WarningHistory
+
+ history = WarningHistory(pluginData.Name, warnings);
+ plugin.assertUsing(pluginData.QualificationContext, history, IsWarningFree);
+ end
+
+ function verifyWarningFree(plugin, pluginData, warnings)
+ import matlab.unittest.internal.plugins.IsWarningFree
+ import matlab.unittest.internal.plugins.WarningHistory
+
+ history = WarningHistory(pluginData.Name, warnings);
+ plugin.verifyUsing(pluginData.QualificationContext, history, IsWarningFree);
+ end
+
+ function resetSharedTestFixtureWarningsStack(plugin)
+ plugin.SharedTestFixtureWarningsStack = {};
+ end
+
+ function initializeSharedFixtureWarningStackForNewSharedTestFixture(plugin)
+ import matlab.internal.diagnostic.Warning
+
+ plugin.SharedTestFixtureWarningsStack = [{Warning.empty(1, 0)}, ...
+ plugin.SharedTestFixtureWarningsStack];
+ end
+
+ function replaceArrayAtTopOfSharedFixtureStack(plugin, warnings)
+ plugin.SharedTestFixtureWarningsStack{1} = warnings;
+ end
+
+ function warnings = peekSharedTestFixtureWarningsStack(plugin)
+ warnings = plugin.SharedTestFixtureWarningsStack{1};
+ end
+
+ function popSharedTestFixtureWarningsStack(plugin)
+ plugin.SharedTestFixtureWarningsStack(1) = [];
+ end
+ end
+end
+
+function validateWarningIdentifiers(identifiers)
+if isempty(identifiers)
+ error("FailOnSpecificWarningsPlugin:EmptyIdentifiers", ...
+ "Specify at least one warning identifier.");
+end
+
+invalidIdentifiers = identifiers(strlength(identifiers) == 0 | ...
+ arrayfun(@(id)isempty(regexp(id, ...
+ "^[A-Za-z]\w*(?::[A-Za-z]\w*)+$", "once")), identifiers));
+
+if ~isempty(invalidIdentifiers)
+ error("FailOnSpecificWarningsPlugin:InvalidIdentifier", ...
+ "Invalid warning identifier: %s", invalidIdentifiers(1));
+end
+end
diff --git a/tests/plugins/FailOnSpecificWarningsPluginTest.m b/tests/plugins/FailOnSpecificWarningsPluginTest.m
new file mode 100644
index 0000000..7af0991
--- /dev/null
+++ b/tests/plugins/FailOnSpecificWarningsPluginTest.m
@@ -0,0 +1,96 @@
+classdef FailOnSpecificWarningsPluginTest < matlab.unittest.TestCase
+ %FailOnSpecificWarningsPluginTest Tests FailOnSpecificWarningsPlugin.
+
+ properties (Constant)
+ TargetID = "FailOnSpecificWarningsPluginTest:Target"
+ OtherID = "FailOnSpecificWarningsPluginTest:Other"
+ SecondID = "FailOnSpecificWarningsPluginTest:Second"
+ end
+
+ methods (TestClassSetup)
+ function addProjectFoldersToPath(testCase)
+ testFolder = fullfile(testroot(),"testresources","failOnSpecificWarningsPlugin");
+ scenarioTestFolder = fullfile(testFolder, "scenarioTests");
+ fixtureFolder = fullfile(testFolder, "fixtures");
+ testCase.applyFixture(matlab.unittest.fixtures.PathFixture(scenarioTestFolder));
+ testCase.applyFixture(matlab.unittest.fixtures.PathFixture(fixtureFolder));
+ end
+ end
+
+ methods (Test)
+ function warningFreeTestPasses(testCase)
+ results = testCase.runScenarioTest("WarningFreeScenarioTest", testCase.TargetID);
+
+ testCase.verifyFalse(any([results.Failed]));
+ end
+
+ function unrelatedWarningPasses(testCase)
+ results = testCase.runScenarioTest("UnrelatedWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyFalse(any([results.Failed]));
+ end
+
+ function targetWarningFails(testCase)
+ results = testCase.runScenarioTest("TargetWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyTrue(any([results.Failed]));
+ end
+
+ function multipleTargetWarningsFail(testCase)
+ results = testCase.runScenarioTest( ...
+ "SecondWarningScenarioTest", [testCase.TargetID, testCase.SecondID]);
+
+ testCase.verifyTrue(any([results.Failed]));
+ end
+
+ function expectedTargetWarningPasses(testCase)
+ results = testCase.runScenarioTest( ...
+ "ExpectedTargetWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyFalse(any([results.Failed]));
+ end
+
+ function testClassSetupWarningFails(testCase)
+ results = testCase.runScenarioTest( ...
+ "TestClassSetupWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyTrue(any([results.Failed]));
+ end
+
+ function testClassTeardownWarningFails(testCase)
+ results = testCase.runScenarioTest( ...
+ "TestClassTeardownWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyTrue(any([results.Failed]));
+ end
+
+ function sharedFixtureWarningFails(testCase)
+ results = testCase.runScenarioTest( ...
+ "SharedFixtureWarningScenarioTest", testCase.TargetID);
+
+ testCase.verifyTrue(any([results.Failed]));
+ end
+
+ function invalidIdentifierErrors(testCase)
+ testCase.verifyError(@() FailOnSpecificWarningsPlugin("not valid"), ...
+ "FailOnSpecificWarningsPlugin:InvalidIdentifier");
+ end
+
+ function emptyIdentifierErrors(testCase)
+ testCase.verifyError(@() FailOnSpecificWarningsPlugin(string.empty), ...
+ "FailOnSpecificWarningsPlugin:EmptyIdentifiers");
+ end
+ end
+
+ methods (Access=private)
+ function results = runScenarioTest(~, scenarioClassName, warningIdentifiers)
+ import matlab.unittest.TestRunner
+
+ suite = testsuite(scenarioClassName);
+ runner = TestRunner.withNoPlugins;
+ runner.addPlugin(FailOnSpecificWarningsPlugin(warningIdentifiers));
+
+ results = runner.run(suite);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m b/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
new file mode 100644
index 0000000..ea21030
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
@@ -0,0 +1,8 @@
+classdef TargetWarningSharedFixture < matlab.unittest.fixtures.Fixture
+ methods
+ function setup(~)
+ warning("FailOnSpecificWarningsPluginTest:Target", ...
+ "Shared fixture target warning.");
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
new file mode 100644
index 0000000..b002cf2
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
@@ -0,0 +1,12 @@
+classdef ExpectedTargetWarningScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testExpectedTargetWarning(testCase)
+ testCase.verifyWarning(@() issueTargetWarning, ...
+ "FailOnSpecificWarningsPluginTest:Target");
+ end
+ end
+end
+
+function issueTargetWarning
+warning("FailOnSpecificWarningsPluginTest:Target", "Expected target warning.");
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
new file mode 100644
index 0000000..fb07c95
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
@@ -0,0 +1,9 @@
+classdef SecondWarningScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testSecondWarning(testCase)
+ warning("FailOnSpecificWarningsPluginTest:Second", "Second warning.");
+
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
new file mode 100644
index 0000000..ce96bac
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
@@ -0,0 +1,8 @@
+classdef (SharedTestFixtures={TargetWarningSharedFixture}) ...
+ SharedFixtureWarningScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testBody(testCase)
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
new file mode 100644
index 0000000..4b9cb08
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
@@ -0,0 +1,9 @@
+classdef TargetWarningScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testTargetWarning(testCase)
+ warning("FailOnSpecificWarningsPluginTest:Target", "Target warning.");
+
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
new file mode 100644
index 0000000..9ad37b4
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
@@ -0,0 +1,14 @@
+classdef TestClassSetupWarningScenarioTest < matlab.unittest.TestCase
+ methods (TestClassSetup)
+ function issueSetupWarning(~)
+ warning("FailOnSpecificWarningsPluginTest:Target", ...
+ "Test class setup target warning.");
+ end
+ end
+
+ methods (Test)
+ function testBody(testCase)
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
new file mode 100644
index 0000000..8cb6e7d
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
@@ -0,0 +1,14 @@
+classdef TestClassTeardownWarningScenarioTest < matlab.unittest.TestCase
+ methods (TestClassTeardown)
+ function issueTeardownWarning(~)
+ warning("FailOnSpecificWarningsPluginTest:Target", ...
+ "Test class teardown target warning.");
+ end
+ end
+
+ methods (Test)
+ function testBody(testCase)
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
new file mode 100644
index 0000000..db1ef0f
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
@@ -0,0 +1,9 @@
+classdef UnrelatedWarningScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testUnrelatedWarning(testCase)
+ warning("FailOnSpecificWarningsPluginTest:Other", "Other warning.");
+
+ testCase.verifyTrue(true);
+ end
+ end
+end
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
new file mode 100644
index 0000000..c84f24b
--- /dev/null
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
@@ -0,0 +1,7 @@
+classdef WarningFreeScenarioTest < matlab.unittest.TestCase
+ methods (Test)
+ function testWarningFree(testCase)
+ testCase.verifyTrue(true);
+ end
+ end
+end
From 5de2d8afea89c0b277af3bd9b2d683778e29fe09 Mon Sep 17 00:00:00 2001
From: Tim Johns <59954029+timjohns-mw@users.noreply.github.com>
Date: Wed, 22 Jul 2026 14:26:50 +0100
Subject: [PATCH 2/7] Format plugin and add documentation
Update FailOnSpecificWarningsPlugin and its tests to match the existing repo style, including MATLAB help text, block formatting, copyright comments, and scenario test formatting.
Add packaged documentation for the plugin, wire it into the toolbox index, help TOC, Contents listing, and README, and add project metadata for the new documentation and test resource files.
---
README.md | 7 +-
...lOnSpecificWarningsPlugin.md.type.File.xml | 2 +
...failOnSpecificWarningsPlugin.type.File.xml | 2 +
.../1.type.DIR_SIGNIFIER.xml | 2 +
.../fixtures.type.File.xml | 2 +
.../1.type.DIR_SIGNIFIER.xml | 2 +
...TargetWarningSharedFixture.m.type.File.xml | 6 +
.../scenarioTests.type.File.xml | 2 +
.../1.type.DIR_SIGNIFIER.xml | 2 +
...dTargetWarningScenarioTest.m.type.File.xml | 6 +
.../SecondWarningScenarioTest.m.type.File.xml | 6 +
...FixtureWarningScenarioTest.m.type.File.xml | 6 +
.../TargetWarningScenarioTest.m.type.File.xml | 6 +
...ssSetupWarningScenarioTest.m.type.File.xml | 6 +
...eardownWarningScenarioTest.m.type.File.xml | 6 +
...relatedWarningScenarioTest.m.type.File.xml | 6 +
.../WarningFreeScenarioTest.m.type.File.xml | 6 +
tbx/testext/Contents.m | 6 +-
.../plugins/FailOnSpecificWarningsPlugin.m | 169 +++++++++++++-----
.../FailOnSpecificWarningsPlugin.md | 54 ++++++
tbx/testextdoc/helptoc.md | 2 +
tbx/testextdoc/index.md | 7 +-
.../FailOnSpecificWarningsPluginTest.m | 128 ++++++++-----
.../fixtures/TargetWarningSharedFixture.m | 12 +-
.../ExpectedTargetWarningScenarioTest.m | 18 +-
.../scenarioTests/SecondWarningScenarioTest.m | 14 +-
.../SharedFixtureWarningScenarioTest.m | 14 +-
.../scenarioTests/TargetWarningScenarioTest.m | 14 +-
.../TestClassSetupWarningScenarioTest.m | 24 ++-
.../TestClassTeardownWarningScenarioTest.m | 24 ++-
.../UnrelatedWarningScenarioTest.m | 14 +-
.../scenarioTests/WarningFreeScenarioTest.m | 14 +-
32 files changed, 448 insertions(+), 141 deletions(-)
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/FailOnSpecificWarningsPlugin.md.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/1.type.DIR_SIGNIFIER.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/1.type.DIR_SIGNIFIER.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/TargetWarningSharedFixture.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/1.type.DIR_SIGNIFIER.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/ExpectedTargetWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SecondWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SharedFixtureWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TargetWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassSetupWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassTeardownWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/UnrelatedWarningScenarioTest.m.type.File.xml
create mode 100644 resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/WarningFreeScenarioTest.m.type.File.xml
create mode 100644 tbx/testextdoc/FailOnSpecificWarningsPlugin.md
diff --git a/README.md b/README.md
index 1041371..2ca4052 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
[](https://matlab.mathworks.com/open/github/v1?repo=mathworks/test-framework-extensions&project=TestFrameworkExtensions.prj)
[](https://github.com/mathworks/test-framework-extensions/actions/workflows/testext-ci.yml)
-The Test Framework Extensions toolbox provides a number of custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html) and [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html) to aid the testing of MATLAB code.
+The Test Framework Extensions toolbox provides a number of custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html), [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html), and [plugins](https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins.testrunnerplugin-class.html) to aid the testing of MATLAB code.
### Constraints
* `DatetimeTolerance` - allow non-exact matching of datetimes and durations.
@@ -24,7 +24,10 @@ The Test Framework Extensions toolbox provides a number of custom [constraints](
* `SimulinkModelFixture` - load a Simulink model and close it on teardown.
* `SuppressParpoolAutocreateFixture` - suppress the automatic creation of parpools and restore the original setting in teardown.
-The documentation provides examples of how to use these constraints and fixtures.
+### Plugins
+* `FailOnSpecificWarningsPlugin` - fail tests that issue selected warnings.
+
+The documentation provides examples of how to use these constraints, fixtures, and plugins.
See also the [database testing framework](https://www.mathworks.com/matlabcentral/fileexchange/77101-database-testing-framework).
diff --git a/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/FailOnSpecificWarningsPlugin.md.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/FailOnSpecificWarningsPlugin.md.type.File.xml
new file mode 100644
index 0000000..7825d83
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/FailOnSpecificWarningsPlugin.md.type.File.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/1.type.DIR_SIGNIFIER.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/1.type.DIR_SIGNIFIER.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/1.type.DIR_SIGNIFIER.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/1.type.DIR_SIGNIFIER.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/1.type.DIR_SIGNIFIER.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/1.type.DIR_SIGNIFIER.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/TargetWarningSharedFixture.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/TargetWarningSharedFixture.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/fixtures.type.File/TargetWarningSharedFixture.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/1.type.DIR_SIGNIFIER.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/1.type.DIR_SIGNIFIER.xml
new file mode 100644
index 0000000..b8927b2
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/1.type.DIR_SIGNIFIER.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/ExpectedTargetWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/ExpectedTargetWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/ExpectedTargetWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SecondWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SecondWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SecondWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SharedFixtureWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SharedFixtureWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/SharedFixtureWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TargetWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TargetWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TargetWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassSetupWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassSetupWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassSetupWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassTeardownWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassTeardownWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/TestClassTeardownWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/UnrelatedWarningScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/UnrelatedWarningScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/UnrelatedWarningScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/WarningFreeScenarioTest.m.type.File.xml b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/WarningFreeScenarioTest.m.type.File.xml
new file mode 100644
index 0000000..eb4136b
--- /dev/null
+++ b/resources/project/Root.type.Files/tests.type.File/testresources.type.File/failOnSpecificWarningsPlugin.type.File/scenarioTests.type.File/WarningFreeScenarioTest.m.type.File.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tbx/testext/Contents.m b/tbx/testext/Contents.m
index 86fa31a..85c53e0 100644
--- a/tbx/testext/Contents.m
+++ b/tbx/testext/Contents.m
@@ -21,8 +21,12 @@
% SimulinkModelFixture
% SuppressParpoolAutocreateFixture
%
+% Plugins
+%
+% FailOnSpecificWarningsPlugin
+%
% Alias
%
% Testable
-% Copyright 2026 The MathWorks, Inc.
\ No newline at end of file
+% Copyright 2026 The MathWorks, Inc.
diff --git a/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m b/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
index c6e4052..4d58b07 100644
--- a/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
+++ b/tbx/testext/plugins/FailOnSpecificWarningsPlugin.m
@@ -1,43 +1,63 @@
classdef FailOnSpecificWarningsPlugin < matlab.unittest.plugins.QualifyingPlugin & ...
- matlab.unittest.plugins.Parallelizable
- %FailOnSpecificWarningsPlugin Fail tests that issue specified warnings.
- % plugin = FailOnSpecificWarningsPlugin(identifiers) creates a plugin
- % that fails tests only when a warning with one of the specified
- % identifiers is issued.
-
- properties (SetAccess=immutable)
- WarningIdentifiers string
- end
-
- properties (Access=private)
+ matlab.unittest.plugins.Parallelizable
+ %FailOnSpecificWarningsPlugin - Fail tests that issue selected warnings
+ % PLUGIN = FailOnSpecificWarningsPlugin(IDENTIFIERS) creates a
+ % plugin that fails tests when code issues a warning whose identifier
+ % is listed in IDENTIFIERS. Warnings verified with VERIFYWARNING are
+ % ignored.
+ %
+ % FailOnSpecificWarningsPlugin functions:
+ % FailOnSpecificWarningsPlugin - Create plugin that fails on warnings
+ %
+ % FailOnSpecificWarningsPlugin properties:
+ % WarningIdentifiers - Warning identifiers that fail tests
+ %
+ % See also matlab.unittest.TestRunner, verifyWarning
+
+ % Copyright 2026 The MathWorks, Inc.
+
+ properties ( SetAccess = immutable )
+ WarningIdentifiers string % Warning identifiers that fail tests.
+ end % properties ( SetAccess = immutable )
+
+ properties ( Access = private )
Logger
LocalWarnings
TestClassSetupWarnings
SharedTestFixtureWarningsStack
- end
+ end % properties ( Access = private )
methods
+
function plugin = FailOnSpecificWarningsPlugin(identifiers)
+
arguments
identifiers {mustBeText}
- end
+ end % arguments
identifiers = string(identifiers);
identifiers = identifiers(:).';
validateWarningIdentifiers(identifiers);
plugin.WarningIdentifiers = identifiers;
- end
- end
+ end % constructor
+
+ end % methods
+
+ methods ( Hidden, Sealed )
- methods (Hidden, Sealed)
function tf = supportsParallelThreadPool_(~)
+
tf = true;
- end
- end
- methods (Hidden, Access=protected)
+ end % supportsParallelThreadPool_
+
+ end % methods ( Hidden, Sealed )
+
+ methods ( Hidden, Access = protected )
+
function runTestSuite(plugin, pluginData)
+
import matlab.unittest.internal.ExpectedWarningsNotifier
import matlab.unittest.internal.constraints.WarningLogger
@@ -48,21 +68,27 @@ function runTestSuite(plugin, pluginData)
@plugin.recordExpectedWarning); %#ok
runTestSuite@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
- end
+
+ end % runTestSuite
function fixture = createSharedTestFixture(plugin, pluginData)
+
fixture = createSharedTestFixture@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
plugin.initializeSharedFixtureWarningStackForNewSharedTestFixture;
- end
+
+ end % createSharedTestFixture
function setupSharedTestFixture(plugin, pluginData)
+
plugin.startLoggingWarnings;
cleanup = matlab.unittest.internal.Teardownable;
cleanup.addTeardown(@()plugin.stopLoggingWarningsInSharedTestFixtureSetup);
setupSharedTestFixture@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
- end
+
+ end % setupSharedTestFixture
function teardownSharedTestFixture(plugin, pluginData)
+
setupWarnings = plugin.peekSharedTestFixtureWarningsStack;
plugin.popSharedTestFixtureWarningsStack;
@@ -71,125 +97,169 @@ function teardownSharedTestFixture(plugin, pluginData)
teardownWarnings = plugin.stopLoggingWarnings;
plugin.assertWarningFree(pluginData, [setupWarnings, teardownWarnings]);
- end
+
+ end % teardownSharedTestFixture
function setupTestClass(plugin, pluginData)
+
plugin.startLoggingWarnings;
cleanup = matlab.unittest.internal.Teardownable;
cleanup.addTeardown(@()plugin.stopLoggingWarningsInTestClassSetup);
setupTestClass@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
- end
+
+ end % setupTestClass
function teardownTestClass(plugin, pluginData)
+
plugin.startLoggingWarnings;
teardownTestClass@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
teardownWarnings = plugin.stopLoggingWarnings;
warnings = [plugin.TestClassSetupWarnings, teardownWarnings];
plugin.verifyWarningFree(pluginData, warnings);
- end
+
+ end % teardownTestClass
function setupTestMethod(plugin, pluginData)
+
plugin.startLoggingWarnings;
setupTestMethod@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
- end
+
+ end % setupTestMethod
function teardownTestMethod(plugin, pluginData)
+
teardownTestMethod@matlab.unittest.plugins.QualifyingPlugin(plugin, pluginData);
plugin.verifyWarningFree(pluginData, plugin.stopLoggingWarnings);
- end
- end
- methods (Access=private)
+ end % teardownTestMethod
+
+ end % methods ( Hidden, Access = protected )
+
+ methods ( Access = private )
+
function startLoggingWarnings(plugin)
+
import matlab.internal.diagnostic.Warning
plugin.LocalWarnings = Warning.empty;
plugin.Logger.clear;
plugin.Logger.start;
- end
+
+ end % startLoggingWarnings
function warnings = stopLoggingWarnings(plugin)
+
plugin.Logger.stop;
plugin.makeWarningsLocal;
plugin.keepOnlySpecifiedWarnings;
warnings = plugin.LocalWarnings;
- end
+
+ end % stopLoggingWarnings
function stopLoggingWarningsInSharedTestFixtureSetup(plugin)
+
warnings = plugin.stopLoggingWarnings;
plugin.replaceArrayAtTopOfSharedFixtureStack(warnings);
- end
+
+ end % stopLoggingWarningsInSharedTestFixtureSetup
function stopLoggingWarningsInTestClassSetup(plugin)
+
plugin.TestClassSetupWarnings = plugin.stopLoggingWarnings;
- end
+
+ end % stopLoggingWarningsInTestClassSetup
function recordExpectedWarning(plugin, expectedWarnings)
+
plugin.makeWarningsLocal;
plugin.removeExpectedWarningsFromLocalWarnings(expectedWarnings);
- end
+
+ end % recordExpectedWarning
function makeWarningsLocal(plugin)
+
plugin.LocalWarnings = [plugin.LocalWarnings, plugin.Logger.Warnings];
plugin.Logger.clear;
- end
+
+ end % makeWarningsLocal
function removeExpectedWarningsFromLocalWarnings(plugin, expectedWarnings)
+
plugin.LocalWarnings(ismember(plugin.LocalWarnings, expectedWarnings)) = [];
- end
+
+ end % removeExpectedWarningsFromLocalWarnings
function keepOnlySpecifiedWarnings(plugin)
+
identifiers = string({plugin.LocalWarnings.identifier});
plugin.LocalWarnings(~ismember(identifiers, plugin.WarningIdentifiers)) = [];
- end
+
+ end % keepOnlySpecifiedWarnings
function assertWarningFree(plugin, pluginData, warnings)
+
import matlab.unittest.internal.plugins.IsWarningFree
import matlab.unittest.internal.plugins.WarningHistory
history = WarningHistory(pluginData.Name, warnings);
plugin.assertUsing(pluginData.QualificationContext, history, IsWarningFree);
- end
+
+ end % assertWarningFree
function verifyWarningFree(plugin, pluginData, warnings)
+
import matlab.unittest.internal.plugins.IsWarningFree
import matlab.unittest.internal.plugins.WarningHistory
history = WarningHistory(pluginData.Name, warnings);
plugin.verifyUsing(pluginData.QualificationContext, history, IsWarningFree);
- end
+
+ end % verifyWarningFree
function resetSharedTestFixtureWarningsStack(plugin)
+
plugin.SharedTestFixtureWarningsStack = {};
- end
+
+ end % resetSharedTestFixtureWarningsStack
function initializeSharedFixtureWarningStackForNewSharedTestFixture(plugin)
+
import matlab.internal.diagnostic.Warning
plugin.SharedTestFixtureWarningsStack = [{Warning.empty(1, 0)}, ...
plugin.SharedTestFixtureWarningsStack];
- end
+
+ end % initializeSharedFixtureWarningStackForNewSharedTestFixture
function replaceArrayAtTopOfSharedFixtureStack(plugin, warnings)
+
plugin.SharedTestFixtureWarningsStack{1} = warnings;
- end
+
+ end % replaceArrayAtTopOfSharedFixtureStack
function warnings = peekSharedTestFixtureWarningsStack(plugin)
+
warnings = plugin.SharedTestFixtureWarningsStack{1};
- end
+
+ end % peekSharedTestFixtureWarningsStack
function popSharedTestFixtureWarningsStack(plugin)
+
plugin.SharedTestFixtureWarningsStack(1) = [];
- end
- end
-end
+
+ end % popSharedTestFixtureWarningsStack
+
+ end % methods ( Access = private )
+
+end % classdef
function validateWarningIdentifiers(identifiers)
+
if isempty(identifiers)
error("FailOnSpecificWarningsPlugin:EmptyIdentifiers", ...
"Specify at least one warning identifier.");
-end
+end % if
invalidIdentifiers = identifiers(strlength(identifiers) == 0 | ...
arrayfun(@(id)isempty(regexp(id, ...
@@ -198,5 +268,6 @@ function validateWarningIdentifiers(identifiers)
if ~isempty(invalidIdentifiers)
error("FailOnSpecificWarningsPlugin:InvalidIdentifier", ...
"Invalid warning identifier: %s", invalidIdentifiers(1));
-end
-end
+end % if
+
+end % validateWarningIdentifiers
diff --git a/tbx/testextdoc/FailOnSpecificWarningsPlugin.md b/tbx/testextdoc/FailOnSpecificWarningsPlugin.md
new file mode 100644
index 0000000..cf3275f
--- /dev/null
+++ b/tbx/testextdoc/FailOnSpecificWarningsPlugin.md
@@ -0,0 +1,54 @@
+# `FailOnSpecificWarningsPlugin`
+
+A custom MATLAB unit test plugin that fails tests when selected warning identifiers are issued.
+
+## Overview
+
+`FailOnSpecificWarningsPlugin` is a subclass of [`matlab.unittest.plugins.QualifyingPlugin`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins.qualifyingplugin-class.html) that records warnings during test execution and fails tests only for warning identifiers that you specify. Warnings verified with [`verifyWarning`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.qualifications.verifiable.verifywarning.html) are treated as expected and do not fail the test.
+
+## Properties
+
+| Property | Access | Description |
+|----------------------|-----------|----------------------------------------------|
+| `WarningIdentifiers` | Read-only | Warning identifiers that cause test failure. |
+
+## Constructor
+
+### `FailOnSpecificWarningsPlugin(identifiers)`
+
+- **Description**: Constructs a plugin that fails tests when any warning identifier in `identifiers` is issued.
+- **Inputs**:
+ - `identifiers` (text): Warning identifier or vector of warning identifiers to fail on.
+
+```matlab
+plugin = FailOnSpecificWarningsPlugin("myComponent:DeprecatedWorkflow");
+plugin = FailOnSpecificWarningsPlugin([
+ "myComponent:DeprecatedWorkflow"
+ "myComponent:SlowFallback"
+]);
+```
+
+## Example
+
+```matlab
+import matlab.unittest.TestRunner
+
+suite = testsuite("myTestClass");
+runner = TestRunner.withTextOutput;
+runner.addPlugin(FailOnSpecificWarningsPlugin("myCode:UnexpectedWarning"));
+
+results = runner.run(suite);
+```
+
+## Plugin Behavior
+
+- **Fails a test if**:
+ A warning with one of the configured identifiers is issued during test method setup, test method execution, test method teardown, test class setup, test class teardown, shared fixture setup, or shared fixture teardown.
+- **Allows a test to pass if**:
+ No configured warning is issued, a warning has a different identifier, or the configured warning is expected with `verifyWarning`.
+
+## See Also
+
+- [`matlab.unittest.plugins.QualifyingPlugin`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins.qualifyingplugin-class.html)
+- [`matlab.unittest.TestRunner`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.testrunner-class.html)
+- [`verifyWarning`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.qualifications.verifiable.verifywarning.html)
diff --git a/tbx/testextdoc/helptoc.md b/tbx/testextdoc/helptoc.md
index bc21d6d..671ec44 100644
--- a/tbx/testextdoc/helptoc.md
+++ b/tbx/testextdoc/helptoc.md
@@ -18,5 +18,7 @@
* [PreferenceFixture](PreferenceFixture.md)
* [SimulinkModelFixture](SimulinkModelFixture.md)
* [SuppressParpoolAutocreateFixture](SuppressParpoolAutocreateFixture.md)
+ * [Plugins]()
+ * [FailOnSpecificWarningsPlugin](FailOnSpecificWarningsPlugin.md)
* [Alias]()
* [Testable](Testable.md)
diff --git a/tbx/testextdoc/index.md b/tbx/testextdoc/index.md
index ca1c817..e6d357e 100644
--- a/tbx/testextdoc/index.md
+++ b/tbx/testextdoc/index.md
@@ -1,6 +1,6 @@
# Test Framework Extensions Toolbox
-The Test Framework Extensions toolbox provides custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html) and [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html) to aid the testing of MATLAB code.
+The Test Framework Extensions toolbox provides custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html), [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html), and plugins to aid the testing of MATLAB code.
### Constraints
* [`DatetimeTolerance`](DatetimeTolerance.md) - allow non-exact matching of datetimes and durations.
@@ -20,7 +20,10 @@ The Test Framework Extensions toolbox provides custom [constraints](https://www.
* [`SimulinkModelFixture`](PreferenceFixture.md) - load a Simulink model and close it on teardown.
* [`SuppressParpoolAutocreateFixture`](SuppressParpoolAutocreateFixture.md) - suppress the automatic creation of parpools and restore the original setting in teardown.
+### Plugins
+* [`FailOnSpecificWarningsPlugin`](FailOnSpecificWarningsPlugin.md) - fail tests that issue selected warnings.
+
### Alias
* [`Testable`](Testable.md) - alias for `matlab.uitest.TestCase`
-The documentation provides examples of how to use these constraints and fixtures.
\ No newline at end of file
+The documentation provides examples of how to use these constraints, fixtures, and plugins.
diff --git a/tests/plugins/FailOnSpecificWarningsPluginTest.m b/tests/plugins/FailOnSpecificWarningsPluginTest.m
index 7af0991..e4f7613 100644
--- a/tests/plugins/FailOnSpecificWarningsPluginTest.m
+++ b/tests/plugins/FailOnSpecificWarningsPluginTest.m
@@ -1,89 +1,124 @@
classdef FailOnSpecificWarningsPluginTest < matlab.unittest.TestCase
%FailOnSpecificWarningsPluginTest Tests FailOnSpecificWarningsPlugin.
- properties (Constant)
+ properties ( Constant )
TargetID = "FailOnSpecificWarningsPluginTest:Target"
OtherID = "FailOnSpecificWarningsPluginTest:Other"
SecondID = "FailOnSpecificWarningsPluginTest:Second"
- end
+ end % properties ( Constant )
+
+ methods ( TestClassSetup )
- methods (TestClassSetup)
function addProjectFoldersToPath(testCase)
- testFolder = fullfile(testroot(),"testresources","failOnSpecificWarningsPlugin");
- scenarioTestFolder = fullfile(testFolder, "scenarioTests");
- fixtureFolder = fullfile(testFolder, "fixtures");
- testCase.applyFixture(matlab.unittest.fixtures.PathFixture(scenarioTestFolder));
- testCase.applyFixture(matlab.unittest.fixtures.PathFixture(fixtureFolder));
- end
- end
-
- methods (Test)
+
+ testFolder = fullfile( ...
+ testroot(), "testresources", "failOnSpecificWarningsPlugin" );
+ scenarioTestFolder = fullfile( testFolder, "scenarioTests" );
+ fixtureFolder = fullfile( testFolder, "fixtures" );
+ testCase.applyFixture( ...
+ matlab.unittest.fixtures.PathFixture( scenarioTestFolder ) );
+ testCase.applyFixture( ...
+ matlab.unittest.fixtures.PathFixture( fixtureFolder ) );
+
+ end % addProjectFoldersToPath
+
+ end % methods ( TestClassSetup )
+
+ methods ( Test )
+
function warningFreeTestPasses(testCase)
- results = testCase.runScenarioTest("WarningFreeScenarioTest", testCase.TargetID);
- testCase.verifyFalse(any([results.Failed]));
- end
+ results = testCase.runScenarioTest( ...
+ "WarningFreeScenarioTest", testCase.TargetID );
+
+ testCase.verifyFalse( any( [results.Failed] ) );
+
+ end % warningFreeTestPasses
function unrelatedWarningPasses(testCase)
- results = testCase.runScenarioTest("UnrelatedWarningScenarioTest", testCase.TargetID);
- testCase.verifyFalse(any([results.Failed]));
- end
+ results = testCase.runScenarioTest( ...
+ "UnrelatedWarningScenarioTest", testCase.TargetID );
+
+ testCase.verifyFalse( any( [results.Failed] ) );
+
+ end % unrelatedWarningPasses
function targetWarningFails(testCase)
- results = testCase.runScenarioTest("TargetWarningScenarioTest", testCase.TargetID);
- testCase.verifyTrue(any([results.Failed]));
- end
+ results = testCase.runScenarioTest( ...
+ "TargetWarningScenarioTest", testCase.TargetID );
+
+ testCase.verifyTrue( any( [results.Failed] ) );
+
+ end % targetWarningFails
function multipleTargetWarningsFail(testCase)
+
results = testCase.runScenarioTest( ...
- "SecondWarningScenarioTest", [testCase.TargetID, testCase.SecondID]);
+ "SecondWarningScenarioTest", ...
+ [testCase.TargetID, testCase.SecondID] );
- testCase.verifyTrue(any([results.Failed]));
- end
+ testCase.verifyTrue( any( [results.Failed] ) );
+
+ end % multipleTargetWarningsFail
function expectedTargetWarningPasses(testCase)
+
results = testCase.runScenarioTest( ...
- "ExpectedTargetWarningScenarioTest", testCase.TargetID);
+ "ExpectedTargetWarningScenarioTest", testCase.TargetID );
- testCase.verifyFalse(any([results.Failed]));
- end
+ testCase.verifyFalse( any( [results.Failed] ) );
+
+ end % expectedTargetWarningPasses
function testClassSetupWarningFails(testCase)
+
results = testCase.runScenarioTest( ...
- "TestClassSetupWarningScenarioTest", testCase.TargetID);
+ "TestClassSetupWarningScenarioTest", testCase.TargetID );
+
+ testCase.verifyTrue( any( [results.Failed] ) );
- testCase.verifyTrue(any([results.Failed]));
- end
+ end % testClassSetupWarningFails
function testClassTeardownWarningFails(testCase)
+
results = testCase.runScenarioTest( ...
- "TestClassTeardownWarningScenarioTest", testCase.TargetID);
+ "TestClassTeardownWarningScenarioTest", testCase.TargetID );
+
+ testCase.verifyTrue( any( [results.Failed] ) );
- testCase.verifyTrue(any([results.Failed]));
- end
+ end % testClassTeardownWarningFails
function sharedFixtureWarningFails(testCase)
+
results = testCase.runScenarioTest( ...
- "SharedFixtureWarningScenarioTest", testCase.TargetID);
+ "SharedFixtureWarningScenarioTest", testCase.TargetID );
+
+ testCase.verifyTrue( any( [results.Failed] ) );
- testCase.verifyTrue(any([results.Failed]));
- end
+ end % sharedFixtureWarningFails
function invalidIdentifierErrors(testCase)
- testCase.verifyError(@() FailOnSpecificWarningsPlugin("not valid"), ...
+
+ testCase.verifyError( @() FailOnSpecificWarningsPlugin("not valid"), ...
"FailOnSpecificWarningsPlugin:InvalidIdentifier");
- end
+
+ end % invalidIdentifierErrors
function emptyIdentifierErrors(testCase)
- testCase.verifyError(@() FailOnSpecificWarningsPlugin(string.empty), ...
+
+ testCase.verifyError( @() FailOnSpecificWarningsPlugin(string.empty), ...
"FailOnSpecificWarningsPlugin:EmptyIdentifiers");
- end
- end
- methods (Access=private)
+ end % emptyIdentifierErrors
+
+ end % methods ( Test )
+
+ methods ( Access = private )
+
function results = runScenarioTest(~, scenarioClassName, warningIdentifiers)
+
import matlab.unittest.TestRunner
suite = testsuite(scenarioClassName);
@@ -91,6 +126,9 @@ function emptyIdentifierErrors(testCase)
runner.addPlugin(FailOnSpecificWarningsPlugin(warningIdentifiers));
results = runner.run(suite);
- end
- end
-end
+
+ end % runScenarioTest
+
+ end % methods ( Access = private )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m b/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
index ea21030..bed9240 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/fixtures/TargetWarningSharedFixture.m
@@ -1,8 +1,14 @@
classdef TargetWarningSharedFixture < matlab.unittest.fixtures.Fixture
+
methods
+
function setup(~)
+
warning("FailOnSpecificWarningsPluginTest:Target", ...
"Shared fixture target warning.");
- end
- end
-end
+
+ end % setup
+
+ end % methods
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
index b002cf2..3a711c2 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/ExpectedTargetWarningScenarioTest.m
@@ -1,12 +1,20 @@
classdef ExpectedTargetWarningScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testExpectedTargetWarning(testCase)
+
testCase.verifyWarning(@() issueTargetWarning, ...
"FailOnSpecificWarningsPluginTest:Target");
- end
- end
-end
+
+ end % testExpectedTargetWarning
+
+ end % methods ( Test )
+
+end % classdef
function issueTargetWarning
+
warning("FailOnSpecificWarningsPluginTest:Target", "Expected target warning.");
-end
+
+end % issueTargetWarning
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
index fb07c95..6017a8b 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SecondWarningScenarioTest.m
@@ -1,9 +1,15 @@
classdef SecondWarningScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testSecondWarning(testCase)
+
warning("FailOnSpecificWarningsPluginTest:Second", "Second warning.");
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testSecondWarning
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
index ce96bac..9b0361b 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/SharedFixtureWarningScenarioTest.m
@@ -1,8 +1,14 @@
classdef (SharedTestFixtures={TargetWarningSharedFixture}) ...
SharedFixtureWarningScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testBody(testCase)
+
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testBody
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
index 4b9cb08..42bd684 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TargetWarningScenarioTest.m
@@ -1,9 +1,15 @@
classdef TargetWarningScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testTargetWarning(testCase)
+
warning("FailOnSpecificWarningsPluginTest:Target", "Target warning.");
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testTargetWarning
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
index 9ad37b4..e25f410 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassSetupWarningScenarioTest.m
@@ -1,14 +1,24 @@
classdef TestClassSetupWarningScenarioTest < matlab.unittest.TestCase
- methods (TestClassSetup)
+
+ methods ( TestClassSetup )
+
function issueSetupWarning(~)
+
warning("FailOnSpecificWarningsPluginTest:Target", ...
"Test class setup target warning.");
- end
- end
- methods (Test)
+ end % issueSetupWarning
+
+ end % methods ( TestClassSetup )
+
+ methods ( Test )
+
function testBody(testCase)
+
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testBody
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
index 8cb6e7d..133c736 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/TestClassTeardownWarningScenarioTest.m
@@ -1,14 +1,24 @@
classdef TestClassTeardownWarningScenarioTest < matlab.unittest.TestCase
- methods (TestClassTeardown)
+
+ methods ( TestClassTeardown )
+
function issueTeardownWarning(~)
+
warning("FailOnSpecificWarningsPluginTest:Target", ...
"Test class teardown target warning.");
- end
- end
- methods (Test)
+ end % issueTeardownWarning
+
+ end % methods ( TestClassTeardown )
+
+ methods ( Test )
+
function testBody(testCase)
+
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testBody
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
index db1ef0f..9045520 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/UnrelatedWarningScenarioTest.m
@@ -1,9 +1,15 @@
classdef UnrelatedWarningScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testUnrelatedWarning(testCase)
+
warning("FailOnSpecificWarningsPluginTest:Other", "Other warning.");
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testUnrelatedWarning
+
+ end % methods ( Test )
+
+end % classdef
diff --git a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
index c84f24b..7954032 100644
--- a/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
+++ b/tests/testresources/failOnSpecificWarningsPlugin/scenarioTests/WarningFreeScenarioTest.m
@@ -1,7 +1,13 @@
classdef WarningFreeScenarioTest < matlab.unittest.TestCase
- methods (Test)
+
+ methods ( Test )
+
function testWarningFree(testCase)
+
testCase.verifyTrue(true);
- end
- end
-end
+
+ end % testWarningFree
+
+ end % methods ( Test )
+
+end % classdef
From 488690d86739fc886a33b5afaf7a269bfc1bec9c Mon Sep 17 00:00:00 2001
From: Tim Johns <59954029+timjohns-mw@users.noreply.github.com>
Date: Wed, 22 Jul 2026 14:47:50 +0100
Subject: [PATCH 3/7] Add link to plugins doc
---
tbx/testextdoc/index.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tbx/testextdoc/index.md b/tbx/testextdoc/index.md
index e6d357e..ce35912 100644
--- a/tbx/testextdoc/index.md
+++ b/tbx/testextdoc/index.md
@@ -1,6 +1,6 @@
# Test Framework Extensions Toolbox
-The Test Framework Extensions toolbox provides custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html), [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html), and plugins to aid the testing of MATLAB code.
+The Test Framework Extensions toolbox provides custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html), [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html), and [plugins](https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins.testrunnerplugin-class.html) to aid the testing of MATLAB code.
### Constraints
* [`DatetimeTolerance`](DatetimeTolerance.md) - allow non-exact matching of datetimes and durations.
From a4d2789fa49719bbe65d2e0550bac82355cf242b Mon Sep 17 00:00:00 2001
From: Ken Deeley
Date: Wed, 22 Jul 2026 16:23:41 +0100
Subject: [PATCH 4/7] Added note on UIFigureFixture, further links in index and
README, and incremented version to 1.0.7
---
README.md | 3 +++
tbx/testext/Contents.m | 2 +-
tbx/testextdoc/FigureFixture.md | 5 ++++-
tbx/testextdoc/index.md | 2 +-
4 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 2ca4052..1e655e6 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,9 @@ The Test Framework Extensions toolbox provides a number of custom [constraints](
### Plugins
* `FailOnSpecificWarningsPlugin` - fail tests that issue selected warnings.
+### Alias
+* `Testable` - alias for [`matlab.uitest.TestCase`](https://www.mathworks.com/help/matlab/ref/matlab.uitest.testcase-class.html)
+
The documentation provides examples of how to use these constraints, fixtures, and plugins.
See also the [database testing framework](https://www.mathworks.com/matlabcentral/fileexchange/77101-database-testing-framework).
diff --git a/tbx/testext/Contents.m b/tbx/testext/Contents.m
index 85c53e0..715a451 100644
--- a/tbx/testext/Contents.m
+++ b/tbx/testext/Contents.m
@@ -1,5 +1,5 @@
% Test Framework Extensions
-% Version 1.0.6 (R2026a) 13-Jul-2026
+% Version 1.0.7 (R2026a) 22-Jul-2026
%
% Constraints
%
diff --git a/tbx/testextdoc/FigureFixture.md b/tbx/testextdoc/FigureFixture.md
index 86e2f4f..d30447c 100644
--- a/tbx/testextdoc/FigureFixture.md
+++ b/tbx/testextdoc/FigureFixture.md
@@ -2,6 +2,8 @@
A custom MATLAB unit test fixture for managing the lifecycle of a `uifigure` during testing.
+**Note:** from R2026b onwards, you can use the [`UIFigureFixture`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.uifigurefixture-class.html) class provided with MATLAB instead of this custom fixture.
+
## Overview
`FigureFixture` is a subclass of [`matlab.unittest.fixtures.Fixture`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture.html) designed to create and clean up a `uifigure` for use in unit tests. It enables tests to use a new figure, optionally configured via name-value arguments, and ensures the figure is deleted after the test completes.
@@ -57,4 +59,5 @@ end
## See Also
- [`matlab.unittest.fixtures.Fixture`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html)
-- [`uifigure`](https://www.mathworks.com/help/matlab/ref/uifigure.html)
\ No newline at end of file
+- [`uifigure`](https://www.mathworks.com/help/matlab/ref/uifigure.html)
+- [`UIFigureFixture`](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.uifigurefixture-class.html) (available from R2026b)
\ No newline at end of file
diff --git a/tbx/testextdoc/index.md b/tbx/testextdoc/index.md
index ce35912..3f06078 100644
--- a/tbx/testextdoc/index.md
+++ b/tbx/testextdoc/index.md
@@ -24,6 +24,6 @@ The Test Framework Extensions toolbox provides custom [constraints](https://www.
* [`FailOnSpecificWarningsPlugin`](FailOnSpecificWarningsPlugin.md) - fail tests that issue selected warnings.
### Alias
-* [`Testable`](Testable.md) - alias for `matlab.uitest.TestCase`
+* [`Testable`](Testable.md) - alias for [`matlab.uitest.TestCase`](https://www.mathworks.com/help/matlab/ref/matlab.uitest.testcase-class.html)
The documentation provides examples of how to use these constraints, fixtures, and plugins.
From cebe5da0b2611e17156ec53d4e0b8cfb8fa8e81d Mon Sep 17 00:00:00 2001
From: Ken Deeley
Date: Wed, 22 Jul 2026 16:29:26 +0100
Subject: [PATCH 5/7] Do not run tests in strict mode
---
buildfile.m | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/buildfile.m b/buildfile.m
index 0c0756f..ea29afa 100644
--- a/buildfile.m
+++ b/buildfile.m
@@ -32,7 +32,7 @@
% Test task
plan("test") = TestTask( test, ...
SourceFiles=tbx, ...
- Strict=true, ...
+ Strict=false, ...
Dependencies="check" );
% Documentation task
From f7f65b7ab3824148b14e56add60f80035ac339d6 Mon Sep 17 00:00:00 2001
From: Ken Deeley
Date: Wed, 22 Jul 2026 16:39:23 +0100
Subject: [PATCH 6/7] Added section landing pages; fixed broken links in
helptoc and index
---
.../Alias.md.type.File.xml | 2 ++
.../Constraints.md.type.File.xml | 2 ++
.../Fixtures.md.type.File.xml | 2 ++
.../Plugins.md.type.File.xml | 2 ++
tbx/testextdoc/Alias.md | 16 ++++++++++
tbx/testextdoc/Constraints.md | 31 +++++++++++++++++++
tbx/testextdoc/Fixtures.md | 25 +++++++++++++++
tbx/testextdoc/Plugins.md | 16 ++++++++++
tbx/testextdoc/helptoc.md | 10 +++---
tbx/testextdoc/index.md | 10 +++---
10 files changed, 106 insertions(+), 10 deletions(-)
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Alias.md.type.File.xml
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Constraints.md.type.File.xml
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Fixtures.md.type.File.xml
create mode 100644 resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Plugins.md.type.File.xml
create mode 100644 tbx/testextdoc/Alias.md
create mode 100644 tbx/testextdoc/Constraints.md
create mode 100644 tbx/testextdoc/Fixtures.md
create mode 100644 tbx/testextdoc/Plugins.md
diff --git a/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Alias.md.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Alias.md.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Alias.md.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Constraints.md.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Constraints.md.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Constraints.md.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Fixtures.md.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Fixtures.md.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Fixtures.md.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Plugins.md.type.File.xml b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Plugins.md.type.File.xml
new file mode 100644
index 0000000..4356a6a
--- /dev/null
+++ b/resources/project/Root.type.Files/tbx.type.File/testextdoc.type.File/Plugins.md.type.File.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/tbx/testextdoc/Alias.md b/tbx/testextdoc/Alias.md
new file mode 100644
index 0000000..cdd87a9
--- /dev/null
+++ b/tbx/testextdoc/Alias.md
@@ -0,0 +1,16 @@
+# Alias
+
+Convenience aliases for commonly used MATLAB testing classes.
+
+## Available Aliases
+
+* [`Testable`](Testable.md) - alias for
+ [`matlab.uitest.TestCase`](
+ https://www.mathworks.com/help/matlab/ref/matlab.uitest.testcase-class.html)
+
+## See Also
+
+* [Test Framework Extensions Toolbox](index.md)
+* [Constraints](Constraints.md)
+* [Fixtures](Fixtures.md)
+* [Plugins](Plugins.md)
diff --git a/tbx/testextdoc/Constraints.md b/tbx/testextdoc/Constraints.md
new file mode 100644
index 0000000..24f9a56
--- /dev/null
+++ b/tbx/testextdoc/Constraints.md
@@ -0,0 +1,31 @@
+# Constraints
+
+Custom constraints for verifying MATLAB test behavior and test data.
+
+## Available Constraints
+
+* [`DatetimeTolerance`](DatetimeTolerance.md) - allow non-exact
+ matching of datetimes and durations.
+* [`HasStringLengthLessThan`](HasStringLengthLessThan.md) - check
+ that string length is less than a set value.
+* [`IsEqualVector`](IsEqualVector.md) - are two vectors equal
+ irrespective of row or column orientation.
+* [`IsEquivalentText`](IsEquivalentText.md) - is text equal
+ irrespective of `string`, `char`, or `cellstr` type.
+* [`IsSamePathAs`](IsSamePathAs.md) - are paths equal irrespective
+ of data type, file separator, and Windows capitalization.
+* [`MatchesStatistically`](MatchesStatistically.md) - are at least
+ a certain percentage of elements equal within a tolerance.
+* [`NotifiesEvent`](NotifiesEvent.md) - check that a function or
+ method call notifies an event.
+* [`NotifiesPropertyEvent`](NotifiesPropertyEvent.md) - check that
+ a function or method call notifies a property event.
+* [`PassesEventData`](PassesEventData.md) - check that a function
+ or method call notifies an event with custom event data.
+
+## See Also
+
+* [Test Framework Extensions Toolbox](index.md)
+* [Fixtures](Fixtures.md)
+* [Plugins](Plugins.md)
+* [Alias](Alias.md)
diff --git a/tbx/testextdoc/Fixtures.md b/tbx/testextdoc/Fixtures.md
new file mode 100644
index 0000000..7942d05
--- /dev/null
+++ b/tbx/testextdoc/Fixtures.md
@@ -0,0 +1,25 @@
+# Fixtures
+
+Custom fixtures for creating and restoring test state in MATLAB.
+
+## Available Fixtures
+
+* [`FigureFixture`](FigureFixture.md) - create a figure and close
+ it on teardown.
+* [`GridLayoutFixture`](GridLayoutFixture.md) - create a grid
+ layout and delete it on teardown.
+* [`PreferenceFixture`](PreferenceFixture.md) - override a MATLAB
+ preference and restore it on teardown.
+* [`SimulinkModelFixture`](SimulinkModelFixture.md) - load a
+ Simulink model and close it on teardown.
+* [`SuppressParpoolAutocreateFixture`](
+ SuppressParpoolAutocreateFixture.md) - suppress the automatic
+ creation of parpools and restore the original setting in
+ teardown.
+
+## See Also
+
+* [Test Framework Extensions Toolbox](index.md)
+* [Constraints](Constraints.md)
+* [Plugins](Plugins.md)
+* [Alias](Alias.md)
diff --git a/tbx/testextdoc/Plugins.md b/tbx/testextdoc/Plugins.md
new file mode 100644
index 0000000..cb57d6b
--- /dev/null
+++ b/tbx/testextdoc/Plugins.md
@@ -0,0 +1,16 @@
+# Plugins
+
+Custom plugins for changing how the MATLAB test runner behaves.
+
+## Available Plugins
+
+* [`FailOnSpecificWarningsPlugin`](
+ FailOnSpecificWarningsPlugin.md) - fail tests that issue
+ selected warnings.
+
+## See Also
+
+* [Test Framework Extensions Toolbox](index.md)
+* [Constraints](Constraints.md)
+* [Fixtures](Fixtures.md)
+* [Alias](Alias.md)
diff --git a/tbx/testextdoc/helptoc.md b/tbx/testextdoc/helptoc.md
index 671ec44..c206067 100644
--- a/tbx/testextdoc/helptoc.md
+++ b/tbx/testextdoc/helptoc.md
@@ -1,8 +1,8 @@
# Test Framework Extensions
* [Test Framework Extensions](index.md)
- * [Release notes](changelog.md)
- * [Constraints]()
+ * [Release notes](Changelog.md)
+ * [Constraints](Constraints.md)
* [DatetimeTolerance](DatetimeTolerance.md)
* [HasStringLengthLessThan](HasStringLengthLessThan.md)
* [IsEqualVector](IsEqualVector.md)
@@ -12,13 +12,13 @@
* [NotifiesEvent](NotifiesEvent.md)
* [NotifiesPropertyEvent](NotifiesPropertyEvent.md)
* [PassesEventData](PassesEventData.md)
- * [Fixtures]()
+ * [Fixtures](Fixtures.md)
* [FigureFixture](FigureFixture.md)
* [GridLayoutFixture](GridLayoutFixture.md)
* [PreferenceFixture](PreferenceFixture.md)
* [SimulinkModelFixture](SimulinkModelFixture.md)
* [SuppressParpoolAutocreateFixture](SuppressParpoolAutocreateFixture.md)
- * [Plugins]()
+ * [Plugins](Plugins.md)
* [FailOnSpecificWarningsPlugin](FailOnSpecificWarningsPlugin.md)
- * [Alias]()
+ * [Alias](Alias.md)
* [Testable](Testable.md)
diff --git a/tbx/testextdoc/index.md b/tbx/testextdoc/index.md
index 3f06078..d86bb41 100644
--- a/tbx/testextdoc/index.md
+++ b/tbx/testextdoc/index.md
@@ -2,7 +2,7 @@
The Test Framework Extensions toolbox provides custom [constraints](https://www.mathworks.com/help/matlab/ref/matlab.unittest.constraints.constraint-class.html), [fixtures](https://www.mathworks.com/help/matlab/ref/matlab.unittest.fixtures.fixture-class.html), and [plugins](https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins.testrunnerplugin-class.html) to aid the testing of MATLAB code.
-### Constraints
+### [Constraints](Constraints.md)
* [`DatetimeTolerance`](DatetimeTolerance.md) - allow non-exact matching of datetimes and durations.
* [`HasStringLengthLessThan`](HasStringLengthLessThan.md) - check that string length is less than a set value.
* [`IsEqualVector`](IsEqualVector.md) - are two vectors equal irrespective of row or column orientation.
@@ -13,17 +13,17 @@ The Test Framework Extensions toolbox provides custom [constraints](https://www.
* [`NotifiesPropertyEvent`](NotifiesPropertyEvent.md) - check that a function or method call notifies a property event.
* [`PassesEventData`](PassesEventData.md) - check that a function or method call notifies an event with custom event data.
-### Fixtures
+### [Fixtures](Fixtures.md)
* [`FigureFixture`](FigureFixture.md) - create a figure and close it on teardown.
* [`GridLayoutFixture`](GridLayoutFixture.md) - create a grid layout and delete it on teardown.
* [`PreferenceFixture`](PreferenceFixture.md) - override a MATLAB preference and restore it on teardown.
-* [`SimulinkModelFixture`](PreferenceFixture.md) - load a Simulink model and close it on teardown.
+* [`SimulinkModelFixture`](SimulinkModelFixture.md) - load a Simulink model and close it on teardown.
* [`SuppressParpoolAutocreateFixture`](SuppressParpoolAutocreateFixture.md) - suppress the automatic creation of parpools and restore the original setting in teardown.
-### Plugins
+### [Plugins](Plugins.md)
* [`FailOnSpecificWarningsPlugin`](FailOnSpecificWarningsPlugin.md) - fail tests that issue selected warnings.
-### Alias
+### [Alias](Alias.md)
* [`Testable`](Testable.md) - alias for [`matlab.uitest.TestCase`](https://www.mathworks.com/help/matlab/ref/matlab.uitest.testcase-class.html)
The documentation provides examples of how to use these constraints, fixtures, and plugins.
From 18f67a9a0e8fd886b72598c0bd66be8f6d588ae8 Mon Sep 17 00:00:00 2001
From: Ken Deeley
Date: Wed, 22 Jul 2026 16:41:21 +0100
Subject: [PATCH 7/7] Updated changelog for 1.0.7
---
tbx/testextdoc/Changelog.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tbx/testextdoc/Changelog.md b/tbx/testextdoc/Changelog.md
index f169d89..c340aed 100644
--- a/tbx/testextdoc/Changelog.md
+++ b/tbx/testextdoc/Changelog.md
@@ -1,5 +1,10 @@
# Release notes
+## Version 1.0.7
+
+* Added `FailOnSpecificWarningsPlugin`
+* Added landing pages for documentation categories
+
## Version 1.0.6
* Added `Testable` alias