unit uXSLFOTest;

interface
uses
  TestFramework,
  SysUtils,
  Classes,
  Windows,
  XpParser,
  XpDOM,
  XpBase,
  XpvXSLPr,
  XpvFlBas,
  XpvFlXML,
{$IFDEF LINUX}
  uProgress,
{$ELSE}
  uProgressW,
{$ENDIF}
  Forms;


type
  TXpXSLFOTests = class(TTestCase)
    protected
      function CompareStreams(aOldSt,
                              aNewSt : TMemoryStream;
                              aCount : Integer) : Boolean;
        { Compares the specified number of bytes in both streams, starting at
          position zero in both streams. Returns True if the streams are
          equivalent. }
      procedure TestFilter(const aSourcePath,
                                 aCheckPath,
                                 aLogPath    : string;
                           const aFilter     : TXpFilterBase);
    published
      procedure TestFltXMLFormattedGood;
      procedure TestFltXMLNonFormattedGood;
      procedure TestFltHTMLBody;
      procedure TestFltHTMLFull;
      procedure TestFltHTMLCSSBodyNonFormatted;
      procedure TestFltHTMLFormattedFragmentNoCss;
      procedure TestFltHTMLNoCSSFullNonFormatted;
      procedure TestFltRTF;
  end;

implementation
uses
  XpChrFlt,
  XpvFlHTM,
  XpvFlRTF,
  XpExcept;

{=====================================================================}
procedure TXpXSLFOTests.TestFltXMLNonFormattedGood;
var
  XMLFilter : TXpFilterXML;
begin
  XMLFilter := TXpFilterXML.Create(Application.MainForm);
  try
    XMLFilter.OutputEncoding := ceISO88591;

    { Test with nonformatted output.}
      XMLFilter.FormattedOutput := False;
      TestFilter('..\Data\XSLFO\',
                 '..\Data\XSLFO\XMLFilter\NonFormatted\',
                 '..\Data\XSLFO\XMLFilter\NonFormatted\GoodGoneBad.Txt',
                 XMLFilter);
  finally
    XMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltXMLFormattedGood;
var
  XMLFilter : TXpFilterXML;
begin
  XMLFilter := TXpFilterXML.Create(Application.MainForm);
  try
    XMLFilter.OutputEncoding := ceISO88591;

    { Test with formatted output.}
    XMLFilter.FormattedOutput := True;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\XMLFilter\Formatted\',
               '..\Data\XSLFO\XMLFilter\Formatted\GoodGoneBad.Txt',
               XMLFilter);
  finally
    XMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltHTMLFull;
var
  HTMLFilter : TXpFilterHTML;
begin
  HTMLFilter := TXpFilterHTML.Create(Application.MainForm);
  try
    HTMLFilter.OutputMode := xphomFull;
    HTMLFilter.FormattedOutput := True;
    HTMLFilter.CSS := True;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\HTMLFilter\Full\',
               '..\Data\XSLFO\HTMLFilter\Full\GoodGoneBad.Txt',
               HTMLFilter);
  finally
    HTMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltHTMLCSSBodyNonFormatted;
var
  HTMLFilter : TXpFilterHTML;
begin
  HTMLFilter := TXpFilterHTML.Create(Application.MainForm);
  try
    HTMLFilter.OutputMode := xphomBodyOnly;
    HTMLFilter.FormattedOutput := False;
    HTMLFilter.CSS := True;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\HTMLFilter\CSSBodyNonFormatted\',
               '..\Data\XSLFO\HTMLFilter\CSSBodyNonFormatted\GoodGoneBad.Txt',
               HTMLFilter);
  finally
    HTMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltHTMLFormattedFragmentNoCSS;
var
  HTMLFilter : TXpFilterHTML;
begin
  HTMLFilter := TXpFilterHTML.Create(Application.MainForm);
  try
    HTMLFilter.OutputMode := xphomFragment;
    HTMLFilter.FormattedOutput := True;
    HTMLFilter.CSS := False;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\HTMLFilter\FormattedFragmentNoCSS\',
               '..\Data\XSLFO\HTMLFilter\FormattedFragmentNoCSS\GoodGoneBad.Txt',
               HTMLFilter);
  finally
    HTMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltHTMLNoCSSFullNonFormatted;
var
  HTMLFilter : TXpFilterHTML;
