Skip to content

Commit

Permalink
add tests for style checking script implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
rmehri01 committed Jan 2, 2025
1 parent ecc0722 commit c9c4ad0
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 66 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ target
Cargo.lock
*~
style
!style/
7 changes: 6 additions & 1 deletion libc-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,10 @@ harness = true

[[test]]
name = "style"
path = "test/style.rs"
path = "test/check_style.rs"
harness = true

[[test]]
name = "style_tests"
path = "test/style_tests.rs"
harness = true
63 changes: 63 additions & 0 deletions libc-test/test/check_style.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Simple script to verify the coding style of this library
//!
//! ## How to run
//!
//! The first argument to this script is the directory to run on, so running
//! this script should be as simple as:
//!
//! ```notrust
//! cargo test --test style
//! ```
//!
//! ## Guidelines
//!
//! The current style is:
//!
//! * Specific module layout:
//! 1. use directives
//! 2. typedefs
//! 3. structs
//! 4. constants
//! 5. f! { ... } functions
//! 6. extern functions
//! 7. modules + pub use
pub mod style;

use std::env;
use std::path::Path;

use style::{Result, StyleChecker};

#[test]
fn check_style() {
let root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../src");
walk(&root_dir).unwrap();
eprintln!("good style!");
}

fn walk(root_dir: &Path) -> Result<()> {
let mut style_checker = StyleChecker::new();

for entry in glob::glob(&format!(
"{}/**/*.rs",
root_dir.to_str().expect("dir should be valid UTF-8")
))? {
let entry = entry?;

let name = entry
.file_name()
.expect("file name should not end in ..")
.to_str()
.expect("file name should be valid UTF-8");
if let "lib.rs" | "macros.rs" = &name[..] {
continue;
}

let path = entry.as_path();
style_checker.check_file(path)?;
style_checker.reset_state();
}

style_checker.finalize()
}
82 changes: 17 additions & 65 deletions libc-test/test/style.rs → libc-test/test/style/mod.rs
Original file line number Diff line number Diff line change
@@ -1,75 +1,24 @@
//! Simple script to verify the coding style of this library
//! Provides the [StyleChecker] visitor to verify the coding style of
//! this library.
//!
//! ## How to run
//!
//! The first argument to this script is the directory to run on, so running
//! this script should be as simple as:
//!
//! ```notrust
//! cargo test --test style
//! ```
//!
//! ## Guidelines
//!
//! The current style is:
//!
//! * Specific module layout:
//! 1. use directives
//! 2. typedefs
//! 3. structs
//! 4. constants
//! 5. f! { ... } functions
//! 6. extern functions
//! 7. modules + pub use
//! This is split out so that the implementation itself can be tested
//! separately, see test/check_style.rs for how it's used.
use std::fmt::Display;
use std::fs;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::{env, fs};

use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::visit::{self, Visit};
use syn::Token;

type Error = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, Error>;

#[test]
fn check_style() {
let root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../src");
walk(&root_dir).unwrap();
eprintln!("good style!");
}

fn walk(root_dir: &Path) -> Result<()> {
let mut style_checker = StyleChecker::new();

for entry in glob::glob(&format!(
"{}/**/*.rs",
root_dir.to_str().expect("dir should be valid UTF-8")
))? {
let entry = entry?;

let name = entry
.file_name()
.expect("file name should not end in ..")
.to_str()
.expect("file name should be valid UTF-8");
if let "lib.rs" | "macros.rs" = &name[..] {
continue;
}

let path = entry.as_path();
style_checker.check_file(path)?;
style_checker.reset_state();
}

style_checker.finalize()
}
pub type Error = Box<dyn std::error::Error>;
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Default)]
struct StyleChecker {
pub struct StyleChecker {
state: State,
// FIXME: see StyleChecker::set_state
_s_macros: usize,
Expand Down Expand Up @@ -106,32 +55,35 @@ enum ExprCfgElse {
}

impl StyleChecker {
fn new() -> Self {
pub fn new() -> Self {
Self::default()
}

/// Reads and parses the file at the given path and checks
/// for any style violations.
fn check_file(&mut self, path: &Path) -> Result<()> {
pub fn check_file(&mut self, path: &Path) -> Result<()> {
let contents = fs::read_to_string(path)?;
let file = syn::parse_file(&contents)?;

self.path = PathBuf::from(path);
self.visit_file(&file);
self.check_string(contents)
}

pub fn check_string(&mut self, contents: String) -> Result<()> {
let file = syn::parse_file(&contents)?;
self.visit_file(&file);
Ok(())
}

/// Resets the state of the [StyleChecker].
fn reset_state(&mut self) {
pub fn reset_state(&mut self) {
*self = Self {
errors: std::mem::take(&mut self.errors),
..Self::default()
};
}

/// Collect all errors into a single error, reporting them if any.
fn finalize(self) -> Result<()> {
pub fn finalize(self) -> Result<()> {
if self.errors.is_empty() {
return Ok(());
}
Expand Down
157 changes: 157 additions & 0 deletions libc-test/test/style_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//! Verifies the implementation of the style checker in [style]
use style::StyleChecker;

pub mod style;

#[test]
fn correct_module_layout() {
let contents = r#"
use core::mem::size_of;
pub type foo_t = u32;
struct Foo {}
pub const FOO: u32 = 0x20000;
f! {}
extern "C" {}
mod foolib;
pub use self::foolib::*;
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
checker.finalize().unwrap();
}

#[test]
fn incorrect_module_layout() {
let contents = r#"
use core::mem::size_of;
pub type foo_t = u32;
struct Foo {}
pub const FOO: u32 = 0x20000;
extern "C" {}
f! {}
mod foolib;
pub use self::foolib::*;
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

#[test]
fn incorrect_cfg_if_layout() {
let contents = r#"
cfg_if! {
if #[cfg(foo)] {
pub type foo_t = u32;
use core::mem::size_of;
}
}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

#[test]
fn cfg_if_branch_resets_state() {
let contents = r#"
cfg_if! {
if #[cfg(foo)] {
use core::mem::size_of;
pub type foo_t = u32;
} else {
use core::mem::align_of;
}
}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
checker.finalize().unwrap();
}

#[test]
fn multiple_f_macros() {
let contents = r#"
f! {}
f! {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

#[test]
fn cfg_if_over_cfg() {
let contents = r#"
#[cfg(foo)]
pub struct Foo {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

#[test]
fn cfg_if_ignore_target_arch() {
let contents = r#"
#[cfg(target_arch = "x86")]
pub struct Foo {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
checker.finalize().unwrap();
}

#[test]
fn cfg_if_ignore_target_endian_nested() {
let contents = r#"
#[cfg(all(target_endian = "little"))]
pub struct Foo {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
checker.finalize().unwrap();
}

#[test]
fn manual_copy() {
let contents = r#"
#[derive(Copy)]
pub struct Foo {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

#[test]
fn manual_clone() {
let contents = r#"
#[derive(Clone)]
pub struct Foo {}
"#
.to_string();

let mut checker = StyleChecker::new();
checker.check_string(contents).unwrap();
assert!(checker.finalize().is_err());
}

0 comments on commit c9c4ad0

Please sign in to comment.