Skip to content

Commit 2b7ee14

Browse files
committed
wip: add tests and benches for dual resolver
1 parent f6686a3 commit 2b7ee14

File tree

4 files changed

+355
-1
lines changed

4 files changed

+355
-1
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ name = "parser_bench"
2020
path = "src/benches/parser_bench.rs"
2121
harness = false
2222

23+
[[bench]]
24+
name = "resolver_bench"
25+
path = "src/benches/resolver_bench.rs"
26+
harness = false
27+
2328
[[bench]]
2429
name = "owner_resolver_bench"
2530
path = "src/benches/owner_resolver_bench.rs"

src/benches/resolver_bench.rs

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
use codeinput::core::resolver::find_owners_and_tags_for_file;
2+
use codeinput::core::types::{CodeownersEntry, Owner, OwnerType, Tag};
3+
use criterion::{Criterion, criterion_group, criterion_main};
4+
use std::hint::black_box;
5+
use std::path::{Path, PathBuf};
6+
7+
fn create_test_tag(name: &str) -> Tag {
8+
Tag(name.to_string())
9+
}
10+
11+
fn create_test_owner(identifier: &str, owner_type: OwnerType) -> Owner {
12+
Owner {
13+
identifier: identifier.to_string(),
14+
owner_type,
15+
}
16+
}
17+
18+
fn create_test_codeowners_entry(
19+
source_file: &str, line_number: usize, pattern: &str, owners: Vec<Owner>, tags: Vec<Tag>,
20+
) -> CodeownersEntry {
21+
CodeownersEntry {
22+
source_file: PathBuf::from(source_file),
23+
line_number,
24+
pattern: pattern.to_string(),
25+
owners,
26+
tags,
27+
}
28+
}
29+
30+
fn bench_find_owners_and_tags_simple_pattern(c: &mut Criterion) {
31+
let entries = vec![
32+
create_test_codeowners_entry(
33+
"/project/CODEOWNERS",
34+
1,
35+
"*.rs",
36+
vec![create_test_owner("@rust-team", OwnerType::Team)],
37+
vec![create_test_tag("rust")],
38+
),
39+
create_test_codeowners_entry(
40+
"/project/CODEOWNERS",
41+
2,
42+
"*.js",
43+
vec![create_test_owner("@js-team", OwnerType::Team)],
44+
vec![create_test_tag("javascript")],
45+
),
46+
];
47+
48+
let file_path = Path::new("/project/src/main.rs");
49+
50+
c.bench_function("find_owners_and_tags_simple", |b| {
51+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
52+
});
53+
}
54+
55+
fn bench_find_owners_and_tags_complex_patterns(c: &mut Criterion) {
56+
let entries = vec![
57+
create_test_codeowners_entry(
58+
"/project/CODEOWNERS",
59+
1,
60+
"*",
61+
vec![create_test_owner("@global-team", OwnerType::Team)],
62+
vec![create_test_tag("global")],
63+
),
64+
create_test_codeowners_entry(
65+
"/project/CODEOWNERS",
66+
5,
67+
"src/**/*.rs",
68+
vec![create_test_owner("@rust-team", OwnerType::Team)],
69+
vec![create_test_tag("rust-source")],
70+
),
71+
create_test_codeowners_entry(
72+
"/project/CODEOWNERS",
73+
10,
74+
"src/frontend/**/*",
75+
vec![create_test_owner("@frontend-team", OwnerType::Team)],
76+
vec![create_test_tag("frontend")],
77+
),
78+
];
79+
80+
let file_path = Path::new("/project/src/frontend/main.rs");
81+
82+
c.bench_function("find_owners_and_tags_complex", |b| {
83+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
84+
});
85+
}
86+
87+
fn bench_find_owners_and_tags_many_entries(c: &mut Criterion) {
88+
let mut entries = Vec::new();
89+
90+
// Create many entries with different patterns
91+
for i in 0..100 {
92+
entries.push(create_test_codeowners_entry(
93+
"/project/CODEOWNERS",
94+
i + 1,
95+
&format!("src/module_{}/**/*", i),
96+
vec![create_test_owner(&format!("@team-{}", i), OwnerType::Team)],
97+
vec![create_test_tag(&format!("module-{}", i))],
98+
));
99+
}
100+
101+
let file_path = Path::new("/project/src/module_50/file.rs");
102+
103+
c.bench_function("find_owners_and_tags_many_entries", |b| {
104+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
105+
});
106+
}
107+
108+
fn bench_find_owners_and_tags_nested_codeowners(c: &mut Criterion) {
109+
let entries = vec![
110+
// Root CODEOWNERS
111+
create_test_codeowners_entry(
112+
"/project/CODEOWNERS",
113+
1,
114+
"*",
115+
vec![create_test_owner("@root-team", OwnerType::Team)],
116+
vec![create_test_tag("root")],
117+
),
118+
// Nested CODEOWNERS in src/
119+
create_test_codeowners_entry(
120+
"/project/src/CODEOWNERS",
121+
1,
122+
"*.rs",
123+
vec![create_test_owner("@rust-team", OwnerType::Team)],
124+
vec![create_test_tag("rust")],
125+
),
126+
// Nested CODEOWNERS in src/frontend/
127+
create_test_codeowners_entry(
128+
"/project/src/frontend/CODEOWNERS",
129+
1,
130+
"*.tsx",
131+
vec![create_test_owner("@frontend-team", OwnerType::Team)],
132+
vec![create_test_tag("frontend")],
133+
),
134+
];
135+
136+
let file_path = Path::new("/project/src/frontend/component.tsx");
137+
138+
c.bench_function("find_owners_and_tags_nested", |b| {
139+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
140+
});
141+
}
142+
143+
fn bench_find_owners_and_tags_no_matches(c: &mut Criterion) {
144+
let entries = vec![create_test_codeowners_entry(
145+
"/project/CODEOWNERS",
146+
1,
147+
"*.js",
148+
vec![create_test_owner("@js-team", OwnerType::Team)],
149+
vec![create_test_tag("javascript")],
150+
)];
151+
152+
let file_path = Path::new("/project/src/main.rs");
153+
154+
c.bench_function("find_owners_and_tags_no_matches", |b| {
155+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
156+
});
157+
}
158+
159+
fn bench_find_owners_and_tags_multiple_matches(c: &mut Criterion) {
160+
let entries = vec![
161+
create_test_codeowners_entry(
162+
"/project/CODEOWNERS",
163+
1,
164+
"*",
165+
vec![create_test_owner("@global-team", OwnerType::Team)],
166+
vec![create_test_tag("global")],
167+
),
168+
create_test_codeowners_entry(
169+
"/project/CODEOWNERS",
170+
2,
171+
"*.rs",
172+
vec![
173+
create_test_owner("@rust-team", OwnerType::Team),
174+
create_test_owner("@reviewer", OwnerType::User),
175+
],
176+
vec![create_test_tag("rust"), create_test_tag("code")],
177+
),
178+
];
179+
180+
let file_path = Path::new("/project/src/main.rs");
181+
182+
c.bench_function("find_owners_and_tags_multiple_matches", |b| {
183+
b.iter(|| find_owners_and_tags_for_file(black_box(file_path), black_box(&entries)).unwrap())
184+
});
185+
}
186+
187+
criterion_group!(
188+
benches,
189+
bench_find_owners_and_tags_simple_pattern,
190+
bench_find_owners_and_tags_complex_patterns,
191+
bench_find_owners_and_tags_many_entries,
192+
bench_find_owners_and_tags_nested_codeowners,
193+
bench_find_owners_and_tags_no_matches,
194+
bench_find_owners_and_tags_multiple_matches,
195+
);
196+
criterion_main!(benches);

