Skip to content
Snippets Groups Projects
Commit 58467f01 authored by Yen-Chen Chen's avatar Yen-Chen Chen Committed by Jonas Jucker
Browse files

Add C unit tests (!54)

<!--
ICON

---------------------------------------------------------------
Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
Contact information: icon-model.org

See AUTHORS.TXT for a list of authors
See LICENSES/ for license information
SPDX-License-Identifier: CC0-1.0
---------------------------------------------------------------
-->

## What is the new feature
Add unit tests for C functions
## How is it implemented
Use Googletest to implement missing unit tests in #6



## Mandatory steps before review
- [x] Gitlab CI passes _(Hint: use `make format` for linting)_ 
- [x] New feature is covered by additional unit tests
- [x] Mark the merge request as ready by removing `Draft:`

## Mandatory steps before merge
- [x] Test coverage does not decrease
- [ ] Reviewed by a maintainer
- [ ] Incorporate review suggestions
- [ ] Remember to edit the commit message and select the proper changelog category (feature/bugfix/other)

**You are not supposed to merge this request by yourself, the maintainers of fortan-support take care of this action!**

Approved-by: default avatarJonas Jucker <jonas.jucker@env.ethz.ch>
Merged-by: default avatarJonas Jucker <jonas.jucker@env.ethz.ch>
Changelog: other
parent 192aa262
No related branches found
No related tags found
1 merge request!54Add C unit tests
Pipeline #57668 passed
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#ifndef UTIL_STRIDE_H
#define UTIL_STRIDE_H
#ifdef __cplusplus
extern "C" {
#endif
void util_stride_1d(int *out, int elemsize, void *p1, void *p2);
void util_stride_2d(int *out, int elemsize, const void *p1, const void *p2,
const void *p3);
size_t util_get_ptrdiff(const void *a, const void *b);
#ifdef __cplusplus
}
#endif
#endif // UTIL_STRIDE_H
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#ifndef UTIL_STRING_PARSE_H
#define UTIL_STRING_PARSE_H
#ifdef __cplusplus
extern "C" {
#endif
void do_parse_intlist(const char *in_parse_line, const int nvalues,
const int nlev_val, int *out_values, int *ierr);
#ifdef __cplusplus
}
#endif
#endif // UTIL_STRING_PARSE_H
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#ifndef UTIL_SYSTEM_H
#define UTIL_SYSTEM_H
#ifdef __cplusplus
extern "C" {
#endif
void util_exit(int exit_no);
void util_abort(void);
int util_system(char *s);
#ifdef __cplusplus
}
#endif
#endif // UTIL_SYSTEM_H
\ No newline at end of file
......@@ -46,6 +46,9 @@ endif()
add_icon_c_test(UtilArithmeticExprTest ctest_util_arithmetic_expr.cpp)
add_icon_c_test(UtilHashTest ctest_util_hash.cpp)
add_icon_c_test(UtilStrideTest ctest_util_stride.cpp)
add_icon_c_test(UtilStringParseTest ctest_util_string_parse.cpp)
add_icon_c_test(UtilSystemTest ctest_util_system.cpp)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/util_file_test.txt"
"This is a test file for unit tests for util_file.c\n")
......
......@@ -10,6 +10,7 @@
// ---------------------------------------------------------------
#include <gtest/gtest.h>
#include <cmath>
#include <util_arithmetic_expr.h>
......@@ -24,9 +25,36 @@ class UtilArithmeticExprTest : public ::testing::Test {
const char *op_multiplication = "*";
const char *op_power = "^";
void EXPECT_FCT_EQ(char *string, const char *fct) {
EXPECT_PRED2([](auto string, auto fct) { return strcpy(string, fct); },
string, fct);
void EXPECT_T_ITEM_VAL_EQ(t_item item, double val) {
EXPECT_PRED2([](auto item,
auto val) { return item.type == 1 && item.val == val; },
item, val);
}
void EXPECT_T_ITEM_OP_EQ(t_item item, char op) {
EXPECT_PRED2(
[](auto item, auto op) { return item.type == 2 && item.op == op; },
item, op);
}
void EXPECT_T_ITEM_FCT_EQ(t_item item, fct_type fct) {
EXPECT_PRED2([](auto item,
auto fct) { return item.type == 3 && item.fct == fct; },
item, fct);
}
void EXPECT_T_ITEM_VAR_EQ(t_item item, char *field) {
EXPECT_PRED2(
[](auto item, auto field) {
return item.type == 0 && strcpy(item.field, field);
},
item, field);
}
void EXPECT_FCT_NAME_EQ(char *string, const char *fct_name) {
EXPECT_PRED2(
[](auto string, auto fct_name) { return strcpy(string, fct_name); },
string, fct_name);
}
};
......@@ -70,20 +98,79 @@ TEST_F(UtilArithmeticExprTest, CanDoParseInfix) {
}
TEST_F(UtilArithmeticExprTest, ParseInfixIsCorrect) {
std::string expression = "20*10/20";
std::string expression = "20 * 10 / 20";
const char *char_array = expression.c_str();
t_list queue;
do_parse_infix(char_array, &queue);
// Reverse Polish notation: 20 10 * 20 /
EXPECT_T_ITEM_VAL_EQ(queue.list[0], 20);
EXPECT_T_ITEM_VAL_EQ(queue.list[1], 10);
EXPECT_T_ITEM_OP_EQ(queue.list[2], '*');
EXPECT_T_ITEM_VAL_EQ(queue.list[3], 20);
EXPECT_T_ITEM_OP_EQ(queue.list[4], '/');
}
TEST_F(UtilArithmeticExprTest, ParseInfixIsCorrect2) {
std::string expression = "3 + 4 * 2 / (1 - 5) ^ 2 ^ 3";
const char *char_array = expression.c_str();
t_list queue;
do_parse_infix(char_array, &queue);
// TODO: add more concrete examples for do_parse_infix
EXPECT_EQ(queue.list[2].op, '*');
EXPECT_EQ(queue.list[4].op, '/');
// Reverse Polish notation: 3 4 2 * 1 5 - 2 ^ 3 ^ / +
EXPECT_T_ITEM_VAL_EQ(queue.list[0], 3);
EXPECT_T_ITEM_VAL_EQ(queue.list[1], 4);
EXPECT_T_ITEM_VAL_EQ(queue.list[2], 2);
EXPECT_T_ITEM_OP_EQ(queue.list[3], '*');
EXPECT_T_ITEM_VAL_EQ(queue.list[4], 1);
EXPECT_T_ITEM_VAL_EQ(queue.list[5], 5);
EXPECT_T_ITEM_OP_EQ(queue.list[6], '-');
EXPECT_T_ITEM_VAL_EQ(queue.list[7], 2);
EXPECT_T_ITEM_OP_EQ(queue.list[8], '^');
EXPECT_T_ITEM_VAL_EQ(queue.list[9], 3);
EXPECT_T_ITEM_OP_EQ(queue.list[10], '^');
EXPECT_T_ITEM_OP_EQ(queue.list[11], '/');
EXPECT_T_ITEM_OP_EQ(queue.list[12], '+');
}
TEST_F(UtilArithmeticExprTest, ParseInfixIsCorrect3) {
std::string expression = "sin ( max ( 2, 3 ) / 3 * pi )";
const char *char_array = expression.c_str();
t_list queue;
do_parse_infix(char_array, &queue);
// Reverse Polish notation: 2 3 max 3 / pi * sin
EXPECT_T_ITEM_VAL_EQ(queue.list[0], 2);
EXPECT_T_ITEM_VAL_EQ(queue.list[1], 3);
EXPECT_T_ITEM_FCT_EQ(queue.list[2], MAX);
EXPECT_T_ITEM_VAL_EQ(queue.list[3], 3);
EXPECT_T_ITEM_OP_EQ(queue.list[4], '/');
EXPECT_T_ITEM_VAL_EQ(queue.list[5], M_PI);
EXPECT_T_ITEM_OP_EQ(queue.list[6], '*');
EXPECT_T_ITEM_FCT_EQ(queue.list[7], SIN);
}
TEST_F(UtilArithmeticExprTest, ParseInfixIsCorrect4) {
std::string expression = "if([z_sfc] > 2, [z_sfc], 0)";
const char *char_array = expression.c_str();
t_list queue;
do_parse_infix(char_array, &queue);
EXPECT_EQ(queue.list[0].val, 20);
EXPECT_EQ(queue.list[1].val, 10);
EXPECT_EQ(queue.list[3].val, 20);
// Reverse Polish notation: z_sfc 2 > z_sfc 0 if
EXPECT_T_ITEM_VAR_EQ(queue.list[0], (char *) "z_sfc");
EXPECT_T_ITEM_VAL_EQ(queue.list[1], 2);
EXPECT_T_ITEM_OP_EQ(queue.list[2], '>');
EXPECT_T_ITEM_VAR_EQ(queue.list[3], (char *) "z_sfc");
EXPECT_T_ITEM_VAL_EQ(queue.list[4], 0);
EXPECT_T_ITEM_FCT_EQ(queue.list[5], IF);
}
TEST_F(UtilArithmeticExprTest, CanGetFCTName) {
......@@ -102,7 +189,7 @@ TEST_F(UtilArithmeticExprTest, GetFCTNameIsCorrect) {
for (int i = 0; i < NUM_FCT; ++i) {
ierr = get_fctname(i, string);
EXPECT_EQ(ierr, 0);
EXPECT_FCT_EQ(string, fct_name[i]);
EXPECT_FCT_NAME_EQ(string, fct_name[i]);
}
}
......
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#include <gtest/gtest.h>
#include <experimental/random>
#include <util_stride.h>
class UtilStrideTest : public ::testing::Test {};
TEST_F(UtilStrideTest, CanGetPointerDiff) {
double *a, *b;
EXPECT_NO_THROW({ util_get_ptrdiff(a, b); });
}
TEST_F(UtilStrideTest, PointerDiffIsCorrect) {
float f_array[10];
double d_array[10];
EXPECT_EQ(util_get_ptrdiff(&f_array[0], &f_array[1]), 4);
EXPECT_EQ(util_get_ptrdiff(&f_array[2], &f_array[7]), 20);
EXPECT_EQ(util_get_ptrdiff(&f_array[6], &f_array[3]), 12);
EXPECT_EQ(util_get_ptrdiff(&d_array[0], &d_array[1]), 8);
EXPECT_EQ(util_get_ptrdiff(&d_array[0], &d_array[9]), 72);
EXPECT_EQ(util_get_ptrdiff(&d_array[9], &d_array[0]), 72);
EXPECT_EQ(util_get_ptrdiff(&d_array[5], &d_array[2]), 24);
}
TEST_F(UtilStrideTest, CanGet1DStride) {
int stride;
float f_array[100];
double d_array[100];
util_stride_1d(&stride, sizeof(float), &f_array[15], &f_array[25]);
EXPECT_EQ(stride, 10);
util_stride_1d(&stride, sizeof(double), &d_array[37], &d_array[81]);
EXPECT_EQ(stride, 44);
}
TEST_F(UtilStrideTest, CanGet1DStride2) {
int stride;
float f_array[1000];
double d_array[1000];
int p1 = std::experimental::randint(0, 499);
int p2 = std::experimental::randint(500, 999);
util_stride_1d(&stride, sizeof(float), &f_array[p1], &f_array[p2]);
EXPECT_EQ(stride, p2 - p1);
util_stride_1d(&stride, sizeof(double), &d_array[p1], &d_array[p2]);
EXPECT_EQ(stride, p2 - p1);
}
TEST_F(UtilStrideTest, CanGet2DStride) {
int stride[2];
float f_array[100];
double d_array[100];
util_stride_2d(&stride[0], sizeof(float), &f_array[15], &f_array[25],
&f_array[45]);
EXPECT_EQ(stride[0], 10);
EXPECT_EQ(stride[1], 30);
util_stride_2d(&stride[0], sizeof(double), &d_array[37], &d_array[48],
&d_array[81]);
EXPECT_EQ(stride[0], 11);
EXPECT_EQ(stride[1], 44);
}
TEST_F(UtilStrideTest, CanGet2DStride2) {
int stride[2];
float f_array[1000];
double d_array[1000];
int p1 = std::experimental::randint(0, 499);
int p2 = std::experimental::randint(500, 999);
int p3 = std::experimental::randint(500, 999);
util_stride_2d(&stride[0], sizeof(float), &f_array[p1], &f_array[p2],
&f_array[p3]);
EXPECT_EQ(stride[0], p2 - p1);
EXPECT_EQ(stride[1], p3 - p1);
util_stride_2d(&stride[0], sizeof(double), &d_array[p1], &d_array[p2],
&d_array[p3]);
EXPECT_EQ(stride[0], p2 - p1);
EXPECT_EQ(stride[1], p3 - p1);
}
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#include <gtest/gtest.h>
#include <vector>
#include <string>
#include <util_string_parse.h>
class UtilStringParseTest : public ::testing::Test {
public:
void EXPECT_VECTOR_EQ(std::vector<int> &v1, std::vector<int> &v2) {
EXPECT_EQ(v1.size(), v2.size());
for (int i = 0; i < v1.size(); ++i) {
EXPECT_EQ(v1[i], v2[i])
<< "Vector element mismatch at index i = " << i;
}
}
};
TEST_F(UtilStringParseTest, CanParseIntList) {
std::string parse_line = "1,3,5";
std::vector<int> output(11);
int ierr;
const char *char_array = parse_line.c_str();
EXPECT_NO_THROW({
do_parse_intlist(char_array, output.size(), 10, output.data(), &ierr);
});
}
TEST_F(UtilStringParseTest, ParseIntListIsCorrect) {
int nlev = 10;
// comma and semicolon both separates the numbers
std::string parse_line = "1,2,3;nlev";
std::vector<int> result = { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 };
// One extra index [0] unused becuase Fortran index starts from 1
std::vector<int> output(nlev + 1);
int ierr;
const char *char_array = parse_line.c_str();
do_parse_intlist(char_array, output.size(), nlev, output.data(), &ierr);
EXPECT_VECTOR_EQ(output, result);
}
TEST_F(UtilStringParseTest, ParseIntListIsCorrect2) {
int nlev = 10;
// comma and semicolon both separates the numbers
std::string parse_line = "1;3,4...7";
std::vector<int> result = { 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0 };
// One extra index [0] unused becuase Fortran index starts from 1
std::vector<int> output(nlev + 1);
int ierr;
const char *char_array = parse_line.c_str();
do_parse_intlist(char_array, output.size(), nlev, output.data(), &ierr);
EXPECT_VECTOR_EQ(output, result);
}
TEST_F(UtilStringParseTest, ParseIntListIsCorrect3) {
int nlev = 30;
// comma and semicolon both separates the numbers
std::string parse_line = "1,3,5...10,20...nlev";
// clang-format off
std::vector<int> result = { 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
// clang-format on
// One extra index [0] unused becuase Fortran index starts from 1
std::vector<int> output(nlev + 1);
int ierr;
const char *char_array = parse_line.c_str();
do_parse_intlist(char_array, output.size(), nlev, output.data(), &ierr);
EXPECT_VECTOR_EQ(output, result);
}
TEST_F(UtilStringParseTest, ParseIntListIsCorrect4) {
int nlev = 30;
// comma and semicolon both separates the numbers
std::string parse_line = "1,2, 10 ...22;2;16-(3+11), N-2,16-(2+10);5";
// clang-format off
std::vector<int> result = { 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 1, 0, 0 };
// clang-format on
// One extra index [0] unused becuase Fortran index starts from 1
std::vector<int> output(nlev + 1);
int ierr;
const char *char_array = parse_line.c_str();
do_parse_intlist(char_array, output.size(), nlev, output.data(), &ierr);
EXPECT_VECTOR_EQ(output, result);
}
// ICON
//
// ---------------------------------------------------------------
// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
// Contact information: icon-model.org
//
// See AUTHORS.TXT for a list of authors
// See LICENSES/ for license information
// SPDX-License-Identifier: BSD-3-Clause
// ---------------------------------------------------------------
#include <gtest/gtest.h>
#include <util_system.h>
class UtilSystemTest : public ::testing::Test {};
TEST_F(UtilSystemTest, CanAbort) {
EXPECT_EXIT({ util_abort(); }, testing::ExitedWithCode(1), "");
}
TEST_F(UtilSystemTest, CanExit) {
EXPECT_EXIT({ util_exit(1); }, testing::ExitedWithCode(1), "");
}
TEST_F(UtilSystemTest, CanExit2) {
EXPECT_EXIT({ util_exit(2); }, testing::ExitedWithCode(2), "");
}
TEST_F(UtilSystemTest, CanCallSystemDate) {
char sys[] = "date";
EXPECT_NO_THROW({ util_system(sys); });
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment