DelphiScript
In a nutshell, DelphiScript is an OLE scripting language, like VBScript or JScript, but derived from Standard Pascal (not Object Pascal).
Contrary to Standard Pascal, there are units. But, as DelphiScript is meant for scripts, that is, self-standing routines, units are simply groupings of scripts in one file. There is no unit structure (interface, implementation, initialization, etc.).
Note: |
A DelphiScript unit file (.sd) cannot be larger than 1 megabyte (Mb). This restriction is not applied to unit files written in other languages supported by TestComplete. |
数据类型
TestComplete’s script interpreter is based on OLE objects. Thus, all its scripting languages, including DelphiScript, only use OLE-compatible types. Also, they do not support pointers. In DelphiScript all variables are of the OleVariant type. Typecasting is ignored. In variable and array declarations, types are ignored too and they can be skipped. For instance, each of the following declarations is correct:
procedure Test_DataTypes_1;
var i : Integer;
var j : MyCharacter;
var cx, cy;
var Nums : array [1..10];
begin
i:=1;
j:='2';
cx:='SomeObject';
cy:=cx;
Nums[1]:=1;
Log.Message(Nums[1]);
end;
The same rules apply to parameter types in procedure or function declarations: They are ignored and can be skipped. For example, the following code is correct:
function Test_DataTypes_2(AStartPage,AEndPage) : Boolean;
begin
end;
Since DelphiScript does not support pointers, the ^
and @
operators have no effect. If TestComplete meets them while executing script, it posts an error message to the test log. User-defined types, records and classes are also not supported.
数组
Like other scripting languages, DelphiScript supports one- and multi-dimensional arrays. Arrays can be defined statically in the var section or created dynamically using the CreateVariantArray
, CreateVariantArray2
or CreateVariantArray3
functions. Arrays can be passed to any routine as parameters. For example:
procedure Test_p (p: OleVariant); // p is an array
begin
Log.Message(p[0,0]);
Log.Message(p[1,0]);
Log.Message(p[0,1]);
Log.Message(p[1,1]);
end;
procedure Test_Array_1;
var
p : array [0..1, 0..1];
begin
// Initializes array elements
p[0,0] := '00000';
p[1,0] := '11111';
p[0,1] := 'aaaaa';
p[1,1] := 'bbbbb';
Test_p(p); // passes the array as parameter
end;
Note that arrays in DelphiScript cannot be initialized statically. For instance, the following code raises an error:
procedure Test_Array_2;
var
I : array[0..1] of Integer = (3,4) // <-- Error!!!
begin
end;
To solve the problem, initialize the array elements in your code. There are several ways to do this:
l Initializing each element individually
l Initializing elements in a loop
l Initializing all elements at once
procedure Test_Array_2;
var a : array [0..3] of string;
begin
a[0] := 'Element 0';
a[1] := 'Element 1';
a[2] := 'Element 2';
a[3] := 'Element 3';
//...
for i := 0 to 3 do
a[i] := 'Element ' + IntToStr(i);
//...
a := ['Element 0', 'Element 1', 'Element 2', 'Element 3'];
//...
end;
CreateVariantArray
Creates an array of Variant elements.
BuiltIn.CreateVariantArray(Low, High)
Parameters Low |
[in] |
Required |
Integer |
|
High |
[in] |
Required |
Integer |
|
Result |
Variant |
The CreateVariantArray
method lets you create a new array whose elements will have the Variant type.
The method has the following parameters:
Low
The lowest array index.
High
The highest array index.
Return Value
The created array.
procedure Test_Array_CreateVariantArray;
var a1;
begin
a1 := CreateVariantArray(1,3);
a1[1]:=1;
a1[2]:=2;
a1[3]:=3;
Log.Message(a1[1]);
end;
CreateVariantArray2
Creates a two-dimensional array of Variant elements.
BuiltIn.CreateVariantArray2(Low1, High1, Low2, High2)
Parameters Low1 |
[in] |
Required |
Integer |
|
High1 |
[in] |
Required |
Integer |
|
Low2 |
[in] |
Required |
Integer |
|
High2 |
[in] |
Required |
Integer |
|
Result |
Variant |
The CreateVariantArray2
method lets you create a new two-dimensional array whose elements will have the Variant type.
The method has the following parameters:
Low1
The lowest array index of the array's first dimension.
High1
The highest array index of the array's first dimension.
Low2
The lowest array index of the array's second dimension.
High2
The highest array index of the array's second dimension.
Return Value
The created array.
procedure Test_Array_CreateVariantArray2;
var w;
begin
// Creates a two-dimensional array [0..2, 3..4]
w := CreateVariantArray2(0, 2, 3, 4);
w[0,3] := 'Element 0,3';
w[0,4] := 'Element 0,4';
w[1,4] := 'Element 1,4';
w[2,3] := 'Element 2,3';
Log.Message(w[2,3]);
end;
CreateVariantArray3
Creates a three-dimensional array of Variant elements.
BuiltIn.CreateVariantArray3(Low1, High1, Low2, High2, Low3, High3)
Parameters Low1 |
[in] |
Required |
Integer |
|
High1 |
[in] |
Required |
Integer |
|
Low2 |
[in] |
Required |
Integer |
|
High2 |
[in] |
Required |
Integer |
|
Low3 |
[in] |
Required |
Integer |
|
High3 |
[in] |
Required |
Integer |
|
Result |
Variant |
The CreateVariantArray3
method lets you create a new three-dimensional array whose elements will have the Variant type.
The method has the following parameters:
Low1
The lowest array index of the array's first dimension.
High1
The highest array index of the array's first dimension.
Low2
The lowest array index of the array's second dimension.
High2
The highest array index of the array's second dimension.
Low3
The lowest array index of the array's third dimension.
High3
The highest array index of the array's third dimension.
Return Value
The created array.
procedure Test_Array_CreateVariantArray3;
var w;
begin
// Creates a three-dimensional array [0..1, 1..2, 2..3]
w := CreateVariantArray3(0, 1, 1, 2, 2, 3);
w[0,1,2] := 'Element 0,1,2';
w[0,2,2] := 'Element 0,2,2';
w[1,2,2] := 'Element 1,2,2';
w[1,2,3] := 'Element 1,2,3';
Log.Message(w[1,2,3]);
end;
函数和过程
返回值
To return a value from a function, use Result
instead of the function name. Using the function name will cause an error:
function Calc(x, y) : Integer;
begin
//Calc := (x - y) * (x + y); // Error !!!
Result := (x - y) * (x + y); // Correct variant
end;
变量命名
The names of script variables cannot coincide with the names of Delphi keywords regardless of whether this keyword is supported or not supported by DelphiScript. For instance, you cannot use the variable named Message in your scripts, this will cause an error:
procedure TestVariantName;
var
Message : OleVariant; // <-- Error!
begin
end;
支持的Delphi函数
The support of some Delphi functions are built-in in DelphiScript. Some other Delphi routines are provided by the Utilities programming object. This object is available if the Utilities plug-in is installed. The plug-in “registers” Delphi functions in TestComplete and makes them available to your script code. If the plug-in is not installed, calls to Delphi routines outside of System will not be supported. The interpreter will not recognize them, and post an error message when it meets an “unknown” identifier.
文件处理
Append
AssignFile
CloseFile
EOF
Erase
FileSize
Flush
Read
ReadLn
Rename
Reset
Rewrite
Write
WriteLn
ChDir
GetDir
MkDir
RmDir
数学运算
Abs
Cos
Exp
Frac
Int
Ln
Pi
Random
Randomize
Round
Sin
Sqr
Sqrt
Trunc
字符串操作
Chr
Copy
Delete
Insert
Length
Pos
SetLength
内存操作
FreeMem
GetMem
ReallocMem
流程控制
Break
Continue
Exit
Halt
其它
Assigned
Determines whether a variable is assigned.
Dec
Decreases the specified variable.
Evaluate
Evaluates an expression.
ExceptionMessage
Returns the message text of the last raised exception
Inc
Increases the specified variable.
Ord
Returns the ordinal value of a variable.
Raise
Raises an exception with the specified message.
不支持的Delphi函数
The following Delphi routines are not supported in DelphiScript:
|
|
|
|
函数参数默认值
You can specify default values for routine parameters using the same syntax you would use in Delphi.
function Test_Default_Routine_ParameterValue(Param1: OleVariant = 100, Param2: OleVariant = 200 ,Param3: OleVariant = 300);
begin
Log.Message(Param1);
Log.Message(Param2);
Log.Message(Param3);
end;
Note that you must specify a data type for parameters with default values. The data type is ignored, but the DelphiScript syntax parser requires something between the parameter name and the default value.
The default value must be a constant. It can be neither an array, nor an object. It is possible to use expression as default parameter value:
const MyConst=5;
function Test_Default_Routine_ParameterValue_2(Param1 : OleVariant = 100 + MyConst);
begin
Log.Message(Param1);
end;
Parameters with default values must be at the end of the parameter list. That is, the following declaration is incorrect:
// Incorrect!!!
function TestB(Param1 : OleVariant = 20; Param2);
To specify default values for both Param1 and Param2, use the following declaration (note that we separate parameters with a semicolon, not a comma):
// Correct
function TestB(Param1 : OleVariant = 20; Param2 : OleVariant = 100);
If all of the routine’s parameters are optional and you want to omit them during the routine call, then you must omit the parenthesis as well:
TestB; // Correct
TestB(); // Error!!!
If the routine that has default parameter values is forward-declared, you must specify the default parameter values in the forward declaration as well, and they must be the same as the one specified in the routine implementation. That is, you cannot override the default parameter values:
function Test_Default_Routine_ParameterValue_forward(Param1, Param2 : OleVariant = 100); forward;
//...
procedure Main;
var r;
begin
try
//r := Calc(1,2);
//Log.Message(r);
//Test_Default_Routine_ParameterValue;
r:=Test_Default_Routine_ParameterValue_forward(1);
Log.Message(r);
except
Log.Error('Exception', ExceptionMessage)
end;
end;
function Test_Default_Routine_ParameterValue_forward(Param1, Param2: OleVariant = 50); // Error !!!
begin
Result := Param1 + Param2;
end;
However, if you have specified default parameter values in the routine’s forward declaration, you can omit default values from the routine implementation:
function Test_Default_Routine_ParameterValue_forward(Param1, Param2);
begin
Result := Param1 + Param2;
end;
通过引用传递函数参数
Like in Delphi, you can pass parameters to DelphiScript routines by value, reference or as out parameters.
Parameters passed by value are similar to local variables. The routine creates a local copy of this parameter, initializes it with the specified value and then works with the local copy. So, changes made to the parameter value within the routine body do not affect the original variable. Parameters specified with the var keyword are passed by reference. Unlike parameters passed by value, changes made to reference parameters within the routine body are made to the original variable.
The example below demonstrate the difference between parameters passed by value and by reference. The IncByVal
and IncByRef
functions return the same result (parameter value plus 1), however the IncByRef
function does change the value of a variable that has been passed to it.
function IncByVal (x);
begin
x := x + 1;
Result := x;
end;
function IncByRef (var x);
begin
x := x + 1;
Result := x;
end;
procedure Test_ByVal_ByRef;
var a, b, a2, b2 : OleVariant;
begin
a := 2;
b := 2;
a2 := IncByRef(a);
Log.Message('a = ' + aqConvert.VarToStr(a) + ' a2 = ' + aqConvert.VarToStr(a2)); // a = 3, a2 = 3
b2 := IncByVal(b);
Log.Message('b = ' + aqConvert.VarToStr(b) + ' b2 = ' + aqConvert.VarToStr(b2)); // b = 2, b2 = 3
end;
Out parameters are similar to parameters passed by reference. The difference is that out parameters are only used to return data from the routine and not to pass it to:
procedure Copy (x; out y);
begin
y := x;
end;
procedure Test_out;
var a: OleVariant;
begin
Copy(10, a);
Log.Message(aqConvert.VarToStr(a)); // a = 10
end;
Since reference and out parameters can be used to return data from routines, you can use them to create routines that have several return values:
function MultiReturnValue(x; var doublex, squaredx);
begin
doublex := 2 * x;
squaredx := x * x;
end;
procedure Test_MultiReturnValue;
var x, y, z: OleVariant;
begin
x := 5;
MultiReturnValue(x, y, z);
Log.Message(y); // y = 10
Log.Message(z); // z = 25
end;
Note that since reference and out parameters can be assigned, you can only pass variables, not constant values in routine calls:
procedure IncParam (var x);
begin
x := x + 1;
end;
procedure Test_ByRef_Out_PassValue;
var a : OleVariant;
begin
a := 1;
IncParam(a); // Correct
IncParam(5); // Error!!!
end;
逻辑控制语句
In DelphiScript you can use the if
operator in the same way as in Delphi. There are no restrictions on it. The same is true for the loop operators: for
, while
and repeat
...until
.
The case
operator has a bit wider functionality than in Delphi. Blessedly, it can be used for any types including strings.
procedure Test_If_Case_Loop_1;
var a;
begin
a:=0;
if (a=0) then
begin
Log.Message(a);
Log.Message(a);
end
else
Log.Message(a);
end;
procedure Test_If_Case_Loop_2;
var a;
begin
a:=1;
case a of
0:Log.Message('0') ;
1:Log.Message('1') ;
2:Log.Message('2') ;
else
Log.Message('else') ;
end;
end;
procedure Test_If_Case_Loop_3;
var a;
begin
for a := 1 to 10 do
begin
Log.Message(a);
end;
while a>0 do
begin
Log.Message(a);
a:=a-1;
end;
end;
procedure Test_If_Case_Loop_4;
var a;
begin
a:=1;
repeat
begin
a:=a+1;
Log.Message(a);
end;
until(a>10)
end;
异常处理
Each unhandled exception stops script execution and posts an error message to the test log, with the text of the exception message. To handle exceptions during script execution, use the try
... finally
and try
... except
statements. Raise
can be called without any parameters to re-raise the last exception. To raise the exception with a specific message string, use Raise
with that string as a parameter. For instance,
procedure Test_Exception;
begin
Raise('Invalid data');
end;
The ExceptionMessage
function will return the last string posted as an exception message. For example:
procedure Test_Exception;
begin
try
{do something here}
Raise('Invalid data');
except
Log.Error('Exception occurred: ' + ExceptionMessage);
end;
end;
DelphiScript脚本编程
日期操作
When writing scripts we often deal with dates. There are certain date value formats and TestComplete routines that help handle dates.
TestComplete has the aqDateTime
object that contains methods that can be useful when operating with dates.
One more object, aqConvert
, provides methods to convert between date values and their string equivalents
获取明天或昨天的日期
function TomorrowDate: TDateTime;
var CurrentDate, Tomorrow: TDateTime;
begin
CurrentDate := aqDateTime.Today;
Log.Message('Today is: ' + aqConvert.DateTimeToStr(CurrentDate));
Tomorrow := aqDateTime.AddDays(CurrentDate, 1);
Log.Message('Tomorrow will be: ' + aqConvert.DateTimeToStr(Tomorrow));
Result := Tomorrow;
end;
function YesterdayDate: TDateTime;
var CurrentDate, Yesterday: TDateTime;
begin
CurrentDate := aqDateTime.Today;
Log.Message('Today is: ' + aqConvert.DateTimeToStr(CurrentDate));
Yesterday := aqDateTime.AddDays(CurrentDate, -1);
Log.Message('Yesterday was : ' + aqConvert.DateTimeToStr(Yesterday));
Result := Yesterday;
end;
procedure Main;
begin
TomorrowDate();
YesterdayDate();
end;
计算年月日
function DaysInYear(YearNo: Integer): Integer;
begin
if aqDateTime.IsLeapYear(YearNo) then Result:=366 else Result:=365;
end;
function DaysInMonth(MonthNo,YearNo: Integer): Integer;
begin
case MonthNo of
1,3,5,7,8,10,12: Result:=31;
2: if aqDateTime.IsLeapYear(YearNo) then Result:=29 else Result:=28;
4,6,9,11: Result:=30;
end;
end;
procedure Main;
var r;
begin
r:=DaysInYear(2010);
Log.Message(r);
r:=DaysInMonth(2,2010);
Log.Message(r);
end;
日期比较
procedure Test_CompareDate;
var DateTime1, DateTime2,r;
begin
DateTime1 := aqConvert.StrToDate('2010-2-11');
DateTime2 := aqConvert.StrToDate('2010-2-12');
r := aqDateTime.Compare(DateTime1, DateTime2);
if r > 0 then
// DateTime1 > DateTime2;
Log.Message('DateTime1 > DateTime2')
else
begin
if r < 0 then
// DateTime1 < DateTime2;
Log.Message('DateTime1 < DateTime2')
else
// DateTime1 = DateTime2;
Log.Message('DateTime1 = DateTime2')
end;
end;
日期格式转换
procedure EncodeDateDemo;
var myDate : TDateTime;
begin
myDate:=aqDateTime.SetDateElements(2005,12,25);
Log.Message('The encoded date is: '+aqConvert.DateTimeToFormatStr(myDate,'%B/%#d/%Y'));
Log.Message('The variant representation of it is: '+aqConvert.IntToStr(myDate));
end;
procedure DecodeDateDemo;
var CurrentDate : TDateTime;
var Day, Month, Year :Integer;
begin
CurrentDate:=aqDateTime.Today;
Year:=aqDateTime.GetYear(CurrentDate);
Month:=aqDateTime.GetMonth(CurrentDate);
Day:=aqDateTime.GetDay(CurrentDate);
Log.Message(aqConvert.IntToStr(Day)+' day(s) have passed since the beginning of the '+aqConvert.IntToStr(Month)+' month of '+aqConvert.IntToStr(Year)+' year.');
end;
日期运算
procedure ModifyDates;
var Date, AlteredDate: TDateTime;
begin
Date:=aqDateTime.SetDateElements(2007,1,25);
//Increase the date by 7 days
//Note the month changing
AlteredDate:=aqDateTime.AddDays(Date,7);
Log.Message('Initial date: '+aqConvert.DateTimeToStr(Date));
Log.Message('Altered date 1: '+aqConvert.DateTimeToStr(AlteredDate));
//Increase the date by one month
//Note that 28 days were added since the month is February
AlteredDate:=aqDateTime.AddMonths(AlteredDate,1);
Log.Message('Altered date 2: '+aqConvert.DateTimeToStr(AlteredDate));
//Decrease the date by 1 day
AlteredDate:=aqDateTime.AddTime(AlteredDate,-1,0,0,0);
Log.Message('Altered date 3: '+aqConvert.DateTimeToStr(AlteredDate));
end;
计算某日是星期几
procedure DayOfWeekDemo;
var WeekDay : Integer;
DayName : String;
begin
WeekDay:=aqDateTime.GetDayOfWeek(aqDateTime.Today);
case WeekDay of
1: DayName:='Sunday';
2: DayName:='Monday';
3: DayName:='Tuesday';
4: DayName:='Wednesday';
5: DayName:='Thursday';
6: DayName:='Friday';
7: DayName:='Saturday';
end;
Log.Message('Today is '+DayName);
end;
计算出指定日期所在周的开始和结束日期:
function StartOfWeek (InputDate: TDateTime = nil);
begin
//If the input parameter is omitted then current date is taken
if (InputDate=nil) then InputDate:=aqDateTime.Today;
//Using US week day number
Result:=aqDateTime.AddDays(InputDate, - aqDateTime.GetDayOfWeek(InputDate) + 1);
//Using ISO week day number
//Result:=aqDateTime.AddDays(InputDate, - ISODayOfWeek(InputDate) + 1);
end;
function EndOfWeek (InputDate: TDateTime = nil);
begin
//If the input parameter is omitted then current date is taken
if (InputDate=nil) then InputDate:=aqDateTime.Today;
//Using US week day number
Result:=aqDateTime.AddDays(InputDate, - aqDateTime.GetDayOfWeek(InputDate) + 7);
//Using ISO week day number
//Result:=aqDateTime.AddDays(InputDate, - ISODayOfWeek(InputDate) + 7);
end;
procedure TestStartEndOfWeek;
var r;
begin
r:=StartOfWeek;
Log.Message(r);
r:=EndOfWeek;
Log.Message(r);
end;
时间操作
Operations over time values are very similar to operations over dates.
TestComplete has an aqDateTime
object that contains methods that can be useful when operating with date-time values.
Another object, aqConvert
, provides methods to convert between date values and their string equivalents
获取当前时间
procedure GetTime;
var NowValue: TDateTime;
begin
NowValue:=aqDateTime.Now;
Log.Message('The time obtained from the "Now" routine is: '+aqConvert.DateTimeToStr(NowValue));
Log.Message('The variant representation of NowValue is: '+ aqConvert.FloatToStr(NowValue));
end;
格式化输出时间
procedure OutputDemo;
var aDateTime: TDateTime;
begin
aDateTime:=aqDateTime.Now;
Log.Message(aqConvert.DateTimeToStr(aDateTime));
Log.Message(aqConvert.DateTimeToFormatStr(aDateTime, '%A. %B, %d, %Y. %H:%M:%S'));
end;
时间格式转换
procedure EncodeTimeDemo;
var myTime: TDateTime;
begin
myTime:=aqDateTime.SetTimeElements(05,05,05);
Log.Message('The encoded time is: '+TimeToStr(myTime));
//Log.Message('The encoded time is: '+aqConvert.DateTimeToFormatStr(myTime, '%H:%M:%S'));
Log.Message('The variant representation of it is: '+aqConvert.FloatToStr(myTime));
end;
procedure DecodeTimeDemo;
var CurrentTime : TDateTime;
Hours, Minutes, Seconds:Integer;
begin
CurrentTime:=aqDateTime.Time;
Hours:=aqDateTime.GetHours(CurrentTime);
Minutes:=aqDateTime.GetMinutes(CurrentTime);
Seconds:=aqDateTime.GetSeconds(CurrentTime);
Log.Message(aqConvert.IntToStr(Minutes)+ ' minute(s) and '+aqConvert.IntToStr(Seconds)+' second(s) have passed since the hour '+aqConvert.IntToStr(Hours)+' has started.');
end;
时间运算
procedure ModifyingTimeValues;
var CurrentTime, ADateTime, AlteredTime: TDateTime;
begin
CurrentTime:=aqDateTime.Time;
//Increase time by 30 seconds
AlteredTime:=aqDateTime.AddSeconds(CurrentTime,30);
Log.Message('Current time: '+TimeToStr(CurrentTime));
Log.Message('Altered time: '+TimeToStr(AlteredTime));
//Decrease time by 2 hours
AlteredTime:=aqDateTime.AddHours(CurrentTime,-2);
Log.Message('Current time: '+TimeToStr(CurrentTime));
Log.Message('Altered time: '+TimeToStr(AlteredTime));
//Passing both positive and negative arguments
//Increase time by 5 minutes (1 hour minus 55 minutes)
AlteredTime:=aqDateTime.AddTime(CurrentTime,0,1,-55,0);
Log.Message('Current time: '+TimeToStr(CurrentTime));
Log.Message('Altered time: '+TimeToStr(AlteredTime));
//Adding 10 minutes to a date value like 11:55 PM, December 31, 1999 changes the whole date
ADateTime:=aqDateTime.SetDateTimeElements(2011,12,31,23,55,00);
AlteredTime:=aqDateTime.AddMinutes(ADateTime,10);
Log.Message('A date-time value: '+aqConvert.DateTimeToStr(ADateTime));
Log.Message('Altered date-time value: '+aqConvert.DateTimeToStr(AlteredTime));
end;
时间比较
procedure Test_Time_Compare;
var DateTime1, DateTime2,r;
begin
DateTime1:=aqConvert.StrToTime('15:29');
DateTime2:=aqConvert.StrToTime('15:20');
r := aqDateTime.Compare(DateTime1, DateTime2);
if r > 0 then
Log.Message('DateTime1 > DateTime2')
else
begin
if r < 0 then
Log.Message('DateTime1 < DateTime2')
else
Log.Message('DateTime1 = DateTime2');
end;
end;
计时
procedure DoTest1;
var a;
begin
// while a<10000 do
// begin
// a:=a+1;
// end;
aqUtils.Delay(1000);
end;
procedure MeasureTestTime1;
var TimeBefore, TimeAfter: TDateTime;
var TimeUsed;
begin
TimeBefore:=aqDateTime.Now;
DoTest1;
TimeAfter:=aqDateTime.Now;
TimeUsed:=aqDateTime.TimeInterval(TimeBefore, TimeAfter);
Log.Message('Test1 finished.Time Used:='+aqConvert.VarToStr(TimeUsed));
end;
procedure MeasureTestTime2;
var StopWatchObj: OleVariant;
begin
StopWatchObj := HISUtils.StopWatch;
StopWatchObj.Start;
DoTest1;
StopWatchObj.Stop;
Log.Message('Test1 finished.');
Log.Message('Execution time: ' + StopWatchObj.ToString);
end;
procedure MeasureTestTime3;
var StopWatchObj: OleVariant;
i: integer;
begin
StopWatchObj := HISUtils.StopWatch;
StopWatchObj.Start;
for i:=1 to 5 do
begin
DoTest1;
StopWatchObj.Split;
Log.Message('Iteration: '+aqConvert.IntToStr(i)+'. Time elapsed: '+StopWatchObj.ToString);
end;
StopWatchObj.Stop;
Log.Message('Test1 finished.');
Log.Message('Execution time: ' + StopWatchObj.ToString);
end;
数字运算
The aqConvert and aqString objects contain several methods that can be helpful when dealing with numerical values. The tables below list those methods. The objects are available for all supported scripting languages, so that you can use them to operate with date values regardless of the chosen language.
Method |
Description |
Converts a floating-point value to a string. |
|
Converts a floating-point value to a string using the one of the predefined format settings. |
|
Converts the given number into a string. |
|
Converts the specified string to a floating-point value. |
|
Converts the specified string to an integer value. |
Furthermore, DelphiScript has several functions that perform mathematical operations over numbers. Most of them are ported from the original Delphi's System unit. The table below lists these functions.
Function |
Description |
Abs(number) |
Returns the absolute value of a number. |
Cos(number) |
Returns the cosine of a number. |
Dec(number[, IncStep]) |
Decreases the given number by one or by specified value. |
Exp(power) |
Returns e (the base of natural logarithms) raised to the specified power. |
Frac(number) |
Returns the fractional part of a specified number. |
Inc(number[, IncStep]) |
Increases the given number by one or by specified value. |
Int(number) |
Returns the integer part of a specified number. |
Ln(number) |
Returns the natural logarithm of a number. |
Pi |
Returns the Pi constant, which is approximately equal to 3.1415926535897932385. |
Random |
Returns a pseudorandom number between 0 and 1. |
Random(iRange) |
Returns a pseudorandom number between 0 and iRange-1. |
Randomize |
Initializes the random number generator with a value taken from the current tick count. If Randomize is never called, scripts using Random will always run through the same sequence of "random" numbers. If it is called all the time, they may well get the same number on all calls to Random. Randomize should be called only once, at the start of the main script. |
RandSeed |
Variable. Specifies the initial value for the random number generator. This can be necessary to generate the same sequences of "random" numbers in your scripts. |
Round(number) |
Rounds the specifies to the nearest integer value. If the number is exactly midway between two integers, returns the greater integer of the two. |
Sin(number) |
Returns the sine of a number. |
Sqr(number) |
Returns the squared value of a number. |
Sqrt(number) |
Returns the square root of a number. |
DelphiScript also has some additional arithmetic operators:
Integer division (div) |
Calculates the integer result of division for the numbers which are not evenly divisible. |
Modulo (mod) |
Calculates the remainder of the division and is only concerned with the resulting remainder after division is performed on two operands. If the operands are floating point numbers, then they are rounded to integer. |
Sign identity (+) |
Requires a single operand. Returns the value of the same sign as the operand. |
Sign negation (-) |
Requires a single operand. Returns the value of the opposite sign than the operand. |
procedure DelphiScriptOperators;
var aVar1, aVar2: integer;
begin
//Integer division
Log.Message(40 div 10); //Posts 4
Log.Message(49 div 10); //Posts 4
//Modulo
Log.Message(7 mod 3); //Posts 1
Log.Message(40 mod 10); //Posts 0
Log.Message(49 mod 10); //Posts 9
//Sign identity
aVar1:=7;
aVar2:=-7;
Log.Message(+aVar1); //Posts 7
Log.Message(+aVar2); //Posts -7
//Sign negation
Log.Message(-aVar1); //Posts -7
Log.Message(-aVar2); //Posts 7
end;
取整
function Rounders;
var PositiveFloat1, PositiveFloat2, NegativeFloat1, NegativeFloat2: real;
begin
PositiveFloat1:=123.456;
PositiveFloat2:=123.567;
NegativeFloat1:=-123.456;
NegativeFloat2:=-123.567;
Log.Message('Using the Int function');
Log.Message(Int(PositiveFloat1)); //Result is: 123
Log.Message(Int(PositiveFloat2)); //Result is: 123
Log.Message(Int(NegativeFloat1)); //Result is: -123
Log.Message(Int(NegativeFloat2)); //Result is: -123
Log.Message('Using the Round function');
Log.Message(Round(PositiveFloat1)); //Result is: 123
Log.Message(Round(PositiveFloat2)); //Result is: 124
Log.Message(Round(NegativeFloat1)); //Result is: -123
Log.Message(Round(NegativeFloat2)); //Result is: -124
end;
数字与字符串间转换
procedure NumToStrDemo;
var int: integer;
floatpt: real;
begin
int:=17;
Log.Message(aqConvert.IntToStr(int)); //Posts 17
int:=$ff;
Log.Message(aqConvert.IntToStr(int)); //Posts 255
int:=$047C;
Log.Message(aqConvert.IntToStr(int)); //Posts 1148
floatpt:=-1234.567890;
Log.Message(aqConvert.FloatToStr(floatpt)); //Posts -1234.56789
Log.Message(aqString.Format('%1.4E',floatpt)); //Posts -1.2346E+003
end;
function StrToNumDemo;
var int: integer;
floatpt: real;
begin
int:=aqConvert.StrToInt('-1024');
Log.Message(int); //Posts -1024
floatpt:=aqConvert.StrToFloat('-1234.56789e2');
Log.Message(aqConvert.FloatToStr(floatpt)); //Posts -123456.789
end;
However, sometimes the functionality of those methods is insufficient, since they have some drawbacks:
- The StrToInt and StrToFloat methods raise an exception when they cannot recognize the input string.
- Both methods have a predefined set of acceptable characters and do not work with an arbitrary string.
A versatile routine that would extract numbers from any textual string and recognize both integer and floating point values can be implemented with the help of regular expressions. The following regular expression pattern would match positive or negative integer numbers, as well as floating-point numbers both in general and scientific notations: [-+]?\d*\.?\d+([eE][-+]?\d+)?.
Here is a sample for a routine that verifies whether a string contains a number. It uses the regular expression to check the input string and returns True if the input string holds an integer or floating point number.
function ContainsNumber(Str);
var
re: OleVariant;
begin
re:=HISUtils.RegExpr;
re.Expression:='[-+]?\d*\.?\d+([eE][-+]?\d+)?'; //Specify the regular expression
Result:=re.Exec(Str) //Return the verification result
end;
procedure Test_ContainsNumber;
var r;
begin
r:=ContainsNumber('aaa123bbb');
Log.Message(r);
r:=ContainsNumber('aaaxxxbbb');
Log.Message(r);
end;
The same regular expression can be used to extract the number from a string. Since the input string can contain more than one number matching the regular expression, only the first occurrence would be returned by the routine. If the string does not have a number, it is convenient to set the default value that would be returned in this case.
function ExtractNumber(Str, DefaultValue);
var
re: OleVariant;
begin
re:=HISUtils.RegExpr;
re.Expression:='[-+]?\d*\.?\d+([eE][-+]?\d+)?'; //Specify the regular expression
//Search for occurrences
//If no numbers were found then return default value
if (not re.Exec(Str))then Result:=DefaultValue
//Else, convert a string with first occurrence into a number
else Result:=aqConvert.StrToFloat(re.Match[0]);
end;
procedure Test_ExtractNumber;
var r;
begin
r:=ExtractNumber('aaa123bbb','0');
Log.Message(r);
r:=ExtractNumber('aaaxxxbbb','0');
Log.Message(r);
end;
字符串运算
A string is a sequence of symbols or digits. Strings are among the most frequently used data types. Like any other data type, strings in TestComplete are represented as OLE-compatible variants.
In DelphiScript, a sequence of literal characters enclosed in single quotation marks (') is recognized as a string. Double quotation marks (") are allowed within a string. To insert a single quotation mark into a string, it should be duplicated. The following is an example of string:
procedure DelphiScriptString;
var str1,str2,str3;
begin
str1 := 'The brig was heading to Liverpool, when the captain noticed a ship.';
str2 := '"Ahoy! Is there anyone?" - the captain cried.';
str3 := '''Nobody.'' - was the answer.';
Log.Message(str1);
Log.Message(str2);
Log.Message(str3);
end;
特殊字符
In DelphiScript you can emulate any character by using the Chr function with the appropriate ASCII code. Another way to emulate a character is to prefix its ASCII code with # symbol. This also applies to special characters that are used to format string values. The table below lists the most frequently used special characters.
Description |
Character sequence |
Carriage return. |
Chr(13) -- or -- #13 |
Line feed. |
Chr(10) -- or -- #10 |
A combination of carriage return and line feed. |
Chr(13)+Chr(10) -- or -- #13#10 |
Form feed. |
Chr(12) -- or -- #12 |
Horizontal tab. |
Chr(9) -- or -- #9 |
Vertical tab. |
Chr(11) -- or -- #11 |
procedure Test_SpecialChar;
var Str;
begin
Str := 'A string.' + Chr(13) + Chr(10) +'Another one string.';
Log.Message(Str);
end;
procedure Test_SpecialChar_2;
var Str1,Str2;
begin
Str1 := 'A string.' + #13#10 + 'Another one string.';
Str2 := 'A string.'#13#10'Another one string.';
Log.Message(Str1);
Log.Message(Str2);
end;
获取字符长度
procedure StringLengthDemo;
var aString;
begin
aString:='Some text';
Log.Message('The string is ' + IntToStr(aqString.GetLength(aString)) + ' character(s) long.');
Log.Message('The string is ' + IntToStr(Length(aString)) + ' character(s) long.');
end;
字符串拼接
procedure ConcatenationDemo;
var Str1;
begin
Str1:='String No 1 ';
Log.Message(aqString.Concat(Str1, 'String No 2'));
Log.Message(Str1 + 'String No 2 ' + 'String No ' + IntToStr(3) + ' ');
end;
字符串比较
procedure StringComparison;
begin
// Comparing the string in different letter cases
Log.Message('aqString.Compare(''ABRA'', ''abra'', true): ' + aqConvert.VarToStr(aqString.Compare('ABRA', 'abra', true)));
Log.Message('aqString.Compare(''ABRA'', ''abra'', false): ' + aqConvert.VarToStr(aqString.Compare('ABRA', 'abra', false)));
// Applying the equality operator of DelphiScript
Log.Message('''abra'' = ''abra'': ' + aqConvert.VarToStr('abra' = 'abra'));
Log.Message('''abra'' = ''ABRA'': ' + aqConvert.VarToStr('abra' = 'ABRA'));
end;
取出单独字符
procedure StringByLetter;
var aString, i;
begin
aString := 'Per aspera ad astra';
Log.Message('The string is : ' + aString);
Log.Message('And now this text letter by letter using aqString.GetChar:');
for i := 0 to aqString.GetLength(aString)-1 do Log.Message(aqString.GetChar(aString, i));
Log.Message('And now this text letter by letter using indexed access:');
for i := 1 to Length(aString) do Log.Message(aString[i]);
end;
查找字符串
procedure StringOccurrenceDemo;
var aString, aSubString, Res;
begin
aString := 'Per aspera ad astra';
aSubString := 'astra';
Res := aqString.Find(aString, aSubString);
if Res <> -1 then
Log.Message('A substring "' + aSubString + '" was found in string "' + aString+'"' + 'at position ' + aqConvert.IntToStr(Res))
else
Log.Message('There are no occurrences of "' + aSubString + '" in "' + aString + '".');
end;
procedure TextPosDemo;
var aString, aSubString, findpos;
begin
aString:='Per aspera ad astra';
aSubString := 'astra';
findpos := Pos(aSubString, aString);
if findpos <> 0
then
Log.Message('A substring "' + aSubString + '" was found at position ' + IntToStr(findpos))
else
Log.Message('There are no occurrences of ''' + aSubString + ''' in ''' + aString + '''.');
end;
获取子字符串
procedure GetStringDemo;
var Str;
begin
Str := '123456789';
Log.Message(Copy(Str, 2, 5)); // Posts "23456"
Log.Message(Copy(Str, 2, 20)); // Posts "23456789"
Log.Message(Copy(Str, -2, 3)); // Posts "123"
Log.Message(Copy(Str, 2, 0)); // Posts ""
Log.Message(aqString.SubString(Str, 1, 5)); // Posts "23456"
Log.Message(aqString.SubString(Str, 1, 20)); // Posts "23456789"
Log.Message(aqString.SubString(Str, 2, 0)); // Posts ""
end;
拆分字符串
procedure SplitDemo;
var s, ss, prevSep;
begin
s := 'Better late than never but better never late.';
// Assign list separator to space character
prevSep := aqString.ListSeparator;
aqString.ListSeparator := ' ';
// Split by spaces
Log.Message('There are ' + aqConvert.IntToStr(aqString.GetListLength(s)) + ' words in a string');
Log.Message('The first word is: ' + aqString.GetListItem(s, 0));
// Restore previous separator
aqString.ListSeparator := prevSep;
end;
剪掉空格
procedure Test_Trim;
var i,str;
begin
for i := 1 to 2 do
begin
str:=str+' '
end;
str:=str+'123';
for i := 1 to 3 do
begin
str:=str+' '
end;
Log.Message('['+str+']');
str := ' hallo ';
str:=Utilities.Trim(str);
Log.Message('['+str+']');
end;
Another function that can be useful when handling user input strings is excluding extra inner spaces out of the string. This function seems to be similar to Trim
, but the latter only removes spaces at the beginning or end of the string and does not affect the spaces within the string. The general idea of the function is for the string to be parsed into separate words and then a new string is constructed. The new string consists of the same words but is separated with a single space between words.
function TrimInner(Str);
var aWord, prevSep, i;
begin
Result := '';
prevSep := aqString.ListSeparator;
// Split at each space character.
aqString.ListSeparator := ' ';
for i := 0 to aqString.GetListLength(Str)-1 do
begin
aWord := aqString.GetListItem(Str,i);
if aWord <>'' then Result := Result + aWord + ' ';
end;
// Restore previous separator
aqString.ListSeparator := prevSep;
Result := aqString.Trim(Result);
end;
// An example of how to use this function
procedure TrimInnerDemo;
begin
Log.Message(TrimInner(' Follow the white rabbit '));
end;
字符串替换
procedure StringReplaceDemo;
var str;
begin
str := 'Hi, Bob. Have you seen Bob Robbinson?';
str := aqString.Replace(str, 'Bob', 'Jack', true);
Log.Message(str);
end;
procedure RegExpReplaceDemo1;
var str, re;
begin
str := 'Hi, Bob. Have you seen Bob Robbinson?';
// Create a RegExpr instance
re := HISUtils.RegExpr;
// Define regular expression pattern.
re.Expression := 'Bob';
// Perform replace operation
str := re.Replace(str, 'Jack');
Log.Message(str);
end;
procedure RegExpReplaceDemo2;
var str, re;
begin
str := 'The html is widely used in Internet. The HTM file is a text file with tags.';
// Create a RegExpr instance
re := HISUtils.RegExpr;
// Define regular expression pattern.
re.Expression := 'ht(ml|m)';
// Set ignore letter case modifier
re.ModifierStr := 'i';
// Perform replace operation
str := re.Replace(str, 'hypertext markup language');
Log.Message(str);
end;
procedure RegExpReplaceDemo3;
var str, re;
begin
str := 'Date of report: 30/04/2005.';
// Create a RegExpr instance
re := HISUtils.RegExpr;
// Define regular expression pattern.
re.Expression := '\d{1,2}.\d{1,2}.\d{2,4}';
// Perform replace operation
str := re.Replace(str,'Some Date');
Log.Message(str);
end;
大小写转换
procedure LetterCaseDemo;
var str;
begin
str := 'The word "Champagne" is of French origin';
// Converting to lower case
Log.Message(aqString.ToLower(str));
// Converting to upper case
Log.Message(aqString.ToUpper(str));
end;
字符串列表操作
Some scripting objects, generally, controls like ListBoxes, ComboBoxes, Memos, return data about their state or contents as string lists. The individual data elements (or items) in this list are separated by commas, line breaks, carriage returns or some other delimiter characters.
procedure ListDialogOptions;
var OptStr, prevSep, i;
begin
// Get a string with dialog options
OptStr := UserForms.UserForm1.SaveDialog1.Options;
// Assign list separator to comma
prevSep := aqString.ListSeparator;
aqString.ListSeparator := ',';
// Get the number of dialog options
Log.Message('The dialog has ' + aqConvert.IntToStr(aqString.GetListLength(OptStr)) + ' option(s) enabled:');
// Iterate through the options list
for i := 0 to aqString.GetListLength(OptStr)-1 do
//Get the option and post it to log
Log.Message('Option No ' + aqConvert.IntToStr(i+1) + ' is: ' + aqString.GetListItem(OptStr, i));
// Restore previous separator
aqString.ListSeparator := prevSep;
end;
procedure ManageMemoText;
var StrList, prevSep;
begin
// Get a string with memo lines
StrList := UserForms.UserForm1.cxMemo1.Lines.Text;
// Post the memo contents to log
Log.Message(UserForms.UserForm1.cxMemo1.Lines.Text);
// Assign list separator to newline character
prevSep := aqString.ListSeparator;
aqString.ListSeparator := #13#10;
// Append one more line
StrList := aqString.AddListItem(StrList, 'Last Line');
Log.Message(StrList);
// Change the value of the first line
StrList := aqString.ChangeListItem(StrList, 'New First Line', 0);
// Set the memo contents to a new list
UserForms.UserForm1.cxMemo1.Lines.Text := StrList;
// Post the memo contents to log
Log.Message(UserForms.UserForm1.cxMemo1.Lines.Text);
// Restore previous separator
aqString.ListSeparator := prevSep;
end;