unit uFltrTst;

interface
uses
{$IFDEF WIN32}
  Windows,
  Forms,
{$ENDIF}
{$IFDEF LINUX}
  QForms,
{$ENDIF}

  TestFramework,
  SysUtils,
  Classes;

type
  TXpFilterTests = class(TTestCase)
    protected
      ES : TMemoryStream; {Stream with a couple bytes of data to be used
                           in testing InCharFilter w/ no data}
      OS : TMemoryStream; {Empty stream used with testing OutCharFilter}
      procedure Setup; override;
      procedure Teardown; override;
    published
      { InCharFilter }
      procedure TestInCreateBufferSize;
      procedure TestInFormatDetection;
      procedure TestInFormatChanging;
      procedure TestInReadChar;
      procedure TestInTryRead;
      procedure TestInLinePosProperty;
      procedure TestInLineTermination;
      procedure TestInIgnoreUTFDeterminingBytes;
      procedure TestInExceptions;
      procedure TestTryReadAfterReadChar;

      { OutCharFilter}
      procedure TestOutCreateBufferSize;
      procedure TestOutFormatChanging;
      procedure TestOutUTF16DeterminingBytes;
  end;


implementation
uses
  XpChrFlt,
  xpexcept,
  xpbase;
{ TXpFilterTests }

procedure TXpFilterTests.Setup;
begin
  inherited;

   ES := TMemoryStream.Create;
   ES.Write('xx', 2);

   OS := TMemoryStream.Create;
end;

procedure TXpFilterTests.Teardown;
begin
  ES.Free;
  ES := nil;

  OS.Free;
  OS := nil;

  inherited;
end;

procedure TXpFilterTests.TestInCreateBufferSize;
var
  XF : TXpInCharFilter;
begin
  XF := TXpInCharFilter.Create(ES, 1024);
  XF.FreeStream := False;
  try
    Assert(XF.BufSize = 1024);
  finally
    XF.Free;
  end;

  XF := TXpInCharFilter.Create(ES, 2048);
  XF.FreeStream := False;
  try
    Assert(XF.BufSize = 2048);
  finally
    XF.Free;
  end;

  XF := TXpInCharFilter.Create(ES, 4096);
  XF.FreeStream := False;
  try
    Assert(XF.BufSize = 4096);
  finally
    XF.Free;
  end;
end;

