internal async Task InputReportsBehaveAsExpected(
            string testName,
            IHardwareInternalInfos hardware,
            IEnumerable <byte[]> inputReports
            )
        {
            // Arrange
            Verifier.Initialize();

            Verifier
            .UseFileNameAsDirectory()
            .UseFileName(testName);

            using var context = new StreamDeckHidTestContext(hardware);

            var keyLog = new StringBuilder();

            context.Board.KeyStateChanged += (s, e)
                                             => keyLog.Append(e.Key).Append(" - ").AppendLine(e.IsDown ? "DOWN" : "UP");

            // Act
            foreach (var report in inputReports)
            {
                context.Hid.FakeIncommingInputReport(report);
            }

            // Assert
            await Verifier.VerifyAsync(keyLog.ToString());
        }
        internal async Task CallingShowLogoCausesTheExpectedOutput(IHardwareInternalInfos hardware)
        {
            // Arrange
            Verifier.Initialize();

            Verifier
            .UseFileNameAsDirectory()
            .UseFileName(hardware.DeviceName);

            using var context = new StreamDeckHidTestContext(hardware);

            // Act
            context.Board.ShowLogo();

            // Assert
            await Verifier.VerifyAsync(context.Log.ToString());
        }
        internal async Task SettingBrightnessCausesTheExpectedOuput(IHardwareInternalInfos hardware, byte brightness)
        {
            // Arrange
            Verifier.Initialize();

            Verifier
            .UseFileNameAsDirectory()
            .UseFileName(hardware.DeviceName)
            .UseUniqueSuffix($"Value={brightness}");

            using var context = new StreamDeckHidTestContext(hardware);

            // Act
            context.Board.SetBrightness(brightness);

            // Assert
            await Verifier.VerifyAsync(context.Log.ToString());
        }
        internal void GettingFirmwareVersionWorksAsExpected(
            IHardwareInternalInfos hardware,
            byte[] featureData,
            string expectedParsedFirmware
            )
        {
            // Arrange
            using var context = new StreamDeckHidTestContext(hardware);

            context.Hid.ReadFeatureResonseQueue.Enqueue((hardware.FirmwareVersionFeatureId, true, featureData));

            // Act
            context.Board.GetFirmwareVersion().Should().Be(expectedParsedFirmware);

            // Assert
            context.Hid.ReadFeatureResonseQueue.Should().BeEmpty();
            context.Log.ToString().Should().BeEmpty();
        }
        internal async Task BasicBitmapKeyOutputAsExpected(IHardwareInternalInfos hardware)
        {
            // Arrange
            Verifier.Initialize();

            Verifier
            .UseFileNameAsDirectory()
            .UseFileName(hardware.DeviceName)
            ;

            using var context = new StreamDeckHidTestContext(hardware);
            context.Hid.BytesPerLineOutput = 1024;

            var colorEachChannelDifferent = KeyBitmap.Create.FromRgb(0x6A, 0x4A, 0x4F);
            var red  = KeyBitmap.Create.FromRgb(0xFF, 0, 0);
            var blue = KeyBitmap.Create.FromRgb(0, 0, 0xFF);

            // Act
            context.Log.WriteLine("Set all keys to a defined color.");
            context.Board.SetKeyBitmap(colorEachChannelDifferent);

            context.Log.WriteLine("Clear all keys.");
            context.Board.ClearKeys();

            context.Log.WriteLine("Set key 0 to red.");
            context.Board.SetKeyBitmap(0, red);

            context.Log.WriteLine("Clear key 0.");
            context.Board.ClearKey(0);

            context.Log.WriteLine("Set key 0 to blue");
            context.Board.SetKeyBitmap(0, blue);

            context.Log.WriteLine("Set key 0 to KeyBitmap.Black");
            context.Board.SetKeyBitmap(0, KeyBitmap.Black);

            // Assert
            await Verifier.VerifyAsync(context.Log.ToString());
        }
        internal async Task SetBitmapResultsInExpectedOutput8PxTiles(IHardwareInternalInfos hardware)
        {
            // Arrange
            Verifier.Initialize();

            Verifier
            .UseFileNameAsDirectory()
            .UseFileName(hardware.DeviceName)
            ;

            using var context = new StreamDeckHidTestContext(hardware);
            context.Hid.BytesPerLineOutput = 1024;

            // create an image that probably survives JPEG compression
            // by using 8x8 tiles that have the same color and hopefully results in similar JPEGs
            // even when using different JPEG encoders.
            // In a best case scenario I hope this test is resistant against swapping JPEG encoders.

            // we have to create a key bitmap for the exact key size to prevent automatic resizing.

            var keySize = hardware.Keys.KeySize;

            const int tileSize     = 8;
            const int channelCount = 3;

            // make sure the key size is divisible by 8
            (keySize % tileSize).Should().Be(0);

            var tileCnt     = keySize / tileSize;
            var rnd         = new Random(42);
            var colorBuffer = new byte[3];

            (byte R, byte G, byte B) GetNextRndColor()
            {
                rnd.NextBytes(colorBuffer);
                return(colorBuffer[0], colorBuffer[1], colorBuffer[2]);
            }

            var pixelData = new byte[keySize * keySize * channelCount];

            for (int y = 0; y < tileCnt; y++)
            {
                for (int x = 0; x < tileCnt; x++)
                {
                    var(r, g, b) = GetNextRndColor();

                    for (int dy = 0; dy < tileSize; dy++)
                    {
                        for (int dx = 0; dx < tileSize; dx++)
                        {
                            var yOffset = (y * tileSize + dy) * keySize;
                            var xOffset = x * tileSize + dx;
                            var index   = (yOffset + xOffset) * channelCount;

                            pixelData[index]     = b;
                            pixelData[index + 1] = g;
                            pixelData[index + 2] = r;
                        }
                    }
                }
            }

            var colorFullKeyBitmap = KeyBitmap.FromBgr24Array(keySize, keySize, pixelData);

            // Act
            context.Board.SetKeyBitmap(0, colorFullKeyBitmap);

            // Assert
            await Verifier.VerifyAsync(context.Log.ToString());
        }