Skip to content

Commit

Permalink
Add unit tests for linter (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh authored Aug 13, 2022
1 parent 52afc02 commit 4a67c8d
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 18 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,28 @@ jobs:
${{ runner.os }}-
- 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:
name: "maturin build"
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions resources/test/src/duplicate_argument_name.py
Original file line number Diff line number Diff line change
@@ -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
5 changes: 0 additions & 5 deletions resources/test/src/foo.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
for _ in range(5):
if True:
pass
elif (1, 2):
elif (3, 4):
pass
1 change: 1 addition & 0 deletions resources/test/src/import_star_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from if_tuple import *
48 changes: 40 additions & 8 deletions src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@ use std::collections::HashSet;

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};

#[derive(Default)]
struct Checker {
checks: Vec<Check>,
}

impl Checker {
fn new() -> Self {
Checker { checks: vec![] }
}
}

impl Visitor for Checker {
fn visit_stmt(&mut self, stmt: &Stmt) {
match &stmt.node {
Expand Down Expand Up @@ -79,9 +74,46 @@ pub fn check_ast(python_ast: &Suite) -> Vec<Check> {
python_ast
.iter()
.flat_map(|stmt| {
let mut checker = Checker::new();
let mut checker: Checker = Default::default();
checker.visit_stmt(stmt);
checker.checks
})
.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]);
}
}
}
3 changes: 2 additions & 1 deletion src/check.rs → src/checks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CheckKind {
DuplicateArgumentName,
ImportStarUsage,
Expand All @@ -28,6 +28,7 @@ impl CheckKind {
}
}

#[derive(Debug, PartialEq, Eq)]
pub struct Check {
pub kind: CheckKind,
pub location: Location,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod cache;
mod check;
pub mod checker;
mod checks;
pub mod fs;
pub mod linter;
pub mod logging;
Expand Down
89 changes: 89 additions & 0 deletions src/linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,92 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {

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 changes: 2 additions & 2 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use colored::Colorize;
use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize};

use crate::check::CheckKind;
use crate::checks::CheckKind;

#[derive(Serialize, Deserialize)]
#[serde(remote = "Location")]
Expand All @@ -21,7 +21,7 @@ impl From<LocationDef> for Location {
}
}

#[derive(Serialize, Deserialize)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Message {
pub kind: CheckKind,
#[serde(with = "LocationDef")]
Expand Down

0 comments on commit 4a67c8d

Please sign in to comment.