procedure TXpFilterTests.TestInExceptions;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutChar(#8, #0, BothUsed);
  finally
    OutF.Free;
  end;

  Os.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  Inf.FreeStream := False;
  try
    try
      InF.ReadandSkipChar;
      Assert(False);
    except
      on Ex : EXpFilterError do
        if not (Ex.Reason = sInvalidXMLChar) then
          raise;
    end;
  finally
    Inf.Free;
  end;

end;

procedure TXpFilterTests.TestInFormatChanging;
var
  XF : TXpInCharFilter;
begin
  XF := TXpInCharFilter.Create(ES, 1024);
  XF.FreeStream := False;
  try
    Assert(XF.Format = sfUTF8, 'Pretest Unexpected format: ' + intToStr(Ord(XF.Format)));
    XF.Format := sfUTF8;
    Assert(XF.Format = sfUTF8, 'Unexpected format: ' + intToStr(Ord(XF.Format)));

    XF.Format := sfISO88591;
    Assert(XF.Format = sfISO88591);

    XF.Format := sfUTF16LE;
    Assert(XF.Format = sfUTF16LE);

    {Onece in a UTF16 format, the format cannot be changed}
    XF.Format := sfUTF16BE;
    Assert(XF.Format <> sfUTF16BE);
  finally
    XF.Free;
  end;

  XF := TXpInCharFilter.Create(ES, 1024);
  XF.FreeStream := False;
  try
    XF.Format := sfUTF8;
    Assert(XF.Format = sfUTF8);

    XF.Format := sfISO88591;
    Assert(XF.Format = sfISO88591);

    XF.Format := sfUTF16BE;
    Assert(XF.Format = sfUTF16BE);

    {Onece in a UTF16 format, the format cannot be changed}
    XF.Format := sfUTF16LE;
    Assert(XF.Format <> sfUTF16LE);
  finally
    XF.Free;
  end;

end;

procedure TXpFilterTests.TestInFormatDetection;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    Assert(OutF.Format = sfUTF8);
    OutF.PutChar('A', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.TryRead([Ord('A')]));
  finally
    InF.Free;
  end;

  TearDown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16LE;
    Assert(OutF.Format = sfUTF16LE);
    OutF.PutChar('A', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
    Assert(InF.TryRead([Ord('A')]));
  finally
    InF.Free;
  end;

  TearDown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16BE;
    Assert(OutF.Format = sfUTF16BE);
    OutF.PutChar('A', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;
  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16BE);
    Assert(InF.TryRead([Ord('A')]));
  finally
    InF.Free;
  end;
end;

procedure TXpFilterTests.TestInIgnoreUTFDeterminingBytes;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16LE;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Inf.ReadandSkipChar;
    Assert(Inf.IsEOF);
  finally
    InF.Free;
  end;
end;

procedure TXpFilterTests.TestInLinePosProperty;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar('E', #0, BothUsed);
    OutF.PutChar('F', #0, BothUsed);
    OutF.PutChar('G', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.LinePos = 1);
    Inf.ReadChar;
    Assert(Inf.LinePos = 1);
    Inf.ReadandSkipChar;
    Assert(Inf.LinePos = 2);
    Inf.ReadandSkipChar;
    Assert(Inf.LinePos = 3);
    Inf.TryRead([Ord('~')]);
    Assert(Inf.LinePos = 3);
    Inf.TryRead([Ord('C')]);
    Assert(Inf.LinePos = 4);
  finally
    InF.Free;
  end;
end;

procedure TXpFilterTests.TestInLineTermination;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar(#10, #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
  finally
    OutF.Free;
  end;
  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.TryRead([65, 66, 67, 68, 10,65, 66, 67, 68, 10, 68]));
  finally
    Inf.Free;
  end;

  OS.Position := 0;
  Inf := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'D');
  finally
    Inf.Free;
  end;

  Teardown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16LE;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar(#10, #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
    Assert(InF.TryRead([65, 66, 67, 68, 10,65, 66, 67, 68, 10, 68]));
  finally
    Inf.Free;
  end;

  OS.Position := 0;
  Inf := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'D');
  finally
    Inf.Free;
  end;

  Teardown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16BE;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar(#10, #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
    OutF.PutChar(#13, #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16BE);
    Assert(InF.TryRead([65, 66, 67, 68, 10,65, 66, 67, 68, 10, 68]));
  finally
    Inf.Free;
  end;

  OS.Position := 0;

  Inf := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16BE);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadandSkipChar = 'D');
    Assert(InF.ReadChar = #10);
    Assert(InF.ReadandSkipChar = #10);
    Assert(InF.ReadandSkipChar = 'D');
  finally
    Inf.Free;
  end;
end;

procedure TXpFilterTests.TestInReadChar;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('C', #0, BothUsed);
    OutF.PutChar('D', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.ReadChar = 'A');
    Assert(InF.ReadChar = 'A');
    Assert(InF.ReadChar = 'A');
    Assert(InF.ReadandSkipChar = 'A');
    Assert(InF.ReadandSkipChar = 'B');
    Assert(InF.ReadandSkipChar = 'C');
    Assert(InF.ReadChar = 'D');
    Assert(InF.ReadChar = 'D');
    Assert(InF.ReadChar = 'D');
    Assert(InF.ReadChar = 'D');
  finally
    InF.Free;
  end;
end;

procedure TXpFilterTests.TestInTryRead;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
  finally
    Inf.Free;
  end;

  TearDown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16LE;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
  finally
    Inf.Free;
  end;

  TearDown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16BE;
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('A', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
    OutF.PutChar('B', #0, BothUsed);
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16BE);
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('B')]));
    Assert(InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
    Assert(not InF.TryRead([Ord('A')]));
    Assert(InF.TryRead([Ord('B')]));
  finally
    Inf.Free;
  end;
end;

procedure TXpFilterTests.TestOutCreateBufferSize;
var
  XO : TXpOutCharFilter;
begin
  XO := TXpOutCharFilter.Create(OS, 1024);
  XO.FreeStream := False;
  try
    Assert(XO.BufSize = 1024);
  finally
    XO.Free;
  end;

  XO := TXpOutCharFilter.Create(OS, 2048);
  XO.FreeStream := False;
  try
    Assert(XO.BufSize = 2048);
  finally
    XO.Free;
  end;

  XO := TXpOutCharFilter.Create(OS, 4096);
  XO.FreeStream := False;
  try
    Assert(XO.BufSize = 4096);
  finally
    XO.Free;
  end;
end;

procedure TXpFilterTests.TestOutFormatChanging;
var
  XO : TXpOutCharFilter;
  BothUsed : Boolean;
begin
  XO := TXpOutCharFilter.Create(OS, 1024);
  XO.FreeStream := False;
  try
    XO.Format := sfUTF8;
    Assert(XO.Format = sfUTF8);

    XO.Format := sfUTF16LE;
    Assert(XO.Format = sfUTF16LE);

    XO.Format := sfUTF16BE;
    Assert(XO.Format = sfUTF16BE);

    XO.Format := sfISO88591;
    Assert(XO.Format = sfISO88591);

    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);

    {Once we have written data, we should no longer be able to change the format}
    XO.Format := sfUTF8;
    Assert(XO.Format <> sfUTF8);

    XO.Format := sfUTF16LE;
    Assert(XO.Format <> sfUTF16LE);

    XO.Format := sfUTF16BE;
    Assert(XO.Format <> sfUTF16BE);

  finally
    XO.Free;
  end;
  
  Teardown;
  Setup;

  XO := TXpOutCharFilter.Create(OS, 1024);
  XO.FreeStream := False;
  try
    XO.Format := sfUTF8;
    Assert(XO.Format = sfUTF8);

    XO.Format := sfUTF16LE;
    Assert(XO.Format = sfUTF16LE);

    XO.Format := sfISO88591;
    Assert(XO.Format = sfISO88591);

    XO.Format := sfUTF16BE;
    Assert(XO.Format = sfUTF16BE);


    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);
    XO.PutChar('X', #0, BothUsed);

    {Once we have written data, we should no longer be able to change the format}
    XO.Format := sfUTF8;
    Assert(XO.Format <> sfUTF8);

    XO.Format := sfUTF16LE;
    Assert(XO.Format <> sfUTF16LE);

    XO.Format := sfISO88591;
    Assert(XO.Format <> sfISO88591);

  finally
    XO.Free;
  end;

end;

procedure TXpFilterTests.TestOutUTF16DeterminingBytes;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
begin
  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16LE;
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16LE);
  finally
    InF.Free;
  end;

  Teardown;
  Setup;

  OutF := TXpOutCharFilter.Create(OS, 1024);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF16BE;
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 1024);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF16BE);
  finally
    InF.Free;
  end;
end;

procedure TXpFilterTests.TestTryReadAfterReadChar;
var
  InF : TXpInCharFilter;
  OutF : TXpOutCharFilter;
  WS : WideString;
begin
  { This test should verify that TryRead works as expected after ReadChar is
    called. Should be tested two ways, ReadChar(UpdatePos = False) and
    ReadChar(UpdatePos = True);

    The reverse should also be tested.}

  {Check that the character sequences work }
  OutF := TXpOutCharFilter.Create(OS, 2048);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('D'));
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 2048);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    WS := InF.ReadChar;
    Assert(WS[1]='A');
    WS := InF.ReadChar;
    Assert(WS[1]='A');
    WS := InF.ReadChar;
    Assert(WS[1]='A');
    Assert(not Inf.TryRead([Ord('B')]));
    WS := InF.ReadChar;
    Assert(WS[1]='A');
    Assert(InF.TryRead([Ord('A')]));
    Assert(not InF.TryRead([Ord('C')]));
    Assert(not InF.TryRead([Ord('C')]));
    Assert(InF.TryRead([Ord('B')]));
    WS := InF.ReadChar;
    Assert(WS[1]='C');
    WS := InF.ReadandSkipChar;
    Assert(WS[1]='C');
    WS := InF.ReadandSkipChar;
    Assert(WS[1]='D');
  finally
    InF.Free;
  end;

  TearDown;
  Setup;

  {Make sure that blocks of text work}
  OutF := TXpOutCharFilter.Create(OS, 2048);
  OutF.FreeStream := False;
  try
    OutF.Format := sfUTF8;
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('A'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('B'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('C'));
    OutF.PutUCS4Char(Ord('D'));
    OutF.PutUCS4Char(Ord('D'));
    OutF.PutUCS4Char(Ord('D'));
    OutF.PutUCS4Char(Ord('D'));
    OutF.PutUCS4Char(Ord('D'));
  finally
    OutF.Free;
  end;

  OS.Position := 0;

  InF := TXpInCharFilter.Create(OS, 2048);
  InF.FreeStream := False;
  try
    Assert(InF.Format = sfUTF8);
    Assert(InF.TryRead([Ord('A'),Ord('A'),Ord('A'),Ord('A'),Ord('A')]));
    Assert(not InF.TryRead([Ord('C'),Ord('C'),Ord('C'),Ord('C'),Ord('C')]));
    Assert(InF.TryRead([Ord('B'),Ord('B'),Ord('B'),Ord('B'),Ord('B')]));
    Assert(not InF.TryRead([Ord('D'),Ord('D'),Ord('D'),Ord('D'),Ord('D')]));
    Assert(InF.TryRead([Ord('C'),Ord('C'),Ord('C'),Ord('C'),Ord('C')]));
    Assert(not InF.TryRead([Ord('A'),Ord('A'),Ord('A'),Ord('A'),Ord('A')]));
    Assert(InF.TryRead([Ord('D'),Ord('D'),Ord('D'),Ord('D'),Ord('D')]));
  finally
    InF.Free;
  end;
end;

initialization
  RegisterTest('Filter Tests', TXpFilterTests);
end.
