matlab(tdcs): scenario derivation + derived data export
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
classdef tScenarioData < matlab.unittest.TestCase
|
||||
%TSCENARIODATA Tests for tdcs_scenario_data (Task 2).
|
||||
%
|
||||
% Authored per TDD: written before tdcs_scenario_data.m existed, so
|
||||
% it is expected to fail until the function is implemented. As of
|
||||
% this commit MATLAB is not licensed in this environment, so this
|
||||
% suite has been authored and reviewed by hand but has NOT been
|
||||
% executed. Expected per-scenario subject-per-group counts were
|
||||
% hand-derived from the Task 1 curated counts (Naive=4,
|
||||
% Electrode-Box-A2=3, Electrode-Box-B2=3, Electrode-Box-A=1,
|
||||
% Right-Electrode=1) plus each scenario's merge map, and cross-
|
||||
% checked against task-2-brief.md's table (see task-2-report.md).
|
||||
|
||||
properties (TestParameter)
|
||||
scenarioCase = struct( ...
|
||||
'unmerged_full', struct( ...
|
||||
'scenario', 'unmerged_full', ...
|
||||
'maxDay', 26, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A', 'Electrode-Box-A2', ...
|
||||
'Electrode-Box-B2', 'Naive', 'Right-Electrode'}, ...
|
||||
{1, 3, 3, 4, 1})), ...
|
||||
'unmerged_d0_10', struct( ...
|
||||
'scenario', 'unmerged_d0_10', ...
|
||||
'maxDay', 10, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A', 'Electrode-Box-A2', ...
|
||||
'Electrode-Box-B2', 'Naive', 'Right-Electrode'}, ...
|
||||
{1, 3, 3, 4, 1})), ...
|
||||
'mergeA2_full', struct( ...
|
||||
'scenario', 'mergeA2_full', ...
|
||||
'maxDay', 26, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A2', 'Electrode-Box-B2', 'Naive'}, ...
|
||||
{4, 4, 4})), ...
|
||||
'mergeA2_d0_10', struct( ...
|
||||
'scenario', 'mergeA2_d0_10', ...
|
||||
'maxDay', 10, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A2', 'Electrode-Box-B2', 'Naive'}, ...
|
||||
{4, 4, 4})), ...
|
||||
'mergeB2_full', struct( ...
|
||||
'scenario', 'mergeB2_full', ...
|
||||
'maxDay', 26, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A2', 'Electrode-Box-B2', 'Naive'}, ...
|
||||
{3, 5, 4})), ...
|
||||
'mergeB2_d0_10', struct( ...
|
||||
'scenario', 'mergeB2_d0_10', ...
|
||||
'maxDay', 10, ...
|
||||
'counts', containers.Map( ...
|
||||
{'Electrode-Box-A2', 'Electrode-Box-B2', 'Naive'}, ...
|
||||
{3, 5, 4})) ...
|
||||
)
|
||||
end
|
||||
|
||||
methods (Test)
|
||||
function testGroupCountsWindowAndReference(testCase, scenarioCase)
|
||||
[S, meta] = tdcs_scenario_data(scenarioCase.scenario);
|
||||
|
||||
% Day window.
|
||||
testCase.verifyEqual(meta.maxDay, scenarioCase.maxDay);
|
||||
testCase.verifyLessThanOrEqual(max(S.day), scenarioCase.maxDay);
|
||||
|
||||
% meta fields derived from the scenario name.
|
||||
expectedMergeKey = regexprep(scenarioCase.scenario, '_full$|_d0_10$', '');
|
||||
testCase.verifyEqual(meta.mergeKey, expectedMergeKey);
|
||||
testCase.verifyEqual(meta.isUnmerged, strcmp(expectedMergeKey, 'unmerged'));
|
||||
|
||||
% Reference (first) category of S.group is Electrode-Box-B2.
|
||||
allCats = categories(S.group);
|
||||
testCase.verifyEqual(allCats{1}, 'Electrode-Box-B2');
|
||||
|
||||
% Per-group subject counts.
|
||||
actualCounts = tScenarioData.localSubjectCountsByGroup(S);
|
||||
expectedCounts = scenarioCase.counts;
|
||||
|
||||
testCase.verifyEqual(actualCounts.Count, expectedCounts.Count);
|
||||
actualNames = keys(actualCounts);
|
||||
for i = 1:numel(actualNames)
|
||||
name = actualNames{i};
|
||||
testCase.verifyTrue(isKey(expectedCounts, name), ...
|
||||
sprintf('Unexpected group "%s" in scenario "%s".', ...
|
||||
name, scenarioCase.scenario));
|
||||
testCase.verifyEqual(actualCounts(name), expectedCounts(name), ...
|
||||
sprintf('Subject count mismatch for group "%s" in scenario "%s".', ...
|
||||
name, scenarioCase.scenario));
|
||||
end
|
||||
end
|
||||
|
||||
function testMergeB2FullCsvIsWrittenAndReloads(testCase)
|
||||
[S, ~] = tdcs_scenario_data('mergeB2_full');
|
||||
|
||||
thisDir = fileparts(mfilename('fullpath'));
|
||||
matlabDir = fileparts(thisDir);
|
||||
csvFile = fullfile(matlabDir, 'derived', 'mergeB2_full.csv');
|
||||
|
||||
testCase.verifyTrue(isfile(csvFile), ...
|
||||
'derived/mergeB2_full.csv was not written.');
|
||||
|
||||
Sreload = readtable(csvFile);
|
||||
Sreload.group = categorical(Sreload.group);
|
||||
|
||||
countsOrig = tScenarioData.localSubjectCountsByGroup(S);
|
||||
countsReload = tScenarioData.localSubjectCountsByGroup(Sreload);
|
||||
|
||||
testCase.verifyEqual(countsReload.Count, countsOrig.Count);
|
||||
namesOrig = keys(countsOrig);
|
||||
for i = 1:numel(namesOrig)
|
||||
name = namesOrig{i};
|
||||
testCase.verifyTrue(isKey(countsReload, name), ...
|
||||
sprintf('Group "%s" missing after CSV reload.', name));
|
||||
testCase.verifyEqual(countsReload(name), countsOrig(name), ...
|
||||
sprintf('Subject count mismatch for group "%s" after CSV reload.', name));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
methods (Static)
|
||||
function m = localSubjectCountsByGroup(T)
|
||||
%LOCALSUBJECTCOUNTSBYGROUP containers.Map group name -> #unique subjects.
|
||||
subjGroup = unique(T(:, {'subject', 'group'}));
|
||||
group = subjGroup.group;
|
||||
if ~iscategorical(group)
|
||||
group = categorical(group);
|
||||
end
|
||||
counts = countcats(group);
|
||||
catNames = categories(group);
|
||||
m = containers.Map('KeyType', 'char', 'ValueType', 'double');
|
||||
for i = 1:numel(catNames)
|
||||
m(catNames{i}) = counts(i);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user