blob: 697695b382b70e5d5e3c067524172070ecd1ba8c [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 Colletd5d9bc32015-08-23 23:13:49 +0100516 if (cSize > 3)
Yann Collete9853b22015-08-07 19:07:32 +0100517 {
Yann Colletf4ce8912015-08-11 14:18:45 +0100518 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
519 const size_t tooSmallSize = cSize - missing;
Yann Collet602834f2015-08-20 07:46:10 +0100520 static const U32 endMark = 0x4DC2B1A9;
521 U32 endCheck;
522 memcpy(dstBuffer+tooSmallSize, &endMark, 4);
Yann Colletdc5e3e92015-11-20 09:23:56 +0100523 errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel);
Yann Collet5be2dd22015-11-11 13:43:58 +0100524 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 +0100525 memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
Yann Collet5be2dd22015-11-11 13:43:58 +0100526 CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow");
Yann Collete9853b22015-08-07 19:07:32 +0100527 }
528
Yann Colletf3cb79b2015-08-20 00:02:43 +0100529 /* successfull decompression tests*/
Yann Collet4856a002015-01-24 01:58:16 +0100530 dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
531 dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize);
Yann Collet3e358272015-11-04 18:19:39 +0100532 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 +0100533 crcDest = XXH64(dstBuffer, sampleSize, 0);
Yann Collet110cc142015-11-19 12:02:28 +0100534 CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize);
535
536 free(sampleBuffer); /* no longer useful after this point */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100537
538 /* truncated src decompression test */
539 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100540 const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
541 const size_t tooSmallSize = cSize - missing;
542 void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */
Yann Colletf3cb79b2015-08-20 00:02:43 +0100543 CHECK(cBufferTooSmall == NULL, "not enough memory !");
Yann Colletd5d9bc32015-08-23 23:13:49 +0100544 memcpy(cBufferTooSmall, cBuffer, tooSmallSize);
Yann Colletf3cb79b2015-08-20 00:02:43 +0100545 errorCode = ZSTD_decompress(dstBuffer, dstBufferSize, cBufferTooSmall, tooSmallSize);
546 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed ! (truncated src buffer)");
547 free(cBufferTooSmall);
548 }
549
550 /* too small dst decompression test */
551 if (sampleSize > 3)
552 {
Yann Colletf3cb79b2015-08-20 00:02:43 +0100553 const size_t missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */
554 const size_t tooSmallSize = sampleSize - missing;
555 static const BYTE token = 0xA9;
556 dstBuffer[tooSmallSize] = token;
557 errorCode = ZSTD_decompress(dstBuffer, tooSmallSize, cBuffer, cSize);
558 CHECK(!ZSTD_isError(errorCode), "ZSTD_decompress should have failed : %u > %u (dst buffer too small)", (U32)errorCode, (U32)tooSmallSize);
559 CHECK(dstBuffer[tooSmallSize] != token, "ZSTD_decompress : dst buffer overflow");
560 }
Yann Collet997f9ee2015-08-21 02:44:20 +0100561
562 /* noisy src decompression test */
563 if (cSize > 6)
564 {
565 const U32 maxNbBits = FUZ_highbit32((U32)(cSize-4));
566 size_t pos = 4; /* preserve magic number (too easy to detect) */
567 U32 nbBits = FUZ_rand(&lseed) % maxNbBits;
568 size_t mask = (1<<nbBits) - 1;
569 size_t skipLength = FUZ_rand(&lseed) & mask;
570 pos += skipLength;
571
572 while (pos < cSize)
573 {
574 /* add noise */
575 size_t noiseStart, noiseLength;
576 nbBits = FUZ_rand(&lseed) % maxNbBits;
577 if (nbBits>0) nbBits--;
578 mask = (1<<nbBits) - 1;
579 noiseLength = (FUZ_rand(&lseed) & mask) + 1;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100580 if ( pos+noiseLength > cSize ) noiseLength = cSize-pos;
Yann Collet997f9ee2015-08-21 02:44:20 +0100581 noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength);
582 memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength);
583 pos += noiseLength;
584
585 /* keep some original src */
586 nbBits = FUZ_rand(&lseed) % maxNbBits;
587 mask = (1<<nbBits) - 1;
588 skipLength = FUZ_rand(&lseed) & mask;
589 pos += skipLength;
590 }
591
592 /* decompress noisy source */
593 {
Yann Colletd5d9bc32015-08-23 23:13:49 +0100594 U32 noiseSrc = FUZ_rand(&lseed) % 5;
Yann Collet997f9ee2015-08-21 02:44:20 +0100595 const U32 endMark = 0xA9B1C3D6;
596 U32 endCheck;
Yann Colletd5d9bc32015-08-23 23:13:49 +0100597 srcBuffer = cNoiseBuffer[noiseSrc];
Yann Collet997f9ee2015-08-21 02:44:20 +0100598 memcpy(dstBuffer+sampleSize, &endMark, 4);
599 errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize);
600 /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */
601 CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize),
602 "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize);
603 memcpy(&endCheck, dstBuffer+sampleSize, 4);
604 CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow");
605 }
606 }
Yann Collet417890c2015-12-04 17:16:37 +0100607
Yann Collete47c4e52015-12-05 09:23:53 +0100608 /* Streaming compression of scattered segments test */
Yann Collet5835e1b2016-01-05 01:44:36 +0100609 XXH64_reset(xxh64, 0);
Yann Collet417890c2015-12-04 17:16:37 +0100610 nbChunks = (FUZ_rand(&lseed) & 127) + 2;
611 sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog;
612 maxTestSize = (size_t)1 << sampleSizeLog;
613 maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1);
Yann Collete47c4e52015-12-05 09:23:53 +0100614 if (maxTestSize >= dstBufferSize) maxTestSize = dstBufferSize-1;
Yann Collet4bfe4152015-12-06 13:18:37 +0100615
616 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
617 sampleSize = (size_t)1 << sampleSizeLog;
618 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
619 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
620 dict = srcBuffer + sampleStart;
621 dictSize = sampleSize;
622
Yann Collet1c8e1942016-01-26 16:31:22 +0100623 errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1);
624 CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode));
Yann Collet7b51a292016-01-26 15:58:49 +0100625 errorCode = ZSTD_copyCCtx(ctx, refCtx);
Yann Collet464fa992016-02-03 01:09:46 +0100626 CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode));
Yann Colletecd651b2016-01-07 15:35:18 +0100627 totalTestSize = 0; cSize = 0;
Yann Collet417890c2015-12-04 17:16:37 +0100628 for (n=0; n<nbChunks; n++)
629 {
630 sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog;
631 sampleSize = (size_t)1 << sampleSizeLog;
632 sampleSize += FUZ_rand(&lseed) & (sampleSize-1);
633 sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize);
634
635 if (cBufferSize-cSize < ZSTD_compressBound(sampleSize))
636 /* avoid invalid dstBufferTooSmall */
637 break;
Yann Collete47c4e52015-12-05 09:23:53 +0100638 if (totalTestSize+sampleSize > maxTestSize) break;
Yann Collet417890c2015-12-04 17:16:37 +0100639
640 errorCode = ZSTD_compressContinue(ctx, cBuffer+cSize, cBufferSize-cSize, srcBuffer+sampleStart, sampleSize);
641 CHECK (ZSTD_isError(errorCode), "multi-segments compression error : %s", ZSTD_getErrorName(errorCode));
642 cSize += errorCode;
643
Yann Collet5835e1b2016-01-05 01:44:36 +0100644 XXH64_update(xxh64, srcBuffer+sampleStart, sampleSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100645 memcpy(mirrorBuffer + totalTestSize, srcBuffer+sampleStart, sampleSize);
Yann Collet417890c2015-12-04 17:16:37 +0100646 totalTestSize += sampleSize;
Yann Collet417890c2015-12-04 17:16:37 +0100647 }
648 errorCode = ZSTD_compressEnd(ctx, cBuffer+cSize, cBufferSize-cSize);
649 CHECK (ZSTD_isError(errorCode), "multi-segments epilogue error : %s", ZSTD_getErrorName(errorCode));
650 cSize += errorCode;
Yann Collet5835e1b2016-01-05 01:44:36 +0100651 crcOrig = XXH64_digest(xxh64);
Yann Collete47c4e52015-12-05 09:23:53 +0100652
653 /* streaming decompression test */
Yann Collet7b51a292016-01-26 15:58:49 +0100654 errorCode = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
Yann Collete47c4e52015-12-05 09:23:53 +0100655 CHECK (ZSTD_isError(errorCode), "cannot init DCtx : %s", ZSTD_getErrorName(errorCode));
656 totalCSize = 0;
657 totalGenSize = 0;
658 while (totalCSize < cSize)
659 {
660 size_t inSize = ZSTD_nextSrcSizeToDecompress(dctx);
661 size_t genSize = ZSTD_decompressContinue(dctx, dstBuffer+totalGenSize, dstBufferSize-totalGenSize, cBuffer+totalCSize, inSize);
662 CHECK (ZSTD_isError(genSize), "streaming decompression error : %s", ZSTD_getErrorName(genSize));
663 totalGenSize += genSize;
664 totalCSize += inSize;
665 }
666 CHECK (ZSTD_nextSrcSizeToDecompress(dctx) != 0, "frame not fully decoded");
667 CHECK (totalGenSize != totalTestSize, "decompressed data : wrong size")
668 CHECK (totalCSize != cSize, "compressed data should be fully read")
669 crcDest = XXH64(dstBuffer, totalTestSize, 0);
670 if (crcDest!=crcOrig)
671 errorCode = findDiff(mirrorBuffer, dstBuffer, totalTestSize);
672 CHECK (crcDest!=crcOrig, "streaming decompressed data corrupted : byte %u / %u (%02X!=%02X)",
673 (U32)errorCode, (U32)totalTestSize, dstBuffer[errorCode], mirrorBuffer[errorCode]);
674
Yann Collet4856a002015-01-24 01:58:16 +0100675 }
Yann Collet1c2ddba2015-12-04 17:45:35 +0100676 DISPLAY("\r%u fuzzer tests completed \n", testNb-1);
Yann Collet4856a002015-01-24 01:58:16 +0100677
678_cleanup:
Yann Colletecd651b2016-01-07 15:35:18 +0100679 ZSTD_freeCCtx(refCtx);
Yann Collet2f648e52015-10-29 18:23:38 +0100680 ZSTD_freeCCtx(ctx);
Yann Collete47c4e52015-12-05 09:23:53 +0100681 ZSTD_freeDCtx(dctx);
Yann Colletd5d9bc32015-08-23 23:13:49 +0100682 free(cNoiseBuffer[0]);
683 free(cNoiseBuffer[1]);
684 free(cNoiseBuffer[2]);
685 free(cNoiseBuffer[3]);
686 free(cNoiseBuffer[4]);
Yann Collet4856a002015-01-24 01:58:16 +0100687 free(cBuffer);
688 free(dstBuffer);
Yann Collete47c4e52015-12-05 09:23:53 +0100689 free(mirrorBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100690 return result;
691
692_output_error:
693 result = 1;
694 goto _cleanup;
695}
696
697
698/*********************************************************
699* Command line
700*********************************************************/
701int FUZ_usage(char* programName)
702{
703 DISPLAY( "Usage :\n");
704 DISPLAY( " %s [args]\n", programName);
705 DISPLAY( "\n");
706 DISPLAY( "Arguments :\n");
707 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
708 DISPLAY( " -s# : Select seed (default:prompt user)\n");
709 DISPLAY( " -t# : Select starting test number (default:0)\n");
Yann Collete9853b22015-08-07 19:07:32 +0100710 DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
Yann Collet4856a002015-01-24 01:58:16 +0100711 DISPLAY( " -v : verbose\n");
Yann Collete9853b22015-08-07 19:07:32 +0100712 DISPLAY( " -p : pause at the end\n");
Yann Collet4856a002015-01-24 01:58:16 +0100713 DISPLAY( " -h : display help and exit\n");
714 return 0;
715}
716
717
718int main(int argc, char** argv)
719{
720 U32 seed=0;
721 int seedset=0;
722 int argNb;
723 int nbTests = nbTestsDefault;
724 int testNb = 0;
725 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
726 int result=0;
727 U32 mainPause = 0;
728 char* programName;
729
730 /* Check command line */
731 programName = argv[0];
732 for(argNb=1; argNb<argc; argNb++)
733 {
734 char* argument = argv[argNb];
735
736 if(!argument) continue; /* Protection if argument empty */
737
738 /* Handle commands. Aggregated commands are allowed */
739 if (argument[0]=='-')
740 {
741 argument++;
742
743 while (*argument!=0)
744 {
745 switch(*argument)
746 {
747 case 'h':
748 return FUZ_usage(programName);
749 case 'v':
750 argument++;
751 g_displayLevel=4;
752 break;
753 case 'q':
754 argument++;
755 g_displayLevel--;
756 break;
757 case 'p': /* pause at the end */
758 argument++;
759 mainPause = 1;
760 break;
761
762 case 'i':
Yann Collet553cf6a2015-12-04 17:25:26 +0100763 argument++; g_testTime=0;
Yann Collet4856a002015-01-24 01:58:16 +0100764 nbTests=0;
765 while ((*argument>='0') && (*argument<='9'))
766 {
767 nbTests *= 10;
768 nbTests += *argument - '0';
769 argument++;
770 }
771 break;
772
Yann Collet553cf6a2015-12-04 17:25:26 +0100773 case 'T':
774 argument++;
775 nbTests=0; g_testTime=0;
776 while ((*argument>='0') && (*argument<='9'))
777 {
778 g_testTime *= 10;
779 g_testTime += *argument - '0';
780 argument++;
781 }
782 if (*argument=='m') g_testTime *=60, argument++;
783 if (*argument=='n') argument++;
784 g_testTime *= 1000;
785 break;
786
Yann Collet4856a002015-01-24 01:58:16 +0100787 case 's':
788 argument++;
789 seed=0;
790 seedset=1;
791 while ((*argument>='0') && (*argument<='9'))
792 {
793 seed *= 10;
794 seed += *argument - '0';
795 argument++;
796 }
797 break;
798
799 case 't':
800 argument++;
801 testNb=0;
802 while ((*argument>='0') && (*argument<='9'))
803 {
804 testNb *= 10;
805 testNb += *argument - '0';
806 argument++;
807 }
808 break;
809
810 case 'P': /* compressibility % */
811 argument++;
812 proba=0;
813 while ((*argument>='0') && (*argument<='9'))
814 {
815 proba *= 10;
816 proba += *argument - '0';
817 argument++;
818 }
819 if (proba<0) proba=0;
820 if (proba>100) proba=100;
821 break;
822
823 default:
824 return FUZ_usage(programName);
825 }
826 }
827 }
828 }
829
830 /* Get Seed */
831 DISPLAY("Starting zstd tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION);
832
833 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
834 DISPLAY("Seed = %u\n", seed);
835 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
836
Yann Collet4856a002015-01-24 01:58:16 +0100837 if (testNb==0) result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */
838 if (!result)
839 result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
840 if (mainPause)
841 {
Yann Colletb5e06dc2015-07-04 23:20:56 -0800842 int unused;
Yann Collet4856a002015-01-24 01:58:16 +0100843 DISPLAY("Press Enter \n");
Yann Colletb5e06dc2015-07-04 23:20:56 -0800844 unused = getchar();
845 (void)unused;
Yann Collet4856a002015-01-24 01:58:16 +0100846 }
847 return result;
848}