Type mismatch when calling a function in qtp - vbscript

I am using QTP 11.5 for automating a web application.I am trying to call an action in qtp through driverscript as below:
RFSTestPath = "D:\vf74\D Drive\RFS Automation\"
LoadAndRunAction RFStestPath & LogInApplication,"Action1",oneIteration
Inside the LogInApplication(Action1) am calling a login function as:
Call fncLogInApplication(strURL,strUsesrName,strPasssword)
Definition of fncLogInApplication is written in fncLogInApplication.vbs
When I associate the fncLogInApplication.vbs file to driverscript, am able to execute my code without any errors. But when I de-associate .vbs file from driverscript and associate it to LogInApplication test am getting "Type mismatch: 'fncLogInApplication'"
Can anyone help me in the association please. I want fncLogInApplication to be executed when I associate to LogInApplication not to the main driverscript.
Please comment back if you require any more info

There is only one set of associated libraries that is active at any one time: That is always the outermost test's one.
This means if test A calls test B, test B will be executed with the libraries loaded based upon test A´s associated libraries list, not B's.
This also means that if B depends on a library, and B associated this library, but is called from test A (which does not associated this library), then B will fail to call (locate) the function since the associated libraries of B are never loaded (only those from A are). (As would A, naturally.).
If you are still interested: "Type mismatch" is QTPs (or VBScript´s) poor way of telling you: "The function called is not known, so I bet you instead meant an array variable dereference, and the variable you specified is equal to empty, so it is not an array, and thus cannot be dereferenced as an array variable, which is what I call a 'type mismatch'."
This reasoning is valid, considering the syntax tree of VB/VBScript: Function calls and array variable dereferences cannot be formally differentiated. Syntactically, they are very similar, or identical in most cases. So be prepared to handle "Type mismatch" like the "Unknown function referenced" message that VB/VBScript never display when creating VBScript code.
You can, however, load the library you want in test B´s code (for example, using LoadFunctionLibrary), but this still allows A to call functions from that library once B loaded it and returned from A´s call. This, and all the possible variations of this procedure, however, have side-effects to aspects like debugging, forward references and visibility of global variables, so I would recommend against it.
Additional notes:
There is no good reason to use CALL. Just call the sub or function.
If you call a function and use the result it returns, you must include the arguments in parantheses.
If you call a sub (or a function, and don´t use the result it returns), you must not include the arguments in parantheses. If the sub or function accepts only one argument, it might look like you are allowed to put it in parantheses, but this is not true. In this case, the argument is simply treated like a term in parantheses.
The argument "bracketing" aspects just listed can create very nasty bugs, especially if the argument is byRef, also due (but not limited) to the fact that VBScripts unfortunately allows you to pass values for a byRef argument (where a variable parameter is expected), so it is generally a good idea to put paranthesis only where it belongs (i.e. where absolutely needed).

Related

Is Call MagicFunction(intData1, intData2, Dim intData3) a valid statement in vbs?

