Skip to content

value problem of struct on test process #22260

New issue

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

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

Already on GitHub? Sign in to your account

Open
cxp-13 opened this issue May 29, 2025 · 3 comments
Open

value problem of struct on test process #22260

cxp-13 opened this issue May 29, 2025 · 3 comments

Comments

@cxp-13
Copy link

cxp-13 commented May 29, 2025

I define a struct

public struct ReferralBook has key {
    id: UID,
    referrals: Table<address, address>,
}

but when test get error that

error[E06001]: unused value without 'drop'
   ┌─ ./tests/referral_tests.move:31:33
   │
15 │     let mut _referral_book  = init_for_testing(ctx1);
   │         ------------------ The local variable '_referral_book' still contains a value. The value does not have the 'drop' ability and must be consumed before the function returns
   ·
31 │     test_scenario::end(scenario);
   │                                 ^ Invalid return

test code:

#[test]
fun test_successful_invitation() {
    let mut scenario = test_scenario::begin(@0x123);

    // 第一阶段:使用 ctx 初始化 referral_book
    let ctx1 = test_scenario::ctx(&mut scenario);
    let mut _referral_book  = init_for_testing(ctx1);

    // 下一笔交易前释放 ctx1 的引用
    test_scenario::next_tx(&mut scenario, @0x123);

    let inviter = @0x123;
    let invitee = @0x456;

    // 第二阶段:重新获取 ctx 并记录 referral
    let ctx2 = test_scenario::ctx(&mut scenario);
    referral::record_referral(&mut _referral_book , inviter, invitee, ctx2);

    // 第三阶段:验证 inviter
    let inviter_opt = referral::get_inviter(&_referral_book , invitee);
    assert!(option::is_some(&inviter_opt), 0);
    assert!(*option::borrow(&inviter_opt) == inviter, 0);
    test_scenario::end(scenario);
}

I try to add drop ability but the ID and table can't accept it.

Copy link
Contributor

Thank you for opening this issue, a team member will review it shortly. Until then, please do not interact with any users that claim to be from Sui support and do not click on any links!

@hyd628
Copy link
Collaborator

hyd628 commented May 29, 2025

You are creating an instance of an asset (ReferralBook) which cannot be automatically dropped at the end of the scope. You need to either consume it somehow or transfer it somewhere or just return it with your function.

https://intro.sui-book.com/unit-one/lessons/3_custom_types_and_abilities.html

@cxp-13
Copy link
Author

cxp-13 commented May 29, 2025

You are creating an instance of an asset (ReferralBook) which cannot be automatically dropped at the end of the scope. You need to either consume it somehow or transfer it somewhere or just return it with your function.

https://intro.sui-book.com/unit-one/lessons/3_custom_types_and_abilities.html

My project very simple.
code:

module referral::referral;

use std::string;
use sui::event;
use sui::object::{Self, UID};
use sui::table::{Self, Table};
use sui::transfer;
use sui::tx_context::{Self, TxContext};

/// The main storage struct that tracks all referral relationships
public struct ReferralBook has key {
    id: UID,
    referrals: Table<address, address>,
}

/// Event emitted when a new referral is recorded
public struct ReferralEvent has copy, drop {
    inviter: address,
    invitee: address,
}

/// Error codes
const E_SELF_REFERRAL: u64 = 1;
const E_ALREADY_INVITED: u64 = 2;

/// Initializes the ReferralBook and shares it so it can be accessed by anyone
fun init(ctx: &mut TxContext) {
    let referral_book = ReferralBook {
        id: object::new(ctx),
        referrals: table::new(ctx),
    };
    transfer::share_object(referral_book);
}

#[test_only]
public fun init_for_test(ctx: &mut TxContext): ReferralBook {
    ReferralBook {
        id: object::new(ctx),
        referrals: table::new(ctx),
    }
}

/// Records a new referral relationship
public entry fun record_referral(
    referral_book: &mut ReferralBook,
    inviter: address,
    invitee: address,
    ctx: &mut TxContext,
) {
    // Check that user isn't inviting themselves
    assert!(inviter != invitee, E_SELF_REFERRAL);

    // Check that invitee hasn't been invited before
    assert!(!table::contains(&referral_book.referrals, invitee), E_ALREADY_INVITED);

    // Add the referral relationship
    table::add(&mut referral_book.referrals, invitee, inviter);

    // Emit event
    event::emit(ReferralEvent {
        inviter,
        invitee,
    });
}

/// Gets the inviter for a given invitee
public fun get_inviter(referral_book: &ReferralBook, invitee: address): address {
    assert!(table::contains(&referral_book.referrals, invitee), E_ALREADY_INVITED);
    *table::borrow(&referral_book.referrals, invitee)
}

