-
Notifications
You must be signed in to change notification settings - Fork 349
Increase code coverage in unit test pipeline #3703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
aaronburtle
wants to merge
10
commits into
main
Choose a base branch
from
dev/aaronburtle/improve-code-coverage
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
4218260
add code coverage to easy to cover branches
aaronburtle fa5236b
Merge branch 'main' into dev/aaronburtle/improve-code-coverage
aaronburtle 280fe81
Remove redundant EntitySourceNamesParserTests
aaronburtle 2f3352a
fix format
aaronburtle b14c04a
Merge branch 'dev/aaronburtle/improve-code-coverage' of https://githu…
aaronburtle c28b6f1
fix assertion typing
aaronburtle a9ccbc9
increase branch coverage
aaronburtle 2b547cb
raise code coverage
aaronburtle 26b6ddb
Use block-scoped namespaces in new unit test files for consistency
aaronburtle 369d405
Merge branch 'main' into dev/aaronburtle/improve-code-coverage
aaronburtle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using Azure.DataApiBuilder.Config.ObjectModel; | ||
| using Azure.DataApiBuilder.Service.GraphQLBuilder; | ||
| using Azure.DataApiBuilder.Service.Tests.GraphQLBuilder.Helpers; | ||
| using HotChocolate.Language; | ||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| namespace Azure.DataApiBuilder.Service.Tests.GraphQLBuilder | ||
| { | ||
| /// <summary> | ||
| /// Unit tests for the pure naming helpers in <see cref="GraphQLNaming"/>. | ||
| /// </summary> | ||
| [TestClass] | ||
| public class GraphQLNamingTests | ||
| { | ||
| [DataTestMethod] | ||
| [DataRow("Book", "Book", DisplayName = "Valid name is unchanged")] | ||
| [DataRow("1Book", "Book", DisplayName = "Illegal leading digit is stripped")] | ||
| [DataRow("_Book", "Book", DisplayName = "Illegal leading underscore is stripped")] | ||
| [DataRow("Bo-ok", "Book", DisplayName = "Invalid symbol removed")] | ||
| public void SanitizeGraphQLName_SingleSegment(string input, string expected) | ||
| { | ||
| string[] segments = GraphQLNaming.SanitizeGraphQLName(input); | ||
| Assert.AreEqual(1, segments.Length); | ||
| Assert.AreEqual(expected, segments[0]); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void SanitizeGraphQLName_RemovesSpacesAndInvalidSymbols() | ||
| { | ||
| // Spaces and non-alphanumeric symbols are removed, yielding a single segment. | ||
| string[] segments = GraphQLNaming.SanitizeGraphQLName("my table!"); | ||
| CollectionAssert.AreEqual(new[] { "mytable" }, segments); | ||
| } | ||
|
|
||
| [DataTestMethod] | ||
| [DataRow("Book", false)] | ||
| [DataRow("book", false)] | ||
| [DataRow("1book", true)] | ||
| [DataRow("_book", true)] | ||
| public void ViolatesNamePrefixRequirements(string name, bool expected) | ||
| { | ||
| Assert.AreEqual(expected, GraphQLNaming.ViolatesNamePrefixRequirements(name)); | ||
| } | ||
|
|
||
| [DataTestMethod] | ||
| [DataRow("Book", false)] | ||
| [DataRow("Book_1", false)] | ||
| [DataRow("Bo-ok", true)] | ||
| [DataRow("my table", true)] | ||
| public void ViolatesNameRequirements(string name, bool expected) | ||
| { | ||
| Assert.AreEqual(expected, GraphQLNaming.ViolatesNameRequirements(name)); | ||
| } | ||
|
|
||
| [DataTestMethod] | ||
| [DataRow("__type", true)] | ||
| [DataRow("__schema", true)] | ||
| [DataRow("type", false)] | ||
| [DataRow("_type", false)] | ||
| public void IsIntrospectionField(string fieldName, bool expected) | ||
| { | ||
| Assert.AreEqual(expected, GraphQLNaming.IsIntrospectionField(fieldName)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GetDefinedSingularName_WithSingular_ReturnsSingular() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithSingularPlural("Book", "Books"); | ||
| Assert.AreEqual("Book", GraphQLNaming.GetDefinedSingularName("Book", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GetDefinedSingularName_WithoutSingular_Throws() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEmptyEntity(); | ||
| Assert.ThrowsException<System.ArgumentException>( | ||
| () => GraphQLNaming.GetDefinedSingularName("Book", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GetDefinedPluralName_WithPlural_ReturnsPlural() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithSingularPlural("Book", "Books"); | ||
| Assert.AreEqual("Books", GraphQLNaming.GetDefinedPluralName("Book", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GetDefinedPluralName_WithoutPlural_Throws() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithStringType("Book"); | ||
| Assert.ThrowsException<System.ArgumentException>( | ||
| () => GraphQLNaming.GetDefinedPluralName("Book", entity)); | ||
| } | ||
|
|
||
| [DataTestMethod] | ||
| [DataRow("Book", "book", DisplayName = "First char lowercased")] | ||
| [DataRow("my table", "mytable", DisplayName = "Spaces removed, first char lowercased")] | ||
| [DataRow("book", "book", DisplayName = "Already camel-case unchanged")] | ||
| public void FormatNameForField(string input, string expected) | ||
| { | ||
| Assert.AreEqual(expected, GraphQLNaming.FormatNameForField(input)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void Pluralize_ReturnsConfiguredPluralName() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithSingularPlural("Book", "Books"); | ||
| NameNode result = GraphQLNaming.Pluralize("Book", entity); | ||
| Assert.AreEqual("Books", result.Value); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void ObjectTypeToEntityName_NoModelDirective_ReturnsTypeName() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { id: Int }"); | ||
| Assert.AreEqual("Book", GraphQLNaming.ObjectTypeToEntityName(node)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void ObjectTypeToEntityName_ModelDirectiveWithName_ReturnsModelName() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType(@"type Book @model(name: ""TopLevelBook"") { id: Int }"); | ||
| Assert.AreEqual("TopLevelBook", GraphQLNaming.ObjectTypeToEntityName(node)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void ObjectTypeToEntityName_ModelDirectiveNoArguments_ReturnsTypeName() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book @model { id: Int }"); | ||
| Assert.AreEqual("Book", GraphQLNaming.ObjectTypeToEntityName(node)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GenerateByPKQueryName_UsesSingularWithSuffix() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithSingularPlural("Book", "Books"); | ||
| Assert.AreEqual("book_by_pk", GraphQLNaming.GenerateByPKQueryName("Book", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GenerateListQueryName_UsesPlural() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithSingularPlural("Book", "Books"); | ||
| Assert.AreEqual("books", GraphQLNaming.GenerateListQueryName("Book", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GenerateStoredProcedureGraphQLFieldName_PrefixesExecute() | ||
| { | ||
| Entity entity = GraphQLTestHelpers.GenerateEntityWithStringType("GetBook"); | ||
| Assert.AreEqual("executeGetBook", GraphQLNaming.GenerateStoredProcedureGraphQLFieldName("GetBook", entity)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GenerateLinkingNodeName_ConcatenatesWithPrefix() | ||
| { | ||
| Assert.AreEqual("linkingObjectBookAuthor", GraphQLNaming.GenerateLinkingNodeName("Book", "Author")); | ||
| } | ||
|
|
||
| private static ObjectTypeDefinitionNode ParseObjectType(string sdl) | ||
| { | ||
| DocumentNode document = Utf8GraphQLParser.Parse(sdl); | ||
| return (ObjectTypeDefinitionNode)document.Definitions[0]; | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Generic; | ||
| using Azure.DataApiBuilder.Config.ObjectModel; | ||
| using Azure.DataApiBuilder.Service.Exceptions; | ||
| using Azure.DataApiBuilder.Service.GraphQLBuilder; | ||
| using HotChocolate.Language; | ||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| namespace Azure.DataApiBuilder.Service.Tests.GraphQLBuilder | ||
| { | ||
| /// <summary> | ||
| /// Unit tests for the pure static helpers in <see cref="GraphQLUtils"/>. | ||
| /// </summary> | ||
| [TestClass] | ||
| public class GraphQLUtilsTests | ||
| { | ||
| [DataTestMethod] | ||
| [DataRow(DatabaseType.MSSQL, true)] | ||
| [DataRow(DatabaseType.MySQL, true)] | ||
| [DataRow(DatabaseType.DWSQL, true)] | ||
| [DataRow(DatabaseType.PostgreSQL, true)] | ||
| [DataRow(DatabaseType.CosmosDB_PostgreSQL, true)] | ||
| [DataRow(DatabaseType.CosmosDB_NoSQL, false)] | ||
| public void IsRelationalDb(DatabaseType databaseType, bool expected) | ||
| { | ||
| Assert.AreEqual(expected, GraphQLUtils.IsRelationalDb(databaseType)); | ||
| } | ||
|
|
||
| [DataTestMethod] | ||
| [DataRow("String", true)] | ||
| [DataRow("Int", true)] | ||
| [DataRow("Boolean", true)] | ||
| [DataRow("ID", true)] | ||
| [DataRow("Book", false)] | ||
| [DataRow("CustomType", false)] | ||
| public void IsBuiltInType(string typeName, bool expected) | ||
| { | ||
| ITypeNode typeNode = new NamedTypeNode(new NameNode(typeName)); | ||
| Assert.AreEqual(expected, GraphQLUtils.IsBuiltInType(typeNode)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void IsModelType_WithModelDirective_ReturnsTrue() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType(@"type Book @model(name: ""Book"") { id: Int }"); | ||
| Assert.IsTrue(GraphQLUtils.IsModelType(node)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void IsModelType_WithoutModelDirective_ReturnsFalse() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { id: Int }"); | ||
| Assert.IsFalse(GraphQLUtils.IsModelType(node)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FindPrimaryKeyFields_CosmosNoSql_ReturnsIdAndPartitionKey() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { title: String }"); | ||
| List<FieldDefinitionNode> pkFields = GraphQLUtils.FindPrimaryKeyFields(node, DatabaseType.CosmosDB_NoSQL); | ||
|
|
||
| Assert.AreEqual(2, pkFields.Count); | ||
| CollectionAssert.AreEquivalent( | ||
| new[] { GraphQLUtils.DEFAULT_PRIMARY_KEY_NAME, GraphQLUtils.DEFAULT_PARTITION_KEY_NAME }, | ||
| pkFields.ConvertAll(f => f.Name.Value)); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FindPrimaryKeyFields_PrimaryKeyDirective_ReturnsDirectiveField() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { book_id: Int @primaryKey title: String }"); | ||
| List<FieldDefinitionNode> pkFields = GraphQLUtils.FindPrimaryKeyFields(node, DatabaseType.MSSQL); | ||
|
|
||
| Assert.AreEqual(1, pkFields.Count); | ||
| Assert.AreEqual("book_id", pkFields[0].Name.Value); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FindPrimaryKeyFields_NoDirective_FallsBackToIdField() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { id: Int title: String }"); | ||
| List<FieldDefinitionNode> pkFields = GraphQLUtils.FindPrimaryKeyFields(node, DatabaseType.MSSQL); | ||
|
|
||
| Assert.AreEqual(1, pkFields.Count); | ||
| Assert.AreEqual("id", pkFields[0].Name.Value); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FindPrimaryKeyFields_NoDirectiveNoIdField_Throws() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { title: String }"); | ||
| DataApiBuilderException ex = Assert.ThrowsException<DataApiBuilderException>( | ||
| () => GraphQLUtils.FindPrimaryKeyFields(node, DatabaseType.MSSQL)); | ||
|
|
||
| Assert.AreEqual(DataApiBuilderException.SubStatusCodes.ErrorInInitialization, ex.SubStatusCode); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void IsAutoGeneratedField_WithDirective_ReturnsTrue() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { id: Int @autoGenerated }"); | ||
| Assert.IsTrue(GraphQLUtils.IsAutoGeneratedField(node.Fields[0])); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void IsAutoGeneratedField_WithoutDirective_ReturnsFalse() | ||
| { | ||
| ObjectTypeDefinitionNode node = ParseObjectType("type Book { id: Int }"); | ||
| Assert.IsFalse(GraphQLUtils.IsAutoGeneratedField(node.Fields[0])); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void CreateAuthorizationDirective_NullRoles_ReturnsFalse() | ||
| { | ||
| bool created = GraphQLUtils.CreateAuthorizationDirectiveIfNecessary(null, out DirectiveNode? directive); | ||
| Assert.IsFalse(created); | ||
| Assert.IsNull(directive); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void CreateAuthorizationDirective_EmptyRoles_ReturnsFalse() | ||
| { | ||
| bool created = GraphQLUtils.CreateAuthorizationDirectiveIfNecessary(new List<string>(), out DirectiveNode? directive); | ||
| Assert.IsFalse(created); | ||
| Assert.IsNull(directive); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void CreateAuthorizationDirective_ContainsAnonymous_ReturnsFalse() | ||
| { | ||
| bool created = GraphQLUtils.CreateAuthorizationDirectiveIfNecessary( | ||
| new[] { "role1", GraphQLUtils.SYSTEM_ROLE_ANONYMOUS }, out DirectiveNode? directive); | ||
| Assert.IsFalse(created); | ||
| Assert.IsNull(directive); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void CreateAuthorizationDirective_WithRoles_ReturnsAuthorizeDirective() | ||
| { | ||
| bool created = GraphQLUtils.CreateAuthorizationDirectiveIfNecessary( | ||
| new[] { "role1", "role2" }, out DirectiveNode? directive); | ||
|
|
||
| Assert.IsTrue(created); | ||
| Assert.IsNotNull(directive); | ||
| Assert.AreEqual(GraphQLUtils.AUTHORIZE_DIRECTIVE, directive!.Name.Value); | ||
| Assert.AreEqual(1, directive.Arguments.Count); | ||
| Assert.AreEqual(GraphQLUtils.AUTHORIZE_DIRECTIVE_ARGUMENT_ROLES, directive.Arguments[0].Name.Value); | ||
| } | ||
|
|
||
| private static ObjectTypeDefinitionNode ParseObjectType(string sdl) | ||
| { | ||
| DocumentNode document = Utf8GraphQLParser.Parse(sdl); | ||
| return (ObjectTypeDefinitionNode)document.Definitions[0]; | ||
| } | ||
| } | ||
| } |
59 changes: 59 additions & 0 deletions
59
src/Service.Tests/GraphQLBuilder/Sql/GraphQLStoredProcedureBuilderHelpersTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
|
aaronburtle marked this conversation as resolved.
|
||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Text.Json; | ||
| using Azure.DataApiBuilder.Service.GraphQLBuilder; | ||
| using HotChocolate.Language; | ||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
|
||
| namespace Azure.DataApiBuilder.Service.Tests.GraphQLBuilder.Sql | ||
| { | ||
| /// <summary> | ||
| /// Unit tests for the pure helper methods on <see cref="GraphQLStoredProcedureBuilder"/> that | ||
| /// shape stored-procedure results and default result fields. | ||
| /// </summary> | ||
| [TestClass] | ||
| public class GraphQLStoredProcedureBuilderHelpersTests | ||
| { | ||
| [TestMethod] | ||
| public void FormatStoredProcedureResultAsJsonList_Null_ReturnsEmptyList() | ||
| { | ||
| List<JsonDocument> result = GraphQLStoredProcedureBuilder.FormatStoredProcedureResultAsJsonList(null); | ||
|
|
||
| Assert.IsNotNull(result); | ||
| Assert.AreEqual(0, result.Count); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FormatStoredProcedureResultAsJsonList_EmptyArray_ReturnsEmptyList() | ||
| { | ||
| using JsonDocument input = JsonDocument.Parse("[]"); | ||
| List<JsonDocument> result = GraphQLStoredProcedureBuilder.FormatStoredProcedureResultAsJsonList(input); | ||
|
|
||
| Assert.AreEqual(0, result.Count); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void FormatStoredProcedureResultAsJsonList_MultipleRows_ReturnsOneDocumentPerRow() | ||
| { | ||
| using JsonDocument input = JsonDocument.Parse(@"[{""id"":1,""title"":""A""},{""id"":2,""title"":""B""}]"); | ||
| List<JsonDocument> result = GraphQLStoredProcedureBuilder.FormatStoredProcedureResultAsJsonList(input); | ||
|
|
||
| Assert.AreEqual(2, result.Count); | ||
| Assert.AreEqual(1, result[0].RootElement.GetProperty("id").GetInt32()); | ||
| Assert.AreEqual("B", result[1].RootElement.GetProperty("title").GetString()); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public void GetDefaultResultFieldForStoredProcedure_ReturnsResultStringField() | ||
| { | ||
| FieldDefinitionNode field = GraphQLStoredProcedureBuilder.GetDefaultResultFieldForStoredProcedure(); | ||
|
|
||
| Assert.AreEqual("result", field.Name.Value); | ||
| Assert.AreEqual(0, field.Arguments.Count); | ||
| Assert.IsInstanceOfType(field.Type, typeof(NamedTypeNode)); | ||
| Assert.AreEqual("String", ((NamedTypeNode)field.Type).Name.Value); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.