mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 14:52:01 +00:00
Add unit tests for linter (#9)
This commit is contained in:
parent
52afc02023
commit
4a67c8d44b
10 changed files with 168 additions and 18 deletions
22
.github/workflows/ci.yaml
vendored
22
.github/workflows/ci.yaml
vendored
|
@ -73,6 +73,28 @@ jobs:
|
||||||
${{ runner.os }}-
|
${{ runner.os }}-
|
||||||
- run: cargo clippy -- -D warnings
|
- run: cargo clippy -- -D warnings
|
||||||
|
|
||||||
|
cargo_test:
|
||||||
|
name: "cargo test"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
env:
|
||||||
|
cache-name: cache-cargo
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
${{ runner.os }}-
|
||||||
|
- run: cargo test
|
||||||
|
|
||||||
maturin_build:
|
maturin_build:
|
||||||
name: "maturin build"
|
name: "maturin build"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
10
resources/test/src/duplicate_argument_name.py
Normal file
10
resources/test/src/duplicate_argument_name.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
def foo(x: int, y: int, x: int) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def bar(x: int, y: int, *, x: int) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def baz(x: int, y: int, **x: int) -> None:
|
||||||
|
pass
|
|
@ -1,5 +0,0 @@
|
||||||
from bar import *
|
|
||||||
|
|
||||||
|
|
||||||
def baz(x: int, x: int) -> None:
|
|
||||||
pass
|
|
|
@ -4,5 +4,5 @@ if (1, 2):
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
if True:
|
if True:
|
||||||
pass
|
pass
|
||||||
elif (1, 2):
|
elif (3, 4):
|
||||||
pass
|
pass
|
1
resources/test/src/import_star_usage.py
Normal file
1
resources/test/src/import_star_usage.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from if_tuple import *
|
|
@ -2,19 +2,14 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use rustpython_parser::ast::{Arg, Arguments, ExprKind, Stmt, StmtKind, Suite};
|
use rustpython_parser::ast::{Arg, Arguments, ExprKind, Stmt, StmtKind, Suite};
|
||||||
|
|
||||||
use crate::check::{Check, CheckKind};
|
use crate::checks::{Check, CheckKind};
|
||||||
use crate::visitor::{walk_arguments, walk_stmt, Visitor};
|
use crate::visitor::{walk_arguments, walk_stmt, Visitor};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct Checker {
|
struct Checker {
|
||||||
checks: Vec<Check>,
|
checks: Vec<Check>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Checker {
|
|
||||||
fn new() -> Self {
|
|
||||||
Checker { checks: vec![] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Visitor for Checker {
|
impl Visitor for Checker {
|
||||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
|
@ -79,9 +74,46 @@ pub fn check_ast(python_ast: &Suite) -> Vec<Check> {
|
||||||
python_ast
|
python_ast
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|stmt| {
|
.flat_map(|stmt| {
|
||||||
let mut checker = Checker::new();
|
let mut checker: Checker = Default::default();
|
||||||
checker.visit_stmt(stmt);
|
checker.visit_stmt(stmt);
|
||||||
checker.checks
|
checker.checks
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rustpython_parser::ast::{Alias, Location, Stmt, StmtKind};
|
||||||
|
|
||||||
|
use crate::checker::Checker;
|
||||||
|
use crate::checks::Check;
|
||||||
|
use crate::checks::CheckKind::ImportStarUsage;
|
||||||
|
use crate::visitor::Visitor;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_star_usage() {
|
||||||
|
let mut checker: Checker = Default::default();
|
||||||
|
checker.visit_stmt(&Stmt {
|
||||||
|
location: Location::new(1, 1),
|
||||||
|
custom: (),
|
||||||
|
node: StmtKind::ImportFrom {
|
||||||
|
module: Some("bar".to_string()),
|
||||||
|
names: vec![Alias {
|
||||||
|
name: "*".to_string(),
|
||||||
|
asname: None,
|
||||||
|
}],
|
||||||
|
level: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let actual = checker.checks;
|
||||||
|
let expected = vec![Check {
|
||||||
|
kind: ImportStarUsage,
|
||||||
|
location: Location::new(1, 1),
|
||||||
|
}];
|
||||||
|
assert_eq!(actual.len(), expected.len());
|
||||||
|
for i in 1..actual.len() {
|
||||||
|
assert_eq!(actual[i], expected[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum CheckKind {
|
pub enum CheckKind {
|
||||||
DuplicateArgumentName,
|
DuplicateArgumentName,
|
||||||
ImportStarUsage,
|
ImportStarUsage,
|
||||||
|
@ -28,6 +28,7 @@ impl CheckKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Check {
|
pub struct Check {
|
||||||
pub kind: CheckKind,
|
pub kind: CheckKind,
|
||||||
pub location: Location,
|
pub location: Location,
|
|
@ -1,6 +1,6 @@
|
||||||
mod cache;
|
mod cache;
|
||||||
mod check;
|
|
||||||
pub mod checker;
|
pub mod checker;
|
||||||
|
mod checks;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod linter;
|
pub mod linter;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
|
|
|
@ -28,3 +28,92 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
|
||||||
|
|
||||||
Ok(messages)
|
Ok(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use rustpython_parser::ast::Location;
|
||||||
|
|
||||||
|
use crate::cache;
|
||||||
|
use crate::checks::CheckKind::{DuplicateArgumentName, IfTuple, ImportStarUsage};
|
||||||
|
use crate::linter::check_path;
|
||||||
|
use crate::message::Message;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn duplicate_argument_name() -> Result<()> {
|
||||||
|
let actual = check_path(
|
||||||
|
&Path::new("./resources/test/src/duplicate_argument_name.py"),
|
||||||
|
&cache::Mode::None,
|
||||||
|
)?;
|
||||||
|
let expected = vec![
|
||||||
|
Message {
|
||||||
|
kind: DuplicateArgumentName,
|
||||||
|
location: Location::new(1, 25),
|
||||||
|
filename: "./resources/test/src/duplicate_argument_name.py".to_string(),
|
||||||
|
},
|
||||||
|
Message {
|
||||||
|
kind: DuplicateArgumentName,
|
||||||
|
location: Location::new(5, 9),
|
||||||
|
filename: "./resources/test/src/duplicate_argument_name.py".to_string(),
|
||||||
|
},
|
||||||
|
Message {
|
||||||
|
kind: DuplicateArgumentName,
|
||||||
|
location: Location::new(9, 27),
|
||||||
|
filename: "./resources/test/src/duplicate_argument_name.py".to_string(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
assert_eq!(actual.len(), expected.len());
|
||||||
|
for i in 1..actual.len() {
|
||||||
|
assert_eq!(actual[i], expected[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_tuple() -> Result<()> {
|
||||||
|
let actual = check_path(
|
||||||
|
&Path::new("./resources/test/src/if_tuple.py"),
|
||||||
|
&cache::Mode::None,
|
||||||
|
)?;
|
||||||
|
let expected = vec![
|
||||||
|
Message {
|
||||||
|
kind: IfTuple,
|
||||||
|
location: Location::new(1, 1),
|
||||||
|
filename: "./resources/test/src/if_tuple.py".to_string(),
|
||||||
|
},
|
||||||
|
Message {
|
||||||
|
kind: IfTuple,
|
||||||
|
location: Location::new(7, 5),
|
||||||
|
filename: "./resources/test/src/if_tuple.py".to_string(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
assert_eq!(actual.len(), expected.len());
|
||||||
|
for i in 1..actual.len() {
|
||||||
|
assert_eq!(actual[i], expected[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_star_usage() -> Result<()> {
|
||||||
|
let actual = check_path(
|
||||||
|
&Path::new("./resources/test/src/import_star_usage.py"),
|
||||||
|
&cache::Mode::None,
|
||||||
|
)?;
|
||||||
|
let expected = vec![Message {
|
||||||
|
kind: ImportStarUsage,
|
||||||
|
location: Location::new(1, 1),
|
||||||
|
filename: "./resources/test/src/import_star_usage.py".to_string(),
|
||||||
|
}];
|
||||||
|
assert_eq!(actual.len(), expected.len());
|
||||||
|
for i in 1..actual.len() {
|
||||||
|
assert_eq!(actual[i], expected[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use colored::Colorize;
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::check::CheckKind;
|
use crate::checks::CheckKind;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "Location")]
|
#[serde(remote = "Location")]
|
||||||
|
@ -21,7 +21,7 @@ impl From<LocationDef> for Location {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
pub kind: CheckKind,
|
pub kind: CheckKind,
|
||||||
#[serde(with = "LocationDef")]
|
#[serde(with = "LocationDef")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue