Avoid assert() to assert statement conversion in expressions (#3062)

This commit is contained in:
Charlie Marsh 2023-02-20 12:49:22 -05:00 committed by GitHub
parent d21dd994e6
commit 41f163fc8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 83 deletions

View file

@ -17,6 +17,12 @@ class Test(unittest.TestCase):
self.assertTrue(**{"expr": expr, "msg": msg}) # Error, unfixable self.assertTrue(**{"expr": expr, "msg": msg}) # Error, unfixable
self.assertTrue(msg=msg, expr=expr, unexpected_arg=False) # Error, unfixable self.assertTrue(msg=msg, expr=expr, unexpected_arg=False) # Error, unfixable
self.assertTrue(msg=msg) # Error, unfixable self.assertTrue(msg=msg) # Error, unfixable
(
self.assertIsNotNone(value) # Error, unfixable
if expect_condition
else self.assertIsNone(value) # Error, unfixable
)
return self.assertEqual(True, False) # Error, unfixable
def test_assert_false(self): def test_assert_false(self):
self.assertFalse(True) # Error self.assertFalse(True) # Error

View file

@ -12,7 +12,7 @@ use crate::checkers::ast::Checker;
use crate::fix::Fix; use crate::fix::Fix;
use crate::registry::Diagnostic; use crate::registry::Diagnostic;
use crate::source_code::Stylist; use crate::source_code::Stylist;
use crate::violation::{AlwaysAutofixableViolation, AutofixKind, Availability, Violation}; use crate::violation::{AutofixKind, Availability, Violation};
use super::helpers::is_falsy_constant; use super::helpers::is_falsy_constant;
use super::unittest_assert::UnittestAssert; use super::unittest_assert::UnittestAssert;
@ -94,18 +94,23 @@ impl Violation for AssertAlwaysFalse {
define_violation!( define_violation!(
pub struct UnittestAssertion { pub struct UnittestAssertion {
pub assertion: String, pub assertion: String,
pub fixable: bool,
} }
); );
impl AlwaysAutofixableViolation for UnittestAssertion { impl Violation for UnittestAssertion {
const AUTOFIX: Option<AutofixKind> = Some(AutofixKind::new(Availability::Sometimes));
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
let UnittestAssertion { assertion } = self; let UnittestAssertion { assertion, .. } = self;
format!("Use a regular `assert` instead of unittest-style `{assertion}`") format!("Use a regular `assert` instead of unittest-style `{assertion}`")
} }
fn autofix_title(&self) -> String { fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {
let UnittestAssertion { assertion } = self; self.fixable
format!("Replace `{assertion}(...)` with `assert ...`") .then_some(|UnittestAssertion { assertion, .. }| {
format!("Replace `{assertion}(...)` with `assert ...`")
})
} }
} }
@ -181,13 +186,18 @@ pub fn unittest_assertion(
match &func.node { match &func.node {
ExprKind::Attribute { attr, .. } => { ExprKind::Attribute { attr, .. } => {
if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) { if let Ok(unittest_assert) = UnittestAssert::try_from(attr.as_str()) {
// We're converting an expression to a statement, so avoid applying the fix if
// the assertion is part of a larger expression.
let fixable = checker.current_expr_parent().is_none()
&& matches!(checker.current_stmt().node, StmtKind::Expr { .. });
let mut diagnostic = Diagnostic::new( let mut diagnostic = Diagnostic::new(
UnittestAssertion { UnittestAssertion {
assertion: unittest_assert.to_string(), assertion: unittest_assert.to_string(),
fixable,
}, },
Range::from_located(func), Range::from_located(func),
); );
if checker.patch(diagnostic.kind.rule()) { if fixable && checker.patch(diagnostic.kind.rule()) {
if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) { if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) {
diagnostic.amend(Fix::replacement( diagnostic.amend(Fix::replacement(
unparse_stmt(&stmt, checker.stylist), unparse_stmt(&stmt, checker.stylist),

View file

@ -5,6 +5,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 11 row: 11
column: 8 column: 8
@ -24,6 +25,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 12 row: 12
column: 8 column: 8
@ -43,6 +45,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 13 row: 13
column: 8 column: 8
@ -62,6 +65,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 14 row: 14
column: 8 column: 8
@ -81,6 +85,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 15 row: 15
column: 8 column: 8
@ -100,6 +105,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 16 row: 16
column: 8 column: 8
@ -111,6 +117,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 17 row: 17
column: 8 column: 8
@ -122,6 +129,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 18 row: 18
column: 8 column: 8
@ -133,6 +141,7 @@ expression: diagnostics
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertTrue assertion: assertTrue
fixable: true
location: location:
row: 19 row: 19
column: 8 column: 8
@ -141,365 +150,420 @@ expression: diagnostics
column: 23 column: 23
fix: ~ fix: ~
parent: ~ parent: ~
- kind:
UnittestAssertion:
assertion: assertIsNotNone
fixable: false
location:
row: 21
column: 12
end_location:
row: 21
column: 32
fix: ~
parent: ~
- kind:
UnittestAssertion:
assertion: assertIsNone
fixable: false
location:
row: 23
column: 17
end_location:
row: 23
column: 34
fix: ~
parent: ~
- kind:
UnittestAssertion:
assertion: assertEqual
fixable: false
location:
row: 25
column: 15
end_location:
row: 25
column: 31
fix: ~
parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertFalse assertion: assertFalse
fixable: true
location: location:
row: 22 row: 28
column: 8 column: 8
end_location: end_location:
row: 22 row: 28
column: 24 column: 24
fix: fix:
content: content:
- assert not True - assert not True
location: location:
row: 22 row: 28
column: 8 column: 8
end_location: end_location:
row: 22 row: 28
column: 30 column: 30
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertEqual assertion: assertEqual
fixable: true
location: location:
row: 25 row: 31
column: 8 column: 8
end_location: end_location:
row: 25 row: 31
column: 24 column: 24
fix: fix:
content: content:
- assert 1 == 2 - assert 1 == 2
location: location:
row: 25 row: 31
column: 8 column: 8
end_location: end_location:
row: 25 row: 31
column: 30 column: 30
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertNotEqual assertion: assertNotEqual
fixable: true
location: location:
row: 28 row: 34
column: 8 column: 8
end_location: end_location:
row: 28 row: 34
column: 27 column: 27
fix: fix:
content: content:
- assert 1 != 1 - assert 1 != 1
location: location:
row: 28 row: 34
column: 8 column: 8
end_location: end_location:
row: 28 row: 34
column: 33 column: 33
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertGreater assertion: assertGreater
fixable: true
location: location:
row: 31 row: 37
column: 8 column: 8
end_location: end_location:
row: 31 row: 37
column: 26 column: 26
fix: fix:
content: content:
- assert 1 > 2 - assert 1 > 2
location: location:
row: 31 row: 37
column: 8 column: 8
end_location: end_location:
row: 31 row: 37
column: 32 column: 32
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertGreaterEqual assertion: assertGreaterEqual
fixable: true
location: location:
row: 34 row: 40
column: 8 column: 8
end_location: end_location:
row: 34 row: 40
column: 31 column: 31
fix: fix:
content: content:
- assert 1 >= 2 - assert 1 >= 2
location: location:
row: 34 row: 40
column: 8 column: 8
end_location: end_location:
row: 34 row: 40
column: 37 column: 37
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertLess assertion: assertLess
fixable: true
location: location:
row: 37 row: 43
column: 8 column: 8
end_location: end_location:
row: 37 row: 43
column: 23 column: 23
fix: fix:
content: content:
- assert 2 < 1 - assert 2 < 1
location: location:
row: 37 row: 43
column: 8 column: 8
end_location: end_location:
row: 37 row: 43
column: 29 column: 29
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertLessEqual assertion: assertLessEqual
fixable: true
location: location:
row: 40 row: 46
column: 8 column: 8
end_location: end_location:
row: 40 row: 46
column: 28 column: 28
fix: fix:
content: content:
- assert 1 <= 2 - assert 1 <= 2
location: location:
row: 40 row: 46
column: 8 column: 8
end_location: end_location:
row: 40 row: 46
column: 34 column: 34
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIn assertion: assertIn
fixable: true
location: location:
row: 43 row: 49
column: 8 column: 8
end_location: end_location:
row: 43 row: 49
column: 21 column: 21
fix: fix:
content: content:
- "assert 1 in [2, 3]" - "assert 1 in [2, 3]"
location: location:
row: 43 row: 49
column: 8 column: 8
end_location: end_location:
row: 43 row: 49
column: 32 column: 32
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertNotIn assertion: assertNotIn
fixable: true
location: location:
row: 46 row: 52
column: 8 column: 8
end_location: end_location:
row: 46 row: 52
column: 24 column: 24
fix: fix:
content: content:
- "assert 2 not in [2, 3]" - "assert 2 not in [2, 3]"
location: location:
row: 46 row: 52
column: 8 column: 8
end_location: end_location:
row: 46 row: 52
column: 35 column: 35
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIsNone assertion: assertIsNone
fixable: true
location: location:
row: 49 row: 55
column: 8 column: 8
end_location: end_location:
row: 49 row: 55
column: 25 column: 25
fix: fix:
content: content:
- assert 0 is None - assert 0 is None
location: location:
row: 49 row: 55
column: 8 column: 8
end_location: end_location:
row: 49 row: 55
column: 28 column: 28
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIsNotNone assertion: assertIsNotNone
fixable: true
location: location:
row: 52 row: 58
column: 8 column: 8
end_location: end_location:
row: 52 row: 58
column: 28 column: 28
fix: fix:
content: content:
- assert 0 is not None - assert 0 is not None
location: location:
row: 52 row: 58
column: 8 column: 8
end_location: end_location:
row: 52 row: 58
column: 31 column: 31
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIs assertion: assertIs
fixable: true
location: location:
row: 55 row: 61
column: 8 column: 8
end_location: end_location:
row: 55 row: 61
column: 21 column: 21
fix: fix:
content: content:
- "assert [] is []" - "assert [] is []"
location: location:
row: 55 row: 61
column: 8 column: 8
end_location: end_location:
row: 55 row: 61
column: 29 column: 29
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIsNot assertion: assertIsNot
fixable: true
location: location:
row: 58 row: 64
column: 8 column: 8
end_location: end_location:
row: 58 row: 64
column: 24 column: 24
fix: fix:
content: content:
- assert 1 is not 1 - assert 1 is not 1
location: location:
row: 58 row: 64
column: 8 column: 8
end_location: end_location:
row: 58 row: 64
column: 30 column: 30
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertIsInstance assertion: assertIsInstance
fixable: true
location: location:
row: 61 row: 67
column: 8 column: 8
end_location: end_location:
row: 61 row: 67
column: 29 column: 29
fix: fix:
content: content:
- "assert isinstance(1, str)" - "assert isinstance(1, str)"
location: location:
row: 61 row: 67
column: 8 column: 8
end_location: end_location:
row: 61 row: 67
column: 37 column: 37
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertNotIsInstance assertion: assertNotIsInstance
fixable: true
location: location:
row: 64 row: 70
column: 8 column: 8
end_location: end_location:
row: 64 row: 70
column: 32 column: 32
fix: fix:
content: content:
- "assert not isinstance(1, int)" - "assert not isinstance(1, int)"
location: location:
row: 64 row: 70
column: 8 column: 8
end_location: end_location:
row: 64 row: 70
column: 40 column: 40
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertRegex assertion: assertRegex
fixable: true
location: location:
row: 67 row: 73
column: 8 column: 8
end_location: end_location:
row: 67 row: 73
column: 24 column: 24
fix: fix:
content: content:
- "assert re.search(\"def\", \"abc\")" - "assert re.search(\"def\", \"abc\")"
location: location:
row: 67 row: 73
column: 8 column: 8
end_location: end_location:
row: 67 row: 73
column: 39 column: 39
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertNotRegex assertion: assertNotRegex
fixable: true
location: location:
row: 70 row: 76
column: 8 column: 8
end_location: end_location:
row: 70 row: 76
column: 27 column: 27
fix: fix:
content: content:
- "assert not re.search(\"abc\", \"abc\")" - "assert not re.search(\"abc\", \"abc\")"
location: location:
row: 70 row: 76
column: 8 column: 8
end_location: end_location:
row: 70 row: 76
column: 42 column: 42
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertRegexpMatches assertion: assertRegexpMatches
fixable: true
location: location:
row: 73 row: 79
column: 8 column: 8
end_location: end_location:
row: 73 row: 79
column: 32 column: 32
fix: fix:
content: content:
- "assert re.search(\"def\", \"abc\")" - "assert re.search(\"def\", \"abc\")"
location: location:
row: 73 row: 79
column: 8 column: 8
end_location: end_location:
row: 73 row: 79
column: 47 column: 47
parent: ~ parent: ~
- kind: - kind:
UnittestAssertion: UnittestAssertion:
assertion: assertNotRegex assertion: assertNotRegex
fixable: true
location: location:
row: 76 row: 82
column: 8 column: 8
end_location: end_location:
row: 76 row: 82
column: 27 column: 27
fix: fix:
content: content:
- "assert not re.search(\"abc\", \"abc\")" - "assert not re.search(\"abc\", \"abc\")"
location: location:
row: 76 row: 82
column: 8 column: 8
end_location: end_location:
row: 76 row: 82
column: 42 column: 42
parent: ~ parent: ~