Skip to content

Commit

Permalink
Refactor TS code snippet to interfaces (#1008)
Browse files Browse the repository at this point in the history
* Refactor TS code snippet to interfaces

* Adds unit tests to ModelGraphBuilder

* Move test

* Fix array serialization

* Fix - Get schema inforation for propeties generated under additional data

* Adds TS test cases

* Fix code smells

* Refactor SnippetCodeGraph to constructor initialization

* Update CodeSnippetsReflection.OpenAPI/ModelGraph/SnippetCodeGraph.cs

Co-authored-by: Vincent Biret <vibiret@microsoft.com>

* - additional parenthesis fix

* Update CodeSnippetsReflection.OpenAPI.Test/SnippetCodeGraphTests.cs

Co-authored-by: Vincent Biret <vibiret@microsoft.com>

* Update CodeSnippetsReflection.OpenAPI.Test/SnippetCodeGraphTests.cs

Co-authored-by: Mustafa Zengin <muzengin@microsoft.com>

* Rename AssertUtil to AssertExtenstions

* Fix broken tests

Co-authored-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Mustafa Zengin <muzengin@microsoft.com>
  • Loading branch information
3 people authored Jun 7, 2022
1 parent 4697fff commit 211879b
Show file tree
Hide file tree
Showing 10 changed files with 1,221 additions and 322 deletions.
20 changes: 20 additions & 0 deletions CodeSnippetsReflection.OpenAPI.Test/AssertExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace CodeSnippetsReflection.OpenAPI.Test
{
public static class AssertExtensions
{
public static void ContainsIgnoreWhiteSpace(string expectedSubstring, string actualString)
{
Xunit.Assert.Contains(
expectedSubstring.Replace(" ", string.Empty).Replace(Environment.NewLine, string.Empty),
actualString.Replace(" ", string.Empty).Replace(Environment.NewLine, string.Empty)
);
}
}
}
304 changes: 304 additions & 0 deletions CodeSnippetsReflection.OpenAPI.Test/SnippetCodeGraphTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using CodeSnippetsReflection.OpenAPI.ModelGraph;
using Microsoft.OpenApi.Services;
using Xunit;

namespace CodeSnippetsReflection.OpenAPI.Test
{
public class SnippetCodeGraphTests
{
private const string ServiceRootUrl = "https://graph.microsoft.com/v1.0";
private static OpenApiUrlTreeNode _v1TreeNode;

private static string TypesSample = @"
{
""attendees"": [
{
""type"": ""null"",
""emailAddress"": {
""name"": ""Alex Wilbur"",
""address"": ""alexw@contoso.onmicrosoft.com""
}
}
],
""locationConstraint"": {
""isRequired"": false,
""suggestLocation"": false,
""locations"": [
{
""resolveAvailability"": false,
""displayName"": ""Conf room Hood""
}
]
},
""timeConstraint"": {
""activityDomain"":""work"",
""timeSlots"": [
{
""start"": {
""dateTime"": ""2019-04-16T09:00:00"",
""timeZone"": ""Pacific Standard Time""
},
""end"": {
""dateTime"": ""2019-04-18T17:00:00"",
""timeZone"": ""Pacific Standard Time""
}
}
]
},
""isOrganizerOptional"": ""false"",
""meetingDuration"": ""PT1H"",
""returnSuggestionReasons"": ""true"",
""minimumAttendeePercentage"": 100
}
";

// read the file from disk
private static async Task<OpenApiUrlTreeNode> GetV1TreeNode()
{
if (_v1TreeNode == null)
{
_v1TreeNode = await SnippetModelTests.GetTreeNode("https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/openapi.yaml");
}
return _v1TreeNode;
}

[Fact]
public async Task ParsesHeaders()
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users");

request.Headers.Add("Host", "graph.microsoft.com");
request.Headers.Add("Prefer", "outlook.timezone=\"Pacific Standard Time\"");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);
var header = result.Headers.First();

Assert.True(result.HasHeaders());
Assert.Single(result.Headers); // host should be ignored in headers
Assert.Equal("outlook.timezone=\"Pacific Standard Time\"", header.Value);
Assert.Equal("Prefer", header.Name);
Assert.Equal(PropertyType.String, header.PropertyType);
}

[Fact]
public async Task HasHeadersIsFalseWhenNoneIsInRequest()
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users");
request.Headers.Add("Host", "graph.microsoft.com");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);

Assert.False(result.HasHeaders());
}

[Fact]
public async Task ParsesParameters()
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users/19:4b6bed8d24574f6a9e436813cb2617d8?$select=displayName,givenName,postalCode,identities");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);
var parameter = result.Parameters.First();

Assert.True(result.HasParameters());
Assert.Single(result.Parameters);

var expectedProperty = new CodeProperty { Name = "select", Value = "displayName,givenName,postalCode,identities", PropertyType = PropertyType.String, Children = null };
Assert.Equal(expectedProperty, parameter);

