pebble/tests/fw/util/test_stats.c

359 lines
11 KiB
C
Raw Permalink Normal View History

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "util/size.h"
#include "util/stats.h"
#include "clar.h"
#include <stdio.h>
#include "stubs_pbl_malloc.h"
void test_stats__initialize(void) {
}
void test_stats__cleanup(void) {
}
void test_stats__min(void) {
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Min;
int32_t result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
cl_assert_equal_i(result, 6);
}
void test_stats__max(void) {
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Max;
int32_t result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
cl_assert_equal_i(result, 80);
}
void test_stats__avg(void) {
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Average;
int32_t result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
cl_assert_equal_i(result, 40);
}
void test_stats__sum(void) {
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Sum;
int32_t result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
cl_assert_equal_i(result, 362);
}
static void *s_context = NULL;
static bool prv_filter(int index, int32_t value, void *context) {
cl_assert_equal_p(context, &s_context);
return (value > 0);
}
void test_stats__filtered_count(void) {
const int32_t data[] = { 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Count;
int32_t result;
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
cl_assert_equal_i(result, 14);
}
void test_stats__filtered_consecutive(void) {
const int32_t data[] = { 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Consecutive;
int32_t result;
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
cl_assert_equal_i(result, 5);
}
void test_stats__filtered_consecutive_first(void) {
const int32_t data[] = { 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_ConsecutiveFirst;
int32_t result;
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
cl_assert_equal_i(result, 3);
}
void test_stats__median(void) {
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op = StatsBasicOp_Median;
int32_t result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
cl_assert_equal_i(result, 34);
}
void test_stats__all_basic_ops(void) {
const int32_t data[] = { 10, 0, 40, 6, 0, -5, 0, 32, 73, 0, 80, 34, 25, 62, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op =
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
StatsBasicOp_Median);
struct {
int32_t sum;
int32_t avg;
int32_t min;
int32_t max;
int32_t count;
int32_t max_streak;
int32_t first_streak;
int32_t median;
} result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
cl_assert_equal_i(result.sum, 357);
cl_assert_equal_i(result.avg, 23);
cl_assert_equal_i(result.min, -5);
cl_assert_equal_i(result.max, 80);
cl_assert_equal_i(result.count, num_data);
cl_assert_equal_i(result.max_streak, num_data);
cl_assert_equal_i(result.first_streak, num_data);
cl_assert_equal_i(result.median, 10);
}
void test_stats__all_basic_ops_filtered(void) {
const int32_t data[] = { 10, 0, 40, 6, 0, 0, 0, 32, 73, 0, 80, 34, 25, 62, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op =
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
StatsBasicOp_Median);
struct {
int32_t sum;
int32_t avg;
int32_t min;
int32_t max;
int32_t count;
int32_t max_streak;
int32_t first_streak;
int32_t median;
} result;
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result.sum);
cl_assert_equal_i(result.sum, 362);
cl_assert_equal_i(result.avg, 40);
cl_assert_equal_i(result.min, 6);
cl_assert_equal_i(result.max, 80);
cl_assert_equal_i(result.count, 9);
cl_assert_equal_i(result.max_streak, 4);
cl_assert_equal_i(result.first_streak, 1);
cl_assert_equal_i(result.median, 34);
}
void test_stats__all_basic_ops_filtered_out(void) {
const int32_t data[] = { 0, 0, 0, 0, 0 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op =
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
StatsBasicOp_Median);
struct {
int32_t sum;
int32_t avg;
int32_t min;
int32_t max;
int32_t count;
int32_t max_streak;
int32_t first_streak;
int32_t median;
} result;
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result.sum);
cl_assert_equal_i(result.sum, 0);
cl_assert_equal_i(result.avg, 0);
cl_assert_equal_i(result.min, INT32_MAX);
cl_assert_equal_i(result.max, INT32_MIN);
cl_assert_equal_i(result.count, 0);
cl_assert_equal_i(result.max_streak, 0);
cl_assert_equal_i(result.first_streak, 0);
cl_assert_equal_i(result.median, 0);
}
void test_stats__all_basic_one_value(void) {
const int32_t data[] = { 42 };
const size_t num_data = ARRAY_LENGTH(data);
const StatsBasicOp op =
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
StatsBasicOp_Median);
struct {
int32_t sum;
int32_t avg;
int32_t min;
int32_t max;
int32_t count;
int32_t max_streak;
int32_t first_streak;
int32_t median;
} result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
cl_assert_equal_i(result.sum, 42);
cl_assert_equal_i(result.avg, 42);
cl_assert_equal_i(result.min, 42);
cl_assert_equal_i(result.max, 42);
cl_assert_equal_i(result.count, 1);
cl_assert_equal_i(result.max_streak, 1);
cl_assert_equal_i(result.first_streak, 1);
cl_assert_equal_i(result.median, 42);
}
void test_stats__all_basic_no_values(void) {
const int32_t data[] = {};
const size_t num_data = 0;
const StatsBasicOp op =
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
StatsBasicOp_Median);
struct {
int32_t sum;
int32_t avg;
int32_t min;
int32_t max;
int32_t count;
int32_t max_streak;
int32_t first_streak;
int32_t median;
} result;
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
cl_assert_equal_i(result.sum, 0);
cl_assert_equal_i(result.avg, 0);
cl_assert_equal_i(result.min, INT32_MAX);
cl_assert_equal_i(result.max, INT32_MIN);
cl_assert_equal_i(result.count, 0);
cl_assert_equal_i(result.max_streak, 0);
cl_assert_equal_i(result.first_streak, 0);
cl_assert_equal_i(result.median, 0);
}
void test_stats__null_data(void) {
const StatsBasicOp op = StatsBasicOp_Average;
int32_t result = 0x73110;
stats_calculate_basic(op, NULL, 0, NULL, NULL, &result);
cl_assert_equal_i(result, 0x73110);
}
typedef struct WeightedValue {
int32_t value;
int32_t weight_x100;
} WeightedValue;
void test_stats__weighted_median(void) {
//! Taken from https://en.wikipedia.org/wiki/Weighted_median
struct {
int32_t values[10];
int32_t weights[10];
int32_t num_values;
int32_t answer;
} test_cases[] = {
{
// Simple test case
.values = {1, 3, 1},
.weights = {2, 4, 1},
.num_values = 3,
.answer = 3,
},
{
// Hit exactly S/2 when iterating. Take the mean of [1,2] and [3,4] -> 2
.values = {1, 3, 1},
.weights = {2, 4, 2},
.num_values = 3,
.answer = 2,
},
{
// Would hit exactly S/2 when iterating if we only did integer division. Added a check to
// prevent this.
.values = {1, 3, 1},
.weights = {2, 4, 3},
.num_values = 3,
.answer = 1,
},
{
// Simple test case
.values = {1, 100},
.weights = {2, 1},
.num_values = 2,
.answer = 1,
},
{
// Simple test case
.values = {100, 1},
.weights = {1, 2},
.num_values = 2,
.answer = 1,
},
{
// Simple test case
.values = {100, 1},
.weights = {2, 1},
.num_values = 2,
.answer = 100,
},
{
// Simple test case
.values = {20, 3, 6},
.weights = {1, 50, 50},
.num_values = 3,
.answer = 6,
},
{
// Test if all weights are zero, zero should be returned
.values = {20, 3, 6},
.weights = {0, 0, 0},
.num_values = 3,
.answer = 0,
},
{
// Simple test case
.values = {10, 35, 5, 10, 15, 5, 20},
.weights = {20, 70, 10, 20, 30, 10, 40},
.num_values = 7,
.answer = 20,
},
{
// Only one value, return that value
.values = {1},
.weights = {100},
.num_values = 1,
.answer = 1,
},
{
// Two values, equal weight. Return the lower of the two
.values = {1, 2},
.weights = {1, 1},
.num_values = 2,
.answer = 1,
},
};
for (size_t i = 0; i < ARRAY_LENGTH(test_cases); i++) {
int32_t w_median = stats_calculate_weighted_median(test_cases[i].values,
test_cases[i].weights,
test_cases[i].num_values);
printf("W_Median test case: %d\n", (int)i);
cl_assert_equal_i(test_cases[i].answer, w_median);
}
}