scripts: tests: genpinctrl: add initial tests

Add some tests for genpinctrl script to make sure parsed and generated
data are correct.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
This commit is contained in:
Gerard Marull-Paretas 2020-09-04 18:44:35 +02:00 committed by Kumar Gala
parent bd2e89c49b
commit 8eb3d3fd0b
13 changed files with 470 additions and 0 deletions

8
scripts/.coveragerc Normal file
View File

@ -0,0 +1,8 @@
[run]
omit =
*/tests/*
[report]
exclude_lines =
pragma: no cover
if __name__ == .__main__.:

View File

@ -0,0 +1,2 @@
pytest~=6.0
pytest-cov~=2.10

21
scripts/tests/README.md Normal file
View File

@ -0,0 +1,21 @@
# stm32_hal scripts tests
This folder contains `stm32_hal` scripts tests.
# Dependencies
You can install testing dependencies by running:
```
pip install -r scripts/requirements-test.txt
```
Note that only Python 3 is supported.
# Running
You can launch tests by running:
```
pytest
```

View File

@ -0,0 +1,20 @@
import os
import sys
import pytest
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(_SCRIPT_DIR, "..", "..", "genpinctrl"))
@pytest.fixture()
def data():
"""Pytest fixture to load test data files"""
return os.path.join(_SCRIPT_DIR, "data")
@pytest.fixture()
def cubemx(data):
"""Pytest fixture to load test CubeMX files"""
return os.path.join(data, "cubemx")

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<IP xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<GPIO_Pin PortName="PA" Name="PA0">
<!-- Signal without "SpecificParameter" entry -->
<PinSignal Name="TEST_SIGNAL_INVALID1">
</PinSignal>
<!-- Signal without "PossibleValue" entry -->
<PinSignal Name="TEST_SIGNAL_INVALID2">
<SpecificParameter Name="GPIO_AF">
</SpecificParameter>
</PinSignal>
<!-- Signal with invalid "PossibleValue" value -->
<PinSignal Name="TEST_SIGNAL_INVALID3">
<SpecificParameter Name="GPIO_AF">
<PossibleValue>WRONG_AF</PossibleValue>
</SpecificParameter>
</PinSignal>
<!-- Valid signal -->
<PinSignal Name="UART1_TX">
<SpecificParameter Name="GPIO_AF">
<PossibleValue>GPIO_AF0_TEST</PossibleValue>
</SpecificParameter>
</PinSignal>
<!-- Valid signal -->
<PinSignal Name="UART1_RX">
<SpecificParameter Name="GPIO_AF">
<PossibleValue>GPIO_AF1_TEST</PossibleValue>
</SpecificParameter>
</PinSignal>
</GPIO_Pin>
</IP>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<IP xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<GPIO_Pin PortName="PA" Name="PA0">
<!-- Invalid signal (no remaps) -->
<PinSignal Name="TEST_SIGNAL_INVALID1">
</PinSignal>
<!-- Invalid signal (invalid remap name) -->
<PinSignal Name="TEST_SIGNAL_INVALID2">
<RemapBlock Name="INVALID_REMAP_NAME" DefaultRemap="true" />
</PinSignal>
<!-- Valid signal (multiple remaps) -->
<PinSignal Name="UART1_TX">
<RemapBlock Name="UART1_REMAP0" DefaultRemap="true" />
<RemapBlock Name="UART1_REMAP1">
</RemapBlock>
</PinSignal>
<!-- Valid signal (single remap) -->
<PinSignal Name="UART1_RX">
<RemapBlock Name="UART1_REMAP1">
</RemapBlock>
</PinSignal>
</GPIO_Pin>
</IP>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Mcu Family="STM32F0" RefName="STM32F0TESTDIE" xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<IP Name="GPIO" Version="STM32F0TESTIP"/>
<!-- Non I/O pin -->
<Pin Name="PZ0" Type="Power">
</Pin>
<!-- Pin with wrong name -->
<Pin Name="WRONG_NAME" Type="I/O">
</Pin>
<!-- Valid pin (not in IP) -->
<Pin Name="PA1" Type="I/O">
</Pin>
<!-- Valid pin -->
<Pin Name="PA0" Type="I/O">
<!-- Signal with GPIO name -->
<Signal Name="GPIO"/>
<!-- Signal without a name -->
<Signal/>
<!-- Valid signal -->
<Signal Name="UART1_TX"/>
<!-- Valid signal -->
<Signal Name="UART1_RX"/>
<!-- Valid signal (analog) -->
<Signal Name="ADC1_IN0"/>
</Pin>
</Mcu>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Mcu Family="STM32F0" RefName="STM32F0TESTDIE2" xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<!-- Non existing IP -->
<IP Name="GPIO" Version="NON_EXISTING_IP"/>
</Mcu>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Mcu Family="TEST_FAMILY" RefName="STM32F0TESTDIE1" xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<!-- File without GPIO IP entry -->
<IP Name="X" Version="Y"/>
</Mcu>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Mcu Family="STM32F1" RefName="STM32F1TESTDIE" xmlns="http://mcd.rou.st.com/modules.php?name=mcu">
<IP Name="GPIO" Version="STM32F1TESTIP"/>
<!-- Valid pin -->
<Pin Name="PA0" Type="I/O">
<!-- Valid signal -->
<Signal Name="UART1_TX"/>
<!-- Valid signal -->
<Signal Name="UART1_RX"/>
<!-- Valid signal (analog) -->
<Signal Name="ADC1_IN0"/>
</Pin>
</Mcu>

View File

@ -0,0 +1,34 @@
/*
* NOTE: Autogenerated file using genpinctrl.py
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <dt-bindings/pinctrl/stm32-pinctrl.h>
/ {
soc {
pinctrl: pin-controller@48000000 {
/* ADC_IN / ADC_INN / ADC_INP */
adc1_in0_pa0: adc1_in0_pa0 {
pinmux = <STM32_PINMUX('A', 0, ANALOG)>;
};
/* UART_RX / USART_RX / LPUART_RX */
uart1_rx_pa0: uart1_rx_pa0 {
pinmux = <STM32_PINMUX('A', 0, AF1)>;
};
/* UART_TX / USART_TX / LPUART_TX */
uart1_tx_pa0: uart1_tx_pa0 {
pinmux = <STM32_PINMUX('A', 0, AF0)>;
bias-pull-up;
};
};
};
};

