Skip to content

Support for more builtins via mocks #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Feb 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
af6cf3a
quieter wget
ianfixes Jan 26, 2018
e192634
math, trig, and bit functions mocked
ianfixes Jan 26, 2018
b28338f
clear command errors on executable run
ianfixes Jan 26, 2018
5babcb0
fix headers when we don't touch the library
ianfixes Jan 26, 2018
1055607
move trig tests to trig file
ianfixes Jan 26, 2018
3912a95
add GODMODE, tests, and time stuff
ianfixes Jan 26, 2018
4497273
add WCharacter implementation
ianfixes Jan 26, 2018
258971c
add arduino defines
ianfixes Jan 26, 2018
9c83ea0
add random functions. literally.
ianfixes Jan 26, 2018
598834a
add pin mocks
ianfixes Jan 26, 2018
a65f6b1
allow compare of bool values
ianfixes Jan 30, 2018
e714f97
support String() class
ianfixes Jan 30, 2018
604e1ce
set compiler flags for cross-platorm harmony
ianfixes Jan 31, 2018
41f00d4
fix headers for portability
ianfixes Jan 31, 2018
79a6d1a
update README with GODMODE()
ianfixes Jan 31, 2018
7b975d9
factor out Godmode to its own file
ianfixes Feb 1, 2018
b0cb75a
improve float-string conversion: rounding and non-numbers
ianfixes Feb 1, 2018
709b697
Add support for streams
ianfixes Feb 1, 2018
a2d8c6a
move time functions to godmode
ianfixes Feb 1, 2018
8e33157
fix dependency of String on char lib
ianfixes Feb 1, 2018
642f4c1
fix logging for asserts on bools
ianfixes Feb 1, 2018
7817561
Add serial port support
ianfixes Feb 1, 2018
e7c322d
avoid strlen for portability
ianfixes Feb 1, 2018
502bbec
avoid ambiguous use of isnan/isinf
ianfixes Feb 1, 2018
edf63d2
update README with serial port stuff
ianfixes Feb 1, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
- Support for all builtin Math functions https://www.arduino.cc/reference/en/
- Support for all builtin Bits and Bytes functions https://www.arduino.cc/reference/en/
- Support for GODMODE and time functions
- Support for Character functions https://www.arduino.cc/reference/en/
- Mocks for `random` functions with seed control
- Many original Arduino `#define`s
- Mocks for pinMode, analog/digital read/write
- Support for WString
- Support for Print
- Support for Stream (backed by a String implementation)
- All the IO stuff (pins, serial port support flags, etc) from the Arduino library
- Support for Serial (backed by GODMODE)

### Changed
- Made `wget` have quieter output

### Deprecated

Expand Down
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,82 @@ unittest_main()
This test defines one `unittest` (a macro provided by `ArduionUnitTests.h`), called `your_test_name`, which makes some assertions on the target library. The `unittest_main()` is a macro for the `int main()` boilerplate required for unit testing.


### Using `GODMODE`

Complete control of the Arduino environment is available in your unit tests through a construct called `GODMODE()`.

```C++
unittest(example_godmode_stuff)
{
GodmodeState* state = GODMODE(); // get access to the state
state->reset(); // does a full reset of the state.
state->resetClock(); // - you can reset just the clock (to zero)
state->resetPins(); // - or just the pins
state->micros = 1; // manually set the clock such that micros() returns 1
state->digitalPin[4]; // stores the commanded state of digital pin 4
state->digitalPin[4] = HIGH; // digitalRead(4) will now return HIGH
state->analogPin[3]; // stores the commanded state of analog pin 3
state->analogPin[3] = 99; // analogRead(3) will now return 99
}
```

A more complicated example: working with serial port IO. Let's say I have the following function:

```C++
void smartLightswitchSerialHandler(int pin) {
if (Serial.available() > 0) {
int incomingByte = Serial.read();
int val = incomingByte == '0' ? LOW : HIGH;
Serial.print("Ack ");
digitalWrite(pin, val);
Serial.print(String(pin));
Serial.print(" ");
Serial.print((char)incomingByte);
}
}
```

This function has 3 side effects: it drains the serial port's receive buffer, affects a pin, and puts data in the serial port's send buffer. Or, if the receive buffer is empty, it does nothing at all.