I'm not really sure how to phase it any other way.
The thing is, i'm trying to merge functions with the same name in vbs. Sometimes, the function appears in different forms in other parts of the system. If they are too different, I regretfully leave them as they are. However, if the differences are minor (like having one of the functions only having one variable more than the others, which i can then check for in-function), I'd like to add a variable that would be a stand in.
I already know that Optional variables are not possible in vbs, and I've already had experience with passing an array of variants (works like a charm), but I believe this case is a bit different.
Dim is not correct here. You can do for example:
Public Function MagicFunction(intData1, ByRef intData2, ByVal intData3)
' some code
End Function
and to call it:
MagicFunction 3, iCount, ""
to have "optional arguments", you can only use an array an parse it (for example using UBound(aTab) to select the correct case
Public Function MagicFunction(ByVal aTab)
Select Case UBound(aTab)
Case 1: MagicFunction1 aTab(1)
Case 2: MagicFunction2 aTab(1), aTab(2)
Case Else: MsgBox "function called with more than 2 args" '<-- Should never go there
End Select
End Function
With different version of your function depending on the number of argument, MagicFunction1, MagicFunction2... It's ugly but do the trick!
Another possibility is to use empty strings as argument, and define how your function ignore a part when the string is empty (or to be more accurate, call with a specific key, like "IGNORE_KEY")
I hope I'm answering your question!

What expressions are allowed in tracepoints?

When creating a tracepoint in Visual Studio (right-click the breakpoint and choose "When Hit..."), the dialog has this text, emphasis mine:
You can include the value of a variable or other expression in the message by placing it in curly braces...
What expressions are allowed?
Microsoft's documentation is rather sparse on the exact details of what is and is not allowed. Most of the below was found by trial and error in the Immediate window. Note that this list is for C++, as that's what I code in. I believe in C#, some of the prohibited items below are actually allowed.
Most basic expressions can be evaluated, including casting, setting variables, and calling functions.
General Restrictions
Only C-style casts supported; no static_cast, dynamic_cast, reinterpret_cast, const_cast
Can't declare new variables or create objects
Can't use overloaded operators
Ternary operator doesn't work
Can't use the comma operator because Visual Studio uses it to format the result of the expression; use multiple sets of braces for multiple expressions
Function Calls
Prohibited calls:
Lambdas (can't define or call them)
Functions in an anonymous namespace
Functions that take objects by value (because you can't create objects)
Permitted calls:
Member functions, both regular and virtual
Functions taking references or pointers, to either fundamental or class types
Passing in-scope variables
Using "&" to pass pointers to in-scope variables
Passing the literals "true", "false", numbers
Passing string literals, as long you don't run afoul of the "can't create objects" rule
Calling multiple functions with one tracepoint by using multiple sets of braces
Variable Assignment
Prohibited:
Objects
String literals
Permitted:
Variables with fundamental types, value either from literals or other variables
Memory addresses, after casting: { *(bool*)(0x1234) = true }
Registers: { #eip = 0x1234 }
Use Cases
Calling functions from tracepoints can be quite powerful. You can get around most of the restrictions listed above with a carefully set up function and the right call. Here are some more specific ideas.
Force an if
Pretty straightforward: set up a tracepoint to set a variable and force an if-condition to true or false, depending on what you need to test. All without adding code or leaving the debug session.
Breakpoint "toggling"
I've seen the question a few times, "I need to break in a spot that gets hit a lot. I'd like to simply enable that breakpoint from another breakpoint, so the one I care about only gets breaks from a certain code path. How can I do that?" With our knowledge above, it's easy, although you do need a helper variable.
Create a global boolean, set to false.
Create a breakpoint at your final destination, with a condition to break only when the global flag is true.
Set tracepoints in the critical spots that assign the global flag to true.
The nice thing is that you can move the tracepoints around without leaving the debugging session. Use the Immediate window or the Watch window to reset your global flag, if you need to make another run at it. When you're done, all you need to clean up is that global boolean. No other code to remove.
Automatically skip code
The EIP register (at least on x86) is the instruction pointer. If you assign to it, you can change your program flow.
Find the address of the line you want to skip to by breaking on it once and looking at the value of EIP, either in the Registers window or the Watch window with "#eip,x". (Note that the value in the Registers window is hex, but without the leading "0x".)
Add a tracepoint on the line you want to skip from, with an expression like {#eip = address}, using the address from step 1.
EIP assignment will happen before anything on the line is executed.
Although this can be handy, be careful because skipping code like this can cause weird behavior.
As Kurt Hutchinson says, string assignment is not allowed in a tracepoint. You can get around this by creating a method that assigns the string variable, and call that.
public static class Helper
{
public static void AssignTo(this string value, out string variable)
{
variable = value;
}
}
Then in your tracepoint message:
{"new string value".AssignTo(out stringVariable)}

QTP VBScript type mismatch error in function without arguments

I have run into an annoying problem in QTP (Quick test pro) using VBScript.
I have defined this sub in VBScript (I have also tried defining it as a function with the same result):
Sub KillProcess()
KillprocessIE = "The process i want to kill"
Set ProcessList2 = GetObject("winmgmts://.").InstancesOf("win32_process")
For Each Process In ProcessList2
If Process.Name = KillProcessIE Then
Process.Terminate
Exit for
End If
Next
End Sub
But when I try to run it either by using
call KillProcess()
KillProcess()
KillProcess
I get an error saying "Typer stemmer ikke overens: 'KillProcess'" with translated from Danish means something like "Types does not match: 'KillProcess'. I am guessing it is a type mismatch error but due to translation I cant be sure.
What types is it talking about? I have no arguments in my function call and I am not assigning any values to anything?
It should also be said that if I run the exact same code directly without defining it as a function, it works without issue.
Whenever you call a sub or function that is not defined, you get a type mismatch error.
Even though this is a miracle per se (for which I could find a reasonable reasoning for only for functions, not for subs) it indicates that in your specific scenario, KillProcess was not known in the script in which you called it.
Possible causes:
The KillProcess declaration was in a function library which was not listed in the
associated function library settings dialog.
The KillProcess declaration was active, but your call(s) contained one or more typos,
like "KillProccess", or similar stuff.
As Motti indicated, the code snippet you posted looks fine, so there must be some other glitch.
Another hint regarding subs versus functions: Be aware that you usually never call a Sub with brackets for the arguments. If you do specify them, they are considered to be part of a term to be evaluated, and since
X term
is the same as
X (term)
this consequently does not yield an error message in this case.
However, for Subs with two or more arguments, specifying all actual arguments in one bracket pair, like in
Y (term1, term2)
yields an error, something like "cannot call a Sub with arguments in brackets", or so. This is hard to understand if you consider that one argument indeed can be specified in brackets.
(For a more complete overview about the paranthesis topic, see ByRef and ByVal in VBScript and linked questions).
General suggestion: Use
option explicit
at the top of all scripts (especially function libraries) all the time. RTFM this if needed. It might look like more work (because it forces you to declare all variables before you can use them), but it is useful to avoid subtle bugs.
I think you have run into the strange behavior QTP but though logic when you understand why.
The reason for why this occurs is probably because you "run from step" call KillProcess() and having the function defined above like:
Sub KillProcess()
.
.
.
End Sub
call KillProcess()
If you run the code from "Call KillProcess()" QTP will return the "Run Error" "Type Mismatch"
If instead let the function be defined below the executing statement like this
call KillProcess()
Sub KillProcess()
.
.
.
End Sub
Then QTP "knows" the function that you are calling and will execute the script like it should.
The reason for this is, that when using "Run from step" only reads the line of codes from the step and below and not what you have written above.

Initialize member variables in a method and not the constructor

I have a public method which uses a variable (only in the scope of the public method) I pass as a parameter we will call A, this method calls a private method multiple times which also requires the parameter.
At present I am passing the parameter every time but it looks weird, is it bad practice to make this member variable of the class or would the uncertainty about whether it is initialized out way the advantages of not having to pass it?
Simplified pseudo code:
public_method(parameter a)
do something with a
private_method(string_a, a)
private_method(string_b, a)
private_method(string_c, a)
private_method(String, parameter a)
do something with String and a
Additional information: parameter a is a read only map with over 100 entries and in reality I will be calling private_method about 50 times
I had this same problem myself.
I implemented it differently in 3 different contexts to see hands-on what are result using 3 different strategies, see below.
Note that I am type of programmer that makes many changes to the code always trying to improve it. Thus I settle only for the code that is amenable to changes, readbale, would you call this "flexible" code. I settle only for very clear code.
After experimentation, I came to these results:
Passing a as parameter is perfectly OK if you have one or two - short number - of such values. Passing in parmeters has very good visibility, clarity, clear passing lines, well visible lifetime (initialization points, destruction points), amenable to changes, easy to track.
If number of such values begin to grow to >= 5-6 values, I swithc to approach #3 below.
Passing values through class members -- did not do good to clarity of my code, eventually I got rid of it. It makes for less clear code. Code becomes muddled. I did not like it. It had no advantages.
As alternative to (1) and (2), I adopted Inner class approach, in cases when amount of such values is > 5 (which makes for too long argument list).
I pack those values into small Inner class and pass such object by reference as argument to all internal members.
Public function of a class usually creates an object of Inner class (I call is Impl or Ctx or Args) and passes it down to private functions.
This combines clarity of arg passing with brevity. It's perfect.
Good luck
Edit
Consider preparing array of strings and using a loop rather than writing 50 almost-identical calls. Something like char *strings[] = {...} (C/C++).
This really depends on your use case. Does 'a' represent a state that your application/object care about? Then you might want to make it a member of your object. Evaluate the big picture, think about maintenance, extensibility when designing structures.
If your parameter a is a of a class of your own, you might consider making the private_method a public method for the variable a.
Otherwise, I do not think this looks weird. If you only need a in just 1 function, making it a private variable of your class would be silly (at least to me). However, if you'd need it like 20 times I would do so :P Or even better, just make 'a' an object of your own that has that certain function you need.
A method should ideally not pass more than 7 parameters. Using the number of parameters more than 6-7 usually indicates a problem with the design (do the 7 parameters represent an object of a nested class?).
As for your question, if you want to make the parameter private only for the sake of passing between private methods without the parameter having anything to do with the current state of the object (or some information about the object), then it is not recommended that you do so.
From a performance point of view (memory consumption), reference parameters can be passed around as method parameters without any significant impact on the memory consumption as they are passed by reference rather than by value (i.e. a copy of the data is not created). For small number of parameters that can be grouped together you can use a struct. For example, if the parameters represent x and y coordinates of a point, then pass them in a single Point structure.
Bottomline
Ask yourself this question, does the parameter that you are making as a members represent any information (data) about the object? (data can be state or unique identification information). If the answer to his question is a clear no, then do not include the parameter as a member of the class.
More information
Limit number of parameters per method?
Parameter passing in C#

Debugging generic functions in R

How do you debug a generic function (using debug, or mtrace in the debug package)?
As an example, I want to debug cenreg in the NADA package, specifically the method that takes a formula input.
You can retrieve the method details like this:
library(NADA)
getMethod("cenreg", c("formula", "missing", "missing"))
function (obs, censored, groups, ...)
{
.local <- function (obs, censored, groups, dist, conf.int = 0.95,
...)
{
dist = ifelse(missing(dist), "lognormal", dist)
...
}
The problem is that cenreg itself looks like this:
body(cenreg)
# standardGeneric("cenreg")
I don't know how to step through the underlying method, rather than the generic wrapper.
My first two suggestions are pretty basic: (1) wrap your function call in a try() (that frequently provides more information with S4 classes) and (2) call traceback() after the error is thrown (that can sometimes give hints to where the problem is really occuring).
Calling debug() won't help in this scenario, so you need to use trace or browser. From the debug help page:
"In order to debug S4 methods (see Methods), you need to use trace, typically
calling browser, e.g., as "
trace("plot", browser, exit=browser, signature = c("track", "missing"))
S4 classes can be hard to work with; one example of this is the comment in the debug package documentation (regarding the usage of mtrace() with S4 classes):
"I have no plans to write S4 methods, and hope not to have to
debug other people’s!"
A similar question was asked recently on R-Help. The recommendation from Duncan Murdoch:
"You can insert a call to browser() if you want to modify the source. If
you'd rather not do that, you can use trace() to set a breakpoint in it.
The new setBreakpoint() function in R 2.10.0 will also work, if you
install the package from source with the R_KEEP_PKG_SOURCE=yes
environment variable set. It allows you to set a breakpoint at a
particular line number in the source code."
I've never done this before myself (and it requires R 2.10.0), but you might try installing from source with R_KEEP_PKG_SOURCE=yes.
Incidentally, you can use the CRAN mirror of NADA in github to browse the source.
For a long time this was a standard annoyance point for S4 method debugging. As pointed out by Charles Plessy, I worked with Michael Lawrence to add a number of features to R that are intended to make this easier.
debug, debugonce, undebug and isdebugged all now take a signature argument suitable for specifying s4 methods. Furthermore, debugging S4 methods this way bypasses the weird implementation detail that you previously had to deal with by hand by browsering into the method via trace, stepping through the .local definition, debugging that, then continuing.
In addition, I added debugcall, which you give an actual, full call that you would want to invoke. Doing so sets debugging on the first closue which will be invoked when evaluating that call that is not an S3 or S4 standard generic. So if you are calling a non-generic, that will just be the top level function being called, but if it is a standard S3 or S4 generic, the first method that will be hit is debugged instead of the generic. A "standard S3 generic" is defined as a function where the first top-level (ignoring curly braces) call in the body is a call to UseMethod.
Note we went back and forth on the design of this but at the end of the day settled on debugcall not actually executing the function call being debugged, but it returns the call expression which you can pass it to eval if desired, as illustrated in ?debugcall.

Resources