History

refactor

Sebastian Thiel committed 4 years ago

Commit 162f9a01 parent 0bed9382 files · +183 −179Browse files

Unified · Split

2 files
  1. git-pathspec/src/parse.rs +7 −11
  2. git-pathspec/tests/pathspec.rs +176 −168
git-pathspec/src/parse.rs+7−11
@@ -7,18 +7,14 @@ use crate::{MagicSignature, Pattern, SearchMode}; · 6 unmodified lines
7pub enum Error {7pub enum Error {
8 #[error("Empty string is not a valid pathspec")]8 #[error("Empty string is not a valid pathspec")]
9 EmptyString,9 EmptyString,
10 10 #[error("Found {:?}, which is not a valid keyword", found_keyword)]
11 #[error("Found \"{}\", which is not a valid keyword", found_keyword)]
12 InvalidKeyword { found_keyword: BString },11 InvalidKeyword { found_keyword: BString },
13 12 #[error("Missing ')' at the end of pathspec magic in {:?}", pathspec)]
14 #[error("Missing ')' at the end of pathspec magic in '{}'", pathspec)]
15 MissingClosingParenthesis { pathspec: BString },13 MissingClosingParenthesis { pathspec: BString },
16 14 #[error("Attribute has non-ascii characters or starts with '-': {:?}", attribute)]
17 #[error("Attribute has non-ascii characters or starts with '-': {}", attribute)]
18 InvalidAttribute { attribute: BString },15 InvalidAttribute { attribute: BString },
19 16 #[error("'literal' and 'glob' keywords cannot be used together in the same pathspec")]
20 #[error("'literal' and 'globl' keywords can not be used together in the same pathspec")]17 IncompatibleSearchModes,
21 IncompatibleSearchmodes,
22}18}
23 19
24impl Pattern {20impl Pattern {
@@ -94,11 +90,11 @@ fn parse_keywords(input: &[u8]) -> Result<(MagicSignature, SearchMode, Vec<(BStr · 69 unmodified lines
94 b"attr" => signature |= MagicSignature::ATTR,90 b"attr" => signature |= MagicSignature::ATTR,
95 b"literal" => match searchmode {91 b"literal" => match searchmode {
96 SearchMode::Default => searchmode = SearchMode::Literal,92 SearchMode::Default => searchmode = SearchMode::Literal,
97 _ => return Err(Error::IncompatibleSearchmodes),93 _ => return Err(Error::IncompatibleSearchModes),
98 },94 },
99 b"glob" => match searchmode {95 b"glob" => match searchmode {
100 SearchMode::Default => searchmode = SearchMode::Glob,96 SearchMode::Default => searchmode = SearchMode::Glob,
101 _ => return Err(Error::IncompatibleSearchmodes),97 _ => return Err(Error::IncompatibleSearchModes),
102 },98 },
103 s => {99 s => {
104 if let Some(attrs) = s.strip_prefix(b"attr:") {100 if let Some(attrs) = s.strip_prefix(b"attr:") {
git-pathspec/tests/pathspec.rs+176−168
@@ -1,204 +1,212 @@
1use git_attributes::State;1use git_attributes::State;
2use git_pathspec::parse::Error;
3use git_pathspec::{MagicSignature, Pattern, SearchMode};2use git_pathspec::{MagicSignature, Pattern, SearchMode};
4 3
5#[test]4mod succeed {
6fn can_parse_empty_signatures() {5 use crate::{check_valid_inputs, pat, pat_with_path, pat_with_path_and_sig};
7 let inputs = vec![6 use git_attributes::State;
8 ("some/path", pat_with_path("some/path")),7 use git_pathspec::{MagicSignature, SearchMode};
9 (":some/path", pat_with_path("some/path")),8
10 (":()some/path", pat_with_path("some/path")),9 #[test]
11 ("::some/path", pat_with_path("some/path")),10 fn empty_signatures() {
12 (":::some/path", pat_with_path(":some/path")),11 let inputs = vec![
13 ];12 ("some/path", pat_with_path("some/path")),
14 13 (":some/path", pat_with_path("some/path")),
15 check_valid_inputs(inputs)14 (":()some/path", pat_with_path("some/path")),
16}15 ("::some/path", pat_with_path("some/path")),
16 (":::some/path", pat_with_path(":some/path")),
17 ];
18
19 check_valid_inputs(inputs)
20 }
17 21
18#[test]22 #[test]
19fn can_parse_short_signatures() {23 fn short_signatures() {
20 let inputs = vec![24 let inputs = vec![
21 (":/some/path", pat_with_path_and_sig("some/path", MagicSignature::TOP)),25 (":/some/path", pat_with_path_and_sig("some/path", MagicSignature::TOP)),
22 (26 (
23 ":^some/path",27 ":^some/path",
24 pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),28 pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),
25 ),29 ),
26 (30 (
27 ":!some/path",31 ":!some/path",
28 pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),32 pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),
29 ),33 ),
30 (34 (
31 ":/!some/path",35 ":/!some/path",
32 pat_with_path_and_sig("some/path", MagicSignature::TOP | MagicSignature::EXCLUDE),36 pat_with_path_and_sig("some/path", MagicSignature::TOP | MagicSignature::EXCLUDE),
33 ),37 ),
34 (38 (
35 ":!/^/:",39 ":!/^/:",
36 pat_with_path_and_sig("", MagicSignature::TOP | MagicSignature::EXCLUDE),40 pat_with_path_and_sig("", MagicSignature::TOP | MagicSignature::EXCLUDE),
37 ),41 ),
38 ];42 ];
39
40 check_valid_inputs(inputs)
41}
42 43
43#[test]44 check_valid_inputs(inputs)
44fn can_parse_signatures_and_searchmodes() {45 }
45 let inputs = vec![
46 (":(top)", pat_with_path_and_sig("", MagicSignature::TOP)),
47 (":(icase)", pat_with_path_and_sig("", MagicSignature::ICASE)),
48 (":(attr)", pat_with_path_and_sig("", MagicSignature::ATTR)),
49 (":(exclude)", pat_with_path_and_sig("", MagicSignature::EXCLUDE)),
50 (
51 ":(literal)",
52 pat("", MagicSignature::empty(), SearchMode::Literal, vec![]),
53 ),
54 (":(glob)", pat("", MagicSignature::empty(), SearchMode::Glob, vec![])),
55 (
56 ":(top,exclude)",
57 pat_with_path_and_sig("", MagicSignature::TOP | MagicSignature::EXCLUDE),
58 ),
59 (
60 ":(icase,literal)",
61 pat("", MagicSignature::ICASE, SearchMode::Literal, vec![]),
62 ),
63 (
64 ":!(literal)some/*path",
65 pat("some/*path", MagicSignature::EXCLUDE, SearchMode::Literal, vec![]),
66 ),
67 (
68 ":(top,literal,icase,attr,exclude)some/path",
69 pat("some/path", MagicSignature::all(), SearchMode::Literal, vec![]),
70 ),
71 (
72 ":(top,glob,icase,attr,exclude)some/path",
73 pat("some/path", MagicSignature::all(), SearchMode::Glob, vec![]),
74 ),
75 ];
76
77 check_valid_inputs(inputs);
78}
79 46
80#[test]47 #[test]
81fn can_parse_attributes_in_signature() {48 fn signatures_and_searchmodes() {
82 let inputs = vec![49 let inputs = vec![
83 (50 (":(top)", pat_with_path_and_sig("", MagicSignature::TOP)),
84 ":(attr:someAttr)",51 (":(icase)", pat_with_path_and_sig("", MagicSignature::ICASE)),
85 pat(52 (":(attr)", pat_with_path_and_sig("", MagicSignature::ATTR)),
86 "",53 (":(exclude)", pat_with_path_and_sig("", MagicSignature::EXCLUDE)),
87 MagicSignature::ATTR,54 (
88 SearchMode::Default,55 ":(literal)",
89 vec![("someAttr", State::Set)],56 pat("", MagicSignature::empty(), SearchMode::Literal, vec![]),
90 ),57 ),
91 ),58 (":(glob)", pat("", MagicSignature::empty(), SearchMode::Glob, vec![])),
92 (59 (
93 ":(attr:!someAttr)",60 ":(top,exclude)",
94 pat(61 pat_with_path_and_sig("", MagicSignature::TOP | MagicSignature::EXCLUDE),
95 "",
96 MagicSignature::ATTR,
97 SearchMode::Default,
98 vec![("someAttr", State::Unspecified)],
99 ),62 ),
100 ),63 (
101 (64 ":(icase,literal)",
102 ":(attr:-someAttr)",65 pat("", MagicSignature::ICASE, SearchMode::Literal, vec![]),
103 pat(
104 "",
105 MagicSignature::ATTR,
106 SearchMode::Default,
107 vec![("someAttr", State::Unset)],
108 ),66 ),
109 ),67 (
110 (68 ":!(literal)some/*path",
111 ":(attr:someAttr=value)",69 pat("some/*path", MagicSignature::EXCLUDE, SearchMode::Literal, vec![]),
112 pat(
113 "",
114 MagicSignature::ATTR,
115 SearchMode::Default,
116 vec![("someAttr", State::Value("value".into()))],
117 ),70 ),
118 ),71 (
119 (72 ":(top,literal,icase,attr,exclude)some/path",
120 ":(attr:someAttr anotherAttr)",73 pat("some/path", MagicSignature::all(), SearchMode::Literal, vec![]),
121 pat(
122 "",
123 MagicSignature::ATTR,
124 SearchMode::Default,
125 vec![("someAttr", State::Set), ("anotherAttr", State::Set)],
126 ),74 ),
127 ),75 (
128 ];76 ":(top,glob,icase,attr,exclude)some/path",
129 77 pat("some/path", MagicSignature::all(), SearchMode::Glob, vec![]),
130 check_valid_inputs(inputs)78 ),
131}79 ];
132 80
133#[test]81 check_valid_inputs(inputs);
134fn should_fail_on_empty_input() {82 }
135 let input = "";
136 83
137 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);84 #[test]
85 fn attributes_in_signature() {
86 let inputs = vec![
87 (
88 ":(attr:someAttr)",
89 pat(
90 "",
91 MagicSignature::ATTR,
92 SearchMode::Default,
93 vec![("someAttr", State::Set)],
94 ),
95 ),
96 (
97 ":(attr:!someAttr)",
98 pat(
99 "",
100 MagicSignature::ATTR,
101 SearchMode::Default,
102 vec![("someAttr", State::Unspecified)],
103 ),
104 ),
105 (
106 ":(attr:-someAttr)",
107 pat(
108 "",
109 MagicSignature::ATTR,
110 SearchMode::Default,
111 vec![("someAttr", State::Unset)],
112 ),
113 ),
114 (
115 ":(attr:someAttr=value)",
116 pat(
117 "",
118 MagicSignature::ATTR,
119 SearchMode::Default,
120 vec![("someAttr", State::Value("value".into()))],
121 ),
122 ),
123 (
124 ":(attr:someAttr anotherAttr)",
125 pat(
126 "",
127 MagicSignature::ATTR,
128 SearchMode::Default,
129 vec![("someAttr", State::Set), ("anotherAttr", State::Set)],
130 ),
131 ),
132 ];
138 133
139 let output = git_pathspec::parse(input.as_bytes());134 check_valid_inputs(inputs)
140 assert!(output.is_err());135 }
141 assert!(matches!(output.unwrap_err(), Error::EmptyString { .. }));
142}136}
143 137
144#[test]138mod fail {
145fn should_fail_on_invalid_keywords() {139 use crate::is_valid_in_git;
146 let inputs = vec![140 use git_pathspec::parse::Error;
147 ":( )some/path",141
148 ":(tp)some/path",142 #[test]
149 ":(top, exclude)some/path",143 fn empty_input() {
150 ":(top,exclude,icse)some/path",144 let input = "";
151 ];
152 145
153 inputs.into_iter().for_each(|input| {
154 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);146 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);
155 147
156 let output = git_pathspec::parse(input.as_bytes());148 let output = git_pathspec::parse(input.as_bytes());
157 assert!(output.is_err());149 assert!(output.is_err());
158 assert!(matches!(output.unwrap_err(), Error::InvalidKeyword { .. }));150 assert!(matches!(output.unwrap_err(), Error::EmptyString { .. }));
159 });151 }
160}
161 152
162#[test]153 #[test]
163fn should_fail_on_invalid_attributes() {154 fn invalid_keywords() {
164 let inputs = vec![155 let inputs = vec![
165 ":(attr:+invalidAttr)some/path",156 ":( )some/path",
166 ":(attr:validAttr +invalidAttr)some/path",157 ":(tp)some/path",
167 ];158 ":(top, exclude)some/path",
159 ":(top,exclude,icse)some/path",
160 ];
161
162 inputs.into_iter().for_each(|input| {
163 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);
164
165 let output = git_pathspec::parse(input.as_bytes());
166 assert!(output.is_err());
167 assert!(matches!(output.unwrap_err(), Error::InvalidKeyword { .. }));
168 });
169 }
168 170
169 for input in inputs {171 #[test]
170 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);172 fn invalid_attributes() {
173 let inputs = vec![
174 ":(attr:+invalidAttr)some/path",
175 ":(attr:validAttr +invalidAttr)some/path",
176 ];
171 177
172 let output = git_pathspec::parse(input.as_bytes());178 for input in inputs {
173 assert!(output.is_err());179 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);
174 assert!(matches!(output.unwrap_err(), Error::InvalidAttribute { .. }));180
181 let output = git_pathspec::parse(input.as_bytes());
182 assert!(output.is_err());
183 assert!(matches!(output.unwrap_err(), Error::InvalidAttribute { .. }));
184 }
175 }185 }
176}
177 186
178#[test]187 #[test]
179fn should_fail_on_missing_parentheses() {188 fn missing_parentheses() {
180 let input = ":(top";189 let input = ":(top";
181 190
182 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);191 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);
183 192
184 let output = git_pathspec::parse(input.as_bytes());193 let output = git_pathspec::parse(input.as_bytes());
185 assert!(output.is_err());194 assert!(output.is_err());
186 assert!(matches!(output.unwrap_err(), Error::MissingClosingParenthesis { .. }));195 assert!(matches!(output.unwrap_err(), Error::MissingClosingParenthesis { .. }));
187}196 }
188 197
189#[test]198 #[test]
190fn should_fail_on_glob_and_literal_present() {199 fn glob_and_literal_keywords_present() {
191 let input = ":(glob,literal)some/path";200 let input = ":(glob,literal)some/path";
192 201
193 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);202 assert!(!is_valid_in_git(input), "This pathspec is valid in git: {}", input);
194 203
195 let output = git_pathspec::parse(input.as_bytes());204 let output = git_pathspec::parse(input.as_bytes());
196 assert!(output.is_err());205 assert!(output.is_err());
197 assert!(matches!(output.unwrap_err(), Error::IncompatibleSearchmodes));206 assert!(matches!(output.unwrap_err(), Error::IncompatibleSearchModes));
207 }
198}208}
199 209
200// --- Helpers ---
201
202fn check_valid_inputs(inputs: Vec<(&str, Pattern)>) {210fn check_valid_inputs(inputs: Vec<(&str, Pattern)>) {
203 inputs.into_iter().for_each(|(input, expected)| {211 inputs.into_iter().for_each(|(input, expected)| {
204 assert!(is_valid_in_git(input), "This pathspec is invalid in git: {}", input);212 assert!(is_valid_in_git(input), "This pathspec is invalid in git: {}", input);