| | #include "unity/unity.h" |
| | #include "zlib.h" |
| | #include "deflate.h" |
| | #include <string.h> |
| | #include <stdlib.h> |
| |
|
| | |
| | extern uInt test_longest_match(deflate_state *s, IPos cur_match); |
| |
|
| | static z_stream g_strm; |
| | static deflate_state *S; |
| |
|
| | void setUp(void) { |
| | memset(&g_strm, 0, sizeof(g_strm)); |
| | int ret = deflateInit(&g_strm, Z_DEFAULT_COMPRESSION); |
| | TEST_ASSERT_EQUAL_INT(Z_OK, ret); |
| | S = (deflate_state *)g_strm.state; |
| | TEST_ASSERT_NOT_NULL(S); |
| | } |
| |
|
| | void tearDown(void) { |
| | deflateEnd(&g_strm); |
| | } |
| |
|
| | |
| | static void prepare_positions(IPos *out_strstart, IPos *out_cur, uInt back_distance) { |
| | |
| | IPos strstart = (IPos)(S->w_size); |
| | IPos cur = strstart - (IPos)back_distance; |
| | TEST_ASSERT_TRUE_MESSAGE(cur >= 1, "cur_match must be >= 1"); |
| | *out_strstart = strstart; |
| | *out_cur = cur; |
| | } |
| |
|
| | |
| | void test_longest_match_basic_match(void) { |
| | IPos strstart, cur; |
| | prepare_positions(&strstart, &cur, 100); |
| |
|
| | const uInt L = 10; |
| | |
| | for (uInt i = 0; i < L; i++) { |
| | Byte b = (Byte)('A' + (i % 3)); |
| | S->window[strstart + i] = b; |
| | S->window[cur + i] = b; |
| | } |
| | |
| | S->window[strstart + L] = 'X'; |
| | S->window[cur + L] = 'Y'; |
| |
|
| | |
| | for (uInt i = L + 1; i <= MAX_MATCH + 5; i++) { |
| | S->window[strstart + i] = 0; |
| | S->window[cur + i] = 0; |
| | } |
| |
|
| | S->strstart = strstart; |
| | S->lookahead = L + 10; |
| |
|
| | |
| | S->prev[cur & S->w_mask] = NIL; |
| |
|
| | uInt got = test_longest_match(S, cur); |
| | TEST_ASSERT_EQUAL_UINT(L, got); |
| | TEST_ASSERT_EQUAL_UINT(cur, S->match_start); |
| | } |
| |
|
| | |
| | void test_longest_match_capped_by_lookahead(void) { |
| | IPos strstart, cur; |
| | prepare_positions(&strstart, &cur, 200); |
| |
|
| | const uInt actual_match_len = 50; |
| | const uInt lookahead = 20; |
| |
|
| | |
| | for (uInt i = 0; i < actual_match_len + 5; i++) { |
| | Byte b = (Byte)('M' + (i % 5)); |
| | S->window[strstart + i] = b; |
| | S->window[cur + i] = b; |
| | } |
| | |
| | S->window[strstart + actual_match_len + 6] = 'p'; |
| | S->window[cur + actual_match_len + 6] = 'q'; |
| |
|
| | for (uInt i = actual_match_len + 7; i <= MAX_MATCH + 10; i++) { |
| | S->window[strstart + i] = 0; |
| | S->window[cur + i] = 0; |
| | } |
| |
|
| | S->strstart = strstart; |
| | S->lookahead = lookahead; |
| |
|
| | S->prev[cur & S->w_mask] = NIL; |
| |
|
| | uInt got = test_longest_match(S, cur); |
| | TEST_ASSERT_EQUAL_UINT(lookahead, got); |
| | TEST_ASSERT_EQUAL_UINT(cur, S->match_start); |
| | } |
| |
|
| | |
| | void test_longest_match_no_match_returns_prev_length(void) { |
| | IPos strstart, cur; |
| | prepare_positions(&strstart, &cur, 50); |
| |
|
| | |
| | S->window[strstart + 0] = 'A'; |
| | S->window[cur + 0] = 'B'; |
| | S->window[strstart + 1] = 'C'; |
| | S->window[cur + 1] = 'D'; |
| | S->window[strstart + 2] = 'E'; |
| | S->window[cur + 2] = 'F'; |
| |
|
| | for (uInt i = 3; i <= MAX_MATCH + 5; i++) { |
| | S->window[strstart + i] = (Byte)0; |
| | S->window[cur + i] = (Byte)0; |
| | } |
| |
|
| | S->strstart = strstart; |
| | S->lookahead = 100; |
| |
|
| | S->prev[cur & S->w_mask] = NIL; |
| |
|
| | |
| | TEST_ASSERT_EQUAL_UINT(MIN_MATCH - 1, S->prev_length); |
| |
|
| | uInt got = test_longest_match(S, cur); |
| | TEST_ASSERT_EQUAL_UINT(MIN_MATCH - 1, got); |
| | |
| | } |
| |
|
| | |
| | void test_longest_match_discards_shorter_than_prev_length(void) { |
| | IPos strstart, cur; |
| | prepare_positions(&strstart, &cur, 120); |
| |
|
| | const uInt shorter_match = 10; |
| | |
| | for (uInt i = 0; i < shorter_match; i++) { |
| | Byte b = (Byte)('Z' - (i % 3)); |
| | S->window[strstart + i] = b; |
| | S->window[cur + i] = b; |
| | } |
| | S->window[strstart + shorter_match] = 'x'; |
| | S->window[cur + shorter_match] = 'y'; |
| |
|
| | for (uInt i = shorter_match + 1; i <= MAX_MATCH + 5; i++) { |
| | S->window[strstart + i] = (Byte)0; |
| | S->window[cur + i] = (Byte)0; |
| | } |
| |
|
| | S->strstart = strstart; |
| | S->lookahead = 40; |
| |
|
| | |
| | S->prev_length = 15; |
| |
|
| | S->prev[cur & S->w_mask] = NIL; |
| |
|
| | uInt got = test_longest_match(S, cur); |
| | TEST_ASSERT_EQUAL_UINT(15, got); |
| | |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_longest_match_basic_match); |
| | RUN_TEST(test_longest_match_capped_by_lookahead); |
| | RUN_TEST(test_longest_match_no_match_returns_prev_length); |
| | RUN_TEST(test_longest_match_discards_shorter_than_prev_length); |
| | return UNITY_END(); |
| | } |