From 08c1c576a8f24c6b0d49785cd80e7e1cc55b0282 Mon Sep 17 00:00:00 2001 From: Bernhard <90285552+4gwe@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:39:08 +0100 Subject: [PATCH 1/2] some test for pspm --- src/pspm_eye.m | 13 +- test/pspm_check_data_test | 224 ++++++++++++++++++++++++++ test/pspm_check_data_test.m | 211 ++++++++++++++++++++++++ test/pspm_eye_test.m | 163 +++++++++++++++++++ test/pspm_load_channel_test.m | 210 ++++++++++++++++++++++++ test/pspm_select_channels_test.m | 266 +++++++++++++++++++++++++++++++ test/pspm_time2index_test.m | 72 +++++++++ 7 files changed, 1155 insertions(+), 4 deletions(-) create mode 100644 test/pspm_check_data_test create mode 100644 test/pspm_check_data_test.m create mode 100644 test/pspm_eye_test.m create mode 100644 test/pspm_load_channel_test.m create mode 100644 test/pspm_select_channels_test.m create mode 100644 test/pspm_time2index_test.m diff --git a/src/pspm_eye.m b/src/pspm_eye.m index b894bf68..d7d7ef81 100644 --- a/src/pspm_eye.m +++ b/src/pspm_eye.m @@ -37,10 +37,15 @@ Y = settings.lateral.char.r; end case 'cell' - Y{Y=='l'} = settings.lateral.char.l; - Y{Y=='r'} = settings.lateral.char.r; - Y{Y=='lr'} = settings.lateral.char.c; - Y{Y=='rl'} = settings.lateral.char.c; + %Y{Y=='l'} = settings.lateral.char.l; + %Y{Y=='r'} = settings.lateral.char.r; + %Y{Y=='lr'} = settings.lateral.char.c; + %Y{Y=='rl'} = settings.lateral.char.c; + Y(strcmp(Y, 'l')) = {settings.lateral.char.l}; + Y(strcmp(Y, 'r')) = {settings.lateral.char.r}; + Y(strcmp(Y, 'lr')) = {settings.lateral.char.c}; + Y(strcmp(Y, 'rl')) = {settings.lateral.char.c}; + end case 'char2cell' % Examples diff --git a/test/pspm_check_data_test b/test/pspm_check_data_test new file mode 100644 index 00000000..8e6be3f0 --- /dev/null +++ b/test/pspm_check_data_test @@ -0,0 +1,224 @@ +classdef pspm_check_data_test < matlab.unittest.TestCase + % Testclass for pspm_check_data + % This class contains unit tests for the function pspm_check_data. + + + + + + + + + methods (Test) + function testValidData(testCase) + % Test pspm_check_data with valid data and infos structures. + + % Generate valid test data + duration = 10; % seconds + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; % sampling rate + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Call pspm_check_data + [sts, dataOut] = pspm_check_data(data, infos); + + % Verify that sts == 1 (success) + testCase.verifyEqual(sts, 1); + % Verify that dataOut is not empty + testCase.verifyNotEmpty(dataOut); + end + + function testMissingHeader(testCase) + % Test pspm_check_data with missing header field in data. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Remove header field + data{1} = rmfield(data{1}, 'header'); + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data + [sts, ~] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == -1 (failure) + testCase.verifyEqual(sts, -1); + end + + function testInvalidChantype(testCase) + % Test pspm_check_data with an invalid chantype. + + % Generate test data with invalid chantype + duration = 10; + channels{1}.chantype = 'invalid_type'; + channels{1}.sr = 100; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data + [sts, ~] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == -1 (failure) + testCase.verifyEqual(sts, -1); + end + + function testEmptyData(testCase) + % Test pspm_check_data with empty data field. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Make data field empty + data{1}.data = []; + + % Suppress expected warning + warning('off', 'ID:missing_data'); + + % Call pspm_check_data + [sts, dataOut] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:missing_data'); + + % Verify that sts == 1 (success despite empty data) + testCase.verifyEqual(sts, 1); + % Verify that dataOut{1}.data is zeros(1,0) + testCase.verifyEqual(dataOut{1}.data, zeros(1,0)); + end + + function testDataOrientation(testCase) + % Test pspm_check_data with data in wrong orientation (row vector). + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Transpose data to incorrect orientation + data{1}.data = data{1}.data'; + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data + [sts, dataOut] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == 1 (function corrects orientation) + testCase.verifyEqual(sts, 1); + % Verify that dataOut{1}.data is a column vector + testCase.verifySize(dataOut{1}.data, [length(dataOut{1}.data), 1]); + end + + function testEventDataOutOfRange(testCase) + % Test pspm_check_data with event data outside [0, infos.duration]. + + % Generate event-based test data + duration = 10; + channels{1}.chantype = 'marker'; + channels{1}.eventrt = 1; % events per second + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Modify event data to be out of range + data{1}.data = data{1}.data + duration + 1; + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data + [sts, ~] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == -1 (failure due to out-of-range data) + testCase.verifyEqual(sts, -1); + end + + function testMissingInfos(testCase) + % Test pspm_check_data without providing infos structure. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data without infos + [sts, ~] = pspm_check_data(data); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == 1 (infos is optional) + testCase.verifyEqual(sts, 1); + end + + function testInvalidInfos(testCase) + % Test pspm_check_data with invalid infos structure. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = struct(); % Empty infos structure + + % Suppress expected warning + warning('off', 'ID:invalid_data_structure'); + + % Call pspm_check_data + [sts, ~] = pspm_check_data(data, infos); + + % Re-enable warnings + warning('on', 'ID:invalid_data_structure'); + + % Verify that sts == -1 (failure due to invalid infos) + testCase.verifyEqual(sts, -1); + end + + end +end diff --git a/test/pspm_check_data_test.m b/test/pspm_check_data_test.m new file mode 100644 index 00000000..b4e4854a --- /dev/null +++ b/test/pspm_check_data_test.m @@ -0,0 +1,211 @@ +classdef pspm_check_data_test < matlab.unittest.TestCase +% ● Description +% unittest class for pspm_check_data, PsPM TestEnvironment +% ● History +% Written in 2024 by Bernhard Agoué von Raußendorf +% ● Developer's notes + + + +methods (Test) + function testValidDataTest(testCase) + % Test pspm_check_data with valid data and infos structures. + + % Generate valid test data + duration = 10; % seconds + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; % sampling rate + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + [sts, dataOut] = pspm_check_data(data, infos); + + testCase.verifyEqual(sts, 1); + testCase.verifyNotEmpty(dataOut); + end + function channeltype2chantypeTest(testCase) + % Test pspm_check_data channeltype to chantype + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; % sampling rate + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + % change chantype to channeltype + dataStruct.data{1, 1}.header.channeltype = dataStruct.data{1, 1}.header.chantype; + dataStruct.data{1, 1}.header = rmfield(dataStruct.data{1, 1}.header, 'chantype'); + + data = dataStruct.data; + infos = dataStruct.infos; + + [~ , dataOut] = pspm_check_data(data, infos); + + %dataOut{1, 1}.header + testCase.verifyTrue(isfield(dataOut{1, 1}.header,"chantype")) + end + function MissingHeaderFieldsTest(testCase) + % Test pspm_check_data with missing required fields in the header. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Remove the 'chantype' field from the header + data{1}.header = rmfield(data{1}.header, 'chantype'); + + [sts, dataOut] = pspm_check_data(data, infos); + + % Verify that the status indicates an error (-1) + testCase.verifyEqual(sts, -1); + % Optionally, verify that an appropriate warning was issued + % (requires capturing warnings) + end + function UnknownChannelTypeTest(testCase) + % Test pspm_check_data with an unknown channel type. + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + dataStruct.data{1, 1}.header.chantype = 'unknow channeltype'; + + data = dataStruct.data; + infos = dataStruct.infos; + + [sts, ~ ] = pspm_check_data(data, infos); + + + testCase.verifyEqual(sts, -1); % maybe check over warrning ID? + end + function EmptyDataTest(testCase) + % Test pspm_check_data with empty data field. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + data{1,1}.data = []; + + [sts, dataOut] = pspm_check_data(data, infos); + + testCase.verifyEqual(sts, -1); % maybe check over warrning ID? + end + function IncorrectDataOrientationTest(testCase) + % Test pspm_check_data with data in incorrect orientation. + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Data converted into a row vector + data{1}.data = data{1}.data'; + + [sts, dataOut] = pspm_check_data(data, infos); + + % Verify pspm_check_data transposed the data back and sts remains 1 + testCase.verifyEqual(size(dataOut{1}.data, 1), length(data{1}.data)); + testCase.verifyEqual(size(dataOut{1}.data, 2), 1); + testCase.verifyEqual(sts, 1); + end + function DataOutOfRangeTest(testCase) + % Test pspm_check_data with data exceeding infos.duration. + + + % Generate valid test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Extend the data beyond the expected duration + extraSamples = 50; % number of extra samples + data{1}.data = [data{1}.data; zeros(extraSamples, 1)]; + + [sts, DataOut ] = pspm_check_data(data, infos); + + + % Data was not changed + testCase.verifyEqual(size(data{1}.data,1), size(DataOut{1}.data,1)) + testCase.verifyEqual(sts, -1); + end + function InvalidDataTypesTest(testCase) + % Test pspm_check_data with invalid data types in the data field. + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + % Set data field to a non-numeric type string + data{1}.data = 'invalid data'; + + [sts, ~] = pspm_check_data(data, infos); + testCase.verifyEqual(sts, -1); + + end + + function MultipleChannelsTest(testCase) + % Test pspm_check_data with multiple channels. + % This checks if the function can handle and process multiple channels correctly. + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.sr = 200; + channels{2}.units = 'mV'; + + dataStruct = pspm_testdata_gen(channels, duration); + + data = dataStruct.data; + infos = dataStruct.infos; + + [sts, dataOut] = pspm_check_data(data, infos); + + % Verify that sts is 1, indicating successful validation of multiple channels + testCase.verifyEqual(sts, 1); + % Verify that both channels are present in the output + testCase.verifyEqual(numel(dataOut), 2); + % Verify that each channel has the correct sampling rate and units + testCase.verifyEqual(dataOut{1}.header.sr, 100); + testCase.verifyEqual(dataOut{1}.header.units, 'microsiemens'); + testCase.verifyEqual(dataOut{2}.header.sr, 200); + testCase.verifyEqual(dataOut{2}.header.units, 'mV'); + end + +end +end diff --git a/test/pspm_eye_test.m b/test/pspm_eye_test.m new file mode 100644 index 00000000..2f85b065 --- /dev/null +++ b/test/pspm_eye_test.m @@ -0,0 +1,163 @@ +classdef pspm_eye_test < matlab.unittest.TestCase + % Unit tests for the pspm_eye function + + methods (Test) + + function test_lr2c_char(testCase) + % Test 'lr2c' feature with character inputs + + % Test inputs + input1 = 'l'; + input2 = 'R'; + input3 = 'lr'; + input4 = 'rL'; + + % Expected outputs + expected1 = 'l'; + expected2 = 'r'; + expected3 = 'c'; + expected4 = 'c'; + + % Verify conversions + testCase.verifyEqual(pspm_eye(input1, 'lr2c'), expected1); + testCase.verifyEqual(pspm_eye(input2, 'lr2c'), expected2); + testCase.verifyEqual(pspm_eye(input3, 'lr2c'), expected3); + testCase.verifyEqual(pspm_eye(input4, 'lr2c'), expected4); + end + + function test_lr2c_cell(testCase) + % Test 'lr2c' feature with cell array inputs + + % Test input + input = {'L', 'r', 'Lr', 'rl'}; + % Expected output + expected = {'l', 'r', 'c', 'c'}; + + % Verify conversion + result = pspm_eye(input, 'lr2c'); + testCase.verifyEqual(result, expected); + end + + function test_char2cell_single(testCase) + % Test 'char2cell' feature with single character inputs + + % Test inputs + input1 = 'l'; + input2 = 'R'; + input3 = 'C'; + input4 = 'lR'; + + % Expected outputs + expected1 = {'l'}; + expected2 = {'r'}; + expected3 = {'l', 'r'}; + expected4 = {'l', 'r'}; + + + % Verify conversions + testCase.verifyEqual(pspm_eye(input1, 'char2cell'), expected1); + testCase.verifyEqual(pspm_eye(input2, 'char2cell'), expected2); + testCase.verifyEqual(pspm_eye(input3, 'char2cell'), expected3); + testCase.verifyEqual(pspm_eye(input4, 'char2cell'), expected4); + end + + function test_char2cell_combined(testCase) + % Test 'char2cell' feature with combined characters + + % Test inputs + input1 = 'lr'; + input2 = 'RL'; + + % Expected output + expected = {'l', 'r'}; + + % Verify conversions + testCase.verifyEqual(pspm_eye(input1, 'char2cell'), expected); + testCase.verifyEqual(pspm_eye(input2, 'char2cell'), expected); + end + + function test_channel2lateral_char(testCase) + % Test 'channel2lateral' feature with single channel name inputs + + % Test inputs + input1 = 'pupil_l'; + input2 = 'gaze_x_r'; + input3 = 'gaze_y_lr'; + input4 = 'something_y_rl'; + input5 = 'pupil_c'; + + % Expected outputs + expected1 = 'l'; + expected2 = 'r'; + expected3 = 'c'; + expected4 = 'c'; + expected5 = 'c'; + + % Verify conversions + testCase.verifyEqual(pspm_eye(input1, 'channel2lateral'), expected1); + testCase.verifyEqual(pspm_eye(input2, 'channel2lateral'), expected2); + testCase.verifyEqual(pspm_eye(input3, 'channel2lateral'), expected3); + testCase.verifyEqual(pspm_eye(input4, 'channel2lateral'), expected4); + testCase.verifyEqual(pspm_eye(input5, 'channel2lateral'), expected5); + end + + function test_channel2lateral_cell(testCase) + % Test 'channel2lateral' feature with cell array of channel names + + % Test input + input = {'pupil_r', 'gaze_y_l', 'gaze_x_rl', 'pupil_c', 'gaze_x_lr'}; + + % Expected output + expected = {'r', 'l', 'c', 'c', 'c'}; + + % Verify conversion + result = pspm_eye(input, 'channel2lateral'); + testCase.verifyEqual(result, expected); + end + + function test_channel2lateral_char_wrong(testCase) + % Test 'channel2lateral' feature with single wrong channel name + + input1 = 'pupil_'; + expected1 = {}; + % Verify conversions + testCase.verifyEqual(pspm_eye(input1, 'channel2lateral'), expected1); + end + + function test_channel2lateral_cell_wrong(testCase) + % Test 'channel2lateral' feature with cell array of wrong channel names + + % Test input + input = {'pupilr', 'gaze_yl', 'gaze_x_r_l', 'pupil_C', 'gaze_x_lR'}; + + % Expected output + expected = {{}, {}, 'l', 'c', 'c'}; + + % Verify conversion + result = pspm_eye(input, 'channel2lateral'); + testCase.verifyEqual(result, expected); + end + + function test_channel2lateral_cell_char_UPPERCASE(testCase) + % Test 'channel2lateral' feature with cell array of channel names + + % Test input + input1 = {'pupil_x_R', 'gaze_y_LR', 'gaze_x_RL', 'pupil_C', 'gaze_x_L'}; + input2 = 'pupil_x_RL'; + + % Expected output + expected1 = {'r', 'c', 'c', 'c', 'l'}; + expected2 = 'c'; + + % Verify conversion + + testCase.verifyEqual(pspm_eye(input1, 'channel2lateral'), expected1); + + result = pspm_eye(input2, 'channel2lateral'); + testCase.verifyEqual(result, expected2); + + end + + + end +end diff --git a/test/pspm_load_channel_test.m b/test/pspm_load_channel_test.m new file mode 100644 index 00000000..f7ee92cc --- /dev/null +++ b/test/pspm_load_channel_test.m @@ -0,0 +1,210 @@ +classdef pspm_load_channel_test < matlab.unittest.TestCase +% ● Description +% unittest class for pspm_load_channel, PsPM TestEnvironment +% ● History +% Written in 2024 by Bernhard Agoué von Raußendorf +% ● Developer's notes + +% pspm_load_channel_test overwrite if file already exist or clean up?? + +methods (Test) + + function TestValidNumericChannel(testCase) + % Test loading a channel by valid numeric index + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.sr = 200; + channels{2}.units = 'bpm'; + dataStruct = pspm_testdata_gen(channels, duration); + + fn = 'temp_test.mat'; + save(fn, '-struct', 'dataStruct'); + + % Load channel by numeric index + [sts, data_struct, infos, pos_of_channel] = pspm_load_channel(fn, 2); + + % Verifing + testCase.verifyEqual(sts, 1); + testCase.verifyEqual(pos_of_channel, 2); + testCase.verifyEqual(data_struct.header.chantype, 'hr'); + + % Clean up + delete([fn]); + end + function TestValidChannelType(testCase) + % Test loading a channel by channel type string + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.sr = 200; + channels{2}.units = 'bpm'; + dataStruct = pspm_testdata_gen(channels, duration); + + fn = 'temp_test2.mat'; + save(fn, '-struct', 'dataStruct'); + + % Load channel by channel type + [sts, data_struct, infos, pos_of_channel] = pspm_load_channel(fn, 'hr'); + + % Verify the status + testCase.verifyEqual(sts, 1); + testCase.verifyEqual(data_struct.header.chantype, 'hr'); + + % Clean up + delete([fn ]); + end + function TestChannelWithUnits(testCase) + % Test loading a channel specifying both channel type and units + + % Create test data with specific units + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'scr'; + channels{2}.sr = 100; + channels{2}.units = 'unknown'; + dataStruct = pspm_testdata_gen(channels, duration); + + % Save dataStruct to a temporary file + fn = 'temp_test.mat'; + save(fn, '-struct', 'dataStruct'); + + % Define channel as struct with units + channel.channel = 'scr'; + channel.units = 'microsiemens'; + + % Load channel + [sts, data_struct, infos, pos_of_channel] = pspm_load_channel(fn, channel); + + % Verify the status + testCase.verifyEqual(sts, 1); + % Verify the correct channel is loaded + testCase.verifyEqual(data_struct.header.units, 'microsiemens'); + + % Clean up + delete([fn]); + end + function TestInvalidChannelNumberError(testCase) + % Test error handling when an invalid channel number is provided + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + dataStruct = pspm_testdata_gen(channels, duration); + + % Save dataStruct to a temporary file + fn = 'temp.mat'; + save(fn, '-struct', 'dataStruct'); + + % Attempt to load a non-existent channel + [sts, ~ , ~ , ~ ] = pspm_load_channel(fn, 5); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + + % Clean up + delete([fn]); + end + function TestInvalidChannelTypeError(testCase) + % Test error handling when an invalid channel type is provided + + duration = 10; + channels{1}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + + fn = 'temp.mat'; + save(fn, '-struct', 'dataStruct'); + + [sts, ~, ~, ~] = pspm_load_channel(fn, 'invalid_type'); + + testCase.verifyEqual(sts, -1); + delete([fn]); + + end + + + function TestMultipleChannels(testCase) + % Test loading when multiple channels of the same type exist + + % Create test data with multiple 'scr' channels + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.sr = 100; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'scr'; + channels{2}.sr = 100; + channels{2}.units = 'microsiemens'; + channels{3}.chantype = 'scr'; + channels{3}.sr = 100; + channels{3}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + fn = 'temp.mat'; + save(fn, '-struct', 'dataStruct'); + + [sts, data_struct, infos, pos_of_channel] = pspm_load_channel(fn, 'scr'); + + % Verify the status + testCase.verifyEqual(sts, 1); + testCase.verifyEqual(pos_of_channel, 3); + + % Clean up + delete([fn]); + end + function TestNoChannelsAvailableError(testCase) + % Test behavior when no channels are available in the data + + dataStruct.infos.duration = 10; + dataStruct.infos.durationinfo = 'Duration in seconds'; + dataStruct.data = {}; + + % Save dataStruct to a temporary file + fn = 'temp.mat'; + save(fn, '-struct', 'dataStruct'); + + [sts, ~, ~, ~] = pspm_load_channel(fn, 1); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + + % Clean up + delete([fn]); + end + + function TestUnitsMismatchError(testCase) + % Test behavior when units do not match any channel + + % Create test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + + % Save dataStruct to a temporary file + fn = 'temp.mat'; + save(fn, '-struct', 'dataStruct'); + + % Define channel with units that do not match + channel.channel = 'scr'; + channel.units = 'unknown_units'; + + % Attempt to load the channel + [sts, ~, ~, ~] = pspm_load_channel(fn, channel); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + + % Clean up + delete([fn '.mat']); + end + +end +end diff --git a/test/pspm_select_channels_test.m b/test/pspm_select_channels_test.m new file mode 100644 index 00000000..65f92526 --- /dev/null +++ b/test/pspm_select_channels_test.m @@ -0,0 +1,266 @@ +classdef pspm_select_channels_test < matlab.unittest.TestCase + % Unit tests for the pspm_select_channels function + +methods (Test) + function TestNumericChannelSelection(testCase) + % Test selecting channels using numeric indices + + % Create test data with multiple channels + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.units = 'bpm'; + channels{3}.chantype = 'resp'; + channels{3}.units = 'arbitrary'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Select channels 1 and 3 + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 2); + + % Verify the status + testCase.verifyEqual(sts, 1); + % Verify that the correct channel nad units are selected + testCase.verifyEqual(pos_of_channels, 2); + testCase.verifyEqual(selected_data{1}.header.chantype, 'hr'); + testCase.verifyEqual(selected_data{1}.header.units, 'bpm'); + + end + function TestNumericChannelSelectionVector(testCase) + % Test selecting channels using numeric indices + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.units = 'bpm'; + channels{3}.chantype = 'resp'; + channels{3}.units = 'arbitrary'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Select channels 1 and 3 + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, [1, 3]); + + % Verify the status + testCase.verifyEqual(sts, 1); + % Verify that the correct channels are selected + testCase.verifyEqual(pos_of_channels, [1, 3]); + testCase.verifyEqual(selected_data{1}.header.chantype, 'scr'); + testCase.verifyEqual(selected_data{2}.header.chantype, 'resp'); + end + function TestValidChannelType(testCase) + % Test selecting channels by specifying a valid channel type + + % Create test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{2}.chantype = 'scr'; + channels{3}.chantype = 'hr'; + channels{4}.chantype = 'hr'; + channels{5}.chantype = 'hr'; + % Units unkown + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Select 'scr' channels + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 'scr'); + + % Verify the status + testCase.verifyEqual(sts, 1); + % Verify that both 'scr' channels are selected + testCase.verifyEqual(numel(selected_data), 2); + testCase.verifyEqual(selected_data{1}.header.chantype, 'scr'); + testCase.verifyEqual(selected_data{2}.header.chantype, 'scr'); + end + function TestChannelWithUnits(testCase) + % Test selecting channels by specifying channel type and units + + % Create test data with specific units + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'scr'; + channels{2}.units = 'unknown'; + channels{3}.chantype = 'hr'; + channels{3}.units = 'bpm'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Select 'scr' channels with units 'microsiemens' + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 'scr', 'microsiemens'); + + % Verify the status + testCase.verifyEqual(sts, 1); + % Verify that only the correct channel is selected + testCase.verifyEqual(numel(selected_data), 1); + testCase.verifyEqual(selected_data{1}.header.units, 'microsiemens'); + end + function TestNumericChannelSelectionError(testCase) + % Test handling of invalid channel numbers + + % Create test data with two channels + duration = 10; + channels{1}.chantype = 'scr'; + channels{2}.chantype = 'hr'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Attempt to select a non-existent channel number + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 5); + + testCase.verifyEqual(sts, -1); + % All the data will be selected + testCase.verifyEqual(numel(data), numel(selected_data)); + testCase.verifyEqual(5,pos_of_channels ) + + end + function TestNumericChannelSelectionVectorOneValedOneInvaledError(testCase) + % Test handling of one valid and one invalid channel numbers + % (vector) + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.units = 'bpm'; + channels{3}.chantype = 'resp'; + channels{3}.units = 'arbitrary'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + selction = [1,5]; + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, selction); + + testCase.verifyEqual(sts, -1); + % All the data will passed through! + testCase.verifyEqual(numel(data), numel(selected_data)); + testCase.verifyEqual(selction,pos_of_channels ) + + end + function TestNumericChannelSelectionVectorMultipleInvaledError(testCase) + % Test handling of invalid channel numbers + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + channels{2}.chantype = 'hr'; + channels{2}.units = 'bpm'; + channels{3}.chantype = 'resp'; + channels{3}.units = 'arbitrary'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + selction = [5,6,9]; + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, selction); + + testCase.verifyEqual(sts, -1); + % All the data will passed through! + testCase.verifyEqual(numel(data), numel(selected_data)); + testCase.verifyEqual(selction,pos_of_channels ) + + end + function TestInvalidChannelTypeError(testCase) + % Test handling of invalid channel type + + duration = 10; + channels{1}.chantype = 'scr'; + channels{2}.chantype = 'hr'; + channels{3}.chantype = 'hr'; + + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Attempt to select an invalid channel type + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 'invalid_type'); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + % All the data will be selected + testCase.verifyEqual(numel(data), numel(selected_data)); + % No channel selected + testCase.verifyFalse(any(pos_of_channels)) + + end + function TestNoMatchingChannelsError(testCase) + % Test behavior when no channels match the criteria + + % Create test data + duration = 10; + channels{1}.chantype = 'scr'; + channels{2}.chantype = 'scr'; + channels{3}.chantype = 'scr'; + channels{4}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Attempt to select a channel type that doesn't exist + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 'hr'); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + % All the data will be selected + testCase.verifyEqual(numel(data), numel(selected_data)); + % No channel selected + testCase.verifyFalse(any(pos_of_channels)) + end + function TestUnitsMismatchError(testCase) + % Test behavior when units do not match any channel + + duration = 10; + channels{1}.chantype = 'scr'; + channels{1}.units = 'microsiemens'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Attempt to select 'scr' channels with units 'unknown' + [sts, selected_data, pos_of_channels] = pspm_select_channels(data, 'scr', 'unknown'); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + % All the data will be selected + testCase.verifyEqual(numel(data), numel(selected_data)); + % No channel selected + testCase.verifyFalse(any(pos_of_channels)) + end + function TestNegativeChannelNumberError(testCase) + % Test handling of negative channel numbers + + % Create test data + duration = 10; + channels{1}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + % Attempt to select a negative channel number + [sts,selected_data, pos_of_channels] = pspm_select_channels(data, -1); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + % All the data will be selected + testCase.verifyEqual(numel(data), numel(selected_data)); + % No channel selected + testCase.verifyFalse(any(pos_of_channels)) + end + function TestNegativeChannelNumberVectorError(testCase) + % Test handling of negative channel numbers + + % Create test data + duration = 10; + channels{1}.chantype = 'scr'; + dataStruct = pspm_testdata_gen(channels, duration); + data = dataStruct.data; + + selction = [-21,-2,-3]; + [sts,selected_data, pos_of_channels] = pspm_select_channels(data, selction); + + % Verify the status indicates failure + testCase.verifyEqual(sts, -1); + + + end + + +end +end diff --git a/test/pspm_time2index_test.m b/test/pspm_time2index_test.m new file mode 100644 index 00000000..3116f93f --- /dev/null +++ b/test/pspm_time2index_test.m @@ -0,0 +1,72 @@ +classdef pspm_time2index_test < matlab.unittest.TestCase + % Unit tests for the pspm_time2index function + +methods (Test) + function TestBasicTimeConversion(testCase) + % Verify basic time to index conversion with default parameters + + time = [0, 0.1, 0.2, 0.3, 0.4]; + sr = 10; + + expected_indices = [1, 2, 3, 4, 5]; + index = pspm_time2index(time, sr); + + testCase.verifyEqual(index, expected_indices); + end + function TestWithDataLength(testCase) + % Ensure indices are capped at the specified data length + + time = [0, 0.1, 0.2, 0.3, 0.4, 0.5]; + sr = 10; + data_length = 4; + + expected_indices = [1, 2, 3, 4, 4, 4]; + + index = pspm_time2index(time, sr, data_length); + + testCase.verifyEqual(index, expected_indices); + end + function TestDurationConversion(testCase) + % Test conversion when is_duration is set to 1 + + time = [0.05, 0.15, 0.25]; + sr = 20; + is_duration = 1; + data_length = inf; + + expected_indices = [1, 3, 5]; + + duration = pspm_time2index(time, sr, data_length, is_duration); + + % Verify the duration in (samples) + testCase.verifyEqual(duration, expected_indices); + end + function TestTimeBeyondDataLength(testCase) + % Test times that result in indices beyond the data length + + time = [0.2, 0.4, 0.6, 0.8, 1.0]; + sr = 5; + data_length = 3; + + % Expected indices (capped at data_length) + expected_indices = [2, 3, 3, 3, 3]; + + index = pspm_time2index(time, sr, data_length); + + testCase.verifyEqual(index, expected_indices); + end + function TestMatrixInput(testCase) + % Test function with matrix inputs for time + + time = [0.1, 0.2; 0.3, 0.4]; + sr = 10; + + expected_indices = [2, 3; 4, 5]; + + index = pspm_time2index(time, sr); + + testCase.verifyEqual(index, expected_indices); + end + +end +end \ No newline at end of file From f842b8c4b1c359f4e89d9e24b0ecd2e3fd278c9b Mon Sep 17 00:00:00 2001 From: Dominik Bach Date: Mon, 28 Oct 2024 14:29:27 +0100 Subject: [PATCH 2/2] delete orphaned file --- test/pspm_check_data_test | 224 -------------------------------------- 1 file changed, 224 deletions(-) delete mode 100644 test/pspm_check_data_test diff --git a/test/pspm_check_data_test b/test/pspm_check_data_test deleted file mode 100644 index 8e6be3f0..00000000 --- a/test/pspm_check_data_test +++ /dev/null @@ -1,224 +0,0 @@ -classdef pspm_check_data_test < matlab.unittest.TestCase - % Testclass for pspm_check_data - % This class contains unit tests for the function pspm_check_data. - - - - - - - - - methods (Test) - function testValidData(testCase) - % Test pspm_check_data with valid data and infos structures. - - % Generate valid test data - duration = 10; % seconds - channels{1}.chantype = 'scr'; - channels{1}.sr = 100; % sampling rate - channels{1}.units = 'microsiemens'; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Call pspm_check_data - [sts, dataOut] = pspm_check_data(data, infos); - - % Verify that sts == 1 (success) - testCase.verifyEqual(sts, 1); - % Verify that dataOut is not empty - testCase.verifyNotEmpty(dataOut); - end - - function testMissingHeader(testCase) - % Test pspm_check_data with missing header field in data. - - % Generate valid test data - duration = 10; - channels{1}.chantype = 'scr'; - channels{1}.sr = 100; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Remove header field - data{1} = rmfield(data{1}, 'header'); - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data - [sts, ~] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == -1 (failure) - testCase.verifyEqual(sts, -1); - end - - function testInvalidChantype(testCase) - % Test pspm_check_data with an invalid chantype. - - % Generate test data with invalid chantype - duration = 10; - channels{1}.chantype = 'invalid_type'; - channels{1}.sr = 100; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data - [sts, ~] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == -1 (failure) - testCase.verifyEqual(sts, -1); - end - - function testEmptyData(testCase) - % Test pspm_check_data with empty data field. - - % Generate valid test data - duration = 10; - channels{1}.chantype = 'scr'; - channels{1}.sr = 100; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Make data field empty - data{1}.data = []; - - % Suppress expected warning - warning('off', 'ID:missing_data'); - - % Call pspm_check_data - [sts, dataOut] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:missing_data'); - - % Verify that sts == 1 (success despite empty data) - testCase.verifyEqual(sts, 1); - % Verify that dataOut{1}.data is zeros(1,0) - testCase.verifyEqual(dataOut{1}.data, zeros(1,0)); - end - - function testDataOrientation(testCase) - % Test pspm_check_data with data in wrong orientation (row vector). - - % Generate valid test data - duration = 10; - channels{1}.chantype = 'scr'; - channels{1}.sr = 100; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Transpose data to incorrect orientation - data{1}.data = data{1}.data'; - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data - [sts, dataOut] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == 1 (function corrects orientation) - testCase.verifyEqual(sts, 1); - % Verify that dataOut{1}.data is a column vector - testCase.verifySize(dataOut{1}.data, [length(dataOut{1}.data), 1]); - end - - function testEventDataOutOfRange(testCase) - % Test pspm_check_data with event data outside [0, infos.duration]. - - % Generate event-based test data - duration = 10; - channels{1}.chantype = 'marker'; - channels{1}.eventrt = 1; % events per second - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = dataStruct.infos; - - % Modify event data to be out of range - data{1}.data = data{1}.data + duration + 1; - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data - [sts, ~] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == -1 (failure due to out-of-range data) - testCase.verifyEqual(sts, -1); - end - - function testMissingInfos(testCase) - % Test pspm_check_data without providing infos structure. - - % Generate valid test data - duration = 10; - channels{1}.chantype = 'scr'; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data without infos - [sts, ~] = pspm_check_data(data); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == 1 (infos is optional) - testCase.verifyEqual(sts, 1); - end - - function testInvalidInfos(testCase) - % Test pspm_check_data with invalid infos structure. - - % Generate valid test data - duration = 10; - channels{1}.chantype = 'scr'; - dataStruct = pspm_testdata_gen(channels, duration); - - data = dataStruct.data; - infos = struct(); % Empty infos structure - - % Suppress expected warning - warning('off', 'ID:invalid_data_structure'); - - % Call pspm_check_data - [sts, ~] = pspm_check_data(data, infos); - - % Re-enable warnings - warning('on', 'ID:invalid_data_structure'); - - % Verify that sts == -1 (failure due to invalid infos) - testCase.verifyEqual(sts, -1); - end - - end -end