Skip to content
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
f9783b5
signature
ajfriend Aug 15, 2025
9aa8370
basic test
ajfriend Aug 15, 2025
5ceba54
basic tests working
ajfriend Aug 15, 2025
9860ab5
move tests to separate file
ajfriend Aug 15, 2025
7a750c1
better test setup
ajfriend Aug 15, 2025
ea5c54a
test for off-by-one in digits to resolution conversion
ajfriend Aug 15, 2025
efe4d86
fancy tests
ajfriend Aug 15, 2025
70008d0
testing framework
ajfriend Aug 15, 2025
026a6b8
some tests working
ajfriend Aug 16, 2025
2d0f8c9
clean up
ajfriend Aug 16, 2025
0692b29
clean
ajfriend Aug 16, 2025
565e057
error tests
ajfriend Aug 16, 2025
4c3b9b1
res 15 test
ajfriend Aug 16, 2025
18012ec
question about validity testing
ajfriend Aug 16, 2025
0c61ae7
test file summary
ajfriend Aug 16, 2025
e475dfa
invalid deleted subsequence
ajfriend Aug 17, 2025
161d9f2
one more test
ajfriend Aug 17, 2025
1e547c3
note
ajfriend Aug 17, 2025
491eead
Update installation.mdx Java for v4.3.0 (#1039)
isaacbrodsky Aug 22, 2025
12909a4
works, but not as clean as i like
ajfriend Aug 22, 2025
7e8ae64
new test setup
ajfriend Aug 23, 2025
c0758f6
new tests read cleaner
ajfriend Aug 23, 2025
cc4bf77
move over some resolution domain error tests
ajfriend Aug 23, 2025
84e73ce
translate some domain error tests
ajfriend Aug 23, 2025
bae525a
a plan is formulated
ajfriend Aug 23, 2025
a8ff615
test for invalid cells
ajfriend Aug 23, 2025
48dade3
art is alignment
ajfriend Aug 23, 2025
aa8977c
much clean.
ajfriend Aug 23, 2025
c62b484
removed test that's covered
ajfriend Aug 23, 2025
80089d6
add some new error codes
ajfriend Aug 23, 2025
244d193
better errors
ajfriend Aug 23, 2025
e3ad65b
reference: tests pass here (but don't implement deleted subsequence t…
ajfriend Aug 23, 2025
221685c
woof freely, i say
ajfriend Aug 23, 2025
65be2d0
ok, its just this one test
ajfriend Aug 23, 2025
8af934b
clean up tests and isBaseCellPentagonArr
ajfriend Aug 23, 2025
8e45165
clean
ajfriend Aug 23, 2025
11e7af4
small things
ajfriend Aug 24, 2025
e884438
notes
ajfriend Aug 24, 2025
c0217ac
roundtrip tests with iterators
ajfriend Aug 27, 2025
2981aad
we used to print one dot per cell when testing the whole res. too noi…
ajfriend Aug 28, 2025
bed0483
i think this is the better way to do it
ajfriend Aug 31, 2025
c84b416
errors should not be valid h3 indexes
ajfriend Aug 31, 2025
3a456d5
file rename note
ajfriend Aug 31, 2025
7f2d2f7
Fix valid index bug in getIndexDigit (#1042)
ajfriend Sep 8, 2025
4c56ad1
examples: update tested cmake version (#1050)
isaacbrodsky Oct 3, 2025
e9437f2
Bump algoliasearch-helper from 3.11.0 to 3.26.0 in /website (#1047)
dependabot[bot] Oct 6, 2025
08a2ee9
fix: valid index in cli (#1055)
justinhwang Oct 10, 2025
5af8ee5
Updating "README.md" to avoid confusion (#1054)
benguild Oct 13, 2025
05032d4
Add isValidIndex function (#1056)
cnaples79 Oct 13, 2025
1cbc65f
Update CHANGELOG.md for isValidIndex (#1061)
ajfriend Oct 13, 2025
d8ede43
signature
ajfriend Aug 15, 2025
a5c7f99
basic test
ajfriend Aug 15, 2025
bde884e
basic tests working
ajfriend Aug 15, 2025
f16db65
move tests to separate file
ajfriend Aug 15, 2025
e3c3307
better test setup
ajfriend Aug 15, 2025
d4bac7a
test for off-by-one in digits to resolution conversion
ajfriend Aug 15, 2025
f5978a7
fancy tests
ajfriend Aug 15, 2025
b14db3f
testing framework
ajfriend Aug 15, 2025
e640053
some tests working
ajfriend Aug 16, 2025
73e9985
clean up
ajfriend Aug 16, 2025
a02210c
clean
ajfriend Aug 16, 2025
5e48b28
error tests
ajfriend Aug 16, 2025
33f93ae
res 15 test
ajfriend Aug 16, 2025
d36a7c8
question about validity testing
ajfriend Aug 16, 2025
d697beb
test file summary
ajfriend Aug 16, 2025
0ab3606
invalid deleted subsequence
ajfriend Aug 17, 2025
0142260
one more test
ajfriend Aug 17, 2025
7b218d1
note
ajfriend Aug 17, 2025
b8035da
works, but not as clean as i like
ajfriend Aug 22, 2025
44c2151
new test setup
ajfriend Aug 23, 2025
e4e661c
new tests read cleaner
ajfriend Aug 23, 2025
2bcbf50
move over some resolution domain error tests
ajfriend Aug 23, 2025
428e4ce
translate some domain error tests
ajfriend Aug 23, 2025
9e6b993
a plan is formulated
ajfriend Aug 23, 2025
104a5f3
test for invalid cells
ajfriend Aug 23, 2025
4b35ab8
art is alignment
ajfriend Aug 23, 2025
7d5cea9
much clean.
ajfriend Aug 23, 2025
838695b
removed test that's covered
ajfriend Aug 23, 2025
31db3e5
add some new error codes
ajfriend Aug 23, 2025
df42122
better errors
ajfriend Aug 23, 2025
7118847
reference: tests pass here (but don't implement deleted subsequence t…
ajfriend Aug 23, 2025
9dde927
woof freely, i say
ajfriend Aug 23, 2025
7297ce2
ok, its just this one test
ajfriend Aug 23, 2025
d02a3da
clean up tests and isBaseCellPentagonArr
ajfriend Aug 23, 2025
4eb1018
clean
ajfriend Aug 23, 2025
5b4e0ba
small things
ajfriend Aug 24, 2025
aab9992
notes
ajfriend Aug 24, 2025
9233805
roundtrip tests with iterators
ajfriend Aug 27, 2025
5794fe1
we used to print one dot per cell when testing the whole res. too noi…
ajfriend Aug 28, 2025
17cdb05
i think this is the better way to do it
ajfriend Aug 31, 2025
adad2f6
errors should not be valid h3 indexes
ajfriend Aug 31, 2025
9c1646c
file rename note
ajfriend Aug 31, 2025
299ad93
Merge remote-tracking branch 'origin/cell_from_components' into cell_…
ajfriend Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ set(OTHER_SOURCE_FILES
src/apps/testapps/mkRandGeo.c
src/apps/testapps/testH3Api.c
src/apps/testapps/testIndexDigits.c
src/apps/testapps/testCreateCell.c
src/apps/testapps/testCellsToLinkedMultiPolygon.c
src/apps/testapps/testCellToLocalIj.c
src/apps/testapps/testCellToLocalIjInternal.c
Expand Down
1 change: 1 addition & 0 deletions CMakeTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ add_h3_test(testH3Index src/apps/testapps/testH3Index.c)
add_h3_test(testH3IndexInternal src/apps/testapps/testH3IndexInternal.c)
add_h3_test(testH3Api src/apps/testapps/testH3Api.c)
add_h3_test(testIndexDigits src/apps/testapps/testIndexDigits.c)
add_h3_test(testCreateCell src/apps/testapps/testCreateCell.c)
add_h3_test(testCellsToLinkedMultiPolygon
src/apps/testapps/testCellsToLinkedMultiPolygon.c)
add_h3_test(testH3SetToVertexGraphInternal
Expand Down
17 changes: 17 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
init: purge
mkdir build

build:
cd build; cmake -DCMAKE_BUILD_TYPE=Release ..; make

purge:
rm -rf build

test: build
./build/bin/testCreateCell

test-fast: build
cd build; make test-fast

test-slow: build
cd build; make test
161 changes: 161 additions & 0 deletions src/apps/testapps/testCreateCell.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* 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 function to create cell from components
*
* usage: `testCreateCell`
*/

#include "h3api.h"
#include "test.h"
#include "utility.h"

// Helper struct to represent validation tests
typedef struct {
H3Index h;
int res;
int bc;
int digits[15];
} CellAndComponents;

typedef struct {
H3ErrorCodes err;
int res;
int bc;
int digits[15];
} ErrorAndComponents;

H3Index components_to_cell(CellAndComponents cnc) {
H3Index h;
t_assertSuccess(H3_EXPORT(createCell)(cnc.res, cnc.bc, cnc.digits, &h));
return h;
}

CellAndComponents cell_to_components(H3Index h) {
CellAndComponents cnc = {.h = h,
.res = H3_EXPORT(getResolution)(h),
.bc = H3_EXPORT(getBaseCellNumber)(h)};

for (int r = 1; r <= cnc.res; r++) {
H3_EXPORT(getIndexDigit)(h, r, &cnc.digits[r - 1]);
}

return cnc;
}

// Validate components_to_cell and cell_to_components work based on given test
// data
void validate_cnc(CellAndComponents a) {
H3Index h = components_to_cell(a);
t_assert(h == a.h, "Index matches");
t_assert(H3_EXPORT(isValidCell)(h), "Should be valid cell");

CellAndComponents b = cell_to_components(a.h);

t_assert(a.h == b.h, "Index matches");
t_assert(a.res == b.res, "Resolution matches");
t_assert(a.bc == b.bc, "Base cell number matches");

for (int r = 1; r <= a.res; r++) {
t_assert(a.digits[r - 1] == b.digits[r - 1], "Digit matches");
}
}

void expect_error(ErrorAndComponents a) {
H3Index h;
H3Error err = H3_EXPORT(createCell)(a.res, a.bc, a.digits, &h);

t_assert(err == a.err, "Expecting an error");
}

SUITE(createCell) {
TEST(createCell) {
H3Index h;

t_assertSuccess(H3_EXPORT(createCell)(0, 0, NULL, &h));
t_assert(h == 0x8001fffffffffff, "match");
t_assert(H3_EXPORT(isValidCell)(h), "should be valid cell");

t_assertSuccess(H3_EXPORT(createCell)(0, 1, NULL, &h));
t_assert(h == 0x8003fffffffffff, "match");
t_assert(H3_EXPORT(isValidCell)(h), "should be valid cell");

t_assertSuccess(H3_EXPORT(createCell)(0, 121, NULL, &h));
t_assert(h == 0x80f3fffffffffff, "match");
t_assert(H3_EXPORT(isValidCell)(h), "should be valid cell");

// t_assertSuccess(H3_EXPORT(createCell)(0, 122, NULL, &h));
// t_assert(h == 0x80f5fffffffffff, "match");
// t_assert(!H3_EXPORT(isValidCell)(h), "should NOT be valid cell");
}

TEST(createCell2) {
H3Index h;

int res = 3;
int bc = 73;
int digits[] = {1, 2, 3};
t_assertSuccess(H3_EXPORT(createCell)(res, bc, digits, &h));

t_assert(h == 0x839253fffffffff, "match");
t_assert(H3_EXPORT(isValidCell)(h), "should be valid cell");
}

TEST(createCellFancy) {
CellAndComponents tests[] = {
{.h = 0x8001fffffffffff, .res = 0, .bc = 0, .digits = {}},
{.h = 0x8003fffffffffff, .res = 0, .bc = 1, .digits = {}},
{.h = 0x80f3fffffffffff, .res = 0, .bc = 121, .digits = {}},
{.h = 0x839253fffffffff, .res = 3, .bc = 73, .digits = {1, 2, 3}},
{.h = 0x821f67fffffffff, .res = 2, .bc = 15, .digits = {5, 4}},
{.h = 0x8155bffffffffff, .res = 1, .bc = 42, .digits = {6}},
{.h = 0x8f754e64992d6d8,
.res = 15,
.bc = 58,
.digits = {5, 1, 6, 3, 1, 1, 1, 4, 4, 5, 5, 3, 3, 3, 0}}};

for (int i = 0; i < ARRAY_SIZE(tests); i++) {
validate_cnc(tests[i]);
}
}

TEST(createCellErrors) {
ErrorAndComponents tests[] = {
{.err = E_RES_DOMAIN, .res = 16, .bc = 0, .digits = {}},
{.err = E_DOMAIN, .res = 0, .bc = 122, .digits = {}},
{.err = E_DOMAIN, .res = 1, .bc = 40, .digits = {-1}},
{.err = E_DOMAIN, .res = 1, .bc = 40, .digits = {7}},
{.err = E_DOMAIN, .res = 1, .bc = 40, .digits = {8}}};

for (int i = 0; i < ARRAY_SIZE(tests); i++) {
expect_error(tests[i]);
}
}

TEST(sneakyInvalidCell) {
// Create cell with a "deleted subsequence".
// This is the trickiest case to detect of an invalid cell.

H3Index h;
int res = 3;
int bc = 4;
int digits[] = {0, 0, 1};
t_assertSuccess(H3_EXPORT(createCell)(res, bc, digits, &h));

t_assert(h == 0x830801fffffffff, "match");
t_assert(!H3_EXPORT(isValidCell)(h), "should NOT be a valid cell");
}
}
11 changes: 11 additions & 0 deletions src/h3lib/include/h3api.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,17 @@ DECLSPEC int H3_EXPORT(getBaseCellNumber)(H3Index h);
DECLSPEC H3Error H3_EXPORT(getIndexDigit)(H3Index h, int res, int *out);
/** @} */

/** @defgroup createCell createCell
* Functions for createCell
* @{
*/
/** @brief create a cell from its components
*
**/
DECLSPEC H3Error H3_EXPORT(createCell)(int res, int baseCellNumber, int *digits,
H3Index *out);
/** @} */

/** @defgroup stringToH3 stringToH3
* Functions for stringToH3
* @{
Expand Down
32 changes: 32 additions & 0 deletions src/h3lib/lib/h3Index.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,38 @@ H3Error H3_EXPORT(getIndexDigit)(H3Index h, int res, int *out) {
return E_SUCCESS;
}

H3Error H3_EXPORT(createCell)(int res, int baseCellNumber, int *digits,
H3Index *out) {
if (res < 0 || res > MAX_H3_RES) {
return E_RES_DOMAIN;
}
if (baseCellNumber < 0 || baseCellNumber >= NUM_BASE_CELLS) {
return E_DOMAIN;
}

H3Index h = H3_INIT;
H3_SET_MODE(h, H3_CELL_MODE);
H3_SET_RESOLUTION(h, res);
H3_SET_BASE_CELL(h, baseCellNumber);
for (int r = 1; r <= res; r++) {
int d = digits[r - 1];
if (d < 0 || d > 6) {
return E_DOMAIN;
}
H3_SET_INDEX_DIGIT(h, r, d);
}

// Optional: isValidCells is a more expensive test. do we want to run it
// every time?
// if (!isValidCell(h)) {
// return E_CELL_INVALID;
// }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to allow users to specify invalid indexes if desired, as that could be used with getIndexDigit

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to only generate valid cells, I think the only missing check is for the pentagon deleted subequence, so the full call to isValidCell might not be needed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I like the idea of this function only returning valid cells. I've reworked the code towards that.


*out = h;

return E_SUCCESS;
}

/**
* Converts a string representation of an H3 index into an H3 index.
* @param str The string representation of an H3 index.
Expand Down
Loading