AUnit  0.3.1
Unit testing framework for Arduino platforms inspired by ArduinoUnit.
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 intergers 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 
133 #ifdef ESP8266
134 #include <pgmspace.h>
135 #else
136 #include <avr/pgmspace.h>
137 #endif
138 
139 #include "Compare.h"
140 #include "FCString.h"
141 
142 namespace aunit {
143 
144 // compareString()
145 
146 int compareString(const char* a, const char* b) {
147  return strcmp(a, b);
148 }
149 
150 int compareString(const char* a, const String& b) {
151  return strcmp(a, b.c_str());
152 }
153 
154 int compareString(const char* a, const __FlashStringHelper* b) {
155  return strcmp_P(a, (const char*)b);
156 }
157 
158 int compareString(const String& a, const char* b) {
159  return strcmp(a.c_str(), b);
160 }
161 
162 int compareString(const String& a, const String& b) {
163  return a.compareTo(b);
164 }
165 
166 int compareString(const String& a, const __FlashStringHelper* b) {
167  return strcmp_P(a.c_str(), (const char*)b);
168 }
169 
170 int compareString(const __FlashStringHelper* a, const char* b) {
171  return -strcmp_P(b, (const char*) a);
172 }
173 
174 // On ESP8266, pgm_read_byte() already takes care of 4-byte alignment, and
175 // memcpy_P(s, p, 4) makes 4 calls to pgm_read_byte() anyway, so don't bother
176 // optimizing for 4-byte alignment here.
177 int compareString(const __FlashStringHelper* a, const __FlashStringHelper* b) {
178  const char* aa = reinterpret_cast<const char*>(a);
179  const char* bb = reinterpret_cast<const char*>(b);
180 
181  while (true) {
182  uint8_t ca = pgm_read_byte(aa);
183  uint8_t cb = pgm_read_byte(bb);
184  if (ca != cb) return (int) ca - (int) cb;
185  if (ca == '\0') return 0;
186  aa++;
187  bb++;
188  }
189 }
190 
191 int compareString(const __FlashStringHelper* a, const String& b) {
192  return -strcmp_P(b.c_str(), (const char*)a);
193 }
194 
195 int compareString(const FCString& a, const FCString& b) {
196  if (a.getType() == FCString::kCStringType) {
197  if (b.getType() == FCString::kCStringType) {
198  return compareString(a.getCString(), b.getCString());
199  } else {
200  return compareString(a.getCString(), b.getFString());
201  }
202  } else {
203  if (b.getType() == FCString::kCStringType) {
204  return compareString(a.getFString(), b.getCString());
205  } else {
206  return compareString(a.getFString(), b.getFString());
207  }
208  }
209 }
210 
211 // compareStringN()
212 
213 int compareStringN(const char* a, const char* b, size_t n) {
214  return strncmp(a, b, n);
215 }
216 
217 int compareStringN(const char* a, const __FlashStringHelper* b, size_t n) {
218  return strncmp_P(a, (const char*)b, n);
219 }
220 
221 int compareStringN(const __FlashStringHelper* a, const char* b, size_t n) {
222  return -strncmp_P(b, (const char*)a, n);
223 }
224 
225 // On ESP8266, pgm_read_byte() already takes care of 4-byte alignment, and
226 // memcpy_P(s, p, 4) makes 4 calls to pgm_read_byte() anyway, so don't bother
227 // optimizing for 4-byte alignment here.
228 int compareStringN(const __FlashStringHelper* a, const __FlashStringHelper* b,
229  size_t n) {
230  const char* aa = reinterpret_cast<const char*>(a);
231  const char* bb = reinterpret_cast<const char*>(b);
232 
233  while (n > 0) {
234  uint8_t ca = pgm_read_byte(aa);
235  uint8_t cb = pgm_read_byte(bb);
236  if (ca != cb) return (int) ca - (int) cb;
237  if (ca == '\0') return 0;
238  aa++;
239  bb++;
240  n--;
241  }
242  return 0;
243 }
244 
245 int compareStringN(const FCString& a, const char* b, size_t n) {
246  if (a.getType() == FCString::kCStringType) {
247  return compareStringN(a.getCString(), b, n);
248  } else {
249  return compareStringN(a.getFString(), b, n);
250  }
251 }
252 
253 int compareStringN(const FCString& a, const __FlashStringHelper* b, size_t n) {
254  if (a.getType() == FCString::kCStringType) {
255  return compareStringN(a.getCString(), b, n);
256  } else {
257  return compareStringN(a.getFString(), b, n);
258  }
259 }
260 
261 // compareEqual()
262 
263 bool compareEqual(bool a, bool b) {
264  return (a == b);
265 }
266 
267 bool compareEqual(char a, char b) {
268  return (a == b);
269 }
270 
271 bool compareEqual(int a, int b) {
272  return (a == b);
273 }
274 
275 bool compareEqual(unsigned int a, unsigned int b) {
276  return (a == b);
277 }
278 
279 bool compareEqual(long a, long b) {
280  return (a == b);
281 }
282 
283 bool compareEqual(unsigned long a, unsigned long b) {
284  return (a == b);
285 }
286 
287 bool compareEqual(double a, double b) {
288  return (a == b);
289 }
290 
291 bool compareEqual(const char* a, const char* b) {
292  return compareString(a, b) == 0;
293 }
294 
295 bool compareEqual(const char* a, const String& b) {
296  return compareString(a, b) == 0;
297 }
298 
299 bool compareEqual(const char* a, const __FlashStringHelper* b) {
300  return compareString(a, b) == 0;
301 }
302 
303 bool compareEqual(const __FlashStringHelper* a, const char* b) {
304  return compareString(a, b) == 0;
305 }
306 
307 bool compareEqual(const __FlashStringHelper* a, const __FlashStringHelper* b) {
308  return compareString(a, b) == 0;
309 }
310 
311 bool compareEqual(const __FlashStringHelper* a, const String& b) {
312  return compareString(a, b) == 0;
313 }
314 
315 bool compareEqual(const String& a, const char* b) {
316  return compareString(a, b) == 0;
317 }
318 
319 bool compareEqual(const String& a, const String& b) {
320  return compareString(a, b) == 0;
321 }
322 
323 bool compareEqual(const String& a, const __FlashStringHelper* b) {
324  return compareString(a, b) == 0;
325 }
326 
327 // compareLess()
328 
329 bool compareLess(bool a, bool b) {
330  return (a < b);
331 }
332 
333 bool compareLess(char a, char b) {
334  return (a < b);
335 }
336 
337 bool compareLess(int a, int b) {
338  return (a < b);
339 }
340 
341 bool compareLess(unsigned int a, unsigned int b) {
342  return (a < b);
343 }
344 
345 bool compareLess(long a, long b) {
346  return (a < b);
347 }
348 
349 bool compareLess(unsigned long a, unsigned long b) {
350  return (a < b);
351 }
352 
353 bool compareLess(double a, double b) {
354  return (a < b);
355 }
356 
357 bool compareLess(const char* a, const char* b) {
358  return compareString(a, b) < 0;
359 }
360 
361 bool compareLess(const char* a, const String& b) {
362  return compareString(a, b) < 0;
363 }
364 
365 bool compareLess(const char* a, const __FlashStringHelper* b) {
366  return compareString(a, b) < 0;
367 }
368 
369 bool compareLess(const __FlashStringHelper* a, const char* b) {
370  return compareString(a, b) < 0;
371 }
372 
373 bool compareLess(
374  const __FlashStringHelper* a, const __FlashStringHelper* b) {
375  return compareString(a, b) < 0;
376 }
377 
378 bool compareLess(const __FlashStringHelper* a, const String& b) {
379  return compareString(a, b) < 0;
380 }
381 
382 bool compareLess(const String& a, const char* b) {
383  return compareString(a, b) < 0;
384 }
385 
386 bool compareLess(const String& a, const String& b) {
387  return compareString(a, b) < 0;
388 }
389 
390 bool compareLess(const String& a, const __FlashStringHelper* b) {
391  return compareString(a, b) < 0;
392 }
393 
394 // compareMore()
395 
396 bool compareMore(bool a, bool b) {
397  return (a > b);
398 }
399 
400 bool compareMore(char a, char b) {
401  return (a > b);
402 }
403 
404 bool compareMore(int a, int b) {
405  return (a > b);
406 }
407 
408 bool compareMore(unsigned int a, unsigned int b) {
409  return (a > b);
410 }
411 
412 bool compareMore(long a, long b) {
413  return (a > b);
414 }
415 
416 bool compareMore(unsigned long a, unsigned long b) {
417  return (a > b);
418 }
419 
420 bool compareMore(double a, double b) {
421  return (a > b);
422 }
423 
424 bool compareMore(const char* a, const char* b) {
425  return compareString(a, b) > 0;
426 }
427 
428 bool compareMore(const char* a, const String& b) {
429  return compareString(a, b) > 0;
430 }
431 
432 bool compareMore(const char* a, const __FlashStringHelper* b) {
433  return compareString(a, b) > 0;
434 }
435 
436 bool compareMore(const __FlashStringHelper* a, const char* b) {
437  return compareString(a, b) > 0;
438 }
439 
440 bool compareMore(const __FlashStringHelper* a, const __FlashStringHelper* b) {
441  return compareString(a, b) > 0;
442 }
443 
444 bool compareMore(const __FlashStringHelper* a, const String& b) {
445  return compareString(a, b) > 0;
446 }
447 
448 bool compareMore(const String& a, const char* b) {
449  return compareString(a, b) > 0;
450 }
451 
452 bool compareMore(const String& a, const String& b) {
453  return compareString(a, b) > 0;
454 }
455 
456 bool compareMore(const String& a, const __FlashStringHelper* b) {
457  return compareString(a, b) > 0;
458 }
459 
460 // compareLessOrEqual
461 
462 bool compareLessOrEqual(bool a, bool b) {
463  return (a <= b);
464 }
465 
466 bool compareLessOrEqual(char a, char b) {
467  return (a <= b);
468 }
469 
470 bool compareLessOrEqual(int a, int b) {
471  return (a <= b);
472 }
473 
474 bool compareLessOrEqual(unsigned int a, unsigned int b) {
475  return (a <= b);
476 }
477 
478 bool compareLessOrEqual(long a, long b) {
479  return (a <= b);
480 }
481 
482 bool compareLessOrEqual(unsigned long a, unsigned long b) {
483  return (a <= b);
484 }
485 
486 bool compareLessOrEqual(double a, double b) {
487  return (a <= b);
488 }
489 
490 bool compareLessOrEqual(const char* a, const char* b) {
491  return compareString(a, b) <= 0;
492 }
493 
494 bool compareLessOrEqual(const char* a, const String& b) {
495  return compareString(a, b) <= 0;
496 }
497 
498 bool compareLessOrEqual(const char* a, const __FlashStringHelper* b) {
499  return compareString(a, b) <= 0;
500 }
501 
502 bool compareLessOrEqual(const __FlashStringHelper* a, const char* b) {
503  return compareString(a, b) <= 0;
504 }
505 
506 bool compareLessOrEqual(
507  const __FlashStringHelper* a, const __FlashStringHelper* b) {
508  return compareString(a, b) <= 0;
509 }
510 
511 bool compareLessOrEqual(const __FlashStringHelper* a, const String& b) {
512  return compareString(a, b) <= 0;
513 }
514 
515 bool compareLessOrEqual(const String& a, const char* b) {
516  return compareString(a, b) <= 0;
517 }
518 
519 bool compareLessOrEqual(const String& a, const String& b) {
520  return compareString(a, b) <= 0;
521 }
522 
523 bool compareLessOrEqual(const String& a, const __FlashStringHelper* b) {
524  return compareString(a, b) <= 0;
525 }
526 
527 // compareMoreOrEqual
528 
529 bool compareMoreOrEqual(bool a, bool b) {
530  return (a >= b);
531 }
532 
533 bool compareMoreOrEqual(char a, char b) {
534  return (a >= b);
535 }
536 
537 bool compareMoreOrEqual(int a, int b) {
538  return (a >= b);
539 }
540 
541 bool compareMoreOrEqual(unsigned int a, unsigned int b) {
542  return (a >= b);
543 }
544 
545 bool compareMoreOrEqual(long a, long b) {
546  return (a >= b);
547 }
548 
549 bool compareMoreOrEqual(unsigned long a, unsigned long b) {
550  return (a >= b);
551 }
552 
553 bool compareMoreOrEqual(double a, double b) {
554  return (a >= b);
555 }
556 
557 bool compareMoreOrEqual(const char* a, const char* b) {
558  return compareString(a, b) >= 0;
559 }
560 
561 bool compareMoreOrEqual(const char* a, const String& b) {
562  return compareString(a, b) >= 0;
563 }
564 
565 bool compareMoreOrEqual(const char* a, const __FlashStringHelper* b) {
566  return compareString(a, b) >= 0;
567 }
568 
569 bool compareMoreOrEqual(const __FlashStringHelper* a, const char* b) {
570  return compareString(a, b) >= 0;
571 }
572 
573 bool compareMoreOrEqual(
574  const __FlashStringHelper* a, const __FlashStringHelper* b) {
575  return compareString(a, b) >= 0;
576 }
577 
578 bool compareMoreOrEqual(const __FlashStringHelper* a, const String& b) {
579  return compareString(a, b) >= 0;
580 }
581 
582 bool compareMoreOrEqual(const String& a, const char* b) {
583  return compareString(a, b) >= 0;
584 }
585 
586 bool compareMoreOrEqual(const String& a, const String& b) {
587  return compareString(a, b) >= 0;
588 }
589 
590 bool compareMoreOrEqual(const String& a, const __FlashStringHelper* b) {
591  return compareString(a, b) >= 0;
592 }
593 
594 // compareNotEqual
595 
596 bool compareNotEqual(bool a, bool b) {
597  return (a != b);
598 }
599 
600 bool compareNotEqual(char a, char b) {
601  return (a != b);
602 }
603 
604 bool compareNotEqual(int a, int b) {
605  return (a != b);
606 }
607 
608 bool compareNotEqual(unsigned int a, unsigned int b) {
609  return (a != b);
610 }
611 
612 bool compareNotEqual(long a, long b) {
613  return (a != b);
614 }
615 
616 bool compareNotEqual(unsigned long a, unsigned long b) {
617  return (a != b);
618 }
619 
620 bool compareNotEqual(double a, double b) {
621  return (a != b);
622 }
623 
624 bool compareNotEqual(const char* a, const char* b) {
625  return compareString(a, b) != 0;
626 }
627 
628 bool compareNotEqual(const char* a, const String& b) {
629  return compareString(a, b) != 0;
630 }
631 
632 bool compareNotEqual(const char* a, const __FlashStringHelper* b) {
633  return compareString(a, b) != 0;
634 }
635 
636 bool compareNotEqual(const __FlashStringHelper* a, const char* b) {
637  return compareString(a, b) != 0;
638 }
639 
640 bool compareNotEqual(
641  const __FlashStringHelper* a, const __FlashStringHelper* b) {
642  return compareString(a, b) != 0;
643 }
644 
645 bool compareNotEqual(const __FlashStringHelper* a, const String& b) {
646  return compareString(a, b) != 0;
647 }
648 
649 bool compareNotEqual(const String& a, const char* b) {
650  return compareString(a, b) != 0;
651 }
652 
653 bool compareNotEqual(const String& a, const String& b) {
654  return compareString(a, b) != 0;
655 }
656 
657 bool compareNotEqual(const String& a, const __FlashStringHelper* b) {
658  return compareString(a, b) != 0;
659 }
660 
661 }