Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@
% getSingleton - Method for retrieving singleton object
% Defined in separate file in class folder
singletonObject = getSingleton(options)

function notifyModelVersionChanged()
% notifyModelVersionChanged - Release the registry for a change of model version
%
% Syntax:
% openminds.introspection.internal.MetaTypeRegistry.notifyModelVersionChanged()
%
% The registry holds enumeration values (openminds.enum.Types)
% of the model version it was built for, and a registry left in
% place across a version switch keeps the previous version's
% types in memory. This method deletes the registry; it is
% rebuilt on its next use. It is called from
% openminds.selectModelVersion.
%
% See also openminds.selectModelVersion

singletonObject = getappdata(0, ...
openminds.introspection.internal.MetaTypeRegistry.SINGLETON_NAME);

if ~isempty(singletonObject) && isvalid(singletonObject)
delete(singletonObject)
end
end
end

methods (Access = private)
Expand Down
7 changes: 7 additions & 0 deletions code/+openminds/selectModelVersion.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ function selectModelVersion(versionNumber)
% enumerations and the controlled term base class generated for it.
addpath(genpath( fullfile(generatedFolder, versionAsString) ))

% MATLAB reads the classes of the selected version only once nothing
% holds those of the previous one. The type registry holds enumeration
% values of the version it was built for, so it is released here: before
% the pause that lets the reload happen, and before the instance library
% resolves types against the reloaded classes. Its next use rebuilds it.
openminds.introspection.internal.MetaTypeRegistry.notifyModelVersionChanged()

% Add a second pause for changes to take effect.
pause(1) % Ad hoc value. Usually at least 0.3 - 0.4 seconds is necessary

Expand Down
12 changes: 8 additions & 4 deletions tools/tests/unitTests/InstanceLibraryIntegrationTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,19 @@ function testLibraryVersionFollowsTheModelVersion(testCase)
'The instance library holds no instances for this version.')

% Check that the instances were read from the v3.0 folder, not
% merely labelled v3.0. Whether every instance then resolves to
% a type depends on the model classes having been reloaded,
% which MATLAB cannot do while objects of those classes exist
% in the session, so that is not checked here.
% merely labelled v3.0.
readFromVersion = contains(library.InstanceTable.Filepath, ...
fullfile(filesep, "v3.0", filesep));

testCase.verifyTrue(all(readFromVersion), ...
'The library must read the instances of the selected version.')

% The instances must also be typed against that version's
% classes. Selecting a version releases the type registry, so
% the classes reload and every instance resolves to a type.
testCase.verifyEmpty( ...
library.InstanceTable(library.InstanceTable.Type == "", :), ...
'Every instance of the selected version must resolve to a type.')
end

function testModelVersionWithoutInstancesIsReported(testCase)
Expand Down
49 changes: 49 additions & 0 deletions tools/tests/unitTests/SelectModelVersionTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
classdef SelectModelVersionTest < matlab.unittest.TestCase
% SelectModelVersionTest - Tests for selecting a model version within a session
%
% A model version is selected by putting its generated classes on the
% search path. MATLAB reads a class definition from the path again only
% once nothing holds an instance of it, so anything the toolbox itself
% keeps across a switch pins the classes of the previous version.

methods (Test)
function testTheTypeRegistryDoesNotPinThePreviousVersion(testCase)
% The type registry holds enumeration values of the version it was
% built for. Left in place across a switch, it kept the previous
% version's Types enumeration in memory, and the instance library
% then resolved the selected version's instances against it: every
% type the two versions do not share came out untyped.
%
% The two versions are numbered ones, which are pinned to a schema
% commit and do not change, unlike latest. They are chosen for
% what tells them apart: v5.0 declares AnatomicalAtlas, which v3.0
% calls BrainAtlas. The first is selected here rather than assumed,
% so that the test does not pass for nothing in a session that is
% on v3.0 or v4.0 already.

import ommtest.helper.ModelVersionFixture

testCase.applyFixture(ModelVersionFixture("v5.0"))
testCase.assertTrue(ismember("AnatomicalAtlas", typesInMemory()), ...
'v5.0 is pinned and declares AnatomicalAtlas; something changed it.')

% Held, as a session that has looked any type up holds it.
openminds.introspection.internal.MetaTypeRegistry.getSingleton();

testCase.applyFixture(ModelVersionFixture("v3.0"))

membersInMemory = typesInMemory();

testCase.verifyTrue(ismember("BrainAtlas", membersInMemory), ...
'The Types enumeration in memory must be the selected version''s.')
testCase.verifyFalse(ismember("AnatomicalAtlas", membersInMemory), ...
'The previous version''s Types enumeration must not stay in memory.')
end
end
end

function names = typesInMemory()
% typesInMemory - The Types enumeration as loaded, not as on the path
names = string({ ...
meta.class.fromName("openminds.enum.Types").EnumerationMemberList.Name});
end
Loading