OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestBinConfigWriter.cpp
Go to the documentation of this file.
1//
2// Unit tests for BinConfigWriter.
3//
4
5#include <gtest/gtest.h>
6
7#include "Ippl.h"
10
11#include <cmath>
12#include <fstream>
13#include <sstream>
14#include <string>
15#include <vector>
16
17class BinConfigWriterTest : public ::testing::Test {
18protected:
19 static void SetUpTestSuite() {
20 int argc = 0;
21 char** argv = nullptr;
22 ippl::initialize(argc, argv);
23 }
24
25 static void TearDownTestSuite() { ippl::finalize(); }
26
27 // Helper to read entire file into string.
28 static std::string readFile(const std::string& path) {
29 std::ifstream f(path);
30 std::stringstream ss;
31 ss << f.rdbuf();
32 return ss.str();
33 }
34
35 // Helper to check that a string is valid JSON array (basic structural check).
36 static bool looksLikeJsonArray(const std::string& s) {
37 if (s.empty()) return false;
38 size_t i = 0;
39 while (i < s.size() && (s[i] == ' ' || s[i] == '\n'))
40 ++i;
41 if (i >= s.size() || s[i] != '[') return false;
42 size_t depth = 0;
43 for (; i < s.size(); ++i) {
44 if (s[i] == '[')
45 ++depth;
46 else if (s[i] == ']') {
47 if (depth == 0) return false;
48 --depth;
49 }
50 }
51 return depth == 0;
52 }
53};
54
55// ConstructionOpensFileAndWritesOpeningBracket:
56// Constructor creates the file and writes "[\n".
57TEST_F(BinConfigWriterTest, ConstructionOpensFileAndWritesOpeningBracket) {
58 const std::string path = "bin_config_construction_test.json";
59 {
60 BinConfigWriter w(path);
61 }
62 std::string content = readFile(path);
63 EXPECT_TRUE(content.find("[\n") == 0)
64 << "Expected file to start with '[\\n', got: " << content.substr(0, 20);
65}
66
67// SingleEntryProducesValidJson:
68// One writeEntry produces a well-formed JSON array with one object.
69TEST_F(BinConfigWriterTest, SingleEntryProducesValidJson) {
70 const std::string path = "bin_config_single_entry_test.json";
71 {
72 BinConfigWriter w(path);
73 std::vector<std::size_t> counts = {10, 20, 30};
74 std::vector<double> widths = {0.1, 0.2, 0.3};
75 w.writeEntry(0, 1.0e-10, true, counts, widths, 0.5);
76 }
77 std::string content = readFile(path);
78 EXPECT_TRUE(looksLikeJsonArray(content))
79 << "Output is not valid JSON array: " << content.substr(0, 200);
80 EXPECT_NE(content.find("\"step\": 0"), std::string::npos);
81 EXPECT_NE(content.find("\"time\":"), std::string::npos);
82 EXPECT_NE(content.find("\"preMerge\": true"), std::string::npos);
83 EXPECT_NE(content.find("\"xMin\":"), std::string::npos);
84 EXPECT_NE(content.find("\"binCounts\": ["), std::string::npos);
85 EXPECT_NE(content.find("10, 20, 30"), std::string::npos);
86 EXPECT_NE(content.find("\"binWidths\": ["), std::string::npos);
87}
88
89// MultipleEntriesProduceValidJsonArray:
90// Several writeEntry calls produce a JSON array with multiple objects.
91TEST_F(BinConfigWriterTest, MultipleEntriesProduceValidJsonArray) {
92 const std::string path = "bin_config_multi_entry_test.json";
93 {
94 BinConfigWriter w(path);
95 std::vector<std::size_t> counts1 = {100};
96 std::vector<double> widths1 = {1.0};
97 w.writeEntry(0, 0.0, true, counts1, widths1, 0.0);
98
99 std::vector<std::size_t> counts2 = {50, 50};
100 std::vector<double> widths2 = {0.5, 0.5};
101 w.writeEntry(1, 1.0e-10, false, counts2, widths2, 0.25);
102 }
103 std::string content = readFile(path);
104 EXPECT_TRUE(looksLikeJsonArray(content));
105 EXPECT_NE(content.find("\"step\": 0"), std::string::npos);
106 EXPECT_NE(content.find("\"step\": 1"), std::string::npos);
107 EXPECT_NE(content.find("\"preMerge\": true"), std::string::npos);
108 EXPECT_NE(content.find("\"preMerge\": false"), std::string::npos);
109}
110
111// EmptyArraysHandledCorrectly:
112// writeEntry with empty binCounts and binWidths produces valid JSON.
113// (Writer outputs "binCounts": [ ], and "binWidths": [ ] with spaces, not "[]".)
114TEST_F(BinConfigWriterTest, EmptyArraysHandledCorrectly) {
115 const std::string path = "bin_config_empty_arrays_test.json";
116 {
117 BinConfigWriter w(path);
118 std::vector<std::size_t> counts;
119 std::vector<double> widths;
120 w.writeEntry(42, 3.14, false, counts, widths, -1.5);
121 }
122 std::string content = readFile(path);
123 EXPECT_TRUE(looksLikeJsonArray(content));
124 EXPECT_NE(content.find("\"step\": 42"), std::string::npos);
125 // Writer formats empty arrays as "key": [ ], with spaces before ]
126 EXPECT_NE(content.find("\"binCounts\": ["), std::string::npos);
127 EXPECT_NE(content.find("\"binWidths\": ["), std::string::npos);
128}
129
130// FileClosedAfterEachEntry:
131// After each writeEntry, the file on disk ends with a closing ']' (self-closing design).
132TEST_F(BinConfigWriterTest, FileClosedAfterEachEntry) {
133 const std::string path = "bin_config_closed_test.json";
134 {
135 BinConfigWriter w(path);
136 std::vector<std::size_t> counts = {1};
137 std::vector<double> widths = {1.0};
138 w.writeEntry(0, 0.0, true, counts, widths, 0.0);
139 // File should already be valid and closed; read without destroying writer.
140 }
141 std::string content = readFile(path);
142 EXPECT_TRUE(looksLikeJsonArray(content));
143 EXPECT_EQ(content.back(), '\n');
144 size_t lastBracket = content.rfind(']');
145 EXPECT_NE(lastBracket, std::string::npos);
146 EXPECT_GT(lastBracket, 0u);
147}
148
149// InvalidPathThrows:
150// Constructor throws OpalException when the file cannot be opened.
151TEST_F(BinConfigWriterTest, InvalidPathThrows) {
152 // Use a path under a non-existent directory; open should fail on most systems.
153 const std::string path = "/nonexistent_directory_xyz123/bin_config_test.json";
154 EXPECT_THROW(BinConfigWriter w(path), OpalException);
155}
TEST_F(BinConfigWriterTest, ConstructionOpensFileAndWritesOpeningBracket)
static bool looksLikeJsonArray(const std::string &s)
static std::string readFile(const std::string &path)
Helper to write binning configuration snapshots as a JSON array.
void writeEntry(long long step, double time, bool preMerge, const std::vector< std::size_t > &binCounts, const std::vector< double > &binWidths, double xMin)