Skip to content
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

[Linter Rules] M1005, M1006, M1007 & M1009 #1706

Merged
merged 4 commits into from
Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/core/AutoRest.Core/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/core/AutoRest.Core/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,7 @@
<data name="PathCannotBeNullOrEmpty" xml:space="preserve">
<value>path cannot be null or an empty string or a string with white spaces while getting the parent directory</value>
</data>
<data name="OperationNameNotValid" xml:space="preserve">
<value>'GET' operation must use method name 'Get' or Method name start with 'List', 'PUT' operation must use method name 'Create', 'PATCH' operation must use method name 'Update' and 'DELETE' operation must use method name 'Delete'.</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"swagger": "2.0",
"info": {
"title": "Operation name not valid",
"description": "Some documentation.",
"version": "2014-04-01-preview"
},
"host": "management.azure.com",
"schemes": [
"https"
],
"basePath": "/",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"paths": {
"/foo": {
"get": {
"operationId": "Noun_NotNamedGet",
"summary": "Foo get path",
"description": "Foo operation",
"responses": {
"default": {
"description": "Unexpected error"
}
}
}
},
"/foo1": {
"put": {
"operationId": "Noun_NotNamedCreate",
"summary": "Foo2 create path",
"description": "Foo2 operation",
"responses": {
"default": {
"description": "Unexpected error"
}
}
}
},
"/foo2": {
"delete": {
"operationId": "Noun_NotNamedDelete",
"summary": "Foo2 delete path",
"description": "Foo2 operation",
"responses": {
"default": {
"description": "Unexpected error"
}
}
}
},
"/foo3": {
"get": {
"operationId": "Noun_List",
"summary": "Foo3 path",
"description": "Foo3 list operation",
"responses": {
"default": {
"description": "Unexpected error"
}
}
}
}
},
"parameters": {
"SubscriptionIdParameter": {
"name": "subscriptionId",
"in": "path",
"required": true,
"type": "string",
"description": "test subscription id"
},
"ApiVersion": {
"name": "api-version",
"in": "path",
"required": true,
"type": "string",
"description": "test api version"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"/pets/{petId}": {
"get": {
"summary": "Info for a specific pet",
"operationId": "showPetById",
"operationId": "getPetById",
"description": "foo",
"tags": [
"pets"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,13 @@ public void Pageable200ResponseNotModeledValidation()
var messages = ValidateSwagger(Path.Combine("Swagger", "Validation", "pageable-no-200-response.json"));
messages.Any(m => m.Type == typeof(PageableRequires200Response));
}

[Fact]
public void OperationNameValidation()
{
var messages = ValidateSwagger(Path.Combine("Swagger", "Validation", "operation-name-not-valid.json"));
messages.AssertOnlyValidationMessage(typeof(OperationNameValidation), 3);
}
}

#region Positive tests
Expand Down
1 change: 1 addition & 0 deletions src/modeler/AutoRest.Swagger/Model/Operation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public Operation()
/// </summary>
[Rule(typeof(OneUnderscoreInOperationId))]
[Rule(typeof(OperationIdNounInVerb))]
[Rule(typeof(OperationNameValidation))]
public string OperationId { get; set; }

public string Summary
Expand Down
72 changes: 72 additions & 0 deletions src/modeler/AutoRest.Swagger/Validation/OperationNameValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using AutoRest.Core.Logging;
using AutoRest.Core.Properties;
using AutoRest.Core.Validation;
using AutoRest.Swagger.Model;

namespace AutoRest.Swagger.Validation
{
public class OperationNameValidation : TypedRule<string>
{
private const string NOUN_VERB_PATTERN = "^(\\w+)?_(\\w+)$";

/// <summary>
/// The template message for this Rule.
/// </summary>
/// <remarks>
/// This may contain placeholders '{0}' for parameterized messages.
/// </remarks>
public override string MessageTemplate => Resources.OperationNameNotValid;

/// <summary>
/// The severity of this message (ie, debug/info/warning/error/fatal, etc)
/// </summary>
/// <remarks>
/// This rule corresponds to M1005, M1006, M1007 & M1009.
/// </remarks>
public override Category Severity => Category.Warning;

/// <summary>
/// This rule passes if the operation id of HTTP Method confirms to M1005, M1006, M1007 & M1009.
/// e.g. For Get method User_Get or User_List
/// or For Put method User_Create
/// or For Patch method User_Update
/// or For Delete method User_Delete
/// are valid names.
/// </summary>
/// <param name="operationDefinition">Dictionary of the path and respective operations.</param>
/// <returns><c>true</c> if operation name confimes to above rules, otherwise <c>false</c>.</returns>
/// <remarks>
/// Message will be shown at the path level.
/// </remarks>
public override bool IsValid(string entity, RuleContext context)
{
bool isOperationNameValid = true;
string httpVerb = context?.Parent?.Key;

if (httpVerb.Equals("GET", StringComparison.InvariantCultureIgnoreCase))
{
isOperationNameValid = (entity.Contains("_") && (entity.EndsWith("_Get") || entity.Contains("_List"))) ||
(entity.StartsWith("get") || entity.StartsWith("list"));
}
else if (httpVerb.Equals("PUT", StringComparison.InvariantCultureIgnoreCase))
{
isOperationNameValid = (entity.Contains("_") && entity.EndsWith("_Create")) || entity.StartsWith("create");
}
else if (httpVerb.Equals("PATCH", StringComparison.InvariantCultureIgnoreCase))
{
isOperationNameValid = (entity.Contains("_") && entity.EndsWith("_Update")) || entity.StartsWith("update");
}
else if (httpVerb.Equals("DELETE", StringComparison.InvariantCultureIgnoreCase))
{
isOperationNameValid = (entity.Contains("_") && entity.EndsWith("_Delete")) || entity.StartsWith("update");
}

return isOperationNameValid;
}
}
}