TestComplete脚本语言 - DelphiScript

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(LowHigh)

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(Low1High1Low2High2)

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(Low1High1Low2High2Low3High3)

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:

Abort
Addr
Assert
Dispose
Finalize

Hi
High
Initialize
Lo
Low

New
Ptr
SetString
SizeOf
Str

UniqueString
VarArrayRef
VarCast
VarCopy

函数参数默认值

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

FloatToStr

Converts a floating-point value to a string.

Format

Converts a floating-point value to a string using the one of the predefined format settings.

IntToStr

Converts the given number into a string.

StrToFloat

Converts the specified string to a floating-point value.

StrToInt

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.
On Unix platforms it is interpreted as new line.

Chr(10) -- or -- #10

A combination of carriage return and line feed.
On Windows platforms it is interpreted as new line.

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;

posted on 2011-02-14 17:28  TIB  阅读(1597)  评论(0编辑  收藏  举报

导航