blob: 72d71ea987dba02312135bcfb6052f9ac2e1842b [file] [log] [blame]
Yann Collet4856a002015-01-24 01:58:16 +01001/*
2 Fuzzer test tool for zstd
3 Copyright (C) Yann Collet 2014-2105
4
5 GPL v2 License
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 You can contact the author at :
22 - ZSTD source repository : https://github.com/Cyan4973/zstd
23 - ZSTD public forum : https://groups.google.com/forum/#!forum/lz4c
24*/
25
26/**************************************
27* Compiler specific
28**************************************/
29#ifdef _MSC_VER /* Visual Studio */
30# define _CRT_SECURE_NO_WARNINGS /* fgets */
31# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
32# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
33#endif
34
35#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
36#ifdef __GNUC__
37# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
38# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
39#endif
40
41
42/**************************************
43* Includes
44**************************************/
45#include <stdlib.h> /* free */
46#include <stdio.h> /* fgets, sscanf */
47#include <sys/timeb.h> /* timeb */
48#include <string.h> /* strcmp */
49#include "zstd_static.h"
Yann Colletd5d9bc32015-08-23 23:13:49 +010050#include "datagen.h" /* RDG_genBuffer */
Yann Collet4856a002015-01-24 01:58:16 +010051#include "xxhash.h" /* XXH64 */
Yann Collet353c5d22015-10-21 14:39:26 +010052#include "mem.h"
Yann Collet4856a002015-01-24 01:58:16 +010053
54
55/**************************************
56 Constants
57**************************************/
58#ifndef ZSTD_VERSION
59# define ZSTD_VERSION ""
60#endif
61
62#define KB *(1U<<10)
63#define MB *(1U<<20)
64#define GB *(1U<<30)
65
Yann Collet110cc142015-11-19 12:02:28 +010066static const U32 nbTestsDefault = 30000;
Yann Collet4856a002015-01-24 01:58:16 +010067#define COMPRESSIBLE_NOISE_LENGTH (10 MB)
68#define FUZ_COMPRESSIBILITY_DEFAULT 50
69static const U32 prime1 = 2654435761U;
70static const U32 prime2 = 2246822519U;
71
72
73
74/**************************************
75* Display Macros
76**************************************/
77#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
78#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
79static U32 g_displayLevel = 2;
80
81#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
Yann Collet553cf6a2015-12-04 17:25:26 +010082 if ((FUZ_GetMilliSpan(g_displayTime) > g_refreshRate) || (g_displayLevel>=4)) \
83 { g_displayTime = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
Yann Collet4856a002015-01-24 01:58:16 +010084 if (g_displayLevel>=4) fflush(stdout); } }
85static const U32 g_refreshRate = 150;
Yann Collet553cf6a2015-12-04 17:25:26 +010086static U32 g_displayTime = 0;
87
88static U32 g_testTime = 0;
Yann Collet4856a002015-01-24 01:58:16 +010089
90
91/*********************************************************
92* Fuzzer functions
93*********************************************************/
Yann Collete93add02016-02-15 17:44:14 +010094#define MIN(a,b) ((a)<(b)?(a):(b))
Yann Collet110cc142015-11-19 12:02:28 +010095#define MAX(a,b) ((a)>(b)?(a):(b))
96
Yann Collet4856a002015-01-24 01:58:16 +010097static U32 FUZ_GetMilliStart(void)
98{
99 struct timeb tb;
100 U32 nCount;
101 ftime( &tb );
102 nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
103 return nCount;
104}
105
106
107static U32 FUZ_GetMilliSpan(U32 nTimeStart)
108{
109 U32 nCurrent = FUZ_GetMilliStart();
110 U32 nSpan = nCurrent - nTimeStart;
111 if (nTimeStart > nCurrent)
112 nSpan += 0x100000 * 1000;
113 return nSpan;
114}
115
116
117# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
118unsigned int FUZ_rand(unsigned int* src)
119{
120 U32 rand32 = *src;
121 rand32 *= prime1;
122 rand32 += prime2;
123 rand32 = FUZ_rotl32(rand32, 13);
124 *src = rand32;
125 return rand32 >> 5;
126}
127
128
Yann Collet997f9ee2015-08-21 02:44:20 +0100129static unsigned FUZ_highbit32(U32 v32)
Yann Collet4856a002015-01-24 01:58:16 +0100130{
131 unsigned nbBits = 0;
132 if (v32==0) return 0;
133 while (v32)
134 {
135 v32 >>= 1;
136 nbBits ++;
137 }
138 return nbBits;
139}
Yann Collet4856a002015-01-24 01:58:16 +0100140
141
142static int basicUnitTests(U32 seed, double compressibility)
143{
144 int testResult = 0;
145 void* CNBuffer;
146 void* compressedBuffer;
147 void* decodedBuffer;
148 U32 randState = seed;
149 size_t result, cSize;
150 U32 testNb=0;
151
Yann Colletd5d9bc32015-08-23 23:13:49 +0100152 /* Create compressible test buffer */
Yann Collet4856a002015-01-24 01:58:16 +0100153 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
154 compressedBuffer = malloc(ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH));
155 decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
Yann Collet94f998b2015-07-04 23:10:40 -0800156 if (!CNBuffer || !compressedBuffer || !decodedBuffer)
157 {
158 DISPLAY("Not enough memory, aborting\n");
159 testResult = 1;
160 goto _end;
161 }
Yann Colletd5d9bc32015-08-23 23:13:49 +0100162 RDG_genBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, 0., randState);
Yann Collet4856a002015-01-24 01:58:16 +0100163
Yann Colletd5d9bc32015-08-23 23:13:49 +0100164 /* Basic tests */
Yann Collet4856a002015-01-24 01:58:16 +0100165 DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
Yann Collet5be2dd22015-11-11 13:43:58 +0100166 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
Yann Collet4856a002015-01-24 01:58:16 +0100167 if (ZSTD_isError(result)) goto _output_error;
168 cSize = result;
169 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
170
171 DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
172 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
173 if (ZSTD_isError(result)) goto _output_error;
Yann Collet4ec29982016-03-04 19:09:28 +0100174 if (result != COMPRESSIBLE_NOISE_LENGTH) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100175 DISPLAYLEVEL(4, "OK \n");
176
177 {
178 size_t i;
179 DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++);
180 for (i=0; i<COMPRESSIBLE_NOISE_LENGTH; i++)
181 {
182 if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
183 }
184 DISPLAYLEVEL(4, "OK \n");
185 }
186
187 DISPLAYLEVEL(4, "test%3i : decompress with 1 missing byte : ", testNb++);
188 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize-1);
189 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100190 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100191 DISPLAYLEVEL(4, "OK \n");
192
193 DISPLAYLEVEL(4, "test%3i : decompress with 1 too much byte : ", testNb++);
194 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize+1);
195 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100196 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100197 DISPLAYLEVEL(4, "OK \n");
198
Yann Collet60096272016-01-08 17:27:50 +0100199 /* Dictionary and Duplication tests */
200 {
201 ZSTD_CCtx* ctxOrig = ZSTD_createCCtx();
202 ZSTD_CCtx* ctxDuplicated = ZSTD_createCCtx();
203 ZSTD_DCtx* dctx = ZSTD_createDCtx();
204 const size_t dictSize = 500;
205 size_t cSizeOrig;
206
207 DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++);
Yann Collet1c8e1942016-01-26 16:31:22 +0100208 result = ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2);
Yann Collet60096272016-01-08 17:27:50 +0100209 if (ZSTD_isError(result)) goto _output_error;
Yann Collet7b51a292016-01-26 15:58:49 +0100210 result = ZSTD_copyCCtx(ctxDuplicated, ctxOrig);
Yann Collet60096272016-01-08 17:27:50 +0100211 if (ZSTD_isError(result)) goto _output_error;
212 DISPLAYLEVEL(4, "OK \n");
213
214 DISPLAYLEVEL(4, "test%3i : compress with dictionary : ", testNb++);
215 cSize = 0;
216 result = ZSTD_compressContinue(ctxOrig, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
217 if (ZSTD_isError(result)) goto _output_error;
218 cSize += result;
219 result = ZSTD_compressEnd(ctxOrig, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
220 if (ZSTD_isError(result)) goto _output_error;
221 cSize += result;
222 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
223
224 DISPLAYLEVEL(4, "test%3i : frame built with dictionary should be decompressible : ", testNb++);
225 result = ZSTD_decompress_usingDict(dctx,
226 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
227 compressedBuffer, cSize,
228 CNBuffer, dictSize);
229 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100230 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100231 ZSTD_freeCCtx(ctxOrig); /* if ctxOrig is read, will produce segfault */
232 DISPLAYLEVEL(4, "OK \n");
233
234 DISPLAYLEVEL(4, "test%3i : compress with duplicated context : ", testNb++);
235 cSizeOrig = cSize;
236 cSize = 0;
237 result = ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), (const char*)CNBuffer + dictSize, COMPRESSIBLE_NOISE_LENGTH - dictSize);
238 if (ZSTD_isError(result)) goto _output_error;
239 cSize += result;
240 result = ZSTD_compressEnd(ctxDuplicated, (char*)compressedBuffer+cSize, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)-cSize);
241 if (ZSTD_isError(result)) goto _output_error;
242 cSize += result;
243 if (cSize != cSizeOrig) goto _output_error; /* should be identical == have same size */
244 ZSTD_freeCCtx(ctxDuplicated);
245 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
246
247 DISPLAYLEVEL(4, "test%3i : frame built with duplicated context should be decompressible : ", testNb++);
248 result = ZSTD_decompress_usingDict(dctx,
249 decodedBuffer, COMPRESSIBLE_NOISE_LENGTH,
250 compressedBuffer, cSize,
251 CNBuffer, dictSize);
252 if (ZSTD_isError(result)) goto _output_error;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100253 if (result != COMPRESSIBLE_NOISE_LENGTH - dictSize) goto _output_error;
Yann Collet60096272016-01-08 17:27:50 +0100254 ZSTD_freeDCtx(dctx);
255 DISPLAYLEVEL(4, "OK \n");
256 }
257
Yann Collet4856a002015-01-24 01:58:16 +0100258 /* Decompression defense tests */
259 DISPLAYLEVEL(4, "test%3i : Check input length for magic number : ", testNb++);
260 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 3);
261 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet977f1f32016-01-21 15:38:47 +0100262 if (result != (size_t)-ZSTD_error_srcSize_wrong) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100263 DISPLAYLEVEL(4, "OK \n");
264
265 DISPLAYLEVEL(4, "test%3i : Check magic Number : ", testNb++);
266 ((char*)(CNBuffer))[0] = 1;
267 result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, CNBuffer, 4);
268 if (!ZSTD_isError(result)) goto _output_error;
Yann Collet4856a002015-01-24 01:58:16 +0100269 DISPLAYLEVEL(4, "OK \n");
270
Yann Colletbf42c8e2016-01-09 01:08:23 +0100271 /* block API tests */
272 {
273 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
274 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
275 const size_t blockSize = 100 KB;
Yann Colletb0125102016-01-09 02:00:10 +0100276 const size_t dictSize = 16 KB;
Yann Colletbf42c8e2016-01-09 01:08:23 +0100277
278 /* basic block compression */
279 DISPLAYLEVEL(4, "test%3i : Block compression test : ", testNb++);
280 result = ZSTD_compressBegin(cctx, 5);
281 if (ZSTD_isError(result)) goto _output_error;
282 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), CNBuffer, blockSize);
283 if (ZSTD_isError(cSize)) goto _output_error;
284 DISPLAYLEVEL(4, "OK \n");
285
286 DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100287 result = ZSTD_decompressBegin(dctx);
Yann Colletbf42c8e2016-01-09 01:08:23 +0100288 if (ZSTD_isError(result)) goto _output_error;
289 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
290 if (ZSTD_isError(result)) goto _output_error;
291 if (result != blockSize) goto _output_error;
292 DISPLAYLEVEL(4, "OK \n");
293
Yann Colletb0125102016-01-09 02:00:10 +0100294 /* dictionary block compression */
295 DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++);
Yann Collet1c8e1942016-01-26 16:31:22 +0100296 result = ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5);
Yann Colletb0125102016-01-09 02:00:10 +0100297 if (ZSTD_isError(result)) goto _output_error;
298 cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize);
299 if (ZSTD_isError(cSize)) goto _output_error;
300 DISPLAYLEVEL(4, "OK \n");
301
302 DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++);
Yann Collet7b51a292016-01-26 15:58:49 +0100303 result = ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize);
Yann Colletb0125102016-01-09 02:00:10 +0100304 if (ZSTD_isError(result)) goto _output_error;
Yann Colletb0125102016-01-09 02:00:10 +0100305 result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize);
306 if (ZSTD_isError(result)) goto _output_error;
307 if (result != blockSize) goto _output_error;
308 DISPLAYLEVEL(4, "OK \n");
309
Yann Colletbf42c8e2016-01-09 01:08:23 +0100310 ZSTD_freeCCtx(cctx);
311 ZSTD_freeDCtx(dctx);
312 }
313
Yann Collet213089c2015-06-18 07:43:16 -0800314 /* long rle test */
315 {
316 size_t sampleSize = 0;
317 DISPLAYLEVEL(4, "test%3i : Long RLE test : ", testNb++);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100318 RDG_genBuffer(CNBuffer, sampleSize, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800319 memset((char*)CNBuffer+sampleSize, 'B', 256 KB - 1);
320 sampleSize += 256 KB - 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100321 RDG_genBuffer((char*)CNBuffer+sampleSize, 96 KB, compressibility, 0., randState);
Yann Collet213089c2015-06-18 07:43:16 -0800322 sampleSize += 96 KB;
Yann Collet5be2dd22015-11-11 13:43:58 +0100323 cSize = ZSTD_compress(compressedBuffer, ZSTD_compressBound(sampleSize), CNBuffer, sampleSize, 1);
Yann Collet213089c2015-06-18 07:43:16 -0800324 if (ZSTD_isError(cSize)) goto _output_error;
325 result = ZSTD_decompress(decodedBuffer, sampleSize, compressedBuffer, cSize);
326 if (ZSTD_isError(result)) goto _output_error;
327 if (result!=sampleSize) goto _output_error;
328 DISPLAYLEVEL(4, "OK \n");
329 }
330
Yann Collet4ba85342016-03-07 20:01:45 +0100331 /* All zeroes test (#137 verif) */
332 #define ZEROESLENGTH 100
333 DISPLAYLEVEL(4, "test%3i : compress %u zeroes : ", testNb++, ZEROESLENGTH);
334 memset(CNBuffer, 0, ZEROESLENGTH);
335 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(ZEROESLENGTH), CNBuffer, ZEROESLENGTH, 1);
336 if (ZSTD_isError(result)) goto _output_error;
337 cSize = result;
338 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/ZEROESLENGTH*100);
339
340 DISPLAYLEVEL(4, "test%3i : decompress %u zeroes : ", testNb++, ZEROESLENGTH);
341 result = ZSTD_decompress(decodedBuffer, ZEROESLENGTH, compressedBuffer, cSize);
342 if (ZSTD_isError(result)) goto _output_error;
343 if (result != ZEROESLENGTH) goto _output_error;
344 DISPLAYLEVEL(4, "OK \n");
345
346 /* nbSeq limit test */
347 {
348 #define _3BYTESTESTLENGTH 131000
349 #define NB3BYTESSEQLOG 9
350 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
351 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
352 BYTE _3BytesSeqs[NB3BYTESSEQ][3];
353 U32 r = 1;
354 int i;
355
356 for (i=0; i < NB3BYTESSEQ; i++) {
357 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&r) & 255);
358 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&r) & 255);
359 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&r) & 255);
360 }
361
Yann Colletdd54bbc2016-03-08 02:35:34 +0100362 for (i=0; i < _3BYTESTESTLENGTH; ) {
Yann Collet4ba85342016-03-07 20:01:45 +0100363 U32 id = FUZ_rand(&r) & NB3BYTESSEQMASK;
364 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
365 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
366 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
367 i += 3;
368 }
369
370 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
371 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19);
372 if (ZSTD_isError(result)) goto _output_error;
373 cSize = result;
374 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
375
376 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
377 result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize);
378 if (ZSTD_isError(result)) goto _output_error;
379 if (result != _3BYTESTESTLENGTH) goto _output_error;
380 DISPLAYLEVEL(4, "OK \n");
381 }
382
Yann Collet4856a002015-01-24 01:58:16 +0100383_end:
384 free(CNBuffer);
385 free(compressedBuffer);
386 free(decodedBuffer);
387 return testResult;
388
389_output_error:
390 testResult = 1;
391 DISPLAY("Error detected in Unit tests ! \n");
392 goto _end;
393}
394
395
396static size_t findDiff(const void* buf1, const void* buf2, size_t max)
397{
Yann Collet213089c2015-06-18 07:43:16 -0800398 const BYTE* b1 = (const BYTE*)buf1;
399 const BYTE* b2 = (const BYTE*)buf2;
Yann Collet4856a002015-01-24 01:58:16 +0100400 size_t i;
401 for (i=0; i<max; i++)
402 {
403 if (b1[i] != b2[i]) break;
404 }
405 return i;
406}
407
408# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
409 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
410
411static const U32 maxSrcLog = 23;
412static const U32 maxSampleLog = 22;
413
414int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility)
415{
Yann Colletd5d9bc32015-08-23 23:13:49 +0100416 BYTE* cNoiseBuffer[5];
Yann Collet4856a002015-01-24 01:58:16 +0100417 BYTE* srcBuffer;
418 BYTE* cBuffer;
419 BYTE* dstBuffer;
Yann Collete47c4e52015-12-05 09:23:53 +0100420 BYTE* mirrorBuffer;
Yann Collet4856a002015-01-24 01:58:16 +0100421 size_t srcBufferSize = (size_t)1<<maxSrcLog;
422 size_t dstBufferSize = (size_t)1<<maxSampleLog;
423 size_t cBufferSize = ZSTD_compressBound(dstBufferSize);
424 U32 result = 0;
425 U32 testNb = 0;
426 U32 coreSeed = seed, lseed = 0;
Yann Colletecd651b2016-01-07 15:35:18 +0100427 ZSTD_CCtx* refCtx;
Yann Collet2f648e52015-10-29 18:23:38 +0100428 ZSTD_CCtx* ctx;
Yann Collete47c4e52015-12-05 09:23:53 +0100429 ZSTD_DCtx* dctx;
Yann Collet553cf6a2015-12-04 17:25:26 +0100430 U32 startTime = FUZ_GetMilliStart();
Yann Collet4856a002015-01-24 01:58:16 +0100431
432 /* allocation */
Yann Colletecd651b2016-01-07 15:35:18 +0100433 refCtx = ZSTD_createCCtx();
Yann Collet2f648e52015-10-29 18:23:38 +0100434 ctx = ZSTD_createCCtx();
Yann Collete47c4e52015-12-05 09:23:53 +0100435 dctx= ZSTD_createDCtx();
Yann Colletd5d9bc32015-08-23 23:13:49 +0100436 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
437 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
438 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
439 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
440 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800441 dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100442 mirrorBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800443 cBuffer = (BYTE*)malloc (cBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100444 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100445 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100446 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100447
Yann Colletd5d9bc32015-08-23 23:13:49 +0100448 /* Create initial samples */
449 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
450 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
451 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
452 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
453 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
454 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100455
456 /* catch up testNb */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100457 for (testNb=1; testNb < startTest; testNb++)
Yann Collet4856a002015-01-24 01:58:16 +0100458 FUZ_rand(&coreSeed);
459
460 /* test loop */
Yann Collet553cf6a2015-12-04 17:25:26 +0100461 for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime); testNb++ )
Yann Collet4856a002015-01-24 01:58:16 +0100462 {
Yann Collet417890c2015-12-04 17:16:37 +0100463 size_t sampleSize, sampleStart, maxTestSize, totalTestSize;
Yann Collete47c4e52015-12-05 09:23:53 +0100464 size_t cSize, dSize, dSupSize, errorCode, totalCSize, totalGenSize;
Yann Collet417890c2015-12-04 17:16:37 +0100465 U32 sampleSizeLog, buffNb, cLevelMod, nbChunks, n;
Yann Collet5835e1b2016-01-05 01:44:36 +0100466 XXH64_CREATESTATE_STATIC(xxh64);
Yann Collet4856a002015-01-24 01:58:16 +0100467 U64 crcOrig, crcDest;
Yann Collet2f648e52015-10-29 18:23:38 +0100468 int cLevel;
Yann Collet110cc142015-11-19 12:02:28 +0100469 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100470 const BYTE* dict;
471 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100472
473 /* init */
Yann Collet1c2ddba2015-12-04 17:45:35 +0100474 if (nbTests >= testNb)
475 { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
476 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
477
Yann Collet4856a002015-01-24 01:58:16 +0100478 FUZ_rand(&coreSeed);
479 lseed = coreSeed ^ prime1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100480 buffNb = FUZ_rand(&lseed) & 127;
481 if (buffNb & 7) buffNb=2;
482 else
483 {
484 buffNb >>= 3;
485 if (buffNb & 7)
486 {
487 const U32 tnb[2] = { 1, 3 };
488 buffNb = tnb[buffNb >> 3];
489 }
490 else
491 {
492 const U32 tnb[2] = { 0, 4 };
493 buffNb = tnb[buffNb >> 3];
494 }
495 }
496 srcBuffer = cNoiseBuffer[buffNb];
Yann Collet4856a002015-01-24 01:58:16 +0100497 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
Yann Colletf4ce8912015-08-11 14:18:45 +0100498 sampleSize = (size_t)1 << sampleSizeLog;
Yann Collet4856a002015-01-24 01:58:16 +0100499 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
500 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
Yann Collet4856a002015-01-24 01:58:16 +0100501
Yann Collet110cc142015-11-19 12:02:28 +0100502 /* create sample buffer (to catch read error with valgrind & sanitizers) */
503 sampleBuffer = (BYTE*)malloc(sampleSize);
504 CHECK (sampleBuffer==NULL, "not enough memory for sample buffer");
505 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize);
506 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
507
508 /* compression test */
Yann Collete93add02016-02-15 17:44:14 +0100509 //cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */
510 cLevelMod = MIN( ZSTD_maxCLevel(), (U32)MAX(1, 55 - 3*(int)sampleSizeLog) ); /* high levels only for small samples, for manageable speed */
Yann Collet4c7aae32015-11-08 14:24:59 +0100511 cLevel = (FUZ_rand(&lseed) % cLevelMod) +1;
Yann Colletdc5e3e92015-11-20 09:23:56 +0100512 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100513 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
Yann Collet4856a002015-01-24 01:58:16 +0100514
Yann Colletf3cb79b2015-08-20 00:02:43 +0100515 /* compression failure test : too small dest buffer */
Yann Collet346bffb2016-03-15 15:24:52 +0100516 if (cSize > 3) {
Yann Colletf4ce8912015-08-11 14:18:45 +0100517 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
518 const size_t tooSmallSize = cSize - missing;
Yann Collet602834f2015-08-20 07:46:10 +0100519 static const U32 endMark = 0x4DC2B1A9;
520 U32 endCheck;
521 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
Yann Colletdc5e3e92015-11-20 09:23:56 +0100522 errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100523 CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize);
Yann Collet602834f2015-08-20 07:46:10 +0100524 memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
Yann Collet5be2dd22015-11-11 13:43:58 +0100525 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow");
Yann Collete9853b22015-08-07 19:07:32 +0100526 }
527
Yann Collet346bffb2016-03-15 15:24:52 +0100528 /* decompression header test */
529 { ZSTD_frameParams dParams;
530 size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize);
531 CHECK(ZSTD_isError(check), "Frame Parameters extraction failed");
532 CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect");
533 }
534
Yann Colletf3cb79b2015-08-20 00:02:43 +0100535 /* successfull decompression tests*/
Yann Collet4856a002015-01-24 01:58:16 +0100536 dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
537 dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize);
Yann Collet3e358272015-11-04 18:19:39 +0100538 CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
Yann Collet4856a002015-01-24 01:58:16 +0100539 crcDest = XXH64(dstBuffer, sampleSize, 0);
Yann Collet110cc142015-11-19 12:02:28 +0100540 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
541
542 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100543
544 /* truncated src decompression test */
545 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100546 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
547 const size_t tooSmallSize = cSize - missing;
548 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100549 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100550 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Colletf3cb79b2015-08-20 00:02:43 +0100551 errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
552 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)");
553 free(cBufferTooSmall);
554 }
555
556 /* too small dst decompression test */
557 if (sampleSize > 3)
558 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100559 const size_t missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
560 const size_t tooSmallSize = sampleSize - missing;
561 static const BYTE token = 0xA9;
562 dstBuffer[tooSmallSize] = token;
563 errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
564 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed : %u > %u (dst buffer too small)", (U32)errorCode, (U32)tooSmallSize);
565 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
566 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100567
568 /* noisy src decompression test */
569 if (cSize > 6)
570 {
571 const U32 maxNbBits = FUZ_highbit32((U32)(cSize-4));
572 size_t pos = 4; /* preserve magic number (too easy to detect) */
573 U32 nbBits = FUZ_rand(&lseed) % maxNbBits;
574 size_t mask = (1<<nbBits) - 1;
575 size_t skipLength = FUZ_rand(&lseed) & mask;
576 pos += skipLength;
577
578 while (pos < cSize)
579 {
580 /* add noise */
581 size_t noiseStart, noiseLength;
582 nbBits = FUZ_rand(&lseed) % maxNbBits;
583 if (nbBits>0) nbBits--;
584 mask = (1<<nbBits) - 1;
585 noiseLength = (FUZ_rand(&lseed) & mask) + 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100586 if ( pos+noiseLength > cSize ) noiseLength = cSize-pos;
Yann Collet997f9ee2015-08-21 02:44:20 +0100587 noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
588 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
589 pos += noiseLength;
590
591 /* keep some original src */
592 nbBits = FUZ_rand(&lseed) % maxNbBits;
593 mask = (1<<nbBits) - 1;
594 skipLength = FUZ_rand(&lseed) & mask;
595 pos += skipLength;
596 }
597
598 /* decompress noisy source */
Yann Colletf3120412016-03-19 11:40:19 +0100599 { U32 const noiseSrc = FUZ_rand(&lseed) % 5;
600 U32 const endMark = 0xA9B1C3D6;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100601 srcBuffer = cNoiseBuffer[noiseSrc];
Yann Collet997f9ee2015-08-21 02:44:20 +0100602 memcpy(dstBuffer+sampleSize, &endMark, 4);
603 errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
604 /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */
605 CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize),
606 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize);
Yann Colletf3120412016-03-19 11:40:19 +0100607 { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4);
608 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow"); }
Yann Collet997f9ee2015-08-21 02:44:20 +0100609 }
610 }
Yann Collet417890c2015-12-04 17:16:37 +0100611
Yann Collete47c4e52015-12-05 09:23:53 +0100612 /* Streaming compression of scattered segments test */
Yann Collet5835e1b2016-01-05 01:44:36 +0100613 XXH64_reset(xxh64, 0);
Yann Collet417890c2015-12-04 17:16:37 +0100614 nbChunks = (FUZ_rand(&lseed) & 127) + 2;
615 sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog;
616 maxTestSize = (size_t)1 << sampleSizeLog;
617 maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1);
Yann Collete47c4e52015-12-05 09:23:53 +0100618 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
Yann Collet4bfe4152015-12-06 13:18:37 +0100619
620 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
621 sampleSize = (size_t)1 << sampleSizeLog;
622 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
623 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
624 dict = srcBuffer + sampleStart;
625 dictSize = sampleSize;
626
Yann Collet1c8e1942016-01-26 16:31:22 +0100627 errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1);
628 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
Yann Collet7b51a292016-01-26 15:58:49 +0100629 errorCode = ZSTD_copyCCtx(ctx, refCtx);
Yann Collet464fa992016-02-03 01:09:46 +0100630 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode));
Yann Colletecd651b2016-01-07 15:35:18 +0100631 totalTestSize = 0; cSize = 0;
Yann Collet417890c2015-12-04 17:16:37 +0100632 for (n=0; n<nbChunks; n++)
633 {
634 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
635 sampleSize = (size_t)1 << sampleSizeLog;
636 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
637 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
638
639 if (cBufferSize-cSize < ZSTD_compressBound(sampleSize))
640 /* avoid invalid dstBufferTooSmall */
641 break;
Yann Collete47c4e52015-12-05 09:23:53 +0100642 if (totalTestSize+sampleSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100643
644 errorCode = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+sampleStart, sampleSize);
645 CHECK (ZSTD_isError(errorCode), "multi-segments compression error : %s", ZSTD_getErrorName(errorCode));
646 cSize += errorCode;
647
Yann Collet5835e1b2016-01-05 01:44:36 +0100648 XXH64_update(xxh64, srcBuffer+sampleStart, sampleSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100649 memcpy(mirrorBuffer + totalTestSize, srcBuffer+sampleStart, sampleSize);
Yann Collet417890c2015-12-04 17:16:37 +0100650 totalTestSize += sampleSize;
Yann Collet417890c2015-12-04 17:16:37 +0100651 }
652 errorCode = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
653 CHECK (ZSTD_isError(errorCode), "multi-segments epilogue error : %s", ZSTD_getErrorName(errorCode));
654 cSize += errorCode;
Yann Collet5835e1b2016-01-05 01:44:36 +0100655 crcOrig = XXH64_digest(xxh64);
Yann Collete47c4e52015-12-05 09:23:53 +0100656
657 /* streaming decompression test */
Yann Collet7b51a292016-01-26 15:58:49 +0100658 errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100659 CHECK (ZSTD_isError(errorCode), "cannot init DCtx : %s", ZSTD_getErrorName(errorCode));
660 totalCSize = 0;
661 totalGenSize = 0;
662 while (totalCSize < cSize)
663 {
664 size_t inSize = ZSTD_nextSrcSizeToDecompress(dctx);
665 size_t genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
666 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
667 totalGenSize += genSize;
668 totalCSize += inSize;
669 }
670 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
671 CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size")
672 CHECK (totalCSize != cSize, "compressed data should be fully read")
673 crcDest = XXH64(dstBuffer, totalTestSize, 0);
674 if (crcDest!=crcOrig)
675 errorCode = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
676 CHECK (crcDest!=crcOrig, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
677 (U32)errorCode, (U32)totalTestSize, dstBuffer[errorCode], mirrorBuffer[errorCode]);
678
Yann Collet4856a002015-01-24 01:58:16 +0100679 }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100680 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100681
682_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100683 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100684 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100685 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100686 free(cNoiseBuffer[0]);
687 free(cNoiseBuffer[1]);
688 free(cNoiseBuffer[2]);
689 free(cNoiseBuffer[3]);
690 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100691 free(cBuffer);
692 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100693 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100694 return result;
695
696_output_error:
697 result = 1;
698 goto _cleanup;
699}
700
701
702/*********************************************************
703* Command line
704*********************************************************/
705int FUZ_usage(char* programName)
706{
707 DISPLAY( "Usage :\n");
708 DISPLAY( " %s [args]\n", programName);
709 DISPLAY( "\n");
710 DISPLAY( "Arguments :\n");
711 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
712 DISPLAY( " -s# : Select seed (default:prompt user)\n");
713 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collete9853b22015-08-07 19:07:32 +0100714 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
Yann Collet4856a002015-01-24 01:58:16 +0100715 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100716 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100717 DISPLAY( " -h : display help and exit\n");
718 return 0;
719}
720
721
722int main(int argc, char** argv)
723{
724 U32 seed=0;
725 int seedset=0;
726 int argNb;
727 int nbTests = nbTestsDefault;
728 int testNb = 0;
729 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
730 int result=0;
731 U32 mainPause = 0;
732 char* programName;
733
734 /* Check command line */
735 programName = argv[0];
736 for(argNb=1; argNb<argc; argNb++)
737 {
738 char* argument = argv[argNb];
739
740 if(!argument) continue; /* Protection if argument empty */
741
742 /* Handle commands. Aggregated commands are allowed */
743 if (argument[0]=='-')
744 {
745 argument++;
746
747 while (*argument!=0)
748 {
749 switch(*argument)
750 {
751 case 'h':
752 return FUZ_usage(programName);
753 case 'v':
754 argument++;
755 g_displayLevel=4;
756 break;
757 case 'q':
758 argument++;
759 g_displayLevel--;
760 break;
761 case 'p': /* pause at the end */
762 argument++;
763 mainPause = 1;
764 break;
765
766 case 'i':
Yann Collet553cf6a2015-12-04 17:25:26 +0100767 argument++; g_testTime=0;
Yann Collet4856a002015-01-24 01:58:16 +0100768 nbTests=0;
769 while ((*argument>='0') && (*argument<='9'))
770 {
771 nbTests *= 10;
772 nbTests += *argument - '0';
773 argument++;
774 }
775 break;
776
Yann Collet553cf6a2015-12-04 17:25:26 +0100777 case 'T':
778 argument++;
779 nbTests=0; g_testTime=0;
780 while ((*argument>='0') && (*argument<='9'))
781 {
782 g_testTime *= 10;
783 g_testTime += *argument - '0';
784 argument++;
785 }
786 if (*argument=='m') g_testTime *=60, argument++;
787 if (*argument=='n') argument++;
788 g_testTime *= 1000;
789 break;
790
Yann Collet4856a002015-01-24 01:58:16 +0100791 case 's':
792 argument++;
793 seed=0;
794 seedset=1;
795 while ((*argument>='0') && (*argument<='9'))
796 {
797 seed *= 10;
798 seed += *argument - '0';
799 argument++;
800 }
801 break;
802
803 case 't':
804 argument++;
805 testNb=0;
806 while ((*argument>='0') && (*argument<='9'))
807 {
808 testNb *= 10;
809 testNb += *argument - '0';
810 argument++;
811 }
812 break;
813
814 case 'P': /* compressibility % */
815 argument++;
816 proba=0;
817 while ((*argument>='0') && (*argument<='9'))
818 {
819 proba *= 10;
820 proba += *argument - '0';
821 argument++;
822 }
823 if (proba<0) proba=0;
824 if (proba>100) proba=100;
825 break;
826
827 default:
828 return FUZ_usage(programName);
829 }
830 }
831 }
832 }
833
834 /* Get Seed */
835 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION);
836
837 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
838 DISPLAY("Seed = %u\n", seed);
839 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
840
Yann Collet4856a002015-01-24 01:58:16 +0100841 if (testNb==0) result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
842 if (!result)
843 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
844 if (mainPause)
845 {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800846 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100847 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800848 unused = getchar();
849 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100850 }
851 return result;
852}