src/apps/testapps/testConstructCell.c (90 lines of code) (raw):

/* * Copyright 2025 Uber Technologies, Inc. * * 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. */ /** @file * @brief tests for `constructCell` function * * usage: `testConstructCell` * * This file sets up a small framework to enable a concise table of tests, * which hopefully make its easy to see when and why expected errors are * happening. The table lists an expected output: either a valid cell, or an * specific error code. */ #include "h3api.h" #include "iterators.h" #include "test.h" #include "utility.h" typedef struct { uint64_t x; // Expected result: either valid H3 cell or error code int res; int bc; int digits[15]; } TestCase; void runTestCase(TestCase tc) { // Construct cell from components, and check that we get the expected output // as tc.x (either a valid cell or a specific error code). // Log one assertion for each TestCase struct H3Index h; bool valid_tcx = H3_EXPORT(isValidCell)(tc.x); H3Error err = H3_EXPORT(constructCell)(tc.res, tc.bc, tc.digits, &h); bool got_expected_valid_cell = valid_tcx && (err == E_SUCCESS) && (tc.x == h); bool got_expected_error = !valid_tcx && (tc.x == err); t_assert(got_expected_valid_cell || got_expected_error, "Got valid cell or expected error."); } bool passesRoundtrip(const H3Index h) { // Test roundtrip: h3index -> components -> h3index int res = H3_EXPORT(getResolution)(h); int bc = H3_EXPORT(getBaseCellNumber)(h); int digits[15]; for (int r = 1; r <= res; r++) { if (H3_EXPORT(getIndexDigit)(h, r, &digits[r - 1]) != E_SUCCESS) { return false; } } H3Index out; if (H3_EXPORT(constructCell)(res, bc, digits, &out) != E_SUCCESS) { return false; } return out == h; } static void testRountripForRes(int res) { // Test roundtrip for all cells at given resolution. // Only count one assertion per resolution. // Otherwise, can easily overflow `globalTestCount` in test.h bool all_passed = true; IterCellsResolution iter = iterInitRes(res); while (iter.h) { if (!passesRoundtrip(iter.h)) { all_passed = false; } iterStepRes(&iter); } t_assert(all_passed, "All cells at this res passed the roundtrip"); } SUITE(constructCell) { TEST(tableOfTests) { static const TestCase tests[] = { // a few valid cell constructions {.x = 0x8001fffffffffff, .res = 0, .bc = 0, .digits = {}}, {.x = 0x8003fffffffffff, .res = 0, .bc = 1, .digits = {}}, {.x = 0x80f3fffffffffff, .res = 0, .bc = 121, .digits = {}}, {.x = 0x839253fffffffff, .res = 3, .bc = 73, .digits = {1, 2, 3}}, {.x = 0x821f67fffffffff, .res = 2, .bc = 15, .digits = {5, 4}}, {.x = 0x8155bffffffffff, .res = 1, .bc = 42, .digits = {6}}, {.x = 0x8f754e64992d6d8, .res = 15, .bc = 58, .digits = {5, 1, 6, 3, 1, 1, 1, 4, 4, 5, 5, 3, 3, 3, 0}}, // tests around resolution {.res = 16, .bc = 0, .digits = {}, .x = E_RES_DOMAIN}, {.res = 18, .bc = 0, .digits = {}, .x = E_RES_DOMAIN}, {.res = -1, .bc = 0, .digits = {}, .x = E_RES_DOMAIN}, {.res = 0, .bc = 0, .digits = {}, .x = 0x8001fffffffffff}, // tests around base cell {.res = 0, .bc = 122, .digits = {}, .x = E_BASE_CELL_DOMAIN}, {.res = 0, .bc = -1, .digits = {}, .x = E_BASE_CELL_DOMAIN}, {.res = 0, .bc = 259, .digits = {}, .x = E_BASE_CELL_DOMAIN}, {.res = 2, .bc = 122, .digits = {1, 0}, .x = E_BASE_CELL_DOMAIN}, // tests around digits {.res = 1, .bc = 40, .digits = {-1}, .x = E_DIGIT_DOMAIN}, {.res = 1, .bc = 40, .digits = {7}, .x = E_DIGIT_DOMAIN}, {.res = 1, .bc = 40, .digits = {8}, .x = E_DIGIT_DOMAIN}, {.res = 1, .bc = 40, .digits = {17}, .x = E_DIGIT_DOMAIN}, // deleted subsequence tests // bc = 4 is a pentagon base cell {.bc = 4, .digits = {0, 0, 0}, .res = 3, .x = 0x830800fffffffff}, {.bc = 4, .digits = {0, 0, 1}, .res = 3, .x = E_DELETED_DIGIT}, {.bc = 4, .digits = {0, 0, 2}, .res = 3, .x = 0x830802fffffffff}, // more deleted subsequence tests // bc = 5 is *not* a pentagon base cell {.bc = 5, .digits = {0, 0, 0}, .res = 3, .x = 0x830a00fffffffff}, {.bc = 5, .digits = {0, 0, 1}, .res = 3, .x = 0x830a01fffffffff}, {.bc = 5, .digits = {0, 0, 2}, .res = 3, .x = 0x830a02fffffffff}, // dummy test avoids a trailing comma issue {.x = E_RES_DOMAIN, .res = -1}}; for (int i = 0; i < ARRAY_SIZE(tests); i++) { runTestCase(tests[i]); } } TEST(roundtrip) { // Test roundtrip for all cells at a few resolutions testRountripForRes(0); testRountripForRes(1); testRountripForRes(2); testRountripForRes(3); testRountripForRes(4); } }