begin
  HTMLFilter := TXpFilterHTML.Create(Application.MainForm);
  try
    HTMLFilter.OutputMode := xphomFull;
    HTMLFilter.FormattedOutput := False;
    HTMLFilter.CSS := False;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\HTMLFilter\NoCSSFullNonFormatted\',
               '..\Data\XSLFO\HTMLFilter\NoCSSFullNonFormatted\GoodGoneBad.Txt',
               HTMLFilter);
  finally
    HTMLFilter.Free;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFltHTMLBody;
var
  HTMLFilter : TXpFilterHTML;
begin
  HTMLFilter := TXpFilterHTML.Create(Application.MainForm);
  try
    HTMLFilter.OutputMode := xphomBodyOnly;
    HTMLFilter.FormattedOutput := False;
    HTMLFilter.CSS := False;
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\HTMLFilter\Body\',
               '..\Data\XSLFO\HTMLFilter\Body\GoodGoneBad.Txt',
               HTMLFilter);
  finally
    HTMLFilter.Free;
  end;
end;
{--------}
function TXpXSLFOTests.CompareStreams(aOldSt,
                                      aNewSt : TMemoryStream;
                                      aCount : Integer) : Boolean;
var
  OldChar, NewChar : Char;
  i : integer;
begin
  aOldSt.Position := 0;
  aNewSt.Position := 0;
  Result := True;
  for i := 0 to pred(aCount) do begin
    aOldSt.Read(OldChar, 1);
    { Skip over #13. }
    if (OldChar = #13) then
      aOldSt.Read(OldChar, 1);
    aNewSt.Read(NewChar, 1);
    { Skip over #13. }
    if (NewChar = #13) then
      aNewSt.Read(NewChar, 1);
    Result := (OldChar = NewChar);
    if (not Result) then
      Break;
  end;
end;
{--------}
procedure TXpXSLFOTests.TestFilter(const aSourcePath,
                                         aCheckPath,
                                         aLogPath    : string;
                                   const aFilter     : TXpFilterBase);
var
  SR              : TSearchRec;
  FindResult      : Boolean;
  DOM             : TXpObjModel;
  ParsedOK        : Boolean;
  FailedTest      : Boolean;
  Log             : TStringList;
  Idx             : Integer;
  FileName,
  MasterFileName  : string;
  FileCount       : Integer;
  Dlg             : TDlgProgress;
  XSLProcessor    : TXpXSLProcessor;
  GeneratedStream,
  MasterStream    : TMemoryStream;
begin
  Log := nil;
  FailedTest := False;
  ParsedOK := True;

  FindResult := FindFirst(aSourcePath + '*.xml', faAnyFile, SR) = 0;
  XSLProcessor := TXpXSLProcessor.Create(Application.MainForm);
  try
    { Set up the XSL processor and filter. }
    XSLProcessor.RaiseErrors := False;
    XSLProcessor.Filter := aFilter;
    Log := TStringList.Create;
    FileCount := 0;
    if FindResult then
      repeat
        inc(FileCount);
      until FindNext(SR) <> 0;
    SysUtils.FindClose(SR);

    Dlg := TDlgProgress.Create(Application.MainForm);
    try
      Dlg.Show;
      Application.ProcessMessages;

      FindResult := FindFirst(aSourcePath + '*.xml', faAnyFile, SR) = 0;
      if (FindResult) then begin
        repeat
          if (AnsiCompareText(ExtractFileExt(Sr.Name), '.xml') = 0) then begin
            {Update progressbar}
            Dlg.FileName := FileName;
            Dlg.Position := Dlg.Position + 1;
            Dlg.Max := FileCount;

            {Verify that XML document is OK}
            DOM := TXpObjModel.Create(nil);
            try
              FileName := aSourcePath + Sr.Name;
              try
                ParsedOK := DOM.LoadDataSource(FileName);
              except
                on E:Exception do
                  ParsedOK := False;
              end;
              { Did the document load successfully?}
              if (ParsedOK) then begin
                { Yes. Look for the corresponding stylesheet. }
                FileName := ChangeFileExt(FileName, '.XSL');
                if (FileExists(FileName)) then begin
                  { Transform the document using the stylesheet. }
                  XSLProcessor.XmlObjModel := DOM;
                  XSLProcessor.StyleURL := FileName;
                  if (XSLProcessor.ApplyStyle) then begin
                    { Find the master output file & compare to generated file. }
                    MasterFileName := aCheckPath + ChangeFileExt(sr.Name, '.Tst');
                    if (FileExists(FileName)) then begin
                      FileName := aCheckPath + ChangeFileExt(sr.Name, '.out');
                      aFilter.SaveToFile(FileName);
                      GeneratedStream := TMemoryStream.Create;
                      GeneratedStream.LoadFromFile(FileName);
                      MasterStream := TMemoryStream.Create;
                      MasterStream.LoadFromFile(MasterFileName);
                      try
                        if (not CompareStreams(MasterStream, GeneratedStream,
                                              GeneratedStream.Size)) then begin
                          FailedTest := True;
                          Log.Add('-----------------------------------------------');
                          Log.Add('  Test failed : ' + FileName);
                          Log.Add('-----------------------------------------------');
                          Log.Add('');
                          Log.SaveToFile(aLogPath);

                          Dlg.AddError('-----------------------------------------------');
                          Dlg.AddError('  Test failed : ' + FileName);
                          Dlg.AddError('-----------------------------------------------');
                          Dlg.AddError('');
                        end;
                      finally
                        GeneratedStream.Free;
                        MasterStream.Free;
                      end;
                    end
                    else begin
                      FailedTest := True;
                      Log.Add('-----------------------------------------------');
                      Log.Add('  Output master not found : ' + MasterFileName);
                      Log.Add('-----------------------------------------------');
                      Log.Add('');
                      Log.SaveToFile(aLogPath);

                      Dlg.AddError('-----------------------------------------------');
                      Dlg.AddError('  Output master not found : ' + MasterFileName);
                      Dlg.AddError('-----------------------------------------------');
                      Dlg.AddError('');
                    end;
                  end
                  else begin
                    FailedTest := True;
                    Log.Add('-----------------------------------------------');
                    Log.Add('  XSL processing failure : ' + FileName);
                    Log.Add('-----------------------------------------------');
                    Log.Add('');
                    Log.SaveToFile(aLogPath);

                    Dlg.AddError('-----------------------------------------------');
                    Dlg.AddError('  XSL processing failure : ' + FileName);
                    Dlg.AddError('-----------------------------------------------');
                    Dlg.AddError('');
                  end;
                end
                else begin
                  FailedTest := True;
                  Log.Add('-----------------------------------------------');
                  Log.Add('  Stylesheet not found : ' + FileName);
                  Log.Add('-----------------------------------------------');
                  Log.Add('');
                  Log.SaveToFile(aLogPath);

                  Dlg.AddError('-----------------------------------------------');
                  Dlg.AddError('  Stylesheet not found : ' + FileName);
                  Dlg.AddError('-----------------------------------------------');
                  Dlg.AddError('');
                end;

              end else begin
                { No. Document failed to load. Log error information. }
                FailedTest := True;
                {Store error messages}
                Log.Add('-----------------------------------------------');
                Log.Add('  Error(s) parsing : ' + FileName);
                Log.Add('');
                for Idx := 0 to Pred(DOM.Errors.Count) do
                  Log.Add(DOM.Errors.Strings[Idx]);
                Log.Add('');
                Log.Add('-----------------------------------------------');
                Log.Add('');
                Log.Add('');
                Log.SaveToFile(aLogPath);

                Dlg.AddError('-----------------------------------------------');
                Dlg.AddError('  Error(s) parsing : ' + FileName);
                Dlg.AddError('');
                for Idx := 0 to Pred(DOM.Errors.Count) do
                  Dlg.AddError(DOM.Errors.Strings[Idx]);
                Dlg.AddError('');
                Dlg.AddError('-----------------------------------------------');
                Dlg.AddError('');
                Dlg.AddError('');
              end
            finally
              DOM.Free;
            end;
          end;
        until FindNext(SR) <> 0;
      end else
        Fail('Good docs not found');
    finally
      Dlg.Hide;
      Dlg.Free;
    end;
  finally
    XSLProcessor.Free;
    Log.Free;
    SysUtils.FindClose(SR);
  end;
  Assert(not FailedTest, 'At least one good doc didn''t parse well. See ' + aLogPath + 'for info');
end;
{=====================================================================}



procedure TXpXSLFOTests.TestFltRTF;
var
  RTFFilter : TXpFilterRTF;
begin
  RTFFilter := TXpFilterRTF.Create(Application.MainForm);
  try
    TestFilter('..\Data\XSLFO\',
               '..\Data\XSLFO\RTFFilter\',
               '..\Data\XSLFO\RTFFilter\GoodGoneBad.Txt',
               RTFFilter);
  finally
    RTFFilter.Free;
  end;
end;

initialization
  RegisterTest('XSLFO Tests', TXpXSLFOTests);
end.