```C++
unittest(does_nothing_if_no_data)
{
// configure initial state
GodmodeState* state = GODMODE();
int myPin = 3;
state->serialPort[0].dataIn = "";
state->serialPort[0].dataOut = "";
state->digitalPin[myPin] = LOW;

// execute action
smartLightswitchSerialHandler(myPin);

// assess final state
assertEqual(LOW, state->digitalPin[myPin]);
assertEqual("", state->serialPort[0].dataIn);
assertEqual("", state->serialPort[0].dataOut);
}

unittest(two_flips)
{
GodmodeState* state = GODMODE();
int myPin = 3;
state->serialPort[0].dataIn = "10junk";
state->serialPort[0].dataOut = "";
state->digitalPin[myPin] = LOW;
smartLightswitchSerialHandler(myPin);
assertEqual(HIGH, state->digitalPin[myPin]);
assertEqual("0junk", state->serialPort[0].dataIn);
assertEqual("Ack 3 1", state->serialPort[0].dataOut);

state->serialPort[0].dataOut = "";
smartLightswitchSerialHandler(myPin);
assertEqual(LOW, state->digitalPin[myPin]);
assertEqual("junk", state->serialPort[0].dataIn);
assertEqual("Ack 3 0", state->serialPort[0].dataOut);
}
```

## More Documentation

This software is in alpha. But [SampleProjects/DoSomething](SampleProjects/DoSomething) has a decent writeup and is a good bare-bones example of all the features.
Expand Down
2 changes: 2 additions & 0 deletions SampleProjects/TestSomething/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# TestSomething

This is a "beater" example that is referenced by tests of the Arduino CI module itself.

All the tests of our mocked `Arduino.h` implementation live here.
11 changes: 11 additions & 0 deletions SampleProjects/TestSomething/test/good-defines.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

unittest(binary)
{
assertEqual(1, B1);
assertEqual(10, B1010);
assertEqual(100, B1100100);
}

unittest_main()
68 changes: 68 additions & 0 deletions SampleProjects/TestSomething/test/good-godmode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

unittest(millis_micros_and_delay)
{
GodmodeState* state = GODMODE();
state->reset();
assertEqual(0, millis());
assertEqual(0, micros());
delay(3);
assertEqual(3, millis());
assertEqual(3000, micros());
delayMicroseconds(11000);
assertEqual(14, millis());
assertEqual(14000, micros());
}

unittest(random)
{
randomSeed(1);
unsigned long x;
x = random(4294967293);
assertEqual(4294967292, x);
x = random(50, 100);
assertEqual(83, x);
x = random(100);
assertEqual(74, x);
}

void myInterruptHandler() {
}

unittest(interrupts)
{
// these are meaningless for testing; just call the routine directly.
// make sure our mocks work though
attachInterrupt(2, myInterruptHandler, CHANGE);
detachInterrupt(2);
}

unittest(pins)
{
GodmodeState* state = GODMODE();
state->reset();
pinMode(1, OUTPUT); // this is a no-op in unit tests. it's just here to prove compilation
digitalWrite(1, HIGH);
assertEqual(HIGH, state->digitalPin[1]);
digitalWrite(1, LOW);
assertEqual(LOW, state->digitalPin[1]);

pinMode(1, INPUT);
state->digitalPin[1] = HIGH;
assertEqual(HIGH, digitalRead(1));
state->digitalPin[1] = LOW;
assertEqual(LOW, digitalRead(1));

analogWrite(1, 37);
assertEqual(37, state->analogPin[1]);
analogWrite(1, 22);
assertEqual(22, state->analogPin[1]);

state->analogPin[1] = 99;
assertEqual(99, analogRead(1));
state->analogPin[1] = 56;
assertEqual(56, analogRead(1));
}

unittest_main()
69 changes: 69 additions & 0 deletions SampleProjects/TestSomething/test/good-math.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

unittest(abs)
{
assertEqual(1, abs(1));
assertEqual(1, abs(-1));
assertEqual(1.0, abs(1.0));
assertEqual(1.0, abs(-1.0));
}

unittest(constrain)
{
assertEqual(3, constrain(1, 3, 5));
assertEqual(5, constrain(9, 3, 5));
assertEqual(2.0, constrain(1, 2.0, 5));
assertEqual(6.0, constrain(1.3, 6.0, 9));
}

unittest(map)
{
assertEqual(30, map(3, 0, 10, 0, 100));
assertEqual(30, map(20, 0, 50, 50, 0));
assertEqual(-4, map(26, 0, 50, 100, -100));
}

