@@ -176,31 +176,18 @@ contract StatisticsTest is Test {
176176 // Test for empty array handling
177177 function test_EmptyArray () external {
178178 uint256 [] memory emptyData = new uint256 [](0 );
179- vm.expectRevert ("Array is empty " );
179+
180+ // Test division by zero error for empty array
181+ vm.expectRevert (); // or vm.expectRevert(stdError.divisionError);
180182 Statistics.avg (emptyData);
181183
182- vm.expectRevert (" Array is empty " );
184+ vm.expectRevert ();
183185 Statistics.variance (emptyData);
184186
185- vm.expectRevert (" Array is empty " );
187+ vm.expectRevert ();
186188 Statistics.stddev (emptyData);
187189 }
188190
189- // Test for single element array
190- function test_SingleElement () external pure {
191- uint256 [] memory singleData = new uint256 [](1 );
192- singleData[0 ] = 100 ;
193-
194- uint256 avg = Statistics.avg (singleData);
195- assertEq (avg, 100 ether);
196-
197- (uint256 variance ,) = Statistics.variance (singleData);
198- assertEq (variance, 0 );
199-
200- (uint256 stddev ,) = Statistics.stddev (singleData);
201- assertEq (stddev, 0 );
202- }
203-
204191 // Test for array bounds
205192 function testFuzz_ArrayBounds (uint8 length ) external pure {
206193 // limit array size to prevent overflow and excessive gas costs
@@ -218,26 +205,7 @@ contract StatisticsTest is Test {
218205 assertEq (variance, 0 );
219206 }
220207
221- // Test for statistical properties
222- function test_StatisticalProperties () external pure {
223- // test mean minimizes squared deviations
224- uint256 [] memory data = new uint256 [](3 );
225- data[0 ] = 10 ;
226- data[1 ] = 20 ;
227- data[2 ] = 30 ;
228-
229- uint256 mean = Statistics.avg (data);
230- (uint256 variance , uint256 calculatedMean ) = Statistics.variance (data);
231-
232- // mean should match between avg() and variance()
233- assertEq (mean, calculatedMean);
234-
235- // variance should equal average of squared deviations
236- uint256 expectedVariance = ((10 ether - mean) ** 2 + (20 ether - mean) ** 2 + (30 ether - mean) ** 2 ) / 3 ;
237- assertApproxEqAbs (variance, expectedVariance, 1e15 );
238- }
239-
240- // test invariance under translation
208+ // Test invariance under translation
241209 function testFuzz_TranslationInvariance (uint8 shift ) external pure {
242210 vm.assume (shift <= 50 ); // Ensure we don't overflow MAX_SCORE
243211
@@ -260,4 +228,61 @@ contract StatisticsTest is Test {
260228 // variance should be invariant under translation
261229 assertApproxEqAbs (variance1, variance2, 1e15 );
262230 }
231+
232+ // Test that variance scales correctly when data is multiplied
233+ function testFuzz_ScaleInvariance (uint8 length , uint8 scale ) external {
234+ vm.assume (length > 0 && length <= 32 );
235+ vm.assume (scale > 0 && scale <= 10 );
236+
237+ uint256 [] memory data = new uint256 [](length);
238+ uint256 [] memory scaledData = new uint256 [](length);
239+
240+ for (uint256 i = 0 ; i < length; i++ ) {
241+ data[i] = bound (uint256 (uint256 (keccak256 (abi.encode (i))) % MAX_SCORE), MIN_SCORE, MAX_SCORE / scale);
242+ scaledData[i] = data[i] * scale;
243+ }
244+
245+ (uint256 variance1 ,) = Statistics.variance (data);
246+ (uint256 variance2 ,) = Statistics.variance (scaledData);
247+
248+ assertApproxEqAbs (variance2, variance1 * scale * scale, 1e15 );
249+ }
250+
251+ function testFuzz_OrderInvariance (uint8 length ) external {
252+ vm.assume (length > 1 && length <= 32 );
253+
254+ uint256 [] memory data = new uint256 [](length);
255+ uint256 [] memory shuffledData = new uint256 [](length);
256+
257+ for (uint256 i = 0 ; i < length; i++ ) {
258+ data[i] = bound (uint256 (uint256 (keccak256 (abi.encode (i))) % MAX_SCORE), MIN_SCORE, MAX_SCORE);
259+ shuffledData[i] = data[i];
260+ }
261+
262+ // Shuffle
263+ for (uint256 i = length - 1 ; i > 0 ; i-- ) {
264+ uint256 j = uint256 (keccak256 (abi.encodePacked (block .timestamp , i))) % (i + 1 );
265+ (shuffledData[i], shuffledData[j]) = (shuffledData[j], shuffledData[i]);
266+ }
267+
268+ uint256 avg1 = Statistics.avg (data);
269+ uint256 avg2 = Statistics.avg (shuffledData);
270+ (uint256 variance1 ,) = Statistics.variance (data);
271+ (uint256 variance2 ,) = Statistics.variance (shuffledData);
272+
273+ assertEq (avg1, avg2);
274+ assertEq (variance1, variance2);
275+ }
276+
277+ function testFuzz_ExtremeValues (uint8 length ) external {
278+ vm.assume (length > 1 && length <= 32 ); // Must have at least 2 elements
279+
280+ uint256 [] memory extremeData = new uint256 [](length);
281+ for (uint256 i = 0 ; i < length; i++ ) {
282+ extremeData[i] = i % 2 == 0 ? MAX_SCORE : MIN_SCORE;
283+ }
284+
285+ (uint256 variance ,) = Statistics.variance (extremeData);
286+ assert (variance > 0 );
287+ }
263288}
0 commit comments