arduino_ci 0.1.18 → 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -37
- data/cpp/arduino/Arduino.h +1 -4
- data/cpp/arduino/Nullptr.h +7 -0
- data/cpp/unittest/Assertion.h +2 -0
- data/cpp/unittest/Compare.h +19 -7
- data/lib/arduino_ci/ci_config.rb +4 -4
- data/lib/arduino_ci/version.rb +1 -1
- metadata +3 -4
- data/exe/arduino_ci_remote.rb.orig +0 -387
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70602a4768ed2df9cbd04f83888f229119f00267
|
4
|
+
data.tar.gz: 337f60474895f3cfdecd9497328a7772adcc9254
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78f6e93158cd15a1398396a631646f20b4ce843d5fd386185505ea84b230f2fc5da927e532bdb174818bf73c060bdb09d2e870ab742653df58fa68c802a37c49
|
7
|
+
data.tar.gz: 2cf0fb5e0755ed5fe2ac989fa591a923fb162c922499c6467a45edb7dd6bd811a2e23ceb945597cf48311656fee45cb0eddbc5005d0688a52179dedf4cce01ec
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
|
2
|
-
# ArduinoCI Ruby gem (`arduino_ci`) [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/0.1.
|
2
|
+
# ArduinoCI Ruby gem (`arduino_ci`) [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/0.1.19)
|
3
3
|
|
4
|
-
You want
|
5
|
-
|
6
|
-
You want to run tests on your Arduino library without hardware present, but the IDE doesn't support that. Arduino CI provides that ability.
|
4
|
+
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.
|
7
5
|
|
8
6
|
You want to precisely replicate certain software states in your library, but you don't have sub-millisecond reflexes for physically faking the inputs, outputs, and serial port. Arduino CI fakes 100% of the physical input and output of an Arduino board, including the clock.
|
9
7
|
|
8
|
+
You want your Arduino library to be automatically built and tested every time someone contributes code to your project on GitHub, but the Arduino IDE lacks the ability to run unit tests. [Arduino CI](https://github.com/ianfixes/arduino_ci) provides that ability.
|
9
|
+
|
10
10
|
`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 Travis or Appveyor. Any OS that can run the Arduino IDE can run `arduino_ci`.
|
11
11
|
|
12
12
|
Platform | CI Status
|
@@ -16,13 +16,36 @@ Linux | [![Linux Build Status](http://badges.herokuapp.com/travis/ianfixes/ar
|
|
16
16
|
Windows | [![Windows Build status](https://ci.appveyor.com/api/projects/status/8f6e39dea319m83q/branch/master?svg=true)](https://ci.appveyor.com/project/ianfixes/arduino-ci)
|
17
17
|
|
18
18
|
|
19
|
-
##
|
19
|
+
## Comparison to Other Arduino Testing Tools
|
20
20
|
|
21
|
-
|
21
|
+
| Project | CI | Builds Examples | Unittest | Arduino Mocks | Windows | OSX | Linux | License |
|
22
|
+
|-----------------------------------------------------------------------------|:--:|:---------------:|:--------:|:-------------:|:-------:|:---:|:-----:|:--------|
|
23
|
+
|[ArduinoCI](https://github.com/ianfixes/arduino_ci) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |Free (Apache-2.0)|
|
24
|
+
|[ArduinoUnit](https://github.com/mmurdoch/arduinounit) | ❌ | ❌ | ⚠️ Hardware-based|❌ | ✅ | ✅ | ✅ |Free (MIT)|
|
25
|
+
|[Adafruit `travis-ci-arduino`](https://github.com/adafruit/travis-ci-arduino)| ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |Free (MIT)|
|
26
|
+
|[PlatformIO](https://platformio.org) | ✅ | ✅ | ⚠️ Paid only | ❌ | ✅ | ✅ | ✅ |⚠️ EULA|
|
27
|
+
|Official [Arduino IDE](https://www.arduino.cc/en/main/software) | ❌ | ⚠️ Manually | ❌ |N/A 😉| ✅ | ✅ | ✅ |Free (GPLv2)|
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
|
30
|
+
## Quick Start
|
31
|
+
|
32
|
+
For a bare-bones example that you can copy from, see [SampleProjects/DoSomething](SampleProjects/DoSomething).
|
33
|
+
|
34
|
+
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.
|
35
|
+
|
36
|
+
|
37
|
+
### You Need Ruby and Bundler
|
38
|
+
|
39
|
+
You'll need Ruby version 2.2 or higher, and to `gem install bundler` if it's not already there.
|
40
|
+
|
41
|
+
|
42
|
+
### You Need A Compiler (`g++`)
|
43
|
+
|
44
|
+
For unit testing, you will need a compiler; [g++](https://gcc.gnu.org/) is preferred.
|
45
|
+
|
46
|
+
* **Linux**: `gcc`/`g++` is likely pre-installed.
|
47
|
+
* **OSX**: `g++` is an alias for `clang`, which is provided by Xcode and the developer tools. You are free to `brew install gcc` as well; this is also tested and working.
|
48
|
+
* **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.
|
26
49
|
|
27
50
|
|
28
51
|
### Changes to Your Repo
|
@@ -34,21 +57,66 @@ source 'https://rubygems.org'
|
|
34
57
|
gem 'arduino_ci'
|
35
58
|
```
|
36
59
|
|
37
|
-
|
60
|
+
It would also make sense to add the following to your `.gitignore`, or copy [the `.gitignore` used by this project](.gitignore):
|
61
|
+
|
62
|
+
```
|
63
|
+
/.bundle/
|
64
|
+
/.yardoc
|
65
|
+
Gemfile.lock
|
66
|
+
/_yardoc/
|
67
|
+
/coverage/
|
68
|
+
/doc/
|
69
|
+
/pkg/
|
70
|
+
/spec/reports/
|
71
|
+
vendor
|
72
|
+
*.gem
|
73
|
+
|
74
|
+
# rspec failure tracking
|
75
|
+
.rspec_status
|
76
|
+
|
77
|
+
# C++ stuff
|
78
|
+
*.bin
|
79
|
+
*.bin.dSYM
|
80
|
+
```
|
81
|
+
|
82
|
+
|
83
|
+
### Installing the Dependencies
|
38
84
|
|
39
|
-
|
85
|
+
Fulfilling the `arduino_ci` library dependency is as easy as running this command:
|
40
86
|
|
41
87
|
```
|
42
88
|
$ bundle install
|
43
89
|
```
|
44
90
|
|
45
91
|
|
92
|
+
### Running tests
|
93
|
+
|
46
94
|
With that installed, just the following shell command each time you want the tests to execute:
|
47
95
|
|
48
96
|
```
|
49
97
|
$ bundle exec arduino_ci_remote.rb
|
50
98
|
```
|
51
99
|
|
100
|
+
`arduino_ci_remote.rb` is the main entry point for this library. This command will iterate over all the library's `examples/` and attempt to compile them. If you set up unit tests, it will run those as well.
|
101
|
+
|
102
|
+
|
103
|
+
### Reference
|
104
|
+
|
105
|
+
For more information on the usage of `arduino_ci_remote.rb`, see [REFERENCE.md](REFERENCE.md). It contains information such as:
|
106
|
+
|
107
|
+
* How to configure build options (platforms to test, Arduino library dependencies to install) with an `.arduino-ci.yml` file
|
108
|
+
* Where to put unit test files
|
109
|
+
* How to structure unit test files
|
110
|
+
* How to control the global (physical) state of the Arduino board
|
111
|
+
* How to modify the Arduino platforms, compilers, test plans, etc
|
112
|
+
|
113
|
+
|
114
|
+
## Setting up Pull Request Testing and/or External CI
|
115
|
+
|
116
|
+
The following prerequisites must be fulfilled:
|
117
|
+
|
118
|
+
* A GitHub (or other repository-hosting) project for your library
|
119
|
+
* A CI system like [Travis CI](https://travis-ci.org/) or [Appveyor](https://www.appveyor.com/) that is linked to your project
|
52
120
|
|
53
121
|
|
54
122
|
### Testing with remote CI
|
@@ -66,10 +134,11 @@ Next, you need this in `.travis.yml` in your repo
|
|
66
134
|
sudo: false
|
67
135
|
language: ruby
|
68
136
|
script:
|
69
|
-
|
70
|
-
|
137
|
+
- bundle install
|
138
|
+
- bundle exec arduino_ci_remote.rb
|
71
139
|
```
|
72
140
|
|
141
|
+
|
73
142
|
#### Appveyor CI
|
74
143
|
|
75
144
|
You'll need to go to https://ci.appveyor.com/projects and add your project.
|
@@ -83,20 +152,6 @@ test_script:
|
|
83
152
|
- bundle exec arduino_ci_remote.rb
|
84
153
|
```
|
85
154
|
|
86
|
-
## Quick Start
|
87
|
-
|
88
|
-
This software is in beta. But [SampleProjects/DoSomething](SampleProjects/DoSomething) has a decent writeup and is a good bare-bones example of all the features.
|
89
|
-
|
90
|
-
## Reference
|
91
|
-
|
92
|
-
For more information on the usage of `arduino_ci`, see [REFERENCE.md](REFERENCE.md). It contains information such as:
|
93
|
-
|
94
|
-
* Where to put unit test files
|
95
|
-
* How to structure unit test files
|
96
|
-
* How to control the global (physical) state of the Arduino board
|
97
|
-
* How to modify the Arduino platforms, compilers, test plans, etc
|
98
|
-
|
99
|
-
|
100
155
|
## Known Problems
|
101
156
|
|
102
157
|
* The Arduino library is not fully mocked.
|
@@ -104,16 +159,6 @@ For more information on the usage of `arduino_ci`, see [REFERENCE.md](REFERENCE.
|
|
104
159
|
* https://github.com/ianfixes/arduino_ci/issues
|
105
160
|
|
106
161
|
|
107
|
-
## Comparison to Other Arduino Testing Tools
|
108
|
-
|
109
|
-
|
110
|
-
| Project | CI | Builds Examples | Unittest | Arduino Mocks | Windows | OSX | Linux | License |
|
111
|
-
|---------|----|-----------------|----------|---------------|---------|-----|-------|---------|
|
112
|
-
|[ArduinoCI](https://github.com/ianfixes/arduino_ci)| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |Free (Apache-2.0)|
|
113
|
-
|[ArduinoUnit](https://github.com/mmurdoch/arduinounit)|❌ |❌ |Hardware-based|❌ | ✅ | ✅ | ✅ |Free (MIT)| |
|
114
|
-
|[Adafruit `travis-ci-arduino`](https://github.com/adafruit/travis-ci-arduino) | ✅ | ✅ | ❌| ❌ | ❌ | ❌ | ✅ |Free (MIT)|
|
115
|
-
|[PlatformIO](https://platformio.org)| ✅ | ✅ | Paid only | ❌ | ✅ | ✅ | ✅ |Proprietary (EULA)|
|
116
|
-
|
117
162
|
## Author
|
118
163
|
|
119
164
|
This gem was written by Ian Katz (ianfixes@gmail.com) in 2018. It's released under the Apache 2.0 license.
|
data/cpp/arduino/Arduino.h
CHANGED
@@ -15,6 +15,7 @@ Where possible, variable names from the Arduino library are used to avoid confli
|
|
15
15
|
#include "Stream.h"
|
16
16
|
#include "HardwareSerial.h"
|
17
17
|
#include "SPI.h"
|
18
|
+
#include "Nullptr.h"
|
18
19
|
|
19
20
|
typedef bool boolean;
|
20
21
|
typedef uint8_t byte;
|
@@ -72,7 +73,3 @@ inline unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8)
|
|
72
73
|
#define word(...) makeWord(__VA_ARGS__)
|
73
74
|
|
74
75
|
|
75
|
-
// Define C++11 nullptr
|
76
|
-
#define nullptr (std::nullptr_t)NULL
|
77
|
-
|
78
|
-
|
data/cpp/unittest/Assertion.h
CHANGED
@@ -39,6 +39,7 @@
|
|
39
39
|
#define assertTrue(arg) assertEqual(true, arg)
|
40
40
|
#define assertFalse(arg) assertEqual(false, arg)
|
41
41
|
#define assertNull(arg) assertEqual((void*)NULL, (void*)arg)
|
42
|
+
#define assertNotNull(arg) assertNotEqual((void*)NULL, (void*)arg)
|
42
43
|
|
43
44
|
/** macro generates optional output and calls fail() followed by a return if false. */
|
44
45
|
#define assureEqual(arg1,arg2) assureOp("assureEqual","expected",arg1,compareEqual,"==","actual",arg2)
|
@@ -50,4 +51,5 @@
|
|
50
51
|
#define assureTrue(arg) assureEqual(true, arg)
|
51
52
|
#define assureFalse(arg) assureEqual(false, arg)
|
52
53
|
#define assureNull(arg) assureEqual((void*)NULL, (void*)arg)
|
54
|
+
#define assureNotNull(arg) assureNotEqual((void*)NULL, (void*)arg)
|
53
55
|
|
data/cpp/unittest/Compare.h
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
#include <avr/pgmspace.h>
|
3
3
|
#include <WString.h>
|
4
|
+
#include <Nullptr.h>
|
4
5
|
|
5
6
|
template < typename A, typename B > struct Compare
|
6
7
|
{
|
@@ -897,10 +898,21 @@ template < size_t N, size_t M > struct Compare<char [N],char [M]>
|
|
897
898
|
return between(a,b) >= 0;
|
898
899
|
} // moreOrEqual
|
899
900
|
};
|
900
|
-
|
901
|
-
|
902
|
-
template <typename
|
903
|
-
template <typename
|
904
|
-
template <typename
|
905
|
-
template <typename
|
906
|
-
template <typename
|
901
|
+
|
902
|
+
// null pointer comparisons
|
903
|
+
template <typename B> int compareBetween( const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::between( a, b); }
|
904
|
+
template <typename B> bool compareEqual( const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::equal( a, b); }
|
905
|
+
template <typename B> bool compareNotEqual( const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::notEqual( a, b); }
|
906
|
+
template <typename B> bool compareLess( const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::less( a, b); }
|
907
|
+
template <typename B> bool compareMore( const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::more( a, b); }
|
908
|
+
template <typename B> bool compareLessOrEqual(const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::lessOrEqual(a, b); }
|
909
|
+
template <typename B> bool compareMoreOrEqual(const my_nullptr_t &a, const B &b) { return Compare<my_nullptr_t,B>::moreOrEqual(a, b); }
|
910
|
+
|
911
|
+
// super general comparisons
|
912
|
+
template <typename A, typename B> int compareBetween( const A &a, const B &b) { return Compare<A,B>::between( a, b); }
|
913
|
+
template <typename A, typename B> bool compareEqual( const A &a, const B &b) { return Compare<A,B>::equal( a, b); }
|
914
|
+
template <typename A, typename B> bool compareNotEqual( const A &a, const B &b) { return Compare<A,B>::notEqual( a, b); }
|
915
|
+
template <typename A, typename B> bool compareLess( const A &a, const B &b) { return Compare<A,B>::less( a, b); }
|
916
|
+
template <typename A, typename B> bool compareMore( const A &a, const B &b) { return Compare<A,B>::more( a, b); }
|
917
|
+
template <typename A, typename B> bool compareLessOrEqual(const A &a, const B &b) { return Compare<A,B>::lessOrEqual(a, b); }
|
918
|
+
template <typename A, typename B> bool compareMoreOrEqual(const A &a, const B &b) { return Compare<A,B>::moreOrEqual(a, b); }
|
data/lib/arduino_ci/ci_config.rb
CHANGED
@@ -287,17 +287,17 @@ module ArduinoCI
|
|
287
287
|
end
|
288
288
|
|
289
289
|
# Config allows select / reject (aka whitelist / blacklist) criteria. Enforce on a dir
|
290
|
-
# @param paths [Array<
|
291
|
-
# @return [Array<
|
290
|
+
# @param paths [Array<Pathname>] the initial set of test files
|
291
|
+
# @return [Array<Pathname>] files that match the select/reject criteria
|
292
292
|
def allowable_unittest_files(paths)
|
293
293
|
return paths if @unittest_info[:testfiles].nil?
|
294
294
|
|
295
295
|
ret = paths
|
296
296
|
unless @unittest_info[:testfiles][:select].nil? || @unittest_info[:testfiles][:select].empty?
|
297
|
-
ret
|
297
|
+
ret.select! { |p| unittest_info[:testfiles][:select].any? { |glob| p.basename.fnmatch(glob) } }
|
298
298
|
end
|
299
299
|
unless @unittest_info[:testfiles][:reject].nil?
|
300
|
-
ret
|
300
|
+
ret.reject! { |p| unittest_info[:testfiles][:reject].any? { |glob| p.basename.fnmatch(glob) } }
|
301
301
|
end
|
302
302
|
ret
|
303
303
|
end
|
data/lib/arduino_ci/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arduino_ci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Katz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: os
|
@@ -113,7 +113,6 @@ email:
|
|
113
113
|
- ianfixes@gmail.com
|
114
114
|
executables:
|
115
115
|
- arduino_ci_remote.rb
|
116
|
-
- arduino_ci_remote.rb.orig
|
117
116
|
- arduino_library_location.rb
|
118
117
|
- ensure_arduino_installation.rb
|
119
118
|
- libasan.rb
|
@@ -129,6 +128,7 @@ files:
|
|
129
128
|
- cpp/arduino/Godmode.cpp
|
130
129
|
- cpp/arduino/Godmode.h
|
131
130
|
- cpp/arduino/HardwareSerial.h
|
131
|
+
- cpp/arduino/Nullptr.h
|
132
132
|
- cpp/arduino/PinHistory.h
|
133
133
|
- cpp/arduino/Print.h
|
134
134
|
- cpp/arduino/SPI.h
|
@@ -424,7 +424,6 @@ files:
|
|
424
424
|
- cpp/unittest/Assertion.h
|
425
425
|
- cpp/unittest/Compare.h
|
426
426
|
- exe/arduino_ci_remote.rb
|
427
|
-
- exe/arduino_ci_remote.rb.orig
|
428
427
|
- exe/arduino_library_location.rb
|
429
428
|
- exe/ensure_arduino_installation.rb
|
430
429
|
- exe/libasan.rb
|
@@ -1,387 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'arduino_ci'
|
3
|
-
require 'set'
|
4
|
-
require 'pathname'
|
5
|
-
require 'optparse'
|
6
|
-
|
7
|
-
WIDTH = 80
|
8
|
-
FIND_FILES_INDENT = 4
|
9
|
-
|
10
|
-
@failure_count = 0
|
11
|
-
@passfail = proc { |result| result ? "✓" : "✗" }
|
12
|
-
|
13
|
-
# Use some basic parsing to allow command-line overrides of config
|
14
|
-
class Parser
|
15
|
-
def self.parse(options)
|
16
|
-
unit_config = {}
|
17
|
-
output_options = {
|
18
|
-
skip_unittests: false,
|
19
|
-
skip_compilation: false,
|
20
|
-
ci_config: {
|
21
|
-
"unittest" => unit_config
|
22
|
-
},
|
23
|
-
}
|
24
|
-
|
25
|
-
opt_parser = OptionParser.new do |opts|
|
26
|
-
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
|
27
|
-
|
28
|
-
opts.on("--skip-unittests", "Don't run unit tests") do |p|
|
29
|
-
output_options[:skip_unittests] = p
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on("--skip-compilation", "Don't compile example sketches") do |p|
|
33
|
-
output_options[:skip_compilation] = p
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on("--testfile-select=GLOB", "Unit test file (or glob) to select") do |p|
|
37
|
-
unit_config["testfiles"] ||= {}
|
38
|
-
unit_config["testfiles"]["select"] ||= []
|
39
|
-
unit_config["testfiles"]["select"] << p
|
40
|
-
end
|
41
|
-
|
42
|
-
opts.on("--testfile-reject=GLOB", "Unit test file (or glob) to reject") do |p|
|
43
|
-
unit_config["testfiles"] ||= {}
|
44
|
-
unit_config["testfiles"]["reject"] ||= []
|
45
|
-
unit_config["testfiles"]["reject"] << p
|
46
|
-
end
|
47
|
-
|
48
|
-
opts.on("-h", "--help", "Prints this help") do
|
49
|
-
puts opts
|
50
|
-
exit
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
opt_parser.parse!(options)
|
55
|
-
output_options
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Read in command line options and make them read-only
|
60
|
-
@cli_options = (Parser.parse ARGV).freeze
|
61
|
-
|
62
|
-
# terminate after printing any debug info. TODO: capture debug info
|
63
|
-
def terminate(final = nil)
|
64
|
-
puts "Failures: #{@failure_count}"
|
65
|
-
unless @failure_count.zero? || final
|
66
|
-
puts "Last message: #{@arduino_cmd.last_msg}"
|
67
|
-
puts "========== Stdout:"
|
68
|
-
puts @arduino_cmd.last_out
|
69
|
-
puts "========== Stderr:"
|
70
|
-
puts @arduino_cmd.last_err
|
71
|
-
end
|
72
|
-
retcode = @failure_count.zero? ? 0 : 1
|
73
|
-
exit(retcode)
|
74
|
-
end
|
75
|
-
|
76
|
-
# make a nice status line for an action and react to the action
|
77
|
-
# TODO / note to self: inform_multline is tougher to write
|
78
|
-
# without altering the signature because it only leaves space
|
79
|
-
# for the checkmark _after_ the multiline, it doesn't know how
|
80
|
-
# to make that conditionally the body
|
81
|
-
# @param message String the text of the progress indicator
|
82
|
-
# @param multiline boolean whether multiline output is expected
|
83
|
-
# @param mark_fn block (string) -> string that says how to describe the result
|
84
|
-
# @param on_fail_msg String custom message for failure
|
85
|
-
# @param tally_on_fail boolean whether to increment @failure_count
|
86
|
-
# @param abort_on_fail boolean whether to abort immediately on failure (i.e. if this is a fatal error)
|
87
|
-
def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abort_on_fail)
|
88
|
-
line = "#{message}... "
|
89
|
-
endline = "...#{message} "
|
90
|
-
if multiline
|
91
|
-
puts line
|
92
|
-
else
|
93
|
-
print line
|
94
|
-
end
|
95
|
-
STDOUT.flush
|
96
|
-
result = yield
|
97
|
-
mark = mark_fn.nil? ? "" : mark_fn.call(result)
|
98
|
-
# if multline, put checkmark at full width
|
99
|
-
print endline if multiline
|
100
|
-
puts mark.to_s.rjust(WIDTH - line.length, " ")
|
101
|
-
unless result
|
102
|
-
puts on_fail_msg unless on_fail_msg.nil?
|
103
|
-
@failure_count += 1 if tally_on_fail
|
104
|
-
# print out error messaging here if we've captured it
|
105
|
-
terminate if abort_on_fail
|
106
|
-
end
|
107
|
-
result
|
108
|
-
end
|
109
|
-
|
110
|
-
# Make a nice status for something that defers any failure code until script exit
|
111
|
-
def attempt(message, &block)
|
112
|
-
perform_action(message, false, @passfail, nil, true, false, &block)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Make a nice status for something that defers any failure code until script exit
|
116
|
-
def attempt_multiline(message, &block)
|
117
|
-
perform_action(message, true, @passfail, nil, true, false, &block)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Make a nice status for something that kills the script immediately on failure
|
121
|
-
FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with ArduinoCI, or your configuration".freeze
|
122
|
-
def assure(message, &block)
|
123
|
-
perform_action(message, false, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
124
|
-
end
|
125
|
-
|
126
|
-
def assure_multiline(message, &block)
|
127
|
-
perform_action(message, true, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
128
|
-
end
|
129
|
-
|
130
|
-
def inform(message, &block)
|
131
|
-
perform_action(message, false, proc { |x| x }, nil, false, false, &block)
|
132
|
-
end
|
133
|
-
|
134
|
-
def inform_multiline(message, &block)
|
135
|
-
perform_action(message, true, nil, nil, false, false, &block)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Assure that a platform exists and return its definition
|
139
|
-
def assured_platform(purpose, name, config)
|
140
|
-
platform_definition = config.platform_definition(name)
|
141
|
-
assure("Requested #{purpose} platform '#{name}' is defined in 'platforms' YML") do
|
142
|
-
!platform_definition.nil?
|
143
|
-
end
|
144
|
-
platform_definition
|
145
|
-
end
|
146
|
-
|
147
|
-
# Return true if the file (or one of the dirs containing it) is hidden
|
148
|
-
def file_is_hidden_somewhere?(path)
|
149
|
-
# this is clunkly but pre-2.2-ish ruby doesn't return ascend as an enumerator
|
150
|
-
path.ascend do |part|
|
151
|
-
return true if part.basename.to_s.start_with? "."
|
152
|
-
end
|
153
|
-
false
|
154
|
-
end
|
155
|
-
|
156
|
-
# print out some files
|
157
|
-
def display_files(pathname)
|
158
|
-
# `find` doesn't follow symlinks, so we should instead
|
159
|
-
realpath = pathname.symlink? ? pathname.readlink : pathname
|
160
|
-
|
161
|
-
# suppress directories and dotfile-based things
|
162
|
-
all_files = realpath.find.select(&:file?)
|
163
|
-
non_hidden = all_files.reject { |path| file_is_hidden_somewhere?(path) }
|
164
|
-
|
165
|
-
# print files with an indent
|
166
|
-
margin = " " * FIND_FILES_INDENT
|
167
|
-
non_hidden.each { |p| puts "#{margin}#{p}" }
|
168
|
-
end
|
169
|
-
|
170
|
-
def perform_unit_tests(file_config)
|
171
|
-
<<<<<<< HEAD
|
172
|
-
puts file_config.to_h[:unittest].to_s
|
173
|
-
config = file_config.with_override_config(@cli_options)
|
174
|
-
puts config.to_h[:unittest].to_s
|
175
|
-
=======
|
176
|
-
if @cli_options[:skip_unittests]
|
177
|
-
inform("Skipping unit tests") { "as requested via command line" }
|
178
|
-
return
|
179
|
-
end
|
180
|
-
config = file_config.with_override_config(@cli_options[:ci_config])
|
181
|
-
>>>>>>> 9c4b0f0... Allow skipping of unittests and/or compilation in arduino_ci_remote.rb
|
182
|
-
cpp_library = ArduinoCI::CppLibrary.new(Pathname.new("."), @arduino_cmd.lib_dir)
|
183
|
-
|
184
|
-
# check GCC
|
185
|
-
compilers = config.compilers_to_use
|
186
|
-
assure("The set of compilers (#{compilers.length}) isn't empty") { !compilers.empty? }
|
187
|
-
compilers.each do |gcc_binary|
|
188
|
-
attempt_multiline("Checking #{gcc_binary} version") do
|
189
|
-
version = cpp_library.gcc_version(gcc_binary)
|
190
|
-
next nil unless version
|
191
|
-
|
192
|
-
puts version.split("\n").map { |l| " #{l}" }.join("\n")
|
193
|
-
version
|
194
|
-
end
|
195
|
-
inform("libasan availability for #{gcc_binary}") { cpp_library.libasan?(gcc_binary) }
|
196
|
-
end
|
197
|
-
|
198
|
-
# Ensure platforms exist for unit test, and save their info in all_platform_info keyed by name
|
199
|
-
all_platform_info = {}
|
200
|
-
config.platforms_to_unittest.each { |p| all_platform_info[p] = assured_platform("unittest", p, config) }
|
201
|
-
|
202
|
-
# iterate boards / tests
|
203
|
-
if !cpp_library.tests_dir.exist?
|
204
|
-
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
|
205
|
-
puts " In case that's an error, this is what was found in the library:"
|
206
|
-
display_files(cpp_library.tests_dir.parent)
|
207
|
-
true
|
208
|
-
end
|
209
|
-
elsif cpp_library.test_files.empty?
|
210
|
-
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
|
211
|
-
puts " In case that's an error, this is what was found in the tests directory:"
|
212
|
-
display_files(cpp_library.tests_dir)
|
213
|
-
true
|
214
|
-
end
|
215
|
-
elsif config.platforms_to_unittest.empty?
|
216
|
-
inform("Skipping unit tests") { "no platforms were requested" }
|
217
|
-
else
|
218
|
-
config.platforms_to_unittest.each do |p|
|
219
|
-
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
|
220
|
-
unittest_name = unittest_path.basename.to_s
|
221
|
-
compilers.each do |gcc_binary|
|
222
|
-
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary}") do
|
223
|
-
exe = cpp_library.build_for_test_with_configuration(
|
224
|
-
unittest_path,
|
225
|
-
config.aux_libraries_for_unittest,
|
226
|
-
gcc_binary,
|
227
|
-
config.gcc_config(p)
|
228
|
-
)
|
229
|
-
puts
|
230
|
-
unless exe
|
231
|
-
puts "Last command: #{cpp_library.last_cmd}"
|
232
|
-
puts cpp_library.last_out
|
233
|
-
puts cpp_library.last_err
|
234
|
-
next false
|
235
|
-
end
|
236
|
-
cpp_library.run_test_file(exe)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def perform_compilation_tests(config)
|
245
|
-
if @cli_options[:skip_compilation]
|
246
|
-
inform("Skipping compilation of examples") { "as requested via command line" }
|
247
|
-
return
|
248
|
-
end
|
249
|
-
|
250
|
-
# index the existing libraries
|
251
|
-
attempt("Indexing libraries") { @arduino_cmd.index_libraries } unless @arduino_cmd.libraries_indexed
|
252
|
-
|
253
|
-
# initialize library under test
|
254
|
-
installed_library_path = attempt("Installing library under test") do
|
255
|
-
@arduino_cmd.install_local_library(Pathname.new("."))
|
256
|
-
end
|
257
|
-
if installed_library_path.exist?
|
258
|
-
inform("Library installed at") { installed_library_path.to_s }
|
259
|
-
else
|
260
|
-
assure_multiline("Library installed successfully") do
|
261
|
-
# print out the contents of the deepest directory we actually find
|
262
|
-
@arduino_cmd.lib_dir.ascend do |path_part|
|
263
|
-
next unless path_part.exist?
|
264
|
-
|
265
|
-
break display_files(path_part)
|
266
|
-
end
|
267
|
-
false
|
268
|
-
end
|
269
|
-
end
|
270
|
-
library_examples = @arduino_cmd.library_examples(installed_library_path)
|
271
|
-
|
272
|
-
# gather up all required boards for compilation so we can install them up front.
|
273
|
-
# start with the "platforms to unittest" and add the examples
|
274
|
-
# while we're doing that, get the aux libraries as well
|
275
|
-
example_platform_info = {}
|
276
|
-
board_package_url = {}
|
277
|
-
aux_libraries = Set.new(config.aux_libraries_for_unittest + config.aux_libraries_for_build)
|
278
|
-
# while collecting the platforms, ensure they're defined
|
279
|
-
|
280
|
-
library_examples.each do |path|
|
281
|
-
ovr_config = config.from_example(path)
|
282
|
-
ovr_config.platforms_to_build.each do |platform|
|
283
|
-
# assure the platform if we haven't already
|
284
|
-
next if example_platform_info.key?(platform)
|
285
|
-
|
286
|
-
platform_info = assured_platform("library example", platform, config)
|
287
|
-
next if platform_info.nil?
|
288
|
-
|
289
|
-
example_platform_info[platform] = platform_info
|
290
|
-
package = platform_info[:package]
|
291
|
-
board_package_url[package] = ovr_config.package_url(package)
|
292
|
-
end
|
293
|
-
aux_libraries.merge(ovr_config.aux_libraries_for_build)
|
294
|
-
end
|
295
|
-
|
296
|
-
# with all platform info, we can extract unique packages and their urls
|
297
|
-
# do that, set the URLs, and download the packages
|
298
|
-
all_packages = example_platform_info.values.map { |v| v[:package] }.uniq.reject(&:nil?)
|
299
|
-
|
300
|
-
# inform about builtin packages
|
301
|
-
all_packages.select { |p| config.package_builtin?(p) }.each do |p|
|
302
|
-
inform("Using built-in board package") { p }
|
303
|
-
end
|
304
|
-
|
305
|
-
# make sure any non-builtin package has a URL defined
|
306
|
-
all_packages.reject { |p| config.package_builtin?(p) }.each do |p|
|
307
|
-
assure("Board package #{p} has a defined URL") { board_package_url[p] }
|
308
|
-
end
|
309
|
-
|
310
|
-
# set up all the board manager URLs.
|
311
|
-
# we can safely reject nils now, they would be for the builtins
|
312
|
-
all_urls = all_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
|
313
|
-
|
314
|
-
unless all_urls.empty?
|
315
|
-
assure("Setting board manager URLs") do
|
316
|
-
@arduino_cmd.board_manager_urls = all_urls
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
all_packages.each do |p|
|
321
|
-
assure("Installing board package #{p}") do
|
322
|
-
@arduino_cmd.install_boards(p)
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
aux_libraries.each do |l|
|
327
|
-
if @arduino_cmd.library_present?(l)
|
328
|
-
inform("Using pre-existing library") { l.to_s }
|
329
|
-
else
|
330
|
-
assure("Installing aux library '#{l}'") { @arduino_cmd.install_library(l) }
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
last_board = nil
|
335
|
-
if config.platforms_to_build.empty?
|
336
|
-
inform("Skipping builds") { "no platforms were requested" }
|
337
|
-
return
|
338
|
-
elsif library_examples.empty?
|
339
|
-
inform_multiline("Skipping builds; no examples found in #{installed_library_path}") do
|
340
|
-
display_files(installed_library_path)
|
341
|
-
end
|
342
|
-
return
|
343
|
-
end
|
344
|
-
|
345
|
-
attempt("Setting compiler warning level") { @arduino_cmd.set_pref("compiler.warning_level", "all") }
|
346
|
-
|
347
|
-
# switching boards takes time, so iterate board first
|
348
|
-
# _then_ whichever examples match it
|
349
|
-
examples_by_platform = library_examples.each_with_object({}) do |example_path, acc|
|
350
|
-
ovr_config = config.from_example(example_path)
|
351
|
-
ovr_config.platforms_to_build.each do |p|
|
352
|
-
acc[p] = [] unless acc.key?(p)
|
353
|
-
acc[p] << example_path
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
examples_by_platform.each do |platform, example_paths|
|
358
|
-
board = example_platform_info[platform][:board]
|
359
|
-
assure("Switching to board for #{platform} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
360
|
-
last_board = board
|
361
|
-
|
362
|
-
example_paths.each do |example_path|
|
363
|
-
example_name = File.basename(example_path)
|
364
|
-
attempt("Verifying #{example_name}") do
|
365
|
-
ret = @arduino_cmd.verify_sketch(example_path)
|
366
|
-
unless ret
|
367
|
-
puts
|
368
|
-
puts "Last command: #{@arduino_cmd.last_msg}"
|
369
|
-
puts @arduino_cmd.last_err
|
370
|
-
end
|
371
|
-
ret
|
372
|
-
end
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
end
|
377
|
-
|
378
|
-
# initialize command and config
|
379
|
-
config = ArduinoCI::CIConfig.default.from_project_library
|
380
|
-
|
381
|
-
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
|
382
|
-
inform("Located Arduino binary") { @arduino_cmd.binary_path.to_s }
|
383
|
-
|
384
|
-
perform_unit_tests(config)
|
385
|
-
perform_compilation_tests(config)
|
386
|
-
|
387
|
-
terminate(true)
|