1 /*
2  * Copyright (C) 2009 Tommi Maekitalo
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
11  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
12  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  */
19 
20 #include <cstring>
21 #include <iostream>
22 #include <sstream>
23 #include <memory>
24 #include <stdexcept>
25 
26 #ifdef _WIN32
27 #include <windows.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <io.h>
32 #include <fileapi.h>
33 #endif
34 
35 #include "gtest/gtest.h"
36 
37 #include "../src/buffer.h"
38 #include "../src/_dirent.h"
39 #include "../src/writer/_dirent.h"
40 
41 #include "tools.h"
42 
43 namespace
44 {
45 
46 using zim::unittests::TempFile;
47 using zim::unittests::write_to_buffer;
48 
writenDirentSize(const zim::writer::Dirent & dirent)49 size_t writenDirentSize(const zim::writer::Dirent& dirent)
50 {
51   TempFile tmpFile("test_dirent");
52   const auto tmp_fd = tmpFile.fd();
53   dirent.write(tmp_fd);
54   auto size = lseek(tmp_fd, 0, SEEK_END);
55   return size;
56 }
57 
TEST(DirentTest,set_get_data_dirent)58 TEST(DirentTest, set_get_data_dirent)
59 {
60   zim::Dirent dirent;
61   dirent.setUrl('A', "Bar");
62   dirent.setArticle(17, zim::cluster_index_t(45), zim::blob_index_t(1234));
63   dirent.setVersion(54346);
64 
65   ASSERT_TRUE(!dirent.isRedirect());
66   ASSERT_EQ(dirent.getNamespace(), 'A');
67   ASSERT_EQ(dirent.getUrl(), "Bar");
68   ASSERT_EQ(dirent.getTitle(), "Bar");
69   ASSERT_EQ(dirent.getParameter(), "");
70   ASSERT_EQ(dirent.getClusterNumber().v, 45U);
71   ASSERT_EQ(dirent.getBlobNumber().v, 1234U);
72   ASSERT_EQ(dirent.getVersion(), 54346U);
73 
74   dirent.setTitle("Foo");
75   ASSERT_EQ(dirent.getNamespace(), 'A');
76   ASSERT_EQ(dirent.getUrl(), "Bar");
77   ASSERT_EQ(dirent.getTitle(), "Foo");
78   ASSERT_EQ(dirent.getParameter(), "");
79 }
80 
TEST(DirentTest,read_write_article_dirent)81 TEST(DirentTest, read_write_article_dirent)
82 {
83   zim::writer::Dirent dirent;
84   dirent.setUrl(zim::writer::Url('A', "Bar"));
85   dirent.setTitle("Foo");
86   dirent.setArticle(17, zim::cluster_index_t(45), zim::blob_index_t(1234));
87 
88   ASSERT_TRUE(!dirent.isRedirect());
89   ASSERT_EQ(dirent.getNamespace(), 'A');
90   ASSERT_EQ(dirent.getUrl(), "Bar");
91   ASSERT_EQ(dirent.getTitle(), "Foo");
92   ASSERT_EQ(dirent.getClusterNumber().v, 45U);
93   ASSERT_EQ(dirent.getBlobNumber().v, 1234U);
94   ASSERT_EQ(dirent.getVersion(), 0U);
95 
96   auto buffer = write_to_buffer(dirent);
97   zim::Dirent dirent2(buffer);
98 
99   ASSERT_TRUE(!dirent2.isRedirect());
100   ASSERT_EQ(dirent2.getNamespace(), 'A');
101   ASSERT_EQ(dirent2.getTitle(), "Foo");
102   ASSERT_EQ(dirent2.getParameter(), "");
103   ASSERT_EQ(dirent2.getClusterNumber().v, 45U);
104   ASSERT_EQ(dirent2.getBlobNumber().v, 1234U);
105   ASSERT_EQ(dirent2.getVersion(), 0U);
106 }
107 
TEST(DirentTest,read_write_article_dirent_unicode)108 TEST(DirentTest, read_write_article_dirent_unicode)
109 {
110   zim::writer::Dirent dirent;
111   dirent.setUrl(zim::writer::Url('A', "L\xc3\xbcliang"));
112   dirent.setArticle(17, zim::cluster_index_t(45), zim::blob_index_t(1234));
113 
114   ASSERT_TRUE(!dirent.isRedirect());
115   ASSERT_EQ(dirent.getNamespace(), 'A');
116   ASSERT_EQ(dirent.getUrl(), "L\xc3\xbcliang");
117   ASSERT_EQ(dirent.getTitle(), "L\xc3\xbcliang");
118   ASSERT_EQ(dirent.getClusterNumber().v, 45U);
119   ASSERT_EQ(dirent.getBlobNumber().v, 1234U);
120 
121   auto buffer = write_to_buffer(dirent);
122   zim::Dirent dirent2(buffer);
123 
124   ASSERT_TRUE(!dirent2.isRedirect());
125   ASSERT_EQ(dirent2.getNamespace(), 'A');
126   ASSERT_EQ(dirent2.getUrl(), "L\xc3\xbcliang");
127   ASSERT_EQ(dirent2.getTitle(), "L\xc3\xbcliang");
128   ASSERT_EQ(dirent2.getParameter(), "");
129   ASSERT_EQ(dirent2.getClusterNumber().v, 45U);
130   ASSERT_EQ(dirent2.getBlobNumber().v, 1234U);
131 }
132 
TEST(DirentTest,read_write_redirect_dirent)133 TEST(DirentTest, read_write_redirect_dirent)
134 {
135   zim::writer::Dirent targetDirent;
136   targetDirent.setIdx(zim::article_index_t(321));
137   zim::writer::Dirent dirent;
138   dirent.setUrl(zim::writer::Url('A', "Bar"));
139   dirent.setRedirect(&targetDirent);
140 
141   ASSERT_TRUE(dirent.isRedirect());
142   ASSERT_EQ(dirent.getNamespace(), 'A');
143   ASSERT_EQ(dirent.getUrl(), "Bar");
144   ASSERT_EQ(dirent.getRedirectIndex().v, 321U);
145 
146   auto buffer = write_to_buffer(dirent);
147   zim::Dirent dirent2(buffer);
148 
149   ASSERT_TRUE(dirent2.isRedirect());
150   ASSERT_EQ(dirent2.getNamespace(), 'A');
151   ASSERT_EQ(dirent2.getUrl(), "Bar");
152   ASSERT_EQ(dirent2.getTitle(), "Bar");
153   ASSERT_EQ(dirent2.getRedirectIndex().v, 321U);
154 }
155 
TEST(DirentTest,read_write_linktarget_dirent)156 TEST(DirentTest, read_write_linktarget_dirent)
157 {
158   zim::writer::Dirent dirent;
159   dirent.setUrl(zim::writer::Url('A', "Bar"));
160   dirent.setLinktarget();
161 
162   ASSERT_TRUE(!dirent.isRedirect());
163   ASSERT_TRUE(dirent.isLinktarget());
164   ASSERT_TRUE(!dirent.isDeleted());
165   ASSERT_EQ(dirent.getNamespace(), 'A');
166   ASSERT_EQ(dirent.getUrl(), "Bar");
167 
168   auto buffer = write_to_buffer(dirent);
169   zim::Dirent dirent2(buffer);
170 
171   ASSERT_TRUE(!dirent2.isRedirect());
172   ASSERT_TRUE(dirent2.isLinktarget());
173   ASSERT_TRUE(!dirent2.isDeleted());
174   ASSERT_EQ(dirent2.getNamespace(), 'A');
175   ASSERT_EQ(dirent2.getUrl(), "Bar");
176   ASSERT_EQ(dirent2.getTitle(), "Bar");
177 }
178 
TEST(DirentTest,read_write_deleted_dirent)179 TEST(DirentTest, read_write_deleted_dirent)
180 {
181   zim::writer::Dirent dirent;
182   dirent.setUrl(zim::writer::Url('A', "Bar"));
183   dirent.setDeleted();
184 
185   ASSERT_TRUE(!dirent.isRedirect());
186   ASSERT_TRUE(!dirent.isLinktarget());
187   ASSERT_TRUE(dirent.isDeleted());
188   ASSERT_EQ(dirent.getNamespace(), 'A');
189   ASSERT_EQ(dirent.getUrl(), "Bar");
190 
191   auto buffer = write_to_buffer(dirent);
192   zim::Dirent dirent2(buffer);
193 
194   ASSERT_TRUE(!dirent2.isRedirect());
195   ASSERT_TRUE(!dirent2.isLinktarget());
196   ASSERT_TRUE(dirent2.isDeleted());
197   ASSERT_EQ(dirent2.getNamespace(), 'A');
198   ASSERT_EQ(dirent2.getUrl(), "Bar");
199   ASSERT_EQ(dirent2.getTitle(), "Bar");
200 }
201 
TEST(DirentTest,dirent_size)202 TEST(DirentTest, dirent_size)
203 {
204   zim::writer::Dirent dirent;
205   std::string s;
206   dirent.setArticle(17, zim::cluster_index_t(45), zim::blob_index_t(1234));
207   dirent.setUrl(zim::writer::Url('A', "Bar"));
208 
209   // case url set, title empty, extralen empty
210   ASSERT_EQ(dirent.getDirentSize(), writenDirentSize(dirent));
211 
212   // case url set, title set, extralen empty
213   dirent.setTitle("Foo");
214   ASSERT_EQ(dirent.getDirentSize(), writenDirentSize(dirent));
215 
216   // case url set, title empty
217   dirent.setTitle(std::string());
218   ASSERT_EQ(dirent.getDirentSize(), writenDirentSize(dirent));
219 }
220 
TEST(DirentTest,redirect_dirent_size)221 TEST(DirentTest, redirect_dirent_size)
222 {
223   zim::writer::Dirent targetDirent;
224   targetDirent.setIdx(zim::article_index_t(321));
225   zim::writer::Dirent dirent;
226   dirent.setUrl(zim::writer::Url('A', "Bar"));
227   dirent.setRedirect(&targetDirent);
228 
229   ASSERT_EQ(dirent.getDirentSize(), writenDirentSize(dirent));
230 }
231 
232 }  // namespace
233