Skip to content

Commit

Permalink
test: add unit tests for scope_enum rule
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Zaunseder committed Feb 7, 2024
1 parent 3d52fda commit 6417854
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 36 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ It's a project to learn Rust, so don't expect production ready code. If anybody
## Todos/Ideas:

1. Configuration system
2. Implement more rules (see [commitlint rules](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/rules/src))
2. Implement more rules (see [commitlint rules](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/rules/src) or [gitlint](https://jorisroovers.com/gitlint/latest/rules/builtin_rules/))
3. Implement unit tests for rules
4. Allow multiple lines in footer and parse references (like original commitlint)
5. Use and parse CLI args (probably with [Clap](https://docs.rs/clap/latest/clap/index.html))
Expand All @@ -17,4 +17,4 @@ It's a project to learn Rust, so don't expect production ready code. If anybody
9. Add devcontainer for easier getting started in VSCode
10. Benchmark against original [commitlint](https://github.com/conventional-changelog/commitlint)
11. Migration docs from original commitlint to commitlint-rs
12. Allow 3rd party rules? Maybe WASM?
12. Allow 3rd party rules? Maybe WASM?
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() -> ExitCode {
}

println!(
"You have {} warnings and {} errors",
"There are {} warnings and {} errors",
lint_result.warnings_len(),
lint_result.errors_len()
);
Expand Down
22 changes: 21 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct CommitSpan<'a> {
}

impl<'a> CommitSpan<'a> {
fn new(input: &'a str, start: usize, end: usize) -> Self {
pub fn new(input: &'a str, start: usize, end: usize) -> Self {
CommitSpan { input, start, end }
}

Expand Down Expand Up @@ -59,6 +59,26 @@ pub struct Commit<'a> {
pub raw: String,
}

impl Commit<'_> {
pub fn new() -> Self {
Commit {
header: CommitSpan::default(),
body: None,
footer: None,
commit_type: CommitSpan::default(),
scope: None,
subject: CommitSpan::default(),
raw: String::from(""),
}
}
}

impl Default for Commit<'_> {
fn default() -> Self {
Self::new()
}
}

pub fn parse_commit(commit_msg: &str) -> Commit {
let pairs = CommitParser::parse(Rule::commit, commit_msg).unwrap_or_else(|e| panic!("{}", e));
println!("{:#?}", pairs);
Expand Down
11 changes: 7 additions & 4 deletions src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,16 @@ enum TargetCase {

/// Options for all rules without options
#[derive(Debug, Deserialize)]
pub(crate) struct NoOpts(Severity, Condition);
pub struct NoOpts(Severity, Condition);
/// Options for all enum rules
type EnumOpts = (Severity, Condition, Vec<String>);
#[derive(Debug, Deserialize)]
pub struct EnumOpts(Severity, Condition, Vec<String>);
/// Options for all length rules
type LengthOpts = (Severity, usize);
#[derive(Debug, Deserialize)]
pub struct LengthOpts(Severity, usize);
/// Options for all case rules
type CaseOpts = (Severity, Condition, TargetCase);
#[derive(Debug, Deserialize)]
pub struct CaseOpts(Severity, Condition, TargetCase);

/// Config all the rules
#[derive(Debug, Deserialize)]
Expand Down
33 changes: 6 additions & 27 deletions src/rules/scope_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,8 @@ mod tests {

#[test]
fn test_empty_scope() {
let commit = Commit {
header: Default::default(),
body: None,
footer: None,
commit_type: Default::default(),
scope: None,
subject: Default::default(),
raw: String::from(""),
};
let mut commit: Commit<'_> = Default::default();
commit.scope = None;

// If the condition is `Never` and the scope is empty, the rule should return an error (read as "the scope should never be empty")
let rule = ScopeEmptyRule {
Expand All @@ -89,15 +82,8 @@ mod tests {

#[test]
fn test_filled_scope() {
let commit = Commit {
header: Default::default(),
body: None,
footer: None,
commit_type: Default::default(),
scope: Some(Default::default()),
subject: Default::default(),
raw: String::from(""),
};
let mut commit: Commit<'_> = Default::default();
commit.scope = Some(Default::default());

// If the condition is `Never` and the scope is filled, the rule should return `None` (read as "the scope should never be empty")
let rule = ScopeEmptyRule {
Expand All @@ -116,15 +102,8 @@ mod tests {

#[test]
fn test_severity_off() {
let commit = Commit {
header: Default::default(),
body: None,
footer: None,
commit_type: Default::default(),
scope: Some(Default::default()),
subject: Default::default(),
raw: String::from(""),
};
let mut commit: Commit<'_> = Default::default();
commit.scope = Some(Default::default());

// If the severity is `Off`, the rule should return `None`
let rule = ScopeEmptyRule {
Expand Down
125 changes: 124 additions & 1 deletion src/rules/scope_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl Rule for ScopeEnumRule {
let condition = &self.opts.1;
let scopes = &self.opts.2;

if severity == &Severity::Off {
if severity == &Severity::Off || scopes.is_empty() {
return None;
}

Expand Down Expand Up @@ -54,3 +54,126 @@ impl Rule for ScopeEnumRule {
None
}
}

#[cfg(test)]
mod tests {
use crate::parser::CommitSpan;

use super::*;

#[test]
fn test_empty_scope() {
let mut commit: Commit<'_> = Default::default();
commit.scope = None;

// If the scope is empty this rule behaves the same as it would be Severity::Off
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Never,
vec!["feat".to_string(), "fix".to_string()],
),
};

assert!(rule.run(&commit).is_none());

let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};

assert!(rule.run(&commit).is_none());
}

#[test]
fn test_never_condition() {
let mut commit: Commit<'_> = Default::default();

// If the condition is `Never` the scope should not be in the list of disallowed scopes
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Never,
vec!["feat".to_string(), "fix".to_string()],
),
};

// an empty scope is not disallowed, so return None
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());

// the scope "nice" is not disallowed, so return None
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());

// the scope "feat" is disallowed, so return a Report
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_some());
}

#[test]
fn test_always_condition() {
let mut commit: Commit<'_> = Default::default();

// If the condition is `Always` the scope must be in the list of allowed scopes
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Error,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};

// an empty scope is not allowed, so return a Report
commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_some());

// the scope "nice" is not allowed, so return a Report
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_some());

// the scope "feat" is allowed, so return None
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}

#[test]
fn test_severity_off() {
let mut commit: Commit<'_> = Default::default();

// If the severity is `Off`, the rule should return `None`
let rule = ScopeEnumRule {
opts: EnumOpts(
Severity::Off,
Condition::Always,
vec!["feat".to_string(), "fix".to_string()],
),
};

commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}

#[test]
fn test_empty_list() {
let mut commit: Commit<'_> = Default::default();

let rule = ScopeEnumRule {
opts: EnumOpts(Severity::Error, Condition::Always, vec![]),
};

commit.scope = Some(Default::default());
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("nice", 0, 4));
assert!(rule.run(&commit).is_none());
commit.scope = Some(CommitSpan::new("feat", 0, 4));
assert!(rule.run(&commit).is_none());
}
}

0 comments on commit 6417854

Please sign in to comment.