From a412b75b4ae2385a00375d6499ca6d6af4bc61dd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 04:09:43 +0000 Subject: [PATCH 1/3] Initial plan From 1236cbbe927172a30640187b7a33fe395a71c5f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 04:23:34 +0000 Subject: [PATCH 2/3] Initial plan for missing Spector scenario tests Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- packages/http-client-csharp/global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-csharp/global.json b/packages/http-client-csharp/global.json index 311edc2181a..7be862f576b 100644 --- a/packages/http-client-csharp/global.json +++ b/packages/http-client-csharp/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.103", + "version": "10.0.102", "rollForward": "feature" } } From c152f5e97c49bf14f1692785593fd89ea1cef00f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 04:40:51 +0000 Subject: [PATCH 3/3] Add missing Spector scenario tests for C# emitter Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../Http/Payload/Multipart/MultipartTests.cs | 78 ++++++++ .../Http/Payload/Xml/XmlTests.cs | 10 + .../Http/Routes/PathParameterTests.cs | 180 ++++++++++++++++++ .../Spector.Tests/Http/Routes/QueryTests.cs | 33 ++++ .../SpecialWords/SpecialWordsTests.Models.cs | 18 ++ .../AdditionalPropertiesTests.cs | 39 ++++ packages/http-client-csharp/global.json | 2 +- 7 files changed, 359 insertions(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Multipart/MultipartTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Multipart/MultipartTests.cs index d33df56219e..fe73b9a220f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Multipart/MultipartTests.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Multipart/MultipartTests.cs @@ -227,5 +227,83 @@ private Task MultiBinaryParts(bool hasPicture) => Test(async (host) => .MultiBinaryPartsAsync(content, content.ContentType, null); Assert.AreEqual(204, response.GetRawResponse().Status); }); + + [SpectorTest] + public Task WithWireName() => Test(async (host) => + { + using MultiPartFormDataBinaryContent content = new MultiPartFormDataBinaryContent(); + content.Add("123", "id"); + await using var imageStream = File.OpenRead(SampleJpgPath); + content.Add(imageStream, "profileImage", "profileImage", "application/octet-stream"); + + var response = await new MultiPartClient(host, null).GetFormDataClient() + .WithWireNameAsync(content, content.ContentType, null); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task OptionalParts() => Test(async (host) => + { + var client = new MultiPartClient(host, null).GetFormDataClient(); + + using MultiPartFormDataBinaryContent contentIdOnly = new MultiPartFormDataBinaryContent(); + contentIdOnly.Add("123", "id"); + var response1 = await client.OptionalPartsAsync(contentIdOnly, contentIdOnly.ContentType, null); + Assert.AreEqual(204, response1.GetRawResponse().Status); + + await using var imageStream1 = File.OpenRead(SampleJpgPath); + using MultiPartFormDataBinaryContent contentImageOnly = new MultiPartFormDataBinaryContent(); + contentImageOnly.Add(imageStream1, "profileImage", "profileImage", "application/octet-stream"); + var response2 = await client.OptionalPartsAsync(contentImageOnly, contentImageOnly.ContentType, null); + Assert.AreEqual(204, response2.GetRawResponse().Status); + + await using var imageStream2 = File.OpenRead(SampleJpgPath); + using MultiPartFormDataBinaryContent contentBoth = new MultiPartFormDataBinaryContent(); + contentBoth.Add("123", "id"); + contentBoth.Add(imageStream2, "profileImage", "profileImage", "application/octet-stream"); + var response3 = await client.OptionalPartsAsync(contentBoth, contentBoth.ContentType, null); + Assert.AreEqual(204, response3.GetRawResponse().Status); + }); + + [SpectorTest] + public Task FileUploadFileSpecificContentType() => Test(async (host) => + { + using MultiPartFormDataBinaryContent content = new MultiPartFormDataBinaryContent(); + await using var imageStream = File.OpenRead(SamplePngPath); + content.Add(imageStream, "file", "image.png", "image/png"); + + var response = await new MultiPartClient(host, null).GetFormDataClient() + .GetFormDataFileClient() + .UploadFileSpecificContentTypeAsync(content, content.ContentType, null); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task FileUploadFileRequiredFilename() => Test(async (host) => + { + using MultiPartFormDataBinaryContent content = new MultiPartFormDataBinaryContent(); + await using var imageStream = File.OpenRead(SamplePngPath); + content.Add(imageStream, "file", "image.png", "image/png"); + + var response = await new MultiPartClient(host, null).GetFormDataClient() + .GetFormDataFileClient() + .UploadFileRequiredFilenameAsync(content, content.ContentType, null); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task FileUploadFileArray() => Test(async (host) => + { + using MultiPartFormDataBinaryContent content = new MultiPartFormDataBinaryContent(); + await using var imageStream1 = File.OpenRead(SamplePngPath); + content.Add(imageStream1, "files", "image1.png", "image/png"); + await using var imageStream2 = File.OpenRead(SamplePngPath); + content.Add(imageStream2, "files", "image2.png", "image/png"); + + var response = await new MultiPartClient(host, null).GetFormDataClient() + .GetFormDataFileClient() + .UploadFileArrayAsync(content, content.ContentType, null); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Xml/XmlTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Xml/XmlTests.cs index 681e3122024..7d013a8d3a1 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Xml/XmlTests.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Payload/Xml/XmlTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.ClientModel; using System.Collections.Generic; using System.Threading.Tasks; using NUnit.Framework; @@ -352,5 +353,14 @@ public Task PutModelWithEncodedNames() => Test(async (host) => Assert.AreEqual(204, response.GetRawResponse().Status); }); + + [SpectorTest] + public Task GetXmlErrorValue() => Test((host) => + { + var exception = Assert.ThrowsAsync( + async () => await new XmlClient(host, null).GetXmlErrorValueClient().GetAsync()); + Assert.AreEqual(400, exception!.Status); + return Task.CompletedTask; + }); } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/PathParameterTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/PathParameterTests.cs index bd851f94bed..329784a8603 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/PathParameterTests.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/PathParameterTests.cs @@ -135,5 +135,185 @@ public Task LabelExpansionRecord() => Test(async (host) => .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); Assert.AreEqual(204, response.GetRawResponse().Status); }); + + [SpectorTest] + public Task SimpleExpansionPrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionStandardClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task SimpleExpansionArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionStandardClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task SimpleExpansionRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionStandardClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task SimpleExpansionExplodePrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionExplodeClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task SimpleExpansionExplodeArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionExplodeClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task SimpleExpansionExplodeRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersSimpleExpansionClient() + .GetPathParametersSimpleExpansionExplodeClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionPrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionStandardClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionStandardClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionStandardClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionExplodePrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionExplodeClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionExplodeArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionExplodeClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task PathExpansionExplodeRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersPathExpansionClient() + .GetPathParametersPathExpansionExplodeClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionPrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionStandardClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionStandardClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionStandardClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionExplodePrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionExplodeClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionExplodeArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionExplodeClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task MatrixExpansionExplodeRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetPathParametersClient() + .GetPathParametersMatrixExpansionClient() + .GetPathParametersMatrixExpansionExplodeClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/QueryTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/QueryTests.cs index 52f201fea31..36383e6c87b 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/QueryTests.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Routes/QueryTests.cs @@ -123,5 +123,38 @@ public Task QueryContinuationRecord() => Test(async (host) => .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); Assert.AreEqual(204, response.GetRawResponse().Status); }); + + [SpectorTest] + [Ignore("https://github.com/microsoft/typespec/issues/5139")] + public Task QueryContinuationExplodePrimitive() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetQueryParametersClient() + .GetQueryParametersQueryContinuationClient() + .GetQueryParametersQueryContinuationExplodeClient() + .PrimitiveAsync("a"); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + [Ignore("https://github.com/microsoft/typespec/issues/5139")] + public Task QueryContinuationExplodeArray() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetQueryParametersClient() + .GetQueryParametersQueryContinuationClient() + .GetQueryParametersQueryContinuationExplodeClient() + .ArrayAsync(["a", "b"]); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + [Ignore("https://github.com/microsoft/typespec/issues/5139")] + public Task QueryContinuationExplodeRecord() => Test(async (host) => + { + var response = await new RoutesClient(host, null).GetQueryParametersClient() + .GetQueryParametersQueryContinuationClient() + .GetQueryParametersQueryContinuationExplodeClient() + .RecordAsync(new Dictionary {{"a", 1}, {"b", 2}}); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/SpecialWords/SpecialWordsTests.Models.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/SpecialWords/SpecialWordsTests.Models.cs index f6623d5bfc7..1027d52e8ee 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/SpecialWords/SpecialWordsTests.Models.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/SpecialWords/SpecialWordsTests.Models.cs @@ -285,5 +285,23 @@ public Task ModelProperties_SameAsModelAsync() => Test(async (host) => var response = await client.SameAsModelAsync(body); NUnit.Framework.Assert.AreEqual(204, response.GetRawResponse().Status); }); + + [SpectorTest] + public Task ModelProperties_DictMethodsAsync() => Test(async (host) => + { + DictMethods body = new DictMethods("ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok", "ok"); + var client = new SpecialWordsClient(host, null).GetModelPropertiesClient(); + var response = await client.DictMethodsAsync(body); + NUnit.Framework.Assert.AreEqual(204, response.GetRawResponse().Status); + }); + + [SpectorTest] + public Task ModelProperties_WithListAsync() => Test(async (host) => + { + ModelWithList body = new ModelWithList("ok"); + var client = new SpecialWordsClient(host, null).GetModelPropertiesClient(); + var response = await client.WithListAsync(body); + NUnit.Framework.Assert.AreEqual(204, response.GetRawResponse().Status); + }); } } diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/_Type/Property/AdditionalProperties/AdditionalPropertiesTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/_Type/Property/AdditionalProperties/AdditionalPropertiesTests.cs index 0550b638447..926d1cd492f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/_Type/Property/AdditionalProperties/AdditionalPropertiesTests.cs +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/_Type/Property/AdditionalProperties/AdditionalPropertiesTests.cs @@ -841,6 +841,45 @@ public Task SpreadRecordNonDiscriminatedUnion2Put() => Test(async host => Assert.AreEqual(204, response.GetRawResponse().Status); }); + [SpectorTest] + public Task SpreadRecordNonDiscriminatedUnion3Get() => Test(async host => + { + var response = await new AdditionalPropertiesClient(host, null).GetSpreadRecordNonDiscriminatedUnion3Client().GetAsync(); + Assert.AreEqual(200, response.GetRawResponse().Status); + Assert.AreEqual("abc", response.Value.Name); + Assert.AreEqual(2, response.Value.AdditionalProperties.Count); + using var jsonDoc = System.Text.Json.JsonDocument.Parse(response.Value.AdditionalProperties["prop1"].ToMemory()); + var prop1Items = jsonDoc.RootElement.EnumerateArray() + .Select(e => ModelReaderWriter.Read(BinaryData.FromString(e.GetRawText()))) + .ToList(); + Assert.AreEqual(2, prop1Items.Count); + Assert.AreEqual("2021-01-01T00:00:00Z", prop1Items[0]!.Start); + Assert.AreEqual("2021-01-01T00:00:00Z", prop1Items[1]!.Start); + var prop2 = ModelReaderWriter.Read(response.Value.AdditionalProperties["prop2"]); + Assert.AreEqual(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero), prop2!.Start); + Assert.AreEqual(new DateTimeOffset(2021, 1, 2, 0, 0, 0, TimeSpan.Zero), prop2.End); + }); + + [SpectorTest] + public Task SpreadRecordNonDiscriminatedUnion3Put() => Test(async host => + { + var prop1BinaryData = BinaryData.FromString( + "[{\"kind\":\"kind1\",\"start\":\"2021-01-01T00:00:00Z\"},{\"kind\":\"kind1\",\"start\":\"2021-01-01T00:00:00Z\"}]"); + var value = new SpreadRecordForNonDiscriminatedUnion3("abc") + { + AdditionalProperties = + { + ["prop1"] = prop1BinaryData, + ["prop2"] = ModelReaderWriter.Write(new WidgetData1(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero)) + { + End = new DateTimeOffset(2021, 1, 2, 0, 0, 0, TimeSpan.Zero) + }) + } + }; + var response = await new AdditionalPropertiesClient(host, null).GetSpreadRecordNonDiscriminatedUnion3Client().PutAsync(value); + Assert.AreEqual(204, response.GetRawResponse().Status); + }); + [SpectorTest] public Task SpreadRecordUnionGet() => Test(async host => { diff --git a/packages/http-client-csharp/global.json b/packages/http-client-csharp/global.json index 7be862f576b..311edc2181a 100644 --- a/packages/http-client-csharp/global.json +++ b/packages/http-client-csharp/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.102", + "version": "10.0.103", "rollForward": "feature" } }