Skip to content

Commit c2d3ab5

Browse files
k1o0Jai Bhagat
authored andcommitted
setValuesTest (#162) squash and rebase onto dev
* Started setVals test for param editor * Finished ParamEditor tests; changed Timeline flags to switches
1 parent 92d5ec6 commit c2d3ab5

File tree

4 files changed

+119
-43
lines changed

4 files changed

+119
-43
lines changed

+hw/TLOutput.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@
2828
% 2018-01 NS created
2929

3030
properties
31-
Name % The name of the timeline output, for easy identification
32-
Enable = true % Will not do anything with it unless this is true
33-
Verbose = false % Flag to output status updates. Initialization message outputs regardless of verbose.
31+
% The name of the timeline output, for easy identification
32+
Name
33+
% Will not do anything with it unless this is true
34+
Enable matlab.lang.OnOffSwitchState = 'on'
35+
% Flag to output status updates. Initialization message outputs
36+
% regardless of verbose.
37+
Verbose matlab.lang.OnOffSwitchState = 'off'
3438
end
3539

3640
properties (Transient, Hidden, Access = protected)
37-
Session % Holds an NI DAQ session object
41+
% Holds an NI DAQ session object
42+
Session
3843
end
3944

4045
methods (Abstract)

+hw/Timeline.m

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,44 +67,81 @@
6767
% 2017-10 MW updated
6868

6969
properties
70-
DaqVendor = 'ni' % 'ni' is using National Instruments USB-6211 DAQ
71-
DaqIds = 'Dev1' % Device ID can be found with daq.getDevices()
72-
DaqSampleRate = 1000 % rate at which daq aquires data in Hz, see Rate
73-
DaqSamplesPerNotify % determines the number of data samples to be processed each time, see Timeline.process(), constructor and NotifyWhenDataAvailableExceeds
74-
Outputs = hw.TLOutputChrono % array of output classes, defining any signals you desire to be sent from the daq. See Also HW.TLOUTPUT, HW.TLOUTPUTCLOCK
70+
% 'ni' is using National Instruments USB-6211 DAQ
71+
DaqVendor = 'ni'
72+
% Device ID can be found with daq.getDevices()
73+
DaqIds = 'Dev1'
74+
% rate at which daq aquires data in Hz, see Rate
75+
DaqSampleRate = 1000
76+
% determines the number of data samples to be processed each time,
77+
% see Timeline.process(), constructor and
78+
% NotifyWhenDataAvailableExceeds
79+
DaqSamplesPerNotify
80+
% array of output classes, defining any signals you desire to be
81+
% sent from the daq. See Also HW.TLOUTPUT, HW.TLOUTPUTCLOCK
82+
Outputs = hw.TLOutputChrono
83+
% All configured inputs.
7584
Inputs = struct('name', 'chrono',...
76-
'arrayColumn', -1,... % -1 is default indicating unused, this is update when the channels are added during tl.start()
85+
'arrayColumn', -1,... -1 is default indicating unused, this is update when the channels are added during tl.start()
7786
'daqChannelID', 'ai0',...
7887
'measurement', 'Voltage',...
7988
'terminalConfig', 'SingleEnded',...
8089
'axesScale', 1) % multiplicative vertical scaling for when live plotting the input
81-
UseInputs = {'chrono'} % array of inputs to record while tl is running
82-
StopDelay = 2 % currently pauses for at least 2 secs as 'hack' before stopping main DAQ session to allow
83-
MaxExpectedDuration = 2*60*60 % expected experiment time so data structure is initialised to sensible size (in secs)
84-
AquiredDataType = 'double' % default data type for the acquired data array (i.e. Data.rawDAQData)
85-
UseTimeline = false % used by expServer. If true, timeline is started by default (otherwise can be toggled with the t key)
86-
LivePlot = false % if true the data are plotted as the data are aquired
87-
FigureScale = [0 0 1 1]; % figure position in normalized units, default is full screen
88-
WriteBufferToDisk = false % if true the data buffer is written to disk as they're aquired NB: in the future this will happen by default
90+
% array of inputs to record while tl is running
91+
UseInputs = {'chrono'}
92+
% currently pauses for at least 2 secs as 'hack' before stopping
93+
% main DAQ session to allow
94+
StopDelay = 2
95+
% expected experiment time so data structure is initialised to
96+
% sensible size (in secs)
97+
MaxExpectedDuration = 2*60*60
98+
% default data type for the acquired data array (i.e.
99+
% Data.rawDAQData)
100+
AquiredDataType = 'double'
101+
% If true, timeline is started by default (otherwise can be toggled
102+
% with the t key in expServer)
103+
UseTimeline matlab.lang.OnOffSwitchState = 'off'
104+
% if true the data are plotted as the data are aquired
105+
LivePlot matlab.lang.OnOffSwitchState = 'off'
106+
% figure position in normalized units, default is full screen
107+
FigureScale = [0 0 1 1]
108+
% if true the data buffer is written to disk as they're aquired NB:
109+
% in the future this will happen by default
110+
WriteBufferToDisk matlab.lang.OnOffSwitchState = 'off'
89111
end
90112

91113
properties (Dependent)
92-
SamplingInterval % defined as 1/DaqSampleRate
93-
IsRunning = false % flag is set to true when the first chrono pulse is aquired and set to false when tl is stopped (and everything saved), see tl.process and tl.stop
114+
% Sampling interval defined as 1/DaqSampleRate
115+
SamplingInterval
116+
% Switch set to true when the first chrono pulse is aquired and
117+
% set to false when tl is stopped (and everything saved), see
118+
% tl.process and tl.stop
119+
IsRunning matlab.lang.OnOffSwitchState = 'off'
94120
end
95121

96122
properties (Transient, Access = protected)
97-
Listener % holds the listener for 'DataAvailable', see DataAvailable and Timeline.process()
98-
LastTimestamp % the last timestamp returned from the daq during the DataAvailable event. Used to check sampling continuity, see tl.process()
99-
Ref % the expRef string. See tl.start()
100-
AlyxInstance % a struct contraining the Alyx token, user and url for ile registration. See tl.start()
101-
Data % A structure containing timeline data
102-
Axes % A figure handle for plotting the aquired data as it's processed
103-
DataFID % The data file ID for writing aquired data directly to disk
123+
% holds the listener for 'DataAvailable', see DataAvailable and
124+
% Timeline.process()
125+
Listener
126+
% the last timestamp returned from the daq during the DataAvailable
127+
% event. Used to check sampling continuity, see tl.process()
128+
LastTimestamp
129+
% the expRef string. See tl.start()
130+
Ref
131+
% a struct contraining the Alyx token, user and url for ile
132+
% registration. See tl.start()
133+
AlyxInstance
134+
% A structure containing timeline data
135+
Data
136+
% A figure handle for plotting the aquired data as it's processed
137+
Axes
138+
% The data file ID for writing aquired data directly to disk
139+
DataFID
104140
end
105141

106142
properties (Transient, SetAccess = protected, GetAccess = {?hw.Timeline, ?hw.TLOutput})
107-
Sessions = containers.Map % map of daq sessions and their channels, created at tl.start()
143+
% Map of daq sessions and their channels, created at tl.start()
144+
Sessions = containers.Map
108145
end
109146

110147
methods

tests/ParamEditor_test.m

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
classdef (SharedTestFixtures={matlab.unittest.fixtures.PathFixture(...
2-
[fileparts(mfilename('fullpath')) '\fixtures'])})... % add 'fixtures' folder as test fixture
1+
classdef (SharedTestFixtures={ % add 'fixtures' folder as test fixture
2+
matlab.unittest.fixtures.PathFixture('fixtures'),...
3+
matlab.unittest.fixtures.PathFixture(['fixtures' filesep 'util'])})...
34
ParamEditor_test < matlab.unittest.TestCase
45

56
properties
@@ -259,11 +260,45 @@ function test_deleteCondition(testCase)
259260
[PE.Parameters.numTrialConditions, numel(PE.Parameters.TrialSpecificNames)])
260261
end
261262

