why if condition is not working in vugen? - testing

I am not sure what's going wrong.
I want to use if condition to compare the statuscode of webcall in vugen and handle the transaction based on that.
c_statuscode = 409 // it is the extracted value showing in logs
if (atoi(lr_eval_string("{c_statuscode}")) == 409){
lr_output_message("request already exist");
lr_end_transaction("transaction",LR_PASS);
Action();
}
else{
lr_end_transaction("transaction",LR_AUTO);
}
it's suppose to compare the status code and print output message as is in lr_output_message function, and end the transaction and again go to perform the Action() part.
and if "if" condition doesn't match it should end transaction.

For your comparison, see strcmp()
For your status, see web_get_int_property()
Note, your If condition code is outside of a handling function. If you want to make the rest of your action dependent upon this code, then it needs to be included, such as (PCODE)
Action()
{
\\ Some code runs to set the condition for evaluation
If (condition true) then return(1);
\\ The code from here down will execute if the above condition is false
\\ When true the return(1); will cause an immediate start over of the
\\ iteration. Return(0); respects pacing information in the run time
\\ settings. A return(-1); kills the virtual user
return(0);
}

Related

Can you retry a Zig function call when it returns an error?

Zig's documentation shows different methods of error handling including bubbling the error value up the call stack, catching the error and using a default value, panicking, etc.
I'm trying to figure out how to retry functions which provide error values.
For example, in the below snippet from ziglearn, is there a way to retry the nextLine function in the event that a user enters greater than 100 characters?
fn nextLine(reader: anytype, buffer: []u8) !?[]const u8 {
var line = (try reader.readUntilDelimiterOrEof(
buffer,
'\n',
)) orelse return null;
// trim annoying windows-only carriage return character
if (#import("builtin").os.tag == .windows) {
return std.mem.trimRight(u8, line, "\r");
} else {
return line;
}
}
test "read until next line" {
const stdout = std.io.getStdOut();
const stdin = std.io.getStdIn();
try stdout.writeAll(
\\ Enter your name:
);
var buffer: [100]u8 = undefined;
const input = (try nextLine(stdin.reader(), &buffer)).?;
try stdout.writer().print(
"Your name is: \"{s}\"\n",
.{input},
);
}
This should do what you want.
const input = while (true) {
const x = nextLine(stdin.reader(), &buffer) catch continue;
break x;
} else unreachable; // (see comment) fallback value could be an empty string maybe?
To break it down:
instead of try, you can use catch to do something in the case of an error, and we're restarting the loop in this case.
while loops can also be used as expressions and you can break from them with a value. they also need an else branch, in case the loop ends without breaking away from it. in our case this is impossible since we're going to loop forever until nextLine suceeds, but if we had another exit condition (like a limit on the number of retries), then we would need to provide a "fallback" value, instead of unreachable.
You can also make it a one-liner:
const input = while (true) break nextLine(stdin.reader(), &buffer) catch continue else unreachable;
Hopefully the new self-hosted compiler will be able to pick up on the fact that the else branch is not necessary, since we're going to either break with a value loop forever.

How do you test a Require statement in a smartcontract using Mocha?

