blob: 930eac2425e361992b80edbbfc6dacdee2754c04 [file] [log] [blame] [edit]
/*
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package warn
import "testing"
func TestModuleDocstring(t *testing.T) {
checkFindings(t, "module-docstring", ``,
[]string{},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
# empty file`,
[]string{},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
"""This is the module"""
load("foo", "bar")
bar()`,
[]string{},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
load("foo", "bar")
"""This is the module"""
bar()`,
[]string{":1: The file has no module docstring."},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
# comment
# comment
"""This is the module"""
load("foo", "bar")
bar()`,
[]string{},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
# comment
load("foo", "bar")
# comment
"""This is the module"""
bar()`,
[]string{":3: The file has no module docstring."},
scopeBzl|scopeDefault)
checkFindings(t, "module-docstring", `
def foo(bar):
if bar:
f()
return g()`,
[]string{":1: The file has no module docstring."},
scopeBzl|scopeDefault)
}
func TestFunctionDocstringExists(t *testing.T) {
checkFindings(t, "function-docstring", `
def f(x):
# short function
return x
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring", `
def f(x):
"""Short function with a docstring"""
return x
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring", `
def f(x):
# long function
x += 1
x *= 2
x /= 3
x -= 4
x %= 5
return x
`,
[]string{":1: The function \"f\" has no docstring."},
scopeEverywhere)
checkFindings(t, "function-docstring", `
def f(x):
def g(x):
# long function
x += 1
x *= 2
x /= 3
x -= 4
x %= 5
return x
return g
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring", `
def _f(x):
# long private function
x += 1
x *= 2
x /= 3
x -= 4
x %= 5
return x
`,
[]string{},
scopeEverywhere)
}
func TestFunctionDocstringHeader(t *testing.T) {
checkFindings(t, "function-docstring-header", `
def f():
"""This is a function.
this is the description
"""
pass
pass
pass
pass
pass
`,
[]string{`2: The docstring for the function "f" should start with a one-line summary.`},
scopeEverywhere)
checkFindings(t, "function-docstring-header", `
def f():
def g():
"""This is a function.
this is the description
"""
pass
pass
pass
pass
pass
return f
`,
[]string{`3: The docstring for the function "g" should start with a one-line summary.`},
scopeEverywhere)
checkFindings(t, "function-docstring-header", `
def _f(x):
"""Long private function
with a docstring"""
x += 1
x *= 2
x /= 3
x -= 4
x %= 5
return x
`,
[]string{
`:2: The docstring for the function "_f" should start with a one-line summary.`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-header", `
def f(x):
"""Long function with a docstring
Docstring
body
"""
x += 1
x *= 2
x /= 3
x -= 4
x %= 5
return x
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-header", `
def f():
"""
This is a function.
This is a
multiline description"""
pass
pass
pass
pass
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-header", `
def f():
"""\r
Header in a CRLF formatted file.\r
\r
This is a\r
multiline description"""
`,
[]string{},
scopeEverywhere)
}
func TestFunctionDocstringArgs(t *testing.T) {
checkFindings(t, "function-docstring-args", `
def f(x):
"""This is a function.
Documented here:
http://example.com
Args:
x: something, as described at
http://example.com
Returns:
something, as described at
https://example.com
"""
pass
pass
pass
pass
pass
return x
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x):
"""This is a function.
Args:
x: something
"""
passf
pass
pass
pass
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x, y):
"""Short function with a docstring
Arguments:
x: smth
"""
return x + y
`,
[]string{
`2: Argument "y" is not documented.`,
`4: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f():
def g(x, y):
"""Short function with a docstring
Arguments:
x: smth
"""
return x + y
return g
`,
[]string{
`3: Argument "y" is not documented.`,
`5: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f():
def g(x, y):
"""Short function with a docstring
"""
return x + y
return g
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def _f(x, y):
"""Long private function
Args:
x: something
z: something
"""
x *= 2
x /= 3
x -= 4
x %= 5
return x
`,
[]string{
`:2: Argument "y" is not documented.`,
`:6: Argument "z" is documented but doesn't exist in the function signature.`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x, y):
"""This is a function.
Arguments:
x: something
y: something (this is in fact the description of x continued)
z: something else
Returns:
None
"""
pass
pass
pass
pass
pass
`,
[]string{
`2: Argument "y" is not documented.`,
`4: Prefer "Args:" to "Arguments:" when documenting function arguments.`,
`7: Argument "z" is documented but doesn't exist in the function signature.`,
}, scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def my_function(x, y, z = None, *args, **kwargs):
"""This is a function.
"""
pass
pass
pass
pass
pass
`,
[]string{
`2: Arguments "x", "y", "z", "*args", "**kwargs" are not documented.
If the documentation for the arguments exists but is not recognized by Buildifier
make sure it follows the line "Args:" which has the same indentation as the opening """,
and the argument description starts with "<argument_name>:" and indented with at least
one (preferably two) space more than "Args:", for example:
def my_function(x):
"""Function description.
Args:
x: argument description, can be
multiline with additional indentation.
"""`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x, y, z = None, *args, **kwargs):
"""This is a function.
Args:
x (Map[string, int]): x
y (deprecated, mutable): y
z: z
*args (List<string>): the args
**kwargs: the kwargs
"""
pass
pass
pass
pass
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x, *, y, z = None):
"""This is a function.
Args:
x: x
y: y
z: z
"""
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x, *, y, z = None):
"""This is a function.
Args:
x: x
*: a separator
y: y
: argument without a name
z: z
"""
pass
`,
[]string{
`6: Argument "*" is documented but doesn't exist in the function signature.`,
`8: Argument "" is documented but doesn't exist in the function signature.`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x):
"""
This is a function.
Args:
The function signature is extremely complicated
x: something
Returns:
nothing
"""
pass
pass
pass
pass
pass
return None
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(foobar, *bar, **baz):
"""Some function
Args:
foobar: something
foo: something
bar: something
baz: something
"""
pass
`,
[]string{
`:2: Arguments "*bar", "**baz" are not documented.`,
`:6: Argument "foo" is documented but doesn't exist in the function signature.`,
`:7: Argument "bar" is documented but doesn't exist in the function signature. Do you mean "*bar"?`,
`:8: Argument "baz" is documented but doesn't exist in the function signature. Do you mean "**baz"?`,
},
scopeEverywhere)
checkFindings(t, "function-docstring-args", `
def f(x: int, y: str, z: bool = False, *, *bar: List[int], **baz: Mapping[str, bool]):
"""Some function
Args:
x: something
t: something
"""
pass
`,
[]string{
`:2: Arguments "y", "z", "*bar", "**baz" are not documented.`,
`:6: Argument "t" is documented but doesn't exist in the function signature.`,
},
scopeEverywhere)
}
func TestFunctionDocstringReturn(t *testing.T) {
checkFindings(t, "function-docstring-return", `
def f(x):
"""This is a function.
Args:
x: something
Returns:
something
"""
pass
pass
pass
pass
pass
return x
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-return", `
def f(x):
"""This is a function.
Args:
x: something
"""
pass
pass
pass
pass
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-return", `
def f(x):
"""This is a function.
Args:
x: something
"""
def g(y):
return y
pass
pass
pass
pass
pass
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-return", `
def f(x):
"""This is a function.
Args:
x: something
"""
pass
pass
pass
pass
pass
return x
`,
[]string{`2: Return value of "f" is not documented.`},
scopeEverywhere)
checkFindings(t, "function-docstring-return", `
def f():
def g(x):
"""This is a function.
Args:
x: something
"""
pass
pass
pass
pass
pass
return x
return g
`,
[]string{},
scopeEverywhere)
checkFindings(t, "function-docstring-return", `
def f(x):
"""This is a function.
Args:
x: something
"""
pass
pass
pass
pass
pass
if foo:
return
else:
return x
`,
[]string{`2: Return value of "f" is not documented.`},
scopeEverywhere)
}