1 #include <stdlib.h>
2 #include <unistd.h>
3 
4 #include <gtest/gtest.h>
5 
6 #include <vector>
7 #include <iostream>
8 #include <fstream>
9 #include <sstream>
10 #include <stdexcept>
11 
12 #include <jellyfish/err.hpp>
13 #include <jellyfish/misc.hpp>
14 #include <jellyfish/stream_iterator.hpp>
15 
16 namespace {
17 namespace err = jellyfish::err;
18 
19 typedef std::vector<const char*>                  path_vector;
20 typedef path_vector::const_iterator               path_iterator;
21 typedef jellyfish::stream_iterator<path_iterator> stream_iterator;
22 
23 class StreamIterator : public ::testing::Test {
24 protected:
25   static path_vector paths;
26   static int         total_lines;
27   static char*       tmpdir;
28 
SetUpTestCase()29   static void SetUpTestCase() {
30     tmpdir = strdup("/tmp/stream_iterator_XXXXXX");
31     if(!mkdtemp(tmpdir))
32       throw std::runtime_error(err::msg() << "Failed to create tmp directory: " << err::no);
33 
34     int nb_files = jellyfish::random_bits(5);
35     for(int i = 0; i < nb_files; ++i) {
36       std::ostringstream path;
37       path << tmpdir << "/" << i;
38       paths.push_back(strdup(path.str().c_str()));
39       std::ofstream tmp_file(path.str().c_str());
40       if(tmp_file.fail())
41         throw std::runtime_error(err::msg() << "Failed to open file '" << path.str() << "' for writing");
42       int nb_lines = jellyfish::random_bits(6);
43       total_lines += nb_lines;
44       for(int j = 0; j < nb_lines; ++j)
45         tmp_file << "line " << j << "\n";
46     }
47   }
48 
TearDownTestCase()49   static void TearDownTestCase() {
50     for(path_iterator it = paths.begin(); it != paths.end(); ++it) {
51       if(unlink(*it) == -1)
52         throw std::runtime_error(err::msg() << "Failed to unlink file '" << *it << ": " << err::no);
53       free((void*)*it);
54     }
55     if(rmdir(tmpdir) == -1)
56       throw std::runtime_error(err::msg() << "Failed to rmdir '" << tmpdir << ": " << err::no);
57     free(tmpdir);
58   }
59 };
60 path_vector StreamIterator::paths;
61 int         StreamIterator::total_lines = 0;
62 char*       StreamIterator::tmpdir;
63 
TEST_F(StreamIterator,Empty)64 TEST_F(StreamIterator, Empty) {
65   stream_iterator sit(paths.begin(), paths.begin());
66   stream_iterator send;
67 
68   int nb_files = 0;
69   int nb_lines = 0;
70   for( ; sit != send; ++sit, ++nb_files)
71     for(std::string line; std::getline(*sit, line); ++nb_lines) ;
72 
73   EXPECT_EQ(0, nb_files);
74   EXPECT_EQ(0, nb_lines);
75 }
76 
77 
TEST_F(StreamIterator,RandomFiles)78 TEST_F(StreamIterator, RandomFiles) {
79   SCOPED_TRACE(::testing::Message() << "nb_files:" << paths.size() << " nb_lines:" << total_lines);
80 
81   stream_iterator sit(paths.begin(), paths.end());
82   stream_iterator send;
83 
84   int nb_files = 0;
85   int nb_lines = 0;
86   for( ; sit != send; ++sit, ++nb_files) {
87     for(std::string line; std::getline(*sit, line); ++nb_lines) ;
88     EXPECT_TRUE(sit->eof());
89   }
90 
91   EXPECT_EQ(paths.size(), (size_t)nb_files);
92   EXPECT_EQ(total_lines, nb_lines);
93 }
94 }
95