blob: 3726c8735945d3c8ae6a4d3209104601f11c6c59 [file] [log] [blame]
Jens Geyer82fc93e2024-05-24 23:36:07 +02001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19
20unit UnitTests;
21
22{$I ../src/Thrift.Defines.inc}
23
24interface
25
26uses
27 Classes, Windows, SysUtils, Math, ActiveX, ComObj,
28 {$IFDEF SupportsAsync} System.Threading, {$ENDIF}
29 DateUtils,
30 Generics.Collections,
31 TestConstants,
32 TestLogger,
33 ConsoleHelper,
34 Thrift,
35 Thrift.Protocol.Compact,
36 Thrift.Protocol.JSON,
37 Thrift.Protocol,
38 Thrift.Transport.Pipes,
39 Thrift.Transport.WinHTTP,
40 Thrift.Transport.MsxmlHTTP,
41 Thrift.Transport,
42 Thrift.Stream,
43 Thrift.Test,
44 Thrift.WinHTTP,
45 Thrift.Utils,
46 Thrift.Configuration,
47 Thrift.Collections;
48
49type
50 TQuickUnitTests = class sealed
51 strict private
52 FLogger : ITestLogger;
53
54 strict protected
55 // Helper
56 procedure StartTestGroup( const aGroup : string; const aTest : TClientTestGroup); inline;
57 procedure Expect( aTestResult : Boolean; const aTestInfo : string); inline;
58
59 // Test impl
60 procedure JSONProtocolReadWriteTest;
61 procedure HashSetTest;
62 {$IFDEF Win64}
63 procedure UseInterlockedExchangeAdd64;
64 {$ENDIF}
65
66 // main execution part
67 constructor Create( const logger : ITestLogger); reintroduce;
68 procedure Execute; overload;
69 public
70 destructor Destroy; override;
71
72 class procedure Execute( const logger : ITestLogger); overload; static;
73 end;
74
75
76implementation
77
78
79constructor TQuickUnitTests.Create( const logger : ITestLogger);
80begin
81 inherited Create;
82 FLogger := logger;
83end;
84
85
86destructor TQuickUnitTests.Destroy;
87begin
88 try
89 FLogger := nil; //-> Release
90 finally
91 inherited Destroy;
92 end;
93end;
94
95
96class procedure TQuickUnitTests.Execute( const logger : ITestLogger);
97var instance : TQuickUnitTests;
98begin
99 instance := TQuickUnitTests.Create(logger);
100 try
101 instance.Execute;
102 finally
103 instance.Free;
104 end;
105end;
106
107
108procedure TQuickUnitTests.Execute;
109begin
110 {$IFDEF Win64}
111 UseInterlockedExchangeAdd64;
112 {$ENDIF}
113
114 JSONProtocolReadWriteTest;
115 HashSetTest;
116end;
117
118
119procedure TQuickUnitTests.StartTestGroup( const aGroup : string; const aTest : TClientTestGroup);
120begin
121 FLogger.StartTestGroup( aGroup, aTest);
122end;
123
124
125procedure TQuickUnitTests.Expect( aTestResult : Boolean; const aTestInfo : string);
126begin
127 FLogger.Expect( aTestResult, aTestInfo);
128end;
129
130
131{$IFDEF Win64}
132procedure TQuickUnitTests.UseInterlockedExchangeAdd64;
133var a,b : Int64;
134begin
135 a := 1;
136 b := 2;
137 Thrift.Utils.InterlockedExchangeAdd64( a,b);
138 Expect( a = 3, 'InterlockedExchangeAdd64');
139end;
140{$ENDIF}
141
142
143procedure TQuickUnitTests.JSONProtocolReadWriteTest;
144// Tests only then read/write procedures of the JSON protocol
145// All tests succeed, if we can read what we wrote before
146// Note that passing this test does not imply, that our JSON is really compatible to what
147// other clients or servers expect as the real JSON. This is beyond the scope of this test.
148var prot : IProtocol;
149 stm : TStringStream;
150 list : TThriftList;
151 config : IThriftConfiguration;
152 binary, binRead, emptyBinary : TBytes;
153 i,iErr : Integer;
154const
155 TEST_SHORT = ShortInt( $FE);
156 TEST_SMALL = SmallInt( $FEDC);
157 TEST_LONG = LongInt( $FEDCBA98);
158 TEST_I64 = Int64( $FEDCBA9876543210);
159 TEST_DOUBLE = -1.234e-56;
160 DELTA_DOUBLE = TEST_DOUBLE * 1e-14;
161 TEST_STRING = 'abc-'#$00E4#$00f6#$00fc; // german umlauts (en-us: "funny chars")
162 // Test THRIFT-2336 and THRIFT-3404 with U+1D11E (G Clef symbol) and 'Русское Название';
163 G_CLEF_AND_CYRILLIC_TEXT = #$1d11e' '#$0420#$0443#$0441#$0441#$043a#$043e#$0435' '#$041d#$0430#$0437#$0432#$0430#$043d#$0438#$0435;
164 G_CLEF_AND_CYRILLIC_JSON = '"\ud834\udd1e \u0420\u0443\u0441\u0441\u043a\u043e\u0435 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435"';
165 // test both possible solidus encodings
166 SOLIDUS_JSON_DATA = '"one/two\/three"';
167 SOLIDUS_EXCPECTED = 'one/two/three';
168begin
169 stm := TStringStream.Create;
170 try
171 FLogger.StartTestGroup( 'JsonProtocolTest', test_Unknown);
172
173 config := TThriftConfigurationImpl.Create;
174
175 // prepare binary data
176 binary := PrepareBinaryData( FALSE, TTestSize.Normal);
177 SetLength( emptyBinary, 0); // empty binary data block
178
179 // output setup
180 prot := TJSONProtocolImpl.Create(
181 TStreamTransportImpl.Create(
182 nil, TThriftStreamAdapterDelphi.Create( stm, FALSE), config));
183
184 // write
185 Init( list, TType.String_, 9);
186 prot.WriteListBegin( list);
187 prot.WriteBool( TRUE);
188 prot.WriteBool( FALSE);
189 prot.WriteByte( TEST_SHORT);
190 prot.WriteI16( TEST_SMALL);
191 prot.WriteI32( TEST_LONG);
192 prot.WriteI64( TEST_I64);
193 prot.WriteDouble( TEST_DOUBLE);
194 prot.WriteString( TEST_STRING);
195 prot.WriteBinary( binary);
196 prot.WriteString( ''); // empty string
197 prot.WriteBinary( emptyBinary); // empty binary data block
198 prot.WriteListEnd;
199
200 // input setup
201 Expect( stm.Position = stm.Size, 'Stream position/length after write');
202 stm.Position := 0;
203 prot := TJSONProtocolImpl.Create(
204 TStreamTransportImpl.Create(
205 TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
206
207 // read and compare
208 list := prot.ReadListBegin;
209 Expect( list.ElementType = TType.String_, 'list element type');
210 Expect( list.Count = 9, 'list element count');
211 Expect( prot.ReadBool, 'WriteBool/ReadBool: TRUE');
212 Expect( not prot.ReadBool, 'WriteBool/ReadBool: FALSE');
213 Expect( prot.ReadByte = TEST_SHORT, 'WriteByte/ReadByte');
214 Expect( prot.ReadI16 = TEST_SMALL, 'WriteI16/ReadI16');
215 Expect( prot.ReadI32 = TEST_LONG, 'WriteI32/ReadI32');
216 Expect( prot.ReadI64 = TEST_I64, 'WriteI64/ReadI64');
217 Expect( abs(prot.ReadDouble-TEST_DOUBLE) < abs(DELTA_DOUBLE), 'WriteDouble/ReadDouble');
218 Expect( prot.ReadString = TEST_STRING, 'WriteString/ReadString');
219 binRead := prot.ReadBinary;
220 Expect( Length(prot.ReadString) = 0, 'WriteString/ReadString (empty string)');
221 Expect( Length(prot.ReadBinary) = 0, 'empty WriteBinary/ReadBinary (empty data block)');
222 prot.ReadListEnd;
223
224 // test binary data
225 Expect( Length(binary) = Length(binRead), 'Binary data length check');
226 iErr := -1;
227 for i := Low(binary) to High(binary) do begin
228 if binary[i] <> binRead[i] then begin
229 iErr := i;
230 Break;
231 end;
232 end;
233 if iErr < 0
234 then Expect( TRUE, 'Binary data check ('+IntToStr(Length(binary))+' Bytes)')
235 else Expect( FALSE, 'Binary data check at offset '+IntToStr(iErr));
236
237 Expect( stm.Position = stm.Size, 'Stream position after read');
238
239
240 // Solidus can be encoded in two ways. Make sure we can read both
241 stm.Position := 0;
242 stm.Size := 0;
243 stm.WriteString(SOLIDUS_JSON_DATA);
244 stm.Position := 0;
245 prot := TJSONProtocolImpl.Create(
246 TStreamTransportImpl.Create(
247 TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
248 Expect( prot.ReadString = SOLIDUS_EXCPECTED, 'Solidus encoding');
249
250
251 // Widechars should work too. Do they?
252 // After writing, we ensure that we are able to read it back
253 // We can't assume hex-encoding, since (nearly) any Unicode char is valid JSON
254 stm.Position := 0;
255 stm.Size := 0;
256 prot := TJSONProtocolImpl.Create(
257 TStreamTransportImpl.Create(
258 nil, TThriftStreamAdapterDelphi.Create( stm, FALSE), config));
259 prot.WriteString( G_CLEF_AND_CYRILLIC_TEXT);
260 stm.Position := 0;
261 prot := TJSONProtocolImpl.Create(
262 TStreamTransportImpl.Create(
263 TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
264 FLogger.Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Writing JSON with chars > 8 bit');
265
266 // Widechars should work with hex-encoding too. Do they?
267 stm.Position := 0;
268 stm.Size := 0;
269 stm.WriteString( G_CLEF_AND_CYRILLIC_JSON);
270 stm.Position := 0;
271 prot := TJSONProtocolImpl.Create(
272 TStreamTransportImpl.Create(
273 TThriftStreamAdapterDelphi.Create( stm, FALSE), nil, config));
274 FLogger.Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Reading JSON with chars > 8 bit');
275
276
277 finally
278 stm.Free;
279 prot := nil; //-> Release
280 FLogger.StartTestGroup( '', test_Unknown); // no more tests here
281 end;
282end;
283
284
285procedure TQuickUnitTests.HashSetTest;
286var container : IThriftHashSet<Integer>;
287 testdata : array of Integer;
288 i : Integer;
289const
290 TEST_COUNT = 4096;
291begin
292 StartTestGroup( 'IThriftHashSet<T> implementation', test_Containers);
293
294 // prepare test data
295 SetLength( testdata, 5);
296 testdata[0] := -2;
297 testdata[1] := 0;
298 testdata[2] := 42;
299 testdata[3] := MaxInt;
300 testdata[4] := Low(Integer);
301
302 // first insert
303 container := TThriftHashSetImpl<Integer>.Create;
304 for i in testdata do begin
305 Expect( container.Add( i), 'add first '+IntToStr(i));
306 Expect( container.Contains( i), 'contains '+IntToStr(i));
307 end;
308 Expect( container.Count = Length(testdata), 'container size');
309
310 // insert again
311 for i in testdata do begin
312 Expect( not container.Add( i), 'add second '+IntToStr(i));
313 Expect( container.Contains( i), 'contains '+IntToStr(i));
314 end;
315 Expect( container.Count = Length(testdata), 'container size');
316
317 // remove
318 for i in testdata do begin
319 Expect( container.Remove( i), 'first remove '+IntToStr(i));
320 Expect( not container.Contains( i), 'not contains '+IntToStr(i));
321 end;
322 Expect( container.Count = 0, 'container size');
323
324 // remove again
325 for i in testdata do begin
326 Expect( not container.Remove( i), 'second remove '+IntToStr(i));
327 Expect( not container.Contains( i), 'not contains '+IntToStr(i));
328 end;
329 Expect( container.Count = 0, 'container size');
330
331 // append and clear
332 for i := 0 to TEST_COUNT-1 do begin
333 container.Add(-i);
334 container.Add(+i);
335 end;
336 Expect( container.Count = 2*TEST_COUNT-1, 'container size check');
337 Expect( not container.Contains( -TEST_COUNT), 'element not contained');
338 Expect( not container.Contains( TEST_COUNT), 'element not contained');
339 container.Clear;
340 Expect( container.Count = 0, 'count=0 after clear');
341end;
342
343
344
345
346
347
348
349
350end.