1 #include "maxminddb_test_helper.h"
2 
test_metadata(MMDB_s * mmdb,const char * mode_desc)3 void test_metadata(MMDB_s *mmdb, const char *mode_desc) {
4     cmp_ok(mmdb->metadata.node_count,
5            "==",
6            37,
7            "node_count is 37 - %s",
8            mode_desc);
9     cmp_ok(mmdb->metadata.record_size,
10            "==",
11            24,
12            "record_size is 24 - %s",
13            mode_desc);
14     cmp_ok(
15         mmdb->metadata.ip_version, "==", 4, "ip_version is 4 - %s", mode_desc);
16     is(mmdb->metadata.database_type,
17        "Test",
18        "database_type is Test - %s",
19        mode_desc);
20     // 2013-07-01T00:00:00Z
21     uint64_t expect_epoch = 1372636800;
22     int is_ok = cmp_ok(mmdb->metadata.build_epoch,
23                        ">=",
24                        expect_epoch,
25                        "build_epoch > %lli",
26                        expect_epoch);
27     if (!is_ok) {
28         diag("  epoch is %lli", mmdb->metadata.build_epoch);
29     }
30 
31     cmp_ok(mmdb->metadata.binary_format_major_version,
32            "==",
33            2,
34            "binary_format_major_version is 2 - %s",
35            mode_desc);
36     cmp_ok(mmdb->metadata.binary_format_minor_version,
37            "==",
38            0,
39            "binary_format_minor_version is 0 - %s",
40            mode_desc);
41 
42     cmp_ok(mmdb->metadata.languages.count,
43            "==",
44            2,
45            "found 2 languages - %s",
46            mode_desc);
47     is(mmdb->metadata.languages.names[0],
48        "en",
49        "first language is en - %s",
50        mode_desc);
51     is(mmdb->metadata.languages.names[1],
52        "zh",
53        "second language is zh - %s",
54        mode_desc);
55 
56     cmp_ok(mmdb->metadata.description.count,
57            "==",
58            2,
59            "found 2 descriptions - %s",
60            mode_desc);
61     for (uint16_t i = 0; i < mmdb->metadata.description.count; i++) {
62         const char *language =
63             mmdb->metadata.description.descriptions[i]->language;
64         const char *description =
65             mmdb->metadata.description.descriptions[i]->description;
66         if (strncmp(language, "en", 2) == 0) {
67             ok(1, "found en description");
68             is(description, "Test Database", "en description");
69         } else if (strncmp(language, "zh", 2) == 0) {
70             ok(1, "found zh description");
71             is(description, "Test Database Chinese", "zh description");
72         } else {
73             ok(0,
74                "found unknown description in unexpected language - %s",
75                language);
76         }
77     }
78 
79     cmp_ok(mmdb->full_record_byte_size,
80            "==",
81            6,
82            "full_record_byte_size is 6 - %s",
83            mode_desc);
84 }
85 
86 MMDB_entry_data_list_s *
test_languages_value(MMDB_entry_data_list_s * entry_data_list)87 test_languages_value(MMDB_entry_data_list_s *entry_data_list) {
88     MMDB_entry_data_list_s *languages = entry_data_list = entry_data_list->next;
89 
90     cmp_ok(languages->entry_data.type,
91            "==",
92            MMDB_DATA_TYPE_ARRAY,
93            "'languages' key's value is an array");
94     cmp_ok(languages->entry_data.data_size,
95            "==",
96            2,
97            "'languages' key's value has 2 elements");
98 
99     MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next;
100     cmp_ok(idx0->entry_data.type,
101            "==",
102            MMDB_DATA_TYPE_UTF8_STRING,
103            "first array entry is a UTF8_STRING");
104     const char *lang0 = dup_entry_string_or_bail(idx0->entry_data);
105     is(lang0, "en", "first language is en");
106     free((void *)lang0);
107 
108     MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next;
109     cmp_ok(idx1->entry_data.type,
110            "==",
111            MMDB_DATA_TYPE_UTF8_STRING,
112            "second array entry is a UTF8_STRING");
113     const char *lang1 = dup_entry_string_or_bail(idx1->entry_data);
114     is(lang1, "zh", "second language is zh");
115     free((void *)lang1);
116 
117     return entry_data_list;
118 }
119 
120 MMDB_entry_data_list_s *
test_description_value(MMDB_entry_data_list_s * entry_data_list)121 test_description_value(MMDB_entry_data_list_s *entry_data_list) {
122     MMDB_entry_data_list_s *description = entry_data_list =
123         entry_data_list->next;
124     cmp_ok(description->entry_data.type,
125            "==",
126            MMDB_DATA_TYPE_MAP,
127            "'description' key's value is a map");
128     cmp_ok(description->entry_data.data_size,
129            "==",
130            2,
131            "'description' key's value has 2 key/value pairs");
132 
133     for (int i = 0; i < 2; i++) {
134         MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next;
135         cmp_ok(key->entry_data.type,
136                "==",
137                MMDB_DATA_TYPE_UTF8_STRING,
138                "found a map key in 'map'");
139         const char *key_name = dup_entry_string_or_bail(key->entry_data);
140 
141         MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next;
142         cmp_ok(value->entry_data.type,
143                "==",
144                MMDB_DATA_TYPE_UTF8_STRING,
145                "map value is a UTF8_STRING");
146         const char *description = dup_entry_string_or_bail(value->entry_data);
147 
148         if (strcmp(key_name, "en") == 0) {
149             is(description,
150                "Test Database",
151                "en description == 'Test Database'");
152         } else if (strcmp(key_name, "zh") == 0) {
153             is(description,
154                "Test Database Chinese",
155                "zh description == 'Test Database Chinese'");
156         } else {
157             ok(0, "unknown key found in description map - %s", key_name);
158         }
159 
160         free((void *)key_name);
161         free((void *)description);
162     }
163 
164     return entry_data_list;
165 }
166 
test_metadata_as_data_entry_list(MMDB_s * mmdb,const char * mode_desc)167 void test_metadata_as_data_entry_list(MMDB_s *mmdb, const char *mode_desc) {
168     MMDB_entry_data_list_s *entry_data_list, *first;
169     int status = MMDB_get_metadata_as_entry_data_list(mmdb, &entry_data_list);
170 
171     first = entry_data_list;
172 
173     cmp_ok(status,
174            "==",
175            MMDB_SUCCESS,
176            "get metadata as data_entry_list - %s",
177            mode_desc);
178 
179     cmp_ok(first->entry_data.data_size,
180            "==",
181            9,
182            "metadata map has 9 key/value pairs");
183 
184     while (1) {
185         MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next;
186 
187         if (!key) {
188             break;
189         }
190 
191         cmp_ok(key->entry_data.type,
192                "==",
193                MMDB_DATA_TYPE_UTF8_STRING,
194                "found a map key");
195 
196         const char *key_name = dup_entry_string_or_bail(key->entry_data);
197         if (strcmp(key_name, "node_count") == 0) {
198             MMDB_entry_data_list_s *value = entry_data_list =
199                 entry_data_list->next;
200             cmp_ok(value->entry_data.uint32, "==", 37, "node_count == 37");
201         } else if (strcmp(key_name, "record_size") == 0) {
202             MMDB_entry_data_list_s *value = entry_data_list =
203                 entry_data_list->next;
204             cmp_ok(value->entry_data.uint16, "==", 24, "record_size == 24");
205         } else if (strcmp(key_name, "ip_version") == 0) {
206             MMDB_entry_data_list_s *value = entry_data_list =
207                 entry_data_list->next;
208             cmp_ok(value->entry_data.uint16, "==", 4, "ip_version == 4");
209         } else if (strcmp(key_name, "binary_format_major_version") == 0) {
210             MMDB_entry_data_list_s *value = entry_data_list =
211                 entry_data_list->next;
212             cmp_ok(value->entry_data.uint16,
213                    "==",
214                    2,
215                    "binary_format_major_version == 2");
216         } else if (strcmp(key_name, "binary_format_minor_version") == 0) {
217             MMDB_entry_data_list_s *value = entry_data_list =
218                 entry_data_list->next;
219             cmp_ok(value->entry_data.uint16,
220                    "==",
221                    0,
222                    "binary_format_minor_version == 0");
223         } else if (strcmp(key_name, "build_epoch") == 0) {
224             MMDB_entry_data_list_s *value = entry_data_list =
225                 entry_data_list->next;
226             ok(value->entry_data.uint64 > 1373571901,
227                "build_epoch > 1373571901");
228         } else if (strcmp(key_name, "database_type") == 0) {
229             MMDB_entry_data_list_s *value = entry_data_list =
230                 entry_data_list->next;
231             const char *type = dup_entry_string_or_bail(value->entry_data);
232             is(type, "Test", "type == Test");
233             free((void *)type);
234         } else if (strcmp(key_name, "languages") == 0) {
235             entry_data_list = test_languages_value(entry_data_list);
236         } else if (strcmp(key_name, "description") == 0) {
237             entry_data_list = test_description_value(entry_data_list);
238         } else {
239             ok(0, "unknown key found in metadata map - %s", key_name);
240         }
241 
242         free((void *)key_name);
243     }
244 
245     MMDB_free_entry_data_list(first);
246 }
247 
run_tests(int mode,const char * mode_desc)248 void run_tests(int mode, const char *mode_desc) {
249     const char *file = "MaxMind-DB-test-ipv4-24.mmdb";
250     const char *path = test_database_path(file);
251     MMDB_s *mmdb = open_ok(path, mode, mode_desc);
252 
253     // All of the remaining tests require an open mmdb
254     if (NULL == mmdb) {
255         diag("could not open %s - skipping remaining tests", path);
256         return;
257     }
258     free((void *)path);
259 
260     test_metadata(mmdb, mode_desc);
261     test_metadata_as_data_entry_list(mmdb, mode_desc);
262 
263     MMDB_close(mmdb);
264     free(mmdb);
265 }
266 
main(void)267 int main(void) {
268     plan(NO_PLAN);
269     for_all_modes(&run_tests);
270     done_testing();
271 }
272