test_file.cpp
Go to the documentation of this file.
1 /*
2  * Author(s):
3  * - Joël Lamotte <jlamotte@aldebaran.com>
4  *
5  * Copyright (c) 2014 Aldebaran. All rights reserved.
6  */
7 
8 #include <gtest/gtest.h>
9 #include <boost/filesystem/fstream.hpp>
10 #include <boost/filesystem.hpp>
11 #include <atomic>
12 
13 #include <qicore/file.hpp>
14 #include <qi/path.hpp>
15 #include <qi/application.hpp>
16 #include <qi/type/dynamicobjectbuilder.hpp>
17 #include <testsession/testsessionpair.hpp>
18 #include <testsession/testsession.hpp>
19 
20 qiLogCategory("qimessaging.testFile");
21 
22 namespace
23 {
24 struct TemporaryDir
25 {
26  const qi::Path PATH;
27  TemporaryDir()
28  : PATH(qi::os::mktmpdir("qiCoreTestFile"))
29  {
30  }
31  ~TemporaryDir()
32  {
33  boost::system::error_code err;
34  const auto path = boost::filesystem::system_complete(PATH);
35  boost::filesystem::remove_all(path, err);
36  if (err)
37  {
38  qiLogError() << "Failed to remove temporary directory '" << PATH << "' : " << err.message();
39  }
40  }
41 } const TEMPORARY_DIR;
42 
43 const qi::Path SMALL_TEST_FILE_PATH{TEMPORARY_DIR.PATH / "\xED\x95\x9C/testfile.data"};
44 qi::Path BIG_TEST_FILE_PATH;
45 
46 const std::string TESTFILE_CONTENT = "abcdefghijklmnopqrstuvwxyz";
47 const std::streamoff TESTFILE_PARTIAL_BEGIN_POSITION = 23;
48 const std::streamoff TESTFILE_PARTIAL_SIZE = 3;
49 
50 const std::streamoff TESTFILE_MIDDLE_BEGIN_POSITION = TESTFILE_CONTENT.size() / 3;
51 const std::streamoff TESTFILE_MIDDLE_SIZE = TESTFILE_CONTENT.size() / 3;
52 
53 void makeSmallTestFile()
54 {
55  boost::filesystem::remove(SMALL_TEST_FILE_PATH);
56  boost::filesystem::create_directories(SMALL_TEST_FILE_PATH.parent());
57  boost::filesystem::ofstream fileOutput(SMALL_TEST_FILE_PATH, std::ios::out | std::ios::binary);
58  assert(fileOutput.is_open());
59  fileOutput << TESTFILE_CONTENT;
60  fileOutput.flush();
61 }
62 
63 void checkIsTestFileContent(const qi::Buffer& buffer, std::streamoff beginOffset, std::streamsize bytesCount)
64 {
65  EXPECT_EQ(static_cast<std::streamsize>(buffer.size()), bytesCount);
66  for (size_t idx = 0; idx < buffer.totalSize(); ++idx)
67  {
68  EXPECT_EQ(static_cast<const char*>(buffer.data())[idx], TESTFILE_CONTENT[beginOffset + idx]);
69  }
70 }
71 
72 void checkIsTestFileMiddleContent(const qi::Buffer& buffer)
73 {
74  return checkIsTestFileContent(buffer, TESTFILE_MIDDLE_BEGIN_POSITION, TESTFILE_MIDDLE_SIZE);
75 }
76 
77 void checkIsTestFilePartialContent(const qi::Buffer& buffer)
78 {
79  return checkIsTestFileContent(buffer, TESTFILE_PARTIAL_BEGIN_POSITION, TESTFILE_PARTIAL_SIZE);
80 }
81 
82 void checkIsTestFileContent(const qi::Buffer& buffer)
83 {
84  for (size_t idx = 0; idx < buffer.totalSize(); ++idx)
85  {
86  EXPECT_EQ(static_cast<const char*>(buffer.data())[idx], TESTFILE_CONTENT[idx]);
87  }
88 }
89 
90 void checkIsTestFileContent(qi::File& file)
91 {
92  ASSERT_TRUE(file.isOpen());
93  EXPECT_EQ(static_cast<std::streamsize>(TESTFILE_CONTENT.size()), file.size());
94  file.seek(0);
95  const qi::Buffer allFileData = file.read(file.size());
96  EXPECT_EQ(TESTFILE_CONTENT.size(), allFileData.totalSize());
97  checkIsTestFileContent(allFileData);
98 }
99 
100 // Compare contents of the files and report any difference explicitly
101 void checkSameFilesContent(qi::File& leftFile, qi::File& rightFile)
102 {
103  ASSERT_TRUE(leftFile.isOpen());
104  ASSERT_TRUE(rightFile.isOpen());
105  ASSERT_EQ(leftFile.size(), rightFile.size());
106  static const std::streamsize BYTES_STEP = 1024 * 64;
107 
108  for (std::streamoff byteOffset = 0;
109  byteOffset < static_cast<std::streamoff>(rightFile.size());
110  byteOffset += BYTES_STEP)
111  {
112  qi::Buffer leftBytes = leftFile.read(byteOffset, BYTES_STEP);
113  qi::Buffer rightBytes = rightFile.read(byteOffset, BYTES_STEP);
114  EXPECT_GE(BYTES_STEP, static_cast<std::streamsize>(leftBytes.totalSize()));
115  EXPECT_GE(BYTES_STEP, static_cast<std::streamsize>(rightBytes.totalSize()));
116  EXPECT_EQ(leftBytes.totalSize(), rightBytes.totalSize());
117 
118  ASSERT_TRUE(std::equal(static_cast<char*>(leftBytes.data()),
119  static_cast<char*>(leftBytes.data()) + leftBytes.totalSize(),
120  static_cast<char*>(rightBytes.data())));
121  }
122 }
123 }
124 
125 TEST(TestFile, cannotReadUnknownFile)
126 {
127  EXPECT_THROW(
128  {
129  qi::FilePtr file = qi::openLocalFile("file/that/doesnt/exists.atall");
130  },
131  std::runtime_error);
132 }
133 
134 TEST(TestFile, cannotReadClosedFile)
135 {
136  qi::FilePtr file = qi::openLocalFile(SMALL_TEST_FILE_PATH);
137  EXPECT_TRUE(file->isOpen());
138 
139  file->close();
140  EXPECT_FALSE(file->isOpen());
141  EXPECT_EQ(0, file->size());
142  EXPECT_THROW(
143  {
144  file->read(42);
145  },
146  std::runtime_error);
147  EXPECT_THROW(
148  {
149  file->seek(42);
150  },
151  std::runtime_error);
152 }
153 
154 TEST(TestFile, readLocalFile)
155 {
156  qi::FilePtr testFile = qi::openLocalFile(SMALL_TEST_FILE_PATH);
157  EXPECT_TRUE(testFile->isOpen());
158  EXPECT_EQ(std::streamsize(TESTFILE_CONTENT.size()), testFile->size());
159 
160  static const size_t COUNT_BYTES_TO_READ = 20;
161 
162  qi::Buffer buffer = testFile->read(COUNT_BYTES_TO_READ);
163  ASSERT_EQ(COUNT_BYTES_TO_READ, buffer.totalSize());
164  checkIsTestFileContent(buffer);
165 }
166 
167 TEST(TestFile, cannotReadPastEnd)
168 {
169  qi::FilePtr testFile = qi::openLocalFile(SMALL_TEST_FILE_PATH);
170  EXPECT_TRUE(testFile->isOpen());
171  EXPECT_EQ(std::streamsize(TESTFILE_CONTENT.size()), testFile->size());
172 
173  testFile->read(testFile->size());
174  qi::Buffer buffer = testFile->read(1);
175  EXPECT_EQ(0u, buffer.totalSize());
176 }
177 
178 TEST(TestFile, localCopy)
179 {
180  qi::FilePtr testFile = qi::openLocalFile(SMALL_TEST_FILE_PATH);
181  EXPECT_TRUE(testFile->isOpen());
182  EXPECT_EQ(std::streamsize(TESTFILE_CONTENT.size()), testFile->size());
183 
184  static const qi::Path LOCAL_COPY_PATH("if_this_is_not_removed_test_file_failed.txt");
185  boost::filesystem::remove(LOCAL_COPY_PATH);
186  {
187  copyToLocal(testFile, LOCAL_COPY_PATH);
188 
189  qi::FilePtr copiedFile = qi::openLocalFile(SMALL_TEST_FILE_PATH);
190  EXPECT_TRUE(copiedFile->isOpen());
191  checkSameFilesContent(*testFile, *copiedFile);
192  }
193  boost::filesystem::remove(LOCAL_COPY_PATH);
194 }
195 
196 namespace
197 {
198 qi::FilePtr getTestFile(const qi::Path& filePath)
199 {
200  qi::FilePtr testFile = qi::openLocalFile(filePath);
201  EXPECT_TRUE(testFile->isOpen());
202  return testFile;
203 }
204 
205 std::atomic<bool> printProgressHaveBeenCalled(false);
206 void printTranferProgress(double progress)
207 {
208  printProgressHaveBeenCalled = true;
209  qiLogInfo() << "#### File Transfer Progress = " << (progress * 100.0) << "%";
210 }
211 
212 class Test_ReadRemoteFile : public ::testing::Test
213 {
214 public:
215  void SetUp()
216  {
217  qi::DynamicObjectBuilder objectBuilder;
218  objectBuilder.advertiseMethod("getTestFile", &getTestFile);
219  service = objectBuilder.object();
220 
221  qi::SessionPtr serverSession = sessionPair.server();
222  serverSession->registerService("service", service);
223  }
224 
225  qi::FilePtr clientAcquireTestFile(const qi::Path& path)
226  {
227  qi::AnyObject service = sessionPair.client()->service("service").value();
228  qi::FilePtr testFile = service.call<qi::FilePtr>("getTestFile", path);
229  EXPECT_TRUE(testFile->isRemote());
230  return testFile;
231  }
232 
233 private:
234  TestSessionPair sessionPair;
235  qi::AnyObject service;
236 };
237 }
238 
239 TEST_F(Test_ReadRemoteFile, isLocalOrRemote)
240 {
241  {
242  qi::FilePtr testFile = openLocalFile(SMALL_TEST_FILE_PATH);
243  EXPECT_FALSE(testFile->isRemote());
244  }
245  {
246  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
247  EXPECT_TRUE(testFile->isRemote());
248  }
249 }
250 
251 TEST_F(Test_ReadRemoteFile, someReading)
252 {
253  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
254 
255  static const size_t COUNT_BYTES_TO_READ = 20;
256 
257  qi::Buffer buffer = testFile->read(COUNT_BYTES_TO_READ);
258  ASSERT_EQ(COUNT_BYTES_TO_READ, buffer.totalSize());
259  checkIsTestFileContent(buffer);
260 }
261 
262 TEST_F(Test_ReadRemoteFile, readAll)
263 {
264  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
265 
266  static const size_t COUNT_BYTES_TO_READ_PER_CYCLE = 10;
267 
268  qi::Buffer buffer;
269  qi::Buffer cycleBuffer;
270  while (true)
271  {
272  cycleBuffer = testFile->read(COUNT_BYTES_TO_READ_PER_CYCLE);
273  buffer.write(cycleBuffer.data(), cycleBuffer.totalSize());
274  if (cycleBuffer.totalSize() < COUNT_BYTES_TO_READ_PER_CYCLE)
275  break;
276  }
277 
278  EXPECT_EQ(TESTFILE_CONTENT.size(), buffer.totalSize());
279  checkIsTestFileContent(buffer);
280 }
281 
282 TEST_F(Test_ReadRemoteFile, readAllOnce)
283 {
284  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
285 
286  const std::streamsize fileSize = testFile->size();
287  EXPECT_EQ(std::streamsize(TESTFILE_CONTENT.size()), fileSize);
288 
289  qi::Buffer buffer = testFile->read(fileSize);
290  EXPECT_EQ(TESTFILE_CONTENT.size(), buffer.totalSize());
291  checkIsTestFileContent(buffer);
292 }
293 
294 TEST_F(Test_ReadRemoteFile, filetransfert)
295 {
296  static const qi::Path LOCAL_PATH_TO_RECEIVE_FILE_IN = TEMPORARY_DIR.PATH / "file.data";
297  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
298 
299  {
300  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
301 
302  copyToLocal(testFile, LOCAL_PATH_TO_RECEIVE_FILE_IN);
303  }
304  {
305  qi::FilePtr localFileCopy = qi::openLocalFile(LOCAL_PATH_TO_RECEIVE_FILE_IN);
306  EXPECT_TRUE(localFileCopy->isOpen());
307  checkIsTestFileContent(*localFileCopy);
308  }
309 
310  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
311 }
312 
313 TEST_F(Test_ReadRemoteFile, readInTheMiddle)
314 {
315  qi::FilePtr testFile = clientAcquireTestFile(SMALL_TEST_FILE_PATH);
316 
317  qi::Buffer bufferPartial = testFile->read(TESTFILE_PARTIAL_BEGIN_POSITION, TESTFILE_PARTIAL_SIZE);
318  checkIsTestFilePartialContent(bufferPartial);
319 
320  qi::Buffer bufferMiddle = testFile->read(TESTFILE_MIDDLE_BEGIN_POSITION, TESTFILE_MIDDLE_SIZE);
321  checkIsTestFileMiddleContent(bufferMiddle);
322 }
323 
324 TEST_F(Test_ReadRemoteFile, bigFiletransfert)
325 {
326  static const qi::Path LOCAL_PATH_TO_RECEIVE_FILE_IN = TEMPORARY_DIR.PATH / "bigfile.data";
327  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
328 
329  {
330  qi::FilePtr testFile = clientAcquireTestFile(BIG_TEST_FILE_PATH);
331 
332  qi::FileCopyToLocal fileCopy{testFile, LOCAL_PATH_TO_RECEIVE_FILE_IN};
333  fileCopy.notifier()->progress.connect(&printTranferProgress);
334  fileCopy.start().wait();
335 
336  EXPECT_TRUE(printProgressHaveBeenCalled.load());
337  }
338  {
339  qi::FilePtr originalFile = qi::openLocalFile(BIG_TEST_FILE_PATH);
340  qi::FilePtr localFileCopy = qi::openLocalFile(LOCAL_PATH_TO_RECEIVE_FILE_IN);
341  checkSameFilesContent(*originalFile, *localFileCopy);
342  }
343 
344  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
345 }
346 
347 TEST_F(Test_ReadRemoteFile, cancelFileTransfer)
348 {
349  static const qi::Path LOCAL_PATH_TO_RECEIVE_FILE_IN = TEMPORARY_DIR.PATH / "bigfile.data";
350  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
351 
352  {
353  qi::FilePtr testFile = clientAcquireTestFile(BIG_TEST_FILE_PATH);
354 
355  qi::FileCopyToLocal fileOp{ testFile, LOCAL_PATH_TO_RECEIVE_FILE_IN };
356  auto fileOpNotifier = fileOp.notifier();
357  fileOpNotifier->status.connect([&](qi::ProgressNotifier::Status status){
359  {
360  fileOpNotifier->waitForFinished().cancel();
361  }
362  });
363  qi::Future<void> copyOpFt = fileOp.start();
364  copyOpFt.wait();
365  EXPECT_TRUE(copyOpFt.isCanceled());
366  }
367 
368  EXPECT_FALSE(boost::filesystem::exists(LOCAL_PATH_TO_RECEIVE_FILE_IN));
369  boost::filesystem::remove(LOCAL_PATH_TO_RECEIVE_FILE_IN);
370 }
371 
372 int main(int argc, char** argv)
373 {
374  ::TestMode::forceTestMode(TestMode::Mode_SD);
375  ::testing::InitGoogleTest(&argc, argv);
376  qi::Application app(argc, argv);
377  BIG_TEST_FILE_PATH = qi::path::findLib("qi");
378  makeSmallTestFile();
379  const int result = RUN_ALL_TESTS();
380  return result;
381 }
qi::ProgressNotifier::Status_Running
@ Status_Running
The operation is currently running.
Definition: file.hpp:38
TEST_F
TEST_F(Test_ReadRemoteFile, isLocalOrRemote)
Definition: test_file.cpp:239
printTranferProgress
void printTranferProgress(double progress)
Definition: send_robot_icon.cpp:17
qi::File::read
virtual Buffer read(std::streamsize countBytesToRead)=0
qiLogCategory
qiLogCategory("qimessaging.testFile")
file.hpp
TEST
TEST(TestFile, cannotReadUnknownFile)
Definition: test_file.cpp:125
qi::copyToLocal
FutureSync< void > copyToLocal(FilePtr file, Path localPath)
Definition: fileoperation.cpp:19
qi::File::seek
virtual bool seek(std::streamoff offsetFromBegin)=0
qi::File
Definition: file.hpp:127
qi
Definition: file.hpp:21
qi::File::size
virtual std::streamsize size() const =0
qi::File::isOpen
virtual bool isOpen() const =0
qi::openLocalFile
QICORE_API FilePtr openLocalFile(const qi::Path &localPath)
Definition: fileimpl.cpp:186
file_example.app
app
Definition: file_example.py:8
qi::ProgressNotifier::Status
Status
Definition: file.hpp:35
main
int main(int argc, char **argv)
Definition: test_file.cpp:372
setup.path
path
Definition: setup.py:114
qi::FilePtr
qi::Object< File > FilePtr
Pointer to a file with shared/remote semantic.
Definition: file.hpp:213


naoqi_libqicore
Author(s): Aldebaran
autogenerated on Wed Sep 14 2022 02:22:41