Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AVLTree Implementation #118

Merged
merged 11 commits into from
Jun 26, 2020
39 changes: 39 additions & 0 deletions assembly/__tests__/avlTreeContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { AVLTree } from "../runtime";

Copy link
Contributor

Choose a reason for hiding this comment

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

Any top level code is executed at the start before the contract methods are called. So you can just define it at the top level once. However, I've found that it's best to import it from another file so that if you wanted to unit test this, the test could also import the tree. We currently have an issue with unit testing, where even though we wipe away the storage and state of the Mock VM that handles the env functions, we don't wipe away the state of the contract. This means you need access to the same tree object as the "contract" file so you can clear it. It's fine in your case because since the trees are not in the global scope they won't be used again.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I understand. Am I correct in thinking that it's imperative that unit tests and contracts use distinct prefixes when creating a collection (e.g. AVLTree)?

Copy link
Contributor

@willemneal willemneal Jun 24, 2020

Choose a reason for hiding this comment

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

The issue is that the persistent collections usually have a length or size field, which when not set reads from the storage, and when the storage is refreshed but the local collection isn't it'll have the incorrect size. So reconstructing the collection before each test ensures that the length is uninitialized and will agree with the storage. If you were to make a unit test that tests your avlTreeContract, since it's reconstructed inside each function you're fine. However, if it were a global variable that is initialized when the contract starts, this initialization will only happen once for the unit tests and since you don't have access to the tree from the unit test file, it can't change it. In this case it's best to have a third file that exports the tree, this way after each unit test you can clear the tree.

Copy link
Contributor

Choose a reason for hiding this comment

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

Furthermore, since this contract isn't tested with unit tests, it's fine to just use a global variable for the tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah I see! Changes you made make sense.

const tree = new AVLTree<u32, u32>("tree");

export function insert(key: u32, value: u32): void {
tree.insert(key, value);
}

export function remove(key: u32): void {
tree.remove(key);
}

export function has(key: u32): bool {
return tree.has(key);
}

export function getSome(key: u32): u32 {
return tree.getSome(key);
}

export function keys(): u32[] {
return tree.keys(u32.MIN_VALUE, u32.MAX_VALUE);
}

export function values(): u32[] {
return tree.values(u32.MIN_VALUE, u32.MAX_VALUE);
}

export function isBalanced(): bool {
return tree.isBalanced();
}

export function height(): u32 {
return tree.height;
}

export function size(): u32 {
return tree.size;
}
Loading