sui
sui copied to clipboard
Sui doc content issue or request https://docs.sui.io/build/move/build-test#testing-a-package
Hi, I'm new to move and sui-move.
test_scenario codes have been updated but not the corresponding docs on: https://docs.sui.io/build/move/build-test#testing-a-package.
Anyway, I edited the codes on the docs to:
#[test]
fun test_sword_transactions() {
use sui::test_scenario;
let admin = @0xABBA;
let initial_owner = @0xCAFE;
let final_owner = @0xFACE;
// first transaction executed by admin
let scenario = test_scenario::begin(admin);
{
// create the sword and transfer it to the initial owner
sword_create(42, 7, initial_owner, test_scenario::ctx(&mut scenario));
// anywhere for any expression where a &T value is used, a &mut T value can also be used
// second transaction executed by the initial sword owner
test_scenario::next_tx(&mut scenario, initial_owner);
{
// extract the sword owned by the initial owner
let sword = test_scenario::take_from_sender<Sword>(&mut scenario);
// transfer the sword to the final owner
sword_transfer(sword, final_owner, test_scenario::ctx(&mut scenario));
};
// third transaction executed by the final sword owner
test_scenario::next_tx(&mut scenario, final_owner);
{
// extract the sword owned by the final owner
let sword = test_scenario::take_from_sender<Sword>(&mut scenario);
// verify that the sword has expected properties
assert!(magic(&sword) == 42 && strength(&sword) == 7, 1);
// return the sword to the object pool (it cannot be simply "dropped")
test_scenario::return_to_sender(&mut scenario, sword);
};
test_scenario::end(scenario);
}
When I run sui move test
, it works:
...dir...\my_first_package>sui move test
INCLUDING DEPENDENCY MoveStdlib
INCLUDING DEPENDENCY Sui
BUILDING my_first_package
Running Move unit tests
[ PASS ] 0x0::my_module::test_sword_transactions
Test result: OK. Total tests: 1; passed: 1; failed: 0
My question is:
For the line let scenario = test_scenario::begin(admin);
, scenario is an instance of Scenario and Scenario is a struct from an external module, why are we able to pass a mutable reference of scenario &mut scenario
to test_scenario::ctx(&mut scenario)
on the line sword_create(42, 7, initial_owner, test_scenario::ctx(&mut scenario));
?
My guess is that because test_scenario::ctx(...)
and struct Scenario
are both defined in the same module, hence according to Privileged Struct Operations, test_scenario::ctx(...)
has the privilege to alter/access the fields of struct Scenario
.
Thank you.
Hi @jymchng Thanks for submitting this issue. I have added a few folks to help answer your question. It may take a few days for them to get to it.
Hi @amnn Could you take a look when you get a chance?
@jymchng, regarding your question
For the line
let scenario = test_scenario::begin(admin);
, scenario is an instance of Scenario and Scenario is a struct from an external module, why are we able to pass a mutable reference of scenario&mut scenario
totest_scenario::ctx(&mut scenario)
on the linesword_create(42, 7, initial_owner, test_scenario::ctx(&mut scenario));
?
There is no restriction about which functions can accept mutable references of which other types, but as you pointed out here:
because
test_scenario::ctx(...)
andstruct Scenario
are both defined in the same module, hence according to Privileged Struct Operations,test_scenario::ctx(...)
has the privilege to alter/access the fields ofstruct Scenario
.
only functions defined in the same module as a type can access fields on that type. Where this becomes relevant is when a reference is forwarded on, like in this example:
// mod_a.move
module example::mod_a {
struct A { x: u64 };
public fun new(): A { A { x: 0 } }
public fun bump(a: &mut A) { *a.x = *a.x + 1; }
}
// mod_b.move
module example::mod_b {
use example::mod_a;
public fun forward(a: &mut A) { mod_a::bump(a); }
}
// mod_c.move
module example::mod_c {
use example::mod_a;
use example::mod_b;
public entry fun run() {
let a = mod_a::new();
mod_b::forward(&mut a);
}
}
This code is perfectly legal (and safe), even though a function in mod_b
accepts a mutable reference to a type defined in mod_a
, because all it can do is pass it on to a function in mod_a
that would perform any modification in a safe way.
Thanks for spotting the docs issue as well, that should be fixed as of #5544.
Will close this issue as the docs issue has been resolved, and the question now answered. @jymchng, please feel free to re-open if you feel differently.