diff --git a/sway-lib-std/src/storage.sw b/sway-lib-std/src/storage.sw index f48b71534c3..6bd9e565560 100644 --- a/sway-lib-std/src/storage.sw +++ b/sway-lib-std/src/storage.sw @@ -1,7 +1,11 @@ library r#storage; -use ::hash::sha256; +use ::assert::assert; use ::context::registers::stack_ptr; +use ::hash::sha256; +use ::option::Option; +use ::result::Result; + /// Store a stack variable in storage. #[storage(write)]pub fn store(key: b256, value: T) { @@ -106,3 +110,189 @@ impl StorageMap { get::(key) } } + +/// A persistant vector struct +pub struct StorageVec {} + +impl StorageVec { + /// Appends the value to the end of the vector + /// + /// # Arguments + /// + /// * `value` - The item being added to the end of the vector + #[storage(read, write)] + pub fn push(self, value: V) { + // The length of the vec is stored in the __get_storage_key() slot + let len = get::(__get_storage_key()); + + // Storing the value at the current length index (if this is the first item, starts off at 0) + let key = sha256((len, __get_storage_key())); + store::(key, value); + + // Incrementing the length + store(__get_storage_key(), len + 1); + } + + /// Removes the last element of the vector and returns it, None if empty + #[storage(read, write)] + pub fn pop(self) -> Option { + let len = get::(__get_storage_key()); + // if the length is 0, there is no item to pop from the vec + if len == 0 { + return Option::None; + } + + // reduces len by 1, effectively removing the last item in the vec + store(__get_storage_key(), len - 1); + + let key = sha256((len - 1, __get_storage_key())); + Option::Some::(get::(key)) + } + + /// Gets the value in the given index, None if index is out of bounds + /// + /// # Arguments + /// + /// * `index` - The index of the vec to retrieve the item from + #[storage(read)] + pub fn get(self, index: u64) -> Option { + let len = get::(__get_storage_key()); + // if the index is larger or equal to len, there is no item to return + if len <= index { + return Option::None; + } + + let key = sha256((index, __get_storage_key())); + Option::Some::(get::(key)) + } + + /// Removes the element in the given index and moves all the element in the following indexes + /// Down one index. Also returns the element + /// + /// # WARNING + /// + /// Expensive for larger vecs + /// + /// # Arguments + /// + /// * `index` - The index of the vec to remove the item from + /// + /// # Reverts + /// + /// Reverts if index is larger or equal to length of the vec + #[storage(read, write)] + pub fn remove(self, index: u64) -> V { + let len = get::(__get_storage_key()); + // if the index is larger or equal to len, there is no item to remove + assert(index < len); + + // gets the element before removing it, so it can be returned + let removed_element = get::(sha256((index, __get_storage_key()))); + + // for every element in the vec with an index greater than the input index, + // shifts the index for that element down one + let mut count = index + 1; + while count < len { + // gets the storage location for the previous index + let key = sha256((count - 1, __get_storage_key())); + // moves the element of the current index into the previous index + store::(key, get::(sha256((count, __get_storage_key())))); + + count += 1; + } + + // decrements len by 1 + store(__get_storage_key(), len - 1); + + removed_element + } + + /// Removes the element at the specified index and fills it with the last element + /// Does not preserve ordering. Also returns the element + /// + /// # Arguments + /// + /// * `index` - The index of the vec to remove the item from + /// + /// # Reverts + /// + /// Reverts if index is larger or equal to length of the vec + #[storage(read, write)] + pub fn swap_remove(self, index: u64) -> V { + let len = get::(__get_storage_key()); + // if the index is larger or equal to len, there is no item to remove + assert(index < len); + + let hash_of_to_be_removed = sha256((index, __get_storage_key())); + // gets the element before removing it, so it can be returned + let element_to_be_removed = get::(hash_of_to_be_removed); + + let last_element = get::(sha256((len - 1, __get_storage_key()))); + store::(hash_of_to_be_removed, last_element); + + // decrements len by 1 + store(__get_storage_key(), len - 1); + + element_to_be_removed + } + + /// Inserts the value at the given index, moving the current index's value aswell as the following's + /// Up one index + /// + /// # WARNING + /// + /// Expensive for larger vecs + /// + /// # Arguments + /// + /// * `index` - The index of the vec to insert the item into + /// * `value` - The value to insert into the vec + /// + /// # Reverts + /// + /// Reverts if index is larger than length of the vec + #[storage(read, write)] + pub fn insert(self, index: u64, value: V) { + let len = get::(__get_storage_key()); + // if the index is larger than len, there is no space to insert + assert(index <= len); + + // for every element in the vec with an index larger than the input index, + // move the element up one index. + // performed in reverse to prevent data overwriting + let mut count = len-1; + while count >= index { + let key = sha256((count + 1, __get_storage_key())); + // shifts all the values up one index + store::(key, get::(sha256((count, __get_storage_key())))); + + count -= 1 + } + + // inserts the value into the now unused index + let key = sha256((index, __get_storage_key())); + store::(key, value); + + // increments len by 1 + store(__get_storage_key(), len + 1); + } + + /// Returns the length of the vector + #[storage(read)] + pub fn len(self) -> u64 { + get::(__get_storage_key()) + } + + /// Checks whether the len is 0 or not + #[storage(read)] + pub fn is_empty(self) -> bool { + let len = get::(__get_storage_key()); + len == 0 + } + + /// Sets the len to 0 + #[storage(write)] + pub fn clear(self) { + store(__get_storage_key(), 0); + } +} diff --git a/test/src/sdk-harness/build.sh b/test/src/sdk-harness/build.sh index 35459acd2c3..638675782bc 100755 --- a/test/src/sdk-harness/build.sh +++ b/test/src/sdk-harness/build.sh @@ -27,7 +27,7 @@ while true; do fi done -test_dirs="${base_dir}/test_artifacts/* ${base_dir}/test_projects/*" +test_dirs="${base_dir}/test_artifacts/* ${base_dir}/test_projects/* ${base_dir}/test_artifacts/*/*" for test_dir in $test_dirs; do if [[ -f "${test_dir}/Forc.toml" ]]; then diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.lock new file mode 100644 index 00000000000..37516c69109 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-BAD4826C86E6CE3D' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-BAD4826C86E6CE3D' +dependencies = ['core'] + +[[package]] +name = 'svec_b256' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.toml new file mode 100644 index 00000000000..1b1da6edb36 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_b256" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw new file mode 100644 index 00000000000..1d5b6e4e617 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_b256/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn b256_push(value: b256); + #[storage(read)] + fn b256_get(index: u64) -> b256; + #[storage(read, write)] + fn b256_pop() -> b256; + #[storage(read, write)] + fn b256_remove(index: u64) -> b256; + #[storage(read, write)] + fn b256_swap_remove(index: u64) -> b256; + #[storage(read, write)] + fn b256_insert(index: u64, value: b256); + #[storage(read)] + fn b256_len() -> u64; + #[storage(read)] + fn b256_is_empty() -> bool; + #[storage(write)] + fn b256_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn b256_push(value: b256) { + storage.my_vec.push(value); + } + #[storage(read)] + fn b256_get(index: u64) -> b256 { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn b256_pop() -> b256 { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn b256_remove(index: u64) -> b256 { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn b256_swap_remove(index: u64) -> b256 { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn b256_insert(index: u64, value: b256) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn b256_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn b256_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn b256_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.lock new file mode 100644 index 00000000000..d16c4ca4065 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-112F6FFCFCECE066' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-112F6FFCFCECE066' +dependencies = ['core'] + +[[package]] +name = 'svec_bool' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.toml new file mode 100644 index 00000000000..e7681654fa1 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_bool" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw new file mode 100644 index 00000000000..b0f44012eaa --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_bool/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn bool_push(value: bool); + #[storage(read)] + fn bool_get(index: u64) -> bool; + #[storage(read, write)] + fn bool_pop() -> bool; + #[storage(read, write)] + fn bool_remove(index: u64) -> bool; + #[storage(read, write)] + fn bool_swap_remove(index: u64) -> bool; + #[storage(read, write)] + fn bool_insert(index: u64, value: bool); + #[storage(read)] + fn bool_len() -> u64; + #[storage(read)] + fn bool_is_empty() -> bool; + #[storage(write)] + fn bool_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn bool_push(value: bool) { + storage.my_vec.push(value); + } + #[storage(read)] + fn bool_get(index: u64) -> bool { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn bool_pop() -> bool { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn bool_remove(index: u64) -> bool { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn bool_swap_remove(index: u64) -> bool { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn bool_insert(index: u64, value: bool) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn bool_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn bool_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn bool_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.lock new file mode 100644 index 00000000000..06f1f17cd10 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-BA7DA646BFFC59D3' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-BA7DA646BFFC59D3' +dependencies = ['core'] + +[[package]] +name = 'svec_enum' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.toml new file mode 100644 index 00000000000..6714176a6a2 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_enum" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw new file mode 100644 index 00000000000..94f6c54667d --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_enum/src/main.sw @@ -0,0 +1,72 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +enum TestEnum { + A: bool, + B: u16, +} + +abi MyContract { + #[storage(read, write)] + fn enum_push(value: TestEnum); + #[storage(read)] + fn enum_get(index: u64) -> TestEnum; + #[storage(read, write)] + fn enum_pop() -> TestEnum; + #[storage(read, write)] + fn enum_remove(index: u64) -> TestEnum; + #[storage(read, write)] + fn enum_swap_remove(index: u64) -> TestEnum; + #[storage(read, write)] + fn enum_insert(index: u64, value: TestEnum); + #[storage(read)] + fn enum_len() -> u64; + #[storage(read)] + fn enum_is_empty() -> bool; + #[storage(write)] + fn enum_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn enum_push(value: TestEnum) { + storage.my_vec.push(value); + } + #[storage(read)] + fn enum_get(index: u64) -> TestEnum { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn enum_pop() -> TestEnum { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn enum_remove(index: u64) -> TestEnum { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn enum_swap_remove(index: u64) -> TestEnum { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn enum_insert(index: u64, value: TestEnum) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn enum_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn enum_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn enum_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.lock new file mode 100644 index 00000000000..117a72a36a9 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-5A8E0F2C8C65E65F' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-5A8E0F2C8C65E65F' +dependencies = ['core'] + +[[package]] +name = 'svec_str' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.toml new file mode 100644 index 00000000000..d65b979ece3 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_str" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw new file mode 100644 index 00000000000..aba2250e206 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_str/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn str_push(value: str[4]); + #[storage(read)] + fn str_get(index: u64) -> str[4]; + #[storage(read, write)] + fn str_pop() -> str[4]; + #[storage(read, write)] + fn str_remove(index: u64) -> str[4]; + #[storage(read, write)] + fn str_swap_remove(index: u64) -> str[4]; + #[storage(read, write)] + fn str_insert(index: u64, value: str[4]); + #[storage(read)] + fn str_len() -> u64; + #[storage(read)] + fn str_is_empty() -> bool; + #[storage(write)] + fn str_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn str_push(value: str[4]) { + storage.my_vec.push(value); + } + #[storage(read)] + fn str_get(index: u64) -> str[4] { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn str_pop() -> str[4] { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn str_remove(index: u64) -> str[4] { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn str_swap_remove(index: u64) -> str[4] { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn str_insert(index: u64, value: str[4]) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn str_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn str_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn str_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.lock new file mode 100644 index 00000000000..e185915ccb2 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-5D548BD88B479EAC' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-5D548BD88B479EAC' +dependencies = ['core'] + +[[package]] +name = 'svec_struct' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.toml new file mode 100644 index 00000000000..8ad370c395f --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_struct" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw new file mode 100644 index 00000000000..f9fe22c983e --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_struct/src/main.sw @@ -0,0 +1,72 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +struct TestStruct { + A: bool, + B: u16, +} + +abi MyContract { + #[storage(read, write)] + fn struct_push(value: TestStruct); + #[storage(read)] + fn struct_get(index: u64) -> TestStruct; + #[storage(read, write)] + fn struct_pop() -> TestStruct; + #[storage(read, write)] + fn struct_remove(index: u64) -> TestStruct; + #[storage(read, write)] + fn struct_swap_remove(index: u64) -> TestStruct; + #[storage(read, write)] + fn struct_insert(index: u64, value: TestStruct); + #[storage(read)] + fn struct_len() -> u64; + #[storage(read)] + fn struct_is_empty() -> bool; + #[storage(write)] + fn struct_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn struct_push(value: TestStruct) { + storage.my_vec.push(value); + } + #[storage(read)] + fn struct_get(index: u64) -> TestStruct { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn struct_pop() -> TestStruct { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn struct_remove(index: u64) -> TestStruct { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn struct_swap_remove(index: u64) -> TestStruct { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn struct_insert(index: u64, value: TestStruct) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn struct_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn struct_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn struct_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.lock new file mode 100644 index 00000000000..3b133df026f --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-D2C27CF3A144E426' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-D2C27CF3A144E426' +dependencies = ['core'] + +[[package]] +name = 'svec_u16' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.toml new file mode 100644 index 00000000000..a2f5b819f5b --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_u16" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw new file mode 100644 index 00000000000..db8f8f48ce6 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u16/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn u16_push(value: u16); + #[storage(read)] + fn u16_get(index: u64) -> u16; + #[storage(read, write)] + fn u16_pop() -> u16; + #[storage(read, write)] + fn u16_remove(index: u64) -> u16; + #[storage(read, write)] + fn u16_swap_remove(index: u64) -> u16; + #[storage(read, write)] + fn u16_insert(index: u64, value: u16); + #[storage(read)] + fn u16_len() -> u64; + #[storage(read)] + fn u16_is_empty() -> bool; + #[storage(write)] + fn u16_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn u16_push(value: u16) { + storage.my_vec.push(value); + } + #[storage(read)] + fn u16_get(index: u64) -> u16 { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn u16_pop() -> u16 { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn u16_remove(index: u64) -> u16 { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn u16_swap_remove(index: u64) -> u16 { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn u16_insert(index: u64, value: u16) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn u16_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn u16_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn u16_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.lock new file mode 100644 index 00000000000..233fdbca046 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-273E1774DB1237EA' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-273E1774DB1237EA' +dependencies = ['core'] + +[[package]] +name = 'svec_u32' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.toml new file mode 100644 index 00000000000..8356145b78d --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_u32" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw new file mode 100644 index 00000000000..1b01726def1 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u32/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn u32_push(value: u32); + #[storage(read)] + fn u32_get(index: u64) -> u32; + #[storage(read, write)] + fn u32_pop() -> u32; + #[storage(read, write)] + fn u32_remove(index: u64) -> u32; + #[storage(read, write)] + fn u32_swap_remove(index: u64) -> u32; + #[storage(read, write)] + fn u32_insert(index: u64, value: u32); + #[storage(read)] + fn u32_len() -> u64; + #[storage(read)] + fn u32_is_empty() -> bool; + #[storage(write)] + fn u32_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn u32_push(value: u32) { + storage.my_vec.push(value); + } + #[storage(read)] + fn u32_get(index: u64) -> u32 { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn u32_pop() -> u32 { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn u32_remove(index: u64) -> u32 { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn u32_swap_remove(index: u64) -> u32 { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn u32_insert(index: u64, value: u32) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn u32_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn u32_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn u32_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.lock new file mode 100644 index 00000000000..e7ac2c09eda --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-1BF264D58B073501' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-1BF264D58B073501' +dependencies = ['core'] + +[[package]] +name = 'svec_u64' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.toml new file mode 100644 index 00000000000..beb8efb4f34 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_u64" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw new file mode 100644 index 00000000000..a3251772846 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u64/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn u64_push(value: u64); + #[storage(read)] + fn u64_get(index: u64) -> u64; + #[storage(read, write)] + fn u64_pop() -> u64; + #[storage(read, write)] + fn u64_remove(index: u64) -> u64; + #[storage(read, write)] + fn u64_swap_remove(index: u64) -> u64; + #[storage(read, write)] + fn u64_insert(index: u64, value: u64); + #[storage(read)] + fn u64_len() -> u64; + #[storage(read)] + fn u64_is_empty() -> bool; + #[storage(write)] + fn u64_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn u64_push(value: u64) { + storage.my_vec.push(value); + } + #[storage(read)] + fn u64_get(index: u64) -> u64 { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn u64_pop() -> u64 { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn u64_remove(index: u64) -> u64 { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn u64_swap_remove(index: u64) -> u64 { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn u64_insert(index: u64, value: u64) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn u64_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn u64_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn u64_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/.gitignore b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.lock b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.lock new file mode 100644 index 00000000000..b382eba9f5c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'core' +source = 'path+from-root-0A9A4F1E1D370290' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-0A9A4F1E1D370290' +dependencies = ['core'] + +[[package]] +name = 'svec_u8' +source = 'root' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.toml b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.toml new file mode 100644 index 00000000000..66a399e3211 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "svec_u8" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw new file mode 100644 index 00000000000..27534066c37 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/storage_vec/svec_u8/src/main.sw @@ -0,0 +1,67 @@ +contract; + +use std::{option::Option, result::Result, storage::StorageVec}; + +abi MyContract { + #[storage(read, write)] + fn u8_push(value: u8); + #[storage(read)] + fn u8_get(index: u64) -> u8; + #[storage(read, write)] + fn u8_pop() -> u8; + #[storage(read, write)] + fn u8_remove(index: u64) -> u8; + #[storage(read, write)] + fn u8_swap_remove(index: u64) -> u8; + #[storage(read, write)] + fn u8_insert(index: u64, value: u8); + #[storage(read)] + fn u8_len() -> u64; + #[storage(read)] + fn u8_is_empty() -> bool; + #[storage(write)] + fn u8_clear(); +} + +storage { + my_vec: StorageVec = StorageVec {}, +} + +impl MyContract for Contract { + #[storage(read, write)] + fn u8_push(value: u8) { + storage.my_vec.push(value); + } + #[storage(read)] + fn u8_get(index: u64) -> u8 { + storage.my_vec.get(index).unwrap() + } + #[storage(read, write)] + fn u8_pop() -> u8 { + storage.my_vec.pop().unwrap() + } + #[storage(read, write)] + fn u8_remove(index: u64) -> u8 { + storage.my_vec.remove(index) + } + #[storage(read, write)] + fn u8_swap_remove(index: u64) -> u8 { + storage.my_vec.swap_remove(index) + } + #[storage(read, write)] + fn u8_insert(index: u64, value: u8) { + storage.my_vec.insert(index, value); + } + #[storage(read)] + fn u8_len() -> u64 { + storage.my_vec.len() + } + #[storage(read)] + fn u8_is_empty() -> bool { + storage.my_vec.is_empty() + } + #[storage(write)] + fn u8_clear() { + storage.my_vec.clear(); + } +} diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index 481425e9e25..78e97103c4c 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -15,5 +15,6 @@ mod registers; mod script_data; mod storage; mod storage_map; +mod storage_vec; mod token_ops; mod tx_fields; diff --git a/test/src/sdk-harness/test_projects/storage_vec/b256/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/b256/mod.rs new file mode 100644 index 00000000000..78a744a3ac8 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/b256/mod.rs @@ -0,0 +1,254 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +const BYTES1: [u8; 32] = [1; 32]; +const BYTES2: [u8; 32] = [2; 32]; +const BYTES3: [u8; 32] = [3; 32]; +const BYTES4: [u8; 32] = [4; 32]; +const BYTES5: [u8; 32] = [5; 32]; + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, BYTES1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, BYTES1); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, BYTES1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, BYTES1); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, BYTES1).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, BYTES1); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES2, get(&instance, 1).await); + assert_eq!(BYTES3, get(&instance, 2).await); + assert_eq!(BYTES4, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, BYTES3); + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES2, get(&instance, 1).await); + assert_eq!(BYTES4, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES2, get(&instance, 1).await); + assert_eq!(BYTES3, get(&instance, 2).await); + assert_eq!(BYTES4, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, BYTES2); + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES4, get(&instance, 1).await); + assert_eq!(BYTES3, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES2, get(&instance, 1).await); + assert_eq!(BYTES3, get(&instance, 2).await); + assert_eq!(BYTES4, get(&instance, 3).await); + + insert(&instance, 1, BYTES5).await; + + assert_eq!(BYTES1, get(&instance, 0).await); + assert_eq!(BYTES5, get(&instance, 1).await); + assert_eq!(BYTES2, get(&instance, 2).await); + assert_eq!(BYTES3, get(&instance, 3).await); + assert_eq!(BYTES4, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, BYTES5).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, BYTES1).await; + push(&instance, BYTES2).await; + push(&instance, BYTES3).await; + push(&instance, BYTES4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, BYTES5).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/b256/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/b256/utils.rs new file mode 100644 index 00000000000..cb825715187 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/b256/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_b256/out/debug/svec_b256-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_b256/out/debug/svec_b256.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_b256/out/debug/svec_b256-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: [u8; 32]) { + instance.b256_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> [u8; 32] { + instance.b256_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> [u8; 32] { + instance.b256_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> [u8; 32] { + instance.b256_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> [u8; 32] { + instance.b256_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: [u8; 32]) { + instance.b256_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.b256_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.b256_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.b256_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/bool/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/bool/mod.rs new file mode 100644 index 00000000000..8ccf82a8e3f --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/bool/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, true).await; + let item = get(&instance, 0).await; + + assert_eq!(item, true); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, true).await; + let item = get(&instance, 0).await; + + assert_eq!(item, true); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, true).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, true); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(false, get(&instance, 1).await); + assert_eq!(true, get(&instance, 2).await); + assert_eq!(false, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, true); + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(false, get(&instance, 1).await); + assert_eq!(false, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(false, get(&instance, 1).await); + assert_eq!(true, get(&instance, 2).await); + assert_eq!(false, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, false); + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(false, get(&instance, 1).await); + assert_eq!(true, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(false, get(&instance, 1).await); + assert_eq!(true, get(&instance, 2).await); + assert_eq!(false, get(&instance, 3).await); + + insert(&instance, 1, true).await; + + assert_eq!(true, get(&instance, 0).await); + assert_eq!(true, get(&instance, 1).await); + assert_eq!(false, get(&instance, 2).await); + assert_eq!(true, get(&instance, 3).await); + assert_eq!(false, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, false).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, true).await; + push(&instance, false).await; + push(&instance, true).await; + push(&instance, false).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, true).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/bool/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/bool/utils.rs new file mode 100644 index 00000000000..6ce6dbcf1f4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/bool/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_bool/out/debug/svec_bool-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_bool/out/debug/svec_bool.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_bool/out/debug/svec_bool-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: bool) { + instance.bool_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> bool { + instance.bool_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> bool { + instance.bool_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> bool { + instance.bool_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> bool { + instance.bool_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: bool) { + instance.bool_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.bool_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.bool_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.bool_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/enum/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/enum/mod.rs new file mode 100644 index 00000000000..d178e18463c --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/enum/mod.rs @@ -0,0 +1,255 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, + TestEnum, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +const ENUM1: TestEnum = TestEnum::A(true); +const ENUM2: TestEnum = TestEnum::A(false); +const ENUM3: TestEnum = TestEnum::B(1); +const ENUM4: TestEnum = TestEnum::B(2); +const ENUM5: TestEnum = TestEnum::B(3); + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, ENUM1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, ENUM1); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, ENUM1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, ENUM1); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, ENUM1).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, ENUM1); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM2, get(&instance, 1).await); + assert_eq!(ENUM3, get(&instance, 2).await); + assert_eq!(ENUM4, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, ENUM3); + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM2, get(&instance, 1).await); + assert_eq!(ENUM4, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM2, get(&instance, 1).await); + assert_eq!(ENUM3, get(&instance, 2).await); + assert_eq!(ENUM4, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, ENUM2); + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM4, get(&instance, 1).await); + assert_eq!(ENUM3, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM2, get(&instance, 1).await); + assert_eq!(ENUM3, get(&instance, 2).await); + assert_eq!(ENUM4, get(&instance, 3).await); + + insert(&instance, 1, ENUM5).await; + + assert_eq!(ENUM1, get(&instance, 0).await); + assert_eq!(ENUM5, get(&instance, 1).await); + assert_eq!(ENUM2, get(&instance, 2).await); + assert_eq!(ENUM3, get(&instance, 3).await); + assert_eq!(ENUM4, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, ENUM4).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, ENUM1).await; + push(&instance, ENUM2).await; + push(&instance, ENUM3).await; + push(&instance, ENUM4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, ENUM5).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/enum/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/enum/utils.rs new file mode 100644 index 00000000000..1ff5b442970 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/enum/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_enum/out/debug/svec_enum-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_enum/out/debug/svec_enum.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_enum/out/debug/svec_enum-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: TestEnum) { + instance.enum_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> TestEnum { + instance.enum_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> TestEnum { + instance.enum_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> TestEnum { + instance.enum_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> TestEnum { + instance.enum_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: TestEnum) { + instance.enum_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.enum_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.enum_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.enum_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/mod.rs new file mode 100644 index 00000000000..5dcb56cf8a3 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/mod.rs @@ -0,0 +1,9 @@ +mod b256; +mod bool; +mod r#enum; +mod str; +mod r#struct; +mod u16; +mod u32; +mod u64; +mod u8; diff --git a/test/src/sdk-harness/test_projects/storage_vec/str/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/str/mod.rs new file mode 100644 index 00000000000..d40df2495c9 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/str/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, String::from("0050")).await; + let item = get(&instance, 0).await; + + assert_eq!(item, String::from("0050")); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, String::from("0050")).await; + let item = get(&instance, 0).await; + + assert_eq!(item, String::from("0050")); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, String::from("0050")).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, String::from("0050")); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0100"), get(&instance, 1).await); + assert_eq!(String::from("0150"), get(&instance, 2).await); + assert_eq!(String::from("0200"), get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, String::from("0150")); + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0100"), get(&instance, 1).await); + assert_eq!(String::from("0200"), get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0100"), get(&instance, 1).await); + assert_eq!(String::from("0150"), get(&instance, 2).await); + assert_eq!(String::from("0200"), get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, String::from("0100")); + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0200"), get(&instance, 1).await); + assert_eq!(String::from("0150"), get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0100"), get(&instance, 1).await); + assert_eq!(String::from("0150"), get(&instance, 2).await); + assert_eq!(String::from("0200"), get(&instance, 3).await); + + insert(&instance, 1, String::from("0250")).await; + + assert_eq!(String::from("0050"), get(&instance, 0).await); + assert_eq!(String::from("0250"), get(&instance, 1).await); + assert_eq!(String::from("0100"), get(&instance, 2).await); + assert_eq!(String::from("0150"), get(&instance, 3).await); + assert_eq!(String::from("0200"), get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, String::from("0200")).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, String::from("0050")).await; + push(&instance, String::from("0100")).await; + push(&instance, String::from("0150")).await; + push(&instance, String::from("0200")).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, String::from("0250")).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/str/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/str/utils.rs new file mode 100644 index 00000000000..11d4f50174a --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/str/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_str/out/debug/svec_str-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_str/out/debug/svec_str.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_str/out/debug/svec_str-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: String) { + instance.str_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> String { + instance.str_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> String { + instance.str_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> String { + instance.str_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> String { + instance.str_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: String) { + instance.str_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.str_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.str_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.str_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/struct/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/struct/mod.rs new file mode 100644 index 00000000000..746f49d94b6 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/struct/mod.rs @@ -0,0 +1,255 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, + TestStruct, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +const STRUCT1: TestStruct = TestStruct { a: true, b: 1 }; +const STRUCT2: TestStruct = TestStruct { a: false, b: 2 }; +const STRUCT3: TestStruct = TestStruct { a: true, b: 3 }; +const STRUCT4: TestStruct = TestStruct { a: false, b: 4 }; +const STRUCT5: TestStruct = TestStruct { a: true, b: 5 }; + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, STRUCT1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, STRUCT1); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, STRUCT1).await; + let item = get(&instance, 0).await; + + assert_eq!(item, STRUCT1); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, STRUCT1).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, STRUCT1); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT2, get(&instance, 1).await); + assert_eq!(STRUCT3, get(&instance, 2).await); + assert_eq!(STRUCT4, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, STRUCT3); + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT2, get(&instance, 1).await); + assert_eq!(STRUCT4, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT2, get(&instance, 1).await); + assert_eq!(STRUCT3, get(&instance, 2).await); + assert_eq!(STRUCT4, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, STRUCT2); + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT4, get(&instance, 1).await); + assert_eq!(STRUCT3, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT2, get(&instance, 1).await); + assert_eq!(STRUCT3, get(&instance, 2).await); + assert_eq!(STRUCT4, get(&instance, 3).await); + + insert(&instance, 1, STRUCT5).await; + + assert_eq!(STRUCT1, get(&instance, 0).await); + assert_eq!(STRUCT5, get(&instance, 1).await); + assert_eq!(STRUCT2, get(&instance, 2).await); + assert_eq!(STRUCT3, get(&instance, 3).await); + assert_eq!(STRUCT4, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, STRUCT4).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, STRUCT1).await; + push(&instance, STRUCT2).await; + push(&instance, STRUCT3).await; + push(&instance, STRUCT4).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, STRUCT5).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/struct/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/struct/utils.rs new file mode 100644 index 00000000000..b796c085860 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/struct/utils.rs @@ -0,0 +1,76 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_struct/out/debug/svec_struct-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_struct/out/debug/svec_struct.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_struct/out/debug/svec_struct-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: TestStruct) { + instance.struct_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> TestStruct { + instance.struct_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> TestStruct { + instance.struct_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> TestStruct { + instance.struct_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> TestStruct { + instance + .struct_swap_remove(index) + .call() + .await + .unwrap() + .value + } + + pub async fn insert(instance: &MyContract, index: u64, value: TestStruct) { + instance.struct_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.struct_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.struct_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.struct_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u16/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/u16/mod.rs new file mode 100644 index 00000000000..58b6a9f33d4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u16/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, 50); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, 150); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(200, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, 100); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(200, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + insert(&instance, 1, 250).await; + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(250, get(&instance, 1).await); + assert_eq!(100, get(&instance, 2).await); + assert_eq!(150, get(&instance, 3).await); + assert_eq!(200, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, 200).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, 250).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u16/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/u16/utils.rs new file mode 100644 index 00000000000..8b5fb9179e8 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u16/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_u16/out/debug/svec_u16-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_u16/out/debug/svec_u16.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_u16/out/debug/svec_u16-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: u16) { + instance.u16_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> u16 { + instance.u16_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> u16 { + instance.u16_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> u16 { + instance.u16_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> u16 { + instance.u16_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: u16) { + instance.u16_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.u16_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.u16_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.u16_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u32/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/u32/mod.rs new file mode 100644 index 00000000000..58b6a9f33d4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u32/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, 50); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, 150); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(200, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, 100); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(200, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + insert(&instance, 1, 250).await; + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(250, get(&instance, 1).await); + assert_eq!(100, get(&instance, 2).await); + assert_eq!(150, get(&instance, 3).await); + assert_eq!(200, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, 200).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, 250).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u32/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/u32/utils.rs new file mode 100644 index 00000000000..3e762215989 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u32/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_u32/out/debug/svec_u32-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_u32/out/debug/svec_u32.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_u32/out/debug/svec_u32-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: u32) { + instance.u32_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> u32 { + instance.u32_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> u32 { + instance.u32_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> u32 { + instance.u32_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> u32 { + instance.u32_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: u32) { + instance.u32_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.u32_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.u32_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.u32_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u64/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/u64/mod.rs new file mode 100644 index 00000000000..58b6a9f33d4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u64/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, 50); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, 150); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(200, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, 100); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(200, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + insert(&instance, 1, 250).await; + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(250, get(&instance, 1).await); + assert_eq!(100, get(&instance, 2).await); + assert_eq!(150, get(&instance, 3).await); + assert_eq!(200, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, 200).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, 250).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u64/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/u64/utils.rs new file mode 100644 index 00000000000..18d3db04eee --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u64/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_u64/out/debug/svec_u64-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_u64/out/debug/svec_u64.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_u64/out/debug/svec_u64-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: u64) { + instance.u64_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> u64 { + instance.u64_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> u64 { + instance.u64_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> u64 { + instance.u64_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> u64 { + instance.u64_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: u64) { + instance.u64_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.u64_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.u64_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.u64_clear().call().await.unwrap(); + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u8/mod.rs b/test/src/sdk-harness/test_projects/storage_vec/u8/mod.rs new file mode 100644 index 00000000000..58b6a9f33d4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u8/mod.rs @@ -0,0 +1,248 @@ +mod utils; + +use utils::{ + setup::get_contract_instance, + wrappers::{clear, get, insert, is_empty, len, pop, push, remove, swap_remove}, +}; + +// TODO: Replace many of the get calls with direct storage values +// once the SDK supports that + +mod success { + use super::*; + + #[tokio::test] + async fn can_get() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + } + + #[tokio::test] + async fn can_push() { + let (instance, _id) = get_contract_instance().await; + + let len_before_push = len(&instance).await; + assert_eq!(len_before_push, 0); + + push(&instance, 50).await; + let item = get(&instance, 0).await; + + assert_eq!(item, 50); + + let len_after_push = len(&instance).await; + assert_eq!(len_after_push, 1); + } + + #[tokio::test] + async fn can_pop() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + let len_before_pop = len(&instance).await; + assert_eq!(len_before_pop, 1); + + let item = pop(&instance).await; + assert_eq!(item, 50); + + let len_after_pop = len(&instance).await; + assert_eq!(len_after_pop, 0); + } + + #[tokio::test] + async fn can_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = remove(&instance, 2).await; + assert_eq!(item, 150); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(200, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + let item = swap_remove(&instance, 1).await; + assert_eq!(item, 100); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(200, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 3); + } + + #[tokio::test] + async fn can_insert() { + let (instance, _id) = get_contract_instance().await; + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(100, get(&instance, 1).await); + assert_eq!(150, get(&instance, 2).await); + assert_eq!(200, get(&instance, 3).await); + + insert(&instance, 1, 250).await; + + assert_eq!(50, get(&instance, 0).await); + assert_eq!(250, get(&instance, 1).await); + assert_eq!(100, get(&instance, 2).await); + assert_eq!(150, get(&instance, 3).await); + assert_eq!(200, get(&instance, 4).await); + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_get_len() { + let (instance, _id) = get_contract_instance().await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 0); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let len_vec = len(&instance).await; + assert_eq!(len_vec, 4); + + push(&instance, 200).await; + let len_vec = len(&instance).await; + + assert_eq!(len_vec, 5); + } + + #[tokio::test] + async fn can_confirm_emptiness() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } + + #[tokio::test] + async fn can_clear() { + let (instance, _id) = get_contract_instance().await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + + push(&instance, 50).await; + push(&instance, 100).await; + push(&instance, 150).await; + push(&instance, 200).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, false); + + clear(&instance).await; + + let isempty = is_empty(&instance).await; + assert_eq!(isempty, true); + } +} + +// Some of these are meant to be tests for None returns but since the SDK doesnt support options; +// the options are being unwrapped in the contract and tested as reverts instead +mod failure { + use super::*; + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_get() { + let (instance, _id) = get_contract_instance().await; + + get(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_pop() { + let (instance, _id) = get_contract_instance().await; + + pop(&instance).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_swap_remove() { + let (instance, _id) = get_contract_instance().await; + + let _ = swap_remove(&instance, 0).await; + } + + #[tokio::test] + #[should_panic(expected = "Revert(0)")] + async fn cant_insert() { + let (instance, _id) = get_contract_instance().await; + + insert(&instance, 1, 250).await; + } +} diff --git a/test/src/sdk-harness/test_projects/storage_vec/u8/utils.rs b/test/src/sdk-harness/test_projects/storage_vec/u8/utils.rs new file mode 100644 index 00000000000..5ad1a3e74c8 --- /dev/null +++ b/test/src/sdk-harness/test_projects/storage_vec/u8/utils.rs @@ -0,0 +1,71 @@ +use fuels::{prelude::*, tx::ContractId}; +// Load abi from json +abigen!( + MyContract, + "test_artifacts/storage_vec/svec_u8/out/debug/svec_u8-abi.json" +); + +pub mod setup { + use super::*; + + pub async fn get_contract_instance() -> (MyContract, ContractId) { + // Launch a local network and deploy the contract + let wallet = launch_provider_and_get_wallet().await; + + let id = Contract::deploy( + "test_artifacts/storage_vec/svec_u8/out/debug/svec_u8.bin", + &wallet, + TxParameters::default(), + StorageConfiguration::with_storage_path(Some( + "test_artifacts/storage_vec/svec_u8/out/debug/svec_u8-storage_slots.json" + .to_string(), + )), + ) + .await + .unwrap(); + + let instance = MyContract::new(id.to_string(), wallet); + + (instance, id) + } +} + +pub mod wrappers { + use super::*; + + pub async fn push(instance: &MyContract, value: u8) { + instance.u8_push(value).call().await.unwrap(); + } + + pub async fn get(instance: &MyContract, index: u64) -> u8 { + instance.u8_get(index).call().await.unwrap().value + } + + pub async fn pop(instance: &MyContract) -> u8 { + instance.u8_pop().call().await.unwrap().value + } + + pub async fn remove(instance: &MyContract, index: u64) -> u8 { + instance.u8_remove(index).call().await.unwrap().value + } + + pub async fn swap_remove(instance: &MyContract, index: u64) -> u8 { + instance.u8_swap_remove(index).call().await.unwrap().value + } + + pub async fn insert(instance: &MyContract, index: u64, value: u8) { + instance.u8_insert(index, value).call().await.unwrap(); + } + + pub async fn len(instance: &MyContract) -> u64 { + instance.u8_len().call().await.unwrap().value + } + + pub async fn is_empty(instance: &MyContract) -> bool { + instance.u8_is_empty().call().await.unwrap().value + } + + pub async fn clear(instance: &MyContract) { + instance.u8_clear().call().await.unwrap(); + } +}