mirror of
https://github.com/google/pebble.git
synced 2025-03-19 10:31:21 +00:00
359 lines
11 KiB
C
359 lines
11 KiB
C
|
/*
|
||
|
* 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);
|
||
|
}
|
||
|
}
|