/// Public entry function to query inviter
public entry fun query_inviter(referral_book: &ReferralBook, invitee: address): address {
    get_inviter(referral_book, invitee)
}

unit test:

#[test_only]
module referral::referral_tests;

use referral::referral::{Self, ReferralBook, init_for_test};
use std::string;
use sui::test_scenario;
use sui::tx_context;

#[test]
fun test_successful_invitation() {
    let mut scenario = test_scenario::begin(@0x0);
    let ctx = test_scenario::ctx(&mut scenario);

    // Initialize the referral book
    let mut referral_book = referral::init_for_test(ctx);

    // Get the shared ReferralBook object
    // let referral_book = test_scenario::take_shared<ReferralBook>(&scenario);
    // let referral_book_id = object::id(&referral_book);

    // Test addresses
    let inviter = @0xA;
    let invitee = @0xB;

    // Record a referral
    referral::record_referral(&mut referral_book, inviter, invitee, ctx);

    // Verify the referral was recorded
    let recorded_inviter = referral::get_inviter(&referral_book, invitee);
    assert!(recorded_inviter == inviter, 0);

    // Return the shared object to the scenario
    // test_scenario::return_shared(referral_book);
    test_scenario::end(scenario);
}

// #[test]
// #[expected_failure(abort_code = 2)]
// fun test_double_invitation_fails() {
//     let scenario = test_scenario::begin(@0x0);
//     let ctx = test_scenario::ctx(&mut scenario);

//     // Initialize the referral book
//     referral::init(ctx);

//     // Get the shared ReferralBook object
//     let referral_book = test_scenario::take_shared<ReferralBook>(&scenario);
//     let referral_book_id = object::id(&referral_book);

//     // Test addresses
//     let inviter1 = @0xA;
//     let inviter2 = @0xC;
//     let invitee = @0xB;

//     // First referral should succeed
//     referral::record_referral(&mut referral_book, inviter1, invitee, ctx);

//     // Second referral should fail
//     referral::record_referral(&mut referral_book, inviter2, invitee, ctx);

//     // Return the shared object to the scenario
//     test_scenario::return_shared(referral_book);
//     test_scenario::end(scenario);
// }

// #[test]
// #[expected_failure(abort_code = 1)]
// fun test_self_invitation_fails() {
//     let scenario = test_scenario::begin(@0x0);
//     let ctx = test_scenario::ctx(&mut scenario);

//     // Initialize the referral book
//     referral::init(ctx);

//     // Get the shared ReferralBook object
//     let referral_book = test_scenario::take_shared<ReferralBook>(&scenario);
//     let referral_book_id = object::id(&referral_book);

//     // Test address
//     let user = @0xA;

//     // Attempt to invite self should fail
//     referral::record_referral(&mut referral_book, user, user, ctx);

//     // Return the shared object to the scenario
//     test_scenario::return_shared(referral_book);
//     test_scenario::end(scenario);
// }

// #[test]
// fun test_query_inviter() {
//     let scenario = test_scenario::begin(@0x0);
//     let ctx = test_scenario::ctx(&mut scenario);

//     // Initialize the referral book
//     referral::init(ctx);

//     // Get the shared ReferralBook object
//     let referral_book = test_scenario::take_shared<ReferralBook>(&scenario);
//     let referral_book_id = object::id(&referral_book);

//     // Test addresses
//     let inviter = @0xA;
//     let invitee = @0xB;

//     // Record a referral
//     referral::record_referral(&mut referral_book, inviter, invitee, ctx);

//     // Test the query function
//     let recorded_inviter = referral::query_inviter(&referral_book, invitee);
//     assert!(recorded_inviter == inviter, 0);

//     // Return the shared object to the scenario
//     test_scenario::return_shared(referral_book);
//     test_scenario::end(scenario);
// }

but you can see the error that I can't add drop to struct due to table is not accept.

error[E06001]: unused value without 'drop'
   ┌─ ./tests/referral_tests.move:34:33
   │
15 │     let mut referral_book = referral::init_for_test(ctx);
   │         ----------------- The local variable 'referral_book' still contains a value. The value does not have the 'drop' ability and must be consumed before the function returns
   ·
34 │     test_scenario::end(scenario);
   │                                 ^ Invalid return
   │
   ┌─ ./sources/referral.move:11:15
   │
11 │ public struct ReferralBook has key {
   │               ------------ To satisfy the constraint, the 'drop' ability would need to be added here
   ·
36 │ public fun init_for_test(ctx: &mut TxContext): ReferralBook {
   │                              

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants