How to hydrate a test case in Matchstick - thegraph

I am trying to test some code that tracks transfers of a token. What I am running into is, that I set my sender to start with 20 tokens. However, when my actual code does a Load, it sees that Holder as null, and so gets initialized to 0. The ID of that entity is just the address.
Do I have to do something to like....get them to use the same database or something like that?
Here is my test case. Note that USER_1 is starting with 20 tokens.
test("Can handle new Transfer", () => {
const USER_1 = new Holder("0x11a964a5a0308b2eC87D3e1ab2b1E14Ea00f6974");
USER_1.stellaHolding = BigInt.fromI32(20);
USER_1.save();
const USER_2 = new Holder("0x21a964a5a0308b2eC87D3e1ab2b1E14Ea00f6974")
USER_2.stellaHolding = BigInt.fromI32(0);
USER_2.save();
const newTransferEvent = createNewStellaEvent(Address.fromString(USER_1.id), Address.fromString(USER_2.id), BigInt.fromI32(10));
handleStellaTransfer(newTransferEvent);
const actual = Holder.load(USER_1.id);
if(actual == null){
assert.assertNotNull(false);
return;
}
assert.fieldEquals("Holder", actual.id, "stellaHolding", BigInt.fromI32(10).toString());
})
Here is the function that my test code is calling
export function handleStellaTransfer(event: Transfer): void {
const stella = updateStella(event);
updateReceiver(event, stella);
updateSender(event, stella);
stella.save();
}
And here is the function of interest. Note that the sender is NULL when I load it in.
function updateSender(event: Transfer, stella: Stella): void {
const senderAddr = event.params.from.toHexString();
let sender = Holder.load(senderAddr);
log.info("{}", [senderAddr])
if(sender == null){
log.info("{}", ["This shouldn't happen x2?"])
sender = new Holder(senderAddr);
//Is 0 the right number for this? Double check this later
sender.stellaHolding = BigInt.fromI32(0);
}
log.info("{}", ["Sender"])
log.info("{}", [sender.stellaHolding.toString()])
sender.stellaHolding = sender.stellaHolding.minus(event.params.value);
log.info("{}", [sender.stellaHolding.toString()])
if(! isHolder(sender)){
stella.holders--;
}
sender.lastTransaction = event.block.timestamp;
sender.save();
}

Related

Error: value out-of-bounds on callbackGasLimit variable

i have written a simple contract in solidity as seen below
/**
* #title Lottery
* #notice Enter lottery by paying some amount
* #notice pick a random number( verifiably random)
* #notice winner be selected every xtimes
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "#chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "#chainlink/contracts/src/v0.8/interfaces/KeeperCompatibleInterface.sol";
// ============= Errors ====================
error Lottery__NotEnoughFunds();
error Lottery__TransferFailed();
error Lottery__NotOpen();
error Raffle__UpkeepNotNeeded(uint256 currentBalance, uint256 numPlayers, uint256 raffleState);
contract Lottery is VRFConsumerBaseV2, KeeperCompatibleInterface {
// ============= Type declaration ===========
enum LotteryState {
OPEN,
CALCULATING
}
// ======== state variables ============
uint256 private immutable i_entranceFee;
address payable[] private s_players;
bytes32 private immutable i_gasLane;
uint64 private immutable i_subscriptionId;
uint32 private immutable i_callbackGasLimit;
uint16 private constant REQUEST_CONFIRMATION = 3;
uint32 private constant NUM_WORDS = 1;
VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
address private s_recentwinner;
LotteryState private s_lotteryState;
uint256 private s_lastTimeStamp;
uint256 private immutable i_interval;
// ========== Events ==================
event LotteryEnter(address indexed player);
event RandomwinnerRequest(uint256 indexed requestId);
event WinnerPicked(address indexed winner);
// ========= constructor ============
constructor(
address vrfCoordinatorV2,
uint256 entranceFee,
uint32 callbackGasLimit,
uint256 interval,
bytes32 gasLane,
uint64 subscriptionId
) VRFConsumerBaseV2(vrfCoordinatorV2) {
i_entranceFee = entranceFee;
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
i_gasLane = gasLane;
i_subscriptionId = subscriptionId;
i_callbackGasLimit = callbackGasLimit;
s_lotteryState = LotteryState.OPEN;
i_interval = interval;
s_lastTimeStamp = block.timestamp;
}
// ========== functions ============
function enterLottery() public payable {
if (msg.value < i_entranceFee) {
revert Lottery__NotEnoughFunds();
}
if (s_lotteryState != LotteryState.OPEN ) {
revert Lottery__NotOpen();
}
s_players.push(payable(msg.sender));
emit LotteryEnter(msg.sender);
}
function checkUpkeep(
bytes memory /* checkData */
)
public
view
override
returns (
bool upkeepNeeded,
bytes memory /* performData */
)
{
bool isOpen = LotteryState.OPEN == s_lotteryState;
bool timePassed = ((block.timestamp - s_lastTimeStamp) > i_interval);
bool hasPlayers = s_players.length > 0;
bool hasBalance = address(this).balance > 0;
upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers);
// return (upkeepNeeded, "0x0"); // can we comment this out?
}
function performUpkeep( bytes calldata /* performData */) external override {
( bool upKeepNeeded, ) = checkUpkeep("");
if(!upKeepNeeded){
revert Raffle__UpkeepNotNeeded(
address(this).balance,
s_players.length,
uint256(s_lotteryState)
);
}
// Request a random number
// Once we get it , do something with it
s_lotteryState = LotteryState.CALCULATING;
uint256 requestId = i_vrfCoordinator.requestRandomWords(
i_gasLane,
i_subscriptionId,
REQUEST_CONFIRMATION,
i_callbackGasLimit,
NUM_WORDS
);
emit RandomwinnerRequest(requestId);
}
function fulfillRandomWords(uint256 /*requestId*/, uint256[] memory randomWords) internal override {
// Modulo function
uint256 winnerIndex = randomWords[0] % s_players.length;
address payable recentWinner = s_players[winnerIndex];
s_recentwinner = recentWinner;
s_lotteryState = LotteryState.OPEN;
s_players = new address payable[](0);
s_lastTimeStamp = block.timestamp;
(bool success, ) = recentWinner.call{value: address(this).balance}("");
if (!success) {
revert Lottery__TransferFailed();
}
emit WinnerPicked(recentWinner);
}
// =============== View /Pure functions =============
function getEntraceFee() public view returns (uint256) {
return i_entranceFee;
}
function getPlayers(uint256 index) public view returns (address) {
return s_players[index];
}
function getRecentWinner() public view returns (address) {
return s_recentwinner;
}
function getRaffleState() public view returns (LotteryState) {
return s_lotteryState;
}
function getNumWords() public pure returns (uint256) {
return NUM_WORDS;
}
function getRequestConfirmations() public pure returns (uint256) {
return REQUEST_CONFIRMATION;
}
function getLastTimeStamp() public view returns (uint256) {
return s_lastTimeStamp;
}
function getInterval() public view returns (uint256) {
return i_interval;
}
function getNumberOfPlayers() public view returns (uint256) {
return s_players.length;
}
}
and it deploy script
const { network, ethers } = require("hardhat");
const {
developmentChains,
networkConfig,
VERIFICATION_BLOCK_CONFIRMATIONS,
} = require("../helper-hardhat-config");
const { verify } = require("../utils/verify");
const VR_FUND_AMOUNT = ethers.utils.parseEther("4");
module.exports = async function ({ getNamedAccounts, deployments }) {
const { deploy, log } = deployments;
const { deployer } = await getNamedAccounts();
const chainId = network.config.chainId;
let vrfCoordinatorV2Address, subscriptionId;
if (developmentChains.includes(network.name)) {
const vrfCoordinatorV2Mock = await ethers.getContract(
"VRFCoordinatorV2Mock"
);
vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address;
const transactionResponse = await vrfCoordinatorV2Mock.createSubscription();
const transactionReceipt = await transactionResponse.wait(1);
subscriptionId = transactionReceipt.events[0].args.subId;
// fund the subscription
await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, VR_FUND_AMOUNT);
} else {
vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinatorV2"];
subscriptionId = networkConfig[chainId]["subscriptionId"];
}
const entranceFee = networkConfig[chainId]["entranceFee"];
const gasLane = networkConfig[chainId]["gasLane"];
const callbackGasLimit = networkConfig[chainId]["callbackGasLimit"];
const interval = networkConfig[chainId]["interval"];
const args = [
vrfCoordinatorV2Address,
entranceFee,
gasLane,
subscriptionId,
callbackGasLimit,
interval,
];
const lottery = await deploy("Lottery", {
from: deployer,
args: args,
log: true,
waitConfirmations: network.config.blockConfirmations || 1,
});
if (
!developmentChains.includes(network.name) &&
process.env.ETHERSCAN_API_KEY
) {
log("Verifying.....");
await verify(lottery.address, args);
}
log("-----------------------------------");
};
module.exports.tags = ["all", "lottery"];
mock deploy script
const { network } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")
const BASE_FEE = ethers.utils.parseEther("0.25") // 0.25 is this the premium in LINK?
const GAS_PRICE_LINK = 1e9 // link per gas, is this the gas lane? // 0.000000001 LINK per gas
module.exports = async function ({ getNamedAccounts, deployments }) {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
const args =[BASE_FEE, GAS_PRICE_LINK]
// If we are on a local development network, we need to deploy mocks!
if(developmentChains.includes(network.name)){
log("Local Network Detected! Deploying mocks...")
// deploy a mock vrfCoordinator
await deploy("VRFCoordinatorV2Mock",{
from:deployer,
log:true,
args:args,
})
log("Mocks Deployed!")
log("------------------------------------------")
}
}
module.exports.tags = ["all", "mocks"]
and helper configuration
const { ethers } = require("hardhat")
const networkConfig = {
5:{
name:"goerli",
vrfCoordinatorV2:"0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D",
entranceFee: ethers.utils.parseEther("0.01"),
gasLane:"0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
subscriptionId:"0",
callbackGasLimit:"500000",
interval:"30"
},
31337:{
name:"hardhat",
entranceFee: ethers.utils.parseEther("0.01"),
gasLane:"0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
callbackGasLimit:"500000",
interval:"30"
}
}
const developmentChains = ["hardhat", "localhost"]
module.exports = {
networkConfig,
developmentChains
}
when run yarn hardhat deploy, i encounter an error
as below
An unexpected error occurred:
Error: ERROR processing C:\Users\amoko\Desktop\blockchain\lottery\deploy\01-deploy-lottery.js:
Error: value out-of-bounds (argument="callbackGasLimit", value="0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15", code=INVALID_ARGUMENT, version=abi/5.7.0)
at Logger.makeError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\logger\src.ts\index.ts:269:28)
at Logger.throwError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\logger\src.ts\index.ts:281:20)
at Logger.throwArgumentError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\logger\src.ts\index.ts:285:21)
at NumberCoder.Coder._throwError (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\coders\abstract-coder.ts:68:16)
at NumberCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\coders\number.ts:35:18)
at C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\coders\array.ts:71:19
at Array.forEach (<anonymous>)
at pack (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\coders\array.ts:54:12)
at TupleCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\coders\tuple.ts:54:20)
at AbiCoder.encode (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\#ethersproject\abi\src.ts\abi-coder.ts:111:15)
at DeploymentsManager.executeDeployScripts (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\DeploymentsManager.ts:1222:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at runNextTicks (node:internal/process/task_queues:65:3)
at listOnTimeout (node:internal/timers:528:9)
at processTimers (node:internal/timers:502:7)
at DeploymentsManager.runDeploy (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\DeploymentsManager.ts:1052:5)
at SimpleTaskDefinition.action (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\index.ts:438:5)
at Environment._runTaskDefinition (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat\src\internal\core\runtime-environment.ts:308:14)
at Environment.run (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat\src\internal\core\runtime-environment.ts:156:14)
at SimpleTaskDefinition.action (C:\Users\amoko\Desktop\blockchain\lottery\node_modules\hardhat-deploy\src\index.ts:584:32)
error Command failed with exit code 1.
i need help on figuring out why is it is propagting this error and how to fix it
I have tried changing the callbackgasLimit but it still brings the error. i expect the contract to get deployed on my localhost network when i run yarn hardhat deploy
i discovered that i had used a wrong variable(raffleState) in defining the event "Raffle__UpkeepNotNeeded" so it was leading to a significant increase in gas fees which were exceeding the max gas limit set for the testnet hence the error

Catch StatusCode from execution value in Xunit

I want to compare the return value from controller execution whether that fulfill the condition or not. From debugging I noticed the 'StatusCode' but not got an way to catch that value for comparing. My Code for testing is
public void PostAmount_Withdraw_Returns_Null()
{
// Arrange
Amount amount = new Amount() { Id = 0, PaymentDate = DateTime.Today,
PaymentTypeId = 3, PaymentAmount = 500, ClientId = 1, Balance = 0 };
_accountServiceMock.Setup(s => s.Withdraw(amount)).Throws(new Exception());
var target = SetupAmountsController();
//Act
var actual = target.PostAmount(amount);
//Assert
actual.ShouldNotBeNull();
//actual.Value.ShouldBe(response);
}
What call controller methods below : -
public ActionResult<Amount> PostAmount(Amount amount)
{
try
{
if (amount.PaymentTypeId == 1)
{
_accountService.Deposit(amount);
}
else if (amount.PaymentTypeId == 2)
{
_accountService.Withdraw(amount);
}
else
{
return Problem("Model 'Amounts' is null.");
}
return new OkObjectResult(new { Message = "Payment Success!" });
}
catch (DbUpdateConcurrencyException)
{
return Problem("There was error for updating model Payment");
}
}
And, returned the value after execution from Unit Test
I want to give condition likes below: -
actual.Result.StatusCode = HttpStatusCode.BadRequest or
actual.Result.StatusCode = 500
Just got the answer. It will be likes below: -
(actual.Result as ObjectResult).StatusCode.ShouldBe((int)HttpStatusCode.InternalServerError);
you need to define here 'status code' what want to compare. In my case it was 500.

MVC Entity Framework, Query returns null

Hi guys can you help me understand why i keep getting a null instead of get the value.
Need to receive the saidaservicoid to be able to update. I receive the value from the view but can't update elemento. Stays null.
Thanks in advance for the help.
[Database]
[elementoRepository]
public async Task UpdateElementoSaidaServicosAsync(AddSaidasServicoViewModel model)
{
var saidaServico = await _context.SaidaServicos.FindAsync(model.SaidaServicoId);
var elemento = await _context.Elementos.FindAsync(model.ElementoId);
if (elemento == null)
{
return;
}
var updateElementoSaida = _context.Elementos.Where(e => e.Id == model.ElementoId).FirstOrDefault();
if (updateElementoSaida == null)
{
updateElementoSaida = new Elemento
{
saidaServico = saidaServico,
};
_context.Elementos.Update(updateElementoSaida);
}
else
{
int SaidaServicos = model.SaidaServicoId;
updateElementoSaida.saidaServico = saidaServico;
}
await _context.SaveChangesAsync();
return;
}
Ok. the best way that i found to solve this issue was to get the last ID.
int SaidaServicos = _context.SaidaServicos.Max(item => item.Id);

Moq + xunit + asp.net core: service return null value

I use xUnit as test runner in my asp.net core application.
Here is my test theory:
[Theory(DisplayName = "Search advisors by advisorId"),
ClassData(typeof(SearchAdvisorsByIdTestData))]
public async void SearchAdvisors_ByAdvisorId(int brokerDealerId, FilterParams filter)
{
// Arrange
var _repositoryMock = new Mock<IRepository>();
// Do this section means we bypass the repository layer
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
}))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
);
_advisorService = new AdvisorService(_repositoryMock.Object, _brokerDealerRepositoryMock, _brokerDealerServiceMock);
// Action
var model = await _advisorService.Search(brokerDealerId, filter);
Assert.True(model.AdvisorResults.Count == 1);
Assert.True(model.AdvisorResults[0].LocationResults.Count > 0);
}
The service like this
public async Task<ViewModelBase> Search(int brokerDealerId, FilterParams filter)
{
var opts = new AdvisorSearchOptions
{
SearchKey = filter.SeachKey,
AdvisorId = filter.AdvisorId,
BranchId = filter.BranchId,
City = filter.City,
Skip = filter.Skip,
Limit = filter.Limit,
RadiusInMiles = filter.Limit,
Longitude = filter.Longitude,
Latitude = filter.Latitude
};
var searchResults = await _repository.SearchAdvisors(filter.CID.Value, opts); // line 64 here
if (searchResults.Count == 0 && Utils.IsZipCode(filter.SeachKey))
{
}
//Some other code here
return model;
}
The issue was after run line 64 in the service. I always get null value of searchResults although I already mocked _repository in the test.
What was my wrong there?
Thank in advance.
Argument matcher for SearchAdvisors() mock does not work because you pass different instances of AdvisorSearchOptions. First instance is created in _repositoryMock.Setup() statement and the second one is created in Search() method itself.
There are several ways to fix this problem:
1.If you don't care about verifying whether instance of AdvisorSearchOptions passed to repository is filled correctly, just use It.IsAny<AdvisorSearchOptions>() matcher in mock setup:
_repositoryMock.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(/*...*/);
2.In previous case the test will not verify that AdvisorSearchOptions is filled correctly. To do this, you could override Object.Equals() method in AdvisorSearchOptions class so that mock call will match for different instances:
public class AdvisorSearchOptions
{
// ...
public override bool Equals(object obj)
{
var cmp = obj as AdvisorSearchOptions;
if (cmp == null)
{
return false;
}
return SearchKey == cmp.SearchKey && AdvisorId == cmp.AdvisorId &&
/* ... compare all other fields here */
}
}
3.Another way to verify object passed to mock is to save the instance via Mock callback and then compare required fields:
AdvisorSearchOptions passedSearchOptions = null;
_repositoryMock
.Setup(x => x.SearchAdvisors(filter.CID.Value, It.IsAny<AdvisorSearchOptions>()))
.Returns(Task.FromResult<SearchResults<Advisor>>(
new SearchResults<Advisor>()
{
Count = 1,
Limit = 0,
Skip = 0,
ResultItems = new List<SearchResultItem<Advisor>>() {
//some initialize here
}
})
)
.Callback<int, AdvisorSearchOptions>((id, opt) => passedSearchOptions = opt);
// Action
// ...
Assert.IsNotNull(passedSearchOptions);
Assert.AreEqual(filter.SearchKey, passedSearchOptions.SearchKey);
Assert.AreEqual(filter.AdvisorId, passedSearchOptions.AdvisorId);
// Check all other fields here
// ...

JScript.NET private variables

I'm wondering about JScript.NET private variables. Please take a look on the following code:
import System;
import System.Windows.Forms;
import System.Drawing;
var jsPDF = function(){
var state = 0;
var beginPage = function(){
state = 2;
out('beginPage');
}
var out = function(text){
if(state == 2){
var st = 3;
}
MessageBox.Show(text + ' ' + state);
}
var addHeader = function(){
out('header');
}
return {
endDocument: function(){
state = 1;
addHeader();
out('endDocument');
},
beginDocument: function(){
beginPage();
}
}
}
var j = new jsPDF();
j.beginDocument();
j.endDocument();
Output:
beginPage 2
header 2
endDocument 2
if I run the same script in any browser, the output is:
beginPage 2
header 1
endDocument 1
Why it is so??
Thanks,
Paul.
Just a guess, but it appears that JScript.NET doesn't support closures the same way as EMCAScript, so the state variable in endDocument() isn't referencing the private member of the outer function, but rather an local variable (undeclared). Odd.
You don't have to use new when calling jsPDF here since you're using a singleton pattern. jsPDF is returning an object literal so even without new you'll have access to the beginPage and endDocument methods. To be perfectly honest I don't know what the specifications call for when using new on a function that returns an object literal so I'm not sure if JScript.NET is getting it wrong or the browser. But for now try either getting rid of the new before jsPDF() or change your function to this:
var jsPDF = function(){
var state = 0;
var beginPage = function(){
state = 2;
out('beginPage');
};
var out = function(text){
if(state == 2){
var st = 3;
}
MessageBox.Show(text + ' ' + state);
};
var addHeader = function(){
out('header');
};
this.endDocument = function(){
state = 1;
addHeader();
out('endDocument');
};
this.beginDocument: function(){
beginPage();
};
}
That will allow you to use the new keyword and create more than one jsPDF object.
I've come across the same problem. In the following code, the closure bound to fun should contain only one variable called result. As the code stands, the variable result in the function with one parameter seems to be different to the result variable in the closure.
If in this function the line
result = [];
is removed, then the result in the line
return result;
refers to the result in the closure.
var fun = function() {
var result = [];
// recursive descent, collects property names of obj
// dummy parameter does nothing
var funAux = function(obj, pathToObj, dummy) {
if (typeof obj === "object") {
for (var propName in obj) {
if (obj.hasOwnProperty(propName)) {
funAux(obj[propName], pathToObj.concat(propName), dummy);
}
}
}
else {
// at leaf property, save path to leaf
result.push(pathToObj);
}
}
return function(obj) {
// remove line below and `result' 3 lines below is `result' in closure
result = []; // does not appear to be bound to `result' above
funAux(obj, [], "dummy");
return result; // if result 2 lines above is set, result is closure is a different variable
};
}();