Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

test: Increase code coverage in AssociateTokenRecipientsStep #16927

Merged
merged 2 commits into from
Dec 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.hedera.node.app.service.token.impl.test.handlers.transfer;

import static com.hedera.hapi.node.base.ResponseCodeEnum.TOKEN_NOT_ASSOCIATED_TO_ACCOUNT;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
Expand All @@ -29,14 +30,17 @@
import com.hedera.hapi.node.base.ResponseCodeEnum;
import com.hedera.hapi.node.base.TokenTransferList;
import com.hedera.hapi.node.base.TransferList;
import com.hedera.hapi.node.state.token.TokenRelation;
import com.hedera.hapi.node.token.CryptoTransferTransactionBody;
import com.hedera.node.app.service.token.impl.handlers.transfer.AssociateTokenRecipientsStep;
import com.hedera.node.app.service.token.impl.handlers.transfer.TransferContextImpl;
import com.hedera.node.app.service.token.records.CryptoTransferStreamBuilder;
import com.hedera.node.app.spi.validation.ExpiryValidator;
import com.hedera.node.app.spi.workflows.HandleContext;
import com.hedera.node.app.spi.workflows.HandleException;
import com.hedera.node.config.testfixtures.HederaTestConfigBuilder;
import java.util.List;
import org.assertj.core.api.AssertionsForClassTypes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -61,7 +65,11 @@ public class AssociateTokenRecipientsStepTest extends StepsBase {
private CryptoTransferStreamBuilder builder;

private AssociateTokenRecipientsStep subject;
private AssociateTokenRecipientsStep subjectWithApproval;
private AssociateTokenRecipientsStep subjectNFTWithApproval;
private CryptoTransferTransactionBody txn;
private CryptoTransferTransactionBody txnWithApproval;
private CryptoTransferTransactionBody txnNFTWithApproval;
private TransferContextImpl transferContext;

@BeforeEach
Expand All @@ -71,13 +79,15 @@ public void setUp() {
refreshWritableStores();
givenStoresAndConfig(handleContext);
subject = new AssociateTokenRecipientsStep(txn);
subjectWithApproval = new AssociateTokenRecipientsStep(txnWithApproval);
subjectNFTWithApproval = new AssociateTokenRecipientsStep(txnNFTWithApproval);
transferContext = new TransferContextImpl(handleContext);
writableTokenStore.put(givenValidFungibleToken(ownerId, false, false, false, false, false));
writableTokenStore.put(givenValidNonFungibleToken(false));
}

@Test
void associatesTokenRecepients() {
void associatesTokenRecipients() {
assertThat(writableTokenRelStore.get(ownerId, fungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(ownerId, nonFungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(spenderId, fungibleTokenId)).isNull();
Expand All @@ -98,22 +108,101 @@ void associatesTokenRecepients() {
assertThat(writableTokenRelStore.get(spenderId, nonFungibleTokenId)).isNotNull();
}

@Test
void validateFungibleAllowancesAndOtherPrivateChecks() {
assertThat(writableTokenRelStore.get(ownerId, fungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(ownerId, nonFungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(spenderId, fungibleTokenId)).isNull();
assertThat(writableTokenRelStore.get(spenderId, nonFungibleTokenId)).isNull();

final var modifiedConfiguration = HederaTestConfigBuilder.create()
.withValue("entities.unlimitedAutoAssociationsEnabled", false)
.getOrCreateConfig();
given(handleContext.configuration()).willReturn(modifiedConfiguration);
given(handleContext.savepointStack()).willReturn(stack);
given(stack.getBaseBuilder(any())).willReturn(builder);
given(builder.isUserDispatch()).willThrow(new HandleException(TOKEN_NOT_ASSOCIATED_TO_ACCOUNT));

AssertionsForClassTypes.assertThatThrownBy(() -> subjectWithApproval.doIn(transferContext))
.isInstanceOf(HandleException.class);
}

@Test
void validateNFTAllowancesAndOtherPrivateChecks() {
assertThat(writableTokenRelStore.get(ownerId, fungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(ownerId, nonFungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(spenderId, fungibleTokenId)).isNull();
assertThat(writableTokenRelStore.get(spenderId, nonFungibleTokenId)).isNull();

final var modifiedConfiguration = HederaTestConfigBuilder.create()
.withValue("entities.unlimitedAutoAssociationsEnabled", true)
.getOrCreateConfig();
given(handleContext.configuration()).willReturn(modifiedConfiguration);
given(handleContext.savepointStack()).willReturn(stack);
given(stack.getBaseBuilder(any())).willReturn(builder);
given(builder.isUserDispatch()).willReturn(true);

AssertionsForClassTypes.assertThatThrownBy(() -> subjectNFTWithApproval.doIn(transferContext))
.isInstanceOf(HandleException.class);
}

@Test
void validateNFTAllowancesAndForceToThrow() {
assertThat(writableTokenRelStore.get(ownerId, fungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(ownerId, nonFungibleTokenId)).isNotNull();
assertThat(writableTokenRelStore.get(spenderId, fungibleTokenId)).isNull();
assertThat(writableTokenRelStore.get(spenderId, nonFungibleTokenId)).isNull();
writableTokenRelStore.remove(TokenRelation.newBuilder()
.accountId(ownerId)
.tokenId(nonFungibleTokenId)
.build());
final var modifiedConfiguration = HederaTestConfigBuilder.create()
.withValue("entities.unlimitedAutoAssociationsEnabled", true)
.getOrCreateConfig();
given(handleContext.configuration()).willReturn(modifiedConfiguration);
given(handleContext.savepointStack()).willReturn(stack);

AssertionsForClassTypes.assertThatThrownBy(() -> subjectNFTWithApproval.doIn(transferContext))
.isInstanceOf(HandleException.class);
}

void givenValidTxn() {
txn = CryptoTransferTransactionBody.newBuilder()
.transfers(TransferList.newBuilder()
.accountAmounts(adjustFrom(ownerId, -1_000))
.accountAmounts(adjustFrom(spenderId, +1_000))
.accountAmounts(adjustFrom(ownerId, -1_000, false))
.accountAmounts(adjustFrom(spenderId, +1_000, false))
.build())
.tokenTransfers(
TokenTransferList.newBuilder()
.token(fungibleTokenId)
.transfers(List.of(adjustFrom(ownerId, -1_000), adjustFrom(spenderId, +1_000)))
.transfers(List.of(
adjustFrom(ownerId, -1_000, false), adjustFrom(spenderId, +1_000, false)))
.build(),
TokenTransferList.newBuilder()
.token(nonFungibleTokenId)
.nftTransfers(nftTransferWith(ownerId, spenderId, 1))
.nftTransfers(nftTransferWith(ownerId, spenderId, 1, false))
.build())
.build();
txnWithApproval = CryptoTransferTransactionBody.newBuilder()
.transfers(TransferList.newBuilder()
.accountAmounts(adjustFrom(ownerId, -1_000, true))
.accountAmounts(adjustFrom(spenderId, -1_000, true))
.build())
.tokenTransfers(TokenTransferList.newBuilder()
.token(fungibleTokenId)
.transfers(List.of(adjustFrom(ownerId, -1_000, true), adjustFrom(spenderId, -1_000, true)))
.build())
.build();
txnNFTWithApproval = CryptoTransferTransactionBody.newBuilder()
.transfers(TransferList.newBuilder()
.accountAmounts(adjustFrom(ownerId, -1_000, true))
.accountAmounts(adjustFrom(spenderId, -1_000, true))
.build())
.tokenTransfers(TokenTransferList.newBuilder()
.token(nonFungibleTokenId)
.nftTransfers(nftTransferWith(ownerId, spenderId, 1, true))
.build())
.build();
given(handleContext.configuration()).willReturn(configuration);
given(handleContext.expiryValidator()).willReturn(expiryValidator);
lenient()
Expand All @@ -122,15 +211,20 @@ void givenValidTxn() {
given(handleContext.savepointStack()).willReturn(stack);
}

private AccountAmount adjustFrom(AccountID account, long amount) {
return AccountAmount.newBuilder().accountID(account).amount(amount).build();
private AccountAmount adjustFrom(AccountID account, long amount, boolean isApproval) {
return AccountAmount.newBuilder()
.accountID(account)
.amount(amount)
.isApproval(isApproval)
.build();
}

private NftTransfer nftTransferWith(AccountID from, AccountID to, long serialNo) {
private NftTransfer nftTransferWith(AccountID from, AccountID to, long serialNo, boolean isApproval) {
return NftTransfer.newBuilder()
.senderAccountID(from)
.receiverAccountID(to)
.serialNumber(serialNo)
.isApproval(isApproval)
.build();
}
}