262-
function test_setValues(testCase)
263-
% TODO Add test for the set values button. For now let's fail this
263+
function test_setSelectedValues(testCase)
264+
% (1:10:100) % Sets selected rows to [1 11 21 31 41 51 61 71 81 91]
265+
% @(~)randi(100) % Assigned random integer to each selected row
266+
% @(a)a*50 % Multiplies each condition value by 50
267+
% false % Sets all selected rows to false
264268
testCase.assertTrue(~testCase.Changed, 'Changed flag incorrect')
265-
% PE = testCase.ParamEditor;
266-
testCase.assertTrue(false, 'Test not implemented')
269+
mock = MockDialog.instance('char');
270+
mock.InTest = true;
271+
mock.UseDefaults = false;
272+
mock.Dialogs('Set values') = fun.CellSeq.create({'(1:10:100)', '@(~)randi(100)', '@(a)a*50'});
273+
274+
% Select some cells to set
275+
event.Indices = [(1:5)' ones(5,1)*4];
276+
selection_fn = testCase.Table.CellSelectionCallback;
277+
selection_fn([],event)
278+
279+
% Retrieve function handle for set condition
280+
callback_fn = pick(findobj(testCase.Figure,...
281+
'String', 'Set values'), 'Callback');
282+
callback_fn()
283+
284+
% Verify Changed event triggered
285+
testCase.verifyTrue(testCase.Changed, ...
286+
'Failed to notify listeners of parameter change')
287+
288+
P = testCase.ParamEditor.Parameters;
289+
% Verify values changed
290+
expected = (1:10:100);
291+
testCase.verifyEqual(P.Struct.numRepeats(1:5), expected(1:5), ...
292+
'Failed to modify parameters')
293+
294+
callback_fn()
295+
values = P.Struct.numRepeats(1:5);
296+
testCase.verifyTrue(all(values < 100), ...
297+
'Failed to modify parameters')
298+
299+
callback_fn()
300+
testCase.verifyEqual(P.Struct.numRepeats(1:5)/50, values, ...
301+
'Failed to modify parameters')
267302
end
268303

269304
function test_sortByColumn(testCase)

tests/fixtures/util/MockDialog.m

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function reset(obj)
117117
end
118118
case 'inputdlg'
119119
% Find key
120-
if ~strcmp(obj.Dialogs.KeyType, 'char')
120+
if ~strcmp(obj.Dialogs.KeyType, 'char') && ~obj.UseDefaults
121121
key = obj.fromCount;
122122
elseif isempty(varargin)
123123
key = 'Input';
@@ -141,6 +141,10 @@ function reset(obj)
141141
if isa(answer, 'fun.CellSeq')
142142
answer = answer.first;
143143
obj.Dialogs(key) = obj.Dialogs(key).rest;
144+
elseif isa(answer, 'fun.EmptySeq')
145+
warning('MockDialog:NewCall:EmptySeq', ...
146+
'End of input sequence, using default input instead')
147+
answer = def;
144148
end
145149

146150
% inputdlg always returns a cell
@@ -152,14 +156,9 @@ function reset(obj)
152156

153157
methods (Access = private)
154158

155-
function key = fromCount()
156-
if strcmp(obj.Dialogs.KeyType, 'char')
157-
key = [];
158-
return
159-
elseif ~obj.UseDefaults
160-
assert(obj.Dialogs.Count > 0, 'MockDialog:newCall:NoValuesSet', ...
161-
'No values saved in Dialogs property')
162-
end
159+
function key = fromCount(obj)
160+
assert(obj.Dialogs.Count > 0, 'MockDialog:newCall:NoValuesSet', ...
161+
'No values saved in Dialogs property')
163162
key = obj.NumCalls;
164163
if key > obj.Dialogs.Count
165164
key = key - obj.Dialogs.Count*floor(key/uint32(obj.Dialogs.Count));

0 commit comments

Comments
 (0)