How to select a random parameter captured using
web_reg_save_param("varParamName",
"LB=value=\"",
"RB=\"",
"Ord=All",
LAST);
Your LB and RB conditions are too generic. Pick something more specific to what you are trying to capture
To your greater question, there are several paths on picking an ordinal depending upon your version of LoadRunner. Something which works for every version would be
char foo[50];
...
sprintf(
foo,
"{varParamName_%d}",
rand() * atoi( lr_eval_string("{varParamName_count}" ) ) +1
);
...
lr_save_string(
lr_eval_string( foo ),
"LR_MyRandomCorrelatedvariable"
);
...
lr_output_message(
"%s",
lr_eval_string( "{LR_MyRandomCorrelatedvariable}" )
);
to randomize the correlation values we can use lr_paramarr_random function.
web_reg_save_param("varParamName","LB=value=\"","RB=\"","Ord=All",LAST);
// some request ***web_submit_form()
//Save a randomly selected ID to a Parameter
lr_save_string(lr_paramarr_random("varParamName"),"RandomParam");
now we can use RandomParam instead of varParamName. it will provide random values.
Related
I need to evaluate a dynamic logical expression and I know that in ABAP it is not possible.
I found the class cl_java_script and with this class I could achieve my requeriment. I've try something like this:
result = cl_java_script=>create( )->evaluate( `( 1 + 2 + 3 ) == 6 ;` ).
After the method evaluate execution result = true as espected. But my happiness is over when I look into the class documentation that says This class is obsolete.
My question is, there is another way to achieve this?
Using any turing complete language to parse a "dynamic logical expression" is a terrible idea, as an attacker might be able to run any program inside your expression, i.e. while(true) { } will crash your variant using cl_java_script. Also although I don't know the details of cl_java_script, I assume it launches a separate JS runtime in a separate thread somewhere, this does not seem to be the most efficient choice to calculate such a small dynamic expression.
Instead you could implement your own small parser. This has the advantage that you can limit what it supports to the bare minimum whilst being able to extend it to everything you need in your usecase. Here's a small example using reverse polish notation which is able to correctly evaluate the expression you've shown (using RPN simplifies parsing a lot, though for sure one can also build a full fledged expression parser):
REPORT z_expr_parser.
TYPES:
BEGIN OF multi_value,
integer TYPE REF TO i,
boolean TYPE REF TO bool,
END OF multi_value.
CLASS lcl_rpn_parser DEFINITION.
PUBLIC SECTION.
METHODS:
constructor
IMPORTING
text TYPE string,
parse
RETURNING VALUE(result) TYPE multi_value.
PRIVATE SECTION.
DATA:
tokens TYPE STANDARD TABLE OF string,
stack TYPE STANDARD TABLE OF multi_value.
METHODS pop_int
RETURNING VALUE(result) TYPE i.
METHODS pop_bool
RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.
CLASS lcl_rpn_parser IMPLEMENTATION.
METHOD constructor.
" a most simple lexer:
SPLIT text AT ' ' INTO TABLE tokens.
ASSERT lines( tokens ) > 0.
ENDMETHOD.
METHOD pop_int.
DATA(peek) = stack[ lines( stack ) ].
ASSERT peek-integer IS BOUND.
result = peek-integer->*.
DELETE stack INDEX lines( stack ).
ENDMETHOD.
METHOD pop_bool.
DATA(peek) = stack[ lines( stack ) ].
ASSERT peek-boolean IS BOUND.
result = peek-boolean->*.
DELETE stack INDEX lines( stack ).
ENDMETHOD.
METHOD parse.
LOOP AT tokens INTO DATA(token).
IF token = '='.
DATA(comparison) = xsdbool( pop_int( ) = pop_int( ) ).
APPEND VALUE #( boolean = NEW #( comparison ) ) TO stack.
ELSEIF token = '+'.
DATA(addition) = pop_int( ) + pop_int( ).
APPEND VALUE #( integer = NEW #( addition ) ) TO stack.
ELSE.
" assumption: token is integer
DATA value TYPE i.
value = token.
APPEND VALUE #( integer = NEW #( value ) ) TO stack.
ENDIF.
ENDLOOP.
ASSERT lines( stack ) = 1.
result = stack[ 1 ].
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
" 1 + 2 + 3 = 6 in RPN:
DATA(program) = |1 2 3 + + 6 =|.
DATA(parser) = NEW lcl_rpn_parser( program ).
DATA(result) = parser->parse( ).
ASSERT result-boolean IS BOUND.
ASSERT result-boolean->* = abap_true.
SAPs BRF is an option, but potentially massive overkill in your scenario.
Here is a blog on calling BRF from abap.
And here is how Rules/Expressions can be defined dynamically.
BUT, if you know enough about the source problem to generate
1 + 2 + 3 = 6
Then it is hard to imagine why a simple custom parser cant be used.
Just how complex should the expressions be ?
Id probably write my own parser before investing in calling BRF.
Since some/many BSPs use server side JAVAscript and not ABAP as the scripting language, i cant see SAP removing the Kernel routine anytime soon.
SYSTEM-CALL JAVA SCRIPT EVALUATE.
SO maybe consider Just calling the cl_java_script anyway until it is an issue.
Then worry about a parser if and when it is really no longer a valid call.
But definitely some movement in the obsolete space here.
SAP is pushing/forcing you to cloud with the SDK, to execute such things.
https://sap.github.io/cloud-sdk/docs/js/overview-cloud-sdk-for-javascript
So my rule is
/* Addition and subtraction have the lowest precedence. */
additionExp returns [double value]
: m1=multiplyExp {$value = $m1.value;}
( op=AddOp m2=multiplyExp )* {
if($op != null){ // test if matched
if($op.text == "+" ){
$value += $m2.value;
}else{
$value -= $m2.value;
}
}
}
;
AddOp : '+' | '-' ;
My test ist 3 + 4 but op.text always returns NULL and never a char.
Does anyone know how I can test for the value of AddOp?
In the example from ANTLR4 Actions and Attributes it should work:
stat: ID '=' INT ';'
{
if ( !$block::symbols.contains($ID.text) ) {
System.err.println("undefined variable: "+$ID.text);
}
}
| block
;
Are you sure $op.text is always null? Your comparison appears to check for $op.text=="+" rather than checking for null.
I always start these answers with a suggestion that you migrate all of your action code to listeners and/or visitors when using ANTLR 4. It will clean up your grammar and greatly simplify long-term maintenance of your code.
This is probably the primary problem here: Comparing String objects in Java should be performed using equals: "+".equals($op.text). Notice that I used this ordering to guarantee that you never get a NullPointerException, even if $op.text is null.
I recommend removing the op= label and referencing $AddOp instead.
When you switch to using listeners and visitors, removing the explicit label will marginally reduce the size of the parse tree.
(Only relevant to advanced users) In some edge cases involving syntax errors, labels may not be assigned while the object still exists in the parse tree. In particular, this can happen when a label is assigned to a rule reference (your op label is assigned to a token reference), and an error appears within the labeled rule. If you reference the context object via the automatically generated methods in the listener/visitor, the instances will be available even when the labels weren't assigned, improving your ability to report details of some errors.
I want the app when it is executed to start a different layout, I have this code that allows me to choose the layout where to start but want it to be random thanks.
myPager.setCurrentItem(0);
PD: excuse my English, not speaking, he used the translator
You can use Java's built-in pseudo random number generator to get a random value in a defined range. Use this to choose a random value for setCurrentItem. For example:
Random r = new Random();
int randomValue = r.nextInt( 5 );
myPager.setCurrentItem( randomValue );
The value you pass to the nextInt method is one more than the maximum integer you want to receive; the example above will return a random value between 0 and 4 (excluding 5).
I wrote a method in Groovy using the range operator in order to execute the same code multiple times:
/**
* Prints the {#code files} {#code copyCount} times using
* {#code printService}.
* <p>
* Exceptions may be thrown.
* #param printService Print service
* #param files List of {#code File} objects
* #param copyCount Number of copies to print
*/
private static void printJob(
PrintService printService,
List<File> files,
int copyCount) {
// No multiple copy support for PS files, must do it manually
for ( i in 1..copyCount ) {
// Print files
}
}
This method did not pass unit testing as it badly fails when copyCount is 0.
I searched the documentation and it seems that Groovy implements ranges like a "list of sequential values". As I understand, a range does not represent a representation of an interval of integers since it also has the notion of order embedded.
In Groovy a..b is not the set of integers x such that a <= x <= b.
In Groovy a..b is the representation of the enumeration u: [0,|b-a|] -> [a..b] defined as: u(0) = a, for all i in [1,|b-a|], u(i) = u(i-1) + sgn(b-a)
Now I can fix my code:
if (copyCount > 0) for ( i in 1..copyCount ) {
// Print files
}
Also in Groovy a..<b is the representation of the enumeration u: [0,|b-a|-1] -> [a..b-1] defined as: u(0) = a, for all i in [1,|b-a|-1], u(i) = u(i-1) + sgn(b-a)
I noticed that the code below is also working for copyCount positive or zero:
for ( i in 0..<copyCount ) {
// Print files
}
Still, if I can choose a solution where damages are minimized in case of inconsistency (say copyCount is -200, I may get 200 prints)...
0.step(copyCount, 1) {
// Print files
}
At least with this solution I get a GroovyRuntimeException: Infinite loop in case of a negative copyCount. It is groovy but not very pretty and I feel like I’m playing with fire.
There is also this solution, but I find it ugly.
for ( i in 0..<[0,n].max() ) {
// Print files
}
Therefore, in this case, I think the best is to avoid using the range operator, because it may be confusing for developers that are used to Perl, Ruby or Mathematics, or French (there is no word for this definition of range in French, we would just say "intervalle" for a range)... I also found it safer in case of inconsistency. Still, it is not so groovy.
for ( i = 1 ; i <= copyCount ; i++ ) {
// Print files
}
Why does the range operator in Groovy is so complicated? As I see it, the fact that the step is "magically" determined and that we can’t force it (like in Ruby) is a big flaw in this implementation. Am I the only one who was ever troubled by this (two prints instead of none, it would have been a bad bug ^^ )? Did I miss something? Is there any practical case where it is required for a range to revert order when the higher bound gets lower than the lower bound? Am I being too picky?
I need some help understanding how stdext::hash_multimap's lower_bound, upper_bound and equal_range work (at least the VS2005 version of it).
I have the following code (summarized for the question)
#include <hash_map>
using stdext::hash_multimap;
using std::greater;
using stdext::hash_compare;
using std::pair;
using std::cout;
typedef hash_multimap < double, CComBSTR, hash_compare< double, greater<double> > > HMM;
HMM hm1;
HMM :: const_iterator it1, it2;
pair<HMM::const_iterator, HMM::const_iterator> pairHMM;
typedef pair <double, CComBSTR> PairDblStr;
// inserting only two values for sample
hm1.insert ( PairDblStr ( 0.224015748, L"#1-64" ) );
hm1.insert ( PairDblStr ( 0.215354331, L"#1-72" ) );
// Using a double value in between the inserted key values to find one of the elements in the map
it1 = hm1.lower_bound( 0.2175 );
if( it1 == hm1.end() )
{
cout << "lower_bound failed\n";
}
it1 = hm1.upper_bound( 0.2175 );
if( it1 == hm1.end() )
{
cout << "upper_bound failed\n";
}
pairHMM = hm1.equal_range( 0.2175 );
if( ( pairHMM.first == hm1.end() ) && ( pairHMM.second == hm1.end() ) )
{
cout << "equal_range failed\n";
}
As mentioned in the comment I am passing in a value (0.2175) that is in between the two inserted key values (0.224015748, 0.215354331). But the output of the code is:
lower_bound failed
upper_bound failed
equal_range failed
Did I misunderstand how the lower_bound, upper_bound and equal_range can be used in maps? Can we not find a "closest match" key using these methods? If these methods are not suitable, would you have any suggestion on what I could use for my requirement?
Thanks in advance for any help.
Thanks to #billy-oneal #dauphic for their comments and edits. I have updated the code above to make it compilable and runnable (once you include the correct headers of course).
Can we not find a "closest match" key using these methods?
No. hash_multimap is implemented using a hashtable. Two keys that are very close to each other (0.2153 and 0.2175, for example) will likely map to totally different bins in the hashtable.
A hashtable does not maintain its elements in a sorted order, so you cannot find the closest match to a given key without a linear search.
The lower_bound, upper_bound, and equal_range functions in hash_multimap have a somewhat odd implementation in the Visual C++ standard library extensions.
Consider the documentation for lower_bound:
The member function determines the first element X in the controlled sequence that hashes to the same bucket as key and has equivalent ordering to key. If no such element exists, it returns hash_map::end; otherwise it returns an iterator that designates X. You use it to locate the beginning of a sequence of elements currently in the controlled sequence that match a specified key.
And the documentation for upper_bound:
The member function determines the last element X in the controlled sequence that hashes to the same bucket as key and has equivalent ordering to key. If no such element exists, or if X is the last element in the controlled sequence, it returns hash_map::end; otherwise it returns an iterator that designates the first element beyond X. You use it to locate the end of a sequence of elements currently in the controlled sequence that match a specified key.
Essentially, these functions allow you to identify the range of elements that have a given key. Their behavior is not the same as the behavior of std::lower_bound or std::map::lower_bound (theirs is the behavior that you were expecting).
For what it's worth, the C++0x unordered associative containers do not provide lower_bound, upper_bound, or equal_range functions.
Would you have any suggestion on what I could use for my requirement?
Yes: if you need the behavior of lower_bound and upper_bound, use an ordered associative container like std::multimap.