unittest(max)
{
assertEqual(4, max(3, 4));
assertEqual(5, max(3.0, 5));
assertEqual(6.0, max(-4, 6.0));
assertEqual(7.0, max(5.0, 7.0));
}

unittest(min)
{
assertEqual(3, min(3, 4));
assertEqual(3.0, min(3.0, 5));
assertEqual(-4, min(-4, 6.0));
assertEqual(5.0, min(5.0, 7.0));
}

unittest(pow)
{
assertEqual(4.0, pow(2, 2));
assertEqual(4.0, pow(2.0, 2.0));
assertEqual(0.125, pow(2, -3));
assertLess(1.41420, pow(2, 0.5));
assertMore(1.41422, pow(2, 0.5));
}

unittest(sq)
{
assertEqual(9, sq(3));
assertEqual(9.0, sq(3.0));
assertEqual(9, sq(-3));
assertEqual(9.0, sq(-3.0));
assertEqual(0.25, sq(0.5));
assertEqual(0.25, sq(-0.5));
}

unittest(sqrt)
{
assertEqual(3, sqrt(9));
assertEqual(3.0, sqrt(9.0));
}


unittest_main()
44 changes: 44 additions & 0 deletions SampleProjects/TestSomething/test/good-serial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

#if defined(HAVE_HWSERIAL0)
#define HAVE_SERIAL true
#else
#define HAVE_SERIAL false
#endif

bool have_serial_ports = HAVE_SERIAL;

unittest(serial_ports)
{
assertTrue(have_serial_ports);
}

#ifdef HAVE_HWSERIAL0

unittest(reading_writing_serial)
{
GodmodeState* state = GODMODE();
state->serialPort[0].dataIn = "";
state->serialPort[0].dataOut = "";
assertEqual(-1, Serial.peek());
assertEqual("", state->serialPort[0].dataIn);
assertEqual("", state->serialPort[0].dataOut);
state->serialPort[0].dataIn = "a";
assertEqual('a', Serial.peek());
assertEqual("a", state->serialPort[0].dataIn);
assertEqual("", state->serialPort[0].dataOut);
assertEqual('a', Serial.read());
assertEqual("", state->serialPort[0].dataIn);
assertEqual("", state->serialPort[0].dataOut);
Serial.write('b');
assertEqual("", state->serialPort[0].dataIn);
assertEqual("b", state->serialPort[0].dataOut);
Serial.print("cdefg");
assertEqual("", state->serialPort[0].dataIn);
assertEqual("bcdefg", state->serialPort[0].dataOut);
}

#endif

unittest_main()
72 changes: 72 additions & 0 deletions SampleProjects/TestSomething/test/good-stream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>

unittest(stream_construction)
{
String data = "";
unsigned long micros = 100;

Stream s;
s.mGodmodeDataIn = &data;
s.mGodmodeMicrosDelay = &micros;

assertEqual(0, s.available());
data = "abcd";
assertEqual(4, s.available());
assertEqual('a', s.peek());
assertEqual('a', s.read());
assertEqual("bcd", s.readString());
assertEqual("", s.readString());

}


unittest(stream_find)
{
String data = "";
unsigned long micros = 100;

Stream s;
s.mGodmodeDataIn = &data;
s.mGodmodeMicrosDelay = &micros;

data = "abcdefghijkl";
assertEqual('a', s.peek());
assertEqual(true, s.find('f'));
assertEqual('f', s.peek());
assertEqual("fghijkl", s.readString());
data = "fghijkl";
assertEqual(false, s.findUntil("k", "j"));
assertEqual('j', s.peek());
}

unittest(stream_parse)
{
String data = "";
unsigned long micros = 100;

Stream s;
s.mGodmodeDataIn = &data;
s.mGodmodeMicrosDelay = &micros;

long l;
float f;
data = "abcdefghijkl-123-456abcd";
l = s.parseInt();
assertEqual(-123, l);
assertEqual('-', data[0]);
l = s.parseInt();
assertEqual(-456, l);
l = s.parseInt();
assertEqual(0, l);

data = "abc123.456-345.322";
f = s.parseFloat();
assertLess(123.456 - f, 0.0001);
assertEqual('-', data[0]);
f = s.parseFloat();
assertLess(-345.322 - f, 0.0001);

}

unittest_main()
Loading