test parsing config as JSON into a message

this also bumps the proto files in the test directory as a matter of
convenience, so some tests got updated accordingly

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
Brian S. Stephan 2024-01-03 12:19:54 -06:00
parent 23cb5c9e5a
commit f2ed281053
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
10 changed files with 1529 additions and 204 deletions

View File

@ -8,6 +8,7 @@ import binascii
import logging
from google.protobuf.json_format import MessageToJson
from google.protobuf.json_format import Parse as JsonParse
from google.protobuf.message import Message
from gp2040ce_bintools import core_parser, get_config_pb2
@ -61,6 +62,21 @@ def get_config(content: bytes) -> Message:
return config
def get_config_from_json(content: str) -> Message:
"""Read the config represented by a JSON string.
Args:
content: JSON string representing a board config
Returns:
the parsed configuration
"""
config_pb2 = get_config_pb2()
config = config_pb2.Config()
JsonParse(content, config)
logger.debug("parsed: %s", config)
return config
def get_config_footer(content: bytes) -> tuple[int, int, str]:
"""Confirm and retrieve the config footer from a series of bytes of GP2040-CE storage.

View File

@ -20,6 +20,16 @@ def config_binary():
yield content
@pytest.fixture
def config_json():
"""Read in a test GP2040-CE configuration, Protobuf serialized binary form with footer."""
filename = os.path.join(HERE, 'test-files', 'test-config.json')
with open(filename, 'r') as file:
content = file.read()
yield content
@pytest.fixture
def firmware_binary():
"""Read in a test GP2040-CE firmware binary file."""

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,16 @@ message GamepadOptions
optional bool fourWayMode = 8;
optional uint32 profileNumber = 9;
optional PS4ControllerType ps4ControllerType = 10;
optional uint32 debounceDelay = 11;
optional int32 inputModeB1 = 12;
optional int32 inputModeB2 = 13;
optional int32 inputModeB3 = 14;
optional int32 inputModeB4 = 15;
optional int32 inputModeL1 = 16;
optional int32 inputModeL2 = 17;
optional int32 inputModeR1 = 18;
optional int32 inputModeR2 = 19;
optional bool ps4ReportHack = 20;
}
message KeyboardMapping
@ -61,6 +71,41 @@ message HotkeyOptions
optional HotkeyEntry hotkey10 = 10;
optional HotkeyEntry hotkey11 = 11;
optional HotkeyEntry hotkey12 = 12;
optional HotkeyEntry hotkey13 = 13;
optional HotkeyEntry hotkey14 = 14;
optional HotkeyEntry hotkey15 = 15;
optional HotkeyEntry hotkey16 = 16;
}
message PeripheralOptions
{
message I2COptions {
optional bool enabled = 1;
optional int32 sda = 2;
optional int32 scl = 3;
optional uint32 speed = 4;
}
message SPIOptions {
optional bool enabled = 1;
optional int32 rx = 2;
optional int32 cs = 3;
optional int32 sck = 4;
optional int32 tx = 5;
}
message USBOptions {
optional bool enabled = 1;
optional int32 dp = 2;
optional int32 enable5v = 3;
optional uint32 order = 4;
}
optional I2COptions blockI2C0 = 1;
optional I2COptions blockI2C1 = 2;
optional SPIOptions blockSPI0 = 3;
optional SPIOptions blockSPI1 = 4;
optional USBOptions blockUSB0 = 5;
}
message ForcedSetupOptions
@ -117,38 +162,14 @@ message PinMappings
optional int32 pinButtonFn = 19;
}
message GpioMappingInfo
{
optional GpioAction action = 1;
}
message GpioMappings
{
optional GpioAction pin00 = 1;
optional GpioAction pin01 = 2;
optional GpioAction pin02 = 3;
optional GpioAction pin03 = 4;
optional GpioAction pin04 = 5;
optional GpioAction pin05 = 6;
optional GpioAction pin06 = 7;
optional GpioAction pin07 = 8;
optional GpioAction pin08 = 9;
optional GpioAction pin09 = 10;
optional GpioAction pin10 = 11;
optional GpioAction pin11 = 12;
optional GpioAction pin12 = 13;
optional GpioAction pin13 = 14;
optional GpioAction pin14 = 15;
optional GpioAction pin15 = 16;
optional GpioAction pin16 = 17;
optional GpioAction pin17 = 18;
optional GpioAction pin18 = 19;
optional GpioAction pin19 = 20;
optional GpioAction pin20 = 21;
optional GpioAction pin21 = 22;
optional GpioAction pin22 = 23;
optional GpioAction pin23 = 24;
optional GpioAction pin24 = 25;
optional GpioAction pin25 = 26;
optional GpioAction pin26 = 27;
optional GpioAction pin27 = 28;
optional GpioAction pin28 = 29;
optional GpioAction pin29 = 30;
repeated GpioMappingInfo pins = 1 [(nanopb).max_count = 30];
}
@ -171,7 +192,8 @@ message AlternativePinMappings
message ProfileOptions
{
repeated AlternativePinMappings alternativePinMappings = 1 [(nanopb).max_count = 3];
repeated AlternativePinMappings deprecatedAlternativePinMappings = 1 [(nanopb).max_count = 3, deprecated = true];
repeated GpioMappings gpioMappingsSets = 2 [(nanopb).max_count = 3];
}
message DisplayOptions
@ -179,10 +201,10 @@ message DisplayOptions
optional bool enabled = 1;
optional int32 i2cBlock = 2;
optional int32 i2cSDAPin = 3;
optional int32 i2cSCLPin = 4;
optional int32 deprecatedI2cSDAPin = 3 [deprecated = true];
optional int32 deprecatedI2cSCLPin = 4 [deprecated = true];
optional int32 i2cAddress = 5;
optional int32 i2cSpeed = 6;
optional int32 deprecatedI2cSpeed = 6 [deprecated = true];
optional ButtonLayout buttonLayout = 7;
optional ButtonLayoutRight buttonLayoutRight = 8;
@ -237,6 +259,11 @@ message LEDOptions
optional uint32 pledColor = 30;
optional bool turnOffWhenSuspended = 31;
optional int32 pledIndex1 = 32;
optional int32 pledIndex2 = 33;
optional int32 pledIndex3 = 34;
optional int32 pledIndex4 = 35;
};
// This has to be kept in sync with AnimationOptions in AnimationStation.hpp
@ -347,10 +374,10 @@ message SliderOptions
{
optional bool enabled = 1;
optional int32 deprecatedPinSliderOne = 2;
optional int32 deprecatedPinSliderTwo = 3;
optional DpadMode deprecatedModeOne = 4;
optional DpadMode deprecatedModeTwo = 5;
optional int32 deprecatedPinSliderOne = 2 [deprecated = true];
optional int32 deprecatedPinSliderTwo = 3 [deprecated = true];
optional DpadMode deprecatedModeOne = 4 [deprecated = true];
optional DpadMode deprecatedModeTwo = 5 [deprecated = true];
optional DpadMode modeDefault = 6;
}
@ -358,12 +385,12 @@ message SOCDSliderOptions
{
optional bool enabled = 1;
optional int32 deprecatedPinOne = 2;
optional int32 deprecatedPinTwo = 3;
optional int32 deprecatedPinOne = 2 [deprecated = true];
optional int32 deprecatedPinTwo = 3 [deprecated = true];
optional SOCDMode modeDefault = 4;
optional SOCDMode deprecatedModeOne = 5;
optional SOCDMode deprecatedModeTwo = 6;
optional SOCDMode deprecatedModeOne = 5 [deprecated = true];
optional SOCDMode deprecatedModeTwo = 6 [deprecated = true];
}
message ReverseOptions
@ -384,20 +411,20 @@ message AnalogADS1219Options
optional bool enabled = 1;
optional int32 i2cBlock = 2;
optional int32 i2cSDAPin = 3;
optional int32 i2cSCLPin = 4;
optional int32 deprecatedI2cSDAPin = 3 [deprecated = true];
optional int32 deprecatedI2cSCLPin = 4 [deprecated = true];
optional int32 i2cAddress = 5;
optional int32 i2cSpeed = 6;
optional int32 deprecatedI2cSpeed = 6 [deprecated = true];
}
message DualDirectionalOptions
{
optional bool enabled = 1;
optional int32 deprecatedUpPin = 2;
optional int32 deprecatedDownPin = 3;
optional int32 deprecatedLeftPin = 4;
optional int32 deprecatedRightPin = 5;
optional int32 deprecatedUpPin = 2 [deprecated = true];
optional int32 deprecatedDownPin = 3 [deprecated = true];
optional int32 deprecatedLeftPin = 4 [deprecated = true];
optional int32 deprecatedRightPin = 5 [deprecated = true];
optional DpadMode dpadMode = 6;
optional uint32 combineMode = 7;
@ -410,7 +437,7 @@ message TiltOptions
optional int32 tilt1Pin = 2;
optional int32 tilt2Pin = 3;
optional int32 deprecatedTiltFunctionPin = 4;
optional int32 deprecatedTiltFunctionPin = 4 [deprecated = true];
optional int32 tiltLeftAnalogUpPin = 5;
optional int32 tiltLeftAnalogDownPin = 6;
optional int32 tiltLeftAnalogLeftPin = 7;
@ -473,8 +500,13 @@ message PS4Options
message PSPassthroughOptions
{
optional bool enabled = 1;
optional int32 pinDplus = 2;
optional int32 pin5V = 3;
optional int32 deprecatedPinDplus = 2 [deprecated = true];
optional int32 deprecatedPin5V = 3 [deprecated = true];
}
message XBOnePassthroughOptions
{
optional bool enabled = 1;
}
message WiiOptions
@ -589,9 +621,9 @@ message WiiOptions
optional bool enabled = 1;
optional int32 i2cBlock = 2;
optional int32 i2cSDAPin = 3;
optional int32 i2cSCLPin = 4;
optional int32 i2cSpeed = 5;
optional int32 deprecatedI2cSDAPin = 3 [deprecated = true];
optional int32 deprecatedI2cSCLPin = 4 [deprecated = true];
optional int32 deprecatedI2cSpeed = 5 [deprecated = true];
optional ControllerOptions controllers = 6;
}
@ -607,9 +639,9 @@ message SNESOptions
message KeyboardHostOptions
{
optional bool enabled = 1;
optional int32 pinDplus = 2;
optional int32 deprecatedPinDplus = 2 [deprecated = true];
optional KeyboardMapping mapping = 3;
optional int32 pin5V = 4;
optional int32 deprecatedPin5V = 4 [deprecated = true];
}
message FocusModeOptions
@ -652,6 +684,14 @@ message MacroOptions
repeated Macro macroList = 3 [(nanopb).max_count = 6];
}
message InputHistoryOptions
{
optional bool enabled = 1;
optional uint32 length = 2;
optional uint32 col = 3;
optional uint32 row = 4;
}
message AddonOptions
{
optional BootselButtonOptions bootselButtonOptions = 1;
@ -663,7 +703,7 @@ message AddonOptions
optional AnalogADS1219Options analogADS1219Options = 7;
optional DualDirectionalOptions dualDirectionalOptions = 8;
optional BuzzerOptions buzzerOptions = 9;
optional ExtraButtonOptions deprecatedExtraButtonOptions = 10;
optional ExtraButtonOptions deprecatedExtraButtonOptions = 10 [deprecated = true];
optional PlayerNumberOptions playerNumberOptions = 11;
optional PS4Options ps4Options = 12 [(nanopb).disallow_export = true];
optional WiiOptions wiiOptions = 13;
@ -674,12 +714,15 @@ message AddonOptions
optional TiltOptions tiltOptions = 18;
optional PSPassthroughOptions psPassthroughOptions = 19;
optional MacroOptions macroOptions = 20;
optional InputHistoryOptions inputHistoryOptions = 21;
optional XBOnePassthroughOptions xbonePassthroughOptions = 22;
}
message MigrationHistory
{
optional bool hotkeysMigrated = 1 [default = false];
optional bool gpioMappingsMigrated = 2 [default = false];
optional bool buttonProfilesMigrated = 3 [default = false];
}
message Config
@ -688,7 +731,7 @@ message Config
optional GamepadOptions gamepadOptions = 2;
optional HotkeyOptions hotkeyOptions = 3;
optional PinMappings deprecatedPinMappings = 4;
optional PinMappings deprecatedPinMappings = 4 [deprecated = true];
optional KeyboardMapping keyboardMapping = 5;
optional DisplayOptions displayOptions = 6;
optional LEDOptions ledOptions = 7;
@ -700,4 +743,5 @@ message Config
optional string boardConfig = 12 [(nanopb).max_length = 63];
optional GpioMappings gpioMappings = 13;
optional MigrationHistory migrations = 14;
optional PeripheralOptions peripheralOptions = 15;
}

View File

@ -45,7 +45,6 @@ enum ButtonLayoutRight
BUTTON_LAYOUT_CUSTOMB = 16;
BUTTON_LAYOUT_KEYBOARD8B = 17;
BUTTON_LAYOUT_OPENCORE0WASDB = 18;
BUTTON_LAYOUT_BSS = 99;
}
enum SplashMode
@ -89,6 +88,14 @@ enum InputMode
INPUT_MODE_HID = 2;
INPUT_MODE_KEYBOARD = 3;
INPUT_MODE_PS4 = 4;
INPUT_MODE_XBONE = 5;
INPUT_MODE_MDMINI = 6;
INPUT_MODE_NEOGEO = 7;
INPUT_MODE_PCEMINI = 8;
INPUT_MODE_EGRET = 9;
INPUT_MODE_ASTRO = 10;
INPUT_MODE_PSCLASSIC = 11;
INPUT_MODE_XBOXORIGINAL = 12;
INPUT_MODE_CONFIG = 255;
}
@ -191,6 +198,18 @@ enum GamepadHotkey
HOTKEY_R3_BUTTON = 20;
HOTKEY_TOUCHPAD_BUTTON = 21;
HOTKEY_REBOOT_DEFAULT = 22;
HOTKEY_B1_BUTTON = 23;
HOTKEY_B2_BUTTON = 24;
HOTKEY_B3_BUTTON = 25;
HOTKEY_B4_BUTTON = 26;
HOTKEY_L1_BUTTON = 27;
HOTKEY_R1_BUTTON = 28;
HOTKEY_L2_BUTTON = 29;
HOTKEY_R2_BUTTON = 30;
HOTKEY_S1_BUTTON = 31;
HOTKEY_S2_BUTTON = 32;
HOTKEY_A1_BUTTON = 33;
HOTKEY_A2_BUTTON = 34;
}
// This has to be kept in sync with LEDFormat in NeoPico.hpp
@ -244,4 +263,4 @@ enum MacroType
ON_PRESS = 1;
ON_HOLD_REPEAT = 2;
ON_TOGGLE = 3;
};
};

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@ def with_pb2s(test, *args, **kwargs):
def test_concatenate_to_file(tmp_path):
"""Test that we write a file as expected."""
"""Test that we write a file with firmware + binary user config as expected."""
tmp_file = os.path.join(tmp_path, 'concat.bin')
firmware_file = os.path.join(HERE, 'test-files', 'test-firmware.bin')
config_file = os.path.join(HERE, 'test-files', 'test-config.bin')

View File

@ -94,7 +94,7 @@ async def test_simple_toggle():
async with app.run_test() as pilot:
tree = pilot.app.query_one(Tree)
display_node = tree.root.children[5]
invert_node = display_node.children[11]
invert_node = display_node.children[10]
assert 'False' in invert_node.label
app._modify_node(invert_node)
@ -109,8 +109,8 @@ async def test_simple_edit_via_input_field():
async with app.run_test() as pilot:
tree = pilot.app.query_one(Tree)
display_node = tree.root.children[5]
i2cspeed_node = display_node.children[10]
assert pilot.app.config.displayOptions.i2cSpeed == 400000
i2cspeed_node = display_node.children[4]
assert pilot.app.config.displayOptions.deprecatedI2cSpeed == 400000
tree.root.expand_all()
await pilot.wait_for_scheduled_animations()
@ -122,7 +122,7 @@ async def test_simple_edit_via_input_field():
await pilot.press('backspace', 'backspace', 'backspace', 'backspace', 'backspace', 'backspace', '5')
await pilot.wait_for_scheduled_animations()
await pilot.click('Button#save-button')
assert pilot.app.config.displayOptions.i2cSpeed == 5
assert pilot.app.config.displayOptions.deprecatedI2cSpeed == 5
@pytest.mark.asyncio
@ -198,7 +198,7 @@ async def test_add_node_to_repeated():
await pilot.wait_for_scheduled_animations()
await pilot.click('Button#save-button')
assert pilot.app.config.profileOptions.alternativePinMappings[0].pinButtonB4 == 5
assert pilot.app.config.profileOptions.deprecatedAlternativePinMappings[0].pinButtonB4 == 5
@pytest.mark.asyncio

View File

@ -129,12 +129,16 @@ def test_config_from_whole_board_parses(whole_board_dump):
@with_pb2s
def test_serialize_config_with_footer(storage_dump, config_binary):
"""Test that reserializing a read in config matches the original."""
"""Test that reserializing a read in config matches the original.
Note that this isn't going to produce an *identical* result, because new message fields
may have default values that get saved in the reserialized binary, so we can still only test
some particular parts. But it should work.
"""
config = storage.get_config(storage_dump)
assert config.boardVersion == 'v0.7.5'
reserialized = storage.serialize_config_with_footer(config)
assert config_binary == reserialized
assert storage_dump[-12:] == reserialized[-12:]
assert storage_dump[-4:] == reserialized[-4:]
@with_pb2s
@ -176,3 +180,10 @@ def test_get_config_from_usb(config_binary):
mock_get.assert_called_once()
mock_read.assert_called_with(mock_out, mock_in, 0x101FC000, 16384)
assert config == storage.get_config(config_binary)
@with_pb2s
def test_json_config_parses(config_json):
"""Test that we can import a JSON config into a message."""
config = storage.get_config_from_json(config_json)
assert config.boardVersion == 'v0.7.6-15-g71f4512'