Skip to content

Commit e592ea7

Browse files
authored
Merge pull request #238 from ianfixes/2020-12-08_toward_containers
Create a more complete CI environment in a Docker image
2 parents 6aef89f + 6a16d27 commit e592ea7

21 files changed

+441
-134
lines changed

Diff for: .github/workflows/linux.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
- uses: ruby/setup-ruby@v1
1212
with:
1313
ruby-version: 2.6
14-
- name: Check style, funcionality, and usage
14+
- name: Check style, functionality, and usage
1515
run: |
1616
g++ -v
1717
bundle install

Diff for: .github/workflows/macos.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
- uses: ruby/setup-ruby@v1
1212
with:
1313
ruby-version: 2.6
14-
- name: Check style, funcionality, and usage
14+
- name: Check style, functionality, and usage
1515
run: |
1616
g++ -v
1717
bundle install

Diff for: .github/workflows/windows.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
- uses: ruby/setup-ruby@v1
1212
with:
1313
ruby-version: 2.6
14-
- name: Check style, funcionality, and usage
14+
- name: Check style, functionality, and usage
1515
run: |
1616
g++ -v
1717
bundle install

Diff for: .rubocop.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
AllCops:
2-
TargetRubyVersion: 2.6
2+
TargetRubyVersion: 2.5
33
NewCops: enable
44
SuggestExtensions: false
55
Exclude:
@@ -65,15 +65,15 @@ Layout/LineLength:
6565
# Configuration parameters: CountComments.
6666
Metrics/ClassLength:
6767
Enabled: false
68-
Max: 400
6968

7069
Metrics/AbcSize:
7170
Enabled: false
72-
Max: 50
7371

7472
Metrics/MethodLength:
7573
Enabled: false
76-
Max: 50
74+
75+
Metrics/BlockLength:
76+
Enabled: false
7777

7878
# Configuration parameters: CountKeywordArgs.
7979
Metrics/ParameterLists:

Diff for: CHANGELOG.md

+14-1
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,35 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99
### Added
10+
- Environment variable to run a custom initialization script during CI testing: `CUSTOM_INIT_SCRIPT`
11+
- Environment variable to run from a subdirectory during CI testing: `USE_SUBDIR`
12+
- `assertComparativeEquivalent()` and `assertComparativeNotEquivalent()` to evaluate equality on an `a - b == 0` basis (and/or `!(a > b) && !(a < b)`)
13+
- `assertEqualFloat()` and `assertNotEqualFloat()` for comparing floats with epsilon
14+
- `assertInfinity()` and `assertNotInfinity()` for comparing floats to infinity
15+
- `assertNAN()` and `assertNotNAN()` for comparing floats to `NaN`
16+
- `assertion()`, `ReporterTAP.onAssert()`, and `testBehaviorExp` macro to handle simple expression evaluation (is true, is false, etc)
17+
- `Wire.resetMocks()` and documentation
1018

1119
### Changed
20+
- Rubocop expected syntax downgraded from ruby 2.6 to 2.5
21+
- `assertEqual()` and `assertNotEqual()` use actual `==` and `!=` -- they no longer require a type to be totally ordered just to do equality tests
22+
- Evaluative assertions (is true/false/null/etc) now produce simpler error messages instead of masquerading as an operation (e.g. "== true")
1223

1324
### Deprecated
1425

1526
### Removed
1627

1728
### Fixed
29+
- Warnings about directory name mismatches are now based on proper comparison of strings
30+
- Now using the recommended "stable" URL for the `esp32` board family
1831

1932
### Security
2033

2134

2235
## [1.1.0] - 2020-12-02
2336
### Added
2437
- `ensure_arduino_installation.rb` now ensures the existence of the library directory as well
25-
- Environment variables to escalate unit tests or examples not being found during CI testing
38+
- Environment variables to escalate unit tests or examples not being found during CI testing - `EXPECT_EXAMPLES` and `EXPECT_UNITTESTS`
2639

2740
### Changed
2841
- Conserve CI testing minutes by grouping CI into fewer runs

Diff for: README.md

