1 #include <iostream>
2 #include <chrono>
3 #include <future>
4 #include <thread>
5 #include <condition_variable>
6 #include "gtest/gtest.h"
7 #define SRT_TEST_CIRCULAR_BUFFER
8 #include "api.h"
9 #include "common.h"
10 
11 using namespace std;
12 
13 
14 // To test CircularBuffer
15 struct Double
16 {
17     double d;
18     size_t instance;
19     static size_t sourceid;
20 
DoubleDouble21     Double(): d(0.0)
22     {
23         instance = ++sourceid;
24         IF_HEAVY_LOGGING(cerr << "(Double/" << instance << ": empty costruction)\n");
25     }
26 
DoubleDouble27     Double(double dd): d(dd)
28     {
29         instance = ++sourceid;
30         IF_HEAVY_LOGGING(cerr << "(Double:/" << instance << " init construction:" << dd << ")\n");
31     }
32 
DoubleDouble33     Double(const Double& dd): d(dd.d)
34     {
35         instance = ++sourceid;
36         IF_HEAVY_LOGGING(cerr << "(Double:/" << instance << " copy construction:" << dd.d << " object/" << dd.instance << ")\n");
37     }
38 
operator doubleDouble39     operator double() { return d; }
40 
~DoubleDouble41     ~Double()
42     {
43         IF_HEAVY_LOGGING(cerr << "(Double:/" << instance << " destruction:" << d << ")\n");
44     }
45 
operator =Double46     void operator=(double dd)
47     {
48         IF_HEAVY_LOGGING(cerr << "(Double:/" << instance << " copy assignment:" << d << " -> " << dd << " value)\n");
49         d = dd;
50     }
51 
operator =Double52     void operator=(const Double& dd)
53     {
54         IF_HEAVY_LOGGING(cerr << "(Double:/" << instance << " copy assignment:" << d << " -> " << dd.d << " object/" << dd.instance << ")\n");
55         d = dd.d;
56     }
57 
58     // Required for template-based gtest :(
operator ==(const Double & l,double r)59     friend bool operator==(const Double& l, double r) { return l.d == r; }
operator ==(double l,const Double r)60     friend bool operator==(double l, const Double r) { return l == r.d; }
operator ==Double61     bool operator == (const Double& r) { return d == r; }
62 };
63 
64 size_t Double::sourceid = 0;
65 
66 
67 template <class Val> inline
ShowCircularBuffer(const CircularBuffer<Val> & buf)68 void ShowCircularBuffer(const CircularBuffer<Val>& buf)
69 {
70     cerr << "SIZE: " << buf.size() << " FREE:" << buf.spaceleft() << " BEGIN:" << buf.m_xBegin << " END: " << buf.m_xEnd << endl;
71     for (int i = 0; i < buf.size(); ++i)
72     {
73         Double v;
74         if (buf.get(i, (v)))
75             cerr << "[" << i << "] = " << v << endl;
76         else
77             cerr << "[" << i << "] EMPTY!\n";
78     }
79 }
80 
81 struct Add
82 {
83     Double v;
AddAdd84     Add(const Double& vv): v(vv) {}
operator ()Add85     void operator()(Double& accessed, bool isnew)
86     {
87         if (isnew)
88             accessed = v;
89         else
90             accessed = Double(accessed.d + v.d);
91     }
92 };
93 
94 
TEST(CircularBuffer,Overall)95 TEST(CircularBuffer, Overall)
96 {
97     using namespace std;
98 
99     // Create some odd number of elements in a circular buffer.
100 
101     CircularBuffer<Double> buf(7);
102 
103     cerr << dec;
104 
105     // Now, add 3 elements to it and check if succeeded.
106     buf.push(11.2);
107     buf.push(12.3);
108     buf.push(13.4);
109 
110     IF_HEAVY_LOGGING(cerr << "After adding 3 elements: size=" << buf.size() << " capacity=" << buf.capacity() << ":\n");
111     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
112     ASSERT_EQ(buf.size(), 3);
113 
114     IF_HEAVY_LOGGING(cerr << "Adding element at position 5:\n");
115     EXPECT_TRUE(buf.set(5, 15.5));
116     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
117     ASSERT_EQ(buf.size(), 6);
118 
119     IF_HEAVY_LOGGING(cerr << "Adding element at position 7 (should fail):\n");
120     EXPECT_FALSE(buf.set(7, 10.0));
121     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
122     ASSERT_EQ(buf.size(), 6);
123 
124     IF_HEAVY_LOGGING(cerr << "Dropping first 2 elements:\n");
125     buf.drop(2);
126     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
127     ASSERT_EQ(buf.size(), 4);
128 
129     IF_HEAVY_LOGGING(cerr << "Adding again element at position 6 (should roll):\n");
130     buf.set(6, 22.1);
131     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
132 
133     IF_HEAVY_LOGGING(cerr << "Adding element at existing position 2 (overwrite):\n");
134     buf.set(2, 33.1);
135     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
136 
137     IF_HEAVY_LOGGING(cerr << "Adding element at existing position 3 (no overwrite):\n");
138     buf.set(3, 44.4, false);
139     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
140 
141     Double output;
142     // [0] = 13.4 (after dropping first 2 elements)
143     EXPECT_TRUE(buf.get(0, (output)));
144     ASSERT_EQ(output, 13.4);
145     // [2] = 33.1 overwriting
146     EXPECT_TRUE(buf.get(2, (output)));
147     ASSERT_EQ(output, 33.1);
148     // [3] = was 15.5, requested to set 44.4, but not overwriting
149     EXPECT_TRUE(buf.get(3, (output)));
150     ASSERT_EQ(output, 15.5);
151     // [6] = 22.1 (as set with rolling)
152     EXPECT_TRUE(buf.get(6, (output)));
153     ASSERT_EQ(output, 22.1);
154 
155     IF_HEAVY_LOGGING(cerr << "Dropping first 4 positions:\n");
156     buf.drop(4);
157     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
158     EXPECT_TRUE(buf.get(2, (output))); // Was 6 before dropping
159     ASSERT_EQ(output.d, 22.1);
160 
161     IF_HEAVY_LOGGING(cerr << "Pushing 1 aslong there is capacity:\n");
162     int i = 0;
163     while (buf.push(1) != -1)
164     {
165         IF_HEAVY_LOGGING(cerr << "Pushed, begin=" << buf.m_xBegin << " end=" << buf.m_xEnd << endl);
166         ++i;
167     }
168     IF_HEAVY_LOGGING(cerr << "Done " << i << " operations, buffer:\n");
169     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
170 
171     IF_HEAVY_LOGGING(cerr << "Updating value at position 5:\n");
172     EXPECT_TRUE(buf.update(5, Add(3.33)));
173     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
174     EXPECT_TRUE(buf.get(5, (output)));
175     ASSERT_EQ(output, 4.33);
176 
177     int offset = 9;
178     IF_HEAVY_LOGGING(cerr << "Forced adding at position 9 with dropping (capacity: " << buf.capacity() << "):\n");
179     // State we already know it has failed. Calculate drop size.
180     int dropshift = offset - (buf.capacity() - 1); // buf.capacity()-1 is the latest position
181     offset -= dropshift;
182     IF_HEAVY_LOGGING(cerr << "Need to drop: " << dropshift << " New offset:" << offset << endl);
183     ASSERT_GE(dropshift, 0);
184     if (dropshift > 0)
185     {
186         buf.drop(dropshift);
187         IF_HEAVY_LOGGING(cerr << "AFTER DROPPING:\n");
188         IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
189         EXPECT_TRUE(buf.set(offset, 99.1, true));
190 
191         // size() - 1 is the latest possible offset
192         ASSERT_EQ(buf.size() - 1 + dropshift, 9);
193     }
194     else
195     {
196         IF_HEAVY_LOGGING(cerr << "NEGATIVE DROP!\n");
197     }
198     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
199     int size = buf.size();
200 
201     IF_HEAVY_LOGGING(cerr << "Dropping rest of the items (passing " << (size) << "):\n");
202 
203     // NOTE: 'drop' gets the POSITION as argument, but this position
204     // is allowed to be past the last addressable position. When passing
205     // the current size, it should make the container empty.
206     buf.drop(size);
207     EXPECT_TRUE(buf.empty());
208 
209     IF_HEAVY_LOGGING(ShowCircularBuffer(buf));
210 
211     IF_HEAVY_LOGGING(cerr << "DONE.\n");
212 }
213 
TEST(ConfigString,Setting)214 TEST(ConfigString, Setting)
215 {
216     using namespace std;
217 
218     static const auto STRSIZE = 20;
219     StringStorage<STRSIZE> s;
220 
221     EXPECT_TRUE(s.empty());
222     EXPECT_EQ(s.size(), 0U);
223     EXPECT_EQ(s.str(), std::string());
224 
225     char example_ac1[] = "example_long";
226     char example_ac2[] = "short";
227     char example_ac3[] = "example_longer";
228     char example_acx[] = "example_long_excessively";
229     char example_ace[] = "";
230 
231     // According to the standard, this array gets automatically
232     // the number of characters + 1 for terminating 0. Get sizeof()-1
233     // to get the number of characters.
234 
235     EXPECT_TRUE(s.set(example_ac1, sizeof (example_ac1)-1));
236     EXPECT_EQ(s.size(), sizeof (example_ac1)-1);
237     EXPECT_FALSE(s.empty());
238 
239     EXPECT_TRUE(s.set(example_ac2, sizeof (example_ac2)-1));
240     EXPECT_EQ(s.size(), sizeof (example_ac2)-1);
241 
242     EXPECT_TRUE(s.set(example_ac3, sizeof (example_ac3)-1));
243     EXPECT_EQ(s.size(), sizeof (example_ac3)-1);
244 
245     EXPECT_FALSE(s.set(example_acx, sizeof (example_acx)-1));
246     EXPECT_EQ(s.size(), sizeof (example_ac3)-1);
247 
248     EXPECT_TRUE(s.set(example_ace, sizeof (example_ace)-1));
249     EXPECT_EQ(s.size(), 0U);
250 
251     string example_s1 = "example_long";
252     string example_s2 = "short";
253     string example_s3 = "example_longer";
254     string example_sx = "example_long_excessively";
255     string example_se = "";
256 
257     EXPECT_TRUE(s.set(example_s1));
258     EXPECT_EQ(s.size(), example_s1.size());
259     EXPECT_FALSE(s.empty());
260 
261     EXPECT_TRUE(s.set(example_s2));
262     EXPECT_EQ(s.size(), example_s2.size());
263 
264     EXPECT_TRUE(s.set(example_s3));
265     EXPECT_EQ(s.size(), example_s3.size());
266 
267     EXPECT_FALSE(s.set(example_sx));
268     EXPECT_EQ(s.size(), example_s3.size());
269 
270     EXPECT_TRUE(s.set(example_se));
271     EXPECT_EQ(s.size(), 0U);
272     EXPECT_TRUE(s.empty());
273 }
274