I am fairly new to developing smartcontracts and have run into an issue while testing. My intention is to ensure the smartcontract cannot mint more than 13 ERC721 tokens. My understanding is that a require function can have a second string argument that will revert a string as an error if the require condition is not met. Is this correct?
The following is my smart contract code:
contract TheCondemned_Episode is ERC721Enumerable {
string[] public episodes;
constructor() ERC721("TheCondemned_e1", "TCe1") public {
}
function mint(string memory _episode) public {
require(episodes.length <= 13, "Cannot make more than 13 episodes");
episodes.push(_episode);
uint _id= episodes.length;
_mint(msg.sender, _id);
}
}
And the test I am running is as follows:
it('Cannot create more than 13 episodes', async() => {
for(var i=0; i===13; i++){
var episode= `Episode ${i}`
await contract.mint(episode)
}
try {
await contract.mint('Episode 14');
assert(true);
}
catch (err) {
return;
}
assert(false, "The contract did not throw.");
The test fails and returns "The contract did not throw". What is the best practice in regards to catching a revert string from a failed require condition when testing?
My understanding is that a require function can have a second string argument that will revert a string as an error if the require condition is not met. Is this correct?
That's correct. Here's an example of an always failing require() condition that throws an exception with the error message.
require(false, 'Error message');
However, you have a logical error in the Solidity require() condition, as well as in the JS test snippet.
First, let's uncover the Solidity code. For simplicity, let's assume you're allowing to mint only 1 episode.
require(episodes.length <= 1, "Cannot make more than 1 episode");
First iteration (expected to pass)
episodes.length is 0, that's <= 1. Condition passes, you mint the first token, and then push to the episodes array, so its length becomes 1 after the condition.
Second iteration (expected to fail)
episodes.length is 1, that's still <= 1. So the condition passes as well.
Solution: Replace the <= (less than or equal) to just < (less than).
require(episodes.length < 1, "Cannot make more than 1 episode");
First iteration (expected to pass)
episodes.length is 0, that's < 1. Condition passes, you mint the first token, and then push to the episodes array, so its length becomes 1 after the condition.
Second iteration (expected to fail)
episodes.length is 1, which fails the condition 1 < 1, as you expect.
I'm assuming that your intention in the JS snippet is to call the mint() function 13 times in the loop, and then 14th time in the try/catch block.
However, the loop currently doesn't perform any iteration. So in fact, you're only executing the mint() function once (in the try/catch block).
The second parameter in the for loop is a condition stating "this loop will keep iterating for as long as this condition is met". But since you set the value of i to 0 in the first parameter, the loop condition (i===13) is not met, and the loop doesn't perform even the first iteration.
Solution: Check whether the i is "less than 13" instead of just "equals 13".
for(var i = 0; i < 13; i++) {
This way, the loop will iterate 13 times.

How to "Catch" both a non-numeric and Incomplete ArrayList capacity

I created an ArrayList that has a capacity of 5 Ints. I can get the if statement to run if its less than 5 but I can't seem to get the else statement to "Catch" Non-Numerics. For example if I enter 1,2,3,Hello; it will print "Wrong number of sales provided."
fun main(){
val stats = ArrayList<Int>(5)
println("Enter your numbers: ")
try {
while (stats.size < 5) {
stats.add(readLine()!!.toInt())
}
}catch (e: NumberFormatException){
if (stats.size != 5){
println("The wrong number of sales provided.")
}else{
println("All inputs should be numeric.")
}
exitProcess(status = 1)
}
calStats(stats)
}
fun calStats(sales: Collection<Int>){
val min = sales.minOrNull()
val max = sales.maxOrNull()
println("Min: $min\nMax: $max\nRange: ${(max!! - min!!)}\nAverage: ${(BigDecimal(sales.average()).setScale(0, RoundingMode.FLOOR))} ")
}
The problem is how you are handling your exception, in fact since you are checking the size of your array first, if you enter 1,2,3,'Hello' and there are 4 elements in this list it will output the wrong message.
You should nest your try ... catch block inside the while loop.
Actually the if (stats.size != 5) control is reduntant since the while loop will execute until stats has a size of 5, unless the NumberFormatException is thrown.
Try to edit your code like this:
fun main() {
val stats = ArrayList<Int>(5)
println("Enter your numbers: ")
while (stats.size < 5) {
try {
stats.add(readLine()!!.toInt())
} catch (e: NumberFormatException) {
println("All inputs should be numeric.")
exitProcess(status = 1)
}
}
calStats(stats)
}
Your logic loops through, reading lines and adding them until you've collected 5 values. As soon as it fails at parsing one of those lines as an Int, it throws a NumberFormatException and you hit the catch block.
The first thing the catch block does is check how many values you've successfully added to the stats list. If it's not exactly 5, it prints the "wrong number" error instead of the "inputs need to be numeric" one.
But if you think about it, the size is never going to be 5 when you hit the catch block - if you've added 5 items successfully, the while loop ends and there's no way it's going to throw. If you have 4 items and the 5th one fails, it doesn't get added, so you have 4 items when you hit the catch block.
If you need to do it this way, you probably want to keep a counter of how many lines you've read and refer to that. But you'll still throw once you hit the first non-numeric value (even if there's 5 of them to be read in total) and the counter will show how far you've got, not how many there are.
Probably the easiest way is to read in 5 lines to a list, and then transform them to Ints and add those to your collection. That way you can check if you have less than 5 before you start, and handle that case separately.
Something like
// create a list by calling readline() 5 times - produces null at EOF
val lines = List(5) { readLine() }
if (lines.contains(null)) { // handle your "not enough items" here }
// parse all lines as Ints - any that fail will be null
val stats = lines.map { it.toIntOrNull() } // or map(String::toIntOrNull)
if (stats.contains(null)) { // handle bad values here }
Kotlin's style tries to avoid exceptions, which is why you have functions like toIntOrNull alongside toInt - it lets you use nulls as a "failure value" that you can handle in normal code. But you can always throw an exception if you want (e.g. when you get a null line) and handle it in your catch block.

Loop That Doesn't End Until Break

I'm trying to create a loop than continues to take input until the input gives the command to break the loop. What I'm doing now looks a little like this:
int start = 1;
while (start == 1) {
//Program statement
}
However, I feel as though there is an easier, more effective way to create a loop that repeats until the user gives the command to stop it. Does something like that exist?
A common idiom to express a "forever" loop in C and other C-like languages, including Objective-C, is to use an empty for:
for(;;) {
// statements
}
You should do it like this:
while(true)
{
if( exit_condition)
{
break;
}
}
do{
userInput = readUserInput()
}while(userInput != exit_condition)
Any loop as for, while, or even goto can do this job. If you put a condition instead of "true" in the loop, You can reduce code and doesn't need to use the "break" statement.

Evaluating every conditional statement on an if... else if... block

Does Objective-C evaluate every statement on an if... else if... block or does it evaluate each as it comes to them and then skip the remaining evaluations if a true condition has been found?
This is more of a pragmatic question related to performance than anything else.
And yes I do know that the content of the if block itself isn't executed, but I am referring to the actual statements that get evaluated.
Example
if ([condition A] == test) {
// Do something
} else if ([condition B] == test) {
// Do something
} else if ([condition C] == test) {
// Do something
} else {
// Do something because all other tests failed
}
So... if condition A is true, do conditions B and C get evaluated anyway?
If they do, then does using a switch statement perform the same way or does a switch only test each condition as it comes to it and then exits the evaluation because of the break?
My understanding is that on an if... else if... block, every condition is evaluated and therefore using a switch or nested if's (ugh - don't relish the thought there) might be faster on big evaluation operations on a lot of data (hundreds of thousands of items being checked against potentially a hundred statements).
Just curious :-)
No, if condition A is met, B and C are not evaluated. Indeed, they are part of the else-clauses that won't get executed then anyway.
Just a side note: if (condA || condB) or if (condA && condB) also evaluates lazily, i.e. in the first case condB is only evaluated if condA is false, in the second case when condA is true.
It only evaluates them as it comes to them. An if ... else if block is equivalent to if.. else {if...}. It behaves the same way as nested ifs, it's just formatted nicely and omits some braces.
Outside of the []'s objective-c behaves in exactly the same way that C does.
For if() ... else if() ... else ... chains that means each expression is evaluated until one evaluates to true and the block is entered. Basically
if (a) {
...
} else if (b) {
...
} else {
...
}
is interpreted as
if (a) {
...
} else {
if (b) {
...
} else {
...
}
}