codetools+tests: function to fix xml attribute values

git-svn-id: trunk@32634 -
This commit is contained in:
mattias 2011-10-02 23:18:22 +00:00
parent b758561187
commit 10329ea87b
5 changed files with 94 additions and 60 deletions

View File

@ -33,12 +33,16 @@ interface
uses uses
Classes, SysUtils, FileProcs, contnrs, BasicCodeTools; Classes, SysUtils, FileProcs, contnrs, BasicCodeTools;
type
PObjectList = ^TObjectList;
procedure FixFPDocFragment(var Fragment: string; procedure FixFPDocFragment(var Fragment: string;
AllowTags, // for attribute values set this to false, so that all < are converted AllowTags, // for attribute values set this to false, so that all < are converted
Fix: boolean; // fix errors using heuristics creating valid xml Fix: boolean; // fix errors using heuristics creating valid xml
out ErrorList: TObjectList; ErrorList: PObjectList = nil;
Verbose: boolean = false // write debugln to stdout Verbose: boolean = false // write debugln to stdout
); );
procedure FixFPDocAttributeValue(var Value: string);
implementation implementation
@ -51,7 +55,7 @@ type
end; end;
procedure FixFPDocFragment(var Fragment: string; AllowTags, Fix: boolean; procedure FixFPDocFragment(var Fragment: string; AllowTags, Fix: boolean;
out ErrorList: TObjectList; Verbose: boolean); ErrorList: PObjectList; Verbose: boolean);
{ - Fix all tags to lowercase to reduce svn commits { - Fix all tags to lowercase to reduce svn commits
- auto close comments - auto close comments
- remove #0 from comments - remove #0 from comments
@ -105,12 +109,13 @@ var
copy(Fragment,Rel(ErrorPos),LineEnd-Rel(ErrorPos)+1)]); copy(Fragment,Rel(ErrorPos),LineEnd-Rel(ErrorPos)+1)]);
end; end;
if not Fix then exit; if not Fix then exit;
if ErrorList=nil then if ErrorList=nil then exit;
ErrorList:=TObjectList.Create(true); if ErrorList^=nil then
ErrorList^:=TObjectList.Create(true);
NewError:=TFPDocFragmentError.Create; NewError:=TFPDocFragmentError.Create;
NewError.ErrorPos:=Rel(ErrorPos); NewError.ErrorPos:=Rel(ErrorPos);
NewError.Msg:=ErrorMsg; NewError.Msg:=ErrorMsg;
ErrorList.Add(NewError); ErrorList^.Add(NewError);
end; end;
procedure Replace(StartPos, Len: integer; const NewTxt: string); procedure Replace(StartPos, Len: integer; const NewTxt: string);
@ -486,7 +491,6 @@ var
end; end;
begin begin
ErrorList:=nil;
if Fragment='' then exit; if Fragment='' then exit;
Top:=-1; Top:=-1;
TopItem:=nil; TopItem:=nil;
@ -514,6 +518,9 @@ begin
HandleSpecialChar; HandleSpecialChar;
'&': '&':
ParseAmpersand; ParseAmpersand;
'"','''':
if not AllowTags then
HandleSpecialChar;
else else
inc(p); inc(p);
end; end;
@ -530,5 +537,10 @@ begin
end; end;
end; end;
procedure FixFPDocAttributeValue(var Value: string);
begin
FixFPDocFragment(Value,false,true);
end;
end. end.

View File

@ -44,7 +44,7 @@ uses
// codetools // codetools
CodeAtom, CodeTree, CodeToolManager, FindDeclarationTool, BasicCodeTools, CodeAtom, CodeTree, CodeToolManager, FindDeclarationTool, BasicCodeTools,
KeywordFuncLists, PascalParserTool, CodeCache, CacheCodeTools, CustomCodeTool, KeywordFuncLists, PascalParserTool, CodeCache, CacheCodeTools, CustomCodeTool,
FileProcs, FileProcs, CTXMLFixFragment,
{$IFNDEF OldXMLCfg} {$IFNDEF OldXMLCfg}
Laz2_DOM, Laz2_XMLRead, Laz2_XMLWrite, Laz2_DOM, Laz2_XMLRead, Laz2_XMLWrite,
{$ELSE} {$ELSE}
@ -1889,6 +1889,7 @@ begin
CodeNode:=CodeNode.Parent; CodeNode:=CodeNode.Parent;
end; end;
end; end;
//FixFPDocAttributeValue(Result);
end; end;
function TCodeHelpManager.GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode; function TCodeHelpManager.GetFPDocNode(Tool: TCodeTool; CodeNode: TCodeTreeNode;

View File

@ -1270,29 +1270,23 @@ var
function SetValue(Item: TFPDocItem): boolean; function SetValue(Item: TFPDocItem): boolean;
var var
NewValue: String; NewValue: String;
ErrorList: TObjectList;
begin begin
Result:=false; Result:=false;
NewValue:=Values[Item]; NewValue:=Values[Item];
ErrorList:=nil;
try try
try FixFPDocFragment(NewValue,
FixFPDocFragment(NewValue, Item in [fpdiShort,fpdiDescription,fpdiErrors,fpdiSeeAlso],
Item in [fpdiShort,fpdiDescription,fpdiErrors,fpdiSeeAlso], true);
true,ErrorList); CurDocFile.SetChildValue(TopNode,FPDocItemNames[Item],NewValue);
CurDocFile.SetChildValue(TopNode,FPDocItemNames[Item],NewValue); Result:=true;
Result:=true; except
except on E: EXMLReadError do begin
on E: EXMLReadError do begin DebugLn(['SetValue ',dbgs(E.LineCol),' Name=',FPDocItemNames[Item]]);
DebugLn(['SetValue ',dbgs(E.LineCol),' Name=',FPDocItemNames[Item]]); JumpToError(Item,E.LineCol);
JumpToError(Item,E.LineCol); MessageDlg(lisFPDocFPDocSyntaxError,
MessageDlg(lisFPDocFPDocSyntaxError, Format(lisFPDocThereIsASyntaxErrorInTheFpdocElement, [FPDocItemNames
Format(lisFPDocThereIsASyntaxErrorInTheFpdocElement, [FPDocItemNames [Item], #13#13, E.Message]), mtError, [mbOk], '');
[Item], #13#13, E.Message]), mtError, [mbOk], '');
end;
end; end;
finally
FreeAndNil(ErrorList);
end; end;
end; end;

View File

@ -4,6 +4,7 @@
Test individually: Test individually:
./runtests --format=plain --suite=TestFixXMLFragmentComment ./runtests --format=plain --suite=TestFixXMLFragmentComment
./runtests --format=plain --suite=TestFixXMLValue
} }
unit TestCTXMLFixFragments; unit TestCTXMLFixFragments;
@ -12,7 +13,7 @@ unit TestCTXMLFixFragments;
interface interface
uses uses
fpcunit, Classes, SysUtils, FileProcs, contnrs, testglobals, CTXMLFixFragment; fpcunit, Classes, SysUtils, FileProcs, testglobals, CTXMLFixFragment;
type type
@ -20,7 +21,8 @@ type
TTestCTXMLFixFragment = class(TTestCase) TTestCTXMLFixFragment = class(TTestCase)
protected protected
function Test(Title, Fragment, FixedFragment: string): boolean; function TestFrag(Title, Fragment, FixedFragment: string): boolean;
function TestAttr(Title, Value, FixedValue: string): boolean;
published published
procedure TestFixXMLFragmentComment; procedure TestFixXMLFragmentComment;
procedure TestFixXMLFragmentInvalidCharacters; procedure TestFixXMLFragmentInvalidCharacters;
@ -28,76 +30,95 @@ type
procedure TestFixXMLFragmentAttribute; procedure TestFixXMLFragmentAttribute;
procedure TestFixXMLFragmentCloseTag; procedure TestFixXMLFragmentCloseTag;
procedure TestFixXMLFragmentBugReports; procedure TestFixXMLFragmentBugReports;
// attribute value
procedure TestFixXMLValue;
end; end;
implementation implementation
{ TTestCTXMLFixFragment } { TTestCTXMLFixFragment }
function TTestCTXMLFixFragment.Test(Title, Fragment, FixedFragment: string function TTestCTXMLFixFragment.TestFrag(Title, Fragment, FixedFragment: string
): boolean; ): boolean;
var var
s: String; s: String;
ErrorList: TObjectList;
begin begin
Result:=true; Result:=true;
try s:=Fragment;
s:=Fragment; FixFPDocFragment(s,true,true,nil,false);
FixFPDocFragment(s,true,true,ErrorList,false); AssertEquals(Title+' fragment: '+DbgStr(Fragment),dbgstr(FixedFragment),dbgstr(s));
AssertEquals(Title+' fragment: '+DbgStr(Fragment),dbgstr(FixedFragment),dbgstr(s)); end;
finally
ErrorList.Free; function TTestCTXMLFixFragment.TestAttr(Title, Value, FixedValue: string
end; ): boolean;
var
s: String;
begin
Result:=true;
s:=Value;
FixFPDocAttributeValue(s);
AssertEquals(Title+' value: '+DbgStr(Value),dbgstr(FixedValue),dbgstr(s));
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentComment; procedure TTestCTXMLFixFragment.TestFixXMLFragmentComment;
begin begin
Test('close comment','<!--','<!---->'); TestFrag('close comment','<!--','<!---->');
Test('close comment and delete invalid char','<!--null'#0#1#2'comment','<!--nullcomment-->'); TestFrag('close comment and delete invalid char','<!--null'#0#1#2'comment','<!--nullcomment-->');
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentInvalidCharacters; procedure TTestCTXMLFixFragment.TestFixXMLFragmentInvalidCharacters;
begin begin
Test('delete special characters','A'#0'B'#1#127,'AB'); TestFrag('delete special characters','A'#0'B'#1#127,'AB');
Test('replace tag characters','LT< GT>AMP&','LT&lt; GT&gt;AMP&amp;'); TestFrag('replace tag characters','LT< GT>AMP&','LT&lt; GT&gt;AMP&amp;');
Test('lower case special characters','&LT;','&lt;'); TestFrag('lower case special characters','&LT;','&lt;');
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentOpenTag; procedure TTestCTXMLFixFragment.TestFixXMLFragmentOpenTag;
begin begin
Test('valid short tag','<link/>','<link/>'); TestFrag('valid short tag','<link/>','<link/>');
Test('valid short with empty attribute tag','<link id=""/>','<link id=""/>'); TestFrag('valid short with empty attribute tag','<link id=""/>','<link id=""/>');
Test('missing tag name','<>','&lt;&gt;'); TestFrag('missing tag name','<>','&lt;&gt;');
Test('lower case tag name','<A></a>','<a></a>'); TestFrag('lower case tag name','<A></a>','<a></a>');
Test('invalid character in tag','<a "></a>','<a >"&gt;</a>'); TestFrag('invalid character in tag','<a "></a>','<a >"&gt;</a>');
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentAttribute; procedure TTestCTXMLFixFragment.TestFixXMLFragmentAttribute;
begin begin
Test('lower case attribute name','<a Name=""></a>','<a name=""></a>'); TestFrag('lower case attribute name','<a Name=""></a>','<a name=""></a>');
Test('missing attribute equal','<a name ""></a>','<a name =""></a>'); TestFrag('missing attribute equal','<a name ""></a>','<a name =""></a>');
Test('missing attribute value','<a name=></a>','<a name=""></a>'); TestFrag('missing attribute value','<a name=></a>','<a name=""></a>');
Test('missing attribute quotes','<a name=1></a>','<a name="1"></a>'); TestFrag('missing attribute quotes','<a name=1></a>','<a name="1"></a>');
Test('missing attribute ending quote','<a name="1></a>','<a name="1"></a>'); TestFrag('missing attribute ending quote','<a name="1></a>','<a name="1"></a>');
Test('invalid character in attribute value','<a name="&"></a>','<a name="&amp;"></a>'); TestFrag('invalid character in xml fragment attribute value','<a name="&"></a>','<a name="&amp;"></a>');
Test('amp attribute value','<a name="&amp;"></a>','<a name="&amp;"></a>'); TestFrag('amp attribute value','<a name="&amp;"></a>','<a name="&amp;"></a>');
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentCloseTag; procedure TTestCTXMLFixFragment.TestFixXMLFragmentCloseTag;
begin begin
Test('lower case close tag name','<a></A>','<a></a>'); TestFrag('lower case close tag name','<a></A>','<a></a>');
Test('close open tag','<a>','<a/>'); TestFrag('close open tag','<a>','<a/>');
Test('close open sub tag','<p><a></p>','<p><a/></p>'); TestFrag('close open sub tag','<p><a></p>','<p><a/></p>');
Test('disable invalid close tag','</p>','&lt;/p&gt;'); TestFrag('disable invalid close tag','</p>','&lt;/p&gt;');
end; end;
procedure TTestCTXMLFixFragment.TestFixXMLFragmentBugReports; procedure TTestCTXMLFixFragment.TestFixXMLFragmentBugReports;
begin begin
Test('15120','operator <(TPoint, TPoint): Boolean', TestFrag('15120','operator <(TPoint, TPoint): Boolean',
'operator &lt;(TPoint, TPoint): Boolean'); 'operator &lt;(TPoint, TPoint): Boolean');
Test('16671','<br>', TestFrag('16671','<br>',
'<br/>'); '<br/>');
Test('18800','<link id="foo"/>','<link id="foo"/>'); TestFrag('18800','<link id="foo"/>','<link id="foo"/>');
end;
procedure TTestCTXMLFixFragment.TestFixXMLValue;
begin
TestAttr('invalid character in xml attribute value','operator<','operator&lt;');
TestAttr('correct character in xml attribute value','&amp;','&amp;');
TestAttr('lower case character name in attribute value','&AMP;','&amp;');
TestAttr('" in attribute value','"','&quot;');
TestAttr(''' in attribute value','''','&apos;');
TestAttr('< in attribute value','<','&lt;');
TestAttr('> in attribute value','>','&gt;');
end; end;
initialization initialization

View File

@ -129,6 +129,12 @@
<StackChecks Value="True"/> <StackChecks Value="True"/>
</Checks> </Checks>
</CodeGeneration> </CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="True"/>
<DebugInfoType Value="dsAuto"/>
</Debugging>
</Linking>
<Other> <Other>
<CompilerMessages> <CompilerMessages>
<UseMsgFile Value="True"/> <UseMsgFile Value="True"/>