1pub fn chunk_by_max_concurrent<T: Clone>(items: &[T], max_concurrent: usize) -> Vec<Vec<T>> {
26 let batch_size = max_concurrent.max(1);
27 if items.is_empty() {
28 return Vec::new();
29 }
30
31 let mut chunks = Vec::new();
32 let mut index = 0usize;
33
34 while index < items.len() {
35 let next = (index + batch_size).min(items.len());
36 chunks.push(items[index..next].to_vec());
37 index = next;
38 }
39
40 chunks
41}
42
43#[cfg(test)]
44mod tests {
45 use super::chunk_by_max_concurrent;
46
47 #[test]
48 fn chunking_empty_input_returns_no_batches() {
49 let items: Vec<String> = vec![];
50 let chunks = chunk_by_max_concurrent(&items, 4);
51 assert!(chunks.is_empty());
52 }
53
54 #[test]
55 fn chunking_respects_max_concurrent() {
56 let items = vec!["a", "b", "c", "d", "e"];
57 let chunks = chunk_by_max_concurrent(&items, 2);
58
59 assert_eq!(chunks.len(), 3);
60 assert_eq!(chunks[0], vec!["a", "b"]);
61 assert_eq!(chunks[1], vec!["c", "d"]);
62 assert_eq!(chunks[2], vec!["e"]);
63 }
64
65 #[test]
66 fn chunking_preserves_order_and_total_items() {
67 let items = vec![1, 2, 3, 4, 5];
68 let chunks = chunk_by_max_concurrent(&items, 10);
69 let flattened: Vec<i32> = chunks
70 .iter()
71 .flat_map(|chunk| chunk.iter().cloned())
72 .collect();
73
74 assert_eq!(flattened, items);
75 assert_eq!(chunks.len(), 1);
76 }
77
78 #[test]
79 fn chunking_max_concurrent_zero_treated_as_one() {
80 let items = vec!["a", "b", "c"];
81 let chunks = chunk_by_max_concurrent(&items, 0);
82 assert_eq!(chunks.len(), 3);
83 assert_eq!(chunks[0], vec!["a"]);
84 assert_eq!(chunks[1], vec!["b"]);
85 assert_eq!(chunks[2], vec!["c"]);
86 }
87
88 #[test]
89 fn chunking_max_concurrent_usize_max() {
90 let items = vec!["x", "y", "z"];
91 let chunks = chunk_by_max_concurrent(&items, usize::MAX);
92 assert_eq!(chunks.len(), 1);
93 assert_eq!(chunks[0], vec!["x", "y", "z"]);
94 }
95
96 #[test]
97 fn chunking_single_item_with_max_concurrent_one() {
98 let items = vec!["only"];
99 let chunks = chunk_by_max_concurrent(&items, 1);
100 assert_eq!(chunks.len(), 1);
101 assert_eq!(chunks[0], vec!["only"]);
102 }
103
104 #[test]
105 fn chunking_large_list_100_items_by_7() {
106 let items: Vec<i32> = (0..100).collect();
107 let chunks = chunk_by_max_concurrent(&items, 7);
108
109 assert_eq!(chunks.len(), 15);
111 for chunk in &chunks[..14] {
112 assert_eq!(chunk.len(), 7);
113 }
114 assert_eq!(chunks[14].len(), 2);
115
116 let flattened: Vec<i32> = chunks.into_iter().flatten().collect();
117 assert_eq!(flattened, items);
118 }
119
120 #[test]
121 fn chunking_with_integer_types() {
122 let items: Vec<u64> = vec![10, 20, 30, 40, 50, 60];
123 let chunks = chunk_by_max_concurrent(&items, 4);
124 assert_eq!(chunks.len(), 2);
125 assert_eq!(chunks[0], vec![10, 20, 30, 40]);
126 assert_eq!(chunks[1], vec![50, 60]);
127 }
128
129 #[test]
132 fn empty_i32_slice_returns_empty_chunks() {
133 let items: &[i32] = &[];
134 let chunks = chunk_by_max_concurrent(items, 1);
135 assert!(chunks.is_empty());
136 }
137
138 #[test]
139 fn empty_input_with_large_max_concurrent() {
140 let items: Vec<&str> = vec![];
141 let chunks = chunk_by_max_concurrent(&items, 1000);
142 assert!(chunks.is_empty());
143 }
144
145 #[test]
148 fn single_item_with_large_max_concurrent() {
149 let items = vec![42];
150 let chunks = chunk_by_max_concurrent(&items, 100);
151 assert_eq!(chunks.len(), 1);
152 assert_eq!(chunks[0], vec![42]);
153 }
154
155 #[test]
156 fn single_item_with_max_concurrent_zero() {
157 let items = vec!["alone"];
158 let chunks = chunk_by_max_concurrent(&items, 0);
159 assert_eq!(chunks.len(), 1);
160 assert_eq!(chunks[0], vec!["alone"]);
161 }
162
163 #[test]
166 fn chunk_size_much_larger_than_input() {
167 let items = vec![1, 2, 3];
168 let chunks = chunk_by_max_concurrent(&items, 999);
169 assert_eq!(chunks.len(), 1);
170 assert_eq!(chunks[0], vec![1, 2, 3]);
171 }
172
173 #[test]
174 fn chunk_size_exactly_input_length() {
175 let items = vec!["a", "b", "c", "d"];
176 let chunks = chunk_by_max_concurrent(&items, 4);
177 assert_eq!(chunks.len(), 1);
178 assert_eq!(chunks[0], vec!["a", "b", "c", "d"]);
179 }
180
181 #[test]
184 fn chunk_size_one_produces_individual_chunks() {
185 let items = vec!["x", "y", "z", "w"];
186 let chunks = chunk_by_max_concurrent(&items, 1);
187 assert_eq!(chunks.len(), 4);
188 for (i, chunk) in chunks.iter().enumerate() {
189 assert_eq!(chunk.len(), 1);
190 assert_eq!(chunk[0], items[i]);
191 }
192 }
193
194 #[test]
197 fn large_input_1000_items_by_3() {
198 let items: Vec<i32> = (0..1000).collect();
199 let chunks = chunk_by_max_concurrent(&items, 3);
200 assert_eq!(chunks.len(), 334);
202 for chunk in &chunks[..333] {
203 assert_eq!(chunk.len(), 3);
204 }
205 assert_eq!(chunks[333].len(), 1);
206 let flattened: Vec<i32> = chunks.into_iter().flatten().collect();
207 assert_eq!(flattened, items);
208 }
209
210 #[test]
211 fn large_input_1000_items_by_1() {
212 let items: Vec<i32> = (0..1000).collect();
213 let chunks = chunk_by_max_concurrent(&items, 1);
214 assert_eq!(chunks.len(), 1000);
215 for (i, chunk) in chunks.iter().enumerate() {
216 assert_eq!(chunk, &[i as i32]);
217 }
218 }
219
220 #[test]
221 fn large_input_1000_items_by_1000() {
222 let items: Vec<i32> = (0..1000).collect();
223 let chunks = chunk_by_max_concurrent(&items, 1000);
224 assert_eq!(chunks.len(), 1);
225 assert_eq!(chunks[0].len(), 1000);
226 }
227
228 #[test]
229 fn large_input_1000_items_by_17() {
230 let items: Vec<i32> = (0..1000).collect();
231 let chunks = chunk_by_max_concurrent(&items, 17);
232 assert_eq!(chunks.len(), 59);
234 let total: usize = chunks.iter().map(|c| c.len()).sum();
235 assert_eq!(total, 1000);
236 let flattened: Vec<i32> = chunks.into_iter().flatten().collect();
237 assert_eq!(flattened, items);
238 }
239
240 #[test]
243 fn dependency_items_spanning_multiple_chunks() {
244 #[derive(Debug, Clone, PartialEq)]
246 struct CrateItem {
247 name: &'static str,
248 depends_on: Vec<&'static str>,
249 }
250
251 let items = vec![
252 CrateItem {
253 name: "core",
254 depends_on: vec![],
255 },
256 CrateItem {
257 name: "utils",
258 depends_on: vec!["core"],
259 },
260 CrateItem {
261 name: "api",
262 depends_on: vec!["core", "utils"],
263 },
264 CrateItem {
265 name: "cli",
266 depends_on: vec!["api"],
267 },
268 CrateItem {
269 name: "web",
270 depends_on: vec!["api", "utils"],
271 },
272 ];
273
274 let chunks = chunk_by_max_concurrent(&items, 2);
275 assert_eq!(chunks.len(), 3);
276
277 assert_eq!(chunks[0][0].name, "core");
279 assert_eq!(chunks[0][1].name, "utils");
280
281 assert_eq!(chunks[1][0].name, "api");
283 assert_eq!(chunks[1][1].name, "cli");
284
285 assert_eq!(chunks[2][0].name, "web");
287 }
288
289 #[test]
290 fn dependency_items_all_in_one_chunk() {
291 #[derive(Debug, Clone, PartialEq)]
292 struct CrateItem {
293 name: &'static str,
294 depends_on: Vec<&'static str>,
295 }
296
297 let items = vec![
298 CrateItem {
299 name: "core",
300 depends_on: vec![],
301 },
302 CrateItem {
303 name: "utils",
304 depends_on: vec!["core"],
305 },
306 CrateItem {
307 name: "api",
308 depends_on: vec!["core", "utils"],
309 },
310 ];
311
312 let chunks = chunk_by_max_concurrent(&items, 10);
313 assert_eq!(chunks.len(), 1);
314 assert_eq!(chunks[0].len(), 3);
315 assert_eq!(chunks[0][0].name, "core");
317 assert_eq!(chunks[0][2].name, "api");
318 }
319
320 #[test]
323 fn ordering_within_each_chunk_matches_input() {
324 let items: Vec<i32> = (0..20).collect();
325 let chunks = chunk_by_max_concurrent(&items, 4);
326
327 let mut offset = 0;
328 for chunk in &chunks {
329 for (j, &item) in chunk.iter().enumerate() {
330 assert_eq!(item, items[offset + j], "mismatch at offset {offset}+{j}");
331 }
332 offset += chunk.len();
333 }
334 assert_eq!(offset, items.len());
335 }
336
337 #[test]
338 fn ordering_preserved_with_string_items() {
339 let items: Vec<String> = (0..15).map(|i| format!("crate-{i}")).collect();
340 let chunks = chunk_by_max_concurrent(&items, 4);
341
342 let flattened: Vec<String> = chunks.into_iter().flatten().collect();
343 assert_eq!(flattened, items);
344 }
345
346 #[test]
349 fn chunk_boundaries_are_contiguous_and_non_overlapping() {
350 let items: Vec<i32> = (0..13).collect();
351 let chunks = chunk_by_max_concurrent(&items, 4);
352 assert_eq!(chunks.len(), 4);
354 assert_eq!(chunks[0], vec![0, 1, 2, 3]);
355 assert_eq!(chunks[1], vec![4, 5, 6, 7]);
356 assert_eq!(chunks[2], vec![8, 9, 10, 11]);
357 assert_eq!(chunks[3], vec![12]);
358 }
359
360 #[test]
361 fn all_full_chunks_have_exact_batch_size() {
362 let items: Vec<i32> = (0..30).collect();
363 let chunks = chunk_by_max_concurrent(&items, 7);
364 for chunk in &chunks[..4] {
366 assert_eq!(
367 chunk.len(),
368 7,
369 "full chunks must have exactly batch_size items"
370 );
371 }
372 assert_eq!(chunks[4].len(), 2, "remainder chunk has leftover items");
373 }
374
375 #[test]
378 fn remainder_chunk_contains_correct_trailing_items() {
379 let items = vec!["a", "b", "c", "d", "e", "f", "g"];
380 let chunks = chunk_by_max_concurrent(&items, 3);
381 assert_eq!(chunks.last().unwrap(), &vec!["g"]);
383 }
384
385 #[test]
386 fn no_remainder_when_evenly_divisible() {
387 let items: Vec<i32> = (0..12).collect();
388 let chunks = chunk_by_max_concurrent(&items, 4);
389 assert_eq!(chunks.len(), 3);
390 for chunk in &chunks {
391 assert_eq!(
392 chunk.len(),
393 4,
394 "all chunks should be full when evenly divisible"
395 );
396 }
397 }
398
399 #[test]
400 fn remainder_of_one_less_than_batch() {
401 let items: Vec<i32> = (0..11).collect();
402 let chunks = chunk_by_max_concurrent(&items, 4);
403 assert_eq!(chunks.len(), 3);
405 assert_eq!(chunks[2].len(), 3);
406 assert_eq!(chunks[2], vec![8, 9, 10]);
407 }
408
409 #[test]
412 fn two_items_chunk_size_one() {
413 let items = vec!["first", "second"];
414 let chunks = chunk_by_max_concurrent(&items, 1);
415 assert_eq!(chunks, vec![vec!["first"], vec!["second"]]);
416 }
417
418 #[test]
419 fn two_items_chunk_size_two() {
420 let items = vec!["first", "second"];
421 let chunks = chunk_by_max_concurrent(&items, 2);
422 assert_eq!(chunks, vec![vec!["first", "second"]]);
423 }
424
425 #[test]
426 fn two_items_chunk_size_three() {
427 let items = vec!["first", "second"];
428 let chunks = chunk_by_max_concurrent(&items, 3);
429 assert_eq!(chunks.len(), 1);
430 assert_eq!(chunks[0], vec!["first", "second"]);
431 }
432
433 #[test]
436 fn determinism_same_input_always_produces_same_chunks() {
437 let items: Vec<i32> = (0..23).collect();
438 let first = chunk_by_max_concurrent(&items, 5);
439 for _ in 0..50 {
440 let again = chunk_by_max_concurrent(&items, 5);
441 assert_eq!(first, again, "chunking must be deterministic");
442 }
443 }
444
445 #[test]
446 fn determinism_with_string_items() {
447 let items: Vec<String> = (0..17).map(|i| format!("pkg-{i}")).collect();
448 let first = chunk_by_max_concurrent(&items, 3);
449 for _ in 0..20 {
450 assert_eq!(
451 chunk_by_max_concurrent(&items, 3),
452 first,
453 "string chunking must be deterministic"
454 );
455 }
456 }
457
458 #[test]
461 fn chunk_size_one_less_than_total() {
462 let items: Vec<i32> = (0..5).collect();
463 let chunks = chunk_by_max_concurrent(&items, 4);
464 assert_eq!(chunks.len(), 2);
465 assert_eq!(chunks[0], vec![0, 1, 2, 3]);
466 assert_eq!(chunks[1], vec![4]);
467 }
468
469 #[test]
472 fn chunk_size_one_more_than_total() {
473 let items: Vec<i32> = (0..5).collect();
474 let chunks = chunk_by_max_concurrent(&items, 6);
475 assert_eq!(chunks.len(), 1);
476 assert_eq!(chunks[0], vec![0, 1, 2, 3, 4]);
477 }
478
479 #[test]
482 fn no_empty_chunks_emitted() {
483 for n in 0..=20 {
484 for chunk_size in 0..=20 {
485 let items: Vec<i32> = (0..n).collect();
486 let chunks = chunk_by_max_concurrent(&items, chunk_size as usize);
487 for (ci, chunk) in chunks.iter().enumerate() {
488 assert!(
489 !chunk.is_empty(),
490 "chunk {ci} was empty for n={n}, chunk_size={chunk_size}"
491 );
492 }
493 }
494 }
495 }
496
497 #[test]
500 fn prime_item_count_with_non_divisor_chunk_size() {
501 let items: Vec<i32> = (0..37).collect();
503 let chunks = chunk_by_max_concurrent(&items, 6);
504 assert_eq!(chunks.len(), 7);
505 for chunk in &chunks[..6] {
506 assert_eq!(chunk.len(), 6);
507 }
508 assert_eq!(chunks[6].len(), 1);
509 assert_eq!(chunks[6][0], 36);
510 }
511}
512
513#[cfg(test)]
514mod property_tests {
515 use super::chunk_by_max_concurrent;
516 use proptest::prelude::*;
517
518 proptest! {
519 #[test]
520 fn chunking_preserves_items_and_order(
521 items in prop::collection::vec("[a-z]{0,6}", 0..128),
522 max_concurrent in 1usize..16,
523 ) {
524 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
525 let flattened: Vec<String> = chunks
526 .iter()
527 .flat_map(|chunk| chunk.iter().cloned())
528 .collect();
529
530 prop_assert_eq!(flattened.len(), items.len());
531 prop_assert_eq!(flattened, items.clone());
532
533 let sum_len: usize = chunks.iter().map(|chunk| chunk.len()).sum();
534 prop_assert_eq!(sum_len, items.len());
535 for chunk in chunks {
536 prop_assert!(chunk.len() <= max_concurrent.max(1));
537 }
538 }
539
540 #[test]
541 fn chunk_sizes_never_exceed_max_and_total_preserved(
542 items in prop::collection::vec(0i32..1000, 0..200),
543 max_concurrent in 0usize..32,
544 ) {
545 let effective = max_concurrent.max(1);
546 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
547
548 for chunk in &chunks {
550 prop_assert!(chunk.len() <= effective);
551 prop_assert!(!chunk.is_empty());
552 }
553
554 let total: usize = chunks.iter().map(|c| c.len()).sum();
556 prop_assert_eq!(total, items.len());
557
558 let flattened: Vec<i32> = chunks.into_iter().flatten().collect();
560 prop_assert_eq!(flattened, items);
561 }
562
563 #[test]
564 fn total_items_across_chunks_equals_input_length(
565 items in prop::collection::vec(0u32..500, 0..300),
566 max_concurrent in 1usize..64,
567 ) {
568 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
569 let total: usize = chunks.iter().map(|c| c.len()).sum();
570 prop_assert_eq!(total, items.len());
571 }
572
573 #[test]
574 fn chunk_count_is_ceil_of_n_over_chunk_size(
575 n in 0usize..500,
576 max_concurrent in 1usize..64,
577 ) {
578 let items: Vec<usize> = (0..n).collect();
579 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
580
581 let expected_count = if n == 0 {
582 0
583 } else {
584 n.div_ceil(max_concurrent)
585 };
586 prop_assert_eq!(chunks.len(), expected_count);
587 }
588
589 #[test]
590 fn ordering_within_chunks_preserved_property(
591 items in prop::collection::vec(any::<i64>(), 0..150),
592 max_concurrent in 1usize..20,
593 ) {
594 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
595 let mut offset = 0usize;
596 for chunk in &chunks {
597 for (j, item) in chunk.iter().enumerate() {
598 prop_assert_eq!(item, &items[offset + j]);
599 }
600 offset += chunk.len();
601 }
602 prop_assert_eq!(offset, items.len());
603 }
604
605 #[test]
606 fn no_empty_chunks_emitted_property(
607 items in prop::collection::vec(any::<u8>(), 0..200),
608 max_concurrent in 0usize..64,
609 ) {
610 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
611 for chunk in &chunks {
612 prop_assert!(!chunk.is_empty(), "chunks must never be empty");
613 }
614 }
615
616 #[test]
617 fn determinism_property(
618 items in prop::collection::vec(any::<i32>(), 0..100),
619 max_concurrent in 1usize..32,
620 ) {
621 let first = chunk_by_max_concurrent(&items, max_concurrent);
622 let second = chunk_by_max_concurrent(&items, max_concurrent);
623 prop_assert_eq!(first, second, "chunking must be deterministic");
624 }
625
626 #[test]
627 fn all_full_chunks_have_batch_size_property(
628 n in 1usize..300,
629 max_concurrent in 1usize..64,
630 ) {
631 let items: Vec<usize> = (0..n).collect();
632 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
633 let effective = max_concurrent.max(1);
634 if chunks.len() > 1 {
636 for chunk in &chunks[..chunks.len() - 1] {
637 prop_assert_eq!(chunk.len(), effective,
638 "non-last chunks must have exactly batch_size items");
639 }
640 }
641 if let Some(last) = chunks.last() {
643 prop_assert!(!last.is_empty() && last.len() <= effective);
644 }
645 }
646
647 #[test]
649 fn chunks_cover_indices_exactly_once(
650 n in 0usize..200,
651 max_concurrent in 1usize..32,
652 ) {
653 let items: Vec<usize> = (0..n).collect();
654 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
655 let mut seen = std::collections::HashSet::new();
656 for chunk in &chunks {
657 for &item in chunk {
658 prop_assert!(seen.insert(item), "duplicate index {item}");
659 }
660 }
661 prop_assert_eq!(seen.len(), n, "not all indices covered");
662 }
663
664 #[test]
666 fn unique_input_produces_unique_output(
667 items in prop::collection::vec(0u32..10_000, 0..100),
668 max_concurrent in 1usize..16,
669 ) {
670 let unique_input: std::collections::HashSet<u32> = items.iter().copied().collect();
671 let chunks = chunk_by_max_concurrent(&items, max_concurrent);
672 let flattened: Vec<u32> = chunks.into_iter().flatten().collect();
673 let unique_output: std::collections::HashSet<u32> = flattened.iter().copied().collect();
674 prop_assert_eq!(flattened.len(), items.len());
676 prop_assert_eq!(unique_output.len(), unique_input.len());
677 }
678
679 #[test]
681 fn chunking_is_idempotent_after_flatten(
682 items in prop::collection::vec(any::<i32>(), 0..100),
683 max_concurrent in 1usize..16,
684 ) {
685 let chunks1 = chunk_by_max_concurrent(&items, max_concurrent);
686 let flattened: Vec<i32> = chunks1.iter().flat_map(|c| c.iter().cloned()).collect();
687 let chunks2 = chunk_by_max_concurrent(&flattened, max_concurrent);
688 prop_assert_eq!(chunks1, chunks2, "chunking not idempotent");
689 }
690 }
691}
692#[cfg(test)]
693mod snapshot_tests {
694 use super::chunk_by_max_concurrent;
695 use insta::assert_debug_snapshot;
696 use insta::assert_yaml_snapshot;
697
698 #[test]
699 fn snapshot_chunk_5_by_2() {
700 let items = vec!["a", "b", "c", "d", "e"];
701 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 2));
702 }
703
704 #[test]
705 fn snapshot_chunk_6_by_3() {
706 let items = vec!["core", "utils", "api", "cli", "web", "docs"];
707 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 3));
708 }
709
710 #[test]
711 fn snapshot_chunk_single_item() {
712 let items = vec!["only"];
713 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 5));
714 }
715
716 #[test]
717 fn snapshot_chunk_max_concurrent_1() {
718 let items = vec!["a", "b", "c"];
719 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 1));
720 }
721
722 #[test]
723 fn snapshot_chunk_exact_fit() {
724 let items = vec!["x", "y", "z"];
725 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 3));
726 }
727
728 #[test]
729 fn snapshot_chunk_empty() {
730 let items: Vec<&str> = vec![];
731 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 4));
732 }
733
734 #[test]
735 fn snapshot_chunk_max_concurrent_zero() {
736 let items = vec!["a", "b", "c"];
737 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 0));
738 }
739
740 #[test]
741 fn snapshot_chunk_max_concurrent_usize_max() {
742 let items = vec!["x", "y", "z"];
743 assert_debug_snapshot!(chunk_by_max_concurrent(&items, usize::MAX));
744 }
745
746 #[test]
747 fn snapshot_chunk_single_item_max_one() {
748 let items = vec!["solo"];
749 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 1));
750 }
751
752 #[test]
753 fn snapshot_chunk_large_list_by_7() {
754 let items: Vec<i32> = (1..=21).collect();
755 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 7));
756 }
757
758 #[test]
759 fn snapshot_chunk_1000_items_by_10() {
760 let items: Vec<i32> = (0..1000).collect();
761 let chunks = chunk_by_max_concurrent(&items, 10);
762 let lens: Vec<usize> = chunks.iter().map(|c| c.len()).collect();
764 assert_debug_snapshot!(lens);
765 }
766
767 #[test]
768 fn snapshot_chunk_7_items_by_3() {
769 let items = vec![
770 "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf",
771 ];
772 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 3));
773 }
774
775 #[test]
776 fn snapshot_chunk_size_1_with_4_items() {
777 let items = vec!["w", "x", "y", "z"];
778 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 1));
779 }
780
781 #[test]
782 fn snapshot_chunk_10_items_by_5() {
783 let items: Vec<i32> = (1..=10).collect();
784 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 5));
785 }
786
787 #[test]
788 fn snapshot_dependency_like_items_by_2() {
789 let items = vec![
790 ("core", vec![]),
791 ("utils", vec!["core"]),
792 ("api", vec!["core", "utils"]),
793 ("cli", vec!["api"]),
794 ("web", vec!["api", "utils"]),
795 ];
796 assert_debug_snapshot!(chunk_by_max_concurrent(&items, 2));
797 }
798
799 #[test]
800 fn snapshot_chunk_13_items_by_4_with_remainder() {
801 let items: Vec<&str> = vec![
802 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
803 ];
804 assert_yaml_snapshot!(chunk_by_max_concurrent(&items, 4));
805 }
806
807 #[test]
808 fn snapshot_chunk_prime_37_by_6() {
809 let items: Vec<i32> = (0..37).collect();
810 let chunks = chunk_by_max_concurrent(&items, 6);
811 let lens: Vec<usize> = chunks.iter().map(|c| c.len()).collect();
812 assert_debug_snapshot!(lens);
813 }
814}