More debug code moving.
[fjl] / dehuff_test.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4
5 #include "dehuff.h"
6
7 struct custom_read_userdata {
8         uint8_t* bytes;
9         unsigned bytes_left;
10 };
11
12 ssize_t custom_read(void* userdata, uint8_t* buf, size_t count)
13 {
14         struct custom_read_userdata* ud = (struct custom_read_userdata*)userdata;
15         size_t num_to_read = (ud->bytes_left > count ? count : ud->bytes_left);
16         memcpy(buf, ud->bytes, num_to_read);
17         ud->bytes += num_to_read;
18         ud->bytes_left -= num_to_read;
19         return num_to_read;     
20 }
21
22 // The example from section K.3.1 from the JPEG standard.
23 uint8_t example_table_bytes[] = {
24         // Chunk length: Chunk length (2) + coefficient class (1) + 
25         // code lengths (16) + code words (12)
26         0, 31, 
27
28         // DC coefficient, table 0
29         0x00,
30
31         // List of code lengths
32         0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33
34         // Code words
35         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
36 };
37
38 void read_example_tables(huffman_tables_t* tables)
39 {
40         struct custom_read_userdata ud;
41         ud.bytes = example_table_bytes;
42         ud.bytes_left = sizeof(example_table_bytes);
43
44         read_huffman_tables(tables, custom_read, &ud);
45 }       
46
47 // Test that the generated code tables are what we expect.
48 void test_table_gen()
49 {
50         huffman_tables_t tables;
51         read_example_tables(&tables);
52
53         // Expected results (table K.3)
54         struct {
55                 unsigned code_length;
56                 unsigned code_word;
57         } expected_table[12] = {
58                 { 2, 0x0 },
59                 { 3, 0x2 },
60                 { 3, 0x3 },
61                 { 3, 0x4 },
62                 { 3, 0x5 },
63                 { 3, 0x6 },
64                 { 4, 0xe },
65                 { 5, 0x1e },
66                 { 6, 0x3e },
67                 { 7, 0x7e },
68                 { 8, 0xfe },
69                 { 9, 0x1fe },
70         };
71         
72         struct huffman_table* tbl = &tables[DC_CLASS][0];       
73         for (unsigned i = 0; i < 12; ++i) {
74                 assert(tbl->huffsize[i] == expected_table[i].code_length);
75                 assert(tbl->huffcode[i] == expected_table[i].code_word);
76         }
77 }
78
79 // Test that we can decode a simple bit stream.
80 // Note that since we end on a long code, we won't crash into
81 // the end-of-stream problems we have without padding.
82 void test_decoding()
83 {
84         huffman_tables_t tables;
85         read_example_tables(&tables);
86         
87         // Our stream looks like this:
88         //
89         //  0   1   2   3   4   5    6     7      8       9       10        11
90         // 00 010 011 100 101 110 1110 11110 111110 1111110 11111110 111111110
91         uint8_t bytes[] = {
92                 0x13, 0x97, 0x77, 0xbe, 0xfd, 0xfd, 0xfe
93         };
94
95         struct custom_read_userdata ud;
96         ud.bytes = bytes;
97         ud.bytes_left = sizeof(bytes);
98
99         struct bit_source source;
100         init_bit_source(&source, custom_read, 0, &ud);
101                 
102         struct huffman_table* tbl = &tables[DC_CLASS][0];       
103         for (unsigned i = 0; i < 12; ++i) {
104                 unsigned symbol = read_huffman_symbol(tbl, &source);
105                 assert(symbol == i);
106         }
107
108         assert(source.bits_available == 0);
109 }
110
111 // Test that we can decode a bit stream that ends on a short code,
112 // if we've got padding.
113 void test_padded_decoding()
114 {
115         huffman_tables_t tables;
116         read_example_tables(&tables);
117         
118         // Our stream looks like this:
119         //
120         //  0   1   2   3   4
121         // 00 010 011 100 101
122         uint8_t bytes[] = {
123                 0x13, 0x94
124         };
125
126         struct custom_read_userdata ud;
127         ud.bytes = bytes;
128         ud.bytes_left = sizeof(bytes);
129
130         struct bit_source source;
131         init_bit_source(&source, custom_read, 2, &ud);
132                 
133         struct huffman_table* tbl = &tables[DC_CLASS][0];       
134         for (unsigned i = 0; i < 5; ++i) {
135                 unsigned symbol = read_huffman_symbol(tbl, &source);
136                 assert(symbol == i);
137         }
138 }
139
140 int main(void)
141 {
142         printf("test_table_gen()\n");
143         test_table_gen();
144         
145         printf("test_decoding()\n");
146         test_decoding();
147         
148         printf("test_padded_decoding()\n");
149         test_padded_decoding();
150         
151         printf("All tests pass.\n");
152         return 0;
153 }