arduino_ci 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +32 -24
- data/REFERENCE.md +91 -11
- data/cpp/arduino/Arduino.h +0 -5
- data/cpp/arduino/ArduinoDefines.h +3 -0
- data/cpp/arduino/Godmode.h +63 -6
- data/cpp/arduino/Wire.h +37 -13
- data/cpp/unittest/ArduinoUnitTests.h +32 -0
- data/cpp/unittest/Assertion.h +54 -26
- data/cpp/unittest/Compare.h +58 -51
- data/exe/arduino_ci.rb +186 -76
- data/lib/arduino_ci/arduino_backend.rb +18 -2
- data/lib/arduino_ci/ci_config.rb +5 -2
- data/lib/arduino_ci/host.rb +1 -1
- data/lib/arduino_ci/library_properties.rb +6 -1
- data/lib/arduino_ci/version.rb +1 -1
- data/misc/default.yml +2 -2
- metadata +2 -2
@@ -69,6 +69,23 @@ class Test
|
|
69
69
|
}
|
70
70
|
}
|
71
71
|
|
72
|
+
// non-comparative assert
|
73
|
+
void onAssert(
|
74
|
+
const char* file,
|
75
|
+
int line,
|
76
|
+
const char* description,
|
77
|
+
bool pass
|
78
|
+
) {
|
79
|
+
cerr << " " << (pass ? "" : "not ") << "ok " << ++mAssertCounter << " - " << description << endl;
|
80
|
+
if (!pass) {
|
81
|
+
cerr << " ---" << endl;
|
82
|
+
cerr << " at:" << endl;
|
83
|
+
cerr << " file: " << file << endl;
|
84
|
+
cerr << " line: " << line << endl;
|
85
|
+
cerr << " ..." << endl;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
72
89
|
template <typename A, typename B> void onAssert(
|
73
90
|
const char* file,
|
74
91
|
int line,
|
@@ -194,6 +211,21 @@ class Test
|
|
194
211
|
excise();
|
195
212
|
}
|
196
213
|
|
214
|
+
bool assertion(
|
215
|
+
const char *file,
|
216
|
+
int line,
|
217
|
+
const char *description,
|
218
|
+
bool ok)
|
219
|
+
{
|
220
|
+
if (mReporter) {
|
221
|
+
mReporter->onAssert(file, line, description, ok);
|
222
|
+
}
|
223
|
+
|
224
|
+
if (!ok)
|
225
|
+
fail();
|
226
|
+
return ok;
|
227
|
+
}
|
228
|
+
|
197
229
|
template <typename A, typename B>
|
198
230
|
bool assertion(
|
199
231
|
const char *file,
|
data/cpp/unittest/Assertion.h
CHANGED
@@ -6,9 +6,19 @@
|
|
6
6
|
|
7
7
|
#include "Compare.h"
|
8
8
|
|
9
|
-
#define
|
9
|
+
#define arduinoCITestBehaviorExp(die, desc, pass) \
|
10
|
+
do \
|
11
|
+
{ \
|
12
|
+
if (!assertion(__FILE__, __LINE__, \
|
13
|
+
desc, pass)) \
|
14
|
+
{ \
|
15
|
+
if (die) return; \
|
16
|
+
} \
|
17
|
+
} while (0)
|
18
|
+
|
19
|
+
#define arduinoCITestBehaviorOp(die, desc, rel1, arg1, op, op_name, rel2, arg2) \
|
10
20
|
do \
|
11
|
-
|
21
|
+
{ \
|
12
22
|
if (!assertion<typeof(arg1), typeof(arg2)>(__FILE__, __LINE__, \
|
13
23
|
desc, \
|
14
24
|
rel1, #arg1, (arg1), \
|
@@ -22,34 +32,52 @@
|
|
22
32
|
|
23
33
|
|
24
34
|
// helper define for the operators below
|
25
|
-
#define
|
26
|
-
|
35
|
+
#define arduinoCIAssertOp(desc, rel1, arg1, op, op_name, rel2, arg2) \
|
36
|
+
arduinoCITestBehaviorOp(false, "assert" desc, rel1, arg1, op, op_name, rel2, arg2)
|
27
37
|
|
28
|
-
#define
|
29
|
-
|
38
|
+
#define arduinoCIAssureOp(desc, rel1, arg1, op, op_name, rel2, arg2) \
|
39
|
+
arduinoCITestBehaviorOp(true, "assure" desc, rel1, arg1, op, op_name, rel2, arg2)
|
30
40
|
|
31
41
|
|
32
42
|
/** macro generates optional output and calls fail() but does not return if false. */
|
33
|
-
#define
|
34
|
-
#define
|
35
|
-
#define
|
36
|
-
#define
|
37
|
-
#define
|
38
|
-
#define
|
39
|
-
#define
|
40
|
-
#define
|
41
|
-
#define
|
42
|
-
#define
|
43
|
+
#define assertTrue(arg) arduinoCITestBehaviorExp(false, "True " #arg, (arg))
|
44
|
+
#define assertFalse(arg) arduinoCITestBehaviorExp(false, "False " #arg, !(arg))
|
45
|
+
#define assertNull(arg) arduinoCITestBehaviorExp(false, "Null " #arg, ((void*)NULL == (void*)(arg)))
|
46
|
+
#define assertNotNull(arg) arduinoCITestBehaviorExp(false, "NotNull " #arg, ((void*)NULL != (void*)(arg)))
|
47
|
+
#define assertEqual(arg1,arg2) arduinoCIAssertOp("Equal","expected",arg1,compareEqual,"==","actual",arg2)
|
48
|
+
#define assertNotEqual(arg1,arg2) arduinoCIAssertOp("NotEqual","unwanted",arg1,compareNotEqual,"!=","actual",arg2)
|
49
|
+
#define assertComparativeEquivalent(arg1,arg2) arduinoCIAssertOp("ComparativeEquivalent","expected",arg1,compareEquivalent,"!<>","actual",arg2)
|
50
|
+
#define assertComparativeNotEquivalent(arg1,arg2) arduinoCIAssertOp("ComparativeNotEquivalent","unwanted",arg1,compareNotEquivalent,"<>","actual",arg2)
|
51
|
+
#define assertLess(arg1,arg2) arduinoCIAssertOp("Less","lowerBound",arg1,compareLess,"<","actual",arg2)
|
52
|
+
#define assertMore(arg1,arg2) arduinoCIAssertOp("More","upperBound",arg1,compareMore,">","actual",arg2)
|
53
|
+
#define assertLessOrEqual(arg1,arg2) arduinoCIAssertOp("LessOrEqual","lowerBound",arg1,compareLessOrEqual,"<=","actual",arg2)
|
54
|
+
#define assertMoreOrEqual(arg1,arg2) arduinoCIAssertOp("MoreOrEqual","upperBound",arg1,compareMoreOrEqual,">=","actual",arg2)
|
55
|
+
|
56
|
+
#define assertEqualFloat(arg1, arg2, arg3) arduinoCIAssertOp("EqualFloat", "epsilon", arg3, compareMoreOrEqual, ">=", "actualDifference", fabs(arg1 - arg2))
|
57
|
+
#define assertNotEqualFloat(arg1, arg2, arg3) arduinoCIAssertOp("NotEqualFloat", "epsilon", arg3, compareLessOrEqual, "<=", "insufficientDifference", fabs(arg1 - arg2))
|
58
|
+
#define assertInfinity(arg) arduinoCITestBehaviorExp(false, "Infinity " #arg, isinf(arg))
|
59
|
+
#define assertNotInfinity(arg) arduinoCITestBehaviorExp(false, "NotInfinity " #arg, !isinf(arg))
|
60
|
+
#define assertNAN(arg) arduinoCITestBehaviorExp(false, "NAN " #arg, isnan(arg))
|
61
|
+
#define assertNotNAN(arg) arduinoCITestBehaviorExp(false, "NotNAN " #arg, !isnan(arg))
|
62
|
+
|
43
63
|
|
44
64
|
/** macro generates optional output and calls fail() followed by a return if false. */
|
45
|
-
#define
|
46
|
-
#define
|
47
|
-
#define
|
48
|
-
#define
|
49
|
-
#define
|
50
|
-
#define
|
51
|
-
#define
|
52
|
-
#define
|
53
|
-
#define
|
54
|
-
#define
|
65
|
+
#define assureTrue(arg) arduinoCITestBehaviorExp(true, "True " #arg, (arg))
|
66
|
+
#define assureFalse(arg) arduinoCITestBehaviorExp(true, "False " #arg, !(arg))
|
67
|
+
#define assureNull(arg) arduinoCITestBehaviorExp(true, "Null " #arg, ((void*)NULL == (void*)(arg)))
|
68
|
+
#define assureNotNull(arg) arduinoCITestBehaviorExp(true, "NotNull " #arg, ((void*)NULL != (void*)(arg)))
|
69
|
+
#define assureEqual(arg1,arg2) arduinoCIAssureOp("Equal","expected",arg1,compareEqual,"==","actual",arg2)
|
70
|
+
#define assureNotEqual(arg1,arg2) arduinoCIAssureOp("NotEqual","unwanted",arg1,compareNotEqual,"!=","actual",arg2)
|
71
|
+
#define assureComparativeEquivalent(arg1,arg2) arduinoCIAssureOp("ComparativeEquivalent","expected",arg1,compareEquivalent,"!<>","actual",arg2)
|
72
|
+
#define assureComparativeNotEquivalent(arg1,arg2) arduinoCIAssureOp("ComparativeNotEquivalent","unwanted",arg1,compareNotEquivalent,"<>","actual",arg2)
|
73
|
+
#define assureLess(arg1,arg2) arduinoCIAssureOp("Less","lowerBound",arg1,compareLess,"<","actual",arg2)
|
74
|
+
#define assureMore(arg1,arg2) arduinoCIAssureOp("More","upperBound",arg1,compareMore,">","actual",arg2)
|
75
|
+
#define assureLessOrEqual(arg1,arg2) arduinoCIAssureOp("LessOrEqual","lowerBound",arg1,compareLessOrEqual,"<=","actual",arg2)
|
76
|
+
#define assureMoreOrEqual(arg1,arg2) arduinoCIAssureOp("MoreOrEqual","upperBound",arg1,compareMoreOrEqual,">=","actual",arg2)
|
55
77
|
|
78
|
+
#define assureEqualFloat(arg1, arg2, arg3) arduinoCIAssureOp("EqualFloat", "epsilon", arg3, compareMoreOrEqual, ">=", "actualDifference", fabs(arg1 - arg2))
|
79
|
+
#define assureNotEqualFloat(arg1, arg2, arg3) arduinoCIAssureOp("NotEqualFloat", "epsilon", arg3, compareLessOrEqual, "<=", "insufficientDifference", fabs(arg1 - arg2))
|
80
|
+
#define assureInfinity(arg) arduinoCITestBehaviorExp(true, "Infinity " #arg, isinf(arg))
|
81
|
+
#define assureNotInfinity(arg) arduinoCITestBehaviorExp(true, "NotInfinity " #arg, !isinf(arg))
|
82
|
+
#define assureNAN(arg) arduinoCITestBehaviorExp(true, "NAN " #arg, isnan(arg))
|
83
|
+
#define assureNotNAN(arg) arduinoCITestBehaviorExp(true, "NotNAN " #arg, !isnan(arg))
|
data/cpp/unittest/Compare.h
CHANGED
@@ -10,12 +10,14 @@ template < typename A, typename B > struct Compare
|
|
10
10
|
if (b<a) return 1;
|
11
11
|
return 0;
|
12
12
|
}
|
13
|
-
inline static bool equal(const A &a,const B &b)
|
14
|
-
inline static bool notEqual(const A &a,const B &b)
|
15
|
-
inline static bool
|
16
|
-
inline static bool
|
17
|
-
inline static bool
|
18
|
-
inline static bool
|
13
|
+
inline static bool equal(const A &a,const B &b) { return a==b; }
|
14
|
+
inline static bool notEqual(const A &a,const B &b) { return a!=b; }
|
15
|
+
inline static bool equivalent(const A &a,const B &b) { return (!(a < b)) && (!(b < a)); }
|
16
|
+
inline static bool notEquivalent(const A &a,const B &b) { return (a<b) || (b<a); }
|
17
|
+
inline static bool less(const A &a,const B &b) { return a<b; }
|
18
|
+
inline static bool more(const A &a,const B &b) { return b<a; }
|
19
|
+
inline static bool lessOrEqual(const A &a,const B &b) { return !(b<a); }
|
20
|
+
inline static bool moreOrEqual(const A &a,const B &b) { return !(a<b); }
|
19
21
|
};
|
20
22
|
|
21
23
|
// helpers for macros
|
@@ -57,56 +59,61 @@ inline static int arduinoCICompareBetween(const __FlashStringHelper * const &a,c
|
|
57
59
|
|
58
60
|
|
59
61
|
// this macro works for all the string-based comparisons
|
62
|
+
// note that it substitutes equivalence for equality
|
60
63
|
// but just in case, https://stackoverflow.com/a/13842784/2063546
|
61
|
-
#define
|
62
|
-
template < __VA_ARGS__ > struct Compare<T1 T1m, T2 T2m>;
|
63
|
-
template < __VA_ARGS__ > struct Compare<T1 T1m, T2 T2m>
|
64
|
-
{
|
65
|
-
inline static int between(
|
66
|
-
inline static bool equal(
|
67
|
-
inline static bool notEqual(
|
68
|
-
inline static bool
|
69
|
-
inline static bool
|
70
|
-
inline static bool
|
71
|
-
inline static bool
|
64
|
+
#define eqComparisonTemplateMacro(T1, T1m, T2, T2m, betweenImpl, ...) \
|
65
|
+
template < __VA_ARGS__ > struct Compare<T1 T1m, T2 T2m>; \
|
66
|
+
template < __VA_ARGS__ > struct Compare<T1 T1m, T2 T2m> \
|
67
|
+
{ \
|
68
|
+
inline static int between( T1 const (&a)T1m, T2 const (&b)T2m) { return betweenImpl; } \
|
69
|
+
inline static bool equal( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) == 0; } \
|
70
|
+
inline static bool notEqual( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) != 0; } \
|
71
|
+
inline static bool equivalent( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) == 0; } \
|
72
|
+
inline static bool notEquivalent(T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) != 0; } \
|
73
|
+
inline static bool less( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) < 0; } \
|
74
|
+
inline static bool more( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) > 0; } \
|
75
|
+
inline static bool lessOrEqual( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) <= 0; } \
|
76
|
+
inline static bool moreOrEqual( T1 const (&a)T1m, T2 const (&b)T2m) { return between(a, b) >= 0; } \
|
72
77
|
};
|
73
78
|
|
74
|
-
|
75
|
-
|
79
|
+
eqComparisonTemplateMacro(String, , String, , a.compareTo(b))
|
80
|
+
eqComparisonTemplateMacro(String, , const char *, , a.compareTo(b))
|
76
81
|
#if defined(F)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
eqComparisonTemplateMacro(String, , const __FlashStringHelper *, , arduinoCICompareBetween(a, b))
|
83
|
+
eqComparisonTemplateMacro(const char *,, const __FlashStringHelper *, , strcmp_P(a,(const char *)b))
|
84
|
+
eqComparisonTemplateMacro(const __FlashStringHelper *, , String, , -arduinoCICompareBetween(b, a))
|
85
|
+
eqComparisonTemplateMacro(const __FlashStringHelper *, , const char *, , -strcmp_P(b,(const char *)a))
|
86
|
+
eqComparisonTemplateMacro(const __FlashStringHelper *, , const __FlashStringHelper *, , arduinoCICompareBetween(a, b))
|
87
|
+
eqComparisonTemplateMacro(const __FlashStringHelper *, , char *, , -strcmp_P(b,(const char *)a))
|
88
|
+
eqComparisonTemplateMacro(char *, , const __FlashStringHelper *, , strcmp_P(a,(const char *)b))
|
89
|
+
eqComparisonTemplateMacro(const __FlashStringHelper *, , char, [M], -strcmp_P(b,(const char *)a), size_t M)
|
90
|
+
eqComparisonTemplateMacro(char, [N], const __FlashStringHelper *, , strcmp_P(a,(const char *)b), size_t N)
|
86
91
|
#endif
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
92
|
+
eqComparisonTemplateMacro(String, , char *, , a.compareTo(b))
|
93
|
+
eqComparisonTemplateMacro(const char *, , String, , -b.compareTo(a))
|
94
|
+
eqComparisonTemplateMacro(const char *, , const char *, , strcmp(a,b))
|
95
|
+
eqComparisonTemplateMacro(const char *, , char *, , strcmp(a,b))
|
96
|
+
eqComparisonTemplateMacro(char *, , String, , -b.compareTo(a))
|
97
|
+
eqComparisonTemplateMacro(char *, , const char *, , strcmp(a,b))
|
98
|
+
eqComparisonTemplateMacro(char *, , char *, , strcmp(a,b))
|
99
|
+
eqComparisonTemplateMacro(String, , char, [M], a.compareTo(b), size_t M)
|
100
|
+
eqComparisonTemplateMacro(const char *, , char, [M], strcmp(a,b), size_t M)
|
101
|
+
eqComparisonTemplateMacro(char *, , char, [M], strcmp(a,b), size_t M)
|
102
|
+
eqComparisonTemplateMacro(char, [N], String, , -b.compareTo(a), size_t N)
|
103
|
+
eqComparisonTemplateMacro(char, [N], const char *, , strcmp(a,b), size_t N)
|
104
|
+
eqComparisonTemplateMacro(char, [N], char *, , strcmp(a,b), size_t N)
|
105
|
+
eqComparisonTemplateMacro(char, [N], char, [M], strcmp(a,b), size_t N, size_t M)
|
101
106
|
|
102
|
-
|
103
|
-
|
107
|
+
eqComparisonTemplateMacro(A, , std::nullptr_t, , a ? 1 : 0, typename A)
|
108
|
+
eqComparisonTemplateMacro(std::nullptr_t, , B, , b ? -1 : 0, typename B)
|
104
109
|
|
105
110
|
// super general comparisons
|
106
|
-
template <typename A, typename B> int compareBetween(
|
107
|
-
template <typename A, typename B> bool compareEqual(
|
108
|
-
template <typename A, typename B> bool compareNotEqual(
|
109
|
-
template <typename A, typename B> bool
|
110
|
-
template <typename A, typename B> bool
|
111
|
-
template <typename A, typename B> bool
|
112
|
-
template <typename A, typename B> bool
|
111
|
+
template <typename A, typename B> int compareBetween( const A &a, const B &b) { return Compare<A, B>::between( a, b); }
|
112
|
+
template <typename A, typename B> bool compareEqual( const A &a, const B &b) { return Compare<A, B>::equal( a, b); }
|
113
|
+
template <typename A, typename B> bool compareNotEqual( const A &a, const B &b) { return Compare<A, B>::notEqual( a, b); }
|
114
|
+
template <typename A, typename B> bool compareEquivalent( const A &a, const B &b) { return Compare<A, B>::equivalent( a, b); }
|
115
|
+
template <typename A, typename B> bool compareNotEquivalent(const A &a, const B &b) { return Compare<A, B>::notEquivalent(a, b); }
|
116
|
+
template <typename A, typename B> bool compareLess( const A &a, const B &b) { return Compare<A, B>::less( a, b); }
|
117
|
+
template <typename A, typename B> bool compareMore( const A &a, const B &b) { return Compare<A, B>::more( a, b); }
|
118
|
+
template <typename A, typename B> bool compareLessOrEqual( const A &a, const B &b) { return Compare<A, B>::lessOrEqual( a, b); }
|
119
|
+
template <typename A, typename B> bool compareMoreOrEqual( const A &a, const B &b) { return Compare<A, B>::moreOrEqual( a, b); }
|
data/exe/arduino_ci.rb
CHANGED
@@ -5,8 +5,11 @@ require 'pathname'
|
|
5
5
|
require 'optparse'
|
6
6
|
|
7
7
|
WIDTH = 80
|
8
|
-
|
9
|
-
|
8
|
+
VAR_CUSTOM_INIT_SCRIPT = "CUSTOM_INIT_SCRIPT".freeze
|
9
|
+
VAR_USE_SUBDIR = "USE_SUBDIR".freeze
|
10
|
+
VAR_EXPECT_EXAMPLES = "EXPECT_EXAMPLES".freeze
|
11
|
+
VAR_EXPECT_UNITTESTS = "EXPECT_UNITTESTS".freeze
|
12
|
+
VAR_SKIP_LIBPROPS = "SKIP_LIBRARY_PROPERTIES".freeze
|
10
13
|
|
11
14
|
@failure_count = 0
|
12
15
|
@passfail = proc { |result| result ? "✓" : "✗" }
|
@@ -19,6 +22,7 @@ class Parser
|
|
19
22
|
output_options = {
|
20
23
|
skip_unittests: false,
|
21
24
|
skip_compilation: false,
|
25
|
+
skip_library_properties: false,
|
22
26
|
ci_config: {
|
23
27
|
"unittest" => unit_config
|
24
28
|
},
|
@@ -35,6 +39,10 @@ class Parser
|
|
35
39
|
output_options[:skip_compilation] = p
|
36
40
|
end
|
37
41
|
|
42
|
+
opts.on("--skip-library-properties", "Don't validate library.properties entries") do |p|
|
43
|
+
output_options[:skip_compilation] = p
|
44
|
+
end
|
45
|
+
|
38
46
|
opts.on("--testfile-select=GLOB", "Unit test file (or glob) to select") do |p|
|
39
47
|
unit_config["testfiles"] ||= {}
|
40
48
|
unit_config["testfiles"]["select"] ||= []
|
@@ -51,8 +59,12 @@ class Parser
|
|
51
59
|
puts opts
|
52
60
|
puts
|
53
61
|
puts "Additionally, the following environment variables control the script:"
|
62
|
+
puts " - #{VAR_CUSTOM_INIT_SCRIPT} - if set, this script will be run from the Arduino/libraries directory"
|
63
|
+
puts " prior to any automated library installation or testing (e.g. to install unoffical libraries)"
|
64
|
+
puts " - #{VAR_USE_SUBDIR} - if set, the script will install the library from this subdirectory of the cwd"
|
54
65
|
puts " - #{VAR_EXPECT_EXAMPLES} - if set, testing will fail if no example sketches are present"
|
55
66
|
puts " - #{VAR_EXPECT_UNITTESTS} - if set, testing will fail if no unit tests are present"
|
67
|
+
puts " - #{VAR_SKIP_LIBPROPS} - if set, testing will skip [experimental] library.properties validation"
|
56
68
|
exit
|
57
69
|
end
|
58
70
|
end
|
@@ -68,11 +80,12 @@ end
|
|
68
80
|
# terminate after printing any debug info. TODO: capture debug info
|
69
81
|
def terminate(final = nil)
|
70
82
|
puts "Failures: #{@failure_count}"
|
71
|
-
unless @failure_count.zero? || final
|
72
|
-
puts "Last
|
73
|
-
puts
|
83
|
+
unless @failure_count.zero? || final || @backend.nil?
|
84
|
+
puts "========== Last backend command (if relevant):"
|
85
|
+
puts @backend.last_msg.to_s
|
86
|
+
puts "========== Backend Stdout:"
|
74
87
|
puts @backend.last_out
|
75
|
-
puts "========== Stderr:"
|
88
|
+
puts "========== Backend Stderr:"
|
76
89
|
puts @backend.last_err
|
77
90
|
end
|
78
91
|
retcode = @failure_count.zero? ? 0 : 1
|
@@ -141,6 +154,10 @@ def inform_multiline(message, &block)
|
|
141
154
|
perform_action(message, true, nil, nil, false, false, &block)
|
142
155
|
end
|
143
156
|
|
157
|
+
def warn(message)
|
158
|
+
inform("WARNING") { message }
|
159
|
+
end
|
160
|
+
|
144
161
|
# Assure that a platform exists and return its definition
|
145
162
|
def assured_platform(purpose, name, config)
|
146
163
|
platform_definition = config.platform_definition(name)
|
@@ -190,28 +207,20 @@ def install_arduino_library_dependencies(library_names, on_behalf_of, already_in
|
|
190
207
|
installed
|
191
208
|
end
|
192
209
|
|
193
|
-
# @param
|
194
|
-
# @param
|
195
|
-
def install_all_packages(
|
196
|
-
|
197
|
-
#
|
198
|
-
all_packages =
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
unless all_urls.empty?
|
207
|
-
assure_multiline("Setting board manager URLs") do
|
208
|
-
@backend.board_manager_urls = all_urls
|
209
|
-
result = @backend.board_manager_urls
|
210
|
-
result.each { |u| puts " #{u}" }
|
211
|
-
(all_urls - result).empty? # check that all_urls is completely contained in the result
|
212
|
-
end
|
210
|
+
# @param platforms [Array<String>] list of platforms to consider
|
211
|
+
# @param specific_config [CIConfig] configuration to use
|
212
|
+
def install_all_packages(platforms, specific_config)
|
213
|
+
|
214
|
+
# get packages from platforms
|
215
|
+
all_packages = specific_config.platform_info.select { |p, _| platforms.include?(p) }.values.map { |v| v[:package] }.compact.uniq
|
216
|
+
|
217
|
+
all_packages.each do |pkg|
|
218
|
+
next if @backend.boards_installed?(pkg)
|
219
|
+
|
220
|
+
url = assure("Board package #{pkg} has a defined URL") { specific_config.package_url(pkg) }
|
221
|
+
@backend.board_manager_urls = [url]
|
222
|
+
assure("Installing board package #{pkg}") { @backend.install_boards(pkg) }
|
213
223
|
end
|
214
|
-
all_packages.each { |p| assure("Installing board package #{p}") { @backend.install_boards(p) } }
|
215
224
|
end
|
216
225
|
|
217
226
|
# @param expectation_envvar [String] the name of the env var to check
|
@@ -243,17 +252,25 @@ def handle_expectation_of_files(expectation_envvar, operation, filegroup_name, d
|
|
243
252
|
end
|
244
253
|
|
245
254
|
inform(problem) { dir_path }
|
255
|
+
explain_and_exercise_envvar(expectation_envvar, operation, "contents of #{dir_desc}") { display_files(dir) }
|
256
|
+
end
|
257
|
+
|
258
|
+
# @param expectation_envvar [String] the name of the env var to check
|
259
|
+
# @param operation [String] a description of what operation we might be skipping
|
260
|
+
# @param block_desc [String] a description of what information will be dumped to assist the user
|
261
|
+
# @param block [Proc] a function that dumps information
|
262
|
+
def explain_and_exercise_envvar(expectation_envvar, operation, block_desc, &block)
|
246
263
|
inform("Environment variable #{expectation_envvar} is") { "(#{ENV[expectation_envvar].class}) #{ENV[expectation_envvar]}" }
|
247
264
|
if ENV[expectation_envvar].nil?
|
248
265
|
inform_multiline("Skipping #{operation}") do
|
249
|
-
puts " In case that's an error,
|
250
|
-
|
266
|
+
puts " In case that's an error, displaying #{block_desc}:"
|
267
|
+
block.call
|
251
268
|
puts " To force an error in this case, set the environment variable #{expectation_envvar}"
|
252
269
|
true
|
253
270
|
end
|
254
271
|
else
|
255
|
-
assure_multiline("
|
256
|
-
|
272
|
+
assure_multiline("Displaying #{block_desc} before exit") do
|
273
|
+
block.call
|
257
274
|
false
|
258
275
|
end
|
259
276
|
end
|
@@ -277,6 +294,105 @@ def get_annotated_compilers(config, cpp_library)
|
|
277
294
|
compilers
|
278
295
|
end
|
279
296
|
|
297
|
+
# Handle existence or nonexistence of custom initialization script -- run it if you have it
|
298
|
+
#
|
299
|
+
# This feature is to drive GitHub actions / docker image installation where the container is
|
300
|
+
# in a clean-slate state but needs some way to have custom library versions injected into it.
|
301
|
+
# In this case, the user provided script would fetch a git repo or some other method
|
302
|
+
def perform_custom_initialization(_config)
|
303
|
+
script_path = ENV[VAR_CUSTOM_INIT_SCRIPT]
|
304
|
+
inform("Environment variable #{VAR_CUSTOM_INIT_SCRIPT}") { "'#{script_path}'" }
|
305
|
+
return if script_path.nil?
|
306
|
+
return if script_path.empty?
|
307
|
+
|
308
|
+
script_pathname = Pathname.getwd + script_path
|
309
|
+
assure("Script at #{VAR_CUSTOM_INIT_SCRIPT} exists") { script_pathname.exist? }
|
310
|
+
|
311
|
+
assure_multiline("Running #{script_pathname} with sh in libraries working dir") do
|
312
|
+
Dir.chdir(@backend.lib_dir) do
|
313
|
+
IO.popen(["/bin/sh", script_pathname.to_s], err: [:child, :out]) do |io|
|
314
|
+
io.each_line { |line| puts " #{line}" }
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Auto-select some platforms to test based on the information available
|
321
|
+
#
|
322
|
+
# Top choice is always library.properties -- otherwise use the default.
|
323
|
+
# But filter that through any non-default config
|
324
|
+
#
|
325
|
+
# @param config [CIConfig] the overridden config object
|
326
|
+
# @param reason [String] description of why we might use this platform (i.e. unittest or compilation)
|
327
|
+
# @param desired_platforms [Array<String>] the platform names specified
|
328
|
+
# @param library_properties [Hash] the library properties defined by the library
|
329
|
+
# @return [Array<String>] platforms to use
|
330
|
+
def choose_platform_set(config, reason, desired_platforms, library_properties)
|
331
|
+
|
332
|
+
# if there are no properties or no architectures, defer entirely to desired platforms
|
333
|
+
if library_properties.nil? || library_properties.architectures.nil? || library_properties.architectures.empty?
|
334
|
+
# verify that all platforms exist
|
335
|
+
desired_platforms.each { |p| assured_platform(reason, p, config) }
|
336
|
+
return inform_multiline("No architectures listed in library.properties, using configured platforms") do
|
337
|
+
desired_platforms.each { |p| puts " #{p}" } # this returns desired_platforms
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
if library_properties.architectures.include?("*")
|
342
|
+
return inform_multiline("Wildcard architecture in library.properties, using configured platforms") do
|
343
|
+
desired_platforms.each { |p| puts " #{p}" } # this returns desired_platforms
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
platform_architecture = config.platform_info.transform_values { |v| v[:board].split(":")[1] }
|
348
|
+
supported_platforms = platform_architecture.select { |_, a| library_properties.architectures.include?(a) }
|
349
|
+
|
350
|
+
if config.is_default
|
351
|
+
# completely ignore default config, opting for brute-force library matches
|
352
|
+
# OTOH, we don't need to assure platforms because we defined them
|
353
|
+
return inform_multiline("Default config, platforms matching architectures in library.properties") do
|
354
|
+
supported_platforms.each_key do |p|
|
355
|
+
puts " #{p}"
|
356
|
+
end # this returns supported_platforms
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
desired_supported_platforms = supported_platforms.select { |p, _| desired_platforms.include?(p) }.keys
|
361
|
+
desired_supported_platforms.each { |p| assured_platform(reason, p, config) }
|
362
|
+
inform_multiline("Configured platforms that match architectures in library.properties") do
|
363
|
+
desired_supported_platforms.each do |p|
|
364
|
+
puts " #{p}"
|
365
|
+
end # this returns supported_platforms
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
# tests of sane library.properties values
|
370
|
+
def perform_property_tests(cpp_library)
|
371
|
+
return inform("Skipping library.properties tests") { "as requested via command line" } if @cli_options[:skip_library_properties]
|
372
|
+
return inform("Skipping library.properties tests") { "as requested via environment" } unless ENV[VAR_SKIP_LIBPROPS].nil?
|
373
|
+
return inform("Skipping library.properties tests") { "file not found" } unless cpp_library.library_properties?
|
374
|
+
|
375
|
+
props = cpp_library.library_properties
|
376
|
+
|
377
|
+
props.depends&.each do |l|
|
378
|
+
assure("library.properties 'depends=' entry '#{l}' is available via the library manager") { @backend.library_available?(l) }
|
379
|
+
end
|
380
|
+
|
381
|
+
# the IDE would add these entries to a sketch (as "#include <...>" lines), they are nothing to do with the compioler
|
382
|
+
props.includes&.map(&:strip)&.map(&Pathname::method(:new))&.each do |f|
|
383
|
+
if (cpp_library.path + f).exist?
|
384
|
+
inform("library.properties 'includes=' entry found") { f }
|
385
|
+
elsif (cpp_library.path + "src" + f).exist?
|
386
|
+
inform("library.properties 'includes=' entry found") { Pathname.new("src") + f }
|
387
|
+
else
|
388
|
+
# this is if they want to "#include <math>" or something -- may or may not be valid! so just warn.
|
389
|
+
warn("library.properties 'includes=' entry '#{f}' does not refer to a file in the library")
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
# Unit test procedure
|
280
396
|
def perform_unit_tests(cpp_library, file_config)
|
281
397
|
if @cli_options[:skip_unittests]
|
282
398
|
inform("Skipping unit tests") { "as requested via command line" }
|
@@ -285,7 +401,6 @@ def perform_unit_tests(cpp_library, file_config)
|
|
285
401
|
|
286
402
|
config = file_config.with_override_config(@cli_options[:ci_config])
|
287
403
|
compilers = get_annotated_compilers(config, cpp_library)
|
288
|
-
config.platforms_to_unittest.each_with_object({}) { |p, acc| acc[p] = assured_platform("unittest", p, config) }
|
289
404
|
|
290
405
|
inform("Library conforms to Arduino library specification") { cpp_library.one_point_five? ? "1.5" : "1.0" }
|
291
406
|
|
@@ -295,15 +410,20 @@ def perform_unit_tests(cpp_library, file_config)
|
|
295
410
|
return
|
296
411
|
end
|
297
412
|
|
298
|
-
#
|
299
|
-
|
300
|
-
|
301
|
-
|
413
|
+
# Get platforms, handle lack of them
|
414
|
+
platforms = choose_platform_set(config, "unittest", config.platforms_to_unittest, cpp_library.library_properties)
|
415
|
+
if platforms.empty?
|
416
|
+
explain_and_exercise_envvar(VAR_EXPECT_UNITTESTS, "unit tests", "platforms and architectures") do
|
417
|
+
puts " Configured platforms: #{config.platforms_to_unittest}"
|
418
|
+
puts " Configuration is default: #{config.is_default}"
|
419
|
+
arches = cpp_library.library_properties.nil? ? nil : cpp_library.library_properties.architectures
|
420
|
+
puts " Architectures in library.properties: #{arches}"
|
421
|
+
end
|
302
422
|
end
|
303
423
|
|
304
424
|
install_arduino_library_dependencies(config.aux_libraries_for_unittest, "<unittest/libraries>")
|
305
425
|
|
306
|
-
|
426
|
+
platforms.each do |p|
|
307
427
|
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
|
308
428
|
unittest_name = unittest_path.basename.to_s
|
309
429
|
compilers.each do |gcc_binary|
|
@@ -334,47 +454,33 @@ def perform_example_compilation_tests(cpp_library, config)
|
|
334
454
|
return
|
335
455
|
end
|
336
456
|
|
337
|
-
# gather up all required boards for compilation so we can install them up front.
|
338
|
-
# start with the "platforms to unittest" and add the examples
|
339
|
-
# while we're doing that, get the aux libraries as well
|
340
|
-
example_platform_info = {}
|
341
|
-
board_package_url = {}
|
342
|
-
aux_libraries = Set.new(config.aux_libraries_for_build)
|
343
|
-
# while collecting the platforms, ensure they're defined
|
344
|
-
|
345
457
|
library_examples = cpp_library.example_sketches
|
346
|
-
library_examples.each do |path|
|
347
|
-
ovr_config = config.from_example(path)
|
348
|
-
ovr_config.platforms_to_build.each do |platform|
|
349
|
-
# assure the platform if we haven't already
|
350
|
-
next if example_platform_info.key?(platform)
|
351
|
-
|
352
|
-
platform_info = assured_platform("library example", platform, config)
|
353
|
-
next if platform_info.nil?
|
354
|
-
|
355
|
-
example_platform_info[platform] = platform_info
|
356
|
-
package = platform_info[:package]
|
357
|
-
board_package_url[package] = ovr_config.package_url(package)
|
358
|
-
end
|
359
|
-
aux_libraries.merge(ovr_config.aux_libraries_for_build)
|
360
|
-
end
|
361
|
-
|
362
|
-
install_all_packages(example_platform_info, board_package_url)
|
363
|
-
install_arduino_library_dependencies(aux_libraries, "<compile/libraries>")
|
364
458
|
|
365
|
-
if
|
366
|
-
inform("Skipping builds") { "no platforms were requested" }
|
367
|
-
return
|
368
|
-
elsif library_examples.empty?
|
459
|
+
if library_examples.empty?
|
369
460
|
handle_expectation_of_files(VAR_EXPECT_EXAMPLES, "builds", "examples", "the examples directory", cpp_library.examples_dir)
|
370
461
|
return
|
371
462
|
end
|
372
463
|
|
373
464
|
library_examples.each do |example_path|
|
465
|
+
example_name = File.basename(example_path)
|
374
466
|
ovr_config = config.from_example(example_path)
|
375
|
-
ovr_config.platforms_to_build.
|
376
|
-
|
377
|
-
|
467
|
+
platforms = choose_platform_set(ovr_config, "library example", ovr_config.platforms_to_build, cpp_library.library_properties)
|
468
|
+
|
469
|
+
if platforms.empty?
|
470
|
+
explain_and_exercise_envvar(VAR_EXPECT_EXAMPLES, "examples compilation", "platforms and architectures") do
|
471
|
+
puts " Configured platforms: #{config.platforms_to_build}"
|
472
|
+
puts " Configuration is default: #{config.is_default}"
|
473
|
+
arches = cpp_library.library_properties.nil? ? nil : cpp_library.library_properties.architectures
|
474
|
+
puts " Architectures in library.properties: #{arches}"
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
install_all_packages(platforms, ovr_config)
|
479
|
+
|
480
|
+
platforms.each do |p|
|
481
|
+
install_arduino_library_dependencies(ovr_config.aux_libraries_for_build, "<compile/libraries>")
|
482
|
+
|
483
|
+
board = ovr_config.platform_info[p][:board]
|
378
484
|
attempt("Compiling #{example_name} for #{board}") do
|
379
485
|
ret = @backend.compile_sketch(example_path, board)
|
380
486
|
unless ret
|
@@ -390,21 +496,23 @@ end
|
|
390
496
|
|
391
497
|
# initialize command and config
|
392
498
|
config = ArduinoCI::CIConfig.default.from_project_library
|
393
|
-
|
394
499
|
@backend = ArduinoCI::ArduinoInstallation.autolocate!
|
395
500
|
inform("Located arduino-cli binary") { @backend.binary_path.to_s }
|
396
501
|
|
502
|
+
# run any library init scripts from the library itself.
|
503
|
+
perform_custom_initialization(config)
|
504
|
+
|
397
505
|
# initialize library under test
|
398
|
-
|
506
|
+
inform("Environment variable #{VAR_USE_SUBDIR}") { "'#{ENV[VAR_USE_SUBDIR]}'" }
|
507
|
+
cpp_library_path = Pathname.new(ENV[VAR_USE_SUBDIR].nil? ? "." : ENV[VAR_USE_SUBDIR])
|
399
508
|
cpp_library = assure("Installing library under test") do
|
400
509
|
@backend.install_local_library(cpp_library_path)
|
401
510
|
end
|
402
511
|
|
512
|
+
# Warn if the library name isn't obvious
|
403
513
|
assumed_name = @backend.name_of_library(cpp_library_path)
|
404
|
-
ondisk_name = cpp_library_path.realpath.basename
|
405
|
-
if assumed_name != ondisk_name
|
406
|
-
inform("WARNING") { "Installed library named '#{assumed_name}' has directory name '#{ondisk_name}'" }
|
407
|
-
end
|
514
|
+
ondisk_name = cpp_library_path.realpath.basename.to_s
|
515
|
+
warn("Installed library named '#{assumed_name}' has directory name '#{ondisk_name}'") if assumed_name != ondisk_name
|
408
516
|
|
409
517
|
if !cpp_library.nil?
|
410
518
|
inform("Library installed at") { cpp_library.path.to_s }
|
@@ -416,6 +524,8 @@ else
|
|
416
524
|
end
|
417
525
|
end
|
418
526
|
|
527
|
+
perform_property_tests(cpp_library)
|
528
|
+
|
419
529
|
install_arduino_library_dependencies(
|
420
530
|
cpp_library.arduino_library_dependencies,
|
421
531
|
"<#{ArduinoCI::CppLibrary::LIBRARY_PROPERTIES_FILE}>"
|