use indoc::indoc;
use conventional_commit_parser::commit::{CommitType, Footer, Separator};
use conventional_commit_parser::error::ParseErrorKind;
use conventional_commit_parser::parse;
use crate::assertions::*;
mod assertions;
#[test]
fn commits_with_feature_type() {
let commit_message = "feat: toto va à la plage";
let parsed = &parse(commit_message);
assert_commit_type(parsed, CommitType::Feature);
assert_summary(parsed, "toto va à la plage");
assert_no_body(parsed);
assert_no_footers(parsed);
assert_not_breaking_change(parsed);
}
#[test]
fn parsing_a_commit_type_without_colon_separator_should_fail() {
let commit_message = "feat toto va à la plage";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::MissingSeparator);
}
#[test]
fn parsing_a_commit_type_with_whitespace_should_fail() {
let commit_message = "feat toto: va à la plage";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::MissingSeparator);
}
#[test]
fn commits_with_feature_type_and_breaking_change_mark() {
let commit_message = "feat!: toto va à la plage";
let parsed = &parse(commit_message);
assert_commit_type(parsed, CommitType::Feature);
assert_no_scope(parsed);
assert_summary(parsed, "toto va à la plage");
assert_breaking_change(parsed);
assert_no_body(parsed);
assert_no_footers(parsed);
}
#[test]
fn commits_with_feature_type_and_scope_and_breaking_change_mark() {
let commit_message = "fix(parser)!: the parser";
let parsed = &parse(commit_message);
assert_commit_type(parsed, CommitType::BugFix);
assert_scope(parsed, "parser");
assert_summary(parsed, "the parser");
assert_breaking_change(parsed);
assert_no_body(parsed);
assert_no_footers(parsed);
}
#[test]
fn parsing_a_commit_type_without_terminal_column_and_space_should_fail() {
let commit_message = "feat:toto va à la plage";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::MissingWhiteSpace);
}
#[test]
fn parsing_a_scoped_commit_type_without_terminal_column_and_space_should_fail() {
let commit_message = "feat(toto):toto va à la plage";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::MissingWhiteSpace);
}
#[test]
fn parsing_a_scoped_breaking_change_commit_type_without_terminal_column_and_space_should_fail() {
let commit_message = "feat(toto)!:toto va à la plage";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::MissingWhiteSpace);
}
#[test]
fn commits_with_scope() {
let commit_message = "fix(parser): the parser";
let parsed = &parse(commit_message);
assert_scope(parsed, "parser");
}
#[test]
fn scope_with_inner_parenthesis_should_fail() {
let commit_message = "fix((toto): the parser";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::UnexpectedParenthesis);
}
#[test]
fn scope_with_inner_new_line_should_fail() {
let commit_message = "fix(\n)): the parser";
let result = parse(commit_message);
assert_error(&result, ParseErrorKind::UnexpectedWhitespaceOrNewLine);
}
#[test]
fn scope_with_whitespace_should_fail() {
let commit_message = "chore(hello world): a commit";
let parsed = parse(commit_message);
assert_error(&parsed, ParseErrorKind::UnexpectedWhitespaceOrNewLine);
}
#[test]
fn commits_with_body() {
let commit_message = indoc!(
"ci(the_scope)!: the fix
This is a body containing special char like / and \\ and also
Newline. Punctuation and special chars ? , ; ...
Number is something you can have to ! 1 2 .. 42"
);
let parsed = &parse(commit_message);
assert_body(
parsed,
indoc!(
"This is a body containing special char like / and \\ and also
Newline. Punctuation and special chars ? , ; ...
Number is something you can have to ! 1 2 .. 42"
),
);
assert_no_footers(parsed);
}
#[test]
fn commits_with_footer() {
let commit_message = indoc!(
"feat(friture): the the BIG feature
This is a body
a-token: this is a token"
);
let parsed = &parse(commit_message);
assert_body(&parsed, "This is a body");
assert_contains_footer(
parsed,
Footer {
token: "a-token".to_string(),
content: "this is a token".to_string(),
..Default::default()
},
);
}
#[test]
fn commits_with_footers() {
let commit_message = indoc!(
"feat(friture): the the BIG feature
This is a body
a-token: this is a token
another-token #this is a token with hash separator"
);
let parsed = &parse(commit_message);
assert_contains_footer(
parsed,
Footer {
token: "a-token".to_string(),
content: "this is a token".to_string(),
..Default::default()
},
);
assert_contains_footer(
parsed,
Footer {
token: "another-token".to_string(),
content: "this is a token with hash separator".to_string(),
token_separator: Separator::Hash,
},
);
}
#[test]
fn footer_with_whitespace_token_is_parsed_as_body() {
let commit_message = indoc!(
"chore: a commit
This is a body
invalid token : this is a token"
);
let result = parse(commit_message);
assert_body(&result, "This is a body\n\ninvalid token : this is a token");
}
#[test]
fn footer_with_breaking_change_ok() {
let commit_message = indoc!(
"chore: a commit
This is a body
BREAKING CHANGE: message"
);
let parsed = parse(commit_message);
assert_contains_footer(
&parsed,
Footer {
token: "BREAKING CHANGE".to_string(),
content: "message".to_string(),
..Default::default()
},
);
assert_breaking_change(&parsed);
}
#[test]
fn footer_with_no_body() {
let commit_message = indoc!(
"chore: a commit
BREAKING CHANGE: message"
);
let parsed = parse(commit_message);
assert_no_body(&parsed);
assert_contains_footer(
&parsed,
Footer {
token: "BREAKING CHANGE".to_string(),
content: "message".to_string(),
..Default::default()
},
);
assert_breaking_change(&parsed);
}
#[test]
fn footer_with_new_line() {
let commit_message = indoc!(
"chore: a commit
BREAKING CHANGE: a long message that describe a footer
with multiple new line
another-footer: with content"
);
let parsed = parse(commit_message);
assert_no_body(&parsed);
assert_contains_footer(
&parsed,
Footer {
token: "BREAKING CHANGE".to_string(),
content: indoc!(
"a long message that describe a footer
with multiple new line"
)
.to_string(),
..Default::default()
},
);
assert_contains_footer(
&parsed,
Footer {
token: "another-footer".to_string(),
content: "with content".to_string(),
..Default::default()
},
);
assert_breaking_change(&parsed);
}
#[test]
fn lower_case_breaking_change_footer_is_parsed_as_body() {
let commit_message = indoc!(
"chore: a commit
the body
breaking change: oops"
);
let result = parse(commit_message);
assert_body(&result, "the body\n\nbreaking change: oops");
}
#[test]
fn commits_with_camel_case_feature_type() {
let commit_message = "Feat: toto va à la plage";
let parsed = &parse(commit_message);
assert_commit_type(parsed, CommitType::Feature);
}
#[test]
fn breaking_change_with_dash() {
let commit_message = indoc!(
"chore: a commit
BREAKING-CHANGE: message"
);
let parsed = parse(commit_message);
assert_breaking_change(&parsed);
}
#[test]
fn should_parse_dependabot_commit() {
let commit_message = indoc!(
"chore(deps): bump spring-boot-starter-parent from 2.5.5 to 2.5.6
Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.5.5 to 2.5.6.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](spring-projects/spring-boot@v2.5.5...v2.5.6)
---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-parent
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>"
);
let parsed = parse(commit_message);
assert_commit_type(&parsed, CommitType::Chore);
assert_scope(&parsed, "deps");
assert_body(&parsed, indoc!("Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.5.5 to 2.5.6.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](spring-projects/spring-boot@v2.5.5...v2.5.6)
---"));
assert_contains_footer(
&parsed,
Footer {
token: "updated-dependencies".to_string(),
content: indoc!(
"- dependency-name: org.springframework.boot:spring-boot-starter-parent
dependency-type: direct:production
update-type: version-update:semver-patch
..."
)
.to_string(),
token_separator: Separator::ColonWithNewLine,
},
);
assert_contains_footer(
&parsed,
Footer {
token: "Signed-off-by".to_string(),
content: "dependabot[bot] <support@github.com>".to_string(),
token_separator: Separator::Colon,
},
);
}
#[test]
fn should_parse_dependabot_commit_2() {
let commit_message = indoc!(
"chore(deps): bump archunit-junit5-engine from 0.21.0 to 0.22.0 (#11)
Bumps [archunit-junit5-engine](https://github.com/TNG/ArchUnit) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/TNG/ArchUnit/releases)
- [Commits](https://github.com/TNG/ArchUnit/compare/v0.21.0...v0.22.0)
---
updated-dependencies:\r- dependency-name: com.tngtech.archunit:archunit-junit5-engine
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: guillaumer63 <74533647+guillaumer63@users.noreply.github.com>"
);
let parsed = parse(commit_message);
assert_commit_type(&parsed, CommitType::Chore);
assert_scope(&parsed, "deps");
assert_body(
&parsed,
indoc!(
"Bumps [archunit-junit5-engine](https://github.com/TNG/ArchUnit) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/TNG/ArchUnit/releases)
- [Commits](https://github.com/TNG/ArchUnit/compare/v0.21.0...v0.22.0)
---"
),
);
assert_contains_footer(
&parsed,
Footer {
token: "updated-dependencies".to_string(),
content: indoc!(
"- dependency-name: com.tngtech.archunit:archunit-junit5-engine
dependency-type: direct:production
update-type: version-update:semver-minor
..."
)
.to_string(),
token_separator: Separator::ColonWithNewLine,
},
);
assert_contains_footer(
&parsed,
Footer {
token: "Signed-off-by".to_string(),
content: "dependabot[bot] <support@github.com>".to_string(),
token_separator: Separator::Colon,
},
);
assert_contains_footer(
&parsed,
Footer {
token: "Co-authored-by".to_string(),
content: "guillaumer63 <74533647+guillaumer63@users.noreply.github.com>".to_string(),
token_separator: Separator::Colon,
},
);
}
#[test]
fn should_parse_interactively_rebased_commit() {
let commit_message = indoc!(
"feat(References): add new fields in ReferenceWithAlert (#8)
* feat(References): add new fields in ReferenceWithAlert
* feat(PortOfLoading): add unit test
footer: value"
);
let parsed = parse(commit_message);
assert_commit_type(&parsed, CommitType::Feature);
assert_scope(&parsed, "References");
assert_body(
&parsed,
indoc!(
"* feat(References): add new fields in ReferenceWithAlert
* feat(PortOfLoading): add unit test"
),
);
assert_contains_footer(
&parsed,
Footer {
token: "footer".to_string(),
content: "value".to_string(),
token_separator: Separator::Colon,
},
);
}