+12-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci)
44
[![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/1.1.0)
55
[![Gitter](https://badges.gitter.im/Arduino-CI/arduino_ci.svg)](https://gitter.im/Arduino-CI/arduino_ci?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
6+
[![GitHub Marketplace](https://img.shields.io/badge/Get_it-on_Marketplace-informational.svg)](https://github.com/marketplace/actions/arduino_ci)
67

78
You want to run tests on your Arduino library (bonus: without hardware present), but the IDE doesn't support that. Arduino CI provides that ability.
89

@@ -12,6 +13,8 @@ You want your Arduino library to be automatically built and tested every time so
1213

1314
`arduino_ci` is a cross-platform build/test system, consisting of a Ruby gem and a series of C++ mocks. It enables tests to be run both locally and as part of a CI service like GitHub Actions, TravisCI, Appveyor, etc. Any OS that can run the Arduino IDE can run `arduino_ci`.
1415

16+
> Note: for running tests in response to [GitHub events](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/github-event-types), an [Arduino CI GitHub Action](https://github.com/marketplace/actions/arduino_ci) is available for your convenience. This method of running `arduino_ci` is driven by Docker, which may also serve your local testing needs (as it does not require a ruby environment to be installed).
17+
1518

1619
Platform | CI Status
1720
---------|:---------
@@ -20,20 +23,9 @@ Linux | [![Linux Build Status](https://github.com/Arduino-CI/arduino_ci/workf
2023
Windows | [![Windows Build status](https://github.com/Arduino-CI/arduino_ci/workflows/windows/badge.svg)](https://github.com/Arduino-CI/arduino_ci/actions?workflow=windows)
2124

2225

23-
## Comparison to Other Arduino Testing Tools
24-
25-
| Project | CI | Builds Examples | Unittest | Arduino Mocks | Windows | OSX | Linux | License |
26-
|-----------------------------------------------------------------------------|:--:|:---------------:|:--------:|:-------------:|:-------:|:---:|:-----:|:--------|
27-
|[ArduinoCI](https://github.com/Arduino-CI/arduino_ci) ||||||||Free (Apache-2.0)|
28-
|[ArduinoUnit](https://github.com/mmurdoch/arduinounit) ||| ⚠️ Hardware-based|||||Free (MIT)|
29-
|[Adafruit `ci-arduino`](https://github.com/adafruit/ci-arduino)||||||||Free (MIT)|
30-
|[PlatformIO](https://platformio.org) ||| ⚠️ Paid only |||||⚠️ EULA|
31-
|Official [Arduino IDE](https://www.arduino.cc/en/main/software) || ⚠️ Manually ||N/A 😉||||Free (GPLv2)|
32-
33-
3426
## Quick Start
3527

36-
For a bare-bones example that you can copy from, see [SampleProjects/DoSomething](SampleProjects/DoSomething).
28+
For a fairly minimal practical example that you can copy from, see [the `Arduino-CI/Blink` repository](https://github.com/Arduino-CI/Blink).
3729

3830
The complete set of C++ unit tests for the `arduino_ci` library itself are in the [SampleProjects/TestSomething](SampleProjects/TestSomething) project. The [test files](SampleProjects/TestSomething/test/) are named after the type of feature being tested.
3931

@@ -55,13 +47,20 @@ For unit testing, you will need a compiler; [g++](https://gcc.gnu.org/) is prefe
5547
* **Windows**: you will need Cygwin, and the `mingw-gcc-g++` package. A full set of (working) install instructions can be found in `appveyor.yml`, as this is how CI runs for this project.
5648

5749

50+
### You _May_ Need `python`
51+
52+
ESP32 and ESP8266 boards have [a dependency on `python` that they don't install themselves](https://github.com/Arduino-CI/arduino_ci/issues/235#issuecomment-739629243). If you intend to test on these platforms (which are included in the default list of platforms to test against), you will need to make `python` (and possibly `pyserial`) available in the test environment.
53+
54+
Alternately, you might configure `arduino_ci` to simply not test against these. Consult the reference for those details.
55+
56+
5857
### Changes to Your Repo
5958

6059
Add a file called `Gemfile` (no extension) to your Arduino project:
6160

6261
```ruby
6362
source 'https://rubygems.org'
64-
gem 'arduino_ci'
63+
gem 'arduino_ci' '~> 1.1'
6564
```
6665

6766
It would also make sense to add the following to your `.gitignore`, or copy [the `.gitignore` used by this project](.gitignore):

Diff for: REFERENCE.md

+76-10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ This allows a file (or glob) pattern to be executed in your tests directory, cre
3939
This allows a file (or glob) pattern to be executed in your tests directory, creating a blacklist of files to skip. E.g. `--testfile-reject=test_animal_*.cpp` would match `test_animal_cat.cpp` and `test_animal_dog.cpp` (skipping those) and test only `test_plant_rose.cpp`, `test_plant_daisy.cpp`, etc.
4040

4141

42+
### `CUSTOM_INIT_SCRIPT` environment variable
43+
44+
If set, testing will execute (using `/bin/sh`) the script referred to by this variable -- relative to the current working directory. This enables use cases like the GitHub action to install custom library versions (i.e. a version of a library that is different than what the library manager would automatically install by name) prior to CI test runs.
45+
46+
47+
### `USE_SUBDIR` environment variable
48+
49+
If set, testing will be conducted in this subdirectory (relative to the working directory). This is for monorepos or other layouts where the library directory and project root directory are different.
50+
51+
4252
### `EXPECT_UNITTESTS` environment variable
4353

4454
If set, testing will fail if no unit test files are detected (or if the directory does not exist). This is to avoid communicating a passing status in cases where a commit may have accidentally moved or deleted the test files.
@@ -198,15 +208,27 @@ This test defines one `unittest` (a macro provided by `ArduinoUnitTests.h`), cal
198208

199209
The following assertion functions are available in unit tests.
200210

201-
* `assertEqual(expected, actual)`
202-
* `assertNotEqual(expected, actual)`
203-
* `assertLess(expected, actual)`
204-
* `assertMore(expected, actual)`
205-
* `assertLessOrEqual(expected, actual)`
206-
* `assertMoreOrEqual(expected, actual)`
207-
* `assertTrue(actual)`
208-
* `assertFalse(actual)`
209-
* `assertNull(actual)`
211+
```c++
212+
assertEqual(expected, actual); // a == b
213+
assertNotEqual(unwanted, actual); // a != b
214+
assertComparativeEquivalent(expected, actual); // abs(a - b) == 0 or (!(a > b) && !(a < b))
215+
assertComparativeNotEquivalent(unwanted, actual); // abs(a - b) > 0 or ((a > b) || (a < b))
216+
assertLess(upperBound, actual); // a < b
217+
assertMore(lowerBound, actual); // a > b
218+
assertLessOrEqual(upperBound, actual); // a <= b
219+
assertMoreOrEqual(lowerBound, actual); // a >= b
220+
assertTrue(actual);
221+
assertFalse(actual);
222+
assertNull(actual);
223+
224+
// special cases for floats
225+
assertEqualFloat(expected, actual, epsilon); // fabs(a - b) <= epsilon
226+
assertNotEqualFloat(unwanted, actual, epsilon); // fabs(a - b) >= epsilon
227+
assertInfinity(actual); // isinf(a)
228+
assertNotInfinity(actual); // !isinf(a)
229+
assertNAN(arg); // isnan(a)
230+
assertNotNAN(arg); // !isnan(a)
231+
```
210232

211233
These functions will report the result of the test to the console, and the testing will continue if they fail.
212234

@@ -327,7 +349,7 @@ unittest(pin_history)
327349
// we expect 6 values in that queue (5 that we set plus one
328350
// initial value), which we'll hard-code here for convenience.
329351
// (we'll actually assert those 6 values in the next block)
330-
assertEqual(6, state->digitalPin[1].queueSize));
352+
assertEqual(6, state->digitalPin[1].queueSize());
331353
bool expected[6] = {LOW, HIGH, LOW, LOW, HIGH, HIGH};
332354
bool actual[6];
333355
@@ -634,3 +656,47 @@ unittest(eeprom)
634656
assertEqual(10, a);
635657
}
636658
```
659+
660+
661+
### Wire
662+
663+
This library allows communication with I2C / TWI devices.
664+
665+
The interface the library has been fully mocked, with the addition of several functions for debugging
666+
667+
* `Wire.resetMocks()`: Initializes all mocks, and for test repeatability should be called at the top of any unit tests that use Wire.
668+
* `Wire.didBegin()`: returns whether `Wire.begin()` was called at any point
669+
* `Wire.getMosi(address)`: returns a pointer to a `deque` that represents the history of data sent to `address`
670+
* `Wire.getMiso(address)`: returns a pointer to a `deque` that defines what the master will read from `address` (i.e. for you to supply)
671+
672+
```c++
673+
unittest(wire_basics) {
674+
// ensure known starting state
675+
Wire.resetMocks();
676+
677+
// in case you need to check that your library is properly calling .begin()
678+
assertFalse(Wire.didBegin());
679+
Wire.begin();
680+
assertTrue(Wire.didBegin());
681+
682+
// pick a random device. master write buffer should be empty
683+
const uint8_t randomSlaveAddr = 14;
684+
deque<uint8_t>* mosi = Wire.getMosi(randomSlaveAddr);
685+
assertEqual(0, mosi->size());
686+
687+
// write some random data to random device
688+
const uint8_t randomData[] = { 0x07, 0x0E };
689+
Wire.beginTransmission(randomSlaveAddr);
690+
Wire.write(randomData[0]);
691+
Wire.write(randomData[1]);
692+
Wire.endTransmission();
693+
694+
// check master write buffer values
695+
assertEqual(2, mosi->size());
696+
assertEqual(randomData[0], mosi->front());
697+
mosi->pop_front();
698+
assertEqual(randomData[1], mosi->front());
699+
mosi->pop_front();
700+
assertEqual(0, mosi->size());
701+
}
702+
```
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <ArduinoUnitTests.h>
2+
3+
4+
#pragma once
5+
6+
7+
8+
unittest(check_that_assertion_error_messages_are_comprehensible)
9+
{
10+
assertEqual(1, 2);
11+
assertNotEqual(2, 2);
12+
assertComparativeEquivalent(1, 2);
13+
assertComparativeNotEquivalent(2, 2);
14+
assertLess(2, 1);
15+
assertMore(1, 2);
16+
assertLessOrEqual(2, 1);
17+
assertMoreOrEqual(1, 2);
18+
assertTrue(false);
19+
assertFalse(true);
20+
assertNull(3);
21+
assertNotNull(NULL);
22+
23+
assertEqualFloat(1.2, 1.0, 0.01);
24+
assertNotEqualFloat(1.0, 1.02, 0.1);
25+
assertInfinity(42);
26+
assertNotInfinity(INFINITY);
27+
assertNAN(42);
28+
assertNotNAN(0.0/0.0);
29+
}
30+
31+
unittest_main()

Diff for: SampleProjects/DoSomething/test/good-assert.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <ArduinoUnitTests.h>
2+
#include "../do-something.h"
3+
4+
class NonOrderedType {
5+
public:
6+
int x; // ehh why not
7+
NonOrderedType(int some_x) : x(some_x) {}
8+
9+
bool operator==(const NonOrderedType &that) const {
10+
return that.x == x;
11+
}
12+
13+
bool operator!=(const NonOrderedType &that) const {
14+
return that.x != x;
15+
}
16+
};
17+
inline std::ostream& operator << ( std::ostream& out, const NonOrderedType& n ) {
18+
out << "NonOrderedType(" << n.x << ")";
19+
return out;
20+
}
21+
22+
23+
unittest(assert_equal_without_total_ordering)
24+
{
25+
NonOrderedType a(3);
26+
NonOrderedType b(3);
27+
NonOrderedType c(4);
28+
29+
assertEqual(a, b);
30+
assertEqual(a, a);
31+
assertNotEqual(a, c);
32+
33+
}
34+
35+
unittest(float_assertions)
36+
{
37+
assertEqualFloat(1.0, 1.02, 0.1);
38+
assertNotEqualFloat(1.2, 1.0, 0.01);
39+
40+
assertInfinity(exp(800));
41+
assertInfinity(1.0/0.0);
42+
assertNotInfinity(42);
43+
44+
assertNAN(INFINITY - INFINITY);
45+
assertNAN(0.0/0.0);
46+
assertNotNAN(42);
47+
48+
assertComparativeEquivalent(exp(800), INFINITY);
49+
assertComparativeEquivalent(0.0/0.0, INFINITY - INFINITY);
50+
assertComparativeNotEquivalent(INFINITY, -INFINITY);
51+
52+
assertLess(0, INFINITY);
53+
assertLess(-INFINITY, 0);
54+
assertLess(-INFINITY, INFINITY);
55+
}
56+
57+
unittest_main()

Diff for: SampleProjects/TestSomething/test/godmode.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ unittest(analog_pin_write_history) {
146146
}
147147

148148
unittest(ascii_pin_write_history) {
149-
// digitial history as serial data, big-endian
149+
// digital history as serial data, big-endian
150150
bool binaryAscii[24] = {
151151
0, 1, 0, 1, 1, 0, 0, 1,
152152
0, 1, 1, 0, 0, 1, 0, 1,
@@ -157,7 +157,7 @@ unittest(ascii_pin_write_history) {
157157

158158
assertEqual("Yes", state->digitalPin[2].toAscii(1, true));
159159

160-
// digitial history as serial data, little-endian
160+
// digital history as serial data, little-endian
161161
bool binaryAscii2[16] = {
162162
0, 1, 1, 1, 0, 0, 1, 0,
163163
1, 1, 1, 1, 0, 1, 1, 0};

0 commit comments

Comments
 (0)