AUnit  0.5.0
Unit testing framework for Arduino platforms inspired by ArduinoUnit and Google Test.
Compare.cpp
1 /*
2 MIT License
3 
4 Copyright (c) 2018 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 /*
26 Design Notes:
27 ============
28 This file provides overloaded compareXxx(a, b) functions which are used by
29 the various assertXxx() macros. A primary goal of this file is to allow users
30 to use the assertXxx() macros with all combinations of the 3 types of strings
31 available in the Arduino platform:
32 
33  - (const char *)
34  - (String&)
35  - (const __FlashStringHelper*)
36 
37 Clearly, there are 9 binary combinations these string types.
38 
39 Template Specialization:
40 -----------------------
41 One way to implement the compareEqual() for these types is to use template
42 specialization. The problem with Template specialization is that templates
43 use strict type matching, and does not perform the normal implicit type
44 conversion, including const-casting. Therefore, all of the various c-style
45 string types, for example:
46 
47  - char*
48  - const char*
49  - char[1]
50  - char[N]
51  - const char[1]
52  - const char[N]
53 
54 are considered to be different types under the C++ templating system. This
55 causes a combinatorial explosion of template specialization which produces
56 code that is difficult to understand, test and maintain.
57 An example can be seen in the Compare.h file of the ArduinoUnit project:
58 https://github.com/mmurdoch/arduinounit/blob/master/src/ArduinoUnitUtility/Compare.h
59 
60 Function Overloading:
61 ---------------------
62 In this project, I used function overloading instead of template
63 specialization. Function overloading handles c-style strings (i.e. character
64 arrays) naturally, in the way most users expect. For example, (char*) is
65 automarically cast to (const char*), and (char[N]) is autonmatically
66 cast to (const char*).
67 
68 For the primitive value types (e.g. (char), (int), (unsigned char), etc.) I
69 attempted to use a generic templatized version, using sonmething like:
70 
71  template<typename T>
72  compareEqual(const T& a, const T& b) { ... }
73 
74 However, this template introduced this method:
75 
76  compareEqual(char* const& a, char* const& b);
77 
78 that seemed to take precedence over the explicitly defined overload:
79 
80  compareEqual(const char* a, const char*b);
81 
82 When the compareEqual() method is called with a (char*) or a (char[N]),
83 like this:
84 
85  char a[3] = {...};
86  char b[4] = {...};
87  compareEqual(a, b);
88 
89 this calls compareEqual(char* const&, const* const&), which is the wrong
90 version for a c-style string. The only way I could get this to work was to
91 avoid templates completely and manually define all the function overloads
92 even for primitive integer types.
93 
94 Implicit Conversions:
95 ---------------------
96 For basic primitive types, I depend on some casts to avoid having to define
97 some functions. I assume that signed and unsigned integers smaller or equal
98 to (int) will be converted to an (int) to match compareEqual(int, int).
99 
100 I provided an explicit compareEqual(char, char) overload because in C++, a
101 (char) type is distinct from (signed char) and (unsigned char).
102 
103 Technically, there should be a (long long) version and an (unsigned long
104 long) version of compareEqual(). However, it turns out that the Arduino
105 Print::print() method does not have an overload for these types, so it would
106 not do us much good to provide an assertEqual() or compareEqual() for the
107 (long long) and (unsigned long long) types.
108 
109 Custom Assert and Compare Functions:
110 ------------------------------------
111 Another advantage of using function overloading instead of template
112 specialization is that the user is able to add additional function overloads
113 into the 'aunit' namespace. This should allow the user to define the various
114 comporeXxx() and assertXxx() functions for a custom class. I have not
115 tested this though.
116 
117 Comparing Flash Strings:
118 ----------------------
119 Flash memory must be read using 4-byte alignment on the ESP8266. AVR doesn't
120 care. Teensy-ARM fakes the flash memory API but really just uses the normal
121 static RAM. The following code for comparing two (__FlashStringHelper*)
122 against each other will work for all 3 environments.
123 
124 Inlining:
125 --------
126 Even though most of these functions are one-liners, there is no advantage to
127 inlining them because they are almost always used through a function pointer.
128 */
129 
130 #include <string.h>
131 #include <WString.h>
132 #include "Flash.h"
133 #include "Compare.h"
134 #include "FCString.h"
135 
136 namespace aunit {
137 namespace internal {
138 
139 class FCString;
140 
141 // compareString()
142 
143 int compareString(const char* a, const char* b) {
144  return strcmp(a, b);
145 }
146 
147 int compareString(const char* a, const String& b) {
148  return strcmp(a, b.c_str());
149 }
150 
151 int compareString(const char* a, const __FlashStringHelper* b) {
152  return strcmp_P(a, (const char*)b);
153 }
154 
155 int compareString(const String& a, const char* b) {
156  return strcmp(a.c_str(), b);
157 }
158 
159 int compareString(const String& a, const String& b) {
160  return a.compareTo(b);
161 }
162 
163 int compareString(const String& a, const __FlashStringHelper* b) {
164  return strcmp_P(a.c_str(), (const char*)b);
165 }
166 
167 int compareString(const __FlashStringHelper* a, const char* b) {
168  return -strcmp_P(b, (const char*) a);
169 }
170 
171 // On ESP8266, pgm_read_byte() already takes care of 4-byte alignment, and
172 // memcpy_P(s, p, 4) makes 4 calls to pgm_read_byte() anyway, so don't bother
173 // optimizing for 4-byte alignment here.
174 int compareString(const __FlashStringHelper* a, const __FlashStringHelper* b) {
175  const char* aa = reinterpret_cast<const char*>(a);
176  const char* bb = reinterpret_cast<const char*>(b);
177 
178  while (true) {
179  uint8_t ca = pgm_read_byte(aa);
180  uint8_t cb = pgm_read_byte(bb);
181  if (ca != cb) return (int) ca - (int) cb;
182  if (ca == '\0') return 0;
183  aa++;
184  bb++;
185  }
186 }
187 
188 int compareString(const __FlashStringHelper* a, const String& b) {
189  return -strcmp_P(b.c_str(), (const char*)a);
190 }
191 
192 int compareString(const FCString& a, const FCString& b) {
193  if (a.getType() == FCString::kCStringType) {
194  if (b.getType() == FCString::kCStringType) {
195  return compareString(a.getCString(), b.getCString());
196  } else {
197  return compareString(a.getCString(), b.getFString());
198  }
199  } else {
200  if (b.getType() == FCString::kCStringType) {
201  return compareString(a.getFString(), b.getCString());
202  } else {
203  return compareString(a.getFString(), b.getFString());
204  }
205  }
206 }
207 
208 // compareStringN()
209 
210 int compareStringN(const char* a, const char* b, size_t n) {
211  return strncmp(a, b, n);
212 }
213 
214 int compareStringN(const char* a, const __FlashStringHelper* b, size_t n) {
215  return strncmp_P(a, (const char*)b, n);
216 }
217 
218 int compareStringN(const __FlashStringHelper* a, const char* b, size_t n) {
219  return -strncmp_P(b, (const char*)a, n);
220 }
221 
222 // On ESP8266, pgm_read_byte() already takes care of 4-byte alignment, and
223 // memcpy_P(s, p, 4) makes 4 calls to pgm_read_byte() anyway, so don't bother
224 // optimizing for 4-byte alignment here.
225 int compareStringN(const __FlashStringHelper* a, const __FlashStringHelper* b,
226  size_t n) {
227  const char* aa = reinterpret_cast<const char*>(a);
228  const char* bb = reinterpret_cast<const char*>(b);
229 
230  while (n > 0) {
231  uint8_t ca = pgm_read_byte(aa);
232  uint8_t cb = pgm_read_byte(bb);
233  if (ca != cb) return (int) ca - (int) cb;
234  if (ca == '\0') return 0;
235  aa++;
236  bb++;
237  n--;
238  }
239  return 0;
240 }
241 
242 int compareStringN(const FCString& a, const char* b, size_t n) {
243  if (a.getType() == FCString::kCStringType) {
244  return compareStringN(a.getCString(), b, n);
245  } else {
246  return compareStringN(a.getFString(), b, n);
247  }
248 }
249 
250 int compareStringN(const FCString& a, const __FlashStringHelper* b, size_t n) {
251  if (a.getType() == FCString::kCStringType) {
252  return compareStringN(a.getCString(), b, n);
253  } else {
254  return compareStringN(a.getFString(), b, n);
255  }
256 }
257 
258 // compareEqual()
259 
260 bool compareEqual(bool a, bool b) {
261  return (a == b);
262 }
263 
264 bool compareEqual(char a, char b) {
265  return (a == b);
266 }
267 
268 bool compareEqual(int a, int b) {
269  return (a == b);
270 }
271 
272 bool compareEqual(unsigned int a, unsigned int b) {
273  return (a == b);
274 }
275 
276 bool compareEqual(long a, long b) {
277  return (a == b);
278 }
279 
280 bool compareEqual(unsigned long a, unsigned long b) {
281  return (a == b);
282 }
283 
284 bool compareEqual(double a, double b) {
285  return (a == b);
286 }
287 
288 bool compareEqual(const char* a, const char* b) {
289  return compareString(a, b) == 0;
290 }
291 
292 bool compareEqual(const char* a, const String& b) {
293  return compareString(a, b) == 0;
294 }
295 
296 bool compareEqual(const char* a, const __FlashStringHelper* b) {
297  return compareString(a, b) == 0;
298 }
299 
300 bool compareEqual(const __FlashStringHelper* a, const char* b) {
301  return compareString(a, b) == 0;
302 }
303 
304 bool compareEqual(const __FlashStringHelper* a, const __FlashStringHelper* b) {
305  return compareString(a, b) == 0;
306 }
307 
308 bool compareEqual(const __FlashStringHelper* a, const String& b) {
309  return compareString(a, b) == 0;
310 }
311 
312 bool compareEqual(const String& a, const char* b) {
313  return compareString(a, b) == 0;
314 }
315 
316 bool compareEqual(const String& a, const String& b) {
317  return compareString(a, b) == 0;
318 }
319 
320 bool compareEqual(const String& a, const __FlashStringHelper* b) {
321  return compareString(a, b) == 0;
322 }
323 
324 // compareLess()
325 
326 bool compareLess(bool a, bool b) {
327  return (a < b);
328 }
329 
330 bool compareLess(char a, char b) {
331  return (a < b);
332 }
333 
334 bool compareLess(int a, int b) {
335  return (a < b);
336 }
337 
338 bool compareLess(unsigned int a, unsigned int b) {
339  return (a < b);
340 }
341 
342 bool compareLess(long a, long b) {
343  return (a < b);
344 }
345 
346 bool compareLess(unsigned long a, unsigned long b) {
347  return (a < b);
348 }
349 
350 bool compareLess(double a, double b) {
351  return (a < b);
352 }
353 
354 bool compareLess(const char* a, const char* b) {
355  return compareString(a, b) < 0;
356 }
357 
358 bool compareLess(const char* a, const String& b) {
359  return compareString(a, b) < 0;
360 }
361 
362 bool compareLess(const char* a, const __FlashStringHelper* b) {
363  return compareString(a, b) < 0;
364 }
365 
366 bool compareLess(const __FlashStringHelper* a, const char* b) {
367  return compareString(a, b) < 0;
368 }
369 
370 bool compareLess(
371  const __FlashStringHelper* a, const __FlashStringHelper* b) {
372  return compareString(a, b) < 0;
373 }
374 
375 bool compareLess(const __FlashStringHelper* a, const String& b) {
376  return compareString(a, b) < 0;
377 }
378 
379 bool compareLess(const String& a, const char* b) {
380  return compareString(a, b) < 0;
381 }
382 
383 bool compareLess(const String& a, const String& b) {
384  return compareString(a, b) < 0;
385 }
386 
387 bool compareLess(const String& a, const __FlashStringHelper* b) {
388  return compareString(a, b) < 0;
389 }
390 
391 // compareMore()
392 
393 bool compareMore(bool a, bool b) {
394  return (a > b);
395 }
396 
397 bool compareMore(char a, char b) {
398  return (a > b);
399 }
400 
401 bool compareMore(int a, int b) {
402  return (a > b);
403 }
404 
405 bool compareMore(unsigned int a, unsigned int b) {
406  return (a > b);
407 }
408 
409 bool compareMore(long a, long b) {
410  return (a > b);
411 }
412 
413 bool compareMore(unsigned long a, unsigned long b) {
414  return (a > b);
415 }
416 
417 bool compareMore(double a, double b) {
418  return (a > b);
419 }
420 
421 bool compareMore(const char* a, const char* b) {
422  return compareString(a, b) > 0;
423 }
424 
425 bool compareMore(const char* a, const String& b) {
426  return compareString(a, b) > 0;
427 }
428 
429 bool compareMore(const char* a, const __FlashStringHelper* b) {
430  return compareString(a, b) > 0;
431 }
432 
433 bool compareMore(const __FlashStringHelper* a, const char* b) {
434  return compareString(a, b) > 0;
435 }
436 
437 bool compareMore(const __FlashStringHelper* a, const __FlashStringHelper* b) {
438  return compareString(a, b) > 0;
439 }
440 
441 bool compareMore(const __FlashStringHelper* a, const String& b) {
442  return compareString(a, b) > 0;
443 }
444 
445 bool compareMore(const String& a, const char* b) {
446  return compareString(a, b) > 0;
447 }
448 
449 bool compareMore(const String& a, const String& b) {
450  return compareString(a, b) > 0;
451 }
452 
453 bool compareMore(const String& a, const __FlashStringHelper* b) {
454  return compareString(a, b) > 0;
455 }
456 
457 // compareLessOrEqual
458 
459 bool compareLessOrEqual(bool a, bool b) {
460  return (a <= b);
461 }
462 
463 bool compareLessOrEqual(char a, char b) {
464  return (a <= b);
465 }
466 
467 bool compareLessOrEqual(int a, int b) {
468  return (a <= b);
469 }
470 
471 bool compareLessOrEqual(unsigned int a, unsigned int b) {
472  return (a <= b);
473 }
474 
475 bool compareLessOrEqual(long a, long b) {
476  return (a <= b);
477 }
478 
479 bool compareLessOrEqual(unsigned long a, unsigned long b) {
480  return (a <= b);
481 }
482 
483 bool compareLessOrEqual(double a, double b) {
484  return (a <= b);
485 }
486 
487 bool compareLessOrEqual(const char* a, const char* b) {
488  return compareString(a, b) <= 0;
489 }
490 
491 bool compareLessOrEqual(const char* a, const String& b) {
492  return compareString(a, b) <= 0;
493 }
494 
495 bool compareLessOrEqual(const char* a, const __FlashStringHelper* b) {
496  return compareString(a, b) <= 0;
497 }
498 
499 bool compareLessOrEqual(const __FlashStringHelper* a, const char* b) {
500  return compareString(a, b) <= 0;
501 }
502 
503 bool compareLessOrEqual(
504  const __FlashStringHelper* a, const __FlashStringHelper* b) {
505  return compareString(a, b) <= 0;
506 }
507 
508 bool compareLessOrEqual(const __FlashStringHelper* a, const String& b) {
509  return compareString(a, b) <= 0;
510 }
511 
512 bool compareLessOrEqual(const String& a, const char* b) {
513  return compareString(a, b) <= 0;
514 }
515 
516 bool compareLessOrEqual(const String& a, const String& b) {
517  return compareString(a, b) <= 0;
518 }
519 
520 bool compareLessOrEqual(const String& a, const __FlashStringHelper* b) {
521  return compareString(a, b) <= 0;
522 }
523 
524 // compareMoreOrEqual
525 
526 bool compareMoreOrEqual(bool a, bool b) {
527  return (a >= b);
528 }
529 
530 bool compareMoreOrEqual(char a, char b) {
531  return (a >= b);
532 }
533 
534 bool compareMoreOrEqual(int a, int b) {
535  return (a >= b);
536 }
537 
538 bool compareMoreOrEqual(unsigned int a, unsigned int b) {
539  return (a >= b);
540 }
541 
542 bool compareMoreOrEqual(long a, long b) {
543  return (a >= b);
544 }
545 
546 bool compareMoreOrEqual(unsigned long a, unsigned long b) {
547  return (a >= b);
548 }
549 
550 bool compareMoreOrEqual(double a, double b) {
551  return (a >= b);
552 }
553 
554 bool compareMoreOrEqual(const char* a, const char* b) {
555  return compareString(a, b) >= 0;
556 }
557 
558 bool compareMoreOrEqual(const char* a, const String& b) {
559  return compareString(a, b) >= 0;
560 }
561 
562 bool compareMoreOrEqual(const char* a, const __FlashStringHelper* b) {
563  return compareString(a, b) >= 0;
564 }
565 
566 bool compareMoreOrEqual(const __FlashStringHelper* a, const char* b) {
567  return compareString(a, b) >= 0;
568 }
569 
570 bool compareMoreOrEqual(
571  const __FlashStringHelper* a, const __FlashStringHelper* b) {
572  return compareString(a, b) >= 0;
573 }
574 
575 bool compareMoreOrEqual(const __FlashStringHelper* a, const String& b) {
576  return compareString(a, b) >= 0;
577 }
578 
579 bool compareMoreOrEqual(const String& a, const char* b) {
580  return compareString(a, b) >= 0;
581 }
582 
583 bool compareMoreOrEqual(const String& a, const String& b) {
584  return compareString(a, b) >= 0;
585 }
586 
587 bool compareMoreOrEqual(const String& a, const __FlashStringHelper* b) {
588  return compareString(a, b) >= 0;
589 }
590 
591 // compareNotEqual
592 
593 bool compareNotEqual(bool a, bool b) {
594  return (a != b);
595 }
596 
597 bool compareNotEqual(char a, char b) {
598  return (a != b);
599 }
600 
601 bool compareNotEqual(int a, int b) {
602  return (a != b);
603 }
604 
605 bool compareNotEqual(unsigned int a, unsigned int b) {
606  return (a != b);
607 }
608 
609 bool compareNotEqual(long a, long b) {
610  return (a != b);
611 }
612 
613 bool compareNotEqual(unsigned long a, unsigned long b) {
614  return (a != b);
615 }
616 
617 bool compareNotEqual(double a, double b) {
618  return (a != b);
619 }
620 
621 bool compareNotEqual(const char* a, const char* b) {
622  return compareString(a, b) != 0;
623 }
624 
625 bool compareNotEqual(const char* a, const String& b) {
626  return compareString(a, b) != 0;
627 }
628 
629 bool compareNotEqual(const char* a, const __FlashStringHelper* b) {
630  return compareString(a, b) != 0;
631 }
632 
633 bool compareNotEqual(const __FlashStringHelper* a, const char* b) {
634  return compareString(a, b) != 0;
635 }
636 
637 bool compareNotEqual(
638  const __FlashStringHelper* a, const __FlashStringHelper* b) {
639  return compareString(a, b) != 0;
640 }
641 
642 bool compareNotEqual(const __FlashStringHelper* a, const String& b) {
643  return compareString(a, b) != 0;
644 }
645 
646 bool compareNotEqual(const String& a, const char* b) {
647  return compareString(a, b) != 0;
648 }
649 
650 bool compareNotEqual(const String& a, const String& b) {
651  return compareString(a, b) != 0;
652 }
653 
654 bool compareNotEqual(const String& a, const __FlashStringHelper* b) {
655  return compareString(a, b) != 0;
656 }
657 
658 }
659 }
Flash strings (using F() macro) on the ESP8266 platform cannot be placed in an inline context...