mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-05 14:39:05 +02:00
codetools: test write string, widestring, unicodestring
git-svn-id: trunk@56147 -
This commit is contained in:
parent
82ea3d79fe
commit
4151bca8e4
@ -4,7 +4,6 @@
|
|||||||
./runtests --format=plain --suite=TTestCompReaderWriterPas.TestWriteProperties
|
./runtests --format=plain --suite=TTestCompReaderWriterPas.TestWriteProperties
|
||||||
|
|
||||||
ToDo:
|
ToDo:
|
||||||
- root properties
|
|
||||||
- base types
|
- base types
|
||||||
- UTF-8 string
|
- UTF-8 string
|
||||||
- unicodestring
|
- unicodestring
|
||||||
@ -31,11 +30,11 @@ unit TestCompReaderWriterPas;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, typinfo, RtlConsts, LazLoggerBase, fpcunit,
|
Classes, SysUtils, typinfo, RtlConsts, LazLoggerBase, LazUTF8, fpcunit,
|
||||||
testregistry, CodeToolManager, LinkScanner, TestStdCodetools;
|
testregistry, CodeToolManager, LinkScanner, TestStdCodetools;
|
||||||
|
|
||||||
const
|
const
|
||||||
CWPDefaultSignature = '// Pascal writer V1.0';
|
CWPDefaultSignature = '// component writer V1.0';
|
||||||
type
|
type
|
||||||
TDummyComp = class(TComponent); // to access TComponent protected members
|
TDummyComp = class(TComponent); // to access TComponent protected members
|
||||||
TCWPFindAncestorEvent = procedure(Sender: TObject; Component: TComponent;
|
TCWPFindAncestorEvent = procedure(Sender: TObject; Component: TComponent;
|
||||||
@ -46,7 +45,7 @@ type
|
|||||||
TCWPOption = (
|
TCWPOption = (
|
||||||
cwpoNoSignature,
|
cwpoNoSignature,
|
||||||
cwpoSetParentFirst, // add "Parent:=" before properties
|
cwpoSetParentFirst, // add "Parent:=" before properties
|
||||||
cwpoWideStringAsUTF8
|
cwpoSrcCodepageUTF8
|
||||||
);
|
);
|
||||||
TCWPOptions = set of TCWPOption;
|
TCWPOptions = set of TCWPOption;
|
||||||
|
|
||||||
@ -79,6 +78,7 @@ type
|
|||||||
procedure WriteProperty(Instance: TPersistent; PropInfo: PPropInfo);
|
procedure WriteProperty(Instance: TPersistent; PropInfo: PPropInfo);
|
||||||
procedure WriteProperties(Instance: TComponent);
|
procedure WriteProperties(Instance: TComponent);
|
||||||
function GetStringLiteral(const s: string): string;
|
function GetStringLiteral(const s: string): string;
|
||||||
|
function GetWStringLiteral(p: PWideChar; Count: integer): string;
|
||||||
function GetFloatLiteral(const e: Extended): string;
|
function GetFloatLiteral(const e: Extended): string;
|
||||||
public
|
public
|
||||||
constructor Create(AStream: TStream);
|
constructor Create(AStream: TStream);
|
||||||
@ -113,8 +113,8 @@ type
|
|||||||
|
|
||||||
// Tests =======================================================================
|
// Tests =======================================================================
|
||||||
const
|
const
|
||||||
MinSafeIntCurrency = -922337203685477;
|
MinSafeIntCurrency = Low(Int64) div 10000;
|
||||||
MaxSafeIntCurrency = 922337203685477;
|
MaxSafeIntCurrency = High(Int64) div 10000;
|
||||||
MinSafeIntSingle = -16777216;
|
MinSafeIntSingle = -16777216;
|
||||||
MaxSafeIntSingle = 16777216;
|
MaxSafeIntSingle = 16777216;
|
||||||
MaskUIntSingle = $3fffff;
|
MaskUIntSingle = $3fffff;
|
||||||
@ -311,17 +311,94 @@ type
|
|||||||
{ TTestCompReaderWriterPas }
|
{ TTestCompReaderWriterPas }
|
||||||
|
|
||||||
TTestCompReaderWriterPas = class(TCustomTestCTStdCodetools)
|
TTestCompReaderWriterPas = class(TCustomTestCTStdCodetools)
|
||||||
|
private
|
||||||
|
FStream: TMemoryStream;
|
||||||
|
FWriter: TCompWriterPas;
|
||||||
protected
|
protected
|
||||||
|
procedure SetUp; override;
|
||||||
|
procedure TearDown; override;
|
||||||
function WriteDescendant(Component: TComponent; Ancestor: TComponent = nil): string;
|
function WriteDescendant(Component: TComponent; Ancestor: TComponent = nil): string;
|
||||||
procedure TestWriteDescendant(Msg: string; Component: TComponent;
|
procedure TestWriteDescendant(Msg: string; Component: TComponent;
|
||||||
Ancestor: TComponent; const Expected: array of string);
|
Ancestor: TComponent; const Expected: array of string);
|
||||||
|
property Writer: TCompWriterPas read FWriter write FWriter;
|
||||||
published
|
published
|
||||||
procedure TestBaseTypesSkipDefaultValue;
|
procedure TestBaseTypesSkipDefaultValue;
|
||||||
|
procedure TestBaseTypesZeroes;
|
||||||
procedure TestBaseTypesMinValues;
|
procedure TestBaseTypesMinValues;
|
||||||
|
procedure TestBaseTypesMaxValues;
|
||||||
|
procedure TestStringASCII;
|
||||||
|
procedure TestStringUTF8;
|
||||||
|
procedure TestWideString_SrcCodePageSystem;
|
||||||
|
procedure TestWideString_SrcCodePageUTF8;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
function IsValidUTF8(p: PChar): integer;
|
||||||
|
var
|
||||||
|
c: Char;
|
||||||
|
begin
|
||||||
|
c:=p^;
|
||||||
|
if ord(c)<%10000000 then begin
|
||||||
|
// regular single byte ASCII character (#0 is a character, this is Pascal ;)
|
||||||
|
Result:=1;
|
||||||
|
end else if ord(c)<=%11000001 then begin
|
||||||
|
// single byte character, between valid UTF-8 encodings
|
||||||
|
// %11000000 and %11000001 map 2 byte to #0..#128, which is invalid and used for XSS attacks
|
||||||
|
Result:=0;
|
||||||
|
end else if ord(c)<=%11011111 then begin
|
||||||
|
// could be 2 byte character (%110xxxxx %10xxxxxx)
|
||||||
|
if ((ord(p[1]) and %11000000) = %10000000) then
|
||||||
|
Result:=2
|
||||||
|
else
|
||||||
|
Result:=0; // missing following bytes
|
||||||
|
end
|
||||||
|
else if ord(c)<=%11101111 then begin
|
||||||
|
// could be 3 byte character (%1110xxxx %10xxxxxx %10xxxxxx)
|
||||||
|
if ((ord(p[1]) and %11000000) = %10000000)
|
||||||
|
and ((ord(p[2]) and %11000000) = %10000000) then begin
|
||||||
|
if (ord(c)=%11100000) and (ord(p[1])<=%10011111) then
|
||||||
|
Result:=0; // XSS attack: 3 bytes are mapped to the 1 or 2 byte codes
|
||||||
|
Result:=3;
|
||||||
|
end else
|
||||||
|
Result:=0; // missing following bytes
|
||||||
|
end
|
||||||
|
else if ord(c)<=%11110111 then begin
|
||||||
|
// could be 4 byte character (%11110xxx %10xxxxxx %10xxxxxx %10xxxxxx)
|
||||||
|
if ((ord(p[1]) and %11000000) = %10000000)
|
||||||
|
and ((ord(p[2]) and %11000000) = %10000000)
|
||||||
|
and ((ord(p[3]) and %11000000) = %10000000) then begin
|
||||||
|
if (ord(c)=%11110000) and (ord(p[1])<=%10001111) then
|
||||||
|
Result:=0; // XSS attack: 4 bytes are mapped to the 1-3 byte codes
|
||||||
|
Result:=4;
|
||||||
|
end else
|
||||||
|
Result:=0; // missing following bytes
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
Result:=0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsValidUTF16(p: PWideChar): integer;
|
||||||
|
var
|
||||||
|
c: WideChar;
|
||||||
|
begin
|
||||||
|
c:=p^;
|
||||||
|
if c<=#$DC7F then
|
||||||
|
exit(1)
|
||||||
|
else if c<=#$DBFF then begin
|
||||||
|
c:=p[1];
|
||||||
|
if (c>=#$DC00) and (c<=#$DFFF) then
|
||||||
|
exit(2)
|
||||||
|
else
|
||||||
|
exit(0);
|
||||||
|
end else if c<=#$Dfff then begin
|
||||||
|
exit(0);
|
||||||
|
end else
|
||||||
|
exit(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
Type
|
Type
|
||||||
|
|
||||||
{ TPosComponent }
|
{ TPosComponent }
|
||||||
@ -332,6 +409,14 @@ Type
|
|||||||
constructor Create(APos: Integer; AComponent: TComponent);
|
constructor Create(APos: Integer; AComponent: TComponent);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TPosComponent }
|
||||||
|
|
||||||
|
constructor TPosComponent.Create(APos: Integer; AComponent: TComponent);
|
||||||
|
begin
|
||||||
|
FPos:=APos;
|
||||||
|
FComponent:=AComponent;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TCompBaseTypesCustomStored }
|
{ TCompBaseTypesCustomStored }
|
||||||
|
|
||||||
function TCompBaseTypesCustomStored.ABooleanIsStored: Boolean;
|
function TCompBaseTypesCustomStored.ABooleanIsStored: Boolean;
|
||||||
@ -469,14 +554,6 @@ begin
|
|||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TPosComponent }
|
|
||||||
|
|
||||||
constructor TPosComponent.Create(APos: Integer; AComponent: TComponent);
|
|
||||||
begin
|
|
||||||
FPos:=APos;
|
|
||||||
FComponent:=AComponent;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TCompWriterPas }
|
{ TCompWriterPas }
|
||||||
|
|
||||||
procedure TCompWriterPas.DetermineAncestor(Component: TComponent);
|
procedure TCompWriterPas.DetermineAncestor(Component: TComponent);
|
||||||
@ -569,6 +646,7 @@ var
|
|||||||
WStrValue, WDefStrValue: WideString;
|
WStrValue, WDefStrValue: WideString;
|
||||||
UStrValue, UDefStrValue: UnicodeString;
|
UStrValue, UDefStrValue: UnicodeString;
|
||||||
VarValue, DefVarValue: tvardata;
|
VarValue, DefVarValue: tvardata;
|
||||||
|
aTypeData: PTypeData;
|
||||||
begin
|
begin
|
||||||
// do not stream properties without getter
|
// do not stream properties without getter
|
||||||
if not Assigned(PropInfo^.GetProc) then
|
if not Assigned(PropInfo^.GetProc) then
|
||||||
@ -612,9 +690,14 @@ begin
|
|||||||
// Integer with a custom identifier
|
// Integer with a custom identifier
|
||||||
// ToDo: check if this is an actual Pascal constant and remember the unit
|
// ToDo: check if this is an actual Pascal constant and remember the unit
|
||||||
WriteAssign(PropName,Ident)
|
WriteAssign(PropName,Ident)
|
||||||
else
|
else begin
|
||||||
// Integer has to be written just as number
|
// Integer has to be written just as number
|
||||||
WriteAssign(PropName,IntToStr(Int32Value));
|
aTypeData:=GetTypeData(PropInfo^.PropType);
|
||||||
|
if aTypeData^.MinValue>=0 then
|
||||||
|
WriteAssign(PropName,IntToStr(longword(Int32Value)))
|
||||||
|
else
|
||||||
|
WriteAssign(PropName,IntToStr(Int32Value));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
tkChar:
|
tkChar:
|
||||||
case Int32Value of
|
case Int32Value of
|
||||||
@ -630,8 +713,8 @@ begin
|
|||||||
0..31,127..255,$D800..$DFFF:
|
0..31,127..255,$D800..$DFFF:
|
||||||
WriteAssign(PropName,'#'+IntToStr(Int32Value));
|
WriteAssign(PropName,'#'+IntToStr(Int32Value));
|
||||||
else
|
else
|
||||||
if cwpoWideStringAsUTF8 in Options then
|
if cwpoSrcCodepageUTF8 in Options then
|
||||||
WriteAssign(PropName,''''+UTF8Encode(WideChar(Int32Value))+'''')
|
WriteAssign(PropName,''''+UTF16ToUTF8(WideChar(Int32Value))+'''')
|
||||||
else
|
else
|
||||||
WriteAssign(PropName,'#'+IntToStr(Int32Value));
|
WriteAssign(PropName,'#'+IntToStr(Int32Value));
|
||||||
end;
|
end;
|
||||||
@ -734,13 +817,8 @@ begin
|
|||||||
else
|
else
|
||||||
WDefStrValue := '';
|
WDefStrValue := '';
|
||||||
|
|
||||||
if WStrValue <> WDefStrValue then begin
|
if WStrValue <> WDefStrValue then
|
||||||
{$IFDEF VerboseCompWriterPas}
|
WriteAssign(PropName,GetWStringLiteral(PWideChar(WStrValue),length(WStrValue)));
|
||||||
System.writeln('TCompWriterPas.WriteProperty Property="',PropName,'" Kind=',PropType^.Kind);
|
|
||||||
raise EWriteError.Create('proptype not supported: '+GetEnumName(TypeInfo(PropType^.Kind),ord(PropType^.Kind)));
|
|
||||||
{$ENDIF}
|
|
||||||
//ToDo: WriteAssign(PropName,GetWStringLiteral(WStrValue));
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
tkUString:
|
tkUString:
|
||||||
begin
|
begin
|
||||||
@ -750,13 +828,8 @@ begin
|
|||||||
else
|
else
|
||||||
SetLength(UDefStrValue, 0);
|
SetLength(UDefStrValue, 0);
|
||||||
|
|
||||||
if UStrValue <> UDefStrValue then begin
|
if UStrValue <> UDefStrValue then
|
||||||
{$IFDEF VerboseCompWriterPas}
|
WriteAssign(PropName,GetWStringLiteral(PWideChar(UStrValue),length(UStrValue)));
|
||||||
System.writeln('TCompWriterPas.WriteProperty Property="',PropName,'" Kind=',PropType^.Kind);
|
|
||||||
raise EWriteError.Create('proptype not supported: '+GetEnumName(TypeInfo(PropType^.Kind),ord(PropType^.Kind)));
|
|
||||||
{$ENDIF}
|
|
||||||
// ToDo: WriteAssign(PropName,GetWStringLiteral(UStrValue));
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
tkVariant:
|
tkVariant:
|
||||||
begin
|
begin
|
||||||
@ -831,42 +904,121 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TCompWriterPas.GetStringLiteral(const s: string): string;
|
function TCompWriterPas.GetStringLiteral(const s: string): string;
|
||||||
const
|
|
||||||
SpecialChars = [#0..#31,#127..#192];
|
function IsSpecialChar(p: PChar): boolean;
|
||||||
|
const
|
||||||
|
SpecialChars = [#0..#31,#127,#255];
|
||||||
|
begin
|
||||||
|
Result:=(p^ in SpecialChars) or (IsValidUTF8(p)=0);
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
i, StartPos: Integer;
|
|
||||||
InLit: Boolean;
|
InLit: Boolean;
|
||||||
|
p, StartP: PChar;
|
||||||
|
c: Char;
|
||||||
begin
|
begin
|
||||||
Result:='';
|
Result:='';
|
||||||
|
if s='' then exit;
|
||||||
InLit:=false;
|
InLit:=false;
|
||||||
i:=1;
|
p:=PChar(s);
|
||||||
while i<=length(s) do begin
|
repeat
|
||||||
if s[i] in SpecialChars then
|
c:=p^;
|
||||||
|
if (c=#0) and (p-PChar(s)=length(s)) then
|
||||||
|
break
|
||||||
|
else if IsSpecialChar(p) then
|
||||||
begin
|
begin
|
||||||
if InLit then begin
|
if InLit then begin
|
||||||
InLit:=false;
|
InLit:=false;
|
||||||
Result:=Result+'''';
|
Result:=Result+'''';
|
||||||
end;
|
end;
|
||||||
Result:=Result+'#'+IntToStr(ord(s[i]));
|
Result:=Result+'#'+IntToStr(ord(c));
|
||||||
inc(i);
|
inc(p);
|
||||||
end else begin
|
end else begin
|
||||||
if not InLit then begin
|
if not InLit then begin
|
||||||
InLit:=true;
|
InLit:=true;
|
||||||
Result:=Result+'''';
|
Result:=Result+'''';
|
||||||
end;
|
end;
|
||||||
if s[i]='''' then begin
|
if c='''' then begin
|
||||||
Result:=Result+'''''';
|
Result:=Result+'''''';
|
||||||
inc(i);
|
inc(p);
|
||||||
end else begin
|
end else begin
|
||||||
StartPos:=i;
|
StartP:=p;
|
||||||
repeat
|
repeat
|
||||||
inc(i);
|
inc(p,IsValidUTF8(p));
|
||||||
until (i>length(s)) or (s[i] in SpecialChars) or (s[i]='''');
|
c:=p^;
|
||||||
// ToDo: source codepage<>UTF-8
|
until ((c=#0) and (p-PChar(s)=length(s))) or IsSpecialChar(p) or (c='''');
|
||||||
Result:=Result+copy(s,StartPos,i-StartPos);
|
Result:=Result+copy(s,StartP-PChar(s)+1,p-StartP);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
until false;
|
||||||
|
if InLit then
|
||||||
|
Result:=Result+'''';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCompWriterPas.GetWStringLiteral(p: PWideChar; Count: integer): string;
|
||||||
|
|
||||||
|
function IsSpecialChar(w: PWideChar): boolean;
|
||||||
|
const
|
||||||
|
SpecialChars = [#0..#31,#127];
|
||||||
|
begin
|
||||||
|
if w^ in SpecialChars then exit(true);
|
||||||
|
if cwpoSrcCodepageUTF8 in FOptions then begin
|
||||||
|
Result:=IsValidUTF16(w)=0;
|
||||||
|
end else begin
|
||||||
|
Result:=w^>=#$7f;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
InLit: Boolean;
|
||||||
|
c: WideChar;
|
||||||
|
FirstP, StartP: PWideChar;
|
||||||
|
AddLen: SizeUInt;
|
||||||
|
s: string;
|
||||||
|
OldLen: Integer;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
if Count=0 then exit;
|
||||||
|
FirstP:=p;
|
||||||
|
InLit:=false;
|
||||||
|
s:='';
|
||||||
|
repeat
|
||||||
|
c:=p^;
|
||||||
|
if (c=#0) and (p-FirstP=Count) then
|
||||||
|
break
|
||||||
|
else if IsSpecialChar(p) then
|
||||||
|
begin
|
||||||
|
if InLit then begin
|
||||||
|
InLit:=false;
|
||||||
|
Result:=Result+'''';
|
||||||
|
end;
|
||||||
|
Result:=Result+'#'+Format('%.4d',[ord(c)]);
|
||||||
|
inc(p);
|
||||||
|
end else begin
|
||||||
|
if not InLit then begin
|
||||||
|
InLit:=true;
|
||||||
|
Result:=Result+'''';
|
||||||
|
end;
|
||||||
|
if c='''' then begin
|
||||||
|
Result:=Result+'''''';
|
||||||
|
inc(p);
|
||||||
|
end else begin
|
||||||
|
StartP:=p;
|
||||||
|
repeat
|
||||||
|
inc(p,IsValidUTF16(p));
|
||||||
|
c:=p^;
|
||||||
|
until ((c=#0) and (p-FirstP=Count)) or IsSpecialChar(p) or (c='''');
|
||||||
|
AddLen:=p-StartP;
|
||||||
|
if length(s)<AddLen*3 then SetLength(s,AddLen*3);
|
||||||
|
if ConvertUTF16ToUTF8(@s[1],length(s),StartP,AddLen,
|
||||||
|
[toInvalidCharError,toUnfinishedCharError],AddLen)=trNoError then
|
||||||
|
dec(AddLen); // omit #0
|
||||||
|
OldLen:=length(Result);
|
||||||
|
SetLength(Result,OldLen+AddLen);
|
||||||
|
System.Move(s[1],Result[OldLen+1],AddLen);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
until false;
|
||||||
if InLit then
|
if InLit then
|
||||||
Result:=Result+'''';
|
Result:=Result+'''';
|
||||||
end;
|
end;
|
||||||
@ -886,14 +1038,20 @@ begin
|
|||||||
while (i<length(s)) and (s[i+1]='0') do
|
while (i<length(s)) and (s[i+1]='0') do
|
||||||
inc(i);
|
inc(i);
|
||||||
if i>p then
|
if i>p then
|
||||||
Delete(s,p+1,i-p);
|
if i=length(s) then
|
||||||
|
Delete(s,p,i-p+1) // delete whole exponent
|
||||||
|
else
|
||||||
|
Delete(s,p+1,i-p);
|
||||||
// remove trailing 0 of base
|
// remove trailing 0 of base
|
||||||
i:=p;
|
i:=p;
|
||||||
while (i>2) and (s[i-1]='0') do
|
while (i>2) and (s[i-1]='0') do
|
||||||
dec(i);
|
dec(i);
|
||||||
if s[i-1] in ['+','-'] then inc(i);
|
if not (s[i-1] in ['0'..'9']) then inc(i);
|
||||||
if i<p then
|
if i<p then
|
||||||
Delete(s,i,p-i);
|
Delete(s,i,p-i);
|
||||||
|
// remove leading space
|
||||||
|
if s[1]=' ' then
|
||||||
|
Delete(s,1,1);
|
||||||
Result:=s;
|
Result:=s;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1035,28 +1193,31 @@ end;
|
|||||||
|
|
||||||
{ TTestCompReaderWriterPas }
|
{ TTestCompReaderWriterPas }
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.SetUp;
|
||||||
|
begin
|
||||||
|
inherited SetUp;
|
||||||
|
FStream:=TMemoryStream.Create;
|
||||||
|
FWriter:=TCompWriterPas.Create(FStream);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TearDown;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FWriter);
|
||||||
|
FreeAndNil(FStream);
|
||||||
|
inherited TearDown;
|
||||||
|
end;
|
||||||
|
|
||||||
function TTestCompReaderWriterPas.WriteDescendant(Component: TComponent;
|
function TTestCompReaderWriterPas.WriteDescendant(Component: TComponent;
|
||||||
Ancestor: TComponent): string;
|
Ancestor: TComponent): string;
|
||||||
var
|
|
||||||
aStream: TMemoryStream;
|
|
||||||
Writer: TCompWriterPas;
|
|
||||||
begin
|
begin
|
||||||
Writer:=nil;
|
Writer.WriteDescendant(Component,Ancestor);
|
||||||
aStream:=TMemoryStream.Create;
|
FStream.Position:=0;
|
||||||
try
|
SetLength(Result,FStream.size);
|
||||||
Writer:=TCompWriterPas.Create(aStream);
|
if Result<>'' then
|
||||||
Writer.WriteDescendant(Component,Ancestor);
|
FStream.Read(Result[1],length(Result));
|
||||||
aStream.Position:=0;
|
{$IFDEF VerboseCompWriterPas}
|
||||||
SetLength(Result,aStream.size);
|
writeln('TTestCompReaderWriterPas.WriteDescendant "',Result,'"');
|
||||||
if Result<>'' then
|
{$ENDIF}
|
||||||
aStream.Read(Result[1],length(Result));
|
|
||||||
{$IFDEF VerboseCompWriterPas}
|
|
||||||
writeln('TTestCompReaderWriterPas.WriteDescendant "',Result,'"');
|
|
||||||
{$ENDIF}
|
|
||||||
finally
|
|
||||||
Writer.Free;
|
|
||||||
aStream.Free;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTestCompReaderWriterPas.TestWriteDescendant(Msg: string;
|
procedure TTestCompReaderWriterPas.TestWriteDescendant(Msg: string;
|
||||||
@ -1086,6 +1247,60 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestBaseTypesZeroes;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypesCustomStored;
|
||||||
|
begin
|
||||||
|
AComponent:=TCompBaseTypesCustomStored.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
AByte:=0;
|
||||||
|
DefAByte:=AByte+1;
|
||||||
|
AShortInt:=0;
|
||||||
|
DefAShortInt:=AShortInt+1;
|
||||||
|
AWord:=0;
|
||||||
|
DefAWord:=AWord+1;
|
||||||
|
ASmallInt:=0;
|
||||||
|
DefASmallInt:=ASmallInt+1;
|
||||||
|
ALongWord:=0;
|
||||||
|
DefALongWord:=ALongWord+1;
|
||||||
|
ALongInt:=0;
|
||||||
|
DefALongInt:=ALongInt+1;
|
||||||
|
AQWord:=0;
|
||||||
|
DefAQWord:=AQWord+1;
|
||||||
|
AInt64:=0;
|
||||||
|
DefAInt64:=AInt64+1;
|
||||||
|
ACurrency:=0;
|
||||||
|
DefACurrency:=ACurrency+1;
|
||||||
|
ASingle:=0;
|
||||||
|
DefASingle:=ASingle+1;
|
||||||
|
ADouble:=0;
|
||||||
|
DefADouble:=ADouble+1;
|
||||||
|
AChar:=#0;
|
||||||
|
DefAChar:=succ(AChar);
|
||||||
|
AWideChar:=#0;
|
||||||
|
DefAWideChar:=succ(AWideChar);
|
||||||
|
// ToDo: extended
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestBaseTypesZeroes',AComponent,nil,[
|
||||||
|
'AByte:=0;',
|
||||||
|
'AShortInt:=0;',
|
||||||
|
'AWord:=0;',
|
||||||
|
'ASmallInt:=0;',
|
||||||
|
'ALongWord:=0;',
|
||||||
|
'ALongInt:=0;',
|
||||||
|
'ACurrency:= 0.0;',
|
||||||
|
'ASingle:= 0.0;',
|
||||||
|
'ADouble:= 0.0;',
|
||||||
|
'AChar:=#0;',
|
||||||
|
'AWideChar:=#0;',
|
||||||
|
'']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestCompReaderWriterPas.TestBaseTypesMinValues;
|
procedure TTestCompReaderWriterPas.TestBaseTypesMinValues;
|
||||||
var
|
var
|
||||||
AComponent: TCompBaseTypesCustomStored;
|
AComponent: TCompBaseTypesCustomStored;
|
||||||
@ -1093,40 +1308,44 @@ begin
|
|||||||
AComponent:=TCompBaseTypesCustomStored.Create(nil);
|
AComponent:=TCompBaseTypesCustomStored.Create(nil);
|
||||||
try
|
try
|
||||||
with AComponent do begin
|
with AComponent do begin
|
||||||
Name:=AComponent.ClassName+'1';
|
Name:=AComponent.ClassName+'1';
|
||||||
ABoolean:=low(boolean);
|
ABoolean:=low(boolean);
|
||||||
DefABoolean:=not ABoolean;
|
DefABoolean:=not ABoolean;
|
||||||
AByteBool:=boolean(low(byte));
|
AByteBool:=boolean(low(byte));
|
||||||
DefAByteBool:=not AByteBool;
|
DefAByteBool:=not AByteBool;
|
||||||
AWordBool:=boolean(low(word));
|
AWordBool:=boolean(low(word));
|
||||||
DefAWordBool:=not AWordBool;
|
DefAWordBool:=not AWordBool;
|
||||||
ALongBool:=boolean(low(longword));
|
ALongBool:=boolean(low(longword));
|
||||||
DefALongBool:=not ALongBool;
|
DefALongBool:=not ALongBool;
|
||||||
AByte:=low(byte);
|
AByte:=low(byte);
|
||||||
DefAByte:=AByte+1;
|
DefAByte:=AByte+1;
|
||||||
AShortInt:=low(ShortInt);
|
AShortInt:=low(ShortInt);
|
||||||
DefAShortInt:=AShortInt+1;
|
DefAShortInt:=AShortInt+1;
|
||||||
AWord:=low(word);
|
AWord:=low(word);
|
||||||
DefAWord:=AWord+1;
|
DefAWord:=AWord+1;
|
||||||
ASmallInt:=low(SmallInt);
|
ASmallInt:=low(SmallInt);
|
||||||
DefASmallInt:=ASmallInt+1;
|
DefASmallInt:=ASmallInt+1;
|
||||||
ALongWord:=low(LongWord);
|
ALongWord:=low(LongWord);
|
||||||
DefALongWord:=ALongWord+1;
|
DefALongWord:=ALongWord+1;
|
||||||
ALongInt:=low(LongInt);
|
ALongInt:=low(LongInt);
|
||||||
DefALongInt:=ALongInt+1;
|
DefALongInt:=ALongInt+1;
|
||||||
AQWord:=low(qword);
|
AQWord:=low(qword);
|
||||||
DefAQWord:=AQWord+1;
|
DefAQWord:=AQWord+1;
|
||||||
AInt64:=low(Int64);
|
AInt64:=low(Int64);
|
||||||
DefAInt64:=AInt64+1;
|
DefAInt64:=AInt64+1;
|
||||||
ACurrency:=MinSafeIntCurrency;
|
ACurrency:=MinSafeIntCurrency;
|
||||||
DefACurrency:=ACurrency+1;
|
DefACurrency:=ACurrency+1;
|
||||||
ASingle:=MinSafeIntSingle;
|
ASingle:=MinSafeIntSingle;
|
||||||
DefASingle:=ASingle+1;
|
DefASingle:=ASingle+1;
|
||||||
ADouble:=MinSafeIntDouble;
|
ADouble:=MinSafeIntDouble;
|
||||||
DefADouble:=ADouble+1;
|
DefADouble:=ADouble+1;
|
||||||
// ToDo: extended
|
AChar:=low(char);
|
||||||
|
DefAChar:=succ(AChar);
|
||||||
|
AWideChar:=low(WideChar);
|
||||||
|
DefAWideChar:=succ(AWideChar);
|
||||||
|
// ToDo: extended
|
||||||
end;
|
end;
|
||||||
TestWriteDescendant('TestBaseTypesSkipDefaultValue',AComponent,nil,[
|
TestWriteDescendant('TestBaseTypesMinValues',AComponent,nil,[
|
||||||
'ABoolean:=False;',
|
'ABoolean:=False;',
|
||||||
'AByteBool:=False;',
|
'AByteBool:=False;',
|
||||||
'AWordBool:=False;',
|
'AWordBool:=False;',
|
||||||
@ -1141,6 +1360,154 @@ begin
|
|||||||
'ACurrency:=-9.22337203685477E14;',
|
'ACurrency:=-9.22337203685477E14;',
|
||||||
'ASingle:=-1.6777216E7;',
|
'ASingle:=-1.6777216E7;',
|
||||||
'ADouble:=-4.503599627370496E15;',
|
'ADouble:=-4.503599627370496E15;',
|
||||||
|
'AChar:=#0;',
|
||||||
|
'AWideChar:=#0;',
|
||||||
|
'']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestBaseTypesMaxValues;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypesCustomStored;
|
||||||
|
begin
|
||||||
|
AComponent:=TCompBaseTypesCustomStored.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
ABoolean:=high(boolean);
|
||||||
|
DefABoolean:=not ABoolean;
|
||||||
|
AByteBool:=boolean(high(byte));
|
||||||
|
DefAByteBool:=not AByteBool;
|
||||||
|
AWordBool:=boolean(high(word));
|
||||||
|
DefAWordBool:=not AWordBool;
|
||||||
|
ALongBool:=boolean(high(longword));
|
||||||
|
DefALongBool:=not ALongBool;
|
||||||
|
AByte:=high(byte);
|
||||||
|
DefAByte:=AByte-1;
|
||||||
|
AShortInt:=high(ShortInt);
|
||||||
|
DefAShortInt:=AShortInt-1;
|
||||||
|
AWord:=high(word);
|
||||||
|
DefAWord:=AWord-1;
|
||||||
|
ASmallInt:=high(SmallInt);
|
||||||
|
DefASmallInt:=ASmallInt-1;
|
||||||
|
ALongWord:=high(LongWord);
|
||||||
|
DefALongWord:=ALongWord-1;
|
||||||
|
ALongInt:=high(LongInt);
|
||||||
|
DefALongInt:=ALongInt-1;
|
||||||
|
AQWord:=high(qword);
|
||||||
|
DefAQWord:=AQWord-1;
|
||||||
|
AInt64:=high(Int64);
|
||||||
|
DefAInt64:=AInt64-1;
|
||||||
|
ACurrency:=MaxSafeIntCurrency;
|
||||||
|
DefACurrency:=ACurrency-1;
|
||||||
|
ASingle:=MaxSafeIntSingle;
|
||||||
|
DefASingle:=ASingle-1;
|
||||||
|
ADouble:=MaxSafeIntDouble;
|
||||||
|
DefADouble:=ADouble-1;
|
||||||
|
AChar:=high(char);
|
||||||
|
DefAChar:=pred(AChar);
|
||||||
|
AWideChar:=high(WideChar);
|
||||||
|
DefAWideChar:=pred(AWideChar);
|
||||||
|
// ToDo: extended
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestBaseTypesMaxValues',AComponent,nil,[
|
||||||
|
'ABoolean:=True;',
|
||||||
|
'AByteBool:=True;',
|
||||||
|
'AWordBool:=True;',
|
||||||
|
'ALongBool:=True;',
|
||||||
|
'AByte:=255;',
|
||||||
|
'AShortInt:=127;',
|
||||||
|
'AWord:=65535;',
|
||||||
|
'ASmallInt:=32767;',
|
||||||
|
'ALongWord:=4294967295;',
|
||||||
|
'ALongInt:=2147483647;',
|
||||||
|
'AQWord:=18446744073709551615;',
|
||||||
|
'AInt64:=9223372036854775807;',
|
||||||
|
'ACurrency:=9.22337203685477E14;',
|
||||||
|
'ASingle:=1.6777216E7;',
|
||||||
|
'ADouble:=4.503599627370495E15;',
|
||||||
|
'AChar:=#255;',
|
||||||
|
'AWideChar:=#65535;',
|
||||||
|
'']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestStringASCII;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypes;
|
||||||
|
begin
|
||||||
|
AComponent:=TCompBaseTypes.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
AString:=#9'A'#13#10;
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestStringASCII',AComponent,nil,[
|
||||||
|
'AString:=#9''A''#13#10;']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestStringUTF8;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypes;
|
||||||
|
begin
|
||||||
|
AComponent:=TCompBaseTypes.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
AString:='äöü';
|
||||||
|
AShortString:='äöü';
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestStringUTF8',AComponent,nil,[
|
||||||
|
'AString:=''äöü'';',
|
||||||
|
'AShortString:=''äöü'';',
|
||||||
|
'']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestWideString_SrcCodePageSystem;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypes;
|
||||||
|
begin
|
||||||
|
AComponent:=TCompBaseTypes.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
AWideString:=UTF8ToUTF16('äAöü');
|
||||||
|
AUnicodeString:=UTF8ToUTF16('äöBCü');
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestWideString_SrcCodePageSystem',AComponent,nil,[
|
||||||
|
'AWideString:=#0228''A''#0246#0252;',
|
||||||
|
'AUnicodeString:=#0228#0246''BC''#0252;',
|
||||||
|
'']);
|
||||||
|
finally
|
||||||
|
AComponent.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestCompReaderWriterPas.TestWideString_SrcCodePageUTF8;
|
||||||
|
var
|
||||||
|
AComponent: TCompBaseTypes;
|
||||||
|
begin
|
||||||
|
Writer.Options:=Writer.Options+[cwpoSrcCodepageUTF8];
|
||||||
|
AComponent:=TCompBaseTypes.Create(nil);
|
||||||
|
try
|
||||||
|
with AComponent do begin
|
||||||
|
Name:=AComponent.ClassName+'1';
|
||||||
|
AWideString:=UTF8ToUTF16('äöü');
|
||||||
|
AUnicodeString:=UTF8ToUTF16('äöü');
|
||||||
|
end;
|
||||||
|
TestWriteDescendant('TestWideString_SrcCodePageUTF8',AComponent,nil,[
|
||||||
|
'AWideString:=''äöü'';',
|
||||||
|
'AUnicodeString:=''äöü'';',
|
||||||
'']);
|
'']);
|
||||||
finally
|
finally
|
||||||
AComponent.Free;
|
AComponent.Free;
|
||||||
|
Loading…
Reference in New Issue
Block a user