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