src/core/cache.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ pub fn build_cache(
3232

3333
let (owners, tags) =
3434
find_owners_and_tags_for_file(file_path, &entries).unwrap();
35-
//let tags = find_tags_for_file(file_path, &entries).unwrap();
3635

3736
// Build file entry
3837
FileEntry {

src/core/resolver.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,157 @@ pub fn find_owners_and_tags_for_file(
9898
.map(|(entry, _)| (entry.owners.clone(), entry.tags.clone()))
9999
.unwrap_or_default())
100100
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use super::*;
105+
use crate::core::types::{Owner, OwnerType, Tag};
106+
use std::path::PathBuf;
107+
108+
fn create_test_owner(identifier: &str, owner_type: OwnerType) -> Owner {
109+
Owner {
110+
identifier: identifier.to_string(),
111+
owner_type,
112+
}
113+
}
114+
115+
fn create_test_tag(name: &str) -> Tag {
116+
Tag(name.to_string())
117+
}
118+
119+
fn create_test_codeowners_entry(
120+
source_file: &str, line_number: usize, pattern: &str, owners: Vec<Owner>, tags: Vec<Tag>,
121+
) -> CodeownersEntry {
122+
CodeownersEntry {
123+
source_file: PathBuf::from(source_file),
124+
line_number,
125+
pattern: pattern.to_string(),
126+
owners,
127+
tags,
128+
}
129+
}
130+
131+
#[test]
132+
fn test_find_owners_and_tags_for_file_empty_entries() {
133+
let entries = vec![];
134+
let file_path = Path::new("/project/src/main.rs");
135+
let result = find_owners_and_tags_for_file(file_path, &entries).unwrap();
136+
assert!(result.0.is_empty());
137+
assert!(result.1.is_empty());
138+
}
139+
140+
#[test]
141+
fn test_find_owners_and_tags_for_file_simple_match() {
142+
let expected_owner = create_test_owner("@rust-team", OwnerType::Team);
143+
let expected_tag = create_test_tag("rust");
144+
let entries = vec![create_test_codeowners_entry(
145+
"/project/CODEOWNERS",
146+
1,
147+
"*.rs",
148+
vec![expected_owner.clone()],
149+
vec![expected_tag.clone()],
150+
)];
151+
152+
let file_path = Path::new("/project/src/main.rs");
153+
let result = find_owners_and_tags_for_file(file_path, &entries).unwrap();
154+
155+
assert_eq!(result.0.len(), 1);
156+
assert_eq!(result.0[0], expected_owner);
157+
assert_eq!(result.1.len(), 1);
158+
assert_eq!(result.1[0], expected_tag);
159+
}
160+
161+
#[test]
162+
fn test_find_owners_and_tags_for_file_directory_hierarchy() {
163+
let root_owner = create_test_owner("@root-team", OwnerType::Team);
164+
let root_tag = create_test_tag("root");
165+
let src_owner = create_test_owner("@src-team", OwnerType::Team);
166+
let src_tag = create_test_tag("source");
167+
168+
let entries = vec![
169+
create_test_codeowners_entry(
170+
"/project/CODEOWNERS",
171+
1,
172+
"*",
173+
vec![root_owner.clone()],
174+
vec![root_tag.clone()],
175+
),
176+
create_test_codeowners_entry(
177+
"/project/src/CODEOWNERS",
178+
1,
179+
"*.rs",
180+
vec![src_owner.clone()],
181+
vec![src_tag.clone()],
182+
),
183+
];
184+
185+
let file_path = Path::new("/project/src/main.rs");
186+
let result = find_owners_and_tags_for_file(file_path, &entries).unwrap();
187+
188+
assert_eq!(result.0.len(), 1);
189+
assert_eq!(result.0[0], src_owner);
190+
assert_eq!(result.1.len(), 1);
191+
assert_eq!(result.1[0], src_tag);
192+
}
193+
194+
#[test]
195+
fn test_find_owners_and_tags_for_file_line_number_priority() {
196+
let general_owner = create_test_owner("@general-team", OwnerType::Team);
197+
let general_tag = create_test_tag("general");
198+
let specific_owner = create_test_owner("@specific-team", OwnerType::Team);
199+
let specific_tag = create_test_tag("specific");
200+
201+
let entries = vec![
202+
create_test_codeowners_entry(
203+
"/project/CODEOWNERS",
204+
1,
205+
"*",
206+
vec![general_owner.clone()],
207+
vec![general_tag.clone()],
208+
),
209+
create_test_codeowners_entry(
210+
"/project/CODEOWNERS",
211+
10,
212+
"src/*.rs",
213+
vec![specific_owner.clone()],
214+
vec![specific_tag.clone()],
215+
),
216+
];
217+
218+
let file_path = Path::new("/project/src/main.rs");
219+
let result = find_owners_and_tags_for_file(file_path, &entries).unwrap();
220+
221+
assert_eq!(result.0.len(), 1);
222+
assert_eq!(result.0[0], specific_owner);
223+
assert_eq!(result.1.len(), 1);
224+
assert_eq!(result.1[0], specific_tag);
225+
}
226+
227+
#[test]
228+
fn test_find_owners_and_tags_for_file_invalid_pattern() {
229+
let entries = vec![
230+
create_test_codeowners_entry(
231+
"/project/CODEOWNERS",
232+
1,
233+
"[invalid",
234+
vec![create_test_owner("@team1", OwnerType::Team)],
235+
vec![create_test_tag("tag1")],
236+
),
237+
create_test_codeowners_entry(
238+
"/project/CODEOWNERS",
239+
2,
240+
"*.rs",
241+
vec![create_test_owner("@team2", OwnerType::Team)],
242+
vec![create_test_tag("tag2")],
243+
),
244+
];
245+
246+
let file_path = Path::new("/project/src/main.rs");
247+
let result = find_owners_and_tags_for_file(file_path, &entries).unwrap();
248+
249+
assert_eq!(result.0.len(), 1);
250+
assert_eq!(result.0[0].identifier, "@team2");
251+
assert_eq!(result.1.len(), 1);
252+
assert_eq!(result.1[0].0, "tag2");
253+
}
254+
}

0 commit comments

Comments
 (0)