1///////////////////////////////////////////////////////////////////////////////
2//
3/// \file       test_filter_flags.c
4/// \brief      Tests Filter Flags coders
5//
6//  Author:     Lasse Collin
7//
8//  This file has been put into the public domain.
9//  You can do whatever you want with this file.
10//
11///////////////////////////////////////////////////////////////////////////////
12
13#include "tests.h"
14
15
16static uint8_t buffer[4096];
17static lzma_filter known_flags;
18static lzma_filter decoded_flags;
19static lzma_stream strm = LZMA_STREAM_INIT;
20
21
22static bool
23encode(uint32_t known_size)
24{
25	memcrap(buffer, sizeof(buffer));
26
27	uint32_t tmp;
28	if (lzma_filter_flags_size(&tmp, &known_flags) != LZMA_OK)
29		return true;
30
31	if (tmp != known_size)
32		return true;
33
34	size_t out_pos = 0;
35	if (lzma_filter_flags_encode(&known_flags,
36			buffer, &out_pos, known_size) != LZMA_OK)
37		return true;
38
39	if (out_pos != known_size)
40		return true;
41
42	return false;
43}
44
45
46static bool
47decode_ret(uint32_t known_size, lzma_ret expected_ret)
48{
49	memcrap(&decoded_flags, sizeof(decoded_flags));
50
51	size_t pos = 0;
52	if (lzma_filter_flags_decode(&decoded_flags, NULL,
53				buffer, &pos, known_size) != expected_ret
54			|| pos != known_size)
55		return true;
56
57	return false;
58}
59
60
61static bool
62decode(uint32_t known_size)
63{
64	if (decode_ret(known_size, LZMA_OK))
65		return true;
66
67	if (known_flags.id != decoded_flags.id)
68		return true;
69
70	return false;
71}
72
73
74#if defined(HAVE_ENCODER_X86) && defined(HAVE_DECODER_X86)
75static void
76test_bcj(void)
77{
78	// Test 1
79	known_flags.id = LZMA_FILTER_X86;
80	known_flags.options = NULL;
81
82	expect(!encode(2));
83	expect(!decode(2));
84	expect(decoded_flags.options == NULL);
85
86	// Test 2
87	lzma_options_bcj options;
88	options.start_offset = 0;
89	known_flags.options = &options;
90	expect(!encode(2));
91	expect(!decode(2));
92	expect(decoded_flags.options == NULL);
93
94	// Test 3
95	options.start_offset = 123456;
96	known_flags.options = &options;
97	expect(!encode(6));
98	expect(!decode(6));
99	expect(decoded_flags.options != NULL);
100
101	lzma_options_bcj *decoded = decoded_flags.options;
102	expect(decoded->start_offset == options.start_offset);
103
104	free(decoded);
105}
106#endif
107
108
109#if defined(HAVE_ENCODER_DELTA) && defined(HAVE_DECODER_DELTA)
110static void
111test_delta(void)
112{
113	// Test 1
114	known_flags.id = LZMA_FILTER_DELTA;
115	known_flags.options = NULL;
116	expect(encode(99));
117
118	// Test 2
119	lzma_options_delta options = {
120		.type = LZMA_DELTA_TYPE_BYTE,
121		.dist = 0
122	};
123	known_flags.options = &options;
124	expect(encode(99));
125
126	// Test 3
127	options.dist = LZMA_DELTA_DIST_MIN;
128	expect(!encode(3));
129	expect(!decode(3));
130	expect(((lzma_options_delta *)(decoded_flags.options))->dist
131			== options.dist);
132
133	free(decoded_flags.options);
134
135	// Test 4
136	options.dist = LZMA_DELTA_DIST_MAX;
137	expect(!encode(3));
138	expect(!decode(3));
139	expect(((lzma_options_delta *)(decoded_flags.options))->dist
140			== options.dist);
141
142	free(decoded_flags.options);
143
144	// Test 5
145	options.dist = LZMA_DELTA_DIST_MAX + 1;
146	expect(encode(99));
147}
148#endif
149
150/*
151#ifdef HAVE_FILTER_LZMA
152static void
153validate_lzma(void)
154{
155	const lzma_options_lzma *known = known_flags.options;
156	const lzma_options_lzma *decoded = decoded_flags.options;
157
158	expect(known->dictionary_size <= decoded->dictionary_size);
159
160	if (known->dictionary_size == 1)
161		expect(decoded->dictionary_size == 1);
162	else
163		expect(known->dictionary_size + known->dictionary_size / 2
164				> decoded->dictionary_size);
165
166	expect(known->literal_context_bits == decoded->literal_context_bits);
167	expect(known->literal_pos_bits == decoded->literal_pos_bits);
168	expect(known->pos_bits == decoded->pos_bits);
169}
170
171
172static void
173test_lzma(void)
174{
175	// Test 1
176	known_flags.id = LZMA_FILTER_LZMA1;
177	known_flags.options = NULL;
178	expect(encode(99));
179
180	// Test 2
181	lzma_options_lzma options = {
182		.dictionary_size = 0,
183		.literal_context_bits = 0,
184		.literal_pos_bits = 0,
185		.pos_bits = 0,
186		.preset_dictionary = NULL,
187		.preset_dictionary_size = 0,
188		.mode = LZMA_MODE_INVALID,
189		.fast_bytes = 0,
190		.match_finder = LZMA_MF_INVALID,
191		.match_finder_cycles = 0,
192	};
193
194	// Test 3 (empty dictionary not allowed)
195	known_flags.options = &options;
196	expect(encode(99));
197
198	// Test 4 (brute-force test some valid dictionary sizes)
199	options.dictionary_size = LZMA_DICTIONARY_SIZE_MIN;
200	while (options.dictionary_size != LZMA_DICTIONARY_SIZE_MAX) {
201		if (++options.dictionary_size == 5000)
202			options.dictionary_size = LZMA_DICTIONARY_SIZE_MAX - 5;
203
204		expect(!encode(4));
205		expect(!decode(4));
206		validate_lzma();
207
208		free(decoded_flags.options);
209	}
210
211	// Test 5 (too big dictionary size)
212	options.dictionary_size = LZMA_DICTIONARY_SIZE_MAX + 1;
213	expect(encode(99));
214
215	// Test 6 (brute-force test lc/lp/pb)
216	options.dictionary_size = LZMA_DICTIONARY_SIZE_MIN;
217	for (uint32_t lc = LZMA_LITERAL_CONTEXT_BITS_MIN;
218			lc <= LZMA_LITERAL_CONTEXT_BITS_MAX; ++lc) {
219		for (uint32_t lp = LZMA_LITERAL_POS_BITS_MIN;
220				lp <= LZMA_LITERAL_POS_BITS_MAX; ++lp) {
221			for (uint32_t pb = LZMA_POS_BITS_MIN;
222					pb <= LZMA_POS_BITS_MAX; ++pb) {
223				if (lc + lp > LZMA_LITERAL_BITS_MAX)
224					continue;
225
226				options.literal_context_bits = lc;
227				options.literal_pos_bits = lp;
228				options.pos_bits = pb;
229
230				expect(!encode(4));
231				expect(!decode(4));
232				validate_lzma();
233
234				free(decoded_flags.options);
235			}
236		}
237	}
238}
239#endif
240*/
241
242int
243main(void)
244{
245#if defined(HAVE_ENCODER_X86) && defined(HAVE_DECODER_X86)
246	test_bcj();
247#endif
248#if defined(HAVE_ENCODER_DELTA) && defined(HAVE_DECODER_DELTA)
249	test_delta();
250#endif
251// #ifdef HAVE_FILTER_LZMA
252// 	test_lzma();
253// #endif
254
255	lzma_end(&strm);
256
257	return 0;
258}
259