├── .gitignore ├── README.md ├── index.hxx ├── package.json └── test └── index.cxx /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw* 2 | deps/ 3 | test/index 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SYNOPSIS 2 | A Buffer class. 3 | 4 | 5 | # USAGE 6 | This module is designed to work with the [`datcxx`][0] build tool. To add this 7 | module to your project us the following command... 8 | 9 | ```bash 10 | build add datcxx/buffer 11 | ``` 12 | 13 | 14 | # TEST 15 | 16 | ```bash 17 | build test 18 | ``` 19 | 20 | 21 | # EXAMPLE 22 | 23 | ```c++ 24 | Buffer a(128); 25 | Buffer b = { 0x00, 0xFF }; 26 | 27 | auto c = a.concat(b); 28 | ``` 29 | 30 | # API 31 | 32 | 33 | ## CONSTRUCTOR 34 | The `Buffer` constructor overloads `operator<<` so that it can be easily 35 | piped to `std` streams ie `std::cout`. 36 | 37 | ```c++ 38 | Buffer b; 39 | ``` 40 | 41 | ```c++ 42 | Buffer b(size_t size); 43 | ``` 44 | 45 | ```c++ 46 | Buffer b = { 0x00, 0x00 }; 47 | ``` 48 | 49 | ```c++ 50 | Buffer b({ 0x00, 0x00 }); 51 | ``` 52 | 53 | ```c++ 54 | Buffer b(anotherBuffer); 55 | ``` 56 | 57 | 58 | ## METHODS 59 | 60 | 61 | ### length() 62 | Returns an `integer`, the amount of memory allocated for buf in bytes. Note that 63 | this does not necessarily reflect the amount of "usable" data within buf. 64 | 65 | #### EXAMPLE 66 | ```c++ 67 | Buffer b = { 0x00, 0x00 }; 68 | b.length(); // 2 69 | ``` 70 | 71 | ### toString() 72 | Returns a `std::string` version of the buffer's value. 73 | 74 | ### toString(const std::string encoding, size_t start, size_t end) 75 | Returns an encoded `std::String` (at optionally specified start and end). 76 | 77 | | Type | Parameter | Default Value | Optional | Description | 78 | | ----------- | ----------- | ------------- | -------- | ---------------------------------------------------------------- | 79 | | std::string | encoding | | No | Encoding, currently supports either "base64" or "hex". | 80 | | size_t | start | 0 | Yes | The offset within buf from which to begin the slice. | 81 | | size_t | end | buf.length() | Yes | The offset within buf at which to stop the slice. | 82 | 83 | 84 | #### EXAMPLE 85 | ```c++ 86 | Buffer b("Hello, world!"); 87 | b.toString("base64"); // "SGVsbG8sIHdvcmxkIQ==" 88 | ``` 89 | 90 | ### copy(target[, targetStart[, sourceStart[, sourceEnd]]] 91 | Returns an `integer`, the number of bytes copied. 92 | 93 | | Type | Parameter | Default Value | Optional | Description | 94 | | ------ | ----------- | ------------- | -------- | ---------------------------------------------------------------- | 95 | | Buffer | target | | No | A Buffer to copy into. | 96 | | size_t | targetStart | 0 | Yes | The offset within target at which to begin writing. | 97 | | size_t | sourceStart | 0 | Yes | The offset within buf from which to begin copying. | 98 | | size_t | sourceEnd | buf.length() | Yes | The offset within buf at which to stop. copying (not inclusive). | 99 | 100 | 101 | #### EXAMPLE 102 | ```c++ 103 | Buffer a({ 01, 02, 03, 04, 05, 06, 07, 0xFF }); 104 | Buffer b({ 00, 00, 00, 00, 00, 00 }); 105 | a.copy(b, 3, 2); 106 | 107 | // a == 108 | // b == 109 | ``` 110 | 111 | ### concat([buffer[, ...]]) 112 | Returns a new Buffer, the result of concatenating a list of Buffer instances. 113 | 114 | 115 | #### EXAMPLE 116 | ```c++ 117 | Buffer a({ 0x01, 0x02 }); 118 | Buffer b({ 0x03, 0x04 }); 119 | Buffer c({ 0x05, 0x06 }); 120 | 121 | auto d = a.concat({ b, c }); 122 | 123 | // d == 124 | ``` 125 | 126 | ### equals(buffer) 127 | To compare two buffers you can use the `==` and `!=` operators. Each 128 | element in the buffer will be compared, if all are equal the result is `true`. 129 | 130 | #### EXAMPLE 131 | ```c++ 132 | Buffer b({ 0x03, 0x04 }); 133 | Buffer c({ 0x05, 0x06 }); 134 | 135 | b != c; // true 136 | ``` 137 | 138 | 139 | ### slice(start[, end]) 140 | Returns a new instance of Buffer that references the same memory as the 141 | original, but offset and cropped by the start and end indices. 142 | 143 | 144 | | Type | Parameter | Default Value | Optional | Description | 145 | | ------ | --------- | ------------- | -------- | ---------------------------------------------- | 146 | | size_t | start | 0 | No | Where the new Buffer will start. | 147 | | size_t | end | buf.length() | Yes | Where the new Buffer will end (not inclusive). | 148 | 149 | 150 | #### EXAMPLE 151 | ```c++ 152 | Buffer b({ 0x01, 0x02, 0x03, 0x04 }); 153 | 154 | auto slice = b.slice(2, 4); // 155 | ``` 156 | 157 | [0]:https://github.com/datcxx/build 158 | -------------------------------------------------------------------------------- /index.hxx: -------------------------------------------------------------------------------- 1 | #ifndef HYPER_UTIL_BUFFER_H 2 | #define HYPER_UTIL_BUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "deps/datcxx/sodium-encodedecode/index.hxx" 14 | 15 | /// 16 | /// namespace Hyper 17 | /// 18 | namespace Hyper { 19 | 20 | /// 21 | /// namespace Util 22 | /// 23 | namespace Util { 24 | 25 | /// 26 | /// class Buffer 27 | /// comment A class that provides some convenient methods for managing buffers. 28 | /// 29 | template 30 | class Buffer { 31 | public: 32 | 33 | /// 34 | /// property vector value 35 | /// comment Contains a vector of the type the constructor was specialized with. 36 | /// 37 | std::vector value; 38 | 39 | class OutOfRange : public std::exception { 40 | virtual const char* what() const throw() { 41 | return "Out Of Range Exception"; 42 | } 43 | } EX_OUT_OF_RANGE; 44 | 45 | // bool equals(Buffer b); 46 | // int indexOf(T value, int byteOffset); 47 | 48 | /// 49 | /// operator = 50 | /// comment Assign one buffer to another. 51 | /// 52 | Buffer& operator= (const Buffer& buf); 53 | 54 | /// 55 | /// operator == 56 | /// comment Determine if two buffers values are equal. 57 | /// 58 | bool operator== (const Buffer& rhs) { 59 | return std::equal( 60 | std::begin(this->value), 61 | std::end(this->value), 62 | std::begin(rhs.value) 63 | ); 64 | } 65 | 66 | /// 67 | /// operator != 68 | /// comment Determine if two buffers values are not equal. 69 | /// 70 | bool operator!= (const Buffer& rhs) { 71 | return !std::equal( 72 | std::begin(this->value), 73 | std::end(this->value), 74 | std::begin(rhs.value) 75 | ); 76 | } 77 | 78 | 79 | /// 80 | /// operator << 81 | /// comment Allow buffers to interface with streams. The value of the 82 | /// comment buffer will be represented as hex in a angle-bracket delimited 83 | /// comment string. 84 | /// 85 | friend std::ostream& operator<< (std::ostream &os, const Buffer& buf) { 86 | if (buf.value.empty()) { 87 | os << ""; 88 | return os; 89 | } 90 | 91 | std::ios_base::fmtflags f(std::cout.flags()); 92 | 93 | os << ""; 102 | 103 | return os; 104 | }; 105 | 106 | /// 107 | /// operator [] 108 | /// comment Provides access of the buffer via index. 109 | /// 110 | T operator[] (int i) { 111 | return this->value[i]; 112 | } 113 | 114 | /// 115 | /// constructor Buffer(initializer_list list) 116 | /// comment Constructs a buffer from an initializer list. 117 | /// 118 | Buffer(std::initializer_list l) : value(l) {} 119 | 120 | /// 121 | /// constructor Buffer() 122 | /// comment Constructs an empty buffer. 123 | /// 124 | Buffer() { 125 | this->value = std::vector(0); 126 | }; 127 | 128 | /// 129 | /// constructor Buffer(size_t size) 130 | /// comment Constructs a buffer with a value of `size`. 131 | /// 132 | /// param size The size initially allocated for the buffer value. 133 | /// 134 | Buffer(size_t size) { 135 | this->value = std::vector(size); 136 | }; 137 | 138 | /// 139 | /// constructor Buffer(const string& str) 140 | /// comment Constructs a buffer from a string. 141 | /// 142 | Buffer(const std::string& str) { 143 | this->value = std::vector(str.begin(), str.end()); 144 | }; 145 | 146 | /// 147 | /// constructor Buffer(const Buffer& buf) 148 | /// comment Constructs a buffer from another buffer. 149 | /// 150 | Buffer(const Buffer& buf) { 151 | this->value = buf.value; 152 | }; 153 | 154 | /// 155 | /// method fill(const std::string str, size_t start = 0, size_t end = 0) 156 | /// comment Fill the buffer with str from start to end. 157 | /// 158 | /// return Buffer 159 | /// comment Returns a new buffer containing the fill. 160 | /// 161 | Buffer fill(const std::string str, size_t start = 0, size_t end = 0) { 162 | auto size = this->value.size(); 163 | 164 | // don't allow start to be greater than the underlying buffer size. 165 | if (start > size) { 166 | start = size; 167 | } 168 | 169 | // if start is greater than zero, subtract that from the size. 170 | if (start > 0) { 171 | size -= start; 172 | } 173 | 174 | // if end is zero or greater than size, bring it back down to size. 175 | if (end == 0 || end > size) { 176 | end = size; 177 | } 178 | 179 | // construct a return buffer that duplicates the underlying buffer. 180 | Buffer res(this->value.size()); 181 | res.value = this->value; 182 | 183 | for (int i = start; i < end;) { 184 | for (auto& ch : str) { 185 | res.value[i++] = ch; 186 | } 187 | } 188 | 189 | return res; 190 | }; 191 | 192 | /// 193 | /// method toString() 194 | /// comment Get the value of of the buffer as a string. 195 | /// 196 | /// return std::string 197 | /// 198 | std::string toString() { 199 | std::string str(this->value.begin(), this->value.end()); 200 | return str; 201 | }; 202 | 203 | /// 204 | /// method toString(const std::string& encoding, size_t start = 0, size_t end = 0) 205 | /// comment Get the value of of the buffer as a string. 206 | /// 207 | /// param encoding type (currently supports "base64" or "hex"). 208 | /// 209 | /// return std::string 210 | /// 211 | std::string toString(const std::string& encoding, size_t start = 0, size_t end = 0) { 212 | if (end == 0) { 213 | end = this->value.size(); 214 | } else if (end < start) { 215 | return ""; 216 | } 217 | 218 | std::stringstream ss; 219 | 220 | std::string substring( 221 | this->value.begin() + start, 222 | this->value.begin() + end 223 | ); 224 | 225 | if (encoding == "base64") { 226 | return Hyper::Sodium::Base64::encode(substring); 227 | } 228 | 229 | if (encoding == "hex") { 230 | return Hyper::Sodium::Hex::encode(substring); 231 | } 232 | 233 | ss << substring; 234 | return ss.str(); 235 | }; 236 | 237 | /// 238 | /// method length() 239 | /// comment Get the size of the buffer in by bytes. 240 | /// 241 | /// return int 242 | /// 243 | int length() { 244 | return this->value.size(); 245 | }; 246 | 247 | /// 248 | /// method concat(initializer_list& list) 249 | /// comment Concatinate this buffer with a list of buffers. 250 | /// 251 | /// param list A list of buffers to be joined. 252 | /// 253 | /// return Buffer 254 | /// comment Returns a new combined buffer. 255 | /// 256 | template 257 | Buffer concat(const std::initializer_list& list) { 258 | using std::end; 259 | using std::begin; 260 | 261 | unsigned size = 0; 262 | Buffer cpy(size); 263 | 264 | for (auto& buf : list) { 265 | size += this->value.size() + buf.value.size(); 266 | 267 | this->value.reserve(size); 268 | this->value.insert(end(this->value), begin(buf.value), end(buf.value)); 269 | } 270 | 271 | cpy.value = this->value; 272 | return cpy; 273 | }; 274 | 275 | /// 276 | /// method copy(Buffer& target, size_t targetStart, size_t sourceStart, size_t sourceEnd) 277 | /// comment Copies this buffer (or part of it) into another buffer. 278 | /// 279 | /// param target A Buffer to copy into. 280 | /// param targetStart The offset within target at which to begin writing. 281 | /// param sourceStart The offset within buf from which to begin copying. 282 | /// param sourceEnd The offset within buf at which to stop. copying (not inclusive). 283 | /// 284 | /// return size_t 285 | /// comment Returns how many bytes were written to this buffer. 286 | /// 287 | size_t copy (Buffer& buf, size_t targetStart, size_t sourceStart, size_t sourceEnd) { 288 | using std::end; 289 | using std::begin; 290 | 291 | auto& source = this->value; 292 | auto& target = buf.value; 293 | 294 | if (targetStart >= target.size() || sourceStart >= sourceEnd) { 295 | return 0; 296 | } 297 | 298 | if (sourceStart > target.size()) { 299 | throw EX_OUT_OF_RANGE; 300 | } 301 | 302 | if (sourceEnd - sourceStart > target.size() - targetStart) { 303 | sourceEnd = sourceStart + target.size() - targetStart; 304 | } 305 | 306 | unsigned size = std::min( 307 | std::min(sourceEnd - sourceStart, target.size() - targetStart), 308 | target.size() - targetStart 309 | ); 310 | 311 | if (buf.value.size() < size) { 312 | buf.value.resize(size); 313 | } 314 | 315 | std::copy( 316 | begin(source) + sourceStart, 317 | begin(source) + sourceEnd, 318 | begin(target) + targetStart 319 | ); 320 | 321 | return size; 322 | }; 323 | 324 | /// 325 | /// overload copy(Buffer& target) 326 | /// 327 | /// return size_t 328 | /// 329 | size_t copy (Buffer& buf) { 330 | if (buf.value.size() == 0) { 331 | return 0; 332 | } 333 | 334 | buf.value = std::vector (this->value); 335 | return buf.value.size(); 336 | }; 337 | 338 | /// 339 | /// overload copy(Buffer& target, size_t targetStart) 340 | /// 341 | /// return size_t 342 | /// 343 | size_t copy (Buffer& buf, size_t targetStart) { 344 | return copy(buf, targetStart, 0, buf.value.size()); 345 | }; 346 | 347 | /// 348 | /// overload copy(Buffer& target, size_t targetStart, size_t sourceStart) 349 | /// 350 | /// return size_t 351 | /// 352 | size_t copy (Buffer& buf, size_t targetStart, size_t sourceStart) { 353 | return copy(buf, targetStart, sourceStart, buf.value.size()); 354 | }; 355 | 356 | /// 357 | /// method slice(size_t from, size_t to) 358 | /// comment provides a new buffer that represents a slice of this one. 359 | /// 360 | /// param from Where the new Buffer will start. Default: 0. 361 | /// param to Where the new Buffer will end (not inclusive). Default: buf.length. 362 | /// 363 | /// return Buffer 364 | /// 365 | Buffer slice(size_t from, size_t to) { 366 | const auto size = this->value.size(); 367 | 368 | if (from > size || to > size) { 369 | Buffer buf; 370 | return buf; 371 | } 372 | 373 | auto _from = std::begin(this->value) + from; 374 | auto _to = std::begin(this->value) + to; 375 | 376 | std::vector value(_from, _to); 377 | 378 | Buffer buf(value.size()); 379 | buf.value = value; 380 | return buf; 381 | }; 382 | 383 | /// 384 | /// overload slice(size_t from) 385 | /// return Buffer 386 | /// 387 | Buffer slice(size_t from) { 388 | return slice(from, this->value.size()); 389 | }; 390 | 391 | ~Buffer () { 392 | this->value.clear(); 393 | }; 394 | }; 395 | } // namespace Util 396 | } // namespace Hyper 397 | 398 | #endif 399 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "buffer", 3 | "description": "buffers class", 4 | "repository": { 5 | "type": "git", 6 | "url": "git@github.com:datcxx/buffer.git" 7 | }, 8 | "devDependencies": { 9 | "git@github.com:heapwolf/cxx-tap": "07821de0" 10 | }, 11 | "license": "MIT", 12 | "scripts": { 13 | "test": "clang++ test/index.cxx -o test/index && ./test/index", 14 | "install": "" 15 | }, 16 | "flags": [ 17 | "-std=c++2a", 18 | "-stdlib=libc++" 19 | ], 20 | "files": [ 21 | "index.hxx" 22 | ], 23 | "dependencies": { 24 | "git@github.com:datcxx/sodium-encodedecode": "345051bd" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/index.cxx: -------------------------------------------------------------------------------- 1 | #include "../index.hxx" 2 | #include "../deps/heapwolf/cxx-tap/index.hxx" 3 | 4 | #include 5 | #include 6 | 7 | int main() { 8 | using namespace Hyper::Util; 9 | 10 | TAP::Test t; 11 | 12 | t.test("sanity", [](auto t) { 13 | t->ok(true, "true is true"); 14 | t->end(); 15 | }); 16 | 17 | t.test("constructor Buffer(n)", [](auto t) { 18 | Buffer buf(3); 19 | t->equal(buf.length(), 3, "constructed with size"); 20 | t->end(); 21 | }); 22 | 23 | t.test("constructor Buffer({ el, ... })", [](auto t) { 24 | Buffer buf({ 0xFF, 0xF1 }); 25 | t->equal(buf.length(), 2, "constructed with literal"); 26 | t->end(); 27 | }); 28 | 29 | t.test("constructor Buffer(string)", [](auto t) { 30 | Buffer buf("sup"); 31 | t->equal(buf.length(), 3, "constructed with string"); 32 | t->end(); 33 | }); 34 | 35 | t.test("construct from another instance", [](auto t) { 36 | Buffer a("sup"); 37 | Buffer b(a); 38 | t->equal(b.length(), 3, "constructed from another instance"); 39 | t->end(); 40 | }); 41 | 42 | t.test("element access by index", [](auto t) { 43 | Buffer buf({ 0xFF, 0xF1 }); 44 | t->equal(buf[0], 0xFF, "index[0]"); 45 | t->equal(buf[1], 0xF1, "index[1]"); 46 | t->end(); 47 | }); 48 | 49 | t.test("toString() method", [](auto t) { 50 | Buffer buf("sup"); 51 | t->equal(buf.toString(), "sup", "expected stringified value"); 52 | t->end(); 53 | }); 54 | 55 | t.test("concat() method", [](auto t) { 56 | Buffer a({ 0x01, 0x02 }); 57 | Buffer b({ 0x03, 0x04 }); 58 | Buffer c({ 0x05, 0x06 }); 59 | 60 | auto d = a.concat({ b, c }); 61 | 62 | t->equal(d.length(), 6, "length is equal"); 63 | t->equal(d[2], 0x03, "values are in order"); 64 | t->equal(d[5], 0x06, "values are in order"); 65 | 66 | std::cout << std::endl << "# " << d; 67 | 68 | t->end(); 69 | }); 70 | 71 | t.test("ostream overload", [](auto t) { 72 | Buffer a({ 0xf1, 0x02 }); 73 | 74 | std::stringstream ss; 75 | ss << a; 76 | 77 | t->equal(ss.str(), "", "ostream output correct"); 78 | t->end(); 79 | }); 80 | 81 | t.test("ostream empty buffer", [](auto t) { 82 | Buffer a({}); 83 | 84 | std::stringstream ss; 85 | ss << a; 86 | 87 | t->equal(ss.str(), "", "string is empty"); 88 | t->end(); 89 | }); 90 | 91 | t.test("a.copy(b) where b is zero bytes", [](auto t) { 92 | Buffer a({ 0x00, 0x01, 0x02, 0xff }); 93 | Buffer b; 94 | a.copy(b); 95 | t->equal(b.length(), 0, "target is zero bytes"); 96 | t->end(); 97 | }); 98 | 99 | t.test("compare buffers", [](auto t) { 100 | Buffer a({ 0x00, 0x01, 0xff, 0x00 }); 101 | Buffer b({ 0x00, 0x01, 0xff, 0x00 }); 102 | Buffer c({ 0x02, 0x00, 0xff, 0x00 }); 103 | t->ok(a == b, "buffers are the same"); 104 | t->ok(a != c, "buffers are not the same"); 105 | t->end(); 106 | }); 107 | 108 | t.test("a.copy(b)", [](auto t) { 109 | Buffer a({ 0x00, 0x01, 0x02, 0xff }); 110 | Buffer b(4); 111 | a.copy(b); 112 | t->equal(a[0], b[0], "values at index[0] are equal"); 113 | t->equal(a[1], b[1], "values at index[1] are equal"); 114 | t->equal(a[2], b[2], "values at index[2] are equal"); 115 | t->equal(a[3], b[3], "values at index[3] are equal"); 116 | t->equal(a.length(), b.length(), "values are the same size"); 117 | t->end(); 118 | }); 119 | 120 | t.test("copy from A to B start at target offset", [](auto t) { 121 | Buffer a({ 0x01, 0x02, 0x03, 0x04, 0x05 }); 122 | Buffer b(6); 123 | a.copy(b, 1); 124 | 125 | std::cout << std::endl << "# " << a; 126 | std::cout << std::endl << "# " << b; 127 | 128 | t->equal(b[0], 0, "values at index[0] are equal"); 129 | t->equal(b[1], 1, "values at index[1] are equal"); 130 | t->equal(b.length(), 6, "values are the same size"); 131 | t->end(); 132 | }); 133 | 134 | t.test("copy from a to b, target offset and source offset", [](auto t) { 135 | Buffer a({ 01, 02, 03, 04, 05, 06, 07, 0xFF }); 136 | Buffer b({ 00, 00, 00, 00, 00, 00 }); 137 | t->equal(a.copy(b, 3, 2), 3, "correct number of bytes written"); 138 | 139 | std::cout << std::endl << "# " << a; 140 | std::cout << std::endl << "# " << b; 141 | 142 | t->equal(b[0], 0, "value at index[0] is correct"); 143 | t->equal(b[1], 0, "value at index[1] is correct"); 144 | t->equal(b[2], 0, "value at index[2] is correct"); 145 | t->equal(b[3], 3, "value at index[3] is correct"); 146 | t->equal(b[4], 4, "value at index[4] is correct"); 147 | t->equal(b[5], 5, "value at index[5] is correct"); 148 | t->equal(b.length(), 6, "length is correct"); 149 | t->end(); 150 | }); 151 | 152 | t.test("slice", [](auto t) { 153 | Buffer a({ 0x01, 0x02, 0x03, 0x04 }); 154 | auto sliceA = a.slice(0, 2); 155 | t->equal(sliceA[0], 1, "value at index[0] is correct"); 156 | t->equal(sliceA[1], 2, "value at index[1] is correct"); 157 | t->equal(sliceA.length(), 2, "new buffer is correct length"); 158 | 159 | std::cout << std::endl << "# " << sliceA; 160 | 161 | auto sliceB = a.slice(2, 4); 162 | t->equal(sliceB[0], 3, "value at index[0] is correct"); 163 | t->equal(sliceB[1], 4, "value at index[1] is correct"); 164 | t->equal(sliceB.length(), 2, "new buffer is correct length"); 165 | 166 | std::cout << std::endl << "# " << sliceB; 167 | 168 | auto sliceC = a.slice(2); 169 | 170 | std::cout << std::endl << "# " << sliceC; 171 | 172 | t->ok(sliceB == sliceC, "buffers are the same"); 173 | t->ok(sliceA != sliceC, "buffers are the same"); 174 | t->end(); 175 | }); 176 | 177 | t.test("fill(string)", [](auto t) { 178 | { 179 | Buffer a(8); 180 | auto b = a.fill("o"); 181 | std::string expected = "oooooooo"; 182 | t->equal(b.toString(), expected, "strings are equal"); 183 | } 184 | 185 | { 186 | Buffer a(8); 187 | auto b = a.fill("xo"); 188 | std::string expected = "xoxoxoxo"; 189 | t->equal(b.toString(), expected, "strings are equal"); 190 | } 191 | t->end(); 192 | }); 193 | 194 | t.test("toString()", [](auto t) { 195 | Buffer a("abc"); 196 | std::string expected = "abc"; 197 | t->equal(a.toString(), expected, "strings are equal"); 198 | t->end(); 199 | }); 200 | 201 | t.test("toString(\"hex\", 0, 0)", [](auto t) { 202 | Buffer a("abc"); 203 | std::string expected = "616263"; 204 | 205 | t->equal(a.toString("hex"), expected, "hex strings are equal"); 206 | t->end(); 207 | }); 208 | 209 | t.test("toString(\"hex\", 3, 9)", [](auto t) { 210 | Buffer a("abcdef0123456789"); 211 | std::string expected = "646566303132"; 212 | 213 | t->equal(a.toString("hex", 3, 9), expected, "strings are equal"); 214 | t->end(); 215 | }); 216 | 217 | t.test("toString(\"base64\")", [](auto t) { 218 | Buffer buf("Hello, world!"); 219 | std::string expected = "SGVsbG8sIHdvcmxkIQ=="; 220 | 221 | t->equal(buf.toString("base64"), expected, "strings are equal"); 222 | t->end(); 223 | }); 224 | 225 | t.test("toString(\"base64\", 1, 5)", [](auto t) { 226 | Buffer buf("Hello, world!"); 227 | std::string expected = "ZWxsbw=="; 228 | 229 | t->equal(buf.toString("base64", 1, 5), expected, "strings are equal"); 230 | t->notEqual(buf.toString("base64", 1, 4), expected, "strings are not equal"); 231 | t->end(); 232 | }); 233 | } 234 | --------------------------------------------------------------------------------