@@ -8,14 +8,15 @@ function addPaths(testCase)
88 end
99
1010 methods (Static )
11- function ms = makeMetadataStruct(stateKeys , nPoints )
12- % MAKEMETADATASTRUCT Build a fake metadata struct for testing.
13- ms.time_utc = linspace(datenum(2024 ,1 ,1 ), datenum(2024 ,1 ,2 ), nPoints );
11+ function t = makeMetadataTable(stateKeys , nPoints )
12+ % MAKEMETADATATABLE Build a fake metadata table for testing.
13+ Date = datetime(2024 ,1 ,1 ) + linspace(0 , 1 , nPoints )' ;
14+ args = {' Date' , Date };
1415 for i = 1 : numel(stateKeys )
15- ms.(stateKeys{i }) = zeros(1 , nPoints );
16- ms .doc.(stateKeys{i }).name = stateKeys{i };
17- ms .doc.(stateKeys{i }).datum = ' time_utc' ;
16+ args{end + 1 } = stateKeys{i }; % #ok<AGROW>
17+ args{end + 1 } = zeros(nPoints , 1 ); % #ok<AGROW>
1818 end
19+ t = table(args{: });
1920 end
2021
2122 function s = makeSensorWithRule(key , conditionStruct , value )
@@ -34,11 +35,11 @@ function testBasicNumericState(testCase)
3435 s = TestLoadModuleMetadata .makeSensorWithRule( ...
3536 ' temp' , struct(' machine' , 1 ), 50 );
3637
37- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
38+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
3839 % Set state: 0 for first 50 points, 1 for last 50
39- ms .machine(51 : 100 ) = 1 ;
40+ t .machine(51 : 100 ) = 1 ;
4041
41- sensors = loadModuleMetadata(ms , {s });
42+ sensors = loadModuleMetadata(t , {s });
4243
4344 testCase .verifyEqual(numel(sensors ), 1 , ' returns_sensors' );
4445 testCase .verifyEqual(numel(sensors{1 }.StateChannels), 1 , ' one_sc' );
@@ -54,12 +55,11 @@ function testCellStringState(testCase)
5455 s = TestLoadModuleMetadata .makeSensorWithRule( ...
5556 ' temp' , struct(' recipe' , ' bake' ), 80 );
5657
57- ms.doc.recipe.name = ' recipe' ;
58- ms.doc.recipe.datum = ' time_utc' ;
59- ms.time_utc = linspace(datenum(2024 ,1 ,1 ), datenum(2024 ,1 ,2 ), 6 );
60- ms.recipe = {' idle' , ' idle' , ' bake' , ' bake' , ' bake' , ' idle' };
58+ Date = datetime(2024 ,1 ,1 ) + linspace(0 , 1 , 6 )' ;
59+ recipe = {' idle' ; ' idle' ; ' bake' ; ' bake' ; ' bake' ; ' idle' };
60+ t = table(Date , recipe );
6161
62- sensors = loadModuleMetadata(ms , {s });
62+ sensors = loadModuleMetadata(t , {s });
6363
6464 sc = sensors{1 }.StateChannels{1 };
6565 testCase .verifyEqual(sc .Key , ' recipe' , ' sc_key' );
@@ -75,10 +75,10 @@ function testMultipleSensorsGetIndependentHandles(testCase)
7575 s2 = TestLoadModuleMetadata .makeSensorWithRule( ...
7676 ' press' , struct(' machine' , 1 ), 100 );
7777
78- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
79- ms .machine(51 : 100 ) = 1 ;
78+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
79+ t .machine(51 : 100 ) = 1 ;
8080
81- sensors = loadModuleMetadata(ms , {s1 , s2 });
81+ sensors = loadModuleMetadata(t , {s1 , s2 });
8282
8383 sc1 = sensors{1 }.StateChannels{1 };
8484 sc2 = sensors{2 }.StateChannels{1 };
@@ -96,21 +96,21 @@ function testSensorWithNoRulesSkipped(testCase)
9696 s = Sensor(' temp' );
9797 s.X = [1 2 3 ]; s.Y = [4 5 6 ];
9898
99- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
99+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
100100
101- sensors = loadModuleMetadata(ms , {s });
101+ sensors = loadModuleMetadata(t , {s });
102102
103103 testCase .verifyTrue(isempty(sensors{1 }.StateChannels), ' no_sc' );
104104 end
105105
106106 function testRuleReferencesUnknownState(testCase )
107- % Rule references 'recipe' but metadata only has 'machine'
107+ % Rule references 'recipe' but table only has 'machine'
108108 s = TestLoadModuleMetadata .makeSensorWithRule( ...
109109 ' temp' , struct(' recipe' , 1 ), 50 );
110110
111- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
111+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
112112
113- sensors = loadModuleMetadata(ms , {s });
113+ sensors = loadModuleMetadata(t , {s });
114114
115115 testCase .verifyTrue(isempty(sensors{1 }.StateChannels), ...
116116 ' no_sc_for_unknown_key' );
@@ -124,12 +124,12 @@ function testMultipleConditionFields(testCase)
124124 s .addThresholdRule(struct(' machine' , 1 , ' recipe' , 2 ), 50 , ...
125125 ' Direction' , ' upper' , ' Label' , ' test' );
126126
127- ms = TestLoadModuleMetadata .makeMetadataStruct ( ...
127+ t = TestLoadModuleMetadata .makeMetadataTable ( ...
128128 {' machine' , ' recipe' }, 100 );
129- ms .machine(51 : 100 ) = 1 ;
130- ms .recipe(31 : 60 ) = 2 ;
129+ t .machine(51 : 100 ) = 1 ;
130+ t .recipe(31 : 60 ) = 2 ;
131131
132- sensors = loadModuleMetadata(ms , {s });
132+ sensors = loadModuleMetadata(t , {s });
133133
134134 testCase .verifyEqual(numel(sensors{1 }.StateChannels), 2 , ' two_scs' );
135135 keys = cellfun(@(c ) c .Key , sensors{1 }.StateChannels, ...
@@ -143,116 +143,66 @@ function testAllIdenticalValues(testCase)
143143 s = TestLoadModuleMetadata .makeSensorWithRule( ...
144144 ' temp' , struct(' machine' , 0 ), 50 );
145145
146- ms = TestLoadModuleMetadata .makeMetadataStruct({' machine' }, 100 );
147- % machine stays 0 everywhere (default)
146+ t = TestLoadModuleMetadata .makeMetadataTable({' machine' }, 100 );
148147
149- sensors = loadModuleMetadata(ms , {s });
148+ sensors = loadModuleMetadata(t , {s });
150149
151150 sc = sensors{1 }.StateChannels{1 };
152151 testCase .verifyEqual(numel(sc .X ), 1 , ' single_point' );
153152 testCase .verifyEqual(sc .Y , 0 , ' single_value' );
154153 end
155154
156155 function testSinglePointMetadata(testCase )
157- % Metadata with only one time point
156+ % Table with only one row
158157 s = TestLoadModuleMetadata .makeSensorWithRule( ...
159158 ' temp' , struct(' machine' , 1 ), 50 );
160159
161- ms.doc.machine.name = ' machine' ;
162- ms.doc.machine.datum = ' time_utc' ;
163- ms.time_utc = datenum(2024 ,1 ,1 );
164- ms.machine = 1 ;
160+ t = table(datetime(2024 ,1 ,1 ), 1 , ...
161+ ' VariableNames' , {' Date' , ' machine' });
165162
166- sensors = loadModuleMetadata(ms , {s });
163+ sensors = loadModuleMetadata(t , {s });
167164
168165 sc = sensors{1 }.StateChannels{1 };
169166 testCase .verifyEqual(numel(sc .X ), 1 , ' single_pt_X' );
170167 testCase .verifyEqual(sc .Y , 1 , ' single_pt_Y' );
171168 end
172169
173- function testColumnVectorInputs(testCase )
174- % Column vector inputs must produce row vector StateChannel
175- s = TestLoadModuleMetadata .makeSensorWithRule( ...
176- ' temp' , struct(' machine' , 1 ), 50 );
177-
178- ms.doc.machine.name = ' machine' ;
179- ms.doc.machine.datum = ' time_utc' ;
180- ms.time_utc = linspace(datenum(2024 ,1 ,1 ), datenum(2024 ,1 ,2 ), 6 )' ;
181- ms.machine = [0 ; 0 ; 1 ; 1 ; 0 ; 0 ];
182-
183- sensors = loadModuleMetadata(ms , {s });
184-
185- sc = sensors{1 }.StateChannels{1 };
186- testCase .verifyEqual(size(sc .X , 1 ), 1 , ' X_is_row' );
187- testCase .verifyEqual(size(sc .Y , 1 ), 1 , ' Y_is_row' );
188- end
189-
190170 function testEmptySensors(testCase )
191- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
192- sensors = loadModuleMetadata(ms , {});
171+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
172+ sensors = loadModuleMetadata(t , {});
193173 testCase .verifyTrue(isempty(sensors ), ' empty_passthrough' );
194174 end
195175
196- function testMissingDocErrors(testCase )
197- ms = struct(' machine' , [1 2 3 ]);
198- threw = false ;
199- try
200- loadModuleMetadata(ms , {});
201- catch
202- threw = true ;
203- end
204- testCase .verifyTrue(threw , ' missing_doc_throws' );
205- end
206-
207- function testDocMissingDatumErrors(testCase )
208- % doc entry without .datum field
209- ms.doc.machine.name = ' machine' ; % no .datum
210- ms.machine = [1 2 3 ];
211- threw = false ;
212- try
213- loadModuleMetadata(ms , {});
214- catch
215- threw = true ;
216- end
217- testCase .verifyTrue(threw , ' missing_datum_throws' );
218- end
219-
220- function testDatenumFieldNotInStructErrors(testCase )
221- ms.doc.machine.name = ' machine' ;
222- ms.doc.machine.datum = ' nonexistent' ;
223- ms.machine = [1 2 3 ];
176+ function testNotTableErrors(testCase )
224177 threw = false ;
225178 try
226- loadModuleMetadata(ms , {});
179+ loadModuleMetadata(struct( ' x ' , 1 ) , {});
227180 catch
228181 threw = true ;
229182 end
230- testCase .verifyTrue(threw , ' bad_datenum_ref_throws ' );
183+ testCase .verifyTrue(threw , ' not_table_throws ' );
231184 end
232185
233- function testDatumNotCharErrors(testCase )
234- % Defensive test: validates datum type
235- ms.doc.machine.name = ' machine' ;
236- ms.doc.machine.datum = 42 ;
237- ms.machine = [1 2 3 ];
186+ function testMissingDateColumnErrors(testCase )
187+ t = table([1 ; 2 ; 3 ], ' VariableNames' , {' machine' });
238188 threw = false ;
239189 try
240- loadModuleMetadata(ms , {});
190+ loadModuleMetadata(t , {});
241191 catch
242192 threw = true ;
243193 end
244- testCase .verifyTrue(threw , ' non_char_datum_throws ' );
194+ testCase .verifyTrue(threw , ' missing_date_throws ' );
245195 end
246196
247197 function testOutputRowOrientation(testCase )
248198 % StateChannel X/Y must be row vectors (1xN)
249199 s = TestLoadModuleMetadata .makeSensorWithRule( ...
250200 ' temp' , struct(' machine' , 1 ), 50 );
251201
252- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
253- ms .machine(51 : 100 ) = 1 ;
202+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
203+ t .machine(51 : 100 ) = 1 ;
254204
255- sensors = loadModuleMetadata(ms , {s });
205+ sensors = loadModuleMetadata(t , {s });
256206
257207 sc = sensors{1 }.StateChannels{1 };
258208 testCase .verifyEqual(size(sc .X , 1 ), 1 , ' X_is_row' );
@@ -266,9 +216,9 @@ function testUnconditionalRuleNoStateChannel(testCase)
266216 s .addThresholdRule(struct(), 50 , ...
267217 ' Direction' , ' upper' , ' Label' , ' always' );
268218
269- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
219+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
270220
271- sensors = loadModuleMetadata(ms , {s });
221+ sensors = loadModuleMetadata(t , {s });
272222
273223 testCase .verifyTrue(isempty(sensors{1 }.StateChannels), ...
274224 ' unconditional_no_sc' );
@@ -279,11 +229,11 @@ function testRepeatedCallAccumulatesChannels(testCase)
279229 s = TestLoadModuleMetadata .makeSensorWithRule( ...
280230 ' temp' , struct(' machine' , 1 ), 50 );
281231
282- ms = TestLoadModuleMetadata .makeMetadataStruct ({' machine' }, 100 );
283- ms .machine(51 : 100 ) = 1 ;
232+ t = TestLoadModuleMetadata .makeMetadataTable ({' machine' }, 100 );
233+ t .machine(51 : 100 ) = 1 ;
284234
285- loadModuleMetadata(ms , {s });
286- loadModuleMetadata(ms , {s });
235+ loadModuleMetadata(t , {s });
236+ loadModuleMetadata(t , {s });
287237
288238 testCase .verifyEqual(numel(s .StateChannels ), 2 , ...
289239 ' duplicates_accumulated' );
0 commit comments