blob: 6d57080d3f6ca7128939bcb29e81457d5c92cf20 [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 */
Yann Collet370b08e2016-03-08 00:03:59 +0100347 if (0)
Yann Collet4ba85342016-03-07 20:01:45 +0100348 {
349 #define _3BYTESTESTLENGTH 131000
350 #define NB3BYTESSEQLOG 9
351 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG)
352 #define NB3BYTESSEQMASK (NB3BYTESSEQ-1)
353 BYTE _3BytesSeqs[NB3BYTESSEQ][3];
354 U32 r = 1;
355 int i;
356
357 for (i=0; i < NB3BYTESSEQ; i++) {
358 _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&r) & 255);
359 _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&r) & 255);
360 _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&r) & 255);
361 }
362
363 for (i=0; i < _3BYTESTESTLENGTH; ){
364 U32 id = FUZ_rand(&r) & NB3BYTESSEQMASK;
365 ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0];
366 ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1];
367 ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2];
368 i += 3;
369 }
370
371 DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++);
372 result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19);
373 if (ZSTD_isError(result)) goto _output_error;
374 cSize = result;
375 DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100);
376
377 DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++);
378 result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize);
379 if (ZSTD_isError(result)) goto _output_error;
380 if (result != _3BYTESTESTLENGTH) goto _output_error;
381 DISPLAYLEVEL(4, "OK \n");
382 }
383
Yann Collet4856a002015-01-24 01:58:16 +0100384_end:
385 free(CNBuffer);
386 free(compressedBuffer);
387 free(decodedBuffer);
388 return testResult;
389
390_output_error:
391 testResult = 1;
392 DISPLAY("Error detected in Unit tests ! \n");
393 goto _end;
394}
395
396
397static size_t findDiff(const void* buf1, const void* buf2, size_t max)
398{
Yann Collet213089c2015-06-18 07:43:16 -0800399 const BYTE* b1 = (const BYTE*)buf1;
400 const BYTE* b2 = (const BYTE*)buf2;
Yann Collet4856a002015-01-24 01:58:16 +0100401 size_t i;
402 for (i=0; i<max; i++)
403 {
404 if (b1[i] != b2[i]) break;
405 }
406 return i;
407}
408
409# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
410 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
411
412static const U32 maxSrcLog = 23;
413static const U32 maxSampleLog = 22;
414
415int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility)
416{
Yann Colletd5d9bc32015-08-23 23:13:49 +0100417 BYTE* cNoiseBuffer[5];
Yann Collet4856a002015-01-24 01:58:16 +0100418 BYTE* srcBuffer;
419 BYTE* cBuffer;
420 BYTE* dstBuffer;
Yann Collete47c4e52015-12-05 09:23:53 +0100421 BYTE* mirrorBuffer;
Yann Collet4856a002015-01-24 01:58:16 +0100422 size_t srcBufferSize = (size_t)1<<maxSrcLog;
423 size_t dstBufferSize = (size_t)1<<maxSampleLog;
424 size_t cBufferSize = ZSTD_compressBound(dstBufferSize);
425 U32 result = 0;
426 U32 testNb = 0;
427 U32 coreSeed = seed, lseed = 0;
Yann Colletecd651b2016-01-07 15:35:18 +0100428 ZSTD_CCtx* refCtx;
Yann Collet2f648e52015-10-29 18:23:38 +0100429 ZSTD_CCtx* ctx;
Yann Collete47c4e52015-12-05 09:23:53 +0100430 ZSTD_DCtx* dctx;
Yann Collet553cf6a2015-12-04 17:25:26 +0100431 U32 startTime = FUZ_GetMilliStart();
Yann Collet4856a002015-01-24 01:58:16 +0100432
433 /* allocation */
Yann Colletecd651b2016-01-07 15:35:18 +0100434 refCtx = ZSTD_createCCtx();
Yann Collet2f648e52015-10-29 18:23:38 +0100435 ctx = ZSTD_createCCtx();
Yann Collete47c4e52015-12-05 09:23:53 +0100436 dctx= ZSTD_createDCtx();
Yann Colletd5d9bc32015-08-23 23:13:49 +0100437 cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
438 cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
439 cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
440 cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
441 cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800442 dstBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100443 mirrorBuffer = (BYTE*)malloc (dstBufferSize);
Yann Collet213089c2015-06-18 07:43:16 -0800444 cBuffer = (BYTE*)malloc (cBufferSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100445 CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4]
Yann Colletecd651b2016-01-07 15:35:18 +0100446 || !dstBuffer || !mirrorBuffer || !cBuffer || !refCtx || !ctx || !dctx,
Yann Colletd5d9bc32015-08-23 23:13:49 +0100447 "Not enough memory, fuzzer tests cancelled");
Yann Collet4856a002015-01-24 01:58:16 +0100448
Yann Colletd5d9bc32015-08-23 23:13:49 +0100449 /* Create initial samples */
450 RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed); /* pure noise */
451 RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed); /* barely compressible */
452 RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
453 RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed); /* highly compressible */
454 RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed); /* sparse content */
455 srcBuffer = cNoiseBuffer[2];
Yann Collet4856a002015-01-24 01:58:16 +0100456
457 /* catch up testNb */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100458 for (testNb=1; testNb < startTest; testNb++)
Yann Collet4856a002015-01-24 01:58:16 +0100459 FUZ_rand(&coreSeed);
460
461 /* test loop */
Yann Collet553cf6a2015-12-04 17:25:26 +0100462 for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime); testNb++ )
Yann Collet4856a002015-01-24 01:58:16 +0100463 {
Yann Collet417890c2015-12-04 17:16:37 +0100464 size_t sampleSize, sampleStart, maxTestSize, totalTestSize;
Yann Collete47c4e52015-12-05 09:23:53 +0100465 size_t cSize, dSize, dSupSize, errorCode, totalCSize, totalGenSize;
Yann Collet417890c2015-12-04 17:16:37 +0100466 U32 sampleSizeLog, buffNb, cLevelMod, nbChunks, n;
Yann Collet5835e1b2016-01-05 01:44:36 +0100467 XXH64_CREATESTATE_STATIC(xxh64);
Yann Collet4856a002015-01-24 01:58:16 +0100468 U64 crcOrig, crcDest;
Yann Collet2f648e52015-10-29 18:23:38 +0100469 int cLevel;
Yann Collet110cc142015-11-19 12:02:28 +0100470 BYTE* sampleBuffer;
Yann Collet4bfe4152015-12-06 13:18:37 +0100471 const BYTE* dict;
472 size_t dictSize;
Yann Collet4856a002015-01-24 01:58:16 +0100473
474 /* init */
Yann Collet1c2ddba2015-12-04 17:45:35 +0100475 if (nbTests >= testNb)
476 { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); }
477 else { DISPLAYUPDATE(2, "\r%6u ", testNb); }
478
Yann Collet4856a002015-01-24 01:58:16 +0100479 FUZ_rand(&coreSeed);
480 lseed = coreSeed ^ prime1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100481 buffNb = FUZ_rand(&lseed) & 127;
482 if (buffNb & 7) buffNb=2;
483 else
484 {
485 buffNb >>= 3;
486 if (buffNb & 7)
487 {
488 const U32 tnb[2] = { 1, 3 };
489 buffNb = tnb[buffNb >> 3];
490 }
491 else
492 {
493 const U32 tnb[2] = { 0, 4 };
494 buffNb = tnb[buffNb >> 3];
495 }
496 }
497 srcBuffer = cNoiseBuffer[buffNb];
Yann Collet4856a002015-01-24 01:58:16 +0100498 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
Yann Colletf4ce8912015-08-11 14:18:45 +0100499 sampleSize = (size_t)1 << sampleSizeLog;
Yann Collet4856a002015-01-24 01:58:16 +0100500 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
501 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
Yann Collet4856a002015-01-24 01:58:16 +0100502
Yann Collet110cc142015-11-19 12:02:28 +0100503 /* create sample buffer (to catch read error with valgrind & sanitizers) */
504 sampleBuffer = (BYTE*)malloc(sampleSize);
505 CHECK (sampleBuffer==NULL, "not enough memory for sample buffer");
506 memcpy(sampleBuffer, srcBuffer + sampleStart, sampleSize);
507 crcOrig = XXH64(sampleBuffer, sampleSize, 0);
508
509 /* compression test */
Yann Collete93add02016-02-15 17:44:14 +0100510 //cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */
511 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 +0100512 cLevel = (FUZ_rand(&lseed) % cLevelMod) +1;
Yann Colletdc5e3e92015-11-20 09:23:56 +0100513 cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100514 CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed");
Yann Collet4856a002015-01-24 01:58:16 +0100515
Yann Colletf3cb79b2015-08-20 00:02:43 +0100516 /* compression failure test : too small dest buffer */
Yann Colletd5d9bc32015-08-23 23:13:49 +0100517 if (cSize > 3)
Yann Collete9853b22015-08-07 19:07:32 +0100518 {
Yann Colletf4ce8912015-08-11 14:18:45 +0100519 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
520 const size_t tooSmallSize = cSize - missing;
Yann Collet602834f2015-08-20 07:46:10 +0100521 static const U32 endMark = 0x4DC2B1A9;
522 U32 endCheck;
523 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
Yann Colletdc5e3e92015-11-20 09:23:56 +0100524 errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100525 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 +0100526 memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
Yann Collet5be2dd22015-11-11 13:43:58 +0100527 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow");
Yann Collete9853b22015-08-07 19:07:32 +0100528 }
529
Yann Colletf3cb79b2015-08-20 00:02:43 +0100530 /* successfull decompression tests*/
Yann Collet4856a002015-01-24 01:58:16 +0100531 dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
532 dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize);
Yann Collet3e358272015-11-04 18:19:39 +0100533 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 +0100534 crcDest = XXH64(dstBuffer, sampleSize, 0);
Yann Collet110cc142015-11-19 12:02:28 +0100535 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
536
537 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100538
539 /* truncated src decompression test */
540 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100541 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
542 const size_t tooSmallSize = cSize - missing;
543 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100544 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100545 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Colletf3cb79b2015-08-20 00:02:43 +0100546 errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
547 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)");
548 free(cBufferTooSmall);
549 }
550
551 /* too small dst decompression test */
552 if (sampleSize > 3)
553 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100554 const size_t missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
555 const size_t tooSmallSize = sampleSize - missing;
556 static const BYTE token = 0xA9;
557 dstBuffer[tooSmallSize] = token;
558 errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
559 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed : %u > %u (dst buffer too small)", (U32)errorCode, (U32)tooSmallSize);
560 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
561 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100562
563 /* noisy src decompression test */
564 if (cSize > 6)
565 {
566 const U32 maxNbBits = FUZ_highbit32((U32)(cSize-4));
567 size_t pos = 4; /* preserve magic number (too easy to detect) */
568 U32 nbBits = FUZ_rand(&lseed) % maxNbBits;
569 size_t mask = (1<<nbBits) - 1;
570 size_t skipLength = FUZ_rand(&lseed) & mask;
571 pos += skipLength;
572
573 while (pos < cSize)
574 {
575 /* add noise */
576 size_t noiseStart, noiseLength;
577 nbBits = FUZ_rand(&lseed) % maxNbBits;
578 if (nbBits>0) nbBits--;
579 mask = (1<<nbBits) - 1;
580 noiseLength = (FUZ_rand(&lseed) & mask) + 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100581 if ( pos+noiseLength > cSize ) noiseLength = cSize-pos;
Yann Collet997f9ee2015-08-21 02:44:20 +0100582 noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
583 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
584 pos += noiseLength;
585
586 /* keep some original src */
587 nbBits = FUZ_rand(&lseed) % maxNbBits;
588 mask = (1<<nbBits) - 1;
589 skipLength = FUZ_rand(&lseed) & mask;
590 pos += skipLength;
591 }
592
593 /* decompress noisy source */
594 {
Yann Colletd5d9bc32015-08-23 23:13:49 +0100595 U32 noiseSrc = FUZ_rand(&lseed) % 5;
Yann Collet997f9ee2015-08-21 02:44:20 +0100596 const U32 endMark = 0xA9B1C3D6;
597 U32 endCheck;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100598 srcBuffer = cNoiseBuffer[noiseSrc];
Yann Collet997f9ee2015-08-21 02:44:20 +0100599 memcpy(dstBuffer+sampleSize, &endMark, 4);
600 errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
601 /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */
602 CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize),
603 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize);
604 memcpy(&endCheck, dstBuffer+sampleSize, 4);
605 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
606 }
607 }
Yann Collet417890c2015-12-04 17:16:37 +0100608
Yann Collete47c4e52015-12-05 09:23:53 +0100609 /* Streaming compression of scattered segments test */
Yann Collet5835e1b2016-01-05 01:44:36 +0100610 XXH64_reset(xxh64, 0);
Yann Collet417890c2015-12-04 17:16:37 +0100611 nbChunks = (FUZ_rand(&lseed) & 127) + 2;
612 sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog;
613 maxTestSize = (size_t)1 << sampleSizeLog;
614 maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1);
Yann Collete47c4e52015-12-05 09:23:53 +0100615 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
Yann Collet4bfe4152015-12-06 13:18:37 +0100616
617 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
618 sampleSize = (size_t)1 << sampleSizeLog;
619 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
620 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
621 dict = srcBuffer + sampleStart;
622 dictSize = sampleSize;
623
Yann Collet1c8e1942016-01-26 16:31:22 +0100624 errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1);
625 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
Yann Collet7b51a292016-01-26 15:58:49 +0100626 errorCode = ZSTD_copyCCtx(ctx, refCtx);
Yann Collet464fa992016-02-03 01:09:46 +0100627 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode));
Yann Colletecd651b2016-01-07 15:35:18 +0100628 totalTestSize = 0; cSize = 0;
Yann Collet417890c2015-12-04 17:16:37 +0100629 for (n=0; n<nbChunks; n++)
630 {
631 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
632 sampleSize = (size_t)1 << sampleSizeLog;
633 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
634 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
635
636 if (cBufferSize-cSize < ZSTD_compressBound(sampleSize))
637 /* avoid invalid dstBufferTooSmall */
638 break;
Yann Collete47c4e52015-12-05 09:23:53 +0100639 if (totalTestSize+sampleSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100640
641 errorCode = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+sampleStart, sampleSize);
642 CHECK (ZSTD_isError(errorCode), "multi-segments compression error : %s", ZSTD_getErrorName(errorCode));
643 cSize += errorCode;
644
Yann Collet5835e1b2016-01-05 01:44:36 +0100645 XXH64_update(xxh64, srcBuffer+sampleStart, sampleSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100646 memcpy(mirrorBuffer + totalTestSize, srcBuffer+sampleStart, sampleSize);
Yann Collet417890c2015-12-04 17:16:37 +0100647 totalTestSize += sampleSize;
Yann Collet417890c2015-12-04 17:16:37 +0100648 }
649 errorCode = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
650 CHECK (ZSTD_isError(errorCode), "multi-segments epilogue error : %s", ZSTD_getErrorName(errorCode));
651 cSize += errorCode;
Yann Collet5835e1b2016-01-05 01:44:36 +0100652 crcOrig = XXH64_digest(xxh64);
Yann Collete47c4e52015-12-05 09:23:53 +0100653
654 /* streaming decompression test */
Yann Collet7b51a292016-01-26 15:58:49 +0100655 errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100656 CHECK (ZSTD_isError(errorCode), "cannot init DCtx : %s", ZSTD_getErrorName(errorCode));
657 totalCSize = 0;
658 totalGenSize = 0;
659 while (totalCSize < cSize)
660 {
661 size_t inSize = ZSTD_nextSrcSizeToDecompress(dctx);
662 size_t genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
663 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
664 totalGenSize += genSize;
665 totalCSize += inSize;
666 }
667 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
668 CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size")
669 CHECK (totalCSize != cSize, "compressed data should be fully read")
670 crcDest = XXH64(dstBuffer, totalTestSize, 0);
671 if (crcDest!=crcOrig)
672 errorCode = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
673 CHECK (crcDest!=crcOrig, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
674 (U32)errorCode, (U32)totalTestSize, dstBuffer[errorCode], mirrorBuffer[errorCode]);
675
Yann Collet4856a002015-01-24 01:58:16 +0100676 }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100677 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100678
679_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100680 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100681 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100682 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100683 free(cNoiseBuffer[0]);
684 free(cNoiseBuffer[1]);
685 free(cNoiseBuffer[2]);
686 free(cNoiseBuffer[3]);
687 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100688 free(cBuffer);
689 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100690 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100691 return result;
692
693_output_error:
694 result = 1;
695 goto _cleanup;
696}
697
698
699/*********************************************************
700* Command line
701*********************************************************/
702int FUZ_usage(char* programName)
703{
704 DISPLAY( "Usage :\n");
705 DISPLAY( " %s [args]\n", programName);
706 DISPLAY( "\n");
707 DISPLAY( "Arguments :\n");
708 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
709 DISPLAY( " -s# : Select seed (default:prompt user)\n");
710 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collete9853b22015-08-07 19:07:32 +0100711 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
Yann Collet4856a002015-01-24 01:58:16 +0100712 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100713 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100714 DISPLAY( " -h : display help and exit\n");
715 return 0;
716}
717
718
719int main(int argc, char** argv)
720{
721 U32 seed=0;
722 int seedset=0;
723 int argNb;
724 int nbTests = nbTestsDefault;
725 int testNb = 0;
726 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
727 int result=0;
728 U32 mainPause = 0;
729 char* programName;
730
731 /* Check command line */
732 programName = argv[0];
733 for(argNb=1; argNb<argc; argNb++)
734 {
735 char* argument = argv[argNb];
736
737 if(!argument) continue; /* Protection if argument empty */
738
739 /* Handle commands. Aggregated commands are allowed */
740 if (argument[0]=='-')
741 {
742 argument++;
743
744 while (*argument!=0)
745 {
746 switch(*argument)
747 {
748 case 'h':
749 return FUZ_usage(programName);
750 case 'v':
751 argument++;
752 g_displayLevel=4;
753 break;
754 case 'q':
755 argument++;
756 g_displayLevel--;
757 break;
758 case 'p': /* pause at the end */
759 argument++;
760 mainPause = 1;
761 break;
762
763 case 'i':
Yann Collet553cf6a2015-12-04 17:25:26 +0100764 argument++; g_testTime=0;
Yann Collet4856a002015-01-24 01:58:16 +0100765 nbTests=0;
766 while ((*argument>='0') && (*argument<='9'))
767 {
768 nbTests *= 10;
769 nbTests += *argument - '0';
770 argument++;
771 }
772 break;
773
Yann Collet553cf6a2015-12-04 17:25:26 +0100774 case 'T':
775 argument++;
776 nbTests=0; g_testTime=0;
777 while ((*argument>='0') && (*argument<='9'))
778 {
779 g_testTime *= 10;
780 g_testTime += *argument - '0';
781 argument++;
782 }
783 if (*argument=='m') g_testTime *=60, argument++;
784 if (*argument=='n') argument++;
785 g_testTime *= 1000;
786 break;
787
Yann Collet4856a002015-01-24 01:58:16 +0100788 case 's':
789 argument++;
790 seed=0;
791 seedset=1;
792 while ((*argument>='0') && (*argument<='9'))
793 {
794 seed *= 10;
795 seed += *argument - '0';
796 argument++;
797 }
798 break;
799
800 case 't':
801 argument++;
802 testNb=0;
803 while ((*argument>='0') && (*argument<='9'))
804 {
805 testNb *= 10;
806 testNb += *argument - '0';
807 argument++;
808 }
809 break;
810
811 case 'P': /* compressibility % */
812 argument++;
813 proba=0;
814 while ((*argument>='0') && (*argument<='9'))
815 {
816 proba *= 10;
817 proba += *argument - '0';
818 argument++;
819 }
820 if (proba<0) proba=0;
821 if (proba>100) proba=100;
822 break;
823
824 default:
825 return FUZ_usage(programName);
826 }
827 }
828 }
829 }
830
831 /* Get Seed */
832 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION);
833
834 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
835 DISPLAY("Seed = %u\n", seed);
836 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
837
Yann Collet4856a002015-01-24 01:58:16 +0100838 if (testNb==0) result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
839 if (!result)
840 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
841 if (mainPause)
842 {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800843 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100844 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800845 unused = getchar();
846 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100847 }
848 return result;
849}