ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/testsuite/testApp/TestApplication.pas
Revision: 369
Committed: Wed Dec 8 13:12:10 2021 UTC (3 years ago) by tony
Content type: text/x-pascal
File size: 45332 byte(s)
Log Message:
TestApplication no longer dependent on TJnlEntry type being declared

File Contents

# User Rev Content
1 tony 334 (*
2     * MWA Software Test suite. This unit provides common
3     * code for all Firebird Database tests.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19     * The Original Code is (C) 2016-2020 Tony Whyman, MWA Software
20     * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit TestApplication;
28     {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31    
32     {$IFDEF FPC}
33     {$mode delphi}
34     {$codepage utf8}
35     {$ENDIF}
36    
37     {$IF not defined (DCC) and not defined (FPC)}
38     {$DEFINE DCC}
39     {$IFEND}
40    
41     interface
42    
43     uses
44     Classes, SysUtils, {$IFDEF FPC}CustApp,{$ENDIF} Firebird, IB, IBUtils, FmtBCD, FBClientLib;
45    
46     {$IF not defined(LineEnding)}
47     const
48     {$IFDEF WINDOWS}
49     LineEnding = #$0D#$0A;
50     {$ELSE}
51     LineEnding = #$0A;
52     {$ENDIF}
53     {$IFEND}
54    
55     const
56     Copyright = 'Copyright MWA Software 2016-2021';
57    
58     type
59     {$IFDEF DCC}
60     TCustomApplication = class(TComponent)
61     private
62     FTitle: string;
63     protected
64     procedure DoRun; virtual; abstract;
65     public
66     function Exename: string;
67     procedure Run;
68     procedure Terminate;
69     property Title: string read FTitle write FTitle;
70     end;
71     {$ENDIF}
72    
73     TTestApplication = class;
74    
75     { TTestBase }
76    
77     TTestBase = class
78     private
79     FOwner: TTestApplication;
80 tony 351 FFloatTpl: AnsiString;
81     FCursorSeq: integer;
82 tony 334 function GetFirebirdAPI: IFirebirdAPI;
83     procedure SetOwner(AOwner: TTestApplication);
84 tony 369 {$if declared(TJnlEntry) }
85     procedure HandleOnJnlEntry(JnlEntry: TJnlEntry);
86     {$endif}
87 tony 334 protected
88     FHexStrings: boolean;
89 tony 351 FShowBinaryBlob: boolean;
90 tony 334 procedure DumpBCD(bcd: tBCD);
91     procedure ClientLibraryPathChanged; virtual;
92     procedure CreateObjects(Application: TTestApplication); virtual;
93     function ExtractDBName(ConnectString: AnsiString): AnsiString;
94     function GetTestID: AnsiString; virtual; abstract;
95     function GetTestTitle: AnsiString; virtual; abstract;
96     procedure PrintHexString(s: AnsiString);
97     procedure PrintDPB(DPB: IDPB);
98     procedure PrintTPB(TPB: ITPB);
99     procedure PrintSPB(SPB: ISPB);
100     procedure PrintMetaData(meta: IMetaData);
101     procedure ParamInfo(SQLParams: ISQLParams);
102 tony 369 {$if declared(TJnlEntry) }
103     procedure PrintJournalFile(aFileName: AnsiString);
104     procedure PrintJournalTable(Attachment: IAttachment);
105     {$ifend}
106 tony 351 function ReportResults(Statement: IStatement; ShowCursorName: boolean=false): IResultSet;
107 tony 334 procedure ReportResult(aValue: IResults);
108     function StringToHex(octetString: string; MaxLineLength: integer=0): string;
109 tony 369 procedure WriteAttachmentInfo(Attachment: IAttachment);
110 tony 334 procedure WriteArray(ar: IArray);
111     procedure WriteAffectedRows(Statement: IStatement);
112     procedure WriteDBInfo(DBInfo: IDBInformation);
113 tony 369 procedure WriteTRInfo(TrInfo: ITrInformation);
114 tony 334 procedure WriteBytes(Bytes: TByteArray);
115     procedure WriteOperationCounts(Category: AnsiString; ops: TDBOperationCounts);
116     procedure WritePerfStats(stats: TPerfCounters);
117     procedure WriteSQLData(aValue: ISQLData);
118     procedure CheckActivity(Attachment: IAttachment); overload;
119     procedure CheckActivity(Transaction: ITransaction); overload;
120     procedure InitTest; virtual;
121     function SkipTest: boolean; virtual;
122     procedure ProcessResults; virtual;
123 tony 351 procedure SetFloatTemplate(tpl: Ansistring);
124 tony 334 public
125     constructor Create(aOwner: TTestApplication); virtual;
126     function ChildProcess: boolean; virtual;
127     function TestTitle: AnsiString; virtual;
128     property FirebirdAPI: IFirebirdAPI read GetFirebirdAPI;
129     procedure RunTest(CharSet: AnsiString; SQLDialect: integer); virtual; abstract;
130     property Owner: TTestApplication read FOwner;
131     property TestID: AnsiString read GetTestID;
132     end;
133    
134     TTest = class of TTestBase;
135    
136     { TTestApplication }
137    
138     TTestApplication = class(TCustomApplication)
139     private
140     class var FTests: TStringList;
141     private
142     class procedure CreateTestList;
143     class procedure DestroyTestList;
144     private
145     FClientLibraryPath: string;
146     FServer: AnsiString;
147     FEmployeeDatabaseName: AnsiString;
148     FNewDatabaseName: AnsiString;
149     FSecondNewDatabaseName: AnsiString;
150     FTestOption: AnsiString;
151     FUserName: AnsiString;
152     FPassword: AnsiString;
153     FBackupFileName: AnsiString;
154     FShowStatistics: boolean;
155     FFirebirdAPI: IFirebirdAPI;
156     FPortNo: AnsiString;
157     FCreateObjectsDone: boolean;
158     FQuiet: boolean;
159     procedure CleanUp;
160     function GetFirebirdAPI: IFirebirdAPI;
161     function GetIndexByTestID(aTestID: AnsiString): integer;
162     procedure SetClientLibraryPath(aLibName: string);
163     procedure SetUserName(aValue: AnsiString);
164     procedure SetPassword(aValue: AnsiString);
165     procedure SetEmployeeDatabaseName(aValue: AnsiString);
166     procedure SetNewDatabaseName(aValue: AnsiString);
167     procedure SetSecondNewDatabaseName(aValue: AnsiString);
168     procedure SetBackupFileName(aValue: AnsiString);
169     procedure SetServerName(AValue: AnsiString);
170     procedure SetPortNum(aValue: AnsiString);
171     procedure SetTestOption(aValue: AnsiString);
172     protected
173     {$IFDEF FPC}
174     function GetShortOptions: AnsiString; virtual;
175     function GetLongOptions: AnsiString; virtual;
176     {$ENDIF}
177     procedure GetParams(var DoPrompt: boolean; var TestID: string); virtual;
178     procedure DoRun; override;
179     procedure DoTest(index: integer);
180     procedure SetFormatSettings; virtual;
181     procedure WriteHelp; virtual;
182     public
183     constructor Create(AOwner: TComponent); override;
184     destructor Destroy; override;
185     function GetUserName: AnsiString;
186     function GetPassword: AnsiString;
187     function GetEmployeeDatabaseName: AnsiString;
188     function GetNewDatabaseName: AnsiString;
189 tony 351 function GetTempDatabaseName: AnsiString;
190 tony 334 function GetSecondNewDatabaseName: AnsiString;
191     function GetBackupFileName: AnsiString;
192     procedure RunAll;
193     procedure RunTest(TestID: AnsiString);
194     property ShowStatistics: boolean read FShowStatistics write FShowStatistics;
195     property FirebirdAPI: IFirebirdAPI read GetFirebirdAPI;
196     property Server: AnsiString read FServer;
197     property PortNo: AnsiString read FPortNo;
198     property ClientLibraryPath: string read FClientLibraryPath;
199     property TestOption: AnsiString read FTestOption write SetTestOption;
200     property Quiet: boolean read FQuiet;
201     end;
202    
203 tony 351 { TMsgHash }
204    
205     TMsgHash = class
206     private
207     FFinalised: boolean;
208     protected
209     procedure CheckNotFinalised;
210     public
211     procedure AddText(aText: AnsiString); virtual; abstract;
212     procedure Finalise; virtual;
213     function SameHash(otherHash: TMsgHash): boolean;
214     function Digest: AnsiString; virtual; abstract;
215     class function CreateMsgHash: TMsgHash;
216     property Finalised: boolean read FFinalised;
217     end;
218    
219 tony 334 ESkipException = class(Exception);
220    
221     var
222     TestApp: TTestApplication = nil;
223    
224     var OutFile: text;
225    
226     procedure RegisterTest(aTest: TTest);
227    
228     implementation
229    
230 tony 351 {$IFNDEF MSWINDOWS}
231     uses MD5;
232     {$ENDIF}
233    
234 tony 334 {$IFDEF MSWINDOWS}
235 tony 351 uses {$IFDEF FPC}MD5,{$ENDIF} windows;
236 tony 334
237     function GetTempDir: AnsiString;
238     var
239     tempFolder: array[0..MAX_PATH] of Char;
240     begin
241     GetTempPath(MAX_PATH, @tempFolder);
242     result := StrPas(tempFolder);
243     end;
244     {$ENDIF}
245    
246     procedure RegisterTest(aTest: TTest);
247     var test: TTestBase;
248     begin
249     TTestApplication.CreateTestList;
250     test := aTest.Create(TestApp);
251     TTestApplication.FTests.AddObject(test.GetTestID,test);
252     // if TestApp <> nil then
253     // test.CreateObjects(TestApp);
254     end;
255    
256 tony 351 {$IFDEF FPC}
257     type
258    
259     { TMD5MsgHash }
260    
261     TMD5MsgHash = class(TMsgHash)
262     private
263     FMD5Context: TMDContext;
264     FDigest: TMDDigest;
265     public
266     constructor Create;
267     procedure AddText(aText: AnsiString); override;
268     procedure Finalise; override;
269     function Digest: AnsiString; override;
270     end;
271    
272     {$DEFINE MSG_HASH_AVAILABLE}
273    
274     { TMD5MsgHash }
275    
276     constructor TMD5MsgHash.Create;
277     begin
278     inherited Create;
279     MDInit(FMD5Context,MD_VERSION_5);
280     end;
281    
282     procedure TMD5MsgHash.AddText(aText: AnsiString);
283     begin
284     CheckNotFinalised;
285     MDUpdate(FMD5Context,PAnsiChar(aText)^,Length(aText));
286     end;
287    
288     procedure TMD5MsgHash.Finalise;
289     begin
290     CheckNotFinalised;
291     MDFinal(FMD5Context,FDigest);
292     inherited Finalise;
293     end;
294    
295     function TMD5MsgHash.Digest: AnsiString;
296     begin
297     if not FFinalised then
298     Finalise;
299     Result := MD5Print(FDigest);
300     end;
301    
302     class function TMsgHash.CreateMsgHash: TMsgHash;
303     begin
304     Result := TMD5MsgHash.Create;
305     end;
306     {$ENDIF}
307    
308     {$IFNDEF MSG_HASH_AVAILABLE}
309     type
310    
311     { TSimpleMsgHash }
312    
313     TSimpleMsgHash = class(TMsgHash)
314     private
315     FDigest: Int64;
316     Finalised: boolean;
317     public
318     procedure AddText(aText: AnsiString); override;
319     function Digest: AnsiString; override;
320     end;
321    
322     { TSimpleMsgHash }
323    
324     procedure TSimpleMsgHash.AddText(aText: AnsiString);
325     const
326     modulus = high(Int64) div 100;
327     var i: integer;
328     begin
329     CheckNotFinalised;
330     for i := 1 to length(aText) do
331     FDigest := (FDigest * 7 + ord(aText[i])) mod modulus;
332     end;
333    
334     function TSimpleMsgHash.Digest: AnsiString;
335     begin
336     if not Finalised then
337     Finalise;
338     Result := IntToStr(FDigest);
339     end;
340    
341     class function TMsgHash.CreateMsgHash: TMsgHash;
342     begin
343     Result := TSimpleMsgHash.Create;
344     end;
345    
346     {$ENDIF}
347    
348     procedure TMsgHash.CheckNotFinalised;
349     begin
350     if FFinalised then
351     raise Exception.Create('Digest has been finalised');
352     end;
353    
354     procedure TMsgHash.Finalise;
355     begin
356     FFinalised := true;
357     end;
358    
359     function TMsgHash.SameHash(otherHash: TMsgHash): boolean;
360     begin
361     Result := Digest = OtherHash.Digest;
362     end;
363    
364 tony 334 { TTestBase }
365    
366     constructor TTestBase.Create(aOwner: TTestApplication);
367     begin
368     inherited Create;
369     FOwner := aOwner;
370 tony 351 FFloatTpl := '#,###.00';
371 tony 334 end;
372    
373     function TTestBase.ChildProcess: boolean;
374     begin
375     Result := false;
376     end;
377    
378     function TTestBase.TestTitle: AnsiString;
379     begin
380     Result := 'Test ' + GetTestID + ': ' + GetTestTitle;
381     end;
382    
383     function TTestBase.GetFirebirdAPI: IFirebirdAPI;
384     begin
385     Result := FOwner.FirebirdAPI;
386     end;
387    
388     procedure TTestBase.SetOwner(AOwner: TTestApplication);
389     begin
390     FOwner := AOwner;
391     end;
392    
393 tony 369 {$if declared(TJnlEntry)}
394     procedure TTestBase.HandleOnJnlEntry(JnlEntry: TJnlEntry);
395     begin
396     with JnlEntry do
397     begin
398     {$IFNDEF FPC}
399     writeln(OutFile,'Journal Entry = ',ord(JnlEntryType),'(', TJournalProcessor.JnlEntryText(JnlEntryType),')');
400     {$ELSE}
401     writeln(OutFile,'Journal Entry = ',JnlEntryType,'(', TJournalProcessor.JnlEntryText(JnlEntryType),')');
402     {$ENDIF}
403     writeln(OutFIle,'Timestamp = ',FBFormatDateTime('yyyy/mm/dd hh:nn:ss.zzzz',Timestamp));
404     writeln(OutFile,'Session ID = ',SessionID);
405     writeln(OutFile,'Transaction ID = ',TransactionID);
406     case JnlEntry.JnlEntryType of
407     jeTransStart:
408     begin
409     writeln(OutFile,'Transaction Name = "',TransactionName,'"');
410     PrintTPB(TPB);
411     {$IFNDEF FPC}
412     writeln(OutFile,'Default Completion = ',ord(DefaultCompletion));
413     {$ELSE}
414     writeln(OutFile,'Default Completion = ',DefaultCompletion);
415     {$ENDIF}
416     end;
417    
418     jeQuery:
419     begin
420     writeln(OutFile,'Query = ',QueryText);
421     end;
422    
423     jeTransCommitRet,
424     jeTransRollbackRet:
425     writeln(Outfile,'Old TransactionID = ',OldTransactionID);
426     end;
427     end;
428     writeln(OutFile);
429     end;
430     {$ifend}
431    
432 tony 334 procedure TTestBase.DumpBCD(bcd: tBCD);
433     var i,l: integer;
434     begin
435     with bcd do
436     begin
437     writeln(OutFile,' Precision = ',bcd.Precision);
438     writeln(OutFile,' Sign = ',(SignSpecialPlaces and $80) shr 7);
439     writeln(OutFile,' Special = ', (SignSpecialPlaces and $40) shl 6);
440     writeln(OutFile,' Places = ', SignSpecialPlaces and $7F);
441     write(OutFile,' Digits = ');
442     l := Precision div 2;
443     if not odd(Precision) then l := l - 1;
444     for i := 0 to l do
445     write(OutFile,Format('%.2x',[Fraction[i]]),' ');
446     writeln(OutFile);
447     end;
448     end;
449    
450     procedure TTestBase.ClientLibraryPathChanged;
451     begin
452     //Do nothing yet
453     end;
454    
455     procedure TTestBase.CreateObjects(Application: TTestApplication);
456     begin
457     //Do nothing yet
458     end;
459    
460     function TTestBase.ExtractDBName(ConnectString: AnsiString): AnsiString;
461     var ServerName: AnsiString;
462     Protocol: TProtocolAll;
463     PortNo: AnsiString;
464     i: integer;
465     begin
466     if not ParseConnectString(ConnectString, ServerName, Result, Protocol,PortNo) then
467     begin
468     {assume either inet format (remote) or localhost}
469     Result := ConnectString;
470     if Pos('inet',Result) = 1 then
471     begin
472     system.Delete(Result,1,7);
473     i := Pos('/',Result);
474     if i > 0 then
475     system.delete(Result,1,i);
476     end
477     else
478     if Pos('localhost:',Result) = 1 then
479     system.Delete(Result,1,10)
480     end;
481     end;
482    
483     procedure TTestBase.PrintHexString(s: AnsiString);
484     var i: integer;
485     begin
486     for i := 1 to length(s) do
487     write(OutFile,Format('%x ',[byte(s[i])]));
488     end;
489    
490     procedure TTestBase.PrintDPB(DPB: IDPB);
491     var i: integer;
492     begin
493     writeln(OutFile,'DPB: Item Count = ', DPB.getCount);
494     for i := 0 to DPB.getCount - 1 do
495     begin
496     write(OutFile,' ',DPB[i].getParamTypeName);
497     if DPB[i].AsString <> '' then
498     writeln(Outfile,' = ', DPB[i].AsString)
499     else
500     writeln(OutFile);
501     end;
502     writeln(OutFile);
503     end;
504    
505     procedure TTestBase.PrintTPB(TPB: ITPB);
506     var i: integer;
507     begin
508     writeln(OutFile,'TPB: Item Count = ', TPB.getCount);
509     for i := 0 to TPB.getCount - 1 do
510     begin
511     write(OutFile,' ',TPB[i].getParamTypeName);
512     if TPB[i].AsString <> '' then
513     writeln(Outfile,' = ', TPB[i].AsString)
514     else
515     writeln(OutFile);
516     end;
517     writeln(OutFile);
518     end;
519    
520     procedure TTestBase.PrintSPB(SPB: ISPB);
521     var i: integer;
522     begin
523     writeln(OutFile,'SPB: Item Count = ', SPB.getCount);
524     for i := 0 to SPB.getCount - 1 do
525     begin
526     write(OutFile,' ',SPB[i].getParamTypeName);
527     if SPB[i].AsString <> '' then
528     writeln(Outfile,' = ', SPB[i].AsString)
529     else
530     writeln(OutFile);
531     end;
532     writeln(OutFile);
533     end;
534    
535     procedure TTestBase.PrintMetaData(meta: IMetaData);
536     var i, j: integer;
537     ar: IArrayMetaData;
538     bm: IBlobMetaData;
539     Bounds: TArrayBounds;
540     begin
541     writeln(OutFile,'Metadata');
542     for i := 0 to meta.GetCount - 1 do
543     with meta[i] do
544     begin
545     writeln(OutFile,'SQLType =',GetSQLTypeName);
546     writeln(OutFile,'sub type = ',getSubType);
547     writeln(OutFile,'Table = ',getRelationName);
548     writeln(OutFile,'Owner = ',getOwnerName);
549     writeln(OutFile,'Column Name = ',getSQLName);
550     writeln(OutFile,'Alias Name = ',getAliasName);
551     writeln(OutFile,'Field Name = ',getName);
552     writeln(OutFile,'Scale = ',getScale);
553     writeln(OutFile,'Charset id = ',getCharSetID);
554     if getIsNullable then writeln(OutFile,'Nullable') else writeln(OutFile,'Not Null');
555     writeln(OutFile,'Size = ',GetSize);
556     case getSQLType of
557     SQL_ARRAY:
558     begin
559     writeln(OutFile,'Array Meta Data:');
560     ar := GetArrayMetaData;
561     writeln(OutFile,'SQLType =',ar.GetSQLTypeName);
562     writeln(OutFile,'Scale = ',ar.getScale);
563     writeln(OutFile,'Charset id = ',ar.getCharSetID);
564     writeln(OutFile,'Size = ',ar.GetSize);
565     writeln(OutFile,'Table = ',ar.GetTableName);
566     writeln(OutFile,'Column = ',ar.GetColumnName);
567     writeln(OutFile,'Dimensions = ',ar.GetDimensions);
568     write(OutFile,'Bounds: ');
569     Bounds := ar.GetBounds;
570     for j := 0 to Length(Bounds) - 1 do
571     write(OutFile,'(',Bounds[j].LowerBound,':',Bounds[j].UpperBound,') ');
572     writeln(OutFile);
573     end;
574     SQL_BLOB:
575     begin
576     writeln(OutFile);
577     writeln(OutFile,'Blob Meta Data');
578     bm := GetBlobMetaData;
579     writeln(OutFile,'SQL SubType =',bm.GetSubType);
580     writeln(OutFile,'Table = ',bm.GetRelationName);
581     writeln(OutFile,'Column = ',bm.GetColumnName);
582     writeln(OutFile,'CharSetID = ',bm.GetCharSetID);
583     writeln(OutFile,'Segment Size = ',bm.GetSegmentSize);
584     writeln(OutFile);
585     end;
586     end;
587     writeln(OutFile);
588     end;
589     end;
590    
591     procedure TTestBase.ParamInfo(SQLParams: ISQLParams);
592     var i: integer;
593     begin
594     writeln(OutFile,'SQL Params');
595     for i := 0 to SQLParams.Count - 1 do
596     with SQLParams[i] do
597     begin
598     writeln(OutFile,'SQLType =',GetSQLTypeName);
599     writeln(OutFile,'sub type = ',getSubType);
600     writeln(OutFile,'Field Name = ',getName);
601     writeln(OutFile,'Scale = ',getScale);
602     writeln(OutFile,'Charset id = ',getCharSetID);
603     if getIsNullable then writeln(OutFile,'Nullable') else writeln(OutFile,'Not Null');
604     writeln(OutFile,'Size = ',GetSize);
605 tony 351 if not IsNull then
606     writeln(Outfile,'Value = ',getAsString);
607 tony 334 writeln(OutFile);
608     end;
609     end;
610    
611 tony 369 {$if declared(TJnlEntry) }
612     procedure TTestBase.PrintJournalFile(aFileName: AnsiString);
613     begin
614     writeln(OutFile,'Journal Entries');
615     with TJournalProcessor.Create do
616     try
617     Execute(aFileName,FirebirdAPI,HandleOnJnlEntry);
618     finally
619     Free
620     end;
621     end;
622    
623     procedure TTestBase.PrintJournalTable(Attachment: IAttachment);
624     var Results: IResultSet;
625     begin
626     writeln(OutFile,'Journal Table');
627     Results := Attachment.OpenCursorAtStart('Select * From IBX$JOURNALS');
628     while not Results.IsEof do
629     begin
630     ReportResult(Results);
631     Results.Fetchnext;
632     end;
633     end;
634     {$ifend}
635    
636 tony 351 function TTestBase.ReportResults(Statement: IStatement; ShowCursorName: boolean): IResultSet;
637 tony 334 begin
638     Result := Statement.OpenCursor;
639     try
640 tony 351 if ShowCursorName then
641     writeln(Outfile,'Results for Cursor: ',Result.GetCursorName);
642 tony 334 while Result.FetchNext do
643     ReportResult(Result);
644     finally
645     Result.Close;
646     end;
647     writeln(OutFile);
648     end;
649    
650     procedure TTestBase.ReportResult(aValue: IResults);
651     var i: integer;
652     begin
653     for i := 0 to aValue.getCount - 1 do
654     WriteSQLData(aValue[i]);
655     end;
656    
657     function TTestBase.StringToHex(octetString: string; MaxLineLength: integer
658     ): string;
659    
660     function ToHex(aValue: byte): string;
661     const
662     HexChars: array [0..15] of char = '0123456789ABCDEF';
663     begin
664     Result := HexChars[aValue shr 4] +
665     HexChars[(aValue and $0F)];
666     end;
667    
668     var i, j: integer;
669     begin
670     i := 1;
671     Result := '';
672     if MaxLineLength = 0 then
673     while i <= Length(octetString) do
674     begin
675     Result := Result + ToHex(byte(octetString[i]));
676     Inc(i);
677     end
678     else
679     while i <= Length(octetString) do
680     begin
681     for j := 1 to MaxLineLength do
682     begin
683     if i > Length(octetString) then
684     Exit
685     else
686     Result := Result + ToHex(byte(octetString[i]));
687     inc(i);
688     end;
689     Result := Result + LineEnding;
690     end;
691     end;
692    
693 tony 369 procedure TTestBase.WriteAttachmentInfo(Attachment: IAttachment);
694     begin
695     writeln(outfile,'DB Connect String = ',Attachment.GetConnectString);
696     writeln(outfile,'DB Charset ID = ',Attachment.GetDefaultCharSetID);
697     writeln(outfile,'DB SQL Dialect = ',Attachment.GetSQLDialect);
698     writeln(outfile,'DB Remote Protocol = ', Attachment.GetRemoteProtocol);
699     writeln(outfile,'DB ODS Major Version = ',Attachment.GetODSMajorVersion);
700     writeln(outfile,'DB ODS Minor Version = ',Attachment.GetODSMinorVersion);
701     writeln(outfile,'User Authentication Method = ',Attachment.GetAuthenticationMethod);
702     writeln(outfile,'Firebird Library Path = ',Attachment.getFirebirdAPI.GetFBLibrary.GetLibraryFilePath);
703     writeln(outfile,'DB Client Implementation Version = ',Attachment.getFirebirdAPI.GetImplementationVersion);
704     end;
705    
706 tony 334 procedure TTestBase.WriteArray(ar: IArray);
707     var Bounds: TArrayBounds;
708     i,j: integer;
709     begin
710     write(OutFile,'Array: ');
711     Bounds := ar.GetBounds;
712     case ar.GetDimensions of
713     1:
714     begin
715     for i := Bounds[0].LowerBound to Bounds[0].UpperBound do
716     write(OutFile,'(',i,': ',ar.GetAsVariant([i]),') ');
717     end;
718    
719     2:
720     begin
721     for i := Bounds[0].LowerBound to Bounds[0].UpperBound do
722     for j := Bounds[1].LowerBound to Bounds[1].UpperBound do
723     write(OutFile,'(',i,',',j,': ',ar.GetAsVariant([i,j]),') ');
724     end;
725     end;
726     writeln(OutFile);
727     writeln(OutFile);
728     end;
729    
730     procedure TTestBase.WriteAffectedRows(Statement: IStatement);
731     var SelectCount, InsertCount, UpdateCount, DeleteCount: integer;
732     begin
733     Statement.GetRowsAffected(SelectCount, InsertCount, UpdateCount, DeleteCount);
734     writeln(OutFile,'Select Count = ', SelectCount,' InsertCount = ',InsertCount,' UpdateCount = ', UpdateCount, ' DeleteCount = ',DeleteCount);
735     end;
736    
737     procedure TTestBase.WriteDBInfo(DBInfo: IDBInformation);
738     var i, j: integer;
739     bytes: TByteArray;
740     ConType: integer;
741     DBFileName: AnsiString;
742     DBSiteName: AnsiString;
743     Version: byte;
744     VersionString: AnsiString;
745     Users: TStringList;
746     begin
747     for i := 0 to DBInfo.GetCount - 1 do
748     with DBInfo[i] do
749     case getItemType of
750     isc_info_db_read_only:
751     if getAsInteger <> 0 then
752     writeln(OutFile,'Database is Read Only')
753     else
754     writeln(OutFile,'Database is Read/Write');
755     isc_info_allocation:
756     writeln(OutFile,'Pages =',getAsInteger);
757     isc_info_base_level:
758     begin
759     bytes := getAsBytes;
760     write(OutFile,'Base Level = ');
761     WriteBytes(Bytes);
762     end;
763     isc_info_db_id:
764     begin
765     DecodeIDCluster(ConType,DBFileName,DBSiteName);
766     writeln(OutFile,'Database ID = ', ConType,' FB = ', DBFileName, ' SN = ',DBSiteName);
767     end;
768     isc_info_implementation:
769     begin
770     bytes := getAsBytes;
771     write(OutFile,'Implementation = ');
772     WriteBytes(Bytes);
773     end;
774     isc_info_no_reserve:
775     writeln(OutFile,'Reserved = ',getAsInteger);
776     isc_info_ods_minor_version:
777     writeln(OutFile,'ODS minor = ',getAsInteger);
778     isc_info_ods_version:
779     writeln(OutFile,'ODS major = ',getAsInteger);
780     isc_info_page_size:
781     writeln(OutFile,'Page Size = ',getAsInteger);
782     isc_info_version:
783     begin
784     DecodeVersionString(Version,VersionString);
785     writeln(OutFile,'Version = ',Version,': ',VersionString);
786     end;
787     isc_info_current_memory:
788     writeln(OutFile,'Server Memory = ',getAsInteger);
789     isc_info_forced_writes:
790     writeln(OutFile,'Forced Writes = ',getAsInteger);
791     isc_info_max_memory:
792     writeln(OutFile,'Max Memory = ',getAsInteger);
793     isc_info_num_buffers:
794     writeln(OutFile,'Num Buffers = ',getAsInteger);
795     isc_info_sweep_interval:
796     writeln(OutFile,'Sweep Interval = ',getAsInteger);
797     isc_info_user_names:
798     begin
799     Users := TStringList.Create;
800     try
801     write(OutFile,'Logged in Users: ');
802     DecodeUserNames(Users);
803     for j := 0 to Users.Count - 1 do
804     write(OutFile,Users[j],',');
805    
806     finally
807     Users.Free;
808     end;
809     writeln(OutFile);
810     end;
811     isc_info_fetches:
812     writeln(OutFile,'Fetches = ',getAsInteger);
813     isc_info_marks:
814     writeln(OutFile,'Writes = ',getAsInteger);
815     isc_info_reads:
816     writeln(OutFile,'Reads = ',getAsInteger);
817     isc_info_writes:
818     writeln(OutFile,'Page Writes = ',getAsInteger);
819     isc_info_backout_count:
820     WriteOperationCounts('Record Version Removals',getOperationCounts);
821     isc_info_delete_count:
822     WriteOperationCounts('Deletes',getOperationCounts);
823     isc_info_expunge_count:
824     WriteOperationCounts('Expunge Count',getOperationCounts);
825     isc_info_insert_count:
826     WriteOperationCounts('Insert Count',getOperationCounts);
827     isc_info_purge_count:
828     WriteOperationCounts('Purge Count Countites',getOperationCounts);
829     isc_info_read_idx_count:
830     WriteOperationCounts('Indexed Reads Count',getOperationCounts);
831     isc_info_read_seq_count:
832     WriteOperationCounts('Sequential Table Scans',getOperationCounts);
833     isc_info_update_count:
834     WriteOperationCounts('Update Count',getOperationCounts);
835     isc_info_db_SQL_Dialect:
836     writeln(OutFile,'SQL Dialect = ',getAsInteger);
837     isc_info_creation_date:
838     writeln(OutFile,'Database Created: ',DateTimeToStr(getAsDateTime));
839     isc_info_active_tran_count:
840     writeln(OutFile,'Active Transaction Count = ',getAsInteger);
841     fb_info_page_contents:
842     begin
843     writeln('Database Page');
844     PrintHexString(getAsString);
845     writeln;
846     end;
847     fb_info_pages_used:
848     writeln(OutFile,'Pages Used = ',getAsInteger);
849     fb_info_pages_free:
850     writeln(OutFile,'Pages Free = ',getAsInteger);
851    
852     isc_info_truncated:
853     writeln(OutFile,'Results Truncated');
854     else
855     writeln(OutFile,'Unknown Response ',getItemType);
856     end;
857     end;
858    
859 tony 369 procedure TTestBase.WriteTRInfo(TrInfo: ITrInformation);
860     var IsolationType, RecVersion: byte;
861     i: integer;
862     access: integer;
863     begin
864     for i := 0 to TrInfo.GetCount - 1 do
865     with TrInfo[i] do
866     case getItemType of
867     isc_info_tra_id:
868     writeln(OutFile,'Transaction ID = ',getAsInteger);
869     isc_info_tra_oldest_interesting:
870     writeln(OutFile,'Oldest Interesting = ',getAsInteger);
871     isc_info_tra_oldest_active:
872     writeln(OutFile,'Oldest Action = ',getAsInteger);
873     isc_info_tra_oldest_snapshot:
874     writeln(OutFile,'Oldest Snapshot = ',getAsInteger);
875     fb_info_tra_snapshot_number:
876     writeln(OutFile,'Oldest Snapshot Number = ',getAsInteger);
877     isc_info_tra_lock_timeout:
878     writeln(OutFile,'Lock Timeout = ',getAsInteger);
879     isc_info_tra_isolation:
880     begin
881     DecodeTraIsolation(IsolationType, RecVersion);
882     write(OutFile,'Isolation Type = ');
883     case IsolationType of
884     isc_info_tra_consistency:
885     write(OutFile,'isc_info_tra_consistency');
886     isc_info_tra_concurrency:
887     write(OutFile,'isc_info_tra_concurrency');
888     isc_info_tra_read_committed:
889     begin
890     write(OutFile,'isc_info_tra_read_committed, Options =');
891     case RecVersion of
892     isc_info_tra_no_rec_version:
893     write(OutFile,'isc_info_tra_no_rec_version');
894     isc_info_tra_rec_version:
895     write(OutFile,'isc_info_tra_rec_version');
896     isc_info_tra_read_consistency:
897     write(OutFile,'isc_info_tra_read_consistency');
898     end;
899     end;
900     end;
901     writeln(OutFile);
902     end;
903     isc_info_tra_access:
904     begin
905     write(OutFile,'Transaction Access = ');
906     access := getAsInteger;
907     case access of
908     isc_info_tra_readonly:
909     writeln(OutFile,'isc_info_tra_readonly');
910     isc_info_tra_readwrite:
911     writeln(OutFile,'isc_info_tra_readwrite');
912     end;
913     end;
914     fb_info_tra_dbpath:
915     writeln(OutFile,'Transaction Database Path = ',getAsString);
916     end;
917    
918     end;
919    
920 tony 334 procedure TTestBase.WriteBytes(Bytes: TByteArray);
921     var i: integer;
922     begin
923     for i := 0 to length(Bytes) - 1 do
924     write(OutFile,Bytes[i],',');
925     writeln(OutFile);
926     end;
927    
928     procedure TTestBase.WriteOperationCounts(Category: AnsiString;
929     ops: TDBOperationCounts);
930     var i: integer;
931     begin
932     writeln(OutFile,Category,' Operation Counts');
933     for i := 0 to Length(ops) - 1 do
934     begin
935     writeln(OutFile,'Table ID = ',ops[i].TableID);
936     writeln(OutFile,'Count = ',ops[i].Count);
937     end;
938     writeln(OutFile);
939     end;
940    
941     procedure TTestBase.WritePerfStats(stats: TPerfCounters);
942     var LargeCompFormat: string;
943     ThreeSigPlacesFormat: string;
944     begin
945     {$IF declared(DefaultFormatSettings)}
946     with DefaultFormatSettings do
947     {$ELSE}
948     {$IF declared(FormatSettings)}
949     with FormatSettings do
950     {$IFEND}
951     {$IFEND}
952     begin
953     LargeCompFormat := '#' + ThousandSeparator + '##0';
954     ThreeSigPlacesFormat := '#0' + DecimalSeparator + '000';
955     end;
956     writeln(OutFile,'Current memory = ', FormatFloat(LargeCompFormat,stats[psCurrentMemory]));
957     writeln(OutFile,'Delta memory = ', FormatFloat(LargeCompFormat,stats[psDeltaMemory]));
958     writeln(OutFile,'Max memory = ', FormatFloat(LargeCompFormat,stats[psMaxMemory]));
959     writeln(OutFile,'Elapsed time= ', FormatFloat(ThreeSigPlacesFormat,stats[psRealTime]/1000),' sec');
960     writeln(OutFile,'Cpu = ', FormatFloat(ThreeSigPlacesFormat,stats[psUserTime]/1000),' sec');
961     writeln(OutFile,'Buffers = ', FormatFloat('#0',stats[psBuffers]));
962     writeln(OutFile,'Reads = ', FormatFloat('#0',stats[psReads]));
963     writeln(OutFile,'Writes = ', FormatFloat('#0',stats[psWrites]));
964     writeln(OutFile,'Fetches = ', FormatFloat('#0',stats[psFetches]));
965     end;
966    
967     procedure TTestBase.WriteSQLData(aValue: ISQLData);
968     var s: AnsiString;
969     dt: TDateTime;
970     dstOffset: SmallInt;
971     aTimeZone: AnsiString;
972     begin
973     if aValue.IsNull then
974     writeln(OutFile,aValue.Name,' = NULL')
975     else
976     case aValue.SQLType of
977     SQL_ARRAY:
978     begin
979     write(OutFile, aValue.Name,' = ');
980     if not aValue.IsNull then
981     WriteArray(aValue.AsArray)
982     else
983     writeln(OutFile,'NULL');
984     end;
985     SQL_FLOAT,SQL_DOUBLE,
986     SQL_D_FLOAT:
987 tony 351 writeln(OutFile, aValue.Name,' = ',FormatFloat(FFloatTpl,aValue.AsDouble));
988 tony 334
989     SQL_INT64:
990     if aValue.Scale <> 0 then
991 tony 351 writeln(OutFile, aValue.Name,' = ',FormatFloat(FFloatTpl,aValue.AsDouble))
992 tony 334 else
993     writeln(OutFile,aValue.Name,' = ',aValue.AsString);
994    
995     SQL_BLOB:
996     if aValue.IsNull then
997     writeln(OutFile,aValue.Name,' = (null blob)')
998     else
999     if aValue.SQLSubType = 1 then
1000     begin
1001     s := aValue.AsString;
1002     if FHexStrings then
1003     begin
1004     write(OutFile,aValue.Name,' = ');
1005     PrintHexString(s);
1006     writeln(OutFile,' (Charset Id = ',aValue.GetCharSetID, ' Codepage = ',StringCodePage(s),')');
1007     end
1008     else
1009     begin
1010     writeln(OutFile,aValue.Name,' (Charset Id = ',aValue.GetCharSetID, ' Codepage = ',StringCodePage(s),')');
1011     writeln(OutFile);
1012     writeln(OutFile,s);
1013     end
1014     end
1015     else
1016 tony 351 begin
1017 tony 334 writeln(OutFile,aValue.Name,' = (blob), Length = ',aValue.AsBlob.GetBlobSize);
1018 tony 351 if FShowBinaryBlob then
1019     PrintHexString(aValue.AsString);
1020     end;
1021 tony 334
1022     SQL_TEXT,SQL_VARYING:
1023     begin
1024     if aValue.GetCharSetID = 1 then
1025     s := aValue.AsString
1026     else
1027     s := TrimRight(aValue.AsString);
1028     if FHexStrings then
1029     begin
1030     write(OutFile,aValue.Name,' = ');
1031     PrintHexString(s);
1032     writeln(OutFile,' (Charset Id = ',aValue.GetCharSetID, ' Codepage = ',StringCodePage(s),')');
1033     end
1034     else
1035     if aValue.GetCharSetID > 0 then
1036     writeln(OutFile,aValue.Name,' = ',s,' (Charset Id = ',aValue.GetCharSetID, ' Codepage = ',StringCodePage(s),')')
1037     else
1038     writeln(OutFile,aValue.Name,' = ',s);
1039     end;
1040    
1041     SQL_TIMESTAMP:
1042     writeln(OutFile,aValue.Name,' = ',FBFormatDateTime('yyyy/mm/dd hh:nn:ss.zzzz',aValue.AsDateTime));
1043     SQL_TYPE_DATE:
1044     writeln(OutFile,aValue.Name,' = ',FBFormatDateTime('yyyy/mm/dd',aValue.AsDate));
1045     SQL_TYPE_TIME:
1046     writeln(OutFile,aValue.Name,' = ',FBFormatDateTime('hh:nn:ss.zzzz',aValue.AsTime));
1047     SQL_TIMESTAMP_TZ,
1048     SQL_TIMESTAMP_TZ_EX:
1049     begin
1050     aValue.GetAsDateTime(dt,dstOffset,aTimeZone);
1051     writeln(OutFile,aValue.Name,' =');
1052     writeln(OutFile,' AsString = ',aValue.GetAsString);
1053     writeln(OutFile,' Formatted = ',FBFormatDateTime('yyyy/mm/dd hh:nn:ss.zzzz',dt),' ',aTimeZone);
1054     writeln(OutFile,' TimeZoneID = ',aValue.GetStatement.GetAttachment.GetTimeZoneServices.TimeZoneName2TimeZoneID(aTimeZone));
1055     writeln(OutFile,' Time Zone Name = ',aTimeZone);
1056     writeln(OutFile,' UTC Time = ',DateTimeToStr( aValue.GetAsUTCDateTime));
1057     writeln(OutFile,' DST Offset = ',dstOffset);
1058     end;
1059     SQL_TIME_TZ,
1060     SQL_TIME_TZ_EX:
1061     begin
1062     aValue.GetAsDateTime(dt,dstOffset,aTimeZone);
1063     writeln(OutFile,aValue.Name,' =');
1064     writeln(OutFile,' AsString = ',aValue.GetAsString);
1065     writeln(OutFile,' Formatted = ',FBFormatDateTime('hh:nn:ss.zzzz',dt),' ',aTimeZone);
1066     writeln(OutFile,' TimeZoneID = ',aValue.GetStatement.GetAttachment.GetTimeZoneServices.TimeZoneName2TimeZoneID(aTimeZone));
1067     writeln(OutFile,' Time Zone Name = ',aTimeZone);
1068     writeln(OutFile,' UTC Time = ',TimeToStr( aValue.GetAsUTCDateTime));
1069     writeln(OutFile,' DST Offset = ',dstOffset);
1070     end;
1071    
1072     else
1073     writeln(OutFile,aValue.Name,' = ',aValue.AsString);
1074     end;
1075     end;
1076    
1077     procedure TTestBase.CheckActivity(Attachment: IAttachment);
1078     begin
1079     writeln(OutFile,'Database Activity = ',Attachment.HasActivity)
1080     end;
1081    
1082     procedure TTestBase.CheckActivity(Transaction: ITransaction);
1083     begin
1084     writeln(OutFile,'Transaction Activity = ',Transaction.HasActivity)
1085     end;
1086    
1087     procedure TTestBase.InitTest;
1088     begin
1089     //Do nothing yet
1090     end;
1091    
1092     function TTestBase.SkipTest: boolean;
1093     begin
1094     Result := false;
1095     end;
1096    
1097     procedure TTestBase.ProcessResults;
1098     begin
1099     //Do nothing
1100     end;
1101    
1102 tony 351 procedure TTestBase.SetFloatTemplate(tpl: Ansistring);
1103     begin
1104     FFloatTpl := tpl;
1105     end;
1106    
1107 tony 334 { TTestApplication }
1108    
1109     class procedure TTestApplication.CreateTestList;
1110     begin
1111     if FTests = nil then
1112     begin
1113     FTests := TStringList.Create;
1114     FTests.Sorted := true;
1115     FTests.Duplicates := dupError;
1116     end;
1117     end;
1118    
1119     class procedure TTestApplication.DestroyTestList;
1120     var i: integer;
1121     TestID: Ansistring;
1122     begin
1123     if assigned(FTests) then
1124     begin
1125     for i := 0 to FTests.Count - 1 do
1126     if FTests.Objects[i] <> nil then
1127     try
1128     TestID := TTestBase(FTests.Objects[i]).TestID;
1129     FTests.Objects[i].Free;
1130     except on E: Exception do
1131     writeln('Error Freeing Test ',TestID,' Error message = ',E.Message);
1132     end;
1133     FreeAndNil(FTests);
1134     end;
1135     end;
1136    
1137     procedure TTestApplication.CleanUp;
1138     var DPB: IDPB;
1139     Attachment: IAttachment;
1140     begin
1141     DPB := FirebirdAPI.AllocateDPB;
1142     DPB.Add(isc_dpb_user_name).setAsString(GetUserName);
1143     DPB.Add(isc_dpb_password).setAsString(GetPassword);
1144     Attachment := FirebirdAPI.OpenDatabase(GetNewDatabaseName,DPB,false);
1145     if Attachment <> nil then
1146     Attachment.DropDatabase;
1147     Attachment := FirebirdAPI.OpenDatabase(GetSecondNewDatabaseName,DPB,false);
1148     if Attachment <> nil then
1149     Attachment.DropDatabase;
1150     end;
1151    
1152     function TTestApplication.GetFirebirdAPI: IFirebirdAPI;
1153     begin
1154     if FFirebirdAPI = nil then
1155 tony 351 begin
1156 tony 334 FFirebirdAPI := IB.FirebirdAPI;
1157 tony 351 FFirebirdAPI.GetStatus.SetIBDataBaseErrorMessages([ShowIBMessage]);;
1158     end;
1159 tony 334 Result := FFirebirdAPI;
1160     end;
1161    
1162     function TTestApplication.GetIndexByTestID(aTestID: AnsiString): integer;
1163     begin
1164     try
1165     Result := FTests.IndexOf(aTestID);
1166     except
1167     raise Exception.CreateFmt('Invalid Test ID - %s',[aTestID]);
1168     end;
1169     if Result = -1 then
1170     raise Exception. CreateFmt('Invalid Test ID - %s',[aTestID]);
1171     end;
1172    
1173     constructor TTestApplication.Create(AOwner: TComponent);
1174     var i: integer;
1175     begin
1176     inherited Create(AOwner);
1177     TestApp := self;
1178     CreateTestList;
1179     FNewDatabaseName := GetTempDir + 'fbtestsuite.fdb';
1180     FSecondNewDatabaseName := GetTempDir + 'fbtestsuite2.fdb';
1181     FUserName := 'SYSDBA';
1182     FPassword := 'masterkey';
1183     FEmployeeDatabaseName := 'employee';
1184     FBackupFileName := GetTempDir + 'testbackup.gbk';
1185     FServer := 'localhost';
1186     for i := 0 to FTests.Count - 1 do
1187     begin
1188     TTestBase(FTests.Objects[i]).SetOwner(self);
1189     // TTestBase(FTests.Objects[i]).CreateObjects(self);
1190     end;
1191     end;
1192    
1193     destructor TTestApplication.Destroy;
1194     begin
1195     DestroyTestList;
1196     TestApp := nil;
1197     inherited Destroy;
1198     end;
1199    
1200     function TTestApplication.GetUserName: AnsiString;
1201     begin
1202     Result := FUserName;
1203     end;
1204    
1205     function TTestApplication.GetPassword: AnsiString;
1206     begin
1207     Result := FPassword;
1208     end;
1209    
1210     function TTestApplication.GetEmployeeDatabaseName: AnsiString;
1211     begin
1212     if FirebirdAPI.GetClientMajor < 3 then
1213     Result := MakeConnectString(FServer, FEmployeeDatabaseName, TCP,FPortNo)
1214     else
1215     Result := MakeConnectString(FServer, FEmployeeDatabaseName, inet,FPortNo);
1216     end;
1217    
1218     function TTestApplication.GetNewDatabaseName: AnsiString;
1219     begin
1220     if FirebirdAPI.GetClientMajor < 3 then
1221     Result := MakeConnectString(FServer, FNewDatabaseName, TCP,FPortNo)
1222     else
1223     Result := MakeConnectString(FServer, FNewDatabaseName, inet,FPortNo);
1224     end;
1225    
1226 tony 351 function TTestApplication.GetTempDatabaseName: AnsiString;
1227     begin
1228     Result := GetTempDir + 'fbtest.fbd';
1229     end;
1230    
1231 tony 334 function TTestApplication.GetSecondNewDatabaseName: AnsiString;
1232     begin
1233     if FirebirdAPI.GetClientMajor < 3 then
1234     Result := MakeConnectString(FServer, FSecondNewDatabaseName, TCP,FPortNo)
1235     else
1236     Result := MakeConnectString(FServer, FSecondNewDatabaseName, inet,FPortNo);
1237     end;
1238    
1239     function TTestApplication.GetBackupFileName: AnsiString;
1240     begin
1241     Result := FBackupFileName;
1242     end;
1243    
1244     procedure TTestApplication.RunAll;
1245     var i: integer;
1246     begin
1247     CleanUp;
1248     for i := 0 to FTests.Count - 1 do
1249     begin
1250     DoTest(i);
1251     if not Quiet then
1252     writeln(Outfile,'------------------------------------------------------');
1253 tony 351 Sleep(500);
1254 tony 334 end;
1255     end;
1256    
1257     procedure TTestApplication.RunTest(TestID: AnsiString);
1258     begin
1259     CleanUp;
1260     DoTest(GetIndexByTestID(TestID));
1261     end;
1262    
1263     procedure TTestApplication.SetClientLibraryPath(aLibName: string);
1264     var i: integer;
1265     begin
1266     FFirebirdAPI := LoadFBLibrary(aLibName).GetFirebirdAPI;
1267     FClientLibraryPath := aLibName;
1268     for i := 0 to FTests.Count - 1 do
1269     TTestBase(FTests.Objects[i]).ClientLibraryPathChanged;
1270    
1271     end;
1272    
1273     procedure TTestApplication.SetUserName(aValue: AnsiString);
1274     begin
1275     FUserName := aValue;
1276     end;
1277    
1278     procedure TTestApplication.SetPassword(aValue: AnsiString);
1279     begin
1280     FPassword := aValue;
1281     end;
1282    
1283     procedure TTestApplication.SetEmployeeDatabaseName(aValue: AnsiString);
1284     begin
1285     FEmployeeDatabaseName := aValue;
1286     end;
1287    
1288     procedure TTestApplication.SetNewDatabaseName(aValue: AnsiString);
1289     begin
1290     FNewDatabaseName := aValue;
1291     end;
1292    
1293     procedure TTestApplication.SetSecondNewDatabaseName(aValue: AnsiString);
1294     begin
1295     FSecondNewDatabaseName := aValue;
1296     end;
1297    
1298     procedure TTestApplication.SetBackupFileName(aValue: AnsiString);
1299     begin
1300     FBackupFileName := aValue;
1301     end;
1302    
1303     procedure TTestApplication.SetServerName(AValue: AnsiString);
1304     begin
1305     if FServer = AValue then Exit;
1306     FServer := AValue;
1307     end;
1308    
1309     procedure TTestApplication.SetPortNum(aValue: AnsiString);
1310     begin
1311     FPortNo := aValue;
1312     end;
1313    
1314     procedure TTestApplication.SetTestOption(aValue: AnsiString);
1315     begin
1316     FTestOption := AValue;
1317     end;
1318    
1319     {$IFDEF FPC}
1320     function TTestApplication.GetShortOptions: AnsiString;
1321     begin
1322     Result := 'htupensbolrSPXOq';
1323     end;
1324    
1325     function TTestApplication.GetLongOptions: AnsiString;
1326     begin
1327     Result := 'help test user passwd employeedb newdbname secondnewdbname backupfile '+
1328     'outfile fbclientlibrary server stats port prompt TestOption quiet';
1329     end;
1330    
1331     procedure TTestApplication.GetParams(var DoPrompt: boolean; var TestID: string);
1332     var ErrorMsg: String;
1333     begin
1334     // quick check parameters
1335     ErrorMsg := CheckOptions(GetShortOptions,GetLongOptions);
1336     if ErrorMsg <> '' then begin
1337     ShowException(Exception.Create(ErrorMsg));
1338     Terminate;
1339     Exit;
1340     end;
1341    
1342     // parse parameters
1343     if HasOption('h', 'help') then begin
1344     WriteHelp;
1345     Terminate;
1346     Exit;
1347     end;
1348    
1349     if HasOption('t') then
1350     TestID := GetOptionValue('t');
1351     if Length(TestID) = 1 then
1352     TestID := '0' + TestID;
1353    
1354     DoPrompt := HasOption('X','prompt');
1355    
1356     if HasOption('u','user') then
1357     SetUserName(GetOptionValue('u'));
1358    
1359     if HasOption('p','passwd') then
1360     SetPassword(GetOptionValue('p'));
1361    
1362     if HasOption('e','employeedb') then
1363     SetEmployeeDatabaseName(GetOptionValue('e'));
1364    
1365     if HasOption('n','newdbname') then
1366     SetNewDatabaseName(GetOptionValue('n'));
1367    
1368     if HasOption('s','secondnewdbname') then
1369     SetSecondNewDatabaseName(GetOptionValue('s'));
1370    
1371     if HasOption('b','backupfile') then
1372     SetBackupFileName(GetOptionValue('b'));
1373    
1374     if HasOption('l','fbclientlibrary') then
1375     SetClientLibraryPath(GetOptionValue('l'));
1376    
1377     if HasOption('r','server') then
1378     SetServerName(GetOptionValue('r'));
1379    
1380     if HasOption('o','outfile') then
1381     begin
1382     system.Assign(outFile,GetOptionValue('o'));
1383     ReWrite(outFile);
1384     end;
1385    
1386     if HasOption('P','port') then
1387     SetPortNum(GetOptionValue('P'));
1388    
1389     ShowStatistics := HasOption('S','stats');
1390    
1391     if HasOption('O','TestOption') then
1392     SetTestOption(GetOptionValue('O'));
1393    
1394     FQuiet := HasOption('q','quiet')
1395     end;
1396     {$ENDIF}
1397    
1398     {$IFDEF DCC}
1399     procedure TTestApplication.GetParams(var DoPrompt: boolean; var TestID: string);
1400    
1401     function GetCmdLineValue(const Switch: string; var aValue: string): boolean;
1402     var i: integer;
1403     begin
1404     aValue := '';
1405     Result := FindCmdLineSwitch(Switch,false);
1406     if Result then
1407     begin
1408     for i := 0 to ParamCount do
1409     if (ParamStr(i) = '-' + Switch) and (i <= ParamCount) then
1410     begin
1411     aValue := ParamStr(i+1);
1412     exit;
1413     end;
1414     Result := false;
1415     end;
1416     end;
1417    
1418     var aValue: string;
1419    
1420     begin
1421     // parse parameters
1422     if FindCmdLineSwitch('h') or FindCmdLineSwitch('help') then
1423     begin
1424     WriteHelp;
1425     Exit;
1426     end;
1427    
1428     if GetCmdLineValue('t',aValue) then
1429     TestID := aValue;
1430    
1431     DoPrompt := GetCmdLineValue('X',aValue);
1432    
1433     if GetCmdLineValue('u',aValue) or GetCmdLineValue('user',aValue) then
1434     SetUserName(aValue);
1435    
1436     if GetCmdLineValue('p',aValue) or GetCmdLineValue('passwd',aValue) then
1437     SetPassword(aValue);
1438    
1439     if GetCmdLineValue('e',aValue) or GetCmdLineValue('employeedb',aValue) then
1440     SetEmployeeDatabaseName(aValue);
1441    
1442     if GetCmdLineValue('n',aValue) or GetCmdLineValue('newdbname',aValue) then
1443     SetNewDatabaseName(aValue);
1444    
1445     if GetCmdLineValue('s',aValue) or GetCmdLineValue('secondnewdbname',aValue) then
1446     SetSecondNewDatabaseName(aValue);
1447    
1448     if GetCmdLineValue('b',aValue) or GetCmdLineValue('backupfile',aValue) then
1449     SetBackupFileName(aValue);
1450    
1451     if GetCmdLineValue('r',aValue) or GetCmdLineValue('server',aValue) then
1452     SetServerName(aValue);
1453    
1454     if GetCmdLineValue('P',aValue) or GetCmdLineValue('port',aValue) then
1455     SetPortNum(aValue);
1456    
1457     if GetCmdLineValue('l',aValue) or GetCmdLineValue('fbclientlibrary',aValue) then
1458     SetClientLibraryPath(aValue);
1459    
1460     if GetCmdLineValue('o',aValue) or GetCmdLineValue('outfile',aValue) then
1461     begin
1462     system.Assign(outFile,aValue);
1463     ReWrite(outFile);
1464     end;
1465    
1466     ShowStatistics := FindCmdLineSwitch('S',false) or FindCmdLineSwitch('stats');
1467    
1468     if GetCmdLineValue('O',aValue) or GetCmdLineValue('TestOption',aValue) then
1469     SetTestOption(aValue);
1470    
1471     FQuiet := FindCmdLineSwitch('q',false) or FindCmdLineSwitch('quiet');
1472     end;
1473     {$ENDIF}
1474    
1475     procedure TTestApplication.DoRun;
1476     var
1477     DoPrompt: boolean;
1478     TestID: string;
1479     MasterProvider: IFBIMasterProvider;
1480     begin
1481     {$IFDEF FPC}
1482     OutFile := stdout;
1483     {$ELSE}
1484     AssignFile(OutFile,'');
1485     ReWrite(outFile);
1486     {$ENDIF}
1487    
1488     GetParams(DoPrompt,TestID);
1489     if length(TestID) = 1 then
1490     TestID := '0' + TestID;
1491     {$IF declared(SetTextCodePage)}
1492     {Ensure consistent UTF-8 output}
1493     SetTextCodePage(OutFile,cp_utf8);
1494     {$IFEND}
1495     {$IF declared(SetConsoleOutputCP)}
1496     SetConsoleOutputCP(cp_utf8);
1497     {$IFEND}
1498    
1499    
1500     {Ensure consistent date reporting across platforms}
1501     SetFormatSettings;
1502    
1503     if not Quiet then
1504     begin
1505     writeln(OutFile,Title);
1506     writeln(OutFile,Copyright);
1507     writeln(OutFile);
1508     writeln(OutFile,'Starting Tests');
1509     writeln(OutFile,'Client API Version = ',FirebirdAPI.GetImplementationVersion);
1510     writeln(OutFile,'Firebird Environment Variable = ',sysutils.GetEnvironmentVariable('FIREBIRD'));
1511     if FirebirdAPI.HasMasterIntf and (FirebirdAPI.QueryInterface(IFBIMasterProvider,MasterProvider) = S_OK) then
1512     with MasterProvider.GetIMasterIntf.getConfigManager do
1513     begin
1514     writeln(OutFile,'Firebird Bin Directory = ', getDirectory(DIR_BIN));
1515     writeln(OutFile,'Firebird Conf Directory = ', getDirectory(DIR_CONF));
1516     end;
1517     writeln(OutFile,'Firebird Client Library Path = ',FirebirdAPI.GetFBLibrary.GetLibraryFilePath);
1518     end;
1519    
1520     try
1521     if TestID = '' then
1522     RunAll
1523     else
1524     RunTest(TestID);
1525 tony 351 CleanUp;
1526 tony 334 except on E: Exception do
1527     begin
1528     writeln('Exception: ',E.Message);
1529     writeln(OutFile,'Exception: ',E.Message);
1530     end;
1531     end;
1532    
1533     writeln(OutFile,'Test Suite Ends');
1534     Flush(OutFile);
1535     {$IFDEF WINDOWS}
1536     if DoPrompt then
1537     begin
1538     write('Press Entry to continue');
1539     readln; {when running from IDE and console window closes before you can view results}
1540     end;
1541     {$ENDIF}
1542    
1543     // stop program loop
1544     Terminate;
1545     end;
1546    
1547     procedure TTestApplication.DoTest(index: integer);
1548     begin
1549     if FTests.Objects[index] = nil then Exit;
1550     try
1551     with TTestBase(FTests.Objects[index]) do
1552     if SkipTest then
1553     writeln(OutFile,' Skipping ' + TestID)
1554     else
1555     begin
1556     if not Quiet then
1557     writeln(OutFile,'Running ' + TestTitle);
1558     if not ChildProcess then
1559     writeln(ErrOutput,'Running ' + TestTitle);
1560     try
1561     CreateObjects(self);
1562     InitTest;
1563     RunTest('UTF8',3);
1564     ProcessResults;
1565     except
1566     on E:ESkipException do
1567     writeln(OutFile,'Skipping Test: ' + E.Message);
1568     on E:Exception do
1569     begin
1570     writeln(OutFile,'Test Completed with Error: ' + E.Message);
1571     Exit;
1572     end;
1573     end;
1574     if not Quiet then
1575     begin
1576     writeln(OutFile);
1577     writeln(OutFile);
1578     end;
1579     end;
1580     finally
1581     FTests.Objects[index].Free;
1582     FTests.Objects[index] := nil;
1583     DestroyComponents;
1584     end;
1585     end;
1586    
1587     procedure TTestApplication.SetFormatSettings;
1588     begin
1589     {$IF declared(DefaultFormatSettings)}
1590     with DefaultFormatSettings do
1591     {$ELSE}
1592     {$IF declared(FormatSettings)}
1593     with FormatSettings do
1594     {$IFEND}{$IFEND}
1595     begin
1596     ShortDateFormat := 'dd/m/yyyy';
1597     LongTimeFormat := 'HH:MM:SS';
1598     DateSeparator := '/';
1599     end;
1600     end;
1601    
1602     procedure TTestApplication.WriteHelp;
1603     begin
1604     { add your help code here }
1605     writeln(OutFile,'Usage: ', ExeName, ' -h');
1606     end;
1607    
1608     {$IFNDEF FPC}
1609     function TCustomApplication.Exename: string;
1610     begin
1611     Result := ParamStr(0);
1612     end;
1613    
1614     procedure TCustomApplication.Run;
1615     begin
1616     try
1617     DoRun;
1618     except on E: Exception do
1619     writeln(OutFile,E.Message);
1620     end;
1621     end;
1622    
1623     procedure TCustomApplication.Terminate;
1624     begin
1625    
1626     end;
1627     {$ENDIF}
1628    
1629     end.
1630