2016-04-01 10:46:28 +03:00
|
|
|
// Copyright 2016-present Facebook. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// tree_test.c: tests for core methods for tree creation and manipulation.
|
2016-04-01 21:19:53 +03:00
|
|
|
//
|
|
|
|
// no-check-code
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
#include "node.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "tests.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and verifies that the initial two nodes are created
|
|
|
|
* correctly.
|
|
|
|
*/
|
|
|
|
void tree_init_test() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
|
|
|
node_t *shadow_root = tree->shadow_root;
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
ASSERT(shadow_root != NULL);
|
|
|
|
ASSERT(shadow_root->num_children == 1);
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *real_root = get_child_by_index(shadow_root, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(real_root != NULL);
|
|
|
|
ASSERT(real_root->num_children == 0);
|
|
|
|
|
2016-05-03 03:03:15 +03:00
|
|
|
ASSERT(tree->consumed_memory == real_root->block_sz);
|
2016-04-01 10:46:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and adds a node.
|
|
|
|
*/
|
2016-04-09 08:34:24 +03:00
|
|
|
void tree_add_single_child() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t result =
|
|
|
|
add_or_update_path(tree, STRPLUSLEN("abc"),
|
|
|
|
checksum, SHA1_BYTES, 0);
|
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and adds a file and a directory containing a file.
|
|
|
|
*/
|
|
|
|
void tree_add_0_cousin_once_removed() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t result;
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("ab"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("abc/de"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
// verify the shadow root.
|
|
|
|
ASSERT(tree->shadow_root->num_children == 1);
|
|
|
|
|
|
|
|
// obtain the true root, verify that.
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *real_root = get_child_by_index(tree->shadow_root, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
// verify the real root.
|
|
|
|
ASSERT(real_root->num_children == 2);
|
|
|
|
|
|
|
|
// first child should be 'ab'
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *root_first_child = get_child_by_index(real_root, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(root_first_child->num_children == 0);
|
|
|
|
ASSERT(root_first_child->type == TYPE_LEAF);
|
|
|
|
ASSERT(name_compare("ab", 2, root_first_child) == 0);
|
|
|
|
|
|
|
|
// second child should be 'abc'
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *root_second_child = get_child_by_index(real_root, 1);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(root_second_child->num_children == 1);
|
|
|
|
ASSERT(root_second_child->type == TYPE_IMPLICIT);
|
2016-05-17 02:20:57 +03:00
|
|
|
ASSERT(name_compare("abc/", 4, root_second_child) == 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and adds a long skinny branch.
|
|
|
|
*/
|
|
|
|
void tree_add_long_skinny_branch() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t result;
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("ab"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("abc/de"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("abc/def/gh"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("abc/def/ghi/jkl"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and adds a bushy branch.
|
|
|
|
*/
|
|
|
|
void tree_add_bushy_branch() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t result;
|
|
|
|
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN("ab"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, 0);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
|
|
|
|
char tempbuffer[] = "abc/de?";
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < 26; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
tempbuffer[6] = 'a' + ix;
|
|
|
|
result = add_or_update_path(tree, STRPLUSLEN(tempbuffer),
|
|
|
|
checksum, SHA1_BYTES, 0);
|
|
|
|
ASSERT(result == ADD_UPDATE_PATH_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 27);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree and attempt to retrieve a couple paths that are not there.
|
|
|
|
*/
|
|
|
|
void tree_get_empty() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
get_path_result_t result = get_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(result.code == GET_PATH_NOT_FOUND);
|
|
|
|
|
|
|
|
result = get_path(tree, STRPLUSLEN("abc/def"));
|
|
|
|
ASSERT(result.code == GET_PATH_NOT_FOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes a tree, adds a single path, and attempt to retrieve it.
|
|
|
|
*/
|
|
|
|
#define ADD_GET_SIMPLE_FLAGS 0x2e
|
2016-04-09 08:33:07 +03:00
|
|
|
|
2016-04-01 10:46:28 +03:00
|
|
|
void tree_add_get_simple() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-01 10:46:28 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t add_result =
|
|
|
|
add_or_update_path(tree, STRPLUSLEN("abc"),
|
2016-04-09 08:33:07 +03:00
|
|
|
checksum, SHA1_BYTES, ADD_GET_SIMPLE_FLAGS);
|
2016-04-01 10:46:28 +03:00
|
|
|
ASSERT(add_result == ADD_UPDATE_PATH_OK);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 1);
|
|
|
|
|
|
|
|
get_path_result_t get_result = get_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(get_result.code == GET_PATH_OK);
|
2016-04-09 08:33:34 +03:00
|
|
|
ASSERT(get_result.checksum_sz == SHA1_BYTES);
|
|
|
|
ASSERT(memcmp(checksum, get_result.checksum, SHA1_BYTES) == 0);
|
|
|
|
ASSERT(get_result.flags == ADD_GET_SIMPLE_FLAGS);
|
2016-04-01 10:46:28 +03:00
|
|
|
|
|
|
|
get_result = get_path(tree, STRPLUSLEN("abc/def"));
|
|
|
|
ASSERT(get_result.code == GET_PATH_NOT_FOUND);
|
|
|
|
}
|
|
|
|
|
2016-04-09 08:34:03 +03:00
|
|
|
/**
|
|
|
|
* Initializes a tree, adds a single path, and attempt to retrieve a
|
|
|
|
* valid directory node.
|
|
|
|
*/
|
|
|
|
#define ADD_GET_SIMPLE_FLAGS 0x2e
|
|
|
|
void tree_add_get_implicit_node() {
|
|
|
|
tree_t* tree = alloc_tree();
|
|
|
|
|
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-27 01:38:58 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-09 08:34:03 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t add_result =
|
|
|
|
add_or_update_path(tree, STRPLUSLEN("abc/def"),
|
|
|
|
checksum, SHA1_BYTES, ADD_GET_SIMPLE_FLAGS);
|
|
|
|
ASSERT(add_result == ADD_UPDATE_PATH_OK);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 1);
|
|
|
|
|
|
|
|
get_path_result_t get_result = get_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(get_result.code == GET_PATH_NOT_FOUND);
|
|
|
|
}
|
|
|
|
|
2016-04-09 08:32:37 +03:00
|
|
|
/**
|
|
|
|
* Removes a non-existent path.
|
|
|
|
*/
|
|
|
|
void tree_remove_nonexistent() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-09 08:32:37 +03:00
|
|
|
|
|
|
|
remove_path_result_t remove_result = remove_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(remove_result == REMOVE_PATH_NOT_FOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a path and removes it. Then call get to verify that it was
|
|
|
|
* removed.
|
|
|
|
*/
|
|
|
|
void tree_add_remove() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-09 08:32:37 +03:00
|
|
|
|
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-09 08:32:37 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_update_path_result_t add_result =
|
|
|
|
add_or_update_path(tree, STRPLUSLEN("abc"),
|
|
|
|
checksum, SHA1_BYTES, 0);
|
|
|
|
ASSERT(add_result == ADD_UPDATE_PATH_OK);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 1);
|
|
|
|
|
|
|
|
remove_path_result_t remove_result = remove_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(remove_result == REMOVE_PATH_OK);
|
|
|
|
ASSERT(tree->num_leaf_nodes == 0);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
|
|
|
|
|
|
|
|
get_path_result_t get_result = get_path(tree, STRPLUSLEN("abc"));
|
|
|
|
ASSERT(get_result.code == GET_PATH_NOT_FOUND);
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *shadow_root = tree->shadow_root;
|
2016-04-09 08:32:37 +03:00
|
|
|
ASSERT(shadow_root->num_children == 1);
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *real_root = get_child_by_index(shadow_root, 0);
|
2016-04-09 08:32:37 +03:00
|
|
|
ASSERT(real_root->num_children == 0);
|
|
|
|
|
|
|
|
// because the directory nodes may have undergone expansion, we may not
|
|
|
|
// have the exact same memory requirement.
|
2016-05-03 03:03:15 +03:00
|
|
|
ASSERT(tree->consumed_memory == real_root->block_sz);
|
2016-04-09 08:32:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a multiple paths and then remove them.
|
|
|
|
*/
|
|
|
|
void tree_add_remove_multi() {
|
2016-04-09 08:33:07 +03:00
|
|
|
tree_t *tree = alloc_tree();
|
2016-04-09 08:32:37 +03:00
|
|
|
|
|
|
|
uint8_t checksum[SHA1_BYTES];
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (int ix = 0; ix < SHA1_BYTES; ix++) {
|
2016-04-09 08:32:37 +03:00
|
|
|
checksum[ix] = (uint8_t) ix;
|
|
|
|
}
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
char *paths_to_add[] = {
|
|
|
|
"abc",
|
|
|
|
"ab/def",
|
|
|
|
"ab/defg/hi",
|
|
|
|
"ab/defg/h/ijk",
|
|
|
|
"ab/defg/h/i/jkl/mn/op/qr",
|
|
|
|
"ab/defg/h/i/jkl/mn/op/qrs",
|
2016-04-09 08:32:37 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
const size_t num_paths = sizeof(paths_to_add) / sizeof(*paths_to_add);
|
|
|
|
|
|
|
|
for (size_t ix = 0;
|
2016-04-09 08:33:07 +03:00
|
|
|
ix < num_paths;
|
|
|
|
ix++) {
|
2016-04-09 08:32:37 +03:00
|
|
|
add_update_path_result_t add_result =
|
|
|
|
add_or_update_path(tree, STRPLUSLEN(paths_to_add[ix]),
|
|
|
|
checksum, SHA1_BYTES, 0);
|
|
|
|
ASSERT(add_result == ADD_UPDATE_PATH_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t ix = 0;
|
|
|
|
ix < num_paths;
|
2016-04-09 08:33:07 +03:00
|
|
|
ix++) {
|
2016-04-09 08:32:37 +03:00
|
|
|
remove_path_result_t remove_result =
|
|
|
|
remove_path(tree, STRPLUSLEN(paths_to_add[num_paths - ix - 1]));
|
|
|
|
ASSERT(remove_result == REMOVE_CHILD_OK);
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
for (size_t jx = 0; jx < num_paths - ix - 1; jx++) {
|
2016-04-09 08:32:37 +03:00
|
|
|
get_path_result_t get_result =
|
|
|
|
get_path(tree, STRPLUSLEN(paths_to_add[jx]));
|
|
|
|
ASSERT(get_result.code == GET_PATH_OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *shadow_root = tree->shadow_root;
|
2016-04-09 08:32:37 +03:00
|
|
|
ASSERT(shadow_root->num_children == 1);
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
node_t *real_root = get_child_by_index(shadow_root, 0);
|
2016-04-09 08:32:37 +03:00
|
|
|
ASSERT(real_root->num_children == 0);
|
|
|
|
|
|
|
|
ASSERT(tree->num_leaf_nodes == 0);
|
|
|
|
ASSERT(tree->compacted == false);
|
|
|
|
// because the directory nodes may have undergone expansion, we may not
|
|
|
|
// have the exact same memory requirement. however, we should only have
|
|
|
|
// two nodes left, so we can just sum them up directly.
|
2016-05-03 03:03:15 +03:00
|
|
|
ASSERT(tree->consumed_memory == real_root->block_sz);
|
2016-04-09 08:32:37 +03:00
|
|
|
}
|
|
|
|
|
2016-04-09 08:33:07 +03:00
|
|
|
int main(int argc, char *argv[]) {
|
2016-04-01 10:46:28 +03:00
|
|
|
tree_init_test();
|
2016-04-09 08:32:37 +03:00
|
|
|
|
2016-04-09 08:34:24 +03:00
|
|
|
tree_add_single_child();
|
2016-04-01 10:46:28 +03:00
|
|
|
tree_add_0_cousin_once_removed();
|
|
|
|
tree_add_long_skinny_branch();
|
|
|
|
tree_add_bushy_branch();
|
|
|
|
tree_get_empty();
|
|
|
|
tree_add_get_simple();
|
2016-04-09 08:34:03 +03:00
|
|
|
tree_add_get_implicit_node();
|
2016-04-09 08:32:37 +03:00
|
|
|
|
|
|
|
tree_remove_nonexistent();
|
|
|
|
tree_add_remove();
|
|
|
|
tree_add_remove_multi();
|
2016-04-01 10:46:28 +03:00
|
|
|
return 0;
|
|
|
|
}
|