THRIFT-5789 Refactor test suite client implementation
Client: Delphi
Patch: Jens Geyer
diff --git a/lib/delphi/test/testsuite/client/UnitTests.pas b/lib/delphi/test/testsuite/client/UnitTests.pas
new file mode 100644
index 0000000..3726c87
--- /dev/null
+++ b/lib/delphi/test/testsuite/client/UnitTests.pas
@@ -0,0 +1,350 @@
+(*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *)
+
+unit UnitTests;
+
+{$I ../src/Thrift.Defines.inc}
+
+interface
+
+uses
+ Classes, Windows, SysUtils, Math, ActiveX, ComObj,
+ {$IFDEF SupportsAsync} System.Threading, {$ENDIF}
+ DateUtils,
+ Generics.Collections,
+ TestConstants,
+ TestLogger,
+ ConsoleHelper,
+ Thrift,
+ Thrift.Protocol.Compact,
+ Thrift.Protocol.JSON,
+ Thrift.Protocol,
+ Thrift.Transport.Pipes,
+ Thrift.Transport.WinHTTP,
+ Thrift.Transport.MsxmlHTTP,
+ Thrift.Transport,
+ Thrift.Stream,
+ Thrift.Test,
+ Thrift.WinHTTP,
+ Thrift.Utils,
+ Thrift.Configuration,
+ Thrift.Collections;
+
+type
+ TQuickUnitTests = class sealed
+ strict private
+ FLogger : ITestLogger;
+
+ strict protected
+ // Helper
+ procedure StartTestGroup( const aGroup : string; const aTest : TClientTestGroup); inline;
+ procedure Expect( aTestResult : Boolean; const aTestInfo : string); inline;
+
+ // Test impl
+ procedure JSONProtocolReadWriteTest;
+ procedure HashSetTest;
+ {$IFDEF Win64}
+ procedure UseInterlockedExchangeAdd64;
+ {$ENDIF}
+
+ // main execution part
+ constructor Create( const logger : ITestLogger); reintroduce;
+ procedure Execute; overload;
+ public
+ destructor Destroy; override;
+
+ class procedure Execute( const logger : ITestLogger); overload; static;
+ end;
+
+
+implementation
+
+
+constructor TQuickUnitTests.Create( const logger : ITestLogger);
+begin
+ inherited Create;
+ FLogger := logger;
+end;
+
+
+destructor TQuickUnitTests.Destroy;
+begin
+ try
+ FLogger := nil; //-> Release
+ finally
+ inherited Destroy;
+ end;
+end;
+
+
+class procedure TQuickUnitTests.Execute( const logger : ITestLogger);
+var instance : TQuickUnitTests;
+begin
+ instance := TQuickUnitTests.Create(logger);
+ try
+ instance.Execute;
+ finally
+ instance.Free;
+ end;
+end;
+
+
+procedure TQuickUnitTests.Execute;
+begin
+ {$IFDEF Win64}
+ UseInterlockedExchangeAdd64;
+ {$ENDIF}
+
+ JSONProtocolReadWriteTest;
+ HashSetTest;
+end;
+
+
+procedure TQuickUnitTests.StartTestGroup( const aGroup : string; const aTest : TClientTestGroup);
+begin
+ FLogger.StartTestGroup( aGroup, aTest);
+end;
+
+
+procedure TQuickUnitTests.Expect( aTestResult : Boolean; const aTestInfo : string);
+begin
+ FLogger.Expect( aTestResult, aTestInfo);
+end;
+
+
+{$IFDEF Win64}
+procedure TQuickUnitTests.UseInterlockedExchangeAdd64;
+var a,b : Int64;
+begin
+ a := 1;
+ b := 2;
+ Thrift.Utils.InterlockedExchangeAdd64( a,b);
+ Expect( a = 3, 'InterlockedExchangeAdd64');
+end;
+{$ENDIF}
+
+
+procedure TQuickUnitTests.JSONProtocolReadWriteTest;
+// Tests only then read/write procedures of the JSON protocol
+// All tests succeed, if we can read what we wrote before
+// Note that passing this test does not imply, that our JSON is really compatible to what
+// other clients or servers expect as the real JSON. This is beyond the scope of this test.
+var prot : IProtocol;
+ stm : TStringStream;
+ list : TThriftList;
+ config : IThriftConfiguration;
+ binary, binRead, emptyBinary : TBytes;
+ i,iErr : Integer;
+const
+ TEST_SHORT = ShortInt( $FE);
+ TEST_SMALL = SmallInt( $FEDC);
+ TEST_LONG = LongInt( $FEDCBA98);
+ TEST_I64 = Int64( $FEDCBA9876543210);
+ TEST_DOUBLE = -1.234e-56;
+ DELTA_DOUBLE = TEST_DOUBLE * 1e-14;
+ TEST_STRING = 'abc-'#$00E4#$00f6#$00fc; // german umlauts (en-us: "funny chars")
+ // Test THRIFT-2336 and THRIFT-3404 with U+1D11E (G Clef symbol) and 'Русское Название';
+ G_CLEF_AND_CYRILLIC_TEXT = #$1d11e' '#$0420#$0443#$0441#$0441#$043a#$043e#$0435' '#$041d#$0430#$0437#$0432#$0430#$043d#$0438#$0435;
+ G_CLEF_AND_CYRILLIC_JSON = '"\ud834\udd1e \u0420\u0443\u0441\u0441\u043a\u043e\u0435 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435"';
+ // test both possible solidus encodings
+ SOLIDUS_JSON_DATA = '"one/two\/three"';
+ SOLIDUS_EXCPECTED = 'one/two/three';
+begin
+ stm := TStringStream.Create;
+ try
+ FLogger.StartTestGroup( 'JsonProtocolTest', test_Unknown);
+
+ config := TThriftConfigurationImpl.Create;
+
+ // prepare binary data
+ binary := PrepareBinaryData( FALSE, TTestSize.Normal);
+ SetLength( emptyBinary, 0); // empty binary data block
+
+ // output setup
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ nil, TThriftStreamAdapterDelphi.Create( stm, FALSE), config));
+
+ // write
+ Init( list, TType.String_, 9);
+ prot.WriteListBegin( list);
+ prot.WriteBool( TRUE);
+ prot.WriteBool( FALSE);
+ prot.WriteByte( TEST_SHORT);
+ prot.WriteI16( TEST_SMALL);
+ prot.WriteI32( TEST_LONG);
+ prot.WriteI64( TEST_I64);
+ prot.WriteDouble( TEST_DOUBLE);
+ prot.WriteString( TEST_STRING);
+ prot.WriteBinary( binary);
+ prot.WriteString( ''); // empty string
+ prot.WriteBinary( emptyBinary); // empty binary data block
+ prot.WriteListEnd;
+
+ // input setup
+ Expect( stm.Position = stm.Size, 'Stream position/length after write');
+ stm.Position := 0;
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
+
+ // read and compare
+ list := prot.ReadListBegin;
+ Expect( list.ElementType = TType.String_, 'list element type');
+ Expect( list.Count = 9, 'list element count');
+ Expect( prot.ReadBool, 'WriteBool/ReadBool: TRUE');
+ Expect( not prot.ReadBool, 'WriteBool/ReadBool: FALSE');
+ Expect( prot.ReadByte = TEST_SHORT, 'WriteByte/ReadByte');
+ Expect( prot.ReadI16 = TEST_SMALL, 'WriteI16/ReadI16');
+ Expect( prot.ReadI32 = TEST_LONG, 'WriteI32/ReadI32');
+ Expect( prot.ReadI64 = TEST_I64, 'WriteI64/ReadI64');
+ Expect( abs(prot.ReadDouble-TEST_DOUBLE) < abs(DELTA_DOUBLE), 'WriteDouble/ReadDouble');
+ Expect( prot.ReadString = TEST_STRING, 'WriteString/ReadString');
+ binRead := prot.ReadBinary;
+ Expect( Length(prot.ReadString) = 0, 'WriteString/ReadString (empty string)');
+ Expect( Length(prot.ReadBinary) = 0, 'empty WriteBinary/ReadBinary (empty data block)');
+ prot.ReadListEnd;
+
+ // test binary data
+ Expect( Length(binary) = Length(binRead), 'Binary data length check');
+ iErr := -1;
+ for i := Low(binary) to High(binary) do begin
+ if binary[i] <> binRead[i] then begin
+ iErr := i;
+ Break;
+ end;
+ end;
+ if iErr < 0
+ then Expect( TRUE, 'Binary data check ('+IntToStr(Length(binary))+' Bytes)')
+ else Expect( FALSE, 'Binary data check at offset '+IntToStr(iErr));
+
+ Expect( stm.Position = stm.Size, 'Stream position after read');
+
+
+ // Solidus can be encoded in two ways. Make sure we can read both
+ stm.Position := 0;
+ stm.Size := 0;
+ stm.WriteString(SOLIDUS_JSON_DATA);
+ stm.Position := 0;
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
+ Expect( prot.ReadString = SOLIDUS_EXCPECTED, 'Solidus encoding');
+
+
+ // Widechars should work too. Do they?
+ // After writing, we ensure that we are able to read it back
+ // We can't assume hex-encoding, since (nearly) any Unicode char is valid JSON
+ stm.Position := 0;
+ stm.Size := 0;
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ nil, TThriftStreamAdapterDelphi.Create( stm, FALSE), config));
+ prot.WriteString( G_CLEF_AND_CYRILLIC_TEXT);
+ stm.Position := 0;
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
+ FLogger.Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Writing JSON with chars > 8 bit');
+
+ // Widechars should work with hex-encoding too. Do they?
+ stm.Position := 0;
+ stm.Size := 0;
+ stm.WriteString( G_CLEF_AND_CYRILLIC_JSON);
+ stm.Position := 0;
+ prot := TJSONProtocolImpl.Create(
+ TStreamTransportImpl.Create(
+ TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
+ FLogger.Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Reading JSON with chars > 8 bit');
+
+
+ finally
+ stm.Free;
+ prot := nil; //-> Release
+ FLogger.StartTestGroup( '', test_Unknown); // no more tests here
+ end;
+end;
+
+
+procedure TQuickUnitTests.HashSetTest;
+var container : IThriftHashSet<Integer>;
+ testdata : array of Integer;
+ i : Integer;
+const
+ TEST_COUNT = 4096;
+begin
+ StartTestGroup( 'IThriftHashSet<T> implementation', test_Containers);
+
+ // prepare test data
+ SetLength( testdata, 5);
+ testdata[0] := -2;
+ testdata[1] := 0;
+ testdata[2] := 42;
+ testdata[3] := MaxInt;
+ testdata[4] := Low(Integer);
+
+ // first insert
+ container := TThriftHashSetImpl<Integer>.Create;
+ for i in testdata do begin
+ Expect( container.Add( i), 'add first '+IntToStr(i));
+ Expect( container.Contains( i), 'contains '+IntToStr(i));
+ end;
+ Expect( container.Count = Length(testdata), 'container size');
+
+ // insert again
+ for i in testdata do begin
+ Expect( not container.Add( i), 'add second '+IntToStr(i));
+ Expect( container.Contains( i), 'contains '+IntToStr(i));
+ end;
+ Expect( container.Count = Length(testdata), 'container size');
+
+ // remove
+ for i in testdata do begin
+ Expect( container.Remove( i), 'first remove '+IntToStr(i));
+ Expect( not container.Contains( i), 'not contains '+IntToStr(i));
+ end;
+ Expect( container.Count = 0, 'container size');
+
+ // remove again
+ for i in testdata do begin
+ Expect( not container.Remove( i), 'second remove '+IntToStr(i));
+ Expect( not container.Contains( i), 'not contains '+IntToStr(i));
+ end;
+ Expect( container.Count = 0, 'container size');
+
+ // append and clear
+ for i := 0 to TEST_COUNT-1 do begin
+ container.Add(-i);
+ container.Add(+i);
+ end;
+ Expect( container.Count = 2*TEST_COUNT-1, 'container size check');
+ Expect( not container.Contains( -TEST_COUNT), 'element not contained');
+ Expect( not container.Contains( TEST_COUNT), 'element not contained');
+ container.Clear;
+ Expect( container.Count = 0, 'count=0 after clear');
+end;
+
+
+
+
+
+
+
+
+end.