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