From e00dbb07e7835fbedc1979ec80b2a17d21cb2017 Mon Sep 17 00:00:00 2001 From: j4587698 Date: Sat, 28 Feb 2026 01:20:55 +0000 Subject: [PATCH 1/2] fix: Serialize ConsoleSize as JSON array [height, width] for Docker API compatibility --- src/Docker.DotNet/ConsoleSizeConverter.cs | 51 +++++++++++++++++++ .../Models/ConsoleSize.Generated.cs | 1 + 2 files changed, 52 insertions(+) create mode 100644 src/Docker.DotNet/ConsoleSizeConverter.cs diff --git a/src/Docker.DotNet/ConsoleSizeConverter.cs b/src/Docker.DotNet/ConsoleSizeConverter.cs new file mode 100644 index 00000000..8d257789 --- /dev/null +++ b/src/Docker.DotNet/ConsoleSizeConverter.cs @@ -0,0 +1,51 @@ +using Docker.DotNet.Models; + +namespace Docker.DotNet; + +/// +/// Serializes as a JSON array [height, width] to match +/// the Docker Engine API's Go type [2]uint. +/// +internal class ConsoleSizeConverter : JsonConverter +{ + public override ConsoleSize Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType != JsonTokenType.StartArray) + { + throw new JsonException("Expected a JSON array for ConsoleSize."); + } + + reader.Read(); + var height = reader.GetUInt64(); + + reader.Read(); + var width = reader.GetUInt64(); + + reader.Read(); // EndArray + + return new ConsoleSize + { + Height = height, + Width = width + }; + } + + public override void Write(Utf8JsonWriter writer, ConsoleSize value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + writer.WriteStartArray(); + writer.WriteNumberValue(value.Height); + writer.WriteNumberValue(value.Width); + writer.WriteEndArray(); + } +} diff --git a/src/Docker.DotNet/Models/ConsoleSize.Generated.cs b/src/Docker.DotNet/Models/ConsoleSize.Generated.cs index bfffea9c..b79d8d62 100644 --- a/src/Docker.DotNet/Models/ConsoleSize.Generated.cs +++ b/src/Docker.DotNet/Models/ConsoleSize.Generated.cs @@ -1,5 +1,6 @@ namespace Docker.DotNet.Models { + [JsonConverter(typeof(ConsoleSizeConverter))] public class ConsoleSize // (client.ConsoleSize) { [JsonPropertyName("Height")] From eb22fd346120e0bf6b30ac23db1ed16dcbc6bdb1 Mon Sep 17 00:00:00 2001 From: j4587698 Date: Sat, 28 Feb 2026 01:26:45 +0000 Subject: [PATCH 2/2] test: Add ConsoleSizeConverter unit tests --- .../ConsoleSizeConverterTests.cs | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 test/Docker.DotNet.Tests/ConsoleSizeConverterTests.cs diff --git a/test/Docker.DotNet.Tests/ConsoleSizeConverterTests.cs b/test/Docker.DotNet.Tests/ConsoleSizeConverterTests.cs new file mode 100644 index 00000000..d75a0832 --- /dev/null +++ b/test/Docker.DotNet.Tests/ConsoleSizeConverterTests.cs @@ -0,0 +1,147 @@ +namespace Docker.DotNet.Tests; + +public sealed class ConsoleSizeConverterTests +{ + [Fact] + public void Serialize_ConsoleSize_ProducesJsonArray() + { + // Given + var consoleSize = new ConsoleSize { Height = 24, Width = 80 }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(consoleSize); + + // Then + Assert.Equal("[24,80]", jsonString); + } + + [Fact] + public void Deserialize_JsonArray_ProducesConsoleSize() + { + // Given + var json = "[24,80]"; + + // When + var consoleSize = JsonSerializer.Instance.Deserialize(Encoding.UTF8.GetBytes(json)); + + // Then + Assert.NotNull(consoleSize); + Assert.Equal(24UL, consoleSize.Height); + Assert.Equal(80UL, consoleSize.Width); + } + + [Fact] + public void SerializeAndDeserialize_RoundTrip_Succeeds() + { + // Given + var original = new ConsoleSize { Height = 50, Width = 200 }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(original); + var deserialized = JsonSerializer.Instance.Deserialize(Encoding.UTF8.GetBytes(jsonString)); + + // Then + Assert.NotNull(deserialized); + Assert.Equal(original.Height, deserialized.Height); + Assert.Equal(original.Width, deserialized.Width); + } + + [Fact] + public void Serialize_ContainerExecCreateParameters_WithConsoleSize_ProducesArrayFormat() + { + // Given + var parameters = new ContainerExecCreateParameters + { + ConsoleSize = new ConsoleSize { Height = 24, Width = 80 }, + AttachStdin = true, + AttachStdout = true, + TTY = true, + Cmd = new List { "/bin/bash" } + }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(parameters); + + // Then - ConsoleSize should be serialized as [24,80], not {"Height":24,"Width":80} + Assert.Contains("\"ConsoleSize\":[24,80]", jsonString); + Assert.DoesNotContain("\"Height\"", jsonString); + Assert.DoesNotContain("\"Width\"", jsonString); + } + + [Fact] + public void Serialize_ContainerExecCreateParameters_WithoutConsoleSize_OmitsField() + { + // Given + var parameters = new ContainerExecCreateParameters + { + AttachStdin = true, + AttachStdout = true, + TTY = true, + Cmd = new List { "/bin/bash" } + }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(parameters); + + // Then + Assert.DoesNotContain("ConsoleSize", jsonString); + } + + [Fact] + public void Serialize_ContainerExecStartParameters_WithConsoleSize_ProducesArrayFormat() + { + // Given + var parameters = new ContainerExecStartParameters + { + ConsoleSize = new ConsoleSize { Height = 30, Width = 120 } + }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(parameters); + + // Then + Assert.Contains("\"ConsoleSize\":[30,120]", jsonString); + } + + [Fact] + public void Deserialize_ContainerExecCreateParameters_WithArrayConsoleSize_Succeeds() + { + // Given - This is the format Docker API would return + var json = "{\"ConsoleSize\":[24,80],\"AttachStdin\":true,\"Tty\":true,\"Cmd\":[\"/bin/bash\"]}"; + + // When + var parameters = JsonSerializer.Instance.Deserialize(Encoding.UTF8.GetBytes(json)); + + // Then + Assert.NotNull(parameters); + Assert.NotNull(parameters.ConsoleSize); + Assert.Equal(24UL, parameters.ConsoleSize.Height); + Assert.Equal(80UL, parameters.ConsoleSize.Width); + } + + [Fact] + public void Serialize_LargeConsoleSize_HandlesCorrectly() + { + // Given - Test with larger values that still fit in ulong + var consoleSize = new ConsoleSize { Height = 1000, Width = 2000 }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(consoleSize); + + // Then + Assert.Equal("[1000,2000]", jsonString); + } + + [Fact] + public void Serialize_ZeroConsoleSize_HandlesCorrectly() + { + // Given + var consoleSize = new ConsoleSize { Height = 0, Width = 0 }; + + // When + var jsonString = JsonSerializer.Instance.Serialize(consoleSize); + + // Then + Assert.Equal("[0,0]", jsonString); + } +}