1 /*
2 * BloomFilterTests.cpp
3 * Unit Tests for hashmanager and bloomfilter classes
4 * Created on: Aug 14, 2012
5 * Author: cjustin
6 */
7
8 /* automatically create main() function to run tests */
9 #define CATCH_CONFIG_MAIN
10
11 /* lightweight unit test framework */
12 #include "BloomFilter.hpp"
13 #include "vendor/catch.hpp"
14 #include "vendor/ntHashIterator.hpp"
15
16 #include <assert.h>
17 #include <cstring>
18 #include <fstream>
19 #include <sstream>
20 #include <stdlib.h>
21 #include <string>
22
23 using namespace std;
24
25 /** create a uniquely-named temp file (tedious!) */
26 string
createTempFile()27 createTempFile()
28 {
29 const unsigned MAX_FILENAME_SIZE = 1024;
30 const char* fileTemplate = "/XXXXXX";
31 char filename[MAX_FILENAME_SIZE + 1];
32
33 /* allow override of default tmp dir */
34 char* tmpdir = getenv("TMPDIR");
35 if (tmpdir)
36 strcpy(filename, tmpdir);
37 else
38 strcpy(filename, "/tmp");
39
40 assert(strlen(filename) + strlen(fileTemplate) <= MAX_FILENAME_SIZE);
41 strcat(filename, fileTemplate);
42
43 int fd = mkstemp(filename);
44 if (fd == -1) {
45 perror("failed to create temp file");
46 exit(EXIT_FAILURE);
47 }
48 close(fd);
49
50 return string(filename);
51 }
52
53 TEST_CASE("test fixture", "[BloomFilter]")
54 {
55 /*
56 * NOTES:
57 * - The SECTION blocks below are separate tests that share the
58 * same setup code
59 * - The common setup code is _re-run_ before each SECTION
60 * - In unit test terminology, this type of setup is known as a
61 * "test fixture"
62 * - See
63 * https://github.com/philsquared/Catch/blob/master/docs/tutorial.md#test-cases-and-sections for
64 * details
65 */
66
67 /* START COMMON SETUP CODE */
68
69 const size_t filterSize = 1000000000;
70 const unsigned numHashes = 5;
71 const unsigned k = 4;
72 const char* seq = "ACGTAC";
73
74 BloomFilter filter(filterSize, numHashes, k);
75
76 /* insert k-mers ACGT, CGTA, GTAC */
77
78 ntHashIterator insertIt(seq, numHashes, k);
79 while (insertIt != insertIt.end()) {
80 filter.insert(*insertIt);
81 ++insertIt;
82 }
83
84 /* END COMMON SETUP CODE */
85
86 SECTION("query elements")
87 {
88 /* check that k-mers were correctly inserted */
89
90 ntHashIterator queryIt(seq, numHashes, k);
91 while (queryIt != queryIt.end()) {
92 assert(filter.contains(*queryIt));
93 ++queryIt;
94 }
95 }
96
97 SECTION("save/load Bloom file")
98 {
99 /* write filter */
100
101 string filename = createTempFile();
102 filter.storeFilter(filename);
103 ifstream ifile(filename.c_str());
104
105 /* check size of newly-created file */
106 assert(ifile.is_open());
107 /* File header has no fixed element but "[HeaderEnd]"
108 so check for "[HeaderEnd]" in file*/
109 std::string headerEnd = "[HeaderEnd]";
110 std::string line;
111 bool headerEndCheck = false;
112 while (std::getline(ifile, line)) {
113 if (line == headerEnd) {
114 headerEndCheck = true;
115 break;
116 }
117 }
118 assert(headerEndCheck);
119
120 size_t currPos = ifile.tellg();
121 ifile.seekg(0, ios::end);
122 size_t endPos = ifile.tellg();
123 ifile.close();
124
125 /* check loading of stored filter */
126
127 BloomFilter filter2(filename);
128
129 // Checking if sizeInBytes correspond to filesize - header
130
131 assert((endPos - currPos) == filter2.sizeInBytes());
132
133 /* check if loaded filter is able to report expected results */
134
135 ntHashIterator queryIt(seq, numHashes, k);
136 while (queryIt != queryIt.end()) {
137 assert(filter2.contains(*queryIt));
138 ++queryIt;
139 }
140
141 /* cleanup */
142
143 remove(filename.c_str());
144 }
145
146 } /* end test fixture */
147