...

Source file src/github.com/bazelbuild/buildtools/warn/warn_docstring_test.go

Documentation: github.com/bazelbuild/buildtools/warn

     1  /*
     2  Copyright 2020 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package warn
    18  
    19  import "testing"
    20  
    21  func TestModuleDocstring(t *testing.T) {
    22  	checkFindings(t, "module-docstring", ``,
    23  		[]string{},
    24  		scopeBzl|scopeDefault)
    25  
    26  	checkFindings(t, "module-docstring", `
    27  # empty file`,
    28  		[]string{},
    29  		scopeBzl|scopeDefault)
    30  
    31  	checkFindings(t, "module-docstring", `
    32  """This is the module"""
    33  
    34  load("foo", "bar")
    35  
    36  bar()`,
    37  		[]string{},
    38  		scopeBzl|scopeDefault)
    39  
    40  	checkFindings(t, "module-docstring", `
    41  load("foo", "bar")
    42  
    43  """This is the module"""
    44  
    45  bar()`,
    46  		[]string{":1: The file has no module docstring."},
    47  		scopeBzl|scopeDefault)
    48  
    49  	checkFindings(t, "module-docstring", `
    50  # comment
    51  
    52  # comment
    53  """This is the module"""
    54  
    55  load("foo", "bar")
    56  
    57  bar()`,
    58  		[]string{},
    59  		scopeBzl|scopeDefault)
    60  
    61  	checkFindings(t, "module-docstring", `
    62  # comment
    63  
    64  load("foo", "bar")
    65  
    66  # comment
    67  """This is the module"""
    68  
    69  bar()`,
    70  		[]string{":3: The file has no module docstring."},
    71  		scopeBzl|scopeDefault)
    72  
    73  	checkFindings(t, "module-docstring", `
    74  def foo(bar):
    75    if bar:
    76      f()
    77    return g()`,
    78  		[]string{":1: The file has no module docstring."},
    79  		scopeBzl|scopeDefault)
    80  }
    81  
    82  func TestFunctionDocstringExists(t *testing.T) {
    83  	checkFindings(t, "function-docstring", `
    84  def f(x):
    85     # short function
    86     return x
    87  `,
    88  		[]string{},
    89  		scopeEverywhere)
    90  
    91  	checkFindings(t, "function-docstring", `
    92  def f(x):
    93     """Short function with a docstring"""
    94     return x
    95  `,
    96  		[]string{},
    97  		scopeEverywhere)
    98  
    99  	checkFindings(t, "function-docstring", `
   100  def f(x):
   101     # long function
   102     x += 1
   103     x *= 2
   104     x /= 3
   105     x -= 4
   106     x %= 5
   107     return x
   108  `,
   109  		[]string{":1: The function \"f\" has no docstring."},
   110  		scopeEverywhere)
   111  
   112  	checkFindings(t, "function-docstring", `
   113  def f(x):
   114     def g(x):
   115        # long function
   116        x += 1
   117        x *= 2
   118        x /= 3
   119        x -= 4
   120        x %= 5
   121        return x
   122     return g
   123  `,
   124  		[]string{},
   125  		scopeEverywhere)
   126  
   127  	checkFindings(t, "function-docstring", `
   128  def _f(x):
   129     # long private function
   130     x += 1
   131     x *= 2
   132     x /= 3
   133     x -= 4
   134     x %= 5
   135     return x
   136  `,
   137  		[]string{},
   138  		scopeEverywhere)
   139  }
   140  
   141  func TestFunctionDocstringHeader(t *testing.T) {
   142  	checkFindings(t, "function-docstring-header", `
   143  def f():
   144     """This is a function.
   145     this is the description
   146     """
   147     pass
   148     pass
   149     pass
   150     pass
   151     pass
   152  `,
   153  		[]string{`2: The docstring for the function "f" should start with a one-line summary.`},
   154  		scopeEverywhere)
   155  
   156  	checkFindings(t, "function-docstring-header", `
   157  def f():
   158     def g():
   159        """This is a function.
   160        this is the description
   161        """
   162        pass
   163        pass
   164        pass
   165        pass
   166        pass
   167     return f
   168  `,
   169  		[]string{`3: The docstring for the function "g" should start with a one-line summary.`},
   170  		scopeEverywhere)
   171  
   172  	checkFindings(t, "function-docstring-header", `
   173  def _f(x):
   174    """Long private function
   175    with a docstring"""
   176    x += 1
   177    x *= 2
   178    x /= 3
   179    x -= 4
   180    x %= 5
   181    return x
   182  `,
   183  		[]string{
   184  			`:2: The docstring for the function "_f" should start with a one-line summary.`,
   185  		},
   186  		scopeEverywhere)
   187  
   188  	checkFindings(t, "function-docstring-header", `
   189  def f(x):
   190    """Long function with a docstring
   191  
   192  	Docstring
   193  	body
   194  	"""
   195    x += 1
   196    x *= 2
   197    x /= 3
   198    x -= 4
   199    x %= 5
   200    return x
   201  `,
   202  		[]string{},
   203  		scopeEverywhere)
   204  
   205  	checkFindings(t, "function-docstring-header", `
   206  def f():
   207     """
   208  
   209     This is a function.
   210  
   211     This is a
   212     multiline description"""
   213     pass
   214     pass
   215     pass
   216     pass
   217     pass
   218  `,
   219  		[]string{},
   220  		scopeEverywhere)
   221  
   222  	checkFindings(t, "function-docstring-header", `
   223  def f():
   224     """\r
   225     Header in a CRLF formatted file.\r
   226  \r
   227     This is a\r
   228     multiline description"""
   229  `,
   230  		[]string{},
   231  		scopeEverywhere)
   232  
   233  }
   234  
   235  func TestFunctionDocstringArgs(t *testing.T) {
   236  	checkFindings(t, "function-docstring-args", `
   237  def f(x):
   238     """This is a function.
   239  
   240     Documented here:
   241     http://example.com
   242  
   243     Args:
   244       x: something, as described at
   245         http://example.com
   246  
   247     Returns:
   248       something, as described at
   249       https://example.com
   250     """
   251     pass
   252     pass
   253     pass
   254     pass
   255     pass
   256     return x
   257  `,
   258  		[]string{},
   259  		scopeEverywhere)
   260  
   261  	checkFindings(t, "function-docstring-args", `
   262  def f(x):
   263     """This is a function.
   264  
   265     Args:
   266       x: something
   267     """
   268     passf
   269     pass
   270     pass
   271     pass
   272     pass
   273  `,
   274  		[]string{},
   275  		scopeEverywhere)
   276  
   277  	checkFindings(t, "function-docstring-args", `
   278  def f(x, y):
   279    """Short function with a docstring
   280  
   281    Arguments:
   282      x: smth
   283    """
   284    return x + y
   285  `,
   286  		[]string{
   287  			`2: Argument "y" is not documented.`,
   288  			`4: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
   289  		},
   290  		scopeEverywhere)
   291  
   292  	checkFindings(t, "function-docstring-args", `
   293  def f():
   294    def g(x, y):
   295      """Short function with a docstring
   296  
   297      Arguments:
   298        x: smth
   299      """
   300      return x + y
   301    return g
   302  `,
   303  		[]string{
   304  			`3: Argument "y" is not documented.`,
   305  			`5: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
   306  		},
   307  		scopeEverywhere)
   308  
   309  	checkFindings(t, "function-docstring-args", `
   310  def f():
   311    def g(x, y):
   312      """Short function with a docstring
   313      """
   314      return x + y
   315    return g
   316  `,
   317  		[]string{},
   318  		scopeEverywhere)
   319  
   320  	checkFindings(t, "function-docstring-args", `
   321  def _f(x, y):
   322    """Long private function
   323    
   324    Args:
   325      x: something
   326      z: something
   327    """
   328    x *= 2
   329    x /= 3
   330    x -= 4
   331    x %= 5
   332    return x
   333  `,
   334  		[]string{
   335  			`:2: Argument "y" is not documented.`,
   336  			`:6: Argument "z" is documented but doesn't exist in the function signature.`,
   337  		},
   338  		scopeEverywhere)
   339  
   340  	checkFindings(t, "function-docstring-args", `
   341  def f(x, y):
   342     """This is a function.
   343  
   344     Arguments:
   345       x: something
   346          y: something (this is in fact the description of x continued)
   347       z: something else
   348  
   349     Returns:
   350       None
   351     """
   352     pass
   353     pass
   354     pass
   355     pass
   356     pass
   357  `,
   358  		[]string{
   359  			`2: Argument "y" is not documented.`,
   360  			`4: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
   361  			`7: Argument "z" is documented but doesn't exist in the function signature.`,
   362  		}, scopeEverywhere)
   363  
   364  	checkFindings(t, "function-docstring-args", `
   365  def my_function(x, y, z = None, *args, **kwargs):
   366     """This is a function.
   367     """
   368     pass
   369     pass
   370     pass
   371     pass
   372     pass
   373  `,
   374  		[]string{
   375  			`2: Arguments "x", "y", "z", "*args", "**kwargs" are not documented.
   376  
   377  If the documentation for the arguments exists but is not recognized by Buildifier
   378  make sure it follows the line "Args:" which has the same indentation as the opening """,
   379  and the argument description starts with "<argument_name>:" and indented with at least
   380  one (preferably two) space more than "Args:", for example:
   381  
   382      def my_function(x):
   383          """Function description.
   384  
   385          Args:
   386            x: argument description, can be
   387              multiline with additional indentation.
   388          """`,
   389  		},
   390  		scopeEverywhere)
   391  
   392  	checkFindings(t, "function-docstring-args", `
   393  def f(x, y, z = None, *args, **kwargs):
   394     """This is a function.
   395  
   396     Args:
   397      x (Map[string, int]): x
   398      y (deprecated, mutable): y
   399      z: z
   400      *args (List<string>): the args
   401      **kwargs: the kwargs
   402     """
   403     pass
   404     pass
   405     pass
   406     pass
   407     pass
   408  `,
   409  		[]string{},
   410  		scopeEverywhere)
   411  
   412  	checkFindings(t, "function-docstring-args", `
   413  def f(x, *, y, z = None):
   414     """This is a function.
   415  
   416     Args:
   417      x: x
   418      y: y
   419      z: z
   420     """
   421     pass
   422  `,
   423  		[]string{},
   424  		scopeEverywhere)
   425  
   426  	checkFindings(t, "function-docstring-args", `
   427  def f(x, *, y, z = None):
   428     """This is a function.
   429  
   430     Args:
   431      x: x
   432      *: a separator
   433      y: y
   434      : argument without a name
   435      z: z
   436     """
   437     pass
   438  `,
   439  		[]string{
   440  			`6: Argument "*" is documented but doesn't exist in the function signature.`,
   441  			`8: Argument "" is documented but doesn't exist in the function signature.`,
   442  		},
   443  		scopeEverywhere)
   444  
   445  	checkFindings(t, "function-docstring-args", `
   446  def f(x):
   447     """
   448     This is a function.
   449  
   450     Args:
   451  
   452       The function signature is extremely complicated
   453  
   454       x: something
   455     Returns:
   456       nothing
   457     """
   458     pass
   459     pass
   460     pass
   461     pass
   462     pass
   463     return None
   464  `,
   465  		[]string{},
   466  		scopeEverywhere)
   467  
   468  	checkFindings(t, "function-docstring-args", `
   469  def f(foobar, *bar, **baz):
   470    """Some function
   471    
   472    Args:
   473      foobar: something
   474      foo: something
   475      bar: something
   476      baz: something
   477    """
   478    pass
   479  `,
   480  		[]string{
   481  			`:2: Arguments "*bar", "**baz" are not documented.`,
   482  			`:6: Argument "foo" is documented but doesn't exist in the function signature.`,
   483  			`:7: Argument "bar" is documented but doesn't exist in the function signature. Do you mean "*bar"?`,
   484  			`:8: Argument "baz" is documented but doesn't exist in the function signature. Do you mean "**baz"?`,
   485  		},
   486  		scopeEverywhere)
   487  
   488  	checkFindings(t, "function-docstring-args", `
   489  def f(x: int, y: str, z: bool = False, *, *bar: List[int], **baz: Mapping[str, bool]):
   490    """Some function
   491    
   492    Args:
   493      x: something
   494      t: something
   495    """
   496    pass
   497  `,
   498  		[]string{
   499  			`:2: Arguments "y", "z", "*bar", "**baz" are not documented.`,
   500  			`:6: Argument "t" is documented but doesn't exist in the function signature.`,
   501  		},
   502  		scopeEverywhere)
   503  }
   504  
   505  func TestFunctionDocstringReturn(t *testing.T) {
   506  	checkFindings(t, "function-docstring-return", `
   507  def f(x):
   508     """This is a function.
   509  
   510     Args:
   511       x: something
   512  
   513     Returns:
   514       something
   515     """
   516     pass
   517     pass
   518     pass
   519     pass
   520     pass
   521     return x
   522  `,
   523  		[]string{},
   524  		scopeEverywhere)
   525  
   526  	checkFindings(t, "function-docstring-return", `
   527  def f(x):
   528     """This is a function.
   529  
   530     Args:
   531       x: something
   532     """
   533     pass
   534     pass
   535     pass
   536     pass
   537     pass
   538  `,
   539  		[]string{},
   540  		scopeEverywhere)
   541  
   542  	checkFindings(t, "function-docstring-return", `
   543  def f(x):
   544     """This is a function.
   545  
   546     Args:
   547       x: something
   548     """
   549     def g(y):
   550        return y
   551  
   552     pass
   553     pass
   554     pass
   555     pass
   556     pass
   557  `,
   558  		[]string{},
   559  		scopeEverywhere)
   560  
   561  	checkFindings(t, "function-docstring-return", `
   562  def f(x):
   563     """This is a function.
   564  
   565     Args:
   566       x: something
   567     """
   568     pass
   569     pass
   570     pass
   571     pass
   572     pass
   573     return x
   574  `,
   575  		[]string{`2: Return value of "f" is not documented.`},
   576  		scopeEverywhere)
   577  
   578  	checkFindings(t, "function-docstring-return", `
   579  def f():
   580    def g(x):
   581      """This is a function.
   582  
   583      Args:
   584        x: something
   585      """
   586      pass
   587      pass
   588      pass
   589      pass
   590      pass
   591      return x
   592    return g
   593  `,
   594  		[]string{},
   595  		scopeEverywhere)
   596  
   597  	checkFindings(t, "function-docstring-return", `
   598  def f(x):
   599     """This is a function.
   600  
   601     Args:
   602       x: something
   603     """
   604     pass
   605     pass
   606     pass
   607     pass
   608     pass
   609     if foo:
   610       return
   611     else:
   612       return x
   613  `,
   614  		[]string{`2: Return value of "f" is not documented.`},
   615  		scopeEverywhere)
   616  }
   617  

View as plain text