Skip to content
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

Porting legacy tests to new integration-test infra (part 2...) #2295

Merged
merged 3 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 96 additions & 15 deletions internal/integrationtest/compile_4/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ func TestCompileOfProblematicSketches(t *testing.T) {
_, _, err = cli.Run("lib", "install", "[email protected]")
require.NoError(t, err)

// Install custom hardware required for tests
customHwDir, err := paths.New("testdata", "user_hardware").Abs()
require.NoError(t, err)
require.NoError(t, customHwDir.CopyDirTo(cli.SketchbookDir().Join("hardware")))

integrationtest.CLISubtests{
{"SketchWithInlineFunction", testBuilderSketchWithInlineFunction},
{"SketchWithConst", testBuilderSketchWithConst},
Expand Down Expand Up @@ -97,6 +102,8 @@ func TestCompileOfProblematicSketches(t *testing.T) {
{"SketchWithFunctionPointer", tryBuildAvrLeonardo},
{"USBHostExample", testBuilderUSBHostExample},
{"SketchWithConflictingLibraries", testBuilderSketchWithConflictingLibraries},
{"SketchLibraryProvidesAllIncludes", testBuilderSketchLibraryProvidesAllIncludes},
{"UserHardware", testBuilderWithUserHardware},
}.Run(t, env, cli)
}

Expand Down Expand Up @@ -322,8 +329,12 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
require.True(t, buildPath.Join("BridgeExample.ino.hex").Exist())
require.True(t, buildPath.Join("libraries", "Bridge", "Mailbox.cpp.o").Exist())

libs := out.BuilderResult.UsedLibraries
require.Len(t, libs, 1)
require.Equal(t, "Bridge", libs[0].Name)

// Build again...
out2, err2 := tryBuild(t, env, cli, "arduino:avr:leonardo", "no-clean")
out2, err2 := tryBuild(t, env, cli, "arduino:avr:leonardo", &buildOptions{NoClean: true})
require.NoError(t, err2)
buildPath2 := out2.BuilderResult.BuildPath
require.True(t, buildPath2.Join("core", "HardwareSerial.cpp.o").Exist())
Expand All @@ -335,7 +346,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl

t.Run("BuildForSAM", func(t *testing.T) {
// Build again for SAM...
out, err := tryBuild(t, env, cli, "arduino:sam:arduino_due_x_dbg", "all-warnings")
out, err := tryBuild(t, env, cli, "arduino:sam:arduino_due_x_dbg", &buildOptions{AllWarnings: true})
require.NoError(t, err)

buildPath := out.BuilderResult.BuildPath
Expand All @@ -358,7 +369,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl

t.Run("BuildForRedBearAVR", func(t *testing.T) {
// Build again for RedBearLab...
out, err := tryBuild(t, env, cli, "RedBear:avr:blend", "verbose")
out, err := tryBuild(t, env, cli, "RedBear:avr:blend", &buildOptions{Verbose: true})
require.NoError(t, err)
buildPath := out.BuilderResult.BuildPath
require.True(t, buildPath.Join("core", "HardwareSerial.cpp.o").Exist())
Expand All @@ -377,7 +388,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
require.NoError(t, buildPath.Join("libraries", "SPI").MkdirAll())

// Build again...
_, err = tryBuild(t, env, cli, "arduino:avr:leonardo", "no-clean")
_, err = tryBuild(t, env, cli, "arduino:avr:leonardo", &buildOptions{NoClean: true})
require.NoError(t, err)

require.False(t, buildPath.Join("libraries", "SPI").Exist())
Expand Down Expand Up @@ -548,6 +559,52 @@ func testBuilderSketchWithConflictingLibraries(t *testing.T, env *integrationtes
})
}

func testBuilderSketchLibraryProvidesAllIncludes(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
t.Run("Build", func(t *testing.T) {
// Build
out, err := tryBuild(t, env, cli, "arduino:avr:leonardo")
require.NoError(t, err)
libs := out.BuilderResult.UsedLibraries
slices.SortFunc(libs, func(x, y *builderLibrary) bool { return x.Name < y.Name })
require.Len(t, libs, 2)
require.Equal(t, "ANewLibrary-master", libs[0].Name)
require.Equal(t, "IRremote", libs[1].Name)
})
}

func testBuilderWithUserHardware(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
coreSPILib, err := cli.SketchbookDir().Join("hardware", "my_avr_platform", "avr", "libraries", "SPI").Abs()
require.NoError(t, err)
sketchPath := coreSPILib.Join("examples", "BarometricPressureSensor", "BarometricPressureSensor.ino")

t.Run("TestIncludesToIncludeFoldersDuplicateLibs", func(t *testing.T) {
out, err := tryBuild(t, env, cli, "my_avr_platform:avr:custom_yun", &buildOptions{
Sketch: sketchPath,
NoTestLibraries: true,
})
require.NoError(t, err)

importedLibraries := out.BuilderResult.UsedLibraries
require.Equal(t, 1, len(importedLibraries))
require.Equal(t, "SPI", importedLibraries[0].Name)
require.True(t, importedLibraries[0].SourceDir.EquivalentTo(coreSPILib))
})

t.Run("TestIncludesToIncludeFoldersDuplicateLibsWithConflictingLibsOutsideOfPlatform", func(t *testing.T) {
SPILib, err := paths.New("testdata", "libraries", "SPI").Abs()
require.NoError(t, err)
out, err := tryBuild(t, env, cli, "my_avr_platform:avr:custom_yun", &buildOptions{
Sketch: sketchPath,
})
require.NoError(t, err)

importedLibraries := out.BuilderResult.UsedLibraries
require.Equal(t, 1, len(importedLibraries))
require.Equal(t, "SPI", importedLibraries[0].Name)
require.True(t, importedLibraries[0].SourceDir.EquivalentTo(SPILib))
})
}

func tryBuildAvrLeonardo(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
_, err := tryBuild(t, env, cli, "arduino:avr:leonardo")
require.NoError(t, err)
Expand All @@ -568,25 +625,49 @@ type builderLibrary struct {
SourceDir *paths.Path `json:"source_dir"`
}

func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, options ...string) (*builderOutput, error) {
subTestName := strings.Split(t.Name(), "/")[1]
sketchPath, err := paths.New("testdata", subTestName).Abs()
require.NoError(t, err)
libsPath, err := paths.New("testdata", "libraries").Abs()
require.NoError(t, err)
type buildOptions struct {
Sketch *paths.Path
NoTestLibraries bool
CustomLibPath *paths.Path
NoClean bool
AllWarnings bool
Verbose bool
}

func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, optionsArg ...*buildOptions) (*builderOutput, error) {
var options *buildOptions
if len(optionsArg) == 0 {
options = &buildOptions{}
} else {
require.Len(t, optionsArg, 1)
options = optionsArg[0]
}
if options.Sketch == nil {
subTestName := strings.Split(t.Name(), "/")[1]
sketchPath, err := paths.New("testdata", subTestName).Abs()
require.NoError(t, err)
options.Sketch = sketchPath
}
args := []string{
"compile",
"-b", fqbn,
"--libraries", libsPath.String(),
"--format", "json",
sketchPath.String()}
if !slices.Contains(options, "no-clean") {
options.Sketch.String()}
if !options.NoTestLibraries {
libsPath, err := paths.New("testdata", "libraries").Abs()
require.NoError(t, err)
args = append(args, "--libraries", libsPath.String())
}
if options.CustomLibPath != nil {
args = append(args, "--library", options.CustomLibPath.String())
}
if !options.NoClean {
args = append(args, "--clean")
}
if slices.Contains(options, "all-warnings") {
if options.AllWarnings {
args = append(args, "--warnings", "all")
}
if slices.Contains(options, "verbose") {
if options.Verbose {
args = append(args, "-v")
}
jsonOut, _, err := cli.Run(args...)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <anewlibrary.h>
#include <IRremoteInt.h>
#include <IRremote.h>

void setup() {}
void loop() {}
201 changes: 201 additions & 0 deletions internal/integrationtest/compile_4/testdata/libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* Copyright (c) 2010 by Cristian Maglie <[email protected]>
* Copyright (c) 2014 by Paul Stoffregen <[email protected]> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <[email protected]> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <[email protected]> (atomicity fixes)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/

#include "SPI.h"

SPIClass SPI;

uint8_t SPIClass::initialized = 0;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPIClass::inTransactionFlag = 0;
#endif

void SPIClass::begin()
{
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
if (!initialized) {
// Set SS to high so a connected chip will be "deselected" by default
uint8_t port = digitalPinToPort(SS);
uint8_t bit = digitalPinToBitMask(SS);
volatile uint8_t *reg = portModeRegister(port);

// if the SS pin is not already configured as an output
// then set it high (to enable the internal pull-up resistor)
if(!(*reg & bit)){
digitalWrite(SS, HIGH);
}

// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);

// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);

// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
}
initialized++; // reference count
SREG = sreg;
}

void SPIClass::end() {
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
// Decrease the reference counter
if (initialized)
initialized--;
// If there are no more references disable SPI
if (!initialized) {
SPCR &= ~_BV(SPE);
interruptMode = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
inTransactionFlag = 0;
#endif
}
SREG = sreg;
}

// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif

void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
interruptMode = 2;
break;
}
interruptMask |= mask;
if (!interruptMode)
interruptMode = 1;
SREG = sreg;
}

void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
{
// Once in mode 2 we can't go back to 0 without a proper reference count
if (interruptMode == 2)
return;
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
break;
// this case can't be reached
}
interruptMask &= ~mask;
if (!interruptMask)
interruptMode = 0;
SREG = sreg;
}
Loading
Loading