git.fiddlerwoaroof.com
Browse code

Refactor and test random_source

Ed Langley authored on 13/06/2017 22:58:50
Showing 3 changed files
... ...
@@ -14,6 +14,9 @@
14 14
 
15 15
 namespace
16 16
 {
17
+class invalid_random_source_exception : public std::exception
18
+{};
19
+
17 20
 class impl : public random_source_ifc
18 21
 {
19 22
 private:
... ...
@@ -23,16 +26,22 @@ public:
23 26
         : fstreams_ (fstreams)
24 27
     {}
25 28
     std::vector<uint8_t> get_random_bytes (int length) const override {
26
-        std::string file_path = "/dev/urandom";
27 29
         fstreams::pstream random_source = fstreams_.open_fstream (file_path);
28 30
 
29 31
         std::vector<uint8_t> result (length);
30 32
         random_source->read (reinterpret_cast<char *> (result.data()), length);
33
+
34
+        if (random_source->fail()) {
35
+            throw invalid_random_source_exception();
36
+        }
37
+
31 38
         return result;
32 39
     }
33 40
 };
34 41
 }
35 42
 
43
+const std::string random_source_ifc::file_path = "/dev/urandom";
44
+
36 45
 random_source random_source::create(fstreams &fstreams) {
37 46
     return random_source(random_source::delegate (new impl (fstreams)));
38 47
 };
... ...
@@ -23,6 +23,8 @@
23 23
 class random_source_ifc
24 24
 {
25 25
 public:
26
+    const static std::string file_path;
27
+
26 28
     virtual std::vector<uint8_t> get_random_bytes (int length) const
27 29
     {
28 30
         return {};
29 31
new file mode 100644
... ...
@@ -0,0 +1,99 @@
1
+/* Copyright (C) CJ Affiliate
2
+ *
3
+ * You may use, distribute and modify this code under  the
4
+ * terms of the  GNU General Public License  version 2  or
5
+ * later.
6
+ *
7
+ * You should have received a copy of the license with this
8
+ * file. If not, you will find a copy in the "LICENSE" file
9
+ * at https://github.com/cjdev/dual-control.
10
+ */
11
+
12
+#include <memory>
13
+#include <cstring>
14
+#include <pwd.h>
15
+#include <cstdio>
16
+#include <sys/stat.h>
17
+#include <fstream>
18
+#include <sstream>
19
+
20
+#include "sys_fstream.h"
21
+#include "random_source.h"
22
+#include "test_util.h"
23
+
24
+class fake_fstreams : public fstreams_ifc
25
+{
26
+private:
27
+    std::string expected_file_path_;
28
+    std::string file_contents_;
29
+public:
30
+    fake_fstreams (const std::string &expected_file_path,
31
+                   const std::string &file_contents)
32
+        : expected_file_path_ (expected_file_path),
33
+          file_contents_ (file_contents) {}
34
+    pstream open_fstream (const std::string &file_path) const override
35
+    {
36
+        if (file_path == expected_file_path_) {
37
+            return fstreams::pstream (new std::istringstream (file_contents_));
38
+        } else {
39
+            return fstreams_ifc::open_fstream (file_path);
40
+        }
41
+
42
+    }
43
+};
44
+
45
+int reads_from_the_right_file ()
46
+{
47
+    //given
48
+    std::string random_source = random_source_ifc::file_path;
49
+    std::string very_random_bytes { 4, 2 };
50
+    // hardcoded file name is .dual_control in the user's home directory
51
+
52
+    fstreams test_streams (fstreams::delegate (new fake_fstreams (random_source, very_random_bytes)));
53
+
54
+    //file_reader test_file_reader (file_reader::delegate (new fake_file_reader));
55
+    class random_source supplier (random_source::create (test_streams));
56
+
57
+    //when
58
+    std::vector<uint8_t> actual_v = supplier.get_random_bytes (2);
59
+    std::string actual (actual_v.begin(), actual_v.end());
60
+
61
+    //then
62
+    check (actual == very_random_bytes, "didn't get the expected bytes");
63
+    succeed();
64
+}
65
+
66
+int handles_missing_random_source_correctly ()
67
+{
68
+    //given
69
+    std::string very_random_bytes { 4, 2 };
70
+    // hardcoded file name is .dual_control in the user's home directory
71
+
72
+    fstreams test_streams (fstreams::delegate (new fake_fstreams ("/nowhere", very_random_bytes)));
73
+
74
+    //file_reader test_file_reader (file_reader::delegate (new fake_file_reader));
75
+    class random_source supplier (random_source::create (test_streams));
76
+
77
+    //when
78
+    try {
79
+        supplier.get_random_bytes (2);
80
+        fail("get_random_bytes() should throw if it can't access /dev/urandom");
81
+    } catch (std::exception e) {
82
+        succeed();
83
+    }
84
+
85
+    //then
86
+    succeed();
87
+}
88
+
89
+int run_tests()
90
+{
91
+    test (reads_from_the_right_file);
92
+    test (handles_missing_random_source_correctly);
93
+    succeed();
94
+}
95
+
96
+int main (int argc, char *argv[])
97
+{
98
+    return !run_tests();
99
+}