Assert.Equal("displayName,givenName,postalCode,identities", parameter.Value);
Assert.Equal("select", parameter.Name);
Assert.Equal(PropertyType.String, parameter.PropertyType);

Assert.True(result.HasParameters());
}

[Fact]
public async Task ParsesQueryParametersWithSpaces()
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'&$expand=principal");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);
var parameter = result.Parameters.First();

Assert.True(result.HasParameters());
Assert.Equal(2, result.Parameters.Count());

var expectedProperty1 = new CodeProperty { Name = "filter", Value = "roleDefinitionId eq '62e90394-69f5-4237-9190-012177145e10'", PropertyType = PropertyType.String, Children = null };
Assert.Equal(expectedProperty1, result.Parameters.First());

var expectedProperty2 = new CodeProperty { Name = "expand", Value = "principal", PropertyType = PropertyType.String, Children = null };
Assert.Equal(expectedProperty2, result.Parameters.Skip(1).First());

}

[Fact]
public async Task HasParametersIsFalseWhenNoParameterExists()
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/users/19:4b6bed8d24574f6a9e436813cb2617d8");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);

Assert.False(result.HasParameters());
}

[Fact]
public async Task ParsesBodyTypeBinary()
{
using var request = new HttpRequestMessage(HttpMethod.Put, $"{ServiceRootUrl}/applications/{{application-id}}/logo")
{
Content = new ByteArrayContent(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 })
};
request.Content.Headers.ContentType = new("application/octet-stream");

var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);

Assert.Equal(PropertyType.Binary, result.Body.PropertyType);
}

[Fact]
public async Task ParsesBodyWithoutProperContentType()
{

var sampleBody = @"
{
""createdDateTime"": ""2019-02-04T19:58:15.511Z""
}
";

using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/teams/team-id/channels/19:4b6bed8d24574f6a9e436813cb2617d8@thread.tacv2/messages")
{
Content = new StringContent(sampleBody, Encoding.UTF8) // snippet missing content type
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var result = new SnippetCodeGraph(snippetModel);

var expectedObject = new CodeProperty { Name = "MessagesPostRequestBody", Value = null, PropertyType = PropertyType.Object, Children = new List<CodeProperty>() };

Assert.Equal(expectedObject.Name, result.Body.Name);
Assert.Equal(expectedObject.Value, result.Body.Value);
Assert.Equal(expectedObject.PropertyType, result.Body.PropertyType);
}

private CodeProperty? FindPropertyInSnippet(CodeProperty codeProperty, string name)
{
if (codeProperty.Name == name) return codeProperty;

if (codeProperty.Children.Any())
{
foreach (var param in codeProperty.Children)
{
if(FindPropertyInSnippet(param, name) is CodeProperty result) return result;
}
}

return null;
}

[Fact]
public async Task ParsesBodyPropertyTypeString()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

// meetingDuration should be a string
var property = FindPropertyInSnippet(snippetCodeGraph.Body, "meetingDuration").Value;

Assert.Equal(PropertyType.String, property.PropertyType);
Assert.Equal("PT1H", property.Value);
}

[Fact]
public async Task ParsesBodyPropertyTypeNumber()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

var property = FindPropertyInSnippet(snippetCodeGraph.Body, "minimumAttendeePercentage").Value;

Assert.Equal(PropertyType.Number, property.PropertyType);
Assert.Equal("100" , property.Value);
}

[Fact]
public async Task ParsesBodyPropertyTypeBoolean()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

var property = FindPropertyInSnippet(snippetCodeGraph.Body, "suggestLocation").Value;

Assert.Equal(PropertyType.Boolean, property.PropertyType);
Assert.Equal("False", property.Value);
}

[Fact]
public async Task ParsesBodyPropertyTypeObject()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

var property = FindPropertyInSnippet(snippetCodeGraph.Body, "locationConstraint").Value;

Assert.Equal(PropertyType.Object, property.PropertyType);
}

[Fact]
public async Task ParsesBodyPropertyTypeArray()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

var property = FindPropertyInSnippet(snippetCodeGraph.Body, "attendees").Value;

Assert.Equal(PropertyType.Array, property.PropertyType);
}

[Fact]
public async Task ParsesBodyPropertyTypeMap()
{
using var request = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/findMeetingTimes")
{
Content = new StringContent(TypesSample, Encoding.UTF8)
};
var snippetModel = new SnippetModel(request, ServiceRootUrl, await GetV1TreeNode());
var snippetCodeGraph = new SnippetCodeGraph(snippetModel);

var property = FindPropertyInSnippet(snippetCodeGraph.Body, "additionalData").Value;

Assert.Equal(PropertyType.Map, property.PropertyType);
}
}

}
2 changes: 1 addition & 1 deletion CodeSnippetsReflection.OpenAPI.Test/SnippetModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ public async Task GetsTheResponseSchema()
Assert.NotEmpty(snippetModel.ResponseSchema.Properties);
}
}
}
}
Loading

0 comments on commit 211879b

Please sign in to comment.