View File

@ -0,0 +1,33 @@
/*
* NOTE: Autogenerated file using genpinctrl.py
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <dt-bindings/pinctrl/stm32f1-pinctrl.h>
/ {
soc {
pinctrl: pin-controller@40010800 {
/* ADC_IN */
adc1_in0_pa0: adc1_in0_pa0 {
pinmux = <STM32F1_PINMUX('A', 0, ANALOG, NO_REMAP)>;
};
/* UART_RX / USART_RX */
uart1_rx_pa0: uart1_rx_pa0 {
pinmux = <STM32F1_PINMUX('A', 0, GPIO_IN, REMAP_1)>;
};
/* UART_TX / USART_TX */
uart1_tx_pa0: uart1_tx_pa0 {
pinmux = <STM32F1_PINMUX('A', 0, ALTERNATE, NO_REMAP)>;
};
};
};
};

View File

@ -0,0 +1,249 @@
import os
import pytest
from genpinctrl import (
validate_config_entry,
format_mode,
format_mode_f1,
format_remap,
get_gpio_ip_afs,
get_mcu_signals,
main,
)
def test_validate_config_entry():
"""Check that config entries are validated correctly"""
# no name
entry = {}
with pytest.raises(ValueError):
validate_config_entry(entry, "")
# no match
entry = {"name": "TEST"}
with pytest.raises(ValueError):
validate_config_entry(entry, "")
# no mode
entry = {"name": "TEST", "match": "TEST"}
with pytest.raises(ValueError):
validate_config_entry(entry, "")
# invalid mode
entry = {"name": "TEST", "match": "TEST"}
entry["mode"] = "INVALID"
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F0")
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F1")
# valid modes
entry = {"name": "TEST", "match": "TEST"}
entry["mode"] = "analog"
validate_config_entry(entry, "STM32F0")
validate_config_entry(entry, "STM32F1")
entry["mode"] = "alternate"
validate_config_entry(entry, "STM32F0")
validate_config_entry(entry, "STM32F1")
entry["mode"] = "input"
validate_config_entry(entry, "STM32F1")
# invalid bias
entry = {"name": "TEST", "match": "TEST", "mode": "alternate"}
entry["bias"] = "INVALID"
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F0")
entry["bias"] = "pull-up"
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F1")
# valid bias
entry = {"name": "TEST", "match": "TEST"}
entry["bias"] = "disable"
entry["mode"] = "alternate"
validate_config_entry(entry, "STM32F0")
validate_config_entry(entry, "STM32F1")
entry["mode"] = "input"
validate_config_entry(entry, "STM32F1")
entry["bias"] = "pull-up"
entry["mode"] = "alternate"
validate_config_entry(entry, "STM32F0")
entry["mode"] = "input"
validate_config_entry(entry, "STM32F1")
entry["bias"] = "pull-down"
entry["mode"] = "alternate"
validate_config_entry(entry, "STM32F0")
entry["mode"] = "input"
validate_config_entry(entry, "STM32F1")
# invalid drive
entry = {"name": "TEST", "match": "TEST", "mode": "alternate"}
entry["drive"] = "INVALID"
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F0")
# valid drive
entry = {"name": "TEST", "match": "TEST", "mode": "alternate"}
entry["drive"] = "push-pull"
validate_config_entry(entry, "STM32F0")
entry["bias"] = "open-drain"
# invalid slew-rate
entry = {"name": "TEST", "match": "TEST", "mode": "alternate"}
entry["slew-rate"] = "INVALID"
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F0")
with pytest.raises(ValueError):
validate_config_entry(entry, "STM32F1")
# valid slew-rate
entry = {"name": "TEST", "match": "TEST", "mode": "alternate"}
entry["slew-rate"] = "low-speed"
validate_config_entry(entry, "STM32F0")
entry["slew-rate"] = "medium-speed"
validate_config_entry(entry, "STM32F0")
entry["slew-rate"] = "high-speed"
validate_config_entry(entry, "STM32F0")
entry["slew-rate"] = "very-high-speed"
validate_config_entry(entry, "STM32F0")
entry["slew-rate"] = "max-speed-10mhz"
validate_config_entry(entry, "STM32F1")
entry["slew-rate"] = "max-speed-2mhz"
validate_config_entry(entry, "STM32F1")
entry["slew-rate"] = "max-speed-50mhz"
validate_config_entry(entry, "STM32F1")
def test_format_mode():
"""Test that format_mode works."""
assert format_mode("analog", None) == "ANALOG"
assert format_mode("alternate", 0) == "AF0"
with pytest.raises(ValueError):
format_mode("INVALID", 0)
def test_format_mode_f1():
"""Test that format_mode_f1 works."""
assert format_mode_f1("analog") == "ANALOG"
assert format_mode_f1("input") == "GPIO_IN"
assert format_mode_f1("alternate") == "ALTERNATE"
with pytest.raises(ValueError):
format_mode_f1("INVALID")
def test_format_remap():
"""Test that format_remap works."""
assert format_remap(None) == "NO_REMAP"
assert format_remap(0) == "NO_REMAP"
assert format_remap(1) == "REMAP_1"
assert format_remap(2) == "REMAP_2"
assert format_remap(3) == "FULL_REMAP"
with pytest.raises(ValueError):
format_remap(5)
def test_get_gpio_ip_afs(cubemx):
"""Test that IP AF files part of test CubeMX files are parsed correctly."""
afs = get_gpio_ip_afs(cubemx)
assert afs == {
"STM32F0TESTIP": {
"PA0": {
"UART1_TX": 0,
"UART1_RX": 1,
}
},
"STM32F1TESTIP": {
"PA0": {
"UART1_TX": 0,
"UART1_RX": 1,
}
},
}
def test_get_mcu_signals(cubemx):
"""Test that MCU files part of test CubeMX are parsed correctly."""
afs = get_gpio_ip_afs(cubemx)
signals = get_mcu_signals(cubemx, afs)
assert signals == {
"STM32F0": [
{
"name": "STM32F0TESTDIE",
"pins": [
{
"port": "a",
"pin": 0,
"signals": [
{"name": "UART1_TX", "af": 0},
{"name": "UART1_RX", "af": 1},
{"name": "ADC1_IN0", "af": None},
],
},
],
},
],
"STM32F1": [
{
"name": "STM32F1TESTDIE",
"pins": [
{
"port": "a",
"pin": 0,
"signals": [
{"name": "UART1_TX", "af": 0},
{"name": "UART1_RX", "af": 1},
{"name": "ADC1_IN0", "af": None},
],
},
],
},
],
}
def test_cubemx_missing():
"""Test that missing CubeMX folders is handled correctly by parsing functions."""
with pytest.raises(FileNotFoundError):
get_gpio_ip_afs("MISSING_PATH")
with pytest.raises(FileNotFoundError):
get_mcu_signals("MISSING_PATH", dict())
def test_main(data, cubemx, tmp_path):
"""Test that DTS files are generated correctly."""
main(cubemx, tmp_path)
# check f0 file
ref_pinctrl_file = os.path.join(data, "stm32f0testdie-pinctrl.dtsi")
gen_pinctrl_file = os.path.join(tmp_path, "f0", "stm32f0testdie-pinctrl.dtsi")
assert os.path.exists(gen_pinctrl_file)
with open(ref_pinctrl_file) as ref, open(gen_pinctrl_file) as gen:
assert ref.read() == gen.read()
# check f1 file
ref_pinctrl_file = os.path.join(data, "stm32f1testdie-pinctrl.dtsi")
gen_pinctrl_file = os.path.join(tmp_path, "f1", "stm32f1testdie-pinctrl.dtsi")
assert os.path.exists(gen_pinctrl_file)
with open(ref_pinctrl_file) as ref, open(gen_pinctrl_file) as gen:
assert ref.read() == gen.read()