1#![allow(
8 clippy::enum_glob_use,
9 clippy::match_same_arms,
10 clippy::struct_field_names,
11 clippy::wildcard_imports
12)]
13#![allow(
20 clippy::cast_precision_loss,
21 clippy::cast_possible_truncation,
22 clippy::cast_sign_loss
23)]
24#![warn(clippy::arithmetic_side_effects)]
38
39use crate::checker::Checker;
40use crate::metrics::npa::python_is_block;
41use std::fmt;
42
43use crate::macros::implement_metric_trait;
44use crate::*;
45
46#[inline]
51fn min_or_zero(v: usize) -> u64 {
52 if v == usize::MAX { 0 } else { v as u64 }
53}
54
55#[inline]
81fn span_rows(start_row: usize, end_line: usize) -> usize {
82 debug_assert!(
83 end_line >= start_row,
84 "span_rows: end_line {end_line} < start_row {start_row}"
85 );
86 end_line.saturating_sub(start_row)
87}
88
89mod line_set;
90use line_set::LineSet;
91
92#[derive(Debug, Clone, PartialEq)]
94pub struct Sloc {
95 start: usize,
96 end_line: usize,
100 excluded_lines: usize,
109 sloc_min: usize,
110 sloc_max: usize,
111}
112
113impl Default for Sloc {
114 fn default() -> Self {
115 Self {
116 start: 0,
117 end_line: 0,
118 excluded_lines: 0,
119 sloc_min: usize::MAX,
120 sloc_max: 0,
121 }
122 }
123}
124
125impl Sloc {
126 #[inline]
128 #[must_use]
129 pub fn sloc(&self) -> u64 {
130 let span = span_rows(self.start, self.end_line);
133 span.saturating_sub(self.excluded_lines) as u64
139 }
140
141 #[inline]
155 pub(crate) fn exclude_span(&mut self, start_row: usize, end_line: usize) {
156 self.excluded_lines = self
157 .excluded_lines
158 .saturating_add(span_rows(start_row, end_line));
159 }
160
161 #[inline]
164 #[must_use]
165 pub fn sloc_min(&self) -> u64 {
166 min_or_zero(self.sloc_min)
167 }
168
169 #[inline]
171 #[must_use]
172 pub fn sloc_max(&self) -> u64 {
173 self.sloc_max as u64
174 }
175
176 #[inline]
179 pub fn merge(&mut self, other: &Sloc) {
180 self.sloc_min = self.sloc_min.min(other.sloc_min);
185 self.sloc_max = self.sloc_max.max(other.sloc_max);
186
187 self.excluded_lines = self.excluded_lines.saturating_add(other.excluded_lines);
201 }
202
203 #[inline]
204 pub(crate) fn compute_minmax(&mut self) {
205 self.sloc_min = self.sloc_min.min(self.sloc() as usize);
210 self.sloc_max = self.sloc_max.max(self.sloc() as usize);
211 }
212}
213
214#[derive(Debug, Clone, PartialEq)]
216pub struct Ploc {
217 lines: LineSet,
218 ploc_min: usize,
219 ploc_max: usize,
220}
221
222impl Default for Ploc {
223 fn default() -> Self {
224 Self {
225 lines: LineSet::default(),
226 ploc_min: usize::MAX,
227 ploc_max: 0,
228 }
229 }
230}
231
232impl Ploc {
233 #[inline]
235 #[must_use]
236 pub fn ploc(&self) -> u64 {
237 self.lines.len() as u64
240 }
241
242 #[inline]
245 #[must_use]
246 pub fn ploc_min(&self) -> u64 {
247 min_or_zero(self.ploc_min)
248 }
249
250 #[inline]
252 #[must_use]
253 pub fn ploc_max(&self) -> u64 {
254 self.ploc_max as u64
255 }
256
257 #[inline]
259 pub fn merge(&mut self, other: &Ploc) {
260 self.lines.union_with(&other.lines);
265
266 self.ploc_min = self.ploc_min.min(other.ploc_min);
268 self.ploc_max = self.ploc_max.max(other.ploc_max);
269 }
270
271 #[inline]
272 pub(crate) fn compute_minmax(&mut self) {
273 let ploc = self.ploc() as usize;
278 self.ploc_min = self.ploc_min.min(ploc);
279 self.ploc_max = self.ploc_max.max(ploc);
280 }
281}
282
283#[derive(Debug, Clone, PartialEq)]
285pub struct Cloc {
286 only_comment_line_starts: LineSet,
294 code_comment_line_starts: LineSet,
302 comment_line_end: Option<usize>,
303 cloc_min: usize,
304 cloc_max: usize,
305}
306
307impl Default for Cloc {
308 fn default() -> Self {
309 Self {
310 only_comment_line_starts: LineSet::default(),
311 code_comment_line_starts: LineSet::default(),
312 comment_line_end: Option::default(),
313 cloc_min: usize::MAX,
314 cloc_max: 0,
315 }
316 }
317}
318
319impl Cloc {
320 #[inline]
322 #[must_use]
323 pub fn cloc(&self) -> u64 {
324 self.only_comment_line_starts
334 .union_len(&self.code_comment_line_starts) as u64
335 }
336
337 #[inline]
340 #[must_use]
341 pub fn cloc_min(&self) -> u64 {
342 min_or_zero(self.cloc_min)
343 }
344
345 #[inline]
347 #[must_use]
348 pub fn cloc_max(&self) -> u64 {
349 self.cloc_max as u64
350 }
351
352 #[inline]
354 pub fn merge(&mut self, other: &Cloc) {
355 self.only_comment_line_starts
358 .union_with(&other.only_comment_line_starts);
359 self.code_comment_line_starts
360 .union_with(&other.code_comment_line_starts);
361
362 self.cloc_min = self.cloc_min.min(other.cloc_min);
364 self.cloc_max = self.cloc_max.max(other.cloc_max);
365 }
366
367 #[inline]
368 pub(crate) fn compute_minmax(&mut self) {
369 let cloc = self.cloc() as usize;
374 self.cloc_min = self.cloc_min.min(cloc);
375 self.cloc_max = self.cloc_max.max(cloc);
376 }
377}
378
379#[derive(Debug, Clone, PartialEq)]
381pub struct Lloc {
382 logical_lines: usize,
383 lloc_min: usize,
384 lloc_max: usize,
385}
386
387impl Default for Lloc {
388 fn default() -> Self {
389 Self {
390 logical_lines: 0,
391 lloc_min: usize::MAX,
392 lloc_max: 0,
393 }
394 }
395}
396
397impl Lloc {
398 #[inline]
400 #[must_use]
401 pub fn lloc(&self) -> u64 {
402 self.logical_lines as u64
405 }
406
407 #[inline]
410 #[must_use]
411 pub fn lloc_min(&self) -> u64 {
412 min_or_zero(self.lloc_min)
413 }
414
415 #[inline]
417 #[must_use]
418 pub fn lloc_max(&self) -> u64 {
419 self.lloc_max as u64
420 }
421
422 #[inline]
432 fn count_logical_line(&mut self) {
433 self.logical_lines = self.logical_lines.saturating_add(1);
434 }
435
436 #[inline]
438 pub fn merge(&mut self, other: &Lloc) {
439 self.logical_lines = self.logical_lines.saturating_add(other.logical_lines);
441 self.lloc_min = self.lloc_min.min(other.lloc_min);
443 self.lloc_max = self.lloc_max.max(other.lloc_max);
444 }
445
446 #[inline]
447 pub(crate) fn compute_minmax(&mut self) {
448 self.lloc_min = self.lloc_min.min(self.lloc() as usize);
451 self.lloc_max = self.lloc_max.max(self.lloc() as usize);
452 }
453}
454
455#[derive(Debug, Clone, PartialEq)]
457#[non_exhaustive]
458pub struct Stats {
459 sloc: Sloc,
460 ploc: Ploc,
461 cloc: Cloc,
462 lloc: Lloc,
463 space_count: usize,
464 blank_min: usize,
465 blank_max: usize,
466}
467
468impl Default for Stats {
469 fn default() -> Self {
470 Self {
471 sloc: Sloc::default(),
472 ploc: Ploc::default(),
473 cloc: Cloc::default(),
474 lloc: Lloc::default(),
475 space_count: 1,
476 blank_min: usize::MAX,
477 blank_max: 0,
478 }
479 }
480}
481
482impl fmt::Display for Stats {
483 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
484 write!(
485 f,
486 "sloc: {}, ploc: {}, lloc: {}, cloc: {}, blank: {}, sloc_average: {}, ploc_average: {}, lloc_average: {}, cloc_average: {}, blank_average: {}, sloc_min: {}, sloc_max: {}, cloc_min: {}, cloc_max: {}, ploc_min: {}, ploc_max: {}, lloc_min: {}, lloc_max: {}, blank_min: {}, blank_max: {}",
487 self.sloc(),
488 self.ploc(),
489 self.lloc(),
490 self.cloc(),
491 self.blank(),
492 self.sloc_average(),
493 self.ploc_average(),
494 self.lloc_average(),
495 self.cloc_average(),
496 self.blank_average(),
497 self.sloc_min(),
498 self.sloc_max(),
499 self.cloc_min(),
500 self.cloc_max(),
501 self.ploc_min(),
502 self.ploc_max(),
503 self.lloc_min(),
504 self.lloc_max(),
505 self.blank_min(),
506 self.blank_max(),
507 )
508 }
509}
510
511impl Stats {
512 #[cfg(test)]
518 pub(crate) fn with_cloc_sloc(code_comment_lines: usize, sloc_end_row: usize) -> Self {
519 let mut stats = Stats::default();
520 stats.sloc.start = 0;
521 stats.sloc.end_line = sloc_end_row.saturating_add(1);
524 if code_comment_lines > 0 {
529 let synthetic_base = sloc_end_row.saturating_add(1);
530 let synthetic_end = synthetic_base
535 .saturating_add(code_comment_lines)
536 .saturating_sub(1);
537 stats
538 .cloc
539 .code_comment_line_starts
540 .insert_range(synthetic_base, synthetic_end);
541 }
542 stats
543 }
544
545 pub fn merge(&mut self, other: &Stats) {
547 self.sloc.merge(&other.sloc);
548 self.ploc.merge(&other.ploc);
549 self.cloc.merge(&other.cloc);
550 self.lloc.merge(&other.lloc);
551
552 self.space_count = self.space_count.saturating_add(other.space_count);
554
555 self.blank_min = self.blank_min.min(other.blank_min);
557 self.blank_max = self.blank_max.max(other.blank_max);
558 }
559
560 #[inline]
566 pub(crate) fn exclude_test_span(&mut self, start_row: usize, end_line: usize) {
567 self.sloc.exclude_span(start_row, end_line);
568 }
569
570 #[inline]
574 #[must_use]
575 pub fn sloc(&self) -> u64 {
576 self.sloc.sloc()
577 }
578
579 #[inline]
583 #[must_use]
584 pub fn ploc(&self) -> u64 {
585 self.ploc.ploc()
586 }
587
588 #[inline]
592 #[must_use]
593 pub fn lloc(&self) -> u64 {
594 self.lloc.lloc()
595 }
596
597 #[inline]
601 #[must_use]
602 pub fn cloc(&self) -> u64 {
603 self.cloc.cloc()
604 }
605
606 #[inline]
610 #[must_use]
611 pub fn blank(&self) -> u64 {
612 self.sloc()
618 .saturating_sub(self.ploc())
619 .saturating_sub(self.cloc.only_comment_line_starts.len() as u64)
620 }
621
622 #[inline]
626 #[must_use]
627 pub fn sloc_average(&self) -> f64 {
628 crate::metrics::average(self.sloc() as f64, self.space_count)
629 }
630
631 #[inline]
635 #[must_use]
636 pub fn ploc_average(&self) -> f64 {
637 crate::metrics::average(self.ploc() as f64, self.space_count)
638 }
639
640 #[inline]
644 #[must_use]
645 pub fn lloc_average(&self) -> f64 {
646 crate::metrics::average(self.lloc() as f64, self.space_count)
647 }
648
649 #[inline]
653 #[must_use]
654 pub fn cloc_average(&self) -> f64 {
655 crate::metrics::average(self.cloc() as f64, self.space_count)
656 }
657
658 #[inline]
662 #[must_use]
663 pub fn blank_average(&self) -> f64 {
664 crate::metrics::average(self.blank() as f64, self.space_count)
665 }
666
667 #[inline]
669 #[must_use]
670 pub fn sloc_min(&self) -> u64 {
671 self.sloc.sloc_min()
672 }
673
674 #[inline]
676 #[must_use]
677 pub fn sloc_max(&self) -> u64 {
678 self.sloc.sloc_max()
679 }
680
681 #[inline]
683 #[must_use]
684 pub fn cloc_min(&self) -> u64 {
685 self.cloc.cloc_min()
686 }
687
688 #[inline]
690 #[must_use]
691 pub fn cloc_max(&self) -> u64 {
692 self.cloc.cloc_max()
693 }
694
695 #[inline]
697 #[must_use]
698 pub fn ploc_min(&self) -> u64 {
699 self.ploc.ploc_min()
700 }
701
702 #[inline]
704 #[must_use]
705 pub fn ploc_max(&self) -> u64 {
706 self.ploc.ploc_max()
707 }
708
709 #[inline]
711 #[must_use]
712 pub fn lloc_min(&self) -> u64 {
713 self.lloc.lloc_min()
714 }
715
716 #[inline]
718 #[must_use]
719 pub fn lloc_max(&self) -> u64 {
720 self.lloc.lloc_max()
721 }
722
723 #[inline]
726 #[must_use]
727 pub fn blank_min(&self) -> u64 {
728 min_or_zero(self.blank_min)
729 }
730
731 #[inline]
733 #[must_use]
734 pub fn blank_max(&self) -> u64 {
735 self.blank_max as u64
736 }
737
738 #[inline]
739 pub(crate) fn compute_minmax(&mut self) {
740 self.sloc.compute_minmax();
741 self.ploc.compute_minmax();
742 self.cloc.compute_minmax();
743 self.lloc.compute_minmax();
744
745 let blank = self.blank() as usize;
752 self.blank_min = self.blank_min.min(blank);
753 self.blank_max = self.blank_max.max(blank);
754 }
755
756 pub(crate) fn init_unit_span(&mut self, start: usize, end_line: usize) {
757 self.sloc.start = start;
758 self.sloc.end_line = end_line;
759 }
760}
761
762#[doc(hidden)]
763pub(crate) trait Loc
765where
766 Self: Checker,
767{
768 fn compute(node: &Node, ancestors: Ancestors<'_, '_>, stats: &mut Stats, is_func_space: bool);
774}
775
776mod shared;
777pub(crate) use shared::*;
778
779implement_metric_trait!(Loc, PreprocCode, CcommentCode);
783
784mod bash;
785mod c;
786mod cpp;
787mod csharp;
788mod elixir;
789mod go;
790mod groovy;
791mod irules;
792mod java;
793mod javascript;
794mod kotlin;
795mod lua;
796mod mozcpp;
797mod mozjs;
798mod objc;
799mod perl;
800mod php;
801mod python;
802mod ruby;
803mod rust;
804mod tcl;
805mod tsx;
806mod typescript;
807
808#[cfg(test)]
809#[allow(
810 clippy::float_cmp,
811 clippy::cast_precision_loss,
812 clippy::cast_possible_truncation,
813 clippy::cast_sign_loss,
814 clippy::similar_names,
815 clippy::doc_markdown,
816 clippy::needless_raw_string_hashes,
817 clippy::too_many_lines
818)]
819mod tests {
820 use crate::test_support::{check_metrics_only_shim, metrics_verbatim, space_verbatim};
821
822 use super::*;
823
824 check_metrics_only_shim!(check_metrics, Loc);
825
826 #[test]
832 fn loc_empty_file_min_is_zero() {
833 let stats = Stats::default();
834 assert_eq!(stats.sloc_min(), 0);
835 assert_eq!(stats.ploc_min(), 0);
836 assert_eq!(stats.lloc_min(), 0);
837 assert_eq!(stats.cloc_min(), 0);
838 assert_eq!(stats.blank_min(), 0);
839 }
840
841 #[cfg(test)]
847 fn assert_perl_parses_cleanly(source: &str) {
848 use crate::traits::ParserTrait;
849 let path = std::path::PathBuf::from("foo.pl");
853 let mut bytes = source.trim_end_matches('\n').as_bytes().to_vec();
854 bytes.push(b'\n');
855 let parser = PerlParser::new(bytes, &path, None);
856 assert!(
857 !parser.root().has_error(),
858 "tree-sitter-perl returned an error tree for snippet:\n{source}"
859 );
860 }
861
862 #[test]
863 fn python_sloc() {
864 check_metrics::<PythonParser>(
865 "
866
867 a = 42
868
869 ",
870 "foo.py",
871 |metric| {
872 insta::assert_json_snapshot!(
874 metric.loc,
875 @r#"
876 {
877 "sloc": 1,
878 "ploc": 1,
879 "lloc": 1,
880 "cloc": 0,
881 "blank": 0,
882 "sloc_average": 1.0,
883 "ploc_average": 1.0,
884 "lloc_average": 1.0,
885 "cloc_average": 0.0,
886 "blank_average": 0.0,
887 "sloc_min": 1,
888 "sloc_max": 1,
889 "cloc_min": 0,
890 "cloc_max": 0,
891 "ploc_min": 1,
892 "ploc_max": 1,
893 "lloc_min": 1,
894 "lloc_max": 1,
895 "blank_min": 0,
896 "blank_max": 0
897 }
898 "#
899 );
900 },
901 );
902 }
903
904 #[test]
905 fn python_blank() {
906 check_metrics::<PythonParser>(
907 "
908 a = 42
909
910 b = 43
911
912 ",
913 "foo.py",
914 |metric| {
915 insta::assert_json_snapshot!(
917 metric.loc,
918 @r#"
919 {
920 "sloc": 3,
921 "ploc": 2,
922 "lloc": 2,
923 "cloc": 0,
924 "blank": 1,
925 "sloc_average": 3.0,
926 "ploc_average": 2.0,
927 "lloc_average": 2.0,
928 "cloc_average": 0.0,
929 "blank_average": 1.0,
930 "sloc_min": 3,
931 "sloc_max": 3,
932 "cloc_min": 0,
933 "cloc_max": 0,
934 "ploc_min": 2,
935 "ploc_max": 2,
936 "lloc_min": 2,
937 "lloc_max": 2,
938 "blank_min": 1,
939 "blank_max": 1
940 }
941 "#
942 );
943 },
944 );
945 }
946
947 #[test]
948 fn rust_blank() {
949 check_metrics::<RustParser>(
950 "
951
952 let a = 42;
953
954 let b = 43;
955
956 ",
957 "foo.rs",
958 |metric| {
959 insta::assert_json_snapshot!(
961 metric.loc,
962 @r#"
963 {
964 "sloc": 3,
965 "ploc": 2,
966 "lloc": 2,
967 "cloc": 0,
968 "blank": 1,
969 "sloc_average": 3.0,
970 "ploc_average": 2.0,
971 "lloc_average": 2.0,
972 "cloc_average": 0.0,
973 "blank_average": 1.0,
974 "sloc_min": 3,
975 "sloc_max": 3,
976 "cloc_min": 0,
977 "cloc_max": 0,
978 "ploc_min": 2,
979 "ploc_max": 2,
980 "lloc_min": 2,
981 "lloc_max": 2,
982 "blank_min": 1,
983 "blank_max": 1
984 }
985 "#
986 );
987 },
988 );
989
990 check_metrics::<RustParser>("fn func() { /* comment */ }", "foo.rs", |metric| {
991 insta::assert_json_snapshot!(
993 metric.loc,
994 @r#"
995 {
996 "sloc": 1,
997 "ploc": 1,
998 "lloc": 0,
999 "cloc": 1,
1000 "blank": 0,
1001 "sloc_average": 0.5,
1002 "ploc_average": 0.5,
1003 "lloc_average": 0.0,
1004 "cloc_average": 0.5,
1005 "blank_average": 0.0,
1006 "sloc_min": 1,
1007 "sloc_max": 1,
1008 "cloc_min": 1,
1009 "cloc_max": 1,
1010 "ploc_min": 1,
1011 "ploc_max": 1,
1012 "lloc_min": 0,
1013 "lloc_max": 0,
1014 "blank_min": 0,
1015 "blank_max": 0
1016 }
1017 "#
1018 );
1019 });
1020 }
1021
1022 #[test]
1023 fn c_blank() {
1024 check_metrics::<CParser>(
1025 "
1026
1027 int a = 42;
1028
1029 int b = 43;
1030
1031 ",
1032 "foo.c",
1033 |metric| {
1034 insta::assert_json_snapshot!(
1036 metric.loc,
1037 @r#"
1038 {
1039 "sloc": 3,
1040 "ploc": 2,
1041 "lloc": 2,
1042 "cloc": 0,
1043 "blank": 1,
1044 "sloc_average": 3.0,
1045 "ploc_average": 2.0,
1046 "lloc_average": 2.0,
1047 "cloc_average": 0.0,
1048 "blank_average": 1.0,
1049 "sloc_min": 3,
1050 "sloc_max": 3,
1051 "cloc_min": 0,
1052 "cloc_max": 0,
1053 "ploc_min": 2,
1054 "ploc_max": 2,
1055 "lloc_min": 2,
1056 "lloc_max": 2,
1057 "blank_min": 1,
1058 "blank_max": 1
1059 }
1060 "#
1061 );
1062 },
1063 );
1064 }
1065
1066 #[test]
1067 fn python_no_zero_blank() {
1068 check_metrics::<PythonParser>(
1071 "def ConnectToUpdateServer():
1072 pool = 4
1073
1074 updateServer = -42
1075 isConnected = False
1076 currTry = 0
1077 numRetries = 10 # Number of IPC connection retries before
1078 # giving up.
1079 numTries = 20 # Number of IPC connection tries before
1080 # giving up.",
1081 "foo.py",
1082 |metric| {
1083 insta::assert_json_snapshot!(
1085 metric.loc,
1086 @r#"
1087 {
1088 "sloc": 10,
1089 "ploc": 7,
1090 "lloc": 6,
1091 "cloc": 4,
1092 "blank": 1,
1093 "sloc_average": 5.0,
1094 "ploc_average": 3.5,
1095 "lloc_average": 3.0,
1096 "cloc_average": 2.0,
1097 "blank_average": 0.5,
1098 "sloc_min": 10,
1099 "sloc_max": 10,
1100 "cloc_min": 4,
1101 "cloc_max": 4,
1102 "ploc_min": 7,
1103 "ploc_max": 7,
1104 "lloc_min": 6,
1105 "lloc_max": 6,
1106 "blank_min": 1,
1107 "blank_max": 1
1108 }
1109 "#
1110 );
1111 },
1112 );
1113 }
1114
1115 #[test]
1116 fn python_no_blank() {
1117 check_metrics::<PythonParser>(
1120 "def ConnectToUpdateServer():
1121 pool = 4
1122 updateServer = -42
1123 isConnected = False
1124 currTry = 0
1125 numRetries = 10 # Number of IPC connection retries before
1126 # giving up.
1127 numTries = 20 # Number of IPC connection tries before
1128 # giving up.",
1129 "foo.py",
1130 |metric| {
1131 insta::assert_json_snapshot!(
1133 metric.loc,
1134 @r#"
1135 {
1136 "sloc": 9,
1137 "ploc": 7,
1138 "lloc": 6,
1139 "cloc": 4,
1140 "blank": 0,
1141 "sloc_average": 4.5,
1142 "ploc_average": 3.5,
1143 "lloc_average": 3.0,
1144 "cloc_average": 2.0,
1145 "blank_average": 0.0,
1146 "sloc_min": 9,
1147 "sloc_max": 9,
1148 "cloc_min": 4,
1149 "cloc_max": 4,
1150 "ploc_min": 7,
1151 "ploc_max": 7,
1152 "lloc_min": 6,
1153 "lloc_max": 6,
1154 "blank_min": 0,
1155 "blank_max": 0
1156 }
1157 "#
1158 );
1159 },
1160 );
1161 }
1162
1163 #[test]
1164 fn python_no_zero_blank_more_comments() {
1165 check_metrics::<PythonParser>(
1168 "def ConnectToUpdateServer():
1169 pool = 4
1170
1171 updateServer = -42
1172 isConnected = False
1173 currTry = 0 # Set this variable to 0
1174 numRetries = 10 # Number of IPC connection retries before
1175 # giving up.
1176 numTries = 20 # Number of IPC connection tries before
1177 # giving up.",
1178 "foo.py",
1179 |metric| {
1180 insta::assert_json_snapshot!(
1182 metric.loc,
1183 @r#"
1184 {
1185 "sloc": 10,
1186 "ploc": 7,
1187 "lloc": 6,
1188 "cloc": 5,
1189 "blank": 1,
1190 "sloc_average": 5.0,
1191 "ploc_average": 3.5,
1192 "lloc_average": 3.0,
1193 "cloc_average": 2.5,
1194 "blank_average": 0.5,
1195 "sloc_min": 10,
1196 "sloc_max": 10,
1197 "cloc_min": 5,
1198 "cloc_max": 5,
1199 "ploc_min": 7,
1200 "ploc_max": 7,
1201 "lloc_min": 6,
1202 "lloc_max": 6,
1203 "blank_min": 1,
1204 "blank_max": 1
1205 }
1206 "#
1207 );
1208 },
1209 );
1210 }
1211
1212 #[test]
1213 fn rust_no_zero_blank() {
1214 check_metrics::<RustParser>(
1217 "fn ConnectToUpdateServer() {
1218 let pool = 0;
1219
1220 let updateServer = -42;
1221 let isConnected = false;
1222 let currTry = 0;
1223 let numRetries = 10; // Number of IPC connection retries before
1224 // giving up.
1225 let numTries = 20; // Number of IPC connection tries before
1226 // giving up.
1227 }",
1228 "foo.rs",
1229 |metric| {
1230 insta::assert_json_snapshot!(
1232 metric.loc,
1233 @r#"
1234 {
1235 "sloc": 11,
1236 "ploc": 8,
1237 "lloc": 6,
1238 "cloc": 4,
1239 "blank": 1,
1240 "sloc_average": 5.5,
1241 "ploc_average": 4.0,
1242 "lloc_average": 3.0,
1243 "cloc_average": 2.0,
1244 "blank_average": 0.5,
1245 "sloc_min": 11,
1246 "sloc_max": 11,
1247 "cloc_min": 4,
1248 "cloc_max": 4,
1249 "ploc_min": 8,
1250 "ploc_max": 8,
1251 "lloc_min": 6,
1252 "lloc_max": 6,
1253 "blank_min": 1,
1254 "blank_max": 1
1255 }
1256 "#
1257 );
1258 },
1259 );
1260 }
1261
1262 #[test]
1263 fn javascript_no_zero_blank() {
1264 check_metrics::<JavascriptParser>(
1267 "function ConnectToUpdateServer() {
1268 var pool = 0;
1269
1270 var updateServer = -42;
1271 var isConnected = false;
1272 var currTry = 0;
1273 var numRetries = 10; // Number of IPC connection retries before
1274 // giving up.
1275 var numTries = 20; // Number of IPC connection tries before
1276 // giving up.
1277 }",
1278 "foo.js",
1279 |metric| {
1280 insta::assert_json_snapshot!(
1282 metric.loc,
1283 @r#"
1284 {
1285 "sloc": 11,
1286 "ploc": 8,
1287 "lloc": 6,
1288 "cloc": 4,
1289 "blank": 1,
1290 "sloc_average": 5.5,
1291 "ploc_average": 4.0,
1292 "lloc_average": 3.0,
1293 "cloc_average": 2.0,
1294 "blank_average": 0.5,
1295 "sloc_min": 11,
1296 "sloc_max": 11,
1297 "cloc_min": 4,
1298 "cloc_max": 4,
1299 "ploc_min": 8,
1300 "ploc_max": 8,
1301 "lloc_min": 6,
1302 "lloc_max": 6,
1303 "blank_min": 1,
1304 "blank_max": 1
1305 }
1306 "#
1307 );
1308 },
1309 );
1310 }
1311
1312 #[test]
1313 fn cpp_no_zero_blank() {
1314 check_metrics::<CppParser>(
1317 "void ConnectToUpdateServer() {
1318 int pool;
1319
1320 int updateServer = -42;
1321 bool isConnected = false;
1322 int currTry = 0;
1323 const int numRetries = 10; // Number of IPC connection retries before
1324 // giving up.
1325 const int numTries = 20; // Number of IPC connection tries before
1326 // giving up.
1327 }",
1328 "foo.cpp",
1329 |metric| {
1330 insta::assert_json_snapshot!(
1332 metric.loc,
1333 @r#"
1334 {
1335 "sloc": 11,
1336 "ploc": 8,
1337 "lloc": 6,
1338 "cloc": 4,
1339 "blank": 1,
1340 "sloc_average": 5.5,
1341 "ploc_average": 4.0,
1342 "lloc_average": 3.0,
1343 "cloc_average": 2.0,
1344 "blank_average": 0.5,
1345 "sloc_min": 11,
1346 "sloc_max": 11,
1347 "cloc_min": 4,
1348 "cloc_max": 4,
1349 "ploc_min": 8,
1350 "ploc_max": 8,
1351 "lloc_min": 6,
1352 "lloc_max": 6,
1353 "blank_min": 1,
1354 "blank_max": 1
1355 }
1356 "#
1357 );
1358 },
1359 );
1360 }
1361
1362 #[test]
1363 fn cpp_code_line_start_block_blank() {
1364 check_metrics::<CppParser>(
1367 "void ConnectToUpdateServer() {
1368 int pool;
1369
1370 int updateServer = -42;
1371 bool isConnected = false;
1372 int currTry = 0;
1373 const int numRetries = 10; /* Number of IPC connection retries
1374 before
1375 giving up. */
1376 const int numTries = 20; // Number of IPC connection tries before
1377 // giving up.
1378 }",
1379 "foo.cpp",
1380 |metric| {
1381 insta::assert_json_snapshot!(
1383 metric.loc,
1384 @r#"
1385 {
1386 "sloc": 12,
1387 "ploc": 8,
1388 "lloc": 6,
1389 "cloc": 5,
1390 "blank": 1,
1391 "sloc_average": 6.0,
1392 "ploc_average": 4.0,
1393 "lloc_average": 3.0,
1394 "cloc_average": 2.5,
1395 "blank_average": 0.5,
1396 "sloc_min": 12,
1397 "sloc_max": 12,
1398 "cloc_min": 5,
1399 "cloc_max": 5,
1400 "ploc_min": 8,
1401 "ploc_max": 8,
1402 "lloc_min": 6,
1403 "lloc_max": 6,
1404 "blank_min": 1,
1405 "blank_max": 1
1406 }
1407 "#
1408 );
1409 },
1410 );
1411 }
1412
1413 #[test]
1414 fn cpp_block_comment_blank() {
1415 check_metrics::<CppParser>(
1418 "void ConnectToUpdateServer() {
1419 int pool;
1420
1421 int updateServer = -42;
1422 bool isConnected = false;
1423 int currTry = 0;
1424 /* Number of IPC connection retries
1425 before
1426 giving up. */
1427 const int numRetries = 10;
1428 const int numTries = 20; // Number of IPC connection tries before
1429 // giving up.
1430 }",
1431 "foo.cpp",
1432 |metric| {
1433 insta::assert_json_snapshot!(
1435 metric.loc,
1436 @r#"
1437 {
1438 "sloc": 13,
1439 "ploc": 8,
1440 "lloc": 6,
1441 "cloc": 5,
1442 "blank": 1,
1443 "sloc_average": 6.5,
1444 "ploc_average": 4.0,
1445 "lloc_average": 3.0,
1446 "cloc_average": 2.5,
1447 "blank_average": 0.5,
1448 "sloc_min": 13,
1449 "sloc_max": 13,
1450 "cloc_min": 5,
1451 "cloc_max": 5,
1452 "ploc_min": 8,
1453 "ploc_max": 8,
1454 "lloc_min": 6,
1455 "lloc_max": 6,
1456 "blank_min": 1,
1457 "blank_max": 1
1458 }
1459 "#
1460 );
1461 },
1462 );
1463 }
1464
1465 #[test]
1466 fn cpp_code_line_block_one_line_blank() {
1467 check_metrics::<CppParser>(
1470 "void ConnectToUpdateServer() {
1471 int pool;
1472
1473 int updateServer = -42;
1474 bool isConnected = false;
1475 int currTry = 0;
1476 /* Number of IPC connection retries before giving up. */ const int numRetries = 10;
1477 const int numTries = 20; // Number of IPC connection tries before
1478 // giving up.
1479 }",
1480 "foo.cpp",
1481 |metric| {
1482 insta::assert_json_snapshot!(
1484 metric.loc,
1485 @r#"
1486 {
1487 "sloc": 10,
1488 "ploc": 8,
1489 "lloc": 6,
1490 "cloc": 3,
1491 "blank": 1,
1492 "sloc_average": 5.0,
1493 "ploc_average": 4.0,
1494 "lloc_average": 3.0,
1495 "cloc_average": 1.5,
1496 "blank_average": 0.5,
1497 "sloc_min": 10,
1498 "sloc_max": 10,
1499 "cloc_min": 3,
1500 "cloc_max": 3,
1501 "ploc_min": 8,
1502 "ploc_max": 8,
1503 "lloc_min": 6,
1504 "lloc_max": 6,
1505 "blank_min": 1,
1506 "blank_max": 1
1507 }
1508 "#
1509 );
1510 },
1511 );
1512 }
1513
1514 #[test]
1515 fn cpp_code_line_end_block_blank() {
1516 check_metrics::<CppParser>(
1519 "void ConnectToUpdateServer() {
1520 int pool;
1521
1522 int updateServer = -42;
1523 bool isConnected = false;
1524 int currTry = 0;
1525 /* Number of IPC connection retries
1526 before
1527 giving up. */ const int numRetries = 10;
1528 const int numTries = 20; // Number of IPC connection tries before
1529 // giving up.
1530 }",
1531 "foo.cpp",
1532 |metric| {
1533 insta::assert_json_snapshot!(
1535 metric.loc,
1536 @r#"
1537 {
1538 "sloc": 12,
1539 "ploc": 8,
1540 "lloc": 6,
1541 "cloc": 5,
1542 "blank": 1,
1543 "sloc_average": 6.0,
1544 "ploc_average": 4.0,
1545 "lloc_average": 3.0,
1546 "cloc_average": 2.5,
1547 "blank_average": 0.5,
1548 "sloc_min": 12,
1549 "sloc_max": 12,
1550 "cloc_min": 5,
1551 "cloc_max": 5,
1552 "ploc_min": 8,
1553 "ploc_max": 8,
1554 "lloc_min": 6,
1555 "lloc_max": 6,
1556 "blank_min": 1,
1557 "blank_max": 1
1558 }
1559 "#
1560 );
1561 },
1562 );
1563 }
1564
1565 #[test]
1566 fn python_cloc() {
1567 check_metrics::<PythonParser>(
1568 "\"\"\"Block comment
1569 Block comment
1570 \"\"\"
1571 # Line Comment
1572 a = 42 # Line Comment",
1573 "foo.py",
1574 |metric| {
1575 insta::assert_json_snapshot!(
1577 metric.loc,
1578 @r#"
1579 {
1580 "sloc": 5,
1581 "ploc": 1,
1582 "lloc": 2,
1583 "cloc": 5,
1584 "blank": 0,
1585 "sloc_average": 5.0,
1586 "ploc_average": 1.0,
1587 "lloc_average": 2.0,
1588 "cloc_average": 5.0,
1589 "blank_average": 0.0,
1590 "sloc_min": 5,
1591 "sloc_max": 5,
1592 "cloc_min": 5,
1593 "cloc_max": 5,
1594 "ploc_min": 1,
1595 "ploc_max": 1,
1596 "lloc_min": 2,
1597 "lloc_max": 2,
1598 "blank_min": 0,
1599 "blank_max": 0
1600 }
1601 "#
1602 );
1603 },
1604 );
1605 }
1606
1607 #[test]
1608 fn rust_cloc() {
1609 check_metrics::<RustParser>(
1610 "/*Block comment
1611 Block Comment*/
1612 //Line Comment
1613 /*Block Comment*/ let a = 42; // Line Comment",
1614 "foo.rs",
1615 |metric| {
1616 insta::assert_json_snapshot!(
1625 metric.loc,
1626 @r#"
1627 {
1628 "sloc": 4,
1629 "ploc": 1,
1630 "lloc": 1,
1631 "cloc": 4,
1632 "blank": 0,
1633 "sloc_average": 4.0,
1634 "ploc_average": 1.0,
1635 "lloc_average": 1.0,
1636 "cloc_average": 4.0,
1637 "blank_average": 0.0,
1638 "sloc_min": 4,
1639 "sloc_max": 4,
1640 "cloc_min": 4,
1641 "cloc_max": 4,
1642 "ploc_min": 1,
1643 "ploc_max": 1,
1644 "lloc_min": 1,
1645 "lloc_max": 1,
1646 "blank_min": 0,
1647 "blank_max": 0
1648 }
1649 "#
1650 );
1651 },
1652 );
1653 }
1654
1655 #[test]
1656 fn c_cloc() {
1657 check_metrics::<CParser>(
1658 "/*Block comment
1659 Block Comment*/
1660 //Line Comment
1661 /*Block Comment*/ int a = 42; // Line Comment",
1662 "foo.c",
1663 |metric| {
1664 insta::assert_json_snapshot!(
1670 metric.loc,
1671 @r#"
1672 {
1673 "sloc": 4,
1674 "ploc": 1,
1675 "lloc": 1,
1676 "cloc": 4,
1677 "blank": 0,
1678 "sloc_average": 4.0,
1679 "ploc_average": 1.0,
1680 "lloc_average": 1.0,
1681 "cloc_average": 4.0,
1682 "blank_average": 0.0,
1683 "sloc_min": 4,
1684 "sloc_max": 4,
1685 "cloc_min": 4,
1686 "cloc_max": 4,
1687 "ploc_min": 1,
1688 "ploc_max": 1,
1689 "lloc_min": 1,
1690 "lloc_max": 1,
1691 "blank_min": 0,
1692 "blank_max": 0
1693 }
1694 "#
1695 );
1696 },
1697 );
1698 }
1699
1700 #[test]
1701 fn python_lloc() {
1702 check_metrics::<PythonParser>(
1703 "for x in range(0,42):
1704 if x % 2 == 0:
1705 print(x)",
1706 "foo.py",
1707 |metric| {
1708 insta::assert_json_snapshot!(
1710 metric.loc,
1711 @r#"
1712 {
1713 "sloc": 3,
1714 "ploc": 3,
1715 "lloc": 3,
1716 "cloc": 0,
1717 "blank": 0,
1718 "sloc_average": 3.0,
1719 "ploc_average": 3.0,
1720 "lloc_average": 3.0,
1721 "cloc_average": 0.0,
1722 "blank_average": 0.0,
1723 "sloc_min": 3,
1724 "sloc_max": 3,
1725 "cloc_min": 0,
1726 "cloc_max": 0,
1727 "ploc_min": 3,
1728 "ploc_max": 3,
1729 "lloc_min": 3,
1730 "lloc_max": 3,
1731 "blank_min": 0,
1732 "blank_max": 0
1733 }
1734 "#
1735 );
1736 },
1737 );
1738 }
1739
1740 #[test]
1741 fn rust_lloc() {
1742 check_metrics::<RustParser>(
1743 "for x in 0..42 {
1744 if x % 2 == 0 {
1745 println!(\"{}\", x);
1746 }
1747 }",
1748 "foo.rs",
1749 |metric| {
1750 insta::assert_json_snapshot!(
1752 metric.loc,
1753 @r#"
1754 {
1755 "sloc": 5,
1756 "ploc": 5,
1757 "lloc": 3,
1758 "cloc": 0,
1759 "blank": 0,
1760 "sloc_average": 5.0,
1761 "ploc_average": 5.0,
1762 "lloc_average": 3.0,
1763 "cloc_average": 0.0,
1764 "blank_average": 0.0,
1765 "sloc_min": 5,
1766 "sloc_max": 5,
1767 "cloc_min": 0,
1768 "cloc_max": 0,
1769 "ploc_min": 5,
1770 "ploc_max": 5,
1771 "lloc_min": 3,
1772 "lloc_max": 3,
1773 "blank_min": 0,
1774 "blank_max": 0
1775 }
1776 "#
1777 );
1778 },
1779 );
1780
1781 check_metrics::<RustParser>(
1783 "let a = 42;
1784 if true {
1785 42
1786 } else {
1787 43
1788 };",
1789 "foo.rs",
1790 |metric| {
1791 insta::assert_json_snapshot!(
1793 metric.loc,
1794 @r#"
1795 {
1796 "sloc": 6,
1797 "ploc": 6,
1798 "lloc": 3,
1799 "cloc": 0,
1800 "blank": 0,
1801 "sloc_average": 6.0,
1802 "ploc_average": 6.0,
1803 "lloc_average": 3.0,
1804 "cloc_average": 0.0,
1805 "blank_average": 0.0,
1806 "sloc_min": 6,
1807 "sloc_max": 6,
1808 "cloc_min": 0,
1809 "cloc_max": 0,
1810 "ploc_min": 6,
1811 "ploc_max": 6,
1812 "lloc_min": 3,
1813 "lloc_max": 3,
1814 "blank_min": 0,
1815 "blank_max": 0
1816 }
1817 "#
1818 );
1819 },
1820 );
1821 }
1822
1823 #[test]
1824 fn c_lloc() {
1825 check_metrics::<CParser>(
1826 "for (;;)
1827 break;",
1828 "foo.c",
1829 |metric| {
1830 insta::assert_json_snapshot!(
1832 metric.loc,
1833 @r#"
1834 {
1835 "sloc": 2,
1836 "ploc": 2,
1837 "lloc": 2,
1838 "cloc": 0,
1839 "blank": 0,
1840 "sloc_average": 2.0,
1841 "ploc_average": 2.0,
1842 "lloc_average": 2.0,
1843 "cloc_average": 0.0,
1844 "blank_average": 0.0,
1845 "sloc_min": 2,
1846 "sloc_max": 2,
1847 "cloc_min": 0,
1848 "cloc_max": 0,
1849 "ploc_min": 2,
1850 "ploc_max": 2,
1851 "lloc_min": 2,
1852 "lloc_max": 2,
1853 "blank_min": 0,
1854 "blank_max": 0
1855 }
1856 "#
1857 );
1858 },
1859 );
1860 }
1861
1862 #[test]
1863 fn cpp_lloc() {
1864 check_metrics::<CppParser>(
1865 "nsTArray<xpcGCCallback> callbacks(extraGCCallbacks.Clone());
1866 for (uint32_t i = 0; i < callbacks.Length(); ++i) {
1867 callbacks[i](status);
1868 }",
1869 "foo.cpp",
1870 |metric| {
1871 insta::assert_json_snapshot!(
1874 metric.loc,
1875 @r#"
1876 {
1877 "sloc": 4,
1878 "ploc": 4,
1879 "lloc": 3,
1880 "cloc": 0,
1881 "blank": 0,
1882 "sloc_average": 4.0,
1883 "ploc_average": 4.0,
1884 "lloc_average": 3.0,
1885 "cloc_average": 0.0,
1886 "blank_average": 0.0,
1887 "sloc_min": 4,
1888 "sloc_max": 4,
1889 "cloc_min": 0,
1890 "cloc_max": 0,
1891 "ploc_min": 4,
1892 "ploc_max": 4,
1893 "lloc_min": 3,
1894 "lloc_max": 3,
1895 "blank_min": 0,
1896 "blank_max": 0
1897 }
1898 "#
1899 );
1900 },
1901 );
1902 }
1903
1904 #[test]
1905 fn cpp_return_lloc() {
1906 check_metrics::<CppParser>(
1907 "uint8_t* pixel_data = frame.GetFrameDataAtPos(DesktopVector(x, y));
1908 return RgbaColor(pixel_data) == blank_pixel_;",
1909 "foo.cpp",
1910 |metric| {
1911 insta::assert_json_snapshot!(
1914 metric.loc,
1915 @r#"
1916 {
1917 "sloc": 2,
1918 "ploc": 2,
1919 "lloc": 2,
1920 "cloc": 0,
1921 "blank": 0,
1922 "sloc_average": 2.0,
1923 "ploc_average": 2.0,
1924 "lloc_average": 2.0,
1925 "cloc_average": 0.0,
1926 "blank_average": 0.0,
1927 "sloc_min": 2,
1928 "sloc_max": 2,
1929 "cloc_min": 0,
1930 "cloc_max": 0,
1931 "ploc_min": 2,
1932 "ploc_max": 2,
1933 "lloc_min": 2,
1934 "lloc_max": 2,
1935 "blank_min": 0,
1936 "blank_max": 0
1937 }
1938 "#
1939 );
1940 },
1941 );
1942 }
1943
1944 #[test]
1945 fn cpp_for_lloc() {
1946 check_metrics::<CppParser>(
1947 "for (; start != end; ++start) {
1948 const unsigned char idx = *start;
1949 if (idx > 127 || !kValidTokenMap[idx]) return false;
1950 }",
1951 "foo.cpp",
1952 |metric| {
1953 insta::assert_json_snapshot!(
1956 metric.loc,
1957 @r#"
1958 {
1959 "sloc": 4,
1960 "ploc": 4,
1961 "lloc": 4,
1962 "cloc": 0,
1963 "blank": 0,
1964 "sloc_average": 4.0,
1965 "ploc_average": 4.0,
1966 "lloc_average": 4.0,
1967 "cloc_average": 0.0,
1968 "blank_average": 0.0,
1969 "sloc_min": 4,
1970 "sloc_max": 4,
1971 "cloc_min": 0,
1972 "cloc_max": 0,
1973 "ploc_min": 4,
1974 "ploc_max": 4,
1975 "lloc_min": 4,
1976 "lloc_max": 4,
1977 "blank_min": 0,
1978 "blank_max": 0
1979 }
1980 "#
1981 );
1982 },
1983 );
1984 }
1985
1986 #[test]
1987 fn cpp_while_lloc() {
1988 check_metrics::<CppParser>(
1989 "while (sHeapAtoms) {
1990 HttpHeapAtom* next = sHeapAtoms->next;
1991 free(sHeapAtoms);
1992 }",
1993 "foo.cpp",
1994 |metric| {
1995 insta::assert_json_snapshot!(
1998 metric.loc,
1999 @r#"
2000 {
2001 "sloc": 4,
2002 "ploc": 4,
2003 "lloc": 3,
2004 "cloc": 0,
2005 "blank": 0,
2006 "sloc_average": 4.0,
2007 "ploc_average": 4.0,
2008 "lloc_average": 3.0,
2009 "cloc_average": 0.0,
2010 "blank_average": 0.0,
2011 "sloc_min": 4,
2012 "sloc_max": 4,
2013 "cloc_min": 0,
2014 "cloc_max": 0,
2015 "ploc_min": 4,
2016 "ploc_max": 4,
2017 "lloc_min": 3,
2018 "lloc_max": 3,
2019 "blank_min": 0,
2020 "blank_max": 0
2021 }
2022 "#
2023 );
2024 },
2025 );
2026 }
2027
2028 #[test]
2029 fn python_string_on_new_line() {
2030 check_metrics::<PythonParser>(
2032 "capabilities[\"goog:chromeOptions\"][\"androidPackage\"] = \\
2033 \"org.chromium.weblayer.shell\"",
2034 "foo.py",
2035 |metric| {
2036 insta::assert_json_snapshot!(
2038 metric.loc,
2039 @r#"
2040 {
2041 "sloc": 2,
2042 "ploc": 2,
2043 "lloc": 1,
2044 "cloc": 0,
2045 "blank": 0,
2046 "sloc_average": 2.0,
2047 "ploc_average": 2.0,
2048 "lloc_average": 1.0,
2049 "cloc_average": 0.0,
2050 "blank_average": 0.0,
2051 "sloc_min": 2,
2052 "sloc_max": 2,
2053 "cloc_min": 0,
2054 "cloc_max": 0,
2055 "ploc_min": 2,
2056 "ploc_max": 2,
2057 "lloc_min": 1,
2058 "lloc_max": 1,
2059 "blank_min": 0,
2060 "blank_max": 0
2061 }
2062 "#
2063 );
2064 },
2065 );
2066 }
2067
2068 #[test]
2069 fn python_multiline_string_assignment_ploc() {
2070 check_metrics::<PythonParser>(
2073 "QUERY = \"\"\"
2074SELECT id, name
2075FROM users
2076WHERE active = 1
2077ORDER BY name
2078\"\"\"",
2079 "foo.py",
2080 |metric| {
2081 assert_eq!(metric.loc.sloc(), 6);
2083 assert_eq!(metric.loc.ploc(), 6);
2084 assert_eq!(metric.loc.cloc(), 0);
2085 assert_eq!(metric.loc.blank(), 0);
2086 insta::assert_json_snapshot!(
2087 metric.loc,
2088 @r#"
2089 {
2090 "sloc": 6,
2091 "ploc": 6,
2092 "lloc": 1,
2093 "cloc": 0,
2094 "blank": 0,
2095 "sloc_average": 6.0,
2096 "ploc_average": 6.0,
2097 "lloc_average": 1.0,
2098 "cloc_average": 0.0,
2099 "blank_average": 0.0,
2100 "sloc_min": 6,
2101 "sloc_max": 6,
2102 "cloc_min": 0,
2103 "cloc_max": 0,
2104 "ploc_min": 6,
2105 "ploc_max": 6,
2106 "lloc_min": 1,
2107 "lloc_max": 1,
2108 "blank_min": 0,
2109 "blank_max": 0
2110 }
2111 "#
2112 );
2113 },
2114 );
2115 }
2116
2117 #[test]
2118 fn python_multiline_string_argument_ploc() {
2119 check_metrics::<PythonParser>(
2122 "print(\"\"\"
2123line one
2124line two
2125\"\"\")",
2126 "foo.py",
2127 |metric| {
2128 assert_eq!(metric.loc.sloc(), 4);
2130 assert_eq!(metric.loc.ploc(), 4);
2131 assert_eq!(metric.loc.cloc(), 0);
2132 assert_eq!(metric.loc.blank(), 0);
2133 },
2134 );
2135 }
2136
2137 #[test]
2138 fn python_single_line_string_assignment_ploc() {
2139 check_metrics::<PythonParser>("QUERY = \"SELECT 1\"", "foo.py", |metric| {
2142 assert_eq!(metric.loc.sloc(), 1);
2144 assert_eq!(metric.loc.ploc(), 1);
2145 assert_eq!(metric.loc.cloc(), 0);
2146 assert_eq!(metric.loc.blank(), 0);
2147 });
2148 }
2149
2150 #[test]
2151 fn python_multiline_docstring_still_cloc() {
2152 check_metrics::<PythonParser>(
2155 "def f():
2156 \"\"\"Docstring line one
2157 Docstring line two
2158 \"\"\"
2159 return 1",
2160 "foo.py",
2161 |metric| {
2162 assert_eq!(metric.loc.cloc(), 3);
2165 assert_eq!(metric.loc.blank(), 0);
2166 },
2167 );
2168 }
2169
2170 #[test]
2171 fn rust_no_field_expression_lloc() {
2172 check_metrics::<RustParser>(
2173 "struct Foo {
2174 field: usize,
2175 }
2176 let foo = Foo { 42 };
2177 foo.field;",
2178 "foo.rs",
2179 |metric| {
2180 insta::assert_json_snapshot!(
2182 metric.loc,
2183 @r#"
2184 {
2185 "sloc": 5,
2186 "ploc": 5,
2187 "lloc": 2,
2188 "cloc": 0,
2189 "blank": 0,
2190 "sloc_average": 5.0,
2191 "ploc_average": 5.0,
2192 "lloc_average": 2.0,
2193 "cloc_average": 0.0,
2194 "blank_average": 0.0,
2195 "sloc_min": 5,
2196 "sloc_max": 5,
2197 "cloc_min": 0,
2198 "cloc_max": 0,
2199 "ploc_min": 5,
2200 "ploc_max": 5,
2201 "lloc_min": 2,
2202 "lloc_max": 2,
2203 "blank_min": 0,
2204 "blank_max": 0
2205 }
2206 "#
2207 );
2208 },
2209 );
2210 }
2211
2212 #[test]
2213 fn rust_no_parenthesized_expression_lloc() {
2214 check_metrics::<RustParser>("let a = (42 + 0);", "foo.rs", |metric| {
2215 insta::assert_json_snapshot!(
2217 metric.loc,
2218 @r#"
2219 {
2220 "sloc": 1,
2221 "ploc": 1,
2222 "lloc": 1,
2223 "cloc": 0,
2224 "blank": 0,
2225 "sloc_average": 1.0,
2226 "ploc_average": 1.0,
2227 "lloc_average": 1.0,
2228 "cloc_average": 0.0,
2229 "blank_average": 0.0,
2230 "sloc_min": 1,
2231 "sloc_max": 1,
2232 "cloc_min": 0,
2233 "cloc_max": 0,
2234 "ploc_min": 1,
2235 "ploc_max": 1,
2236 "lloc_min": 1,
2237 "lloc_max": 1,
2238 "blank_min": 0,
2239 "blank_max": 0
2240 }
2241 "#
2242 );
2243 });
2244 }
2245
2246 #[test]
2247 fn rust_no_array_expression_lloc() {
2248 check_metrics::<RustParser>("let a = [0; 42];", "foo.rs", |metric| {
2249 insta::assert_json_snapshot!(
2251 metric.loc,
2252 @r#"
2253 {
2254 "sloc": 1,
2255 "ploc": 1,
2256 "lloc": 1,
2257 "cloc": 0,
2258 "blank": 0,
2259 "sloc_average": 1.0,
2260 "ploc_average": 1.0,
2261 "lloc_average": 1.0,
2262 "cloc_average": 0.0,
2263 "blank_average": 0.0,
2264 "sloc_min": 1,
2265 "sloc_max": 1,
2266 "cloc_min": 0,
2267 "cloc_max": 0,
2268 "ploc_min": 1,
2269 "ploc_max": 1,
2270 "lloc_min": 1,
2271 "lloc_max": 1,
2272 "blank_min": 0,
2273 "blank_max": 0
2274 }
2275 "#
2276 );
2277 });
2278 }
2279
2280 #[test]
2281 fn rust_no_tuple_expression_lloc() {
2282 check_metrics::<RustParser>("let a = (0, 42);", "foo.rs", |metric| {
2283 insta::assert_json_snapshot!(
2285 metric.loc,
2286 @r#"
2287 {
2288 "sloc": 1,
2289 "ploc": 1,
2290 "lloc": 1,
2291 "cloc": 0,
2292 "blank": 0,
2293 "sloc_average": 1.0,
2294 "ploc_average": 1.0,
2295 "lloc_average": 1.0,
2296 "cloc_average": 0.0,
2297 "blank_average": 0.0,
2298 "sloc_min": 1,
2299 "sloc_max": 1,
2300 "cloc_min": 0,
2301 "cloc_max": 0,
2302 "ploc_min": 1,
2303 "ploc_max": 1,
2304 "lloc_min": 1,
2305 "lloc_max": 1,
2306 "blank_min": 0,
2307 "blank_max": 0
2308 }
2309 "#
2310 );
2311 });
2312 }
2313
2314 #[test]
2315 fn rust_no_unit_expression_lloc() {
2316 check_metrics::<RustParser>("let a = ();", "foo.rs", |metric| {
2317 insta::assert_json_snapshot!(
2319 metric.loc,
2320 @r#"
2321 {
2322 "sloc": 1,
2323 "ploc": 1,
2324 "lloc": 1,
2325 "cloc": 0,
2326 "blank": 0,
2327 "sloc_average": 1.0,
2328 "ploc_average": 1.0,
2329 "lloc_average": 1.0,
2330 "cloc_average": 0.0,
2331 "blank_average": 0.0,
2332 "sloc_min": 1,
2333 "sloc_max": 1,
2334 "cloc_min": 0,
2335 "cloc_max": 0,
2336 "ploc_min": 1,
2337 "ploc_max": 1,
2338 "lloc_min": 1,
2339 "lloc_max": 1,
2340 "blank_min": 0,
2341 "blank_max": 0
2342 }
2343 "#
2344 );
2345 });
2346 }
2347
2348 #[test]
2349 fn rust_call_function_lloc() {
2350 check_metrics::<RustParser>(
2351 "let a = foo(); // +1
2352 foo(); // +1
2353 k!(foo()); // +1",
2354 "foo.rs",
2355 |metric| {
2356 insta::assert_json_snapshot!(
2358 metric.loc,
2359 @r#"
2360 {
2361 "sloc": 3,
2362 "ploc": 3,
2363 "lloc": 3,
2364 "cloc": 3,
2365 "blank": 0,
2366 "sloc_average": 3.0,
2367 "ploc_average": 3.0,
2368 "lloc_average": 3.0,
2369 "cloc_average": 3.0,
2370 "blank_average": 0.0,
2371 "sloc_min": 3,
2372 "sloc_max": 3,
2373 "cloc_min": 3,
2374 "cloc_max": 3,
2375 "ploc_min": 3,
2376 "ploc_max": 3,
2377 "lloc_min": 3,
2378 "lloc_max": 3,
2379 "blank_min": 0,
2380 "blank_max": 0
2381 }
2382 "#
2383 );
2384 },
2385 );
2386 }
2387
2388 #[test]
2389 fn rust_macro_invocation_lloc() {
2390 check_metrics::<RustParser>(
2391 "let a = foo!(); // +1
2392 foo!(); // +1
2393 k(foo!()); // +1",
2394 "foo.rs",
2395 |metric| {
2396 insta::assert_json_snapshot!(
2398 metric.loc,
2399 @r#"
2400 {
2401 "sloc": 3,
2402 "ploc": 3,
2403 "lloc": 3,
2404 "cloc": 3,
2405 "blank": 0,
2406 "sloc_average": 3.0,
2407 "ploc_average": 3.0,
2408 "lloc_average": 3.0,
2409 "cloc_average": 3.0,
2410 "blank_average": 0.0,
2411 "sloc_min": 3,
2412 "sloc_max": 3,
2413 "cloc_min": 3,
2414 "cloc_max": 3,
2415 "ploc_min": 3,
2416 "ploc_max": 3,
2417 "lloc_min": 3,
2418 "lloc_max": 3,
2419 "blank_min": 0,
2420 "blank_max": 0
2421 }
2422 "#
2423 );
2424 },
2425 );
2426 }
2427
2428 #[test]
2429 fn rust_function_in_loop_lloc() {
2430 check_metrics::<RustParser>(
2431 "for (a, b) in c.iter().enumerate() {} // +1
2432 while (a, b) in c.iter().enumerate() {} // +1
2433 while let Some(a) = c.strip_prefix(\"hi\") {} // +1",
2434 "foo.rs",
2435 |metric| {
2436 insta::assert_json_snapshot!(
2438 metric.loc,
2439 @r#"
2440 {
2441 "sloc": 3,
2442 "ploc": 3,
2443 "lloc": 3,
2444 "cloc": 3,
2445 "blank": 0,
2446 "sloc_average": 3.0,
2447 "ploc_average": 3.0,
2448 "lloc_average": 3.0,
2449 "cloc_average": 3.0,
2450 "blank_average": 0.0,
2451 "sloc_min": 3,
2452 "sloc_max": 3,
2453 "cloc_min": 3,
2454 "cloc_max": 3,
2455 "ploc_min": 3,
2456 "ploc_max": 3,
2457 "lloc_min": 3,
2458 "lloc_max": 3,
2459 "blank_min": 0,
2460 "blank_max": 0
2461 }
2462 "#
2463 );
2464 },
2465 );
2466 }
2467
2468 #[test]
2469 fn rust_function_in_if_lloc() {
2470 check_metrics::<RustParser>(
2471 "if foo() {} // +1
2472 if let Some(a) = foo() {} // +1",
2473 "foo.rs",
2474 |metric| {
2475 insta::assert_json_snapshot!(
2477 metric.loc,
2478 @r#"
2479 {
2480 "sloc": 2,
2481 "ploc": 2,
2482 "lloc": 2,
2483 "cloc": 2,
2484 "blank": 0,
2485 "sloc_average": 2.0,
2486 "ploc_average": 2.0,
2487 "lloc_average": 2.0,
2488 "cloc_average": 2.0,
2489 "blank_average": 0.0,
2490 "sloc_min": 2,
2491 "sloc_max": 2,
2492 "cloc_min": 2,
2493 "cloc_max": 2,
2494 "ploc_min": 2,
2495 "ploc_max": 2,
2496 "lloc_min": 2,
2497 "lloc_max": 2,
2498 "blank_min": 0,
2499 "blank_max": 0
2500 }
2501 "#
2502 );
2503 },
2504 );
2505 }
2506
2507 #[test]
2508 fn rust_function_in_return_lloc() {
2509 check_metrics::<RustParser>(
2510 "return foo();
2511 await foo();",
2512 "foo.rs",
2513 |metric| {
2514 insta::assert_json_snapshot!(
2516 metric.loc,
2517 @r#"
2518 {
2519 "sloc": 2,
2520 "ploc": 2,
2521 "lloc": 2,
2522 "cloc": 0,
2523 "blank": 0,
2524 "sloc_average": 2.0,
2525 "ploc_average": 2.0,
2526 "lloc_average": 2.0,
2527 "cloc_average": 0.0,
2528 "blank_average": 0.0,
2529 "sloc_min": 2,
2530 "sloc_max": 2,
2531 "cloc_min": 0,
2532 "cloc_max": 0,
2533 "ploc_min": 2,
2534 "ploc_max": 2,
2535 "lloc_min": 2,
2536 "lloc_max": 2,
2537 "blank_min": 0,
2538 "blank_max": 0
2539 }
2540 "#
2541 );
2542 },
2543 );
2544 }
2545
2546 #[test]
2547 fn rust_closure_expression_lloc() {
2548 check_metrics::<RustParser>(
2549 "let a = |i: i32| -> i32 { i + 1 }; // +1
2550 a(42); // +1
2551 k(b.iter().map(|n| n.parse.ok().unwrap_or(42))); // +1",
2552 "foo.rs",
2553 |metric| {
2554 insta::assert_json_snapshot!(
2556 metric.loc,
2557 @r#"
2558 {
2559 "sloc": 3,
2560 "ploc": 3,
2561 "lloc": 3,
2562 "cloc": 3,
2563 "blank": 0,
2564 "sloc_average": 1.0,
2565 "ploc_average": 1.0,
2566 "lloc_average": 1.0,
2567 "cloc_average": 1.0,
2568 "blank_average": 0.0,
2569 "sloc_min": 1,
2570 "sloc_max": 3,
2571 "cloc_min": 0,
2572 "cloc_max": 3,
2573 "ploc_min": 1,
2574 "ploc_max": 3,
2575 "lloc_min": 0,
2576 "lloc_max": 3,
2577 "blank_min": 0,
2578 "blank_max": 0
2579 }
2580 "#
2581 );
2582 },
2583 );
2584 }
2585
2586 #[test]
2587 fn python_general_loc() {
2588 check_metrics::<PythonParser>(
2589 "def func(a,
2590 b,
2591 c):
2592 print(a)
2593 print(b)
2594 print(c)",
2595 "foo.py",
2596 |metric| {
2597 insta::assert_json_snapshot!(
2599 metric.loc,
2600 @r#"
2601 {
2602 "sloc": 6,
2603 "ploc": 6,
2604 "lloc": 3,
2605 "cloc": 0,
2606 "blank": 0,
2607 "sloc_average": 3.0,
2608 "ploc_average": 3.0,
2609 "lloc_average": 1.5,
2610 "cloc_average": 0.0,
2611 "blank_average": 0.0,
2612 "sloc_min": 6,
2613 "sloc_max": 6,
2614 "cloc_min": 0,
2615 "cloc_max": 0,
2616 "ploc_min": 6,
2617 "ploc_max": 6,
2618 "lloc_min": 3,
2619 "lloc_max": 3,
2620 "blank_min": 0,
2621 "blank_max": 0
2622 }
2623 "#
2624 );
2625 },
2626 );
2627 }
2628
2629 #[test]
2630 fn python_real_loc() {
2631 check_metrics::<PythonParser>(
2632 "def web_socket_transfer_data(request):
2633 while True:
2634 line = request.ws_stream.receive_message()
2635 if line is None:
2636 return
2637 code, reason = line.split(' ', 1)
2638 if code is None or reason is None:
2639 return
2640 request.ws_stream.close_connection(int(code), reason)
2641 # close_connection() initiates closing handshake. It validates code
2642 # and reason. If you want to send a broken close frame for a test,
2643 # following code will be useful.
2644 # > data = struct.pack('!H', int(code)) + reason.encode('UTF-8')
2645 # > request.connection.write(stream.create_close_frame(data))
2646 # > # Suppress to re-respond client responding close frame.
2647 # > raise Exception(\"customized server initiated closing handshake\")",
2648 "foo.py",
2649 |metric| {
2650 insta::assert_json_snapshot!(
2652 metric.loc,
2653 @r#"
2654 {
2655 "sloc": 16,
2656 "ploc": 9,
2657 "lloc": 8,
2658 "cloc": 7,
2659 "blank": 0,
2660 "sloc_average": 8.0,
2661 "ploc_average": 4.5,
2662 "lloc_average": 4.0,
2663 "cloc_average": 3.5,
2664 "blank_average": 0.0,
2665 "sloc_min": 16,
2666 "sloc_max": 16,
2667 "cloc_min": 7,
2668 "cloc_max": 7,
2669 "ploc_min": 9,
2670 "ploc_max": 9,
2671 "lloc_min": 8,
2672 "lloc_max": 8,
2673 "blank_min": 0,
2674 "blank_max": 0
2675 }
2676 "#
2677 );
2678 },
2679 );
2680 }
2681
2682 #[test]
2683 fn javascript_real_loc() {
2684 check_metrics::<JavascriptParser>(
2685 "assert.throws(Test262Error, function() {
2686 for (let { poisoned: x = ++initEvalCount } = poisonedProperty; ; ) {
2687 return;
2688 }
2689 });",
2690 "foo.js",
2691 |metric| {
2692 insta::assert_json_snapshot!(
2694 metric.loc,
2695 @r#"
2696 {
2697 "sloc": 5,
2698 "ploc": 5,
2699 "lloc": 4,
2700 "cloc": 0,
2701 "blank": 0,
2702 "sloc_average": 2.5,
2703 "ploc_average": 2.5,
2704 "lloc_average": 2.0,
2705 "cloc_average": 0.0,
2706 "blank_average": 0.0,
2707 "sloc_min": 5,
2708 "sloc_max": 5,
2709 "cloc_min": 0,
2710 "cloc_max": 0,
2711 "ploc_min": 5,
2712 "ploc_max": 5,
2713 "lloc_min": 3,
2714 "lloc_max": 4,
2715 "blank_min": 0,
2716 "blank_max": 0
2717 }
2718 "#
2719 );
2720 },
2721 );
2722 }
2723
2724 #[test]
2725 fn mozjs_real_loc() {
2726 check_metrics::<MozjsParser>(
2727 "assert.throws(Test262Error, function() {
2728 for (let { poisoned: x = ++initEvalCount } = poisonedProperty; ; ) {
2729 return;
2730 }
2731 });",
2732 "foo.js",
2733 |metric| {
2734 insta::assert_json_snapshot!(
2736 metric.loc,
2737 @r#"
2738 {
2739 "sloc": 5,
2740 "ploc": 5,
2741 "lloc": 4,
2742 "cloc": 0,
2743 "blank": 0,
2744 "sloc_average": 2.5,
2745 "ploc_average": 2.5,
2746 "lloc_average": 2.0,
2747 "cloc_average": 0.0,
2748 "blank_average": 0.0,
2749 "sloc_min": 5,
2750 "sloc_max": 5,
2751 "cloc_min": 0,
2752 "cloc_max": 0,
2753 "ploc_min": 5,
2754 "ploc_max": 5,
2755 "lloc_min": 3,
2756 "lloc_max": 4,
2757 "blank_min": 0,
2758 "blank_max": 0
2759 }
2760 "#
2761 );
2762 },
2763 );
2764 }
2765
2766 #[test]
2767 fn mozjs_blank_and_comment_loc() {
2768 check_metrics::<MozjsParser>(
2769 "// a comment
2770 function f() {
2771
2772 var x = 1;
2773
2774 }",
2775 "foo.js",
2776 |metric| {
2777 insta::assert_json_snapshot!(
2778 metric.loc,
2779 @r#"
2780 {
2781 "sloc": 6,
2782 "ploc": 3,
2783 "lloc": 1,
2784 "cloc": 1,
2785 "blank": 2,
2786 "sloc_average": 3.0,
2787 "ploc_average": 1.5,
2788 "lloc_average": 0.5,
2789 "cloc_average": 0.5,
2790 "blank_average": 1.0,
2791 "sloc_min": 5,
2792 "sloc_max": 6,
2793 "cloc_min": 0,
2794 "cloc_max": 1,
2795 "ploc_min": 3,
2796 "ploc_max": 3,
2797 "lloc_min": 1,
2798 "lloc_max": 1,
2799 "blank_min": 2,
2800 "blank_max": 2
2801 }
2802 "#
2803 );
2804 },
2805 );
2806 }
2807
2808 #[test]
2809 fn cpp_namespace_loc() {
2810 check_metrics::<CppParser>(
2811 "namespace mozilla::dom::quota {} // namespace mozilla::dom::quota",
2812 "foo.cpp",
2813 |metric| {
2814 insta::assert_json_snapshot!(
2816 metric.loc,
2817 @r#"
2818 {
2819 "sloc": 1,
2820 "ploc": 1,
2821 "lloc": 0,
2822 "cloc": 1,
2823 "blank": 0,
2824 "sloc_average": 0.5,
2825 "ploc_average": 0.5,
2826 "lloc_average": 0.0,
2827 "cloc_average": 0.5,
2828 "blank_average": 0.0,
2829 "sloc_min": 1,
2830 "sloc_max": 1,
2831 "cloc_min": 0,
2832 "cloc_max": 1,
2833 "ploc_min": 1,
2834 "ploc_max": 1,
2835 "lloc_min": 0,
2836 "lloc_max": 0,
2837 "blank_min": 0,
2838 "blank_max": 0
2839 }
2840 "#
2841 );
2842 },
2843 );
2844 }
2845
2846 #[test]
2847 fn java_comments() {
2848 check_metrics::<JavaParser>(
2849 "for (int i = 0; i < 100; i++) { \
2850 // Print hello
2851 System.out.println(\"hello\"); \
2852 // Print world
2853 System.out.println(\"hello\"); \
2854 }",
2855 "foo.java",
2856 |metric| {
2857 insta::assert_json_snapshot!(
2859 metric.loc,
2860 @r#"
2861 {
2862 "sloc": 3,
2863 "ploc": 3,
2864 "lloc": 3,
2865 "cloc": 2,
2866 "blank": 0,
2867 "sloc_average": 3.0,
2868 "ploc_average": 3.0,
2869 "lloc_average": 3.0,
2870 "cloc_average": 2.0,
2871 "blank_average": 0.0,
2872 "sloc_min": 3,
2873 "sloc_max": 3,
2874 "cloc_min": 2,
2875 "cloc_max": 2,
2876 "ploc_min": 3,
2877 "ploc_max": 3,
2878 "lloc_min": 3,
2879 "lloc_max": 3,
2880 "blank_min": 0,
2881 "blank_max": 0
2882 }
2883 "#
2884 );
2885 },
2886 );
2887 }
2888
2889 #[test]
2890 fn java_blank() {
2891 check_metrics::<JavaParser>(
2892 "int x = 1;
2893
2894
2895 int y = 2;",
2896 "foo.java",
2897 |metric| {
2898 insta::assert_json_snapshot!(
2900 metric.loc,
2901 @r#"
2902 {
2903 "sloc": 4,
2904 "ploc": 2,
2905 "lloc": 2,
2906 "cloc": 0,
2907 "blank": 2,
2908 "sloc_average": 4.0,
2909 "ploc_average": 2.0,
2910 "lloc_average": 2.0,
2911 "cloc_average": 0.0,
2912 "blank_average": 2.0,
2913 "sloc_min": 4,
2914 "sloc_max": 4,
2915 "cloc_min": 0,
2916 "cloc_max": 0,
2917 "ploc_min": 2,
2918 "ploc_max": 2,
2919 "lloc_min": 2,
2920 "lloc_max": 2,
2921 "blank_min": 2,
2922 "blank_max": 2
2923 }
2924 "#
2925 );
2926 },
2927 );
2928 }
2929
2930 #[test]
2931 fn java_sloc() {
2932 check_metrics::<JavaParser>(
2933 "for (int i = 0; i < 100; i++) {
2934 System.out.println(i);
2935 }",
2936 "foo.java",
2937 |metric| {
2938 insta::assert_json_snapshot!(
2940 metric.loc,
2941 @r#"
2942 {
2943 "sloc": 3,
2944 "ploc": 3,
2945 "lloc": 2,
2946 "cloc": 0,
2947 "blank": 0,
2948 "sloc_average": 3.0,
2949 "ploc_average": 3.0,
2950 "lloc_average": 2.0,
2951 "cloc_average": 0.0,
2952 "blank_average": 0.0,
2953 "sloc_min": 3,
2954 "sloc_max": 3,
2955 "cloc_min": 0,
2956 "cloc_max": 0,
2957 "ploc_min": 3,
2958 "ploc_max": 3,
2959 "lloc_min": 2,
2960 "lloc_max": 2,
2961 "blank_min": 0,
2962 "blank_max": 0
2963 }
2964 "#
2965 );
2966 },
2967 );
2968 }
2969
2970 #[test]
2971 fn java_module_sloc() {
2972 check_metrics::<JavaParser>(
2973 "module helloworld{
2974 exports com.test;
2975 }",
2976 "foo.java",
2977 |metric| {
2978 insta::assert_json_snapshot!(
2980 metric.loc,
2981 @r#"
2982 {
2983 "sloc": 3,
2984 "ploc": 3,
2985 "lloc": 0,
2986 "cloc": 0,
2987 "blank": 0,
2988 "sloc_average": 3.0,
2989 "ploc_average": 3.0,
2990 "lloc_average": 0.0,
2991 "cloc_average": 0.0,
2992 "blank_average": 0.0,
2993 "sloc_min": 3,
2994 "sloc_max": 3,
2995 "cloc_min": 0,
2996 "cloc_max": 0,
2997 "ploc_min": 3,
2998 "ploc_max": 3,
2999 "lloc_min": 0,
3000 "lloc_max": 0,
3001 "blank_min": 0,
3002 "blank_max": 0
3003 }
3004 "#
3005 );
3006 },
3007 );
3008 }
3009
3010 #[test]
3011 fn java_single_ploc() {
3012 check_metrics::<JavaParser>("int x = 1;", "foo.java", |metric| {
3013 insta::assert_json_snapshot!(
3015 metric.loc,
3016 @r#"
3017 {
3018 "sloc": 1,
3019 "ploc": 1,
3020 "lloc": 1,
3021 "cloc": 0,
3022 "blank": 0,
3023 "sloc_average": 1.0,
3024 "ploc_average": 1.0,
3025 "lloc_average": 1.0,
3026 "cloc_average": 0.0,
3027 "blank_average": 0.0,
3028 "sloc_min": 1,
3029 "sloc_max": 1,
3030 "cloc_min": 0,
3031 "cloc_max": 0,
3032 "ploc_min": 1,
3033 "ploc_max": 1,
3034 "lloc_min": 1,
3035 "lloc_max": 1,
3036 "blank_min": 0,
3037 "blank_max": 0
3038 }
3039 "#
3040 );
3041 });
3042 }
3043
3044 #[test]
3045 fn java_simple_ploc() {
3046 check_metrics::<JavaParser>(
3047 "for (int i = 0; i < 100; i = i++) {
3048 System.out.println(i);
3049 }",
3050 "foo.java",
3051 |metric| {
3052 insta::assert_json_snapshot!(
3054 metric.loc,
3055 @r#"
3056 {
3057 "sloc": 3,
3058 "ploc": 3,
3059 "lloc": 2,
3060 "cloc": 0,
3061 "blank": 0,
3062 "sloc_average": 3.0,
3063 "ploc_average": 3.0,
3064 "lloc_average": 2.0,
3065 "cloc_average": 0.0,
3066 "blank_average": 0.0,
3067 "sloc_min": 3,
3068 "sloc_max": 3,
3069 "cloc_min": 0,
3070 "cloc_max": 0,
3071 "ploc_min": 3,
3072 "ploc_max": 3,
3073 "lloc_min": 2,
3074 "lloc_max": 2,
3075 "blank_min": 0,
3076 "blank_max": 0
3077 }
3078 "#
3079 );
3080 },
3081 );
3082 }
3083
3084 #[test]
3085 fn java_multi_ploc() {
3086 check_metrics::<JavaParser>(
3087 "int x = 1;
3088 for (int i = 0; i < 100; i++) {
3089 System.out.println(i);
3090 }",
3091 "foo.java",
3092 |metric| {
3093 insta::assert_json_snapshot!(
3095 metric.loc,
3096 @r#"
3097 {
3098 "sloc": 4,
3099 "ploc": 4,
3100 "lloc": 3,
3101 "cloc": 0,
3102 "blank": 0,
3103 "sloc_average": 4.0,
3104 "ploc_average": 4.0,
3105 "lloc_average": 3.0,
3106 "cloc_average": 0.0,
3107 "blank_average": 0.0,
3108 "sloc_min": 4,
3109 "sloc_max": 4,
3110 "cloc_min": 0,
3111 "cloc_max": 0,
3112 "ploc_min": 4,
3113 "ploc_max": 4,
3114 "lloc_min": 3,
3115 "lloc_max": 3,
3116 "blank_min": 0,
3117 "blank_max": 0
3118 }
3119 "#
3120 );
3121 },
3122 );
3123 }
3124
3125 #[test]
3126 fn java_single_statement_lloc() {
3127 check_metrics::<JavaParser>("int max = 10;", "foo.java", |metric| {
3128 insta::assert_json_snapshot!(
3130 metric.loc,
3131 @r#"
3132 {
3133 "sloc": 1,
3134 "ploc": 1,
3135 "lloc": 1,
3136 "cloc": 0,
3137 "blank": 0,
3138 "sloc_average": 1.0,
3139 "ploc_average": 1.0,
3140 "lloc_average": 1.0,
3141 "cloc_average": 0.0,
3142 "blank_average": 0.0,
3143 "sloc_min": 1,
3144 "sloc_max": 1,
3145 "cloc_min": 0,
3146 "cloc_max": 0,
3147 "ploc_min": 1,
3148 "ploc_max": 1,
3149 "lloc_min": 1,
3150 "lloc_max": 1,
3151 "blank_min": 0,
3152 "blank_max": 0
3153 }
3154 "#
3155 );
3156 });
3157 }
3158
3159 #[test]
3160 fn java_for_lloc() {
3161 check_metrics::<JavaParser>(
3162 "for (int i = 0; i < 100; i++) { // + 1
3163 System.out.println(i); // + 1
3164 }",
3165 "foo.java",
3166 |metric| {
3167 insta::assert_json_snapshot!(
3169 metric.loc,
3170 @r#"
3171 {
3172 "sloc": 3,
3173 "ploc": 3,
3174 "lloc": 2,
3175 "cloc": 2,
3176 "blank": 0,
3177 "sloc_average": 3.0,
3178 "ploc_average": 3.0,
3179 "lloc_average": 2.0,
3180 "cloc_average": 2.0,
3181 "blank_average": 0.0,
3182 "sloc_min": 3,
3183 "sloc_max": 3,
3184 "cloc_min": 2,
3185 "cloc_max": 2,
3186 "ploc_min": 3,
3187 "ploc_max": 3,
3188 "lloc_min": 2,
3189 "lloc_max": 2,
3190 "blank_min": 0,
3191 "blank_max": 0
3192 }
3193 "#
3194 );
3195 },
3196 );
3197 }
3198
3199 #[test]
3200 fn java_foreach_lloc() {
3201 check_metrics::<JavaParser>(
3202 "
3203 int arr[]={12,13,14,44}; // +1
3204 for (int i:arr) { // +1
3205 System.out.println(i); // +1
3206 }",
3207 "foo.java",
3208 |metric| {
3209 insta::assert_json_snapshot!(
3211 metric.loc,
3212 @r#"
3213 {
3214 "sloc": 4,
3215 "ploc": 4,
3216 "lloc": 3,
3217 "cloc": 3,
3218 "blank": 0,
3219 "sloc_average": 4.0,
3220 "ploc_average": 4.0,
3221 "lloc_average": 3.0,
3222 "cloc_average": 3.0,
3223 "blank_average": 0.0,
3224 "sloc_min": 4,
3225 "sloc_max": 4,
3226 "cloc_min": 3,
3227 "cloc_max": 3,
3228 "ploc_min": 4,
3229 "ploc_max": 4,
3230 "lloc_min": 3,
3231 "lloc_max": 3,
3232 "blank_min": 0,
3233 "blank_max": 0
3234 }
3235 "#
3236 );
3237 },
3238 );
3239 }
3240
3241 #[test]
3242 fn java_while_lloc() {
3243 check_metrics::<JavaParser>(
3244 "
3245 int i=0; // +1
3246 while(i < 10) { // +1
3247 i++; // +1
3248 System.out.println(i); // +1
3249 }",
3250 "foo.java",
3251 |metric| {
3252 insta::assert_json_snapshot!(
3254 metric.loc,
3255 @r#"
3256 {
3257 "sloc": 5,
3258 "ploc": 5,
3259 "lloc": 4,
3260 "cloc": 4,
3261 "blank": 0,
3262 "sloc_average": 5.0,
3263 "ploc_average": 5.0,
3264 "lloc_average": 4.0,
3265 "cloc_average": 4.0,
3266 "blank_average": 0.0,
3267 "sloc_min": 5,
3268 "sloc_max": 5,
3269 "cloc_min": 4,
3270 "cloc_max": 4,
3271 "ploc_min": 5,
3272 "ploc_max": 5,
3273 "lloc_min": 4,
3274 "lloc_max": 4,
3275 "blank_min": 0,
3276 "blank_max": 0
3277 }
3278 "#
3279 );
3280 },
3281 );
3282 }
3283
3284 #[test]
3285 fn java_do_while_lloc() {
3286 check_metrics::<JavaParser>(
3287 "
3288 int i=0; // +1
3289 do { // +1
3290 i++; // +1
3291 System.out.println(i); // +1
3292 } while(i < 10)",
3293 "foo.java",
3294 |metric| {
3295 insta::assert_json_snapshot!(
3297 metric.loc,
3298 @r#"
3299 {
3300 "sloc": 5,
3301 "ploc": 5,
3302 "lloc": 4,
3303 "cloc": 4,
3304 "blank": 0,
3305 "sloc_average": 5.0,
3306 "ploc_average": 5.0,
3307 "lloc_average": 4.0,
3308 "cloc_average": 4.0,
3309 "blank_average": 0.0,
3310 "sloc_min": 5,
3311 "sloc_max": 5,
3312 "cloc_min": 4,
3313 "cloc_max": 4,
3314 "ploc_min": 5,
3315 "ploc_max": 5,
3316 "lloc_min": 4,
3317 "lloc_max": 4,
3318 "blank_min": 0,
3319 "blank_max": 0
3320 }
3321 "#
3322 );
3323 },
3324 );
3325 }
3326
3327 #[test]
3328 fn java_switch_lloc() {
3329 check_metrics::<JavaParser>(
3330 "switch(grade) { // +1
3331 case 'A' :
3332 System.out.println(\"Pass with distinction\"); // +1
3333 break; // +1
3334 case 'B' :
3335 case 'C' :
3336 System.out.println(\"Pass\"); // +1
3337 break; // +1
3338 case 'D' :
3339 System.out.println(\"At risk\"); // +1
3340 case 'F' :
3341 System.out.println(\"Fail\"); // +1
3342 break; // +1
3343 default :
3344 System.out.println(\"Invalid grade\"); // +1
3345 }",
3346 "foo.java",
3347 |metric| {
3348 insta::assert_json_snapshot!(
3350 metric.loc,
3351 @r#"
3352 {
3353 "sloc": 16,
3354 "ploc": 16,
3355 "lloc": 9,
3356 "cloc": 9,
3357 "blank": 0,
3358 "sloc_average": 16.0,
3359 "ploc_average": 16.0,
3360 "lloc_average": 9.0,
3361 "cloc_average": 9.0,
3362 "blank_average": 0.0,
3363 "sloc_min": 16,
3364 "sloc_max": 16,
3365 "cloc_min": 9,
3366 "cloc_max": 9,
3367 "ploc_min": 16,
3368 "ploc_max": 16,
3369 "lloc_min": 9,
3370 "lloc_max": 9,
3371 "blank_min": 0,
3372 "blank_max": 0
3373 }
3374 "#
3375 );
3376 },
3377 );
3378 }
3379
3380 #[test]
3381 fn java_continue_lloc() {
3382 check_metrics::<JavaParser>(
3383 "int max = 10; // +1
3384
3385 for (int i = 0; i < max; i++) { // +1
3386 if(i % 2 == 0) { continue;} + 2
3387 System.out.println(i); // +1
3388 }",
3389 "foo.java",
3390 |metric| {
3391 insta::assert_json_snapshot!(
3393 metric.loc,
3394 @r#"
3395 {
3396 "sloc": 6,
3397 "ploc": 5,
3398 "lloc": 5,
3399 "cloc": 3,
3400 "blank": 1,
3401 "sloc_average": 6.0,
3402 "ploc_average": 5.0,
3403 "lloc_average": 5.0,
3404 "cloc_average": 3.0,
3405 "blank_average": 1.0,
3406 "sloc_min": 6,
3407 "sloc_max": 6,
3408 "cloc_min": 3,
3409 "cloc_max": 3,
3410 "ploc_min": 5,
3411 "ploc_max": 5,
3412 "lloc_min": 5,
3413 "lloc_max": 5,
3414 "blank_min": 1,
3415 "blank_max": 1
3416 }
3417 "#
3418 );
3419 },
3420 );
3421 }
3422
3423 #[test]
3424 fn java_try_lloc() {
3425 check_metrics::<JavaParser>(
3426 "try { // +1
3427 int[] myNumbers = {1, 2, 3}; // +1
3428 System.out.println(myNumbers[10]); // +1
3429 } catch (Exception e) {
3430 System.out.println(e.getMessage()); // +1
3431 throw e; // +1
3432 }",
3433 "foo.java",
3434 |metric| {
3435 insta::assert_json_snapshot!(
3437 metric.loc,
3438 @r#"
3439 {
3440 "sloc": 7,
3441 "ploc": 7,
3442 "lloc": 5,
3443 "cloc": 5,
3444 "blank": 0,
3445 "sloc_average": 7.0,
3446 "ploc_average": 7.0,
3447 "lloc_average": 5.0,
3448 "cloc_average": 5.0,
3449 "blank_average": 0.0,
3450 "sloc_min": 7,
3451 "sloc_max": 7,
3452 "cloc_min": 5,
3453 "cloc_max": 5,
3454 "ploc_min": 7,
3455 "ploc_max": 7,
3456 "lloc_min": 5,
3457 "lloc_max": 5,
3458 "blank_min": 0,
3459 "blank_max": 0
3460 }
3461 "#
3462 );
3463 },
3464 );
3465 }
3466
3467 #[test]
3468 fn java_class_loc() {
3469 check_metrics::<JavaParser>(
3470 "
3471 public class Person {
3472 private String name;
3473 public Person(String name){
3474 this.name = name; // +1
3475 }
3476 public String getName() {
3477 return name; // +1
3478 }
3479 }",
3480 "foo.java",
3481 |metric| {
3482 insta::assert_json_snapshot!(
3484 metric.loc,
3485 @r#"
3486 {
3487 "sloc": 9,
3488 "ploc": 9,
3489 "lloc": 2,
3490 "cloc": 2,
3491 "blank": 0,
3492 "sloc_average": 2.25,
3493 "ploc_average": 2.25,
3494 "lloc_average": 0.5,
3495 "cloc_average": 0.5,
3496 "blank_average": 0.0,
3497 "sloc_min": 3,
3498 "sloc_max": 9,
3499 "cloc_min": 1,
3500 "cloc_max": 2,
3501 "ploc_min": 3,
3502 "ploc_max": 9,
3503 "lloc_min": 1,
3504 "lloc_max": 2,
3505 "blank_min": 0,
3506 "blank_max": 0
3507 }
3508 "#
3509 );
3510 },
3511 );
3512 }
3513
3514 #[test]
3515 fn java_expressions_lloc() {
3516 check_metrics::<JavaParser>(
3517 "int x = 10; // +1 local var declaration
3518 x=+89; // +1 expression statement
3519 int y = x * 2; // +1 local var declaration
3520 IntFunction double = (n) -> n*2; // +1 local var declaration
3521 int y2 = double(x); // +1 local var declaration
3522 System.out.println(\"double \" + x + \" = \" + y2); // +1 expression statement
3523 String message = (x % 2) == 0 ? \"Evenly done.\" : \"Oddly done.\"; // +1 local var declaration
3524 Object done = (Runnable) () -> { System.out.println(\"Done!\"); }; // +2 local var declaration + expression statement
3525 String s = \"string\"; // +1 local var declaration
3526 boolean isS = (s instanceof String); // +1 local var declaration
3527 done.run(); // +1 expression statement
3528 ",
3529 "foo.java",
3530 |metric| {
3531 insta::assert_json_snapshot!(
3533 metric.loc,
3534 @r#"
3535 {
3536 "sloc": 11,
3537 "ploc": 11,
3538 "lloc": 12,
3539 "cloc": 11,
3540 "blank": 0,
3541 "sloc_average": 11.0,
3542 "ploc_average": 11.0,
3543 "lloc_average": 12.0,
3544 "cloc_average": 11.0,
3545 "blank_average": 0.0,
3546 "sloc_min": 11,
3547 "sloc_max": 11,
3548 "cloc_min": 11,
3549 "cloc_max": 11,
3550 "ploc_min": 11,
3551 "ploc_max": 11,
3552 "lloc_min": 12,
3553 "lloc_max": 12,
3554 "blank_min": 0,
3555 "blank_max": 0
3556 }
3557 "#
3558 );
3559 },
3560 );
3561 }
3562
3563 #[test]
3564 fn java_statement_inline_loc() {
3565 check_metrics::<JavaParser>(
3566 "for (int i = 0; i < 100; i++) { System.out.println(\"hello\"); }",
3567 "foo.java",
3568 |metric| {
3569 insta::assert_json_snapshot!(
3571 metric.loc,
3572 @r#"
3573 {
3574 "sloc": 1,
3575 "ploc": 1,
3576 "lloc": 2,
3577 "cloc": 0,
3578 "blank": 0,
3579 "sloc_average": 1.0,
3580 "ploc_average": 1.0,
3581 "lloc_average": 2.0,
3582 "cloc_average": 0.0,
3583 "blank_average": 0.0,
3584 "sloc_min": 1,
3585 "sloc_max": 1,
3586 "cloc_min": 0,
3587 "cloc_max": 0,
3588 "ploc_min": 1,
3589 "ploc_max": 1,
3590 "lloc_min": 2,
3591 "lloc_max": 2,
3592 "blank_min": 0,
3593 "blank_max": 0
3594 }
3595 "#
3596 );
3597 },
3598 );
3599 }
3600
3601 #[test]
3602 fn java_general_loc() {
3603 check_metrics::<JavaParser>(
3604 "int max = 100;
3605
3606 /*
3607 Loop through and print
3608 from: 0
3609 to: max
3610 */
3611 for (int i = 0; i < max; i++) {
3612 // Print the value
3613 System.out.println(i);
3614 }",
3615 "foo.java",
3616 |metric| {
3617 insta::assert_json_snapshot!(
3619 metric.loc,
3620 @r#"
3621 {
3622 "sloc": 11,
3623 "ploc": 4,
3624 "lloc": 3,
3625 "cloc": 6,
3626 "blank": 1,
3627 "sloc_average": 11.0,
3628 "ploc_average": 4.0,
3629 "lloc_average": 3.0,
3630 "cloc_average": 6.0,
3631 "blank_average": 1.0,
3632 "sloc_min": 11,
3633 "sloc_max": 11,
3634 "cloc_min": 6,
3635 "cloc_max": 6,
3636 "ploc_min": 4,
3637 "ploc_max": 4,
3638 "lloc_min": 3,
3639 "lloc_max": 3,
3640 "blank_min": 1,
3641 "blank_max": 1
3642 }
3643 "#
3644 );
3645 },
3646 );
3647 }
3648
3649 #[test]
3650 fn java_main_class_loc() {
3651 check_metrics::<JavaParser>(
3652 "package com.company;
3653 /**
3654 * The HelloWorldApp class implements an application that
3655 * simply prints \"Hello World!\" to standard output.
3656 */
3657
3658 class HelloWorldApp {
3659 public void main(String[] args) {
3660 String message = args.length == 0 ? \"Hello empty world\" : \"Hello world\"; // +1 lloc : 1 var assignment
3661 System.out.println(message); // Display the string. +1 lloc
3662 }
3663 }",
3664 "foo.java",
3665 |metric| {
3666 insta::assert_json_snapshot!(
3668 metric.loc,
3669 @r#"
3670 {
3671 "sloc": 12,
3672 "ploc": 7,
3673 "lloc": 2,
3674 "cloc": 6,
3675 "blank": 1,
3676 "sloc_average": 4.0,
3677 "ploc_average": 2.3333333333333335,
3678 "lloc_average": 0.6666666666666666,
3679 "cloc_average": 2.0,
3680 "blank_average": 0.3333333333333333,
3681 "sloc_min": 4,
3682 "sloc_max": 12,
3683 "cloc_min": 2,
3684 "cloc_max": 6,
3685 "ploc_min": 4,
3686 "ploc_max": 7,
3687 "lloc_min": 2,
3688 "lloc_max": 2,
3689 "blank_min": 0,
3690 "blank_max": 1
3691 }
3692 "#
3693 );
3694 },
3695 );
3696 }
3697
3698 #[test]
3699 fn go_general_loc() {
3700 check_metrics::<GoParser>(
3701 "package main
3702
3703 // entrypoint
3704 func main() {
3705 /* loop body */
3706 for i := 0; i < 10; i++ {
3707 fmt.Println(i)
3708 }
3709 }",
3710 "foo.go",
3711 |metric| {
3712 insta::assert_json_snapshot!(
3717 metric.loc,
3718 @r#"
3719 {
3720 "sloc": 9,
3721 "ploc": 6,
3722 "lloc": 2,
3723 "cloc": 2,
3724 "blank": 1,
3725 "sloc_average": 4.5,
3726 "ploc_average": 3.0,
3727 "lloc_average": 1.0,
3728 "cloc_average": 1.0,
3729 "blank_average": 0.5,
3730 "sloc_min": 6,
3731 "sloc_max": 9,
3732 "cloc_min": 1,
3733 "cloc_max": 2,
3734 "ploc_min": 5,
3735 "ploc_max": 6,
3736 "lloc_min": 2,
3737 "lloc_max": 2,
3738 "blank_min": 0,
3739 "blank_max": 1
3740 }
3741 "#
3742 );
3743 },
3744 );
3745 }
3746
3747 #[test]
3748 fn go_for_clause_does_not_double_count_lloc() {
3749 check_metrics::<GoParser>(
3753 "package main
3754 func f(n int) int {
3755 for i := 0; i < n; i++ {
3756 return i
3757 }
3758 return 0
3759 }",
3760 "foo.go",
3761 |metric| {
3762 assert_eq!(metric.loc.lloc(), 3);
3765 },
3766 );
3767 }
3768
3769 #[test]
3770 fn go_blank() {
3771 check_metrics::<GoParser>(
3772 "package main
3773
3774 func foo() {
3775 x := 1
3776
3777 y := 2
3778 }",
3779 "foo.go",
3780 |metric| {
3781 insta::assert_json_snapshot!(
3784 metric.loc,
3785 @r#"
3786 {
3787 "sloc": 7,
3788 "ploc": 5,
3789 "lloc": 2,
3790 "cloc": 0,
3791 "blank": 2,
3792 "sloc_average": 3.5,
3793 "ploc_average": 2.5,
3794 "lloc_average": 1.0,
3795 "cloc_average": 0.0,
3796 "blank_average": 1.0,
3797 "sloc_min": 5,
3798 "sloc_max": 7,
3799 "cloc_min": 0,
3800 "cloc_max": 0,
3801 "ploc_min": 4,
3802 "ploc_max": 5,
3803 "lloc_min": 2,
3804 "lloc_max": 2,
3805 "blank_min": 1,
3806 "blank_max": 2
3807 }
3808 "#
3809 );
3810 },
3811 );
3812 }
3813
3814 #[test]
3815 fn go_cloc_line_comments() {
3816 check_metrics::<GoParser>(
3817 "package main
3818
3819 // helper adds two numbers.
3820 // It returns their sum.
3821 func add(a, b int) int {
3822 // compute the result
3823 return a + b
3824 }",
3825 "foo.go",
3826 |metric| {
3827 insta::assert_json_snapshot!(
3830 metric.loc,
3831 @r#"
3832 {
3833 "sloc": 8,
3834 "ploc": 4,
3835 "lloc": 1,
3836 "cloc": 3,
3837 "blank": 1,
3838 "sloc_average": 4.0,
3839 "ploc_average": 2.0,
3840 "lloc_average": 0.5,
3841 "cloc_average": 1.5,
3842 "blank_average": 0.5,
3843 "sloc_min": 4,
3844 "sloc_max": 8,
3845 "cloc_min": 1,
3846 "cloc_max": 3,
3847 "ploc_min": 3,
3848 "ploc_max": 4,
3849 "lloc_min": 1,
3850 "lloc_max": 1,
3851 "blank_min": 0,
3852 "blank_max": 1
3853 }
3854 "#
3855 );
3856 },
3857 );
3858 }
3859
3860 #[test]
3861 fn go_cloc_block_comments() {
3862 check_metrics::<GoParser>(
3863 "package main
3864
3865 /* block comment
3866 spanning two lines */
3867 func foo() {
3868 x := 1 /* inline block */
3869 }",
3870 "foo.go",
3871 |metric| {
3872 insta::assert_json_snapshot!(
3875 metric.loc,
3876 @r#"
3877 {
3878 "sloc": 7,
3879 "ploc": 4,
3880 "lloc": 1,
3881 "cloc": 3,
3882 "blank": 1,
3883 "sloc_average": 3.5,
3884 "ploc_average": 2.0,
3885 "lloc_average": 0.5,
3886 "cloc_average": 1.5,
3887 "blank_average": 0.5,
3888 "sloc_min": 3,
3889 "sloc_max": 7,
3890 "cloc_min": 1,
3891 "cloc_max": 3,
3892 "ploc_min": 3,
3893 "ploc_max": 4,
3894 "lloc_min": 1,
3895 "lloc_max": 1,
3896 "blank_min": 0,
3897 "blank_max": 1
3898 }
3899 "#
3900 );
3901 },
3902 );
3903 }
3904
3905 #[test]
3906 fn go_lloc_if_for_switch() {
3907 check_metrics::<GoParser>(
3908 "package main
3909
3910 func foo(n int) int {
3911 if n > 0 {
3912 for i := 0; i < n; i++ {
3913 switch i {
3914 }
3915 }
3916 }
3917 return n
3918 }",
3919 "foo.go",
3920 |metric| {
3921 insta::assert_json_snapshot!(
3924 metric.loc,
3925 @r#"
3926 {
3927 "sloc": 11,
3928 "ploc": 10,
3929 "lloc": 4,
3930 "cloc": 0,
3931 "blank": 1,
3932 "sloc_average": 5.5,
3933 "ploc_average": 5.0,
3934 "lloc_average": 2.0,
3935 "cloc_average": 0.0,
3936 "blank_average": 0.5,
3937 "sloc_min": 9,
3938 "sloc_max": 11,
3939 "cloc_min": 0,
3940 "cloc_max": 0,
3941 "ploc_min": 9,
3942 "ploc_max": 10,
3943 "lloc_min": 4,
3944 "lloc_max": 4,
3945 "blank_min": 0,
3946 "blank_max": 1
3947 }
3948 "#
3949 );
3950 },
3951 );
3952 }
3953
3954 #[test]
3955 fn go_lloc_go_defer() {
3956 check_metrics::<GoParser>(
3957 "package main
3958
3959 func foo() {
3960 go run()
3961 defer cleanup()
3962 }",
3963 "foo.go",
3964 |metric| {
3965 insta::assert_json_snapshot!(
3968 metric.loc,
3969 @r#"
3970 {
3971 "sloc": 6,
3972 "ploc": 5,
3973 "lloc": 2,
3974 "cloc": 0,
3975 "blank": 1,
3976 "sloc_average": 3.0,
3977 "ploc_average": 2.5,
3978 "lloc_average": 1.0,
3979 "cloc_average": 0.0,
3980 "blank_average": 0.5,
3981 "sloc_min": 4,
3982 "sloc_max": 6,
3983 "cloc_min": 0,
3984 "cloc_max": 0,
3985 "ploc_min": 4,
3986 "ploc_max": 5,
3987 "lloc_min": 2,
3988 "lloc_max": 2,
3989 "blank_min": 0,
3990 "blank_max": 1
3991 }
3992 "#
3993 );
3994 },
3995 );
3996 }
3997
3998 #[test]
3999 fn go_lloc_var_const_declarations() {
4000 check_metrics::<GoParser>(
4001 "package main
4002
4003 func foo() {
4004 var x int
4005 var y = 10
4006 const z = 42
4007 a := 3
4008 a = 4
4009 }",
4010 "foo.go",
4011 |metric| {
4012 insta::assert_json_snapshot!(
4016 metric.loc,
4017 @r#"
4018 {
4019 "sloc": 9,
4020 "ploc": 8,
4021 "lloc": 5,
4022 "cloc": 0,
4023 "blank": 1,
4024 "sloc_average": 4.5,
4025 "ploc_average": 4.0,
4026 "lloc_average": 2.5,
4027 "cloc_average": 0.0,
4028 "blank_average": 0.5,
4029 "sloc_min": 7,
4030 "sloc_max": 9,
4031 "cloc_min": 0,
4032 "cloc_max": 0,
4033 "ploc_min": 7,
4034 "ploc_max": 8,
4035 "lloc_min": 5,
4036 "lloc_max": 5,
4037 "blank_min": 0,
4038 "blank_max": 1
4039 }
4040 "#
4041 );
4042 },
4043 );
4044 }
4045
4046 #[test]
4047 fn go_lloc_select() {
4048 check_metrics::<GoParser>(
4049 "package main
4050
4051 func foo(ch chan int) {
4052 select {
4053 case v := <-ch:
4054 _ = v
4055 }
4056 }",
4057 "foo.go",
4058 |metric| {
4059 insta::assert_json_snapshot!(
4064 metric.loc,
4065 @r#"
4066 {
4067 "sloc": 8,
4068 "ploc": 7,
4069 "lloc": 2,
4070 "cloc": 0,
4071 "blank": 1,
4072 "sloc_average": 4.0,
4073 "ploc_average": 3.5,
4074 "lloc_average": 1.0,
4075 "cloc_average": 0.0,
4076 "blank_average": 0.5,
4077 "sloc_min": 6,
4078 "sloc_max": 8,
4079 "cloc_min": 0,
4080 "cloc_max": 0,
4081 "ploc_min": 6,
4082 "ploc_max": 7,
4083 "lloc_min": 2,
4084 "lloc_max": 2,
4085 "blank_min": 0,
4086 "blank_max": 1
4087 }
4088 "#
4089 );
4090 },
4091 );
4092 }
4093
4094 #[test]
4095 fn go_sloc_multiline_function() {
4096 check_metrics::<GoParser>(
4097 "package main
4098
4099 func add(
4100 a int,
4101 b int,
4102 ) int {
4103 return a + b
4104 }",
4105 "foo.go",
4106 |metric| {
4107 insta::assert_json_snapshot!(
4110 metric.loc,
4111 @r#"
4112 {
4113 "sloc": 8,
4114 "ploc": 7,
4115 "lloc": 1,
4116 "cloc": 0,
4117 "blank": 1,
4118 "sloc_average": 4.0,
4119 "ploc_average": 3.5,
4120 "lloc_average": 0.5,
4121 "cloc_average": 0.0,
4122 "blank_average": 0.5,
4123 "sloc_min": 6,
4124 "sloc_max": 8,
4125 "cloc_min": 0,
4126 "cloc_max": 0,
4127 "ploc_min": 6,
4128 "ploc_max": 7,
4129 "lloc_min": 1,
4130 "lloc_max": 1,
4131 "blank_min": 0,
4132 "blank_max": 1
4133 }
4134 "#
4135 );
4136 },
4137 );
4138 }
4139
4140 #[test]
4141 fn go_code_comment_same_line() {
4142 check_metrics::<GoParser>(
4143 "package main
4144
4145 func foo() {
4146 x := 1 // initialize x
4147 y := 2 // initialize y
4148 }",
4149 "foo.go",
4150 |metric| {
4151 insta::assert_json_snapshot!(
4156 metric.loc,
4157 @r#"
4158 {
4159 "sloc": 6,
4160 "ploc": 5,
4161 "lloc": 2,
4162 "cloc": 2,
4163 "blank": 1,
4164 "sloc_average": 3.0,
4165 "ploc_average": 2.5,
4166 "lloc_average": 1.0,
4167 "cloc_average": 1.0,
4168 "blank_average": 0.5,
4169 "sloc_min": 4,
4170 "sloc_max": 6,
4171 "cloc_min": 2,
4172 "cloc_max": 2,
4173 "ploc_min": 4,
4174 "ploc_max": 5,
4175 "lloc_min": 2,
4176 "lloc_max": 2,
4177 "blank_min": 0,
4178 "blank_max": 1
4179 }
4180 "#
4181 );
4182 },
4183 );
4184 }
4185
4186 #[test]
4187 fn perl_grammar_smoke() {
4188 assert_perl_parses_cleanly(
4194 "use strict;
4195use warnings;
4196
4197# line comment
4198
4199=pod
4200multi-line POD
4201=cut
4202
4203sub factorial {
4204 my ($n) = @_;
4205 return 1 if $n <= 1;
4206 return $n * factorial($n - 1);
4207}
4208
4209my @arr = (1, 2, 3);
4210my %hash = (a => 1, b => 2);
4211my $closure = sub { return $_[0] + 1; };
4212
4213for my $i (1..3) {
4214 if ($i % 2 == 0) {
4215 print \"even\\n\";
4216 } elsif ($i == 1) {
4217 print \"one\\n\";
4218 } else {
4219 print \"odd\\n\";
4220 }
4221}
4222
4223while ($x > 0) {
4224 last if $x == 0;
4225 $x--;
4226}
4227
4228unless ($done) {
4229 next;
4230}
4231
4232my $heredoc = <<END;
4233hello
4234END
4235",
4236 );
4237 }
4238
4239 #[test]
4240 fn perl_blank() {
4241 check_metrics::<PerlParser>(
4242 "
4243
4244my $a = 42;
4245
4246my $b = 43;
4247
4248",
4249 "foo.pl",
4250 |metric| {
4251 insta::assert_json_snapshot!(metric.loc, @r#"
4252 {
4253 "sloc": 3,
4254 "ploc": 2,
4255 "lloc": 2,
4256 "cloc": 0,
4257 "blank": 1,
4258 "sloc_average": 3.0,
4259 "ploc_average": 2.0,
4260 "lloc_average": 2.0,
4261 "cloc_average": 0.0,
4262 "blank_average": 1.0,
4263 "sloc_min": 3,
4264 "sloc_max": 3,
4265 "cloc_min": 0,
4266 "cloc_max": 0,
4267 "ploc_min": 2,
4268 "ploc_max": 2,
4269 "lloc_min": 2,
4270 "lloc_max": 2,
4271 "blank_min": 1,
4272 "blank_max": 1
4273 }
4274 "#);
4275 },
4276 );
4277 }
4278
4279 #[test]
4280 fn perl_no_zero_blank() {
4281 check_metrics::<PerlParser>(
4284 "my $a = 1;
4285my $b = 2;
4286
4287my $c = 3; # trailing
4288my $d = 4; # trailing
4289my $e = 5;",
4290 "foo.pl",
4291 |metric| {
4292 assert_eq!(metric.loc.sloc(), 6);
4293 assert_eq!(metric.loc.ploc(), 5);
4294 assert_eq!(metric.loc.cloc(), 2);
4295 assert_eq!(metric.loc.blank(), 1);
4296 insta::assert_json_snapshot!(metric.loc);
4297 },
4298 );
4299 }
4300
4301 #[test]
4302 fn perl_blank_zero_sanity() {
4303 check_metrics::<PerlParser>(
4306 "my $a = 1;
4307my $b = 2;",
4308 "foo.pl",
4309 |metric| {
4310 assert_eq!(metric.loc.sloc(), 2);
4311 assert_eq!(metric.loc.ploc(), 2);
4312 assert_eq!(metric.loc.lloc(), 2);
4313 assert_eq!(metric.loc.cloc(), 0);
4314 assert_eq!(metric.loc.blank(), 0);
4315 },
4316 );
4317 }
4318
4319 #[test]
4325 fn perl_cloc_line_comments() {
4326 check_metrics::<PerlParser>(
4327 "# top comment
4328my $a = 1; # trailing
4329my $b = 2;",
4330 "foo.pl",
4331 |metric| {
4332 insta::assert_json_snapshot!(metric.loc, @r#"
4333 {
4334 "sloc": 3,
4335 "ploc": 2,
4336 "lloc": 2,
4337 "cloc": 2,
4338 "blank": 0,
4339 "sloc_average": 3.0,
4340 "ploc_average": 2.0,
4341 "lloc_average": 2.0,
4342 "cloc_average": 2.0,
4343 "blank_average": 0.0,
4344 "sloc_min": 3,
4345 "sloc_max": 3,
4346 "cloc_min": 2,
4347 "cloc_max": 2,
4348 "ploc_min": 2,
4349 "ploc_max": 2,
4350 "lloc_min": 2,
4351 "lloc_max": 2,
4352 "blank_min": 0,
4353 "blank_max": 0
4354 }
4355 "#);
4356 },
4357 );
4358 }
4359
4360 #[test]
4361 fn perl_cloc_pod_block() {
4362 check_metrics::<PerlParser>(
4363 "my $x = 1;
4364=pod
4365multi-line
4366pod block
4367=cut
4368my $y = 2;",
4369 "foo.pl",
4370 |metric| {
4371 insta::assert_json_snapshot!(metric.loc, @r#"
4372 {
4373 "sloc": 6,
4374 "ploc": 2,
4375 "lloc": 2,
4376 "cloc": 4,
4377 "blank": 0,
4378 "sloc_average": 6.0,
4379 "ploc_average": 2.0,
4380 "lloc_average": 2.0,
4381 "cloc_average": 4.0,
4382 "blank_average": 0.0,
4383 "sloc_min": 6,
4384 "sloc_max": 6,
4385 "cloc_min": 4,
4386 "cloc_max": 4,
4387 "ploc_min": 2,
4388 "ploc_max": 2,
4389 "lloc_min": 2,
4390 "lloc_max": 2,
4391 "blank_min": 0,
4392 "blank_max": 0
4393 }
4394 "#);
4395 },
4396 );
4397 }
4398
4399 #[test]
4400 fn perl_lloc_simple_statements() {
4401 check_metrics::<PerlParser>(
4402 "my $a = 1;
4403my $b = 2;
4404my $c = 3;",
4405 "foo.pl",
4406 |metric| {
4407 insta::assert_json_snapshot!(metric.loc, @r#"
4408 {
4409 "sloc": 3,
4410 "ploc": 3,
4411 "lloc": 3,
4412 "cloc": 0,
4413 "blank": 0,
4414 "sloc_average": 3.0,
4415 "ploc_average": 3.0,
4416 "lloc_average": 3.0,
4417 "cloc_average": 0.0,
4418 "blank_average": 0.0,
4419 "sloc_min": 3,
4420 "sloc_max": 3,
4421 "cloc_min": 0,
4422 "cloc_max": 0,
4423 "ploc_min": 3,
4424 "ploc_max": 3,
4425 "lloc_min": 3,
4426 "lloc_max": 3,
4427 "blank_min": 0,
4428 "blank_max": 0
4429 }
4430 "#);
4431 },
4432 );
4433 }
4434
4435 #[test]
4436 fn perl_lloc_compound_statements() {
4437 check_metrics::<PerlParser>(
4438 "if ($x) {
4439 print 'a';
4440}
4441while ($n > 0) {
4442 $n--;
4443}",
4444 "foo.pl",
4445 |metric| {
4446 insta::assert_json_snapshot!(metric.loc, @r#"
4447 {
4448 "sloc": 6,
4449 "ploc": 6,
4450 "lloc": 4,
4451 "cloc": 0,
4452 "blank": 0,
4453 "sloc_average": 6.0,
4454 "ploc_average": 6.0,
4455 "lloc_average": 4.0,
4456 "cloc_average": 0.0,
4457 "blank_average": 0.0,
4458 "sloc_min": 6,
4459 "sloc_max": 6,
4460 "cloc_min": 0,
4461 "cloc_max": 0,
4462 "ploc_min": 6,
4463 "ploc_max": 6,
4464 "lloc_min": 4,
4465 "lloc_max": 4,
4466 "blank_min": 0,
4467 "blank_max": 0
4468 }
4469 "#);
4470 },
4471 );
4472 }
4473
4474 #[test]
4475 fn perl_lloc_postfix_form_counts_once() {
4476 check_metrics::<PerlParser>(
4480 "sub f {
4481 return 1 if $_[0];
4482}",
4483 "foo.pl",
4484 |metric| {
4485 assert_eq!(metric.loc.lloc(), 1);
4486 },
4487 );
4488 }
4489
4490 #[test]
4491 fn perl_lloc_use_statement() {
4492 check_metrics::<PerlParser>(
4493 "use strict;
4494use warnings;
4495my $x = 1;",
4496 "foo.pl",
4497 |metric| {
4498 insta::assert_json_snapshot!(metric.loc, @r#"
4499 {
4500 "sloc": 3,
4501 "ploc": 3,
4502 "lloc": 3,
4503 "cloc": 0,
4504 "blank": 0,
4505 "sloc_average": 3.0,
4506 "ploc_average": 3.0,
4507 "lloc_average": 3.0,
4508 "cloc_average": 0.0,
4509 "blank_average": 0.0,
4510 "sloc_min": 3,
4511 "sloc_max": 3,
4512 "cloc_min": 0,
4513 "cloc_max": 0,
4514 "ploc_min": 3,
4515 "ploc_max": 3,
4516 "lloc_min": 3,
4517 "lloc_max": 3,
4518 "blank_min": 0,
4519 "blank_max": 0
4520 }
4521 "#);
4522 },
4523 );
4524 }
4525
4526 #[test]
4527 fn perl_lloc_for_loop() {
4528 check_metrics::<PerlParser>(
4529 "for my $i (1..3) {
4530 print $i;
4531}",
4532 "foo.pl",
4533 |metric| {
4534 assert_eq!(metric.loc.lloc(), 2);
4536 },
4537 );
4538 }
4539
4540 #[test]
4541 fn perl_lloc_loop_control_statement() {
4542 check_metrics::<PerlParser>(
4543 "while (1) {
4544 last if $done;
4545}",
4546 "foo.pl",
4547 |metric| {
4548 assert_eq!(metric.loc.lloc(), 2);
4550 },
4551 );
4552 }
4553
4554 #[test]
4555 fn perl_lloc_no_double_count_inside_single_line_statement() {
4556 check_metrics::<PerlParser>(
4559 "sub f {
4560 print 'a' unless $_[0];
4561}",
4562 "foo.pl",
4563 |metric| {
4564 assert_eq!(metric.loc.lloc(), 1);
4565 },
4566 );
4567 }
4568
4569 #[test]
4570 fn perl_lloc_function_definition_not_counted() {
4571 check_metrics::<PerlParser>(
4574 "sub f {
4575 my $x = 1;
4576}",
4577 "foo.pl",
4578 |metric| {
4579 assert_eq!(metric.loc.lloc(), 1);
4580 },
4581 );
4582 }
4583
4584 #[test]
4585 fn perl_lloc_anonymous_function() {
4586 check_metrics::<PerlParser>("my $f = sub { return 1; };", "foo.pl", |metric| {
4590 assert_eq!(metric.loc.lloc(), 2);
4591 });
4592 }
4593
4594 #[test]
4595 fn perl_multiline_string_assignment_ploc() {
4596 check_metrics::<PerlParser>(
4603 "my $s = \"line1
4604line2
4605line3\";",
4606 "foo.pl",
4607 |metric| {
4608 assert_eq!(metric.loc.sloc(), 3);
4610 assert_eq!(metric.loc.ploc(), 3);
4611 assert_eq!(metric.loc.cloc(), 0);
4612 assert_eq!(metric.loc.blank(), 0);
4613 },
4614 );
4615 }
4616
4617 #[test]
4618 fn multiline_string_ploc_consistent_across_languages() {
4619 #[allow(clippy::needless_pass_by_value)]
4627 fn assert_three_code_rows(metric: crate::CodeMetrics) {
4628 assert_eq!(metric.loc.sloc(), 3);
4629 assert_eq!(metric.loc.ploc(), 3);
4630 assert_eq!(metric.loc.cloc(), 0);
4631 assert_eq!(metric.loc.blank(), 0);
4632 }
4633 check_metrics::<PythonParser>(
4634 "s = \"\"\"line1\nline2\nline3\"\"\"",
4635 "foo.py",
4636 assert_three_code_rows,
4637 );
4638 check_metrics::<PerlParser>(
4639 "my $s = \"line1\nline2\nline3\";",
4640 "foo.pl",
4641 assert_three_code_rows,
4642 );
4643 check_metrics::<RubyParser>(
4644 "s = \"line1\nline2\nline3\"",
4645 "foo.rb",
4646 assert_three_code_rows,
4647 );
4648 check_metrics::<GoParser>(
4655 "package p\n\nvar s = `line1\nline2\nline3`",
4656 "foo.go",
4657 |metric| {
4658 assert_eq!(metric.loc.sloc(), 5);
4661 assert_eq!(metric.loc.ploc(), 4);
4662 assert_eq!(metric.loc.cloc(), 0);
4663 assert_eq!(metric.loc.blank(), 1);
4664 },
4665 );
4666 check_metrics::<KotlinParser>(
4667 "val s = \"\"\"line1\nline2\nline3\"\"\"",
4668 "foo.kt",
4669 assert_three_code_rows,
4670 );
4671 check_metrics::<MozcppParser>(
4672 "const char* s = R\"(line1\nline2\nline3)\";",
4673 "foo.cpp",
4674 assert_three_code_rows,
4675 );
4676 }
4677
4678 #[test]
4679 fn perl_lloc_unless_until() {
4680 check_metrics::<PerlParser>(
4681 "unless ($x) {
4682 print 'a';
4683}
4684until ($n == 0) {
4685 $n--;
4686}",
4687 "foo.pl",
4688 |metric| {
4689 assert_eq!(metric.loc.lloc(), 4);
4692 },
4693 );
4694 }
4695
4696 #[test]
4697 fn perl_lloc_heredoc_body_not_counted() {
4698 check_metrics::<PerlParser>(
4701 "my $s = <<END;
4702line1
4703line2
4704END
4705my $x = 1;",
4706 "foo.pl",
4707 |metric| {
4708 assert_eq!(metric.loc.lloc(), 2);
4711 },
4712 );
4713 assert_perl_parses_cleanly(
4717 "my $s = <<END;
4718line1
4719line2
4720END
4721my $x = 1;",
4722 );
4723 }
4724
4725 #[test]
4726 fn perl_lloc_package_and_require() {
4727 check_metrics::<PerlParser>(
4728 "package Foo;
4729require 5.010;
4730my $x = 1;",
4731 "foo.pl",
4732 |metric| {
4733 insta::assert_json_snapshot!(metric.loc, @r#"
4734 {
4735 "sloc": 3,
4736 "ploc": 3,
4737 "lloc": 3,
4738 "cloc": 0,
4739 "blank": 0,
4740 "sloc_average": 3.0,
4741 "ploc_average": 3.0,
4742 "lloc_average": 3.0,
4743 "cloc_average": 0.0,
4744 "blank_average": 0.0,
4745 "sloc_min": 3,
4746 "sloc_max": 3,
4747 "cloc_min": 0,
4748 "cloc_max": 0,
4749 "ploc_min": 3,
4750 "ploc_max": 3,
4751 "lloc_min": 3,
4752 "lloc_max": 3,
4753 "blank_min": 0,
4754 "blank_max": 0
4755 }
4756 "#);
4757 },
4758 );
4759 }
4760
4761 #[test]
4762 fn lua_blank() {
4763 check_metrics::<LuaParser>(
4764 "local x = 1
4765
4766local y = 2",
4767 "foo.lua",
4768 |metric| {
4769 assert_eq!(metric.loc.sloc(), 3);
4770 assert_eq!(metric.loc.ploc(), 2);
4771 assert_eq!(metric.loc.lloc(), 2);
4772 assert_eq!(metric.loc.cloc(), 0);
4773 assert_eq!(metric.loc.blank(), 1);
4774 insta::assert_json_snapshot!(metric.loc);
4775 },
4776 );
4777 }
4778
4779 #[test]
4780 fn lua_no_zero_blank() {
4781 check_metrics::<LuaParser>(
4784 "local a = 1
4785local b = 2
4786
4787local c = 3 -- trailing
4788local d = 4 -- trailing
4789local e = 5",
4790 "foo.lua",
4791 |metric| {
4792 assert_eq!(metric.loc.sloc(), 6);
4793 assert_eq!(metric.loc.ploc(), 5);
4794 assert_eq!(metric.loc.cloc(), 2);
4795 assert_eq!(metric.loc.blank(), 1);
4796 insta::assert_json_snapshot!(metric.loc);
4797 },
4798 );
4799 }
4800
4801 #[test]
4802 fn lua_blank_zero_sanity() {
4803 check_metrics::<LuaParser>(
4806 "local x = 1
4807local y = 2",
4808 "foo.lua",
4809 |metric| {
4810 assert_eq!(metric.loc.sloc(), 2);
4811 assert_eq!(metric.loc.ploc(), 2);
4812 assert_eq!(metric.loc.lloc(), 2);
4813 assert_eq!(metric.loc.cloc(), 0);
4814 assert_eq!(metric.loc.blank(), 0);
4815 },
4816 );
4817 }
4818
4819 #[test]
4820 fn lua_cloc() {
4821 check_metrics::<LuaParser>(
4822 "-- single line comment
4823local x = 1
4824--[[
4825 block comment
4826 second line
4827]]",
4828 "foo.lua",
4829 |metric| {
4830 assert_eq!(metric.loc.sloc(), 6);
4831 assert_eq!(metric.loc.ploc(), 1);
4832 assert_eq!(metric.loc.lloc(), 1);
4833 assert_eq!(metric.loc.cloc(), 5);
4834 assert_eq!(metric.loc.blank(), 0);
4835 insta::assert_json_snapshot!(metric.loc);
4836 },
4837 );
4838 }
4839
4840 #[test]
4841 fn lua_lloc() {
4842 check_metrics::<LuaParser>(
4843 "local function f(x)
4844 if x > 0 then
4845 local y = x + 1
4846 return y
4847 end
4848 return 0
4849end",
4850 "foo.lua",
4851 |metric| {
4852 assert_eq!(metric.loc.sloc(), 7);
4853 assert_eq!(metric.loc.ploc(), 7);
4854 assert_eq!(metric.loc.lloc(), 5);
4855 assert_eq!(metric.loc.cloc(), 0);
4856 assert_eq!(metric.loc.blank(), 0);
4857 insta::assert_json_snapshot!(metric.loc);
4858 },
4859 );
4860 }
4861
4862 #[test]
4863 fn lua_no_string_lloc() {
4864 check_metrics::<LuaParser>(
4866 "local s = [[
4867 line one
4868 line two
4869]]",
4870 "foo.lua",
4871 |metric| {
4872 assert_eq!(metric.loc.sloc(), 4);
4877 assert_eq!(metric.loc.ploc(), 4);
4878 assert_eq!(metric.loc.lloc(), 1);
4879 assert_eq!(metric.loc.cloc(), 0);
4880 assert_eq!(metric.loc.blank(), 0);
4881 insta::assert_json_snapshot!(metric.loc);
4882 },
4883 );
4884 }
4885
4886 #[test]
4887 fn lua_no_functiondefinition_lloc() {
4888 check_metrics::<LuaParser>(
4891 "local f = function(x)
4892 return x + 1
4893end",
4894 "foo.lua",
4895 |metric| {
4896 assert_eq!(metric.loc.sloc(), 3);
4897 assert_eq!(metric.loc.ploc(), 3);
4898 assert_eq!(metric.loc.lloc(), 2);
4899 assert_eq!(metric.loc.cloc(), 0);
4900 assert_eq!(metric.loc.blank(), 0);
4901 insta::assert_json_snapshot!(metric.loc);
4902 },
4903 );
4904 }
4905
4906 #[test]
4907 fn lua_no_elseif_lloc() {
4908 check_metrics::<LuaParser>(
4910 "local function f(x)
4911 if x > 0 then
4912 return 1
4913 elseif x < 0 then
4914 return -1
4915 else
4916 return 0
4917 end
4918end",
4919 "foo.lua",
4920 |metric| {
4921 assert_eq!(metric.loc.sloc(), 9);
4922 assert_eq!(metric.loc.ploc(), 9);
4923 assert_eq!(metric.loc.lloc(), 5);
4924 assert_eq!(metric.loc.cloc(), 0);
4925 assert_eq!(metric.loc.blank(), 0);
4926 insta::assert_json_snapshot!(metric.loc);
4927 },
4928 );
4929 }
4930
4931 #[test]
4932 fn lua_no_else_lloc() {
4933 check_metrics::<LuaParser>(
4935 "local function f(x)
4936 if x > 0 then
4937 return 1
4938 else
4939 return 0
4940 end
4941end",
4942 "foo.lua",
4943 |metric| {
4944 assert_eq!(metric.loc.sloc(), 7);
4945 assert_eq!(metric.loc.ploc(), 7);
4946 assert_eq!(metric.loc.lloc(), 4);
4947 assert_eq!(metric.loc.cloc(), 0);
4948 assert_eq!(metric.loc.blank(), 0);
4949 insta::assert_json_snapshot!(metric.loc);
4950 },
4951 );
4952 }
4953
4954 #[test]
4955 fn lua_functiondeclaration_lloc() {
4956 check_metrics::<LuaParser>(
4958 "function f()
4959 return 1
4960end",
4961 "foo.lua",
4962 |metric| {
4963 assert_eq!(metric.loc.sloc(), 3);
4964 assert_eq!(metric.loc.ploc(), 3);
4965 assert_eq!(metric.loc.lloc(), 2);
4966 assert_eq!(metric.loc.cloc(), 0);
4967 assert_eq!(metric.loc.blank(), 0);
4968 insta::assert_json_snapshot!(metric.loc);
4969 },
4970 );
4971 }
4972
4973 #[test]
4974 fn lua_local_function_lloc() {
4975 check_metrics::<LuaParser>(
4977 "local function g()
4978 return 2
4979end",
4980 "foo.lua",
4981 |metric| {
4982 assert_eq!(metric.loc.sloc(), 3);
4983 assert_eq!(metric.loc.ploc(), 3);
4984 assert_eq!(metric.loc.lloc(), 2);
4985 assert_eq!(metric.loc.cloc(), 0);
4986 assert_eq!(metric.loc.blank(), 0);
4987 insta::assert_json_snapshot!(metric.loc);
4988 },
4989 );
4990 }
4991
4992 #[test]
4993 fn lua_for_numeric_lloc() {
4994 check_metrics::<LuaParser>(
4995 "for i = 1, 10 do
4996 print(i)
4997end",
4998 "foo.lua",
4999 |metric| {
5000 assert_eq!(metric.loc.sloc(), 3);
5001 assert_eq!(metric.loc.ploc(), 3);
5002 assert_eq!(metric.loc.lloc(), 1);
5003 assert_eq!(metric.loc.cloc(), 0);
5004 assert_eq!(metric.loc.blank(), 0);
5005 insta::assert_json_snapshot!(metric.loc);
5006 },
5007 );
5008 }
5009
5010 #[test]
5011 fn lua_for_generic_lloc() {
5012 check_metrics::<LuaParser>(
5013 "for k, v in pairs(t) do
5014 print(k, v)
5015end",
5016 "foo.lua",
5017 |metric| {
5018 assert_eq!(metric.loc.sloc(), 3);
5019 assert_eq!(metric.loc.ploc(), 3);
5020 assert_eq!(metric.loc.lloc(), 1);
5021 assert_eq!(metric.loc.cloc(), 0);
5022 assert_eq!(metric.loc.blank(), 0);
5023 insta::assert_json_snapshot!(metric.loc);
5024 },
5025 );
5026 }
5027
5028 #[test]
5029 fn lua_repeat_lloc() {
5030 check_metrics::<LuaParser>(
5031 "local i = 0
5032repeat
5033 i = i + 1
5034until i >= 10",
5035 "foo.lua",
5036 |metric| {
5037 assert_eq!(metric.loc.sloc(), 4);
5038 assert_eq!(metric.loc.ploc(), 4);
5039 assert_eq!(metric.loc.lloc(), 3);
5040 assert_eq!(metric.loc.cloc(), 0);
5041 assert_eq!(metric.loc.blank(), 0);
5042 insta::assert_json_snapshot!(metric.loc);
5043 },
5044 );
5045 }
5046
5047 #[test]
5048 fn lua_local_decl_lloc() {
5049 check_metrics::<LuaParser>(
5050 "local x = 1
5051local y, z = 2, 3",
5052 "foo.lua",
5053 |metric| {
5054 assert_eq!(metric.loc.sloc(), 2);
5055 assert_eq!(metric.loc.ploc(), 2);
5056 assert_eq!(metric.loc.lloc(), 2);
5057 assert_eq!(metric.loc.cloc(), 0);
5058 assert_eq!(metric.loc.blank(), 0);
5059 insta::assert_json_snapshot!(metric.loc);
5060 },
5061 );
5062 }
5063
5064 #[test]
5065 fn lua_function_call_lloc() {
5066 check_metrics::<LuaParser>(
5069 "print(\"hello\")
5070local x = 1",
5071 "foo.lua",
5072 |metric| {
5073 assert_eq!(metric.loc.sloc(), 2);
5074 assert_eq!(metric.loc.ploc(), 2);
5075 assert_eq!(metric.loc.lloc(), 1);
5076 assert_eq!(metric.loc.cloc(), 0);
5077 assert_eq!(metric.loc.blank(), 0);
5078 insta::assert_json_snapshot!(metric.loc);
5079 },
5080 );
5081 }
5082
5083 #[test]
5084 fn lua_toplevel_assignment_lloc() {
5085 check_metrics::<LuaParser>(
5088 "x = 1
5089y, z = 2, 3",
5090 "foo.lua",
5091 |metric| {
5092 assert_eq!(metric.loc.sloc(), 2);
5093 assert_eq!(metric.loc.ploc(), 2);
5094 assert_eq!(metric.loc.lloc(), 2);
5095 assert_eq!(metric.loc.cloc(), 0);
5096 assert_eq!(metric.loc.blank(), 0);
5097 insta::assert_json_snapshot!(metric.loc);
5098 },
5099 );
5100 }
5101
5102 #[test]
5103 fn tsx_basic_loc() {
5104 check_metrics::<TsxParser>(
5105 "// A simple utility function
5106 function add(a: number, b: number): number {
5107 /* multi-line
5108 comment */
5109 return a + b;
5110 }
5111
5112 const greet = (name: string) => {
5113 return `Hello, ${name}`;
5114 };",
5115 "foo.tsx",
5116 |metric| {
5117 insta::assert_json_snapshot!(
5118 metric.loc,
5119 @r#"
5120 {
5121 "sloc": 10,
5122 "ploc": 6,
5123 "lloc": 3,
5124 "cloc": 3,
5125 "blank": 1,
5126 "sloc_average": 3.3333333333333335,
5127 "ploc_average": 2.0,
5128 "lloc_average": 1.0,
5129 "cloc_average": 1.0,
5130 "blank_average": 0.3333333333333333,
5131 "sloc_min": 3,
5132 "sloc_max": 10,
5133 "cloc_min": 0,
5134 "cloc_max": 3,
5135 "ploc_min": 3,
5136 "ploc_max": 6,
5137 "lloc_min": 1,
5138 "lloc_max": 3,
5139 "blank_min": 0,
5140 "blank_max": 1
5141 }
5142 "#
5143 );
5144 },
5145 );
5146 }
5147
5148 #[test]
5149 fn typescript_basic_loc() {
5150 check_metrics::<TypescriptParser>(
5151 "// Line comment
5152 /* Block
5153 comment */
5154 function greet(name: string): string {
5155 return `Hello, ${name}`;
5156 }
5157
5158 const add = (a: number, b: number): number => a + b;",
5159 "foo.ts",
5160 |metric| {
5161 insta::assert_json_snapshot!(
5162 metric.loc,
5163 @r#"
5164 {
5165 "sloc": 8,
5166 "ploc": 4,
5167 "lloc": 2,
5168 "cloc": 3,
5169 "blank": 1,
5170 "sloc_average": 2.6666666666666665,
5171 "ploc_average": 1.3333333333333333,
5172 "lloc_average": 0.6666666666666666,
5173 "cloc_average": 1.0,
5174 "blank_average": 0.3333333333333333,
5175 "sloc_min": 1,
5176 "sloc_max": 8,
5177 "cloc_min": 0,
5178 "cloc_max": 3,
5179 "ploc_min": 1,
5180 "ploc_max": 4,
5181 "lloc_min": 0,
5182 "lloc_max": 2,
5183 "blank_min": 0,
5184 "blank_max": 1
5185 }
5186 "#
5187 );
5188 },
5189 );
5190 }
5191
5192 #[test]
5193 fn csharp_comments() {
5194 check_metrics::<CsharpParser>(
5195 "for (int i = 0; i < 100; i++) {
5196 // Print hello
5197 System.Console.WriteLine(\"hello\");
5198 /// XML doc comment
5199 System.Console.WriteLine(\"hello\");
5200 }",
5201 "foo.cs",
5202 |metric| {
5203 assert_eq!(metric.loc.sloc(), 6);
5204 assert_eq!(metric.loc.ploc(), 4);
5205 assert_eq!(metric.loc.lloc(), 3);
5206 assert_eq!(metric.loc.cloc(), 2);
5207 assert_eq!(metric.loc.blank(), 0);
5208 insta::assert_json_snapshot!(metric.loc);
5209 },
5210 );
5211 }
5212
5213 #[test]
5214 fn csharp_blank() {
5215 check_metrics::<CsharpParser>(
5216 "int x = 1;
5217
5218
5219 int y = 2;",
5220 "foo.cs",
5221 |metric| {
5222 assert_eq!(metric.loc.sloc(), 4);
5223 assert_eq!(metric.loc.ploc(), 2);
5224 assert_eq!(metric.loc.lloc(), 2);
5225 assert_eq!(metric.loc.cloc(), 0);
5226 assert_eq!(metric.loc.blank(), 2);
5227 insta::assert_json_snapshot!(metric.loc);
5228 },
5229 );
5230 }
5231
5232 #[test]
5233 fn csharp_sloc() {
5234 check_metrics::<CsharpParser>(
5235 "for (int i = 0; i < 100; i++) {
5236 System.Console.WriteLine(i);
5237 }",
5238 "foo.cs",
5239 |metric| {
5240 assert_eq!(metric.loc.sloc(), 3);
5241 assert_eq!(metric.loc.ploc(), 3);
5242 assert_eq!(metric.loc.lloc(), 2);
5243 assert_eq!(metric.loc.cloc(), 0);
5244 assert_eq!(metric.loc.blank(), 0);
5245 insta::assert_json_snapshot!(metric.loc);
5246 },
5247 );
5248 }
5249
5250 #[test]
5251 fn csharp_module_sloc() {
5252 check_metrics::<CsharpParser>(
5253 "namespace HelloWorld {
5254 class Program { }
5255 }",
5256 "foo.cs",
5257 |metric| {
5258 assert_eq!(metric.loc.sloc(), 3);
5259 assert_eq!(metric.loc.ploc(), 3);
5260 assert_eq!(metric.loc.lloc(), 0);
5261 assert_eq!(metric.loc.cloc(), 0);
5262 assert_eq!(metric.loc.blank(), 0);
5263 insta::assert_json_snapshot!(metric.loc);
5264 },
5265 );
5266 }
5267
5268 #[test]
5269 fn csharp_single_ploc() {
5270 check_metrics::<CsharpParser>("int x = 1;", "foo.cs", |metric| {
5271 assert_eq!(metric.loc.sloc(), 1);
5272 assert_eq!(metric.loc.ploc(), 1);
5273 assert_eq!(metric.loc.lloc(), 1);
5274 assert_eq!(metric.loc.cloc(), 0);
5275 assert_eq!(metric.loc.blank(), 0);
5276 insta::assert_json_snapshot!(metric.loc);
5277 });
5278 }
5279
5280 #[test]
5281 fn csharp_simple_ploc() {
5282 check_metrics::<CsharpParser>(
5283 "for (int i = 0; i < 100; i++) {
5284 System.Console.WriteLine(i);
5285 }",
5286 "foo.cs",
5287 |metric| {
5288 assert_eq!(metric.loc.sloc(), 3);
5289 assert_eq!(metric.loc.ploc(), 3);
5290 assert_eq!(metric.loc.lloc(), 2);
5291 assert_eq!(metric.loc.cloc(), 0);
5292 assert_eq!(metric.loc.blank(), 0);
5293 insta::assert_json_snapshot!(metric.loc);
5294 },
5295 );
5296 }
5297
5298 #[test]
5299 fn csharp_multi_ploc() {
5300 check_metrics::<CsharpParser>(
5301 "int x = 1;
5302 for (int i = 0; i < 100; i++) {
5303 System.Console.WriteLine(i);
5304 }",
5305 "foo.cs",
5306 |metric| {
5307 assert_eq!(metric.loc.sloc(), 4);
5308 assert_eq!(metric.loc.ploc(), 4);
5309 assert_eq!(metric.loc.lloc(), 3);
5310 assert_eq!(metric.loc.cloc(), 0);
5311 assert_eq!(metric.loc.blank(), 0);
5312 insta::assert_json_snapshot!(metric.loc);
5313 },
5314 );
5315 }
5316
5317 #[test]
5318 fn csharp_single_statement_lloc() {
5319 check_metrics::<CsharpParser>("int max = 10;", "foo.cs", |metric| {
5320 assert_eq!(metric.loc.sloc(), 1);
5321 assert_eq!(metric.loc.ploc(), 1);
5322 assert_eq!(metric.loc.lloc(), 1);
5323 assert_eq!(metric.loc.cloc(), 0);
5324 assert_eq!(metric.loc.blank(), 0);
5325 insta::assert_json_snapshot!(metric.loc);
5326 });
5327 }
5328
5329 #[test]
5330 fn csharp_for_lloc() {
5331 check_metrics::<CsharpParser>(
5332 "for (int i = 0; i < 10; i++) {
5333 System.Console.WriteLine(i);
5334 }",
5335 "foo.cs",
5336 |metric| {
5337 assert_eq!(metric.loc.sloc(), 3);
5338 assert_eq!(metric.loc.ploc(), 3);
5339 assert_eq!(metric.loc.lloc(), 2);
5340 assert_eq!(metric.loc.cloc(), 0);
5341 assert_eq!(metric.loc.blank(), 0);
5342 insta::assert_json_snapshot!(metric.loc);
5343 },
5344 );
5345 }
5346
5347 #[test]
5348 fn csharp_foreach_lloc() {
5349 check_metrics::<CsharpParser>(
5350 "foreach (var item in items) {
5351 System.Console.WriteLine(item);
5352 }",
5353 "foo.cs",
5354 |metric| {
5355 assert_eq!(metric.loc.sloc(), 3);
5356 assert_eq!(metric.loc.ploc(), 3);
5357 assert_eq!(metric.loc.lloc(), 2);
5358 assert_eq!(metric.loc.cloc(), 0);
5359 assert_eq!(metric.loc.blank(), 0);
5360 insta::assert_json_snapshot!(metric.loc);
5361 },
5362 );
5363 }
5364
5365 #[test]
5366 fn csharp_while_lloc() {
5367 check_metrics::<CsharpParser>(
5368 "int i = 0;
5369 while (i < 10) {
5370 i++;
5371 }",
5372 "foo.cs",
5373 |metric| {
5374 assert_eq!(metric.loc.sloc(), 4);
5375 assert_eq!(metric.loc.ploc(), 4);
5376 assert_eq!(metric.loc.lloc(), 3);
5377 assert_eq!(metric.loc.cloc(), 0);
5378 assert_eq!(metric.loc.blank(), 0);
5379 insta::assert_json_snapshot!(metric.loc);
5380 },
5381 );
5382 }
5383
5384 #[test]
5385 fn csharp_do_while_lloc() {
5386 check_metrics::<CsharpParser>(
5387 "int i = 0;
5388 do {
5389 i++;
5390 } while (i < 10);",
5391 "foo.cs",
5392 |metric| {
5393 assert_eq!(metric.loc.sloc(), 4);
5394 assert_eq!(metric.loc.ploc(), 4);
5395 assert_eq!(metric.loc.lloc(), 3);
5396 assert_eq!(metric.loc.cloc(), 0);
5397 assert_eq!(metric.loc.blank(), 0);
5398 insta::assert_json_snapshot!(metric.loc);
5399 },
5400 );
5401 }
5402
5403 #[test]
5404 fn csharp_switch_lloc() {
5405 check_metrics::<CsharpParser>(
5406 "switch (x) {
5407 case 1: System.Console.WriteLine(1); break;
5408 case 2: System.Console.WriteLine(2); break;
5409 default: System.Console.WriteLine(0); break;
5410 }
5411 string s = x switch { 1 => \"one\", _ => \"other\" };",
5412 "foo.cs",
5413 |metric| {
5414 assert_eq!(metric.loc.sloc(), 6);
5415 assert_eq!(metric.loc.ploc(), 6);
5416 assert_eq!(metric.loc.lloc(), 8);
5417 assert_eq!(metric.loc.cloc(), 0);
5418 assert_eq!(metric.loc.blank(), 0);
5419 insta::assert_json_snapshot!(metric.loc);
5420 },
5421 );
5422 }
5423
5424 #[test]
5425 fn csharp_continue_lloc() {
5426 check_metrics::<CsharpParser>(
5427 "for (int i = 0; i < 10; i++) {
5428 if (i == 5) continue;
5429 System.Console.WriteLine(i);
5430 }",
5431 "foo.cs",
5432 |metric| {
5433 assert_eq!(metric.loc.sloc(), 4);
5434 assert_eq!(metric.loc.ploc(), 4);
5435 assert_eq!(metric.loc.lloc(), 4);
5436 assert_eq!(metric.loc.cloc(), 0);
5437 assert_eq!(metric.loc.blank(), 0);
5438 insta::assert_json_snapshot!(metric.loc);
5439 },
5440 );
5441 }
5442
5443 #[test]
5444 fn csharp_try_lloc() {
5445 check_metrics::<CsharpParser>(
5446 "try {
5447 System.Console.WriteLine(\"try\");
5448 } catch (System.Exception e) {
5449 throw new System.Exception(\"caught\");
5450 } finally {
5451 System.Console.WriteLine(\"done\");
5452 }",
5453 "foo.cs",
5454 |metric| {
5455 assert_eq!(metric.loc.sloc(), 7);
5456 assert_eq!(metric.loc.ploc(), 7);
5457 assert_eq!(metric.loc.lloc(), 4);
5458 assert_eq!(metric.loc.cloc(), 0);
5459 assert_eq!(metric.loc.blank(), 0);
5460 insta::assert_json_snapshot!(metric.loc);
5461 },
5462 );
5463 }
5464
5465 #[test]
5466 fn csharp_class_loc() {
5467 check_metrics::<CsharpParser>(
5468 "class A {
5469 int x;
5470 public void M() {
5471 System.Console.WriteLine(x);
5472 }
5473 }",
5474 "foo.cs",
5475 |metric| {
5476 assert_eq!(metric.loc.sloc(), 6);
5477 assert_eq!(metric.loc.ploc(), 6);
5478 assert_eq!(metric.loc.lloc(), 1);
5479 assert_eq!(metric.loc.cloc(), 0);
5480 assert_eq!(metric.loc.blank(), 0);
5481 insta::assert_json_snapshot!(metric.loc);
5482 },
5483 );
5484 }
5485
5486 #[test]
5487 fn csharp_expressions_lloc() {
5488 check_metrics::<CsharpParser>(
5489 "int a = 1;
5490 int b = 2;
5491 int c = a + b;
5492 System.Console.WriteLine(c);",
5493 "foo.cs",
5494 |metric| {
5495 assert_eq!(metric.loc.sloc(), 4);
5496 assert_eq!(metric.loc.ploc(), 4);
5497 assert_eq!(metric.loc.lloc(), 4);
5498 assert_eq!(metric.loc.cloc(), 0);
5499 assert_eq!(metric.loc.blank(), 0);
5500 insta::assert_json_snapshot!(metric.loc);
5501 },
5502 );
5503 }
5504
5505 #[test]
5506 fn csharp_statement_inline_loc() {
5507 check_metrics::<CsharpParser>(
5508 "if (x > 0) System.Console.WriteLine(x);",
5509 "foo.cs",
5510 |metric| {
5511 assert_eq!(metric.loc.sloc(), 1);
5512 assert_eq!(metric.loc.ploc(), 1);
5513 assert_eq!(metric.loc.lloc(), 2);
5514 assert_eq!(metric.loc.cloc(), 0);
5515 assert_eq!(metric.loc.blank(), 0);
5516 insta::assert_json_snapshot!(metric.loc);
5517 },
5518 );
5519 }
5520
5521 #[test]
5522 fn csharp_general_loc() {
5523 check_metrics::<CsharpParser>(
5524 "using System;
5525 namespace Demo {
5526 class A {
5527 public void M() {
5528 Console.WriteLine(\"hi\");
5529 }
5530 }
5531 class B {
5532 public int N() { return 0; }
5533 }
5534 }",
5535 "foo.cs",
5536 |metric| {
5537 assert_eq!(metric.loc.sloc(), 11);
5538 assert_eq!(metric.loc.ploc(), 11);
5539 assert_eq!(metric.loc.lloc(), 2);
5540 assert_eq!(metric.loc.cloc(), 0);
5541 assert_eq!(metric.loc.blank(), 0);
5542 insta::assert_json_snapshot!(metric.loc);
5543 },
5544 );
5545 }
5546
5547 #[test]
5548 fn csharp_using_lloc() {
5549 check_metrics::<CsharpParser>(
5554 "using System;
5555 using System.IO;
5556 class A {
5557 public void M() {
5558 using (var s = File.OpenRead(\"x\")) {
5559 Console.WriteLine(s);
5560 }
5561 using var t = File.OpenRead(\"y\");
5562 Console.WriteLine(t);
5563 }
5564 }",
5565 "foo.cs",
5566 |metric| {
5567 assert_eq!(metric.loc.sloc(), 11);
5568 assert_eq!(metric.loc.ploc(), 11);
5569 assert_eq!(metric.loc.lloc(), 4);
5570 assert_eq!(metric.loc.cloc(), 0);
5571 assert_eq!(metric.loc.blank(), 0);
5572 insta::assert_json_snapshot!(metric.loc);
5573 },
5574 );
5575 }
5576
5577 #[test]
5578 fn kotlin_loc_basic() {
5579 check_metrics::<KotlinParser>(
5580 "// A simple function
5581 fun greet(name: String): String {
5582 val greeting = \"Hello, \" + name
5583 if (name.isEmpty()) {
5584 return \"Hello, World!\"
5585 }
5586 return greeting
5587 }",
5588 "foo.kt",
5589 |metric| {
5590 insta::assert_json_snapshot!(
5591 metric.loc,
5592 @r#"
5593 {
5594 "sloc": 8,
5595 "ploc": 7,
5596 "lloc": 4,
5597 "cloc": 1,
5598 "blank": 0,
5599 "sloc_average": 4.0,
5600 "ploc_average": 3.5,
5601 "lloc_average": 2.0,
5602 "cloc_average": 0.5,
5603 "blank_average": 0.0,
5604 "sloc_min": 7,
5605 "sloc_max": 8,
5606 "cloc_min": 0,
5607 "cloc_max": 1,
5608 "ploc_min": 7,
5609 "ploc_max": 7,
5610 "lloc_min": 4,
5611 "lloc_max": 4,
5612 "blank_min": 0,
5613 "blank_max": 0
5614 }
5615 "#
5616 );
5617 },
5618 );
5619 }
5620
5621 #[test]
5622 fn kotlin_loc_bare_expression() {
5623 check_metrics::<KotlinParser>(
5624 "fun main() {
5625 val x = 42
5626 println(x)
5627 listOf(1, 2, 3).forEach { println(it) }
5628 }",
5629 "foo.kt",
5630 |metric| {
5631 insta::assert_json_snapshot!(
5635 metric.loc,
5636 @r#"
5637 {
5638 "sloc": 5,
5639 "ploc": 5,
5640 "lloc": 3,
5641 "cloc": 0,
5642 "blank": 0,
5643 "sloc_average": 2.5,
5644 "ploc_average": 2.5,
5645 "lloc_average": 1.5,
5646 "cloc_average": 0.0,
5647 "blank_average": 0.0,
5648 "sloc_min": 5,
5649 "sloc_max": 5,
5650 "cloc_min": 0,
5651 "cloc_max": 0,
5652 "ploc_min": 5,
5653 "ploc_max": 5,
5654 "lloc_min": 3,
5655 "lloc_max": 3,
5656 "blank_min": 0,
5657 "blank_max": 0
5658 }
5659 "#
5660 );
5661 },
5662 );
5663 }
5664
5665 #[test]
5666 fn bash_loc() {
5667 check_metrics::<BashParser>(
5668 "#!/bin/bash
5669# This is a comment
5670f() {
5671 echo 'hello'
5672}
5673
5674# Another comment
5675f",
5676 "foo.sh",
5677 |metric| {
5678 assert_eq!(metric.loc.sloc(), 8);
5679 assert_eq!(metric.loc.ploc(), 4);
5680 assert_eq!(metric.loc.lloc(), 3);
5681 assert_eq!(metric.loc.cloc(), 3);
5682 assert_eq!(metric.loc.blank(), 1);
5683 insta::assert_json_snapshot!(metric.loc);
5684 },
5685 );
5686 }
5687
5688 #[test]
5692 fn python_cloc_crlf_matches_lf() {
5693 check_metrics::<PythonParser>("# comment\nx = 1", "foo.py", |m| {
5694 assert_eq!(m.loc.cloc(), 1);
5695 assert_eq!(m.loc.ploc(), 1);
5696 assert_eq!(m.loc.sloc(), 2);
5697 assert_eq!(m.loc.blank(), 0);
5698 });
5699 check_metrics::<PythonParser>("# comment\r\nx = 1", "foo.py", |m| {
5700 assert_eq!(m.loc.cloc(), 1);
5701 assert_eq!(m.loc.ploc(), 1);
5702 assert_eq!(m.loc.sloc(), 2);
5703 assert_eq!(m.loc.blank(), 0);
5704 });
5705 check_metrics::<PythonParser>("# comment\rx = 1", "foo.py", |m| {
5709 assert_eq!(m.loc.cloc(), 1);
5710 assert_eq!(m.loc.ploc(), 1);
5711 assert_eq!(m.loc.sloc(), 2);
5712 assert_eq!(m.loc.blank(), 0);
5713 });
5714 }
5715
5716 #[test]
5717 fn python_blank_crlf_matches_lf() {
5718 check_metrics::<PythonParser>("# comment\n\nx = 1", "foo.py", |m| {
5719 assert_eq!(m.loc.blank(), 1);
5720 });
5721 check_metrics::<PythonParser>("# comment\r\n\r\nx = 1", "foo.py", |m| {
5722 assert_eq!(m.loc.blank(), 1);
5723 });
5724 check_metrics::<PythonParser>("# comment\r\rx = 1", "foo.py", |m| {
5726 assert_eq!(m.loc.blank(), 1);
5727 });
5728 }
5729
5730 #[test]
5731 fn rust_cloc_crlf_matches_lf() {
5732 check_metrics::<RustParser>(
5733 "fn f() {\n // comment\n let x = 1;\n}",
5734 "foo.rs",
5735 |m| {
5736 assert_eq!(m.loc.cloc(), 1);
5737 assert_eq!(m.loc.sloc(), 4);
5738 },
5739 );
5740 check_metrics::<RustParser>(
5741 "fn f() {\r\n // comment\r\n let x = 1;\r\n}",
5742 "foo.rs",
5743 |m| {
5744 assert_eq!(m.loc.cloc(), 1);
5745 assert_eq!(m.loc.sloc(), 4);
5746 },
5747 );
5748 check_metrics::<RustParser>(
5751 "fn f() {\r // comment\r let x = 1;\r}",
5752 "foo.rs",
5753 |m| {
5754 assert_eq!(m.loc.cloc(), 1);
5755 assert_eq!(m.loc.sloc(), 4);
5756 },
5757 );
5758 }
5759
5760 #[test]
5761 fn tcl_blank() {
5762 check_metrics::<TclParser>("set x 1\n\nset y 2", "foo.tcl", |metric| {
5763 assert_eq!(metric.loc.sloc(), 3);
5764 assert_eq!(metric.loc.ploc(), 2);
5765 assert_eq!(metric.loc.lloc(), 2);
5766 assert_eq!(metric.loc.cloc(), 0);
5767 assert_eq!(metric.loc.blank(), 1);
5768 insta::assert_json_snapshot!(metric.loc);
5769 });
5770 }
5771
5772 #[test]
5773 fn tcl_no_zero_blank() {
5774 check_metrics::<TclParser>(
5778 "set a 1\nset b 2\n\nset c 3 ;# trailing\nset d 4 ;# trailing\nset e 5",
5779 "foo.tcl",
5780 |metric| {
5781 assert_eq!(metric.loc.sloc(), 6);
5782 assert_eq!(metric.loc.ploc(), 5);
5783 assert_eq!(metric.loc.cloc(), 2);
5784 assert_eq!(metric.loc.blank(), 1);
5785 },
5786 );
5787 }
5788
5789 #[test]
5795 fn tcl_cloc() {
5796 check_metrics::<TclParser>("# This is a comment\nset x 1", "foo.tcl", |metric| {
5797 assert_eq!(metric.loc.sloc(), 2);
5798 assert_eq!(metric.loc.ploc(), 1);
5799 assert_eq!(metric.loc.lloc(), 1);
5800 assert_eq!(metric.loc.cloc(), 1);
5801 assert_eq!(metric.loc.blank(), 0);
5802 insta::assert_json_snapshot!(metric.loc);
5803 });
5804 }
5805
5806 #[test]
5807 fn tcl_lloc() {
5808 check_metrics::<TclParser>(
5809 "proc f {x} {
5810 while {$x > 0} {
5811 if {$x > 10} {
5812 set x [expr {$x - 1}]
5813 }
5814 }
5815}",
5816 "foo.tcl",
5817 |metric| {
5818 assert_eq!(metric.loc.sloc(), 7);
5819 assert_eq!(metric.loc.ploc(), 7);
5820 assert_eq!(metric.loc.lloc(), 4);
5821 assert_eq!(metric.loc.cloc(), 0);
5822 assert_eq!(metric.loc.blank(), 0);
5823 insta::assert_json_snapshot!(metric.loc);
5824 },
5825 );
5826 }
5827
5828 #[test]
5829 fn tcl_no_command_substitution_lloc() {
5830 check_metrics::<TclParser>("puts [string toupper x]", "foo.tcl", |metric| {
5832 assert_eq!(metric.loc.sloc(), 1);
5833 assert_eq!(metric.loc.ploc(), 1);
5834 assert_eq!(metric.loc.lloc(), 1);
5835 assert_eq!(metric.loc.cloc(), 0);
5836 assert_eq!(metric.loc.blank(), 0);
5837 insta::assert_json_snapshot!(metric.loc);
5838 });
5839 }
5840
5841 #[test]
5842 fn tcl_procedure_lloc() {
5843 check_metrics::<TclParser>("proc foo {} {\n puts hello\n}", "foo.tcl", |metric| {
5844 assert_eq!(metric.loc.sloc(), 3);
5845 assert_eq!(metric.loc.ploc(), 3);
5846 assert_eq!(metric.loc.lloc(), 2);
5847 assert_eq!(metric.loc.cloc(), 0);
5848 assert_eq!(metric.loc.blank(), 0);
5849 insta::assert_json_snapshot!(metric.loc);
5850 });
5851 }
5852
5853 #[test]
5854 fn tcl_if_lloc() {
5855 check_metrics::<TclParser>("if {1} {\n puts hello\n}", "foo.tcl", |metric| {
5856 assert_eq!(metric.loc.sloc(), 3);
5857 assert_eq!(metric.loc.ploc(), 3);
5858 assert_eq!(metric.loc.lloc(), 2);
5859 assert_eq!(metric.loc.cloc(), 0);
5860 assert_eq!(metric.loc.blank(), 0);
5861 insta::assert_json_snapshot!(metric.loc);
5862 });
5863 }
5864
5865 #[test]
5866 fn tcl_elseif_lloc() {
5867 check_metrics::<TclParser>(
5869 "if {$x > 10} {
5870 puts big
5871} elseif {$x > 5} {
5872 puts medium
5873} else {
5874 puts small
5875}",
5876 "foo.tcl",
5877 |metric| {
5878 assert_eq!(metric.loc.sloc(), 7);
5879 assert_eq!(metric.loc.ploc(), 7);
5880 assert_eq!(metric.loc.lloc(), 5);
5881 assert_eq!(metric.loc.cloc(), 0);
5882 assert_eq!(metric.loc.blank(), 0);
5883 insta::assert_json_snapshot!(metric.loc);
5884 },
5885 );
5886 }
5887
5888 #[test]
5889 fn tcl_while_lloc() {
5890 check_metrics::<TclParser>(
5891 "while {$x > 0} {\n set x [expr {$x - 1}]\n}",
5892 "foo.tcl",
5893 |metric| {
5894 assert_eq!(metric.loc.sloc(), 3);
5895 assert_eq!(metric.loc.ploc(), 3);
5896 assert_eq!(metric.loc.lloc(), 2);
5897 assert_eq!(metric.loc.cloc(), 0);
5898 assert_eq!(metric.loc.blank(), 0);
5899 insta::assert_json_snapshot!(metric.loc);
5900 },
5901 );
5902 }
5903
5904 #[test]
5905 fn tcl_foreach_lloc() {
5906 check_metrics::<TclParser>(
5907 "foreach item {a b c} {\n puts $item\n}",
5908 "foo.tcl",
5909 |metric| {
5910 assert_eq!(metric.loc.sloc(), 3);
5911 assert_eq!(metric.loc.ploc(), 3);
5912 assert_eq!(metric.loc.lloc(), 2);
5913 assert_eq!(metric.loc.cloc(), 0);
5914 assert_eq!(metric.loc.blank(), 0);
5915 insta::assert_json_snapshot!(metric.loc);
5916 },
5917 );
5918 }
5919
5920 #[test]
5921 fn tcl_set_lloc() {
5922 check_metrics::<TclParser>("set x 42", "foo.tcl", |metric| {
5923 assert_eq!(metric.loc.sloc(), 1);
5924 assert_eq!(metric.loc.ploc(), 1);
5925 assert_eq!(metric.loc.lloc(), 1);
5926 assert_eq!(metric.loc.cloc(), 0);
5927 assert_eq!(metric.loc.blank(), 0);
5928 insta::assert_json_snapshot!(metric.loc);
5929 });
5930 }
5931
5932 #[test]
5933 fn tcl_global_lloc() {
5934 check_metrics::<TclParser>("global x", "foo.tcl", |metric| {
5935 assert_eq!(metric.loc.sloc(), 1);
5936 assert_eq!(metric.loc.ploc(), 1);
5937 assert_eq!(metric.loc.lloc(), 1);
5938 assert_eq!(metric.loc.cloc(), 0);
5939 assert_eq!(metric.loc.blank(), 0);
5940 insta::assert_json_snapshot!(metric.loc);
5941 });
5942 }
5943
5944 #[test]
5945 fn tcl_try_catch_lloc() {
5946 check_metrics::<TclParser>(
5948 "catch {
5949 set x 1
5950} result
5951try {
5952 set y 2
5953} on error {msg} {
5954 puts $msg
5955}",
5956 "foo.tcl",
5957 |metric| {
5958 assert_eq!(metric.loc.sloc(), 8);
5959 assert_eq!(metric.loc.ploc(), 8);
5960 assert_eq!(metric.loc.lloc(), 5);
5961 assert_eq!(metric.loc.cloc(), 0);
5962 assert_eq!(metric.loc.blank(), 0);
5963 insta::assert_json_snapshot!(metric.loc);
5964 },
5965 );
5966 }
5967
5968 #[test]
5969 fn tcl_namespace_lloc() {
5970 check_metrics::<TclParser>(
5971 "namespace eval myns {\n set x 1\n}",
5972 "foo.tcl",
5973 |metric| {
5974 assert_eq!(metric.loc.sloc(), 3);
5975 assert_eq!(metric.loc.ploc(), 3);
5976 assert_eq!(metric.loc.lloc(), 2);
5977 assert_eq!(metric.loc.cloc(), 0);
5978 assert_eq!(metric.loc.blank(), 0);
5979 insta::assert_json_snapshot!(metric.loc);
5980 },
5981 );
5982 }
5983
5984 #[test]
5985 fn tcl_regexp_lloc() {
5986 check_metrics::<TclParser>("regexp {^[0-9]+$} $x", "foo.tcl", |metric| {
5987 assert_eq!(metric.loc.sloc(), 1);
5988 assert_eq!(metric.loc.ploc(), 1);
5989 assert_eq!(metric.loc.lloc(), 1);
5990 assert_eq!(metric.loc.cloc(), 0);
5991 assert_eq!(metric.loc.blank(), 0);
5992 insta::assert_json_snapshot!(metric.loc);
5993 });
5994 }
5995
5996 #[test]
5997 fn tcl_expr_cmd_lloc() {
5998 check_metrics::<TclParser>("expr {1 + 2}", "foo.tcl", |metric| {
5999 assert_eq!(metric.loc.sloc(), 1);
6000 assert_eq!(metric.loc.ploc(), 1);
6001 assert_eq!(metric.loc.lloc(), 1);
6002 assert_eq!(metric.loc.cloc(), 0);
6003 assert_eq!(metric.loc.blank(), 0);
6004 insta::assert_json_snapshot!(metric.loc);
6005 });
6006 }
6007
6008 #[test]
6009 fn tcl_no_expr_cmd_substitution_lloc() {
6010 check_metrics::<TclParser>("set x [expr {1 + 2}]", "foo.tcl", |metric| {
6012 assert_eq!(metric.loc.sloc(), 1);
6013 assert_eq!(metric.loc.ploc(), 1);
6014 assert_eq!(metric.loc.lloc(), 1);
6015 assert_eq!(metric.loc.cloc(), 0);
6016 assert_eq!(metric.loc.blank(), 0);
6017 insta::assert_json_snapshot!(metric.loc);
6018 });
6019 }
6020
6021 #[test]
6022 fn tcl_nested_commands_lloc() {
6023 check_metrics::<TclParser>(
6025 "proc f {x} {
6026 set y [expr {$x * 2}]
6027 puts $y
6028}",
6029 "foo.tcl",
6030 |metric| {
6031 assert_eq!(metric.loc.sloc(), 4);
6032 assert_eq!(metric.loc.ploc(), 4);
6033 assert_eq!(metric.loc.lloc(), 3);
6034 assert_eq!(metric.loc.cloc(), 0);
6035 assert_eq!(metric.loc.blank(), 0);
6036 insta::assert_json_snapshot!(metric.loc);
6037 },
6038 );
6039 }
6040
6041 #[test]
6042 fn tcl_command_lloc() {
6043 check_metrics::<TclParser>("puts hello", "foo.tcl", |metric| {
6044 assert_eq!(metric.loc.sloc(), 1);
6045 assert_eq!(metric.loc.ploc(), 1);
6046 assert_eq!(metric.loc.lloc(), 1);
6047 assert_eq!(metric.loc.cloc(), 0);
6048 assert_eq!(metric.loc.blank(), 0);
6049 insta::assert_json_snapshot!(metric.loc);
6050 });
6051 }
6052
6053 #[test]
6054 fn tcl_no_else_lloc() {
6055 check_metrics::<TclParser>(
6057 "if {1} {\n puts yes\n} else {\n puts no\n}",
6058 "foo.tcl",
6059 |metric| {
6060 assert_eq!(metric.loc.sloc(), 5);
6061 assert_eq!(metric.loc.ploc(), 5);
6062 assert_eq!(metric.loc.lloc(), 3);
6063 assert_eq!(metric.loc.cloc(), 0);
6064 assert_eq!(metric.loc.blank(), 0);
6065 insta::assert_json_snapshot!(metric.loc);
6066 },
6067 );
6068 }
6069
6070 #[test]
6071 fn tcl_no_finally_lloc() {
6072 check_metrics::<TclParser>(
6075 "proc f {} {\n try {\n puts hi\n } finally {\n puts done\n }\n}",
6076 "foo.tcl",
6077 |metric| {
6078 assert_eq!(
6079 metric.loc.lloc(),
6080 4,
6081 "finally adds 0 lloc; would be 5 if finally counted"
6082 );
6083 },
6084 );
6085 }
6086
6087 #[test]
6088 fn tcl_multiline_block() {
6089 check_metrics::<TclParser>(
6090 "proc f {x} {
6091 set a 1
6092
6093 set b 2
6094 return [expr {$a + $b}]
6095}",
6096 "foo.tcl",
6097 |metric| {
6098 assert_eq!(metric.loc.sloc(), 6);
6099 assert_eq!(metric.loc.ploc(), 5);
6100 assert_eq!(metric.loc.lloc(), 4);
6101 assert_eq!(metric.loc.cloc(), 0);
6102 assert_eq!(metric.loc.blank(), 1);
6103 insta::assert_json_snapshot!(metric.loc);
6104 },
6105 );
6106 }
6107
6108 #[test]
6109 fn tcl_no_string_lloc() {
6110 check_metrics::<TclParser>(
6115 "set s \"line one\nline two\nline three\"",
6116 "foo.tcl",
6117 |metric| {
6118 assert_eq!(metric.loc.sloc(), 3);
6119 assert_eq!(metric.loc.ploc(), 2);
6120 assert_eq!(metric.loc.lloc(), 1);
6121 assert_eq!(metric.loc.cloc(), 0);
6122 assert_eq!(metric.loc.blank(), 1);
6123 insta::assert_json_snapshot!(metric.loc);
6124 },
6125 );
6126 }
6127
6128 #[test]
6129 fn javascript_blank() {
6130 check_metrics::<JavascriptParser>(
6131 "// header comment
6132 function f() {
6133
6134 var x = 1;
6135
6136 var y = 2;
6137 }",
6138 "foo.js",
6139 |metric| {
6140 assert_eq!(metric.loc.sloc(), 7);
6141 assert_eq!(metric.loc.ploc(), 4);
6142 assert_eq!(metric.loc.lloc(), 2);
6143 assert_eq!(metric.loc.cloc(), 1);
6144 assert_eq!(metric.loc.blank(), 2);
6145 insta::assert_json_snapshot!(metric.loc);
6146 },
6147 );
6148 }
6149
6150 #[test]
6151 fn javascript_cloc() {
6152 check_metrics::<JavascriptParser>(
6153 "// line comment
6154 /* block
6155 comment */
6156 function f() {
6157 return 1; // inline
6158 }",
6159 "foo.js",
6160 |metric| {
6161 assert_eq!(metric.loc.sloc(), 6);
6162 assert_eq!(metric.loc.ploc(), 3);
6163 assert_eq!(metric.loc.lloc(), 1);
6164 assert_eq!(metric.loc.cloc(), 4);
6165 assert_eq!(metric.loc.blank(), 0);
6166 insta::assert_json_snapshot!(metric.loc);
6167 },
6168 );
6169 }
6170
6171 #[test]
6172 fn javascript_cloc_html_comment() {
6173 check_metrics::<JavascriptParser>(
6177 "<!-- header comment -->
6178function f() {
6179 return 1;
6180}",
6181 "foo.js",
6182 |metric| {
6183 assert_eq!(metric.loc.sloc(), 4);
6184 assert_eq!(metric.loc.ploc(), 3);
6185 assert_eq!(metric.loc.lloc(), 1);
6186 assert_eq!(metric.loc.cloc(), 1);
6187 assert_eq!(metric.loc.blank(), 0);
6188 },
6189 );
6190 }
6191
6192 #[test]
6193 fn mozjs_blank() {
6194 check_metrics::<MozjsParser>(
6195 "function f() {
6196
6197 var x = 1;
6198
6199 }",
6200 "foo.js",
6201 |metric| {
6202 assert_eq!(metric.loc.sloc(), 5);
6203 assert_eq!(metric.loc.ploc(), 3);
6204 assert_eq!(metric.loc.lloc(), 1);
6205 assert_eq!(metric.loc.cloc(), 0);
6206 assert_eq!(metric.loc.blank(), 2);
6207 insta::assert_json_snapshot!(metric.loc);
6208 },
6209 );
6210 }
6211
6212 #[test]
6213 fn mozjs_cloc() {
6214 check_metrics::<MozjsParser>(
6215 "// header
6216 /* block comment */
6217 function f() {
6218 return 42;
6219 }",
6220 "foo.js",
6221 |metric| {
6222 assert_eq!(metric.loc.sloc(), 5);
6223 assert_eq!(metric.loc.ploc(), 3);
6224 assert_eq!(metric.loc.lloc(), 1);
6225 assert_eq!(metric.loc.cloc(), 2);
6226 assert_eq!(metric.loc.blank(), 0);
6227 insta::assert_json_snapshot!(metric.loc);
6228 },
6229 );
6230 }
6231
6232 #[test]
6233 fn mozjs_no_zero_blank() {
6234 check_metrics::<MozjsParser>(
6237 "function f() {
6238 var a = 1;
6239
6240 var b = 2; // trailing
6241 var c = 3; // trailing
6242}",
6243 "foo.js",
6244 |metric| {
6245 assert_eq!(metric.loc.sloc(), 6);
6246 assert_eq!(metric.loc.ploc(), 5);
6247 assert_eq!(metric.loc.cloc(), 2);
6248 assert_eq!(metric.loc.blank(), 1);
6249 insta::assert_json_snapshot!(metric.loc);
6250 },
6251 );
6252 }
6253
6254 #[test]
6255 fn mozjs_arrow_function_loc() {
6256 check_metrics::<MozjsParser>(
6257 "const add = (a, b) => a + b;
6258 const greet = name => {
6259 return 'Hello ' + name;
6260 };",
6261 "foo.js",
6262 |metric| {
6263 assert_eq!(metric.loc.sloc(), 4);
6264 assert_eq!(metric.loc.ploc(), 4);
6265 assert_eq!(metric.loc.lloc(), 3);
6266 assert_eq!(metric.loc.cloc(), 0);
6267 assert_eq!(metric.loc.blank(), 0);
6268 insta::assert_json_snapshot!(metric.loc);
6269 },
6270 );
6271 }
6272
6273 #[test]
6274 fn mozjs_multiple_functions_loc() {
6275 check_metrics::<MozjsParser>(
6276 "function f() {
6277 return 1;
6278 }
6279 function g() {
6280 return 2;
6281 }",
6282 "foo.js",
6283 |metric| {
6284 assert_eq!(metric.loc.sloc(), 6);
6285 assert_eq!(metric.loc.ploc(), 6);
6286 assert_eq!(metric.loc.lloc(), 2);
6287 assert_eq!(metric.loc.cloc(), 0);
6288 assert_eq!(metric.loc.blank(), 0);
6289 insta::assert_json_snapshot!(metric.loc);
6290 },
6291 );
6292 }
6293
6294 #[test]
6295 fn mozjs_nested_function_loc() {
6296 check_metrics::<MozjsParser>(
6297 "function outer() {
6298 function inner() {
6299 return 1;
6300 }
6301 return inner();
6302 }",
6303 "foo.js",
6304 |metric| {
6305 assert_eq!(metric.loc.sloc(), 6);
6306 assert_eq!(metric.loc.ploc(), 6);
6307 assert_eq!(metric.loc.lloc(), 2);
6308 assert_eq!(metric.loc.cloc(), 0);
6309 assert_eq!(metric.loc.blank(), 0);
6310 insta::assert_json_snapshot!(metric.loc);
6311 },
6312 );
6313 }
6314
6315 #[test]
6316 fn mozjs_if_lloc() {
6317 check_metrics::<MozjsParser>(
6318 "function f(x) {
6319 if (x > 0) {
6320 return 1;
6321 } else {
6322 return -1;
6323 }
6324 }",
6325 "foo.js",
6326 |metric| {
6327 assert_eq!(metric.loc.sloc(), 7);
6328 assert_eq!(metric.loc.ploc(), 7);
6329 assert_eq!(metric.loc.lloc(), 3);
6336 assert_eq!(metric.loc.cloc(), 0);
6337 assert_eq!(metric.loc.blank(), 0);
6338 insta::assert_json_snapshot!(metric.loc);
6339 },
6340 );
6341 }
6342
6343 #[test]
6350 fn js_family_if_lloc_matches_c_and_rust() {
6351 const JS_SRC: &str = "function f(x) {
6352 if (x > 0) {
6353 return 1;
6354 } else {
6355 return -1;
6356 }
6357 }";
6358 const C_SRC: &str = "int f(int x) {
6359 if (x > 0) {
6360 return 1;
6361 } else {
6362 return -1;
6363 }
6364 }";
6365 const RUST_SRC: &str = "fn f(x: i32) -> i32 {
6366 if x > 0 {
6367 return 1;
6368 } else {
6369 return -1;
6370 }
6371 }";
6372
6373 const EXPECTED_LLOC: usize = 3;
6376
6377 check_metrics::<CppParser>(C_SRC, "f.c", |m| {
6378 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6379 });
6380 check_metrics::<RustParser>(RUST_SRC, "f.rs", |m| {
6381 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6382 });
6383 check_metrics::<MozjsParser>(JS_SRC, "f.js", |m| {
6384 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6385 });
6386 check_metrics::<JavascriptParser>(JS_SRC, "f.js", |m| {
6387 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6388 });
6389 check_metrics::<TypescriptParser>(JS_SRC, "f.ts", |m| {
6390 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6391 });
6392 check_metrics::<TsxParser>(JS_SRC, "f.tsx", |m| {
6393 assert_eq!(m.loc.lloc() as usize, EXPECTED_LLOC);
6394 });
6395 }
6396
6397 #[test]
6398 fn mozjs_for_lloc() {
6399 check_metrics::<MozjsParser>(
6400 "function f(n) {
6401 var s = 0;
6402 for (var i = 0; i < n; i++) {
6403 s += i;
6404 }
6405 return s;
6406 }",
6407 "foo.js",
6408 |metric| {
6409 assert_eq!(metric.loc.sloc(), 7);
6410 assert_eq!(metric.loc.ploc(), 7);
6411 assert_eq!(metric.loc.lloc(), 4);
6412 assert_eq!(metric.loc.cloc(), 0);
6413 assert_eq!(metric.loc.blank(), 0);
6414 insta::assert_json_snapshot!(metric.loc);
6415 },
6416 );
6417 }
6418
6419 #[test]
6420 fn bash_blank() {
6421 check_metrics::<BashParser>(
6422 "#!/bin/bash
6423
6424 f() {
6425
6426 echo hello
6427
6428 }",
6429 "foo.sh",
6430 |metric| {
6431 assert_eq!(metric.loc.sloc(), 7);
6432 assert_eq!(metric.loc.ploc(), 3);
6433 assert_eq!(metric.loc.lloc(), 2);
6434 assert_eq!(metric.loc.cloc(), 1);
6435 assert_eq!(metric.loc.blank(), 3);
6436 insta::assert_json_snapshot!(metric.loc);
6437 },
6438 );
6439 }
6440
6441 #[test]
6442 fn bash_cloc() {
6443 check_metrics::<BashParser>(
6444 "# header comment
6445 f() {
6446 # body comment
6447 echo hello
6448 }",
6449 "foo.sh",
6450 |metric| {
6451 assert_eq!(metric.loc.sloc(), 5);
6452 assert_eq!(metric.loc.ploc(), 3);
6453 assert_eq!(metric.loc.lloc(), 2);
6454 assert_eq!(metric.loc.cloc(), 2);
6455 assert_eq!(metric.loc.blank(), 0);
6456 insta::assert_json_snapshot!(metric.loc);
6457 },
6458 );
6459 }
6460
6461 #[test]
6462 fn bash_no_zero_blank() {
6463 check_metrics::<BashParser>(
6466 "f() {
6467 echo a
6468
6469 echo b # trailing
6470 echo c # trailing
6471}",
6472 "foo.sh",
6473 |metric| {
6474 assert_eq!(metric.loc.sloc(), 6);
6475 assert_eq!(metric.loc.ploc(), 5);
6476 assert_eq!(metric.loc.cloc(), 2);
6477 assert_eq!(metric.loc.blank(), 1);
6478 insta::assert_json_snapshot!(metric.loc);
6479 },
6480 );
6481 }
6482
6483 #[test]
6484 fn bash_comment_before_code_line_reclassified() {
6485 check_metrics::<BashParser>("echo a\n\necho \"$(\n # c\n)\"\n", "foo.sh", |metric| {
6503 assert_eq!(metric.loc.sloc(), 5);
6504 assert_eq!(metric.loc.ploc(), 4);
6505 assert_eq!(metric.loc.lloc(), 3);
6506 assert_eq!(metric.loc.cloc(), 1);
6507 assert_eq!(metric.loc.blank(), 1);
6508 insta::assert_json_snapshot!(
6509 metric.loc,
6510 @r#"
6511 {
6512 "sloc": 5,
6513 "ploc": 4,
6514 "lloc": 3,
6515 "cloc": 1,
6516 "blank": 1,
6517 "sloc_average": 5.0,
6518 "ploc_average": 4.0,
6519 "lloc_average": 3.0,
6520 "cloc_average": 1.0,
6521 "blank_average": 1.0,
6522 "sloc_min": 5,
6523 "sloc_max": 5,
6524 "cloc_min": 1,
6525 "cloc_max": 1,
6526 "ploc_min": 4,
6527 "ploc_max": 4,
6528 "lloc_min": 3,
6529 "lloc_max": 3,
6530 "blank_min": 1,
6531 "blank_max": 1
6532 }
6533 "#
6534 );
6535 });
6536 }
6537
6538 #[test]
6539 fn bash_if_lloc() {
6540 check_metrics::<BashParser>(
6541 "f() {
6542 if [ $1 -gt 0 ]; then
6543 echo positive
6544 else
6545 echo negative
6546 fi
6547 }",
6548 "foo.sh",
6549 |metric| {
6550 assert_eq!(metric.loc.sloc(), 7);
6551 assert_eq!(metric.loc.ploc(), 7);
6552 assert_eq!(metric.loc.lloc(), 4);
6553 assert_eq!(metric.loc.cloc(), 0);
6554 assert_eq!(metric.loc.blank(), 0);
6555 insta::assert_json_snapshot!(metric.loc);
6556 },
6557 );
6558 }
6559
6560 #[test]
6561 fn bash_for_lloc() {
6562 check_metrics::<BashParser>(
6563 "f() {
6564 for i in 1 2 3; do
6565 echo $i
6566 done
6567 }",
6568 "foo.sh",
6569 |metric| {
6570 assert_eq!(metric.loc.sloc(), 5);
6571 assert_eq!(metric.loc.ploc(), 5);
6572 assert_eq!(metric.loc.lloc(), 3);
6573 assert_eq!(metric.loc.cloc(), 0);
6574 assert_eq!(metric.loc.blank(), 0);
6575 insta::assert_json_snapshot!(metric.loc);
6576 },
6577 );
6578 }
6579
6580 #[test]
6581 fn bash_while_lloc() {
6582 check_metrics::<BashParser>(
6583 "f() {
6584 local n=5
6585 while [ $n -gt 0 ]; do
6586 echo $n
6587 n=$((n - 1))
6588 done
6589 }",
6590 "foo.sh",
6591 |metric| {
6592 assert_eq!(metric.loc.sloc(), 7);
6593 assert_eq!(metric.loc.ploc(), 7);
6594 assert_eq!(metric.loc.lloc(), 4);
6595 assert_eq!(metric.loc.cloc(), 0);
6596 assert_eq!(metric.loc.blank(), 0);
6597 insta::assert_json_snapshot!(metric.loc);
6598 },
6599 );
6600 }
6601
6602 #[test]
6603 fn bash_case_lloc() {
6604 check_metrics::<BashParser>(
6605 "f() {
6606 case $1 in
6607 start) echo starting ;;
6608 stop) echo stopping ;;
6609 *) echo unknown ;;
6610 esac
6611 }",
6612 "foo.sh",
6613 |metric| {
6614 assert_eq!(metric.loc.sloc(), 7);
6615 assert_eq!(metric.loc.ploc(), 7);
6616 assert_eq!(metric.loc.lloc(), 5);
6617 assert_eq!(metric.loc.cloc(), 0);
6618 assert_eq!(metric.loc.blank(), 0);
6619 insta::assert_json_snapshot!(metric.loc);
6620 },
6621 );
6622 }
6623
6624 #[test]
6625 fn bash_multiple_functions_loc() {
6626 check_metrics::<BashParser>(
6627 "f() {
6628 echo hello
6629 }
6630 g() {
6631 echo world
6632 }",
6633 "foo.sh",
6634 |metric| {
6635 assert_eq!(metric.loc.sloc(), 6);
6636 assert_eq!(metric.loc.ploc(), 6);
6637 assert_eq!(metric.loc.lloc(), 4);
6638 assert_eq!(metric.loc.cloc(), 0);
6639 assert_eq!(metric.loc.blank(), 0);
6640 insta::assert_json_snapshot!(metric.loc);
6641 },
6642 );
6643 }
6644
6645 #[test]
6646 fn bash_nested_function_loc() {
6647 check_metrics::<BashParser>(
6648 "outer() {
6649 inner() {
6650 echo inner
6651 }
6652 inner
6653 echo outer
6654 }",
6655 "foo.sh",
6656 |metric| {
6657 assert_eq!(metric.loc.sloc(), 7);
6658 assert_eq!(metric.loc.ploc(), 7);
6659 assert_eq!(metric.loc.lloc(), 5);
6660 assert_eq!(metric.loc.cloc(), 0);
6661 assert_eq!(metric.loc.blank(), 0);
6662 insta::assert_json_snapshot!(metric.loc);
6663 },
6664 );
6665 }
6666
6667 #[test]
6668 fn bash_heredoc_loc() {
6669 check_metrics::<BashParser>(
6670 "f() {
6671 cat <<EOF
6672line1
6673line2
6674EOF
6675 }",
6676 "foo.sh",
6677 |metric| {
6678 assert_eq!(metric.loc.sloc(), 6);
6679 assert_eq!(metric.loc.ploc(), 5);
6680 assert_eq!(metric.loc.lloc(), 2);
6681 assert_eq!(metric.loc.cloc(), 0);
6682 assert_eq!(metric.loc.blank(), 1);
6683 insta::assert_json_snapshot!(metric.loc);
6684 },
6685 );
6686 }
6687
6688 #[test]
6689 fn kotlin_loc_blank() {
6690 check_metrics::<KotlinParser>(
6691 "fun f(): Int {
6692
6693 val x = 1
6694
6695 return x
6696 }",
6697 "foo.kt",
6698 |metric| {
6699 assert_eq!(metric.loc.sloc(), 6);
6700 assert_eq!(metric.loc.ploc(), 4);
6701 assert_eq!(metric.loc.lloc(), 2);
6702 assert_eq!(metric.loc.cloc(), 0);
6703 assert_eq!(metric.loc.blank(), 2);
6704 insta::assert_json_snapshot!(metric.loc);
6705 },
6706 );
6707 }
6708
6709 #[test]
6710 fn kotlin_loc_cloc() {
6711 check_metrics::<KotlinParser>(
6712 "// header comment
6713 /* block
6714 comment */
6715 fun f(): Int {
6716 return 42 // inline
6717 }",
6718 "foo.kt",
6719 |metric| {
6720 assert_eq!(metric.loc.sloc(), 6);
6721 assert_eq!(metric.loc.ploc(), 3);
6722 assert_eq!(metric.loc.lloc(), 1);
6723 assert_eq!(metric.loc.cloc(), 4);
6724 assert_eq!(metric.loc.blank(), 0);
6725 insta::assert_json_snapshot!(metric.loc);
6726 },
6727 );
6728 }
6729
6730 #[test]
6731 fn kotlin_loc_no_zero_blank() {
6732 check_metrics::<KotlinParser>(
6735 "fun connectToUpdateServer() {
6736 val pool = 0
6737
6738 val updateServer = -42
6739 val isConnected = false
6740 val currTry = 0
6741 val numRetries = 10 // Number of IPC connection retries before
6742 // giving up.
6743 val numTries = 20 // Number of IPC connection tries before
6744 // giving up.
6745 }",
6746 "foo.kt",
6747 |metric| {
6748 assert_eq!(metric.loc.sloc(), 11);
6751 assert_eq!(metric.loc.ploc(), 8);
6752 assert_eq!(metric.loc.cloc(), 4);
6753 assert_eq!(metric.loc.blank(), 1);
6754 insta::assert_json_snapshot!(
6755 metric.loc,
6756 @r#"
6757 {
6758 "sloc": 11,
6759 "ploc": 8,
6760 "lloc": 6,
6761 "cloc": 4,
6762 "blank": 1,
6763 "sloc_average": 5.5,
6764 "ploc_average": 4.0,
6765 "lloc_average": 3.0,
6766 "cloc_average": 2.0,
6767 "blank_average": 0.5,
6768 "sloc_min": 11,
6769 "sloc_max": 11,
6770 "cloc_min": 4,
6771 "cloc_max": 4,
6772 "ploc_min": 8,
6773 "ploc_max": 8,
6774 "lloc_min": 6,
6775 "lloc_max": 6,
6776 "blank_min": 1,
6777 "blank_max": 1
6778 }
6779 "#
6780 );
6781 },
6782 );
6783 }
6784
6785 #[test]
6786 fn kotlin_loc_blank_zero_sanity() {
6787 check_metrics::<KotlinParser>(
6792 "fun f(): Int {
6793 val x = 1 // x
6794 val y = 2 // y
6795 return x + y
6796 }",
6797 "foo.kt",
6798 |metric| {
6799 assert_eq!(metric.loc.sloc(), 5);
6800 assert_eq!(metric.loc.ploc(), 5);
6801 assert_eq!(metric.loc.lloc(), 3);
6802 assert_eq!(metric.loc.cloc(), 2);
6803 assert_eq!(metric.loc.blank(), 0);
6804 },
6805 );
6806 }
6807
6808 #[test]
6809 fn kotlin_loc_if_lloc() {
6810 check_metrics::<KotlinParser>(
6811 "fun classify(n: Int): String {
6812 if (n > 0) {
6813 return \"positive\"
6814 } else if (n < 0) {
6815 return \"negative\"
6816 }
6817 return \"zero\"
6818 }",
6819 "foo.kt",
6820 |metric| {
6821 assert_eq!(metric.loc.sloc(), 8);
6822 assert_eq!(metric.loc.ploc(), 8);
6823 assert_eq!(metric.loc.lloc(), 5);
6824 assert_eq!(metric.loc.cloc(), 0);
6825 assert_eq!(metric.loc.blank(), 0);
6826 insta::assert_json_snapshot!(metric.loc);
6827 },
6828 );
6829 }
6830
6831 #[test]
6832 fn kotlin_loc_for_lloc() {
6833 check_metrics::<KotlinParser>(
6834 "fun sum(n: Int): Int {
6835 var s = 0
6836 for (i in 1..n) {
6837 s += i
6838 }
6839 return s
6840 }",
6841 "foo.kt",
6842 |metric| {
6843 assert_eq!(metric.loc.sloc(), 7);
6844 assert_eq!(metric.loc.ploc(), 7);
6845 assert_eq!(metric.loc.lloc(), 4);
6846 assert_eq!(metric.loc.cloc(), 0);
6847 assert_eq!(metric.loc.blank(), 0);
6848 insta::assert_json_snapshot!(metric.loc);
6849 },
6850 );
6851 }
6852
6853 #[test]
6854 fn kotlin_loc_when_lloc() {
6855 check_metrics::<KotlinParser>(
6856 "fun describe(x: Int): String {
6857 return when (x) {
6858 1 -> \"one\"
6859 2 -> \"two\"
6860 else -> \"other\"
6861 }
6862 }",
6863 "foo.kt",
6864 |metric| {
6865 assert_eq!(metric.loc.sloc(), 7);
6866 assert_eq!(metric.loc.ploc(), 7);
6867 assert_eq!(metric.loc.lloc(), 2);
6868 assert_eq!(metric.loc.cloc(), 0);
6869 assert_eq!(metric.loc.blank(), 0);
6870 insta::assert_json_snapshot!(metric.loc);
6871 },
6872 );
6873 }
6874
6875 #[test]
6876 fn kotlin_loc_lambda_lloc() {
6877 check_metrics::<KotlinParser>(
6878 "fun f(list: List<Int>): List<Int> {
6879 return list.filter { it > 0 }
6880 .map { it * 2 }
6881 }",
6882 "foo.kt",
6883 |metric| {
6884 assert_eq!(metric.loc.sloc(), 4);
6885 assert_eq!(metric.loc.ploc(), 4);
6886 assert_eq!(metric.loc.lloc(), 1);
6887 assert_eq!(metric.loc.cloc(), 0);
6888 assert_eq!(metric.loc.blank(), 0);
6889 insta::assert_json_snapshot!(metric.loc);
6890 },
6891 );
6892 }
6893
6894 #[test]
6895 fn kotlin_loc_class_loc() {
6896 check_metrics::<KotlinParser>(
6897 "class Counter {
6898 private var count = 0
6899 fun increment() { count++ }
6900 fun get(): Int = count
6901 }",
6902 "foo.kt",
6903 |metric| {
6904 assert_eq!(metric.loc.sloc(), 5);
6905 assert_eq!(metric.loc.ploc(), 5);
6906 assert_eq!(metric.loc.lloc(), 1);
6907 assert_eq!(metric.loc.cloc(), 0);
6908 assert_eq!(metric.loc.blank(), 0);
6909 insta::assert_json_snapshot!(metric.loc);
6910 },
6911 );
6912 }
6913
6914 #[test]
6915 fn kotlin_loc_multiple_functions_loc() {
6916 check_metrics::<KotlinParser>(
6917 "fun f(): Int {
6918 return 1
6919 }
6920 fun g(): Int {
6921 return 2
6922 }",
6923 "foo.kt",
6924 |metric| {
6925 assert_eq!(metric.loc.sloc(), 6);
6926 assert_eq!(metric.loc.ploc(), 6);
6927 assert_eq!(metric.loc.lloc(), 2);
6928 assert_eq!(metric.loc.cloc(), 0);
6929 assert_eq!(metric.loc.blank(), 0);
6930 insta::assert_json_snapshot!(metric.loc);
6931 },
6932 );
6933 }
6934
6935 #[test]
6936 fn kotlin_loc_while_lloc() {
6937 check_metrics::<KotlinParser>(
6938 "fun countdown(n: Int) {
6939 var i = n
6940 while (i > 0) {
6941 println(i)
6942 i--
6943 }
6944 }",
6945 "foo.kt",
6946 |metric| {
6947 assert_eq!(metric.loc.sloc(), 7);
6948 assert_eq!(metric.loc.ploc(), 7);
6949 assert_eq!(metric.loc.lloc(), 3);
6950 assert_eq!(metric.loc.cloc(), 0);
6951 assert_eq!(metric.loc.blank(), 0);
6952 insta::assert_json_snapshot!(metric.loc);
6953 },
6954 );
6955 }
6956
6957 #[test]
6958 fn typescript_blank() {
6959 check_metrics::<TypescriptParser>(
6960 "function f(): void {
6961
6962 const x = 1;
6963
6964 }",
6965 "foo.ts",
6966 |metric| {
6967 assert_eq!(metric.loc.sloc(), 5);
6968 assert_eq!(metric.loc.ploc(), 3);
6969 assert_eq!(metric.loc.lloc(), 1);
6970 assert_eq!(metric.loc.cloc(), 0);
6971 assert_eq!(metric.loc.blank(), 2);
6972 insta::assert_json_snapshot!(metric.loc);
6973 },
6974 );
6975 }
6976
6977 #[test]
6978 fn typescript_cloc() {
6979 check_metrics::<TypescriptParser>(
6980 "// header
6981 /* block
6982 comment */
6983 function f(): number {
6984 return 42; // inline
6985 }",
6986 "foo.ts",
6987 |metric| {
6988 assert_eq!(metric.loc.sloc(), 6);
6989 assert_eq!(metric.loc.ploc(), 3);
6990 assert_eq!(metric.loc.lloc(), 1);
6991 assert_eq!(metric.loc.cloc(), 4);
6992 assert_eq!(metric.loc.blank(), 0);
6993 insta::assert_json_snapshot!(metric.loc);
6994 },
6995 );
6996 }
6997
6998 #[test]
6999 fn typescript_no_zero_blank() {
7000 check_metrics::<TypescriptParser>(
7003 "function f(): void {
7004 const a = 1;
7005
7006 const b = 2; // trailing
7007 const c = 3; // trailing
7008}",
7009 "foo.ts",
7010 |metric| {
7011 assert_eq!(metric.loc.sloc(), 6);
7012 assert_eq!(metric.loc.ploc(), 5);
7013 assert_eq!(metric.loc.cloc(), 2);
7014 assert_eq!(metric.loc.blank(), 1);
7015 insta::assert_json_snapshot!(metric.loc);
7016 },
7017 );
7018 }
7019
7020 #[test]
7021 fn typescript_if_lloc() {
7022 check_metrics::<TypescriptParser>(
7023 "function classify(n: number): string {
7024 if (n > 0) {
7025 return 'positive';
7026 } else {
7027 return 'non-positive';
7028 }
7029 }",
7030 "foo.ts",
7031 |metric| {
7032 assert_eq!(metric.loc.sloc(), 7);
7033 assert_eq!(metric.loc.ploc(), 7);
7034 assert_eq!(metric.loc.lloc(), 3);
7035 assert_eq!(metric.loc.cloc(), 0);
7036 assert_eq!(metric.loc.blank(), 0);
7037 insta::assert_json_snapshot!(metric.loc);
7038 },
7039 );
7040 }
7041
7042 #[test]
7043 fn typescript_for_lloc() {
7044 check_metrics::<TypescriptParser>(
7045 "function sum(n: number): number {
7046 let s = 0;
7047 for (let i = 0; i < n; i++) {
7048 s += i;
7049 }
7050 return s;
7051 }",
7052 "foo.ts",
7053 |metric| {
7054 assert_eq!(metric.loc.sloc(), 7);
7055 assert_eq!(metric.loc.ploc(), 7);
7056 assert_eq!(metric.loc.lloc(), 4);
7057 assert_eq!(metric.loc.cloc(), 0);
7058 assert_eq!(metric.loc.blank(), 0);
7059 insta::assert_json_snapshot!(metric.loc);
7060 },
7061 );
7062 }
7063
7064 #[test]
7065 fn typescript_while_lloc() {
7066 check_metrics::<TypescriptParser>(
7067 "function countdown(n: number): void {
7068 let i = n;
7069 while (i > 0) {
7070 console.log(i);
7071 i--;
7072 }
7073 }",
7074 "foo.ts",
7075 |metric| {
7076 assert_eq!(metric.loc.sloc(), 7);
7077 assert_eq!(metric.loc.ploc(), 7);
7078 assert_eq!(metric.loc.lloc(), 4);
7079 assert_eq!(metric.loc.cloc(), 0);
7080 assert_eq!(metric.loc.blank(), 0);
7081 insta::assert_json_snapshot!(metric.loc);
7082 },
7083 );
7084 }
7085
7086 #[test]
7087 fn typescript_switch_lloc() {
7088 check_metrics::<TypescriptParser>(
7089 "function describe(x: number): string {
7090 switch (x) {
7091 case 1: return 'one';
7092 case 2: return 'two';
7093 default: return 'other';
7094 }
7095 }",
7096 "foo.ts",
7097 |metric| {
7098 assert_eq!(metric.loc.sloc(), 7);
7099 assert_eq!(metric.loc.ploc(), 7);
7100 assert_eq!(metric.loc.lloc(), 4);
7101 assert_eq!(metric.loc.cloc(), 0);
7102 assert_eq!(metric.loc.blank(), 0);
7103 insta::assert_json_snapshot!(metric.loc);
7104 },
7105 );
7106 }
7107
7108 #[test]
7109 fn typescript_class_loc() {
7110 check_metrics::<TypescriptParser>(
7111 "class Counter {
7112 private count: number = 0;
7113 increment(): void { this.count++; }
7114 get(): number { return this.count; }
7115 }",
7116 "foo.ts",
7117 |metric| {
7118 assert_eq!(metric.loc.sloc(), 5);
7119 assert_eq!(metric.loc.ploc(), 5);
7120 assert_eq!(metric.loc.lloc(), 2);
7121 assert_eq!(metric.loc.cloc(), 0);
7122 assert_eq!(metric.loc.blank(), 0);
7123 insta::assert_json_snapshot!(metric.loc);
7124 },
7125 );
7126 }
7127
7128 #[test]
7129 fn typescript_arrow_function_loc() {
7130 check_metrics::<TypescriptParser>(
7131 "const add = (a: number, b: number): number => a + b;
7132 const greet = (name: string): string => {
7133 return `Hello, ${name}`;
7134 };",
7135 "foo.ts",
7136 |metric| {
7137 assert_eq!(metric.loc.sloc(), 4);
7138 assert_eq!(metric.loc.ploc(), 4);
7139 assert_eq!(metric.loc.lloc(), 3);
7140 assert_eq!(metric.loc.cloc(), 0);
7141 assert_eq!(metric.loc.blank(), 0);
7142 insta::assert_json_snapshot!(metric.loc);
7143 },
7144 );
7145 }
7146
7147 #[test]
7148 fn typescript_interface_loc() {
7149 check_metrics::<TypescriptParser>(
7150 "interface Shape {
7151 area(): number;
7152 perimeter(): number;
7153 }
7154 function describe(s: Shape): string {
7155 return `area=${s.area()}`;
7156 }",
7157 "foo.ts",
7158 |metric| {
7159 assert_eq!(metric.loc.sloc(), 7);
7160 assert_eq!(metric.loc.ploc(), 7);
7161 assert_eq!(metric.loc.lloc(), 1);
7162 assert_eq!(metric.loc.cloc(), 0);
7163 assert_eq!(metric.loc.blank(), 0);
7164 insta::assert_json_snapshot!(metric.loc);
7165 },
7166 );
7167 }
7168
7169 #[test]
7170 fn typescript_multiple_functions_loc() {
7171 check_metrics::<TypescriptParser>(
7172 "function f(): number {
7173 return 1;
7174 }
7175 function g(): number {
7176 return 2;
7177 }
7178 function h(): number {
7179 return 3;
7180 }",
7181 "foo.ts",
7182 |metric| {
7183 assert_eq!(metric.loc.sloc(), 9);
7184 assert_eq!(metric.loc.ploc(), 9);
7185 assert_eq!(metric.loc.lloc(), 3);
7186 assert_eq!(metric.loc.cloc(), 0);
7187 assert_eq!(metric.loc.blank(), 0);
7188 insta::assert_json_snapshot!(metric.loc);
7189 },
7190 );
7191 }
7192
7193 #[test]
7194 fn typescript_try_catch_lloc() {
7195 check_metrics::<TypescriptParser>(
7196 "function safe(x: number): number {
7197 try {
7198 return 1 / x;
7199 } catch (e) {
7200 return 0;
7201 }
7202 }",
7203 "foo.ts",
7204 |metric| {
7205 assert_eq!(metric.loc.sloc(), 7);
7206 assert_eq!(metric.loc.ploc(), 7);
7207 assert_eq!(metric.loc.lloc(), 3);
7208 assert_eq!(metric.loc.cloc(), 0);
7209 assert_eq!(metric.loc.blank(), 0);
7210 insta::assert_json_snapshot!(metric.loc);
7211 },
7212 );
7213 }
7214
7215 #[test]
7216 fn typescript_nested_functions_loc() {
7217 check_metrics::<TypescriptParser>(
7218 "function outer(x: number): number {
7219 function inner(y: number): number {
7220 return y * 2;
7221 }
7222 return inner(x) + 1;
7223 }",
7224 "foo.ts",
7225 |metric| {
7226 assert_eq!(metric.loc.sloc(), 6);
7227 assert_eq!(metric.loc.ploc(), 6);
7228 assert_eq!(metric.loc.lloc(), 2);
7229 assert_eq!(metric.loc.cloc(), 0);
7230 assert_eq!(metric.loc.blank(), 0);
7231 insta::assert_json_snapshot!(metric.loc);
7232 },
7233 );
7234 }
7235
7236 #[test]
7237 fn typescript_generic_function_loc() {
7238 check_metrics::<TypescriptParser>(
7239 "function identity<T>(value: T): T {
7240 return value;
7241 }
7242 function first<T>(arr: T[]): T | undefined {
7243 return arr[0];
7244 }",
7245 "foo.ts",
7246 |metric| {
7247 assert_eq!(metric.loc.sloc(), 6);
7248 assert_eq!(metric.loc.ploc(), 6);
7249 assert_eq!(metric.loc.lloc(), 2);
7250 assert_eq!(metric.loc.cloc(), 0);
7251 assert_eq!(metric.loc.blank(), 0);
7252 insta::assert_json_snapshot!(metric.loc);
7253 },
7254 );
7255 }
7256
7257 #[test]
7258 fn tsx_blank() {
7259 check_metrics::<TsxParser>(
7260 "function f(): void {
7261
7262 const x = 1;
7263
7264 }",
7265 "foo.tsx",
7266 |metric| {
7267 assert_eq!(metric.loc.sloc(), 5);
7268 assert_eq!(metric.loc.ploc(), 3);
7269 assert_eq!(metric.loc.lloc(), 1);
7270 assert_eq!(metric.loc.cloc(), 0);
7271 assert_eq!(metric.loc.blank(), 2);
7272 insta::assert_json_snapshot!(metric.loc);
7273 },
7274 );
7275 }
7276
7277 #[test]
7278 fn tsx_cloc() {
7279 check_metrics::<TsxParser>(
7280 "// header
7281 /* block
7282 comment */
7283 function f(): number {
7284 return 42; // inline
7285 }",
7286 "foo.tsx",
7287 |metric| {
7288 assert_eq!(metric.loc.sloc(), 6);
7289 assert_eq!(metric.loc.ploc(), 3);
7290 assert_eq!(metric.loc.lloc(), 1);
7291 assert_eq!(metric.loc.cloc(), 4);
7292 assert_eq!(metric.loc.blank(), 0);
7293 insta::assert_json_snapshot!(metric.loc);
7294 },
7295 );
7296 }
7297
7298 #[test]
7299 fn tsx_no_zero_blank() {
7300 check_metrics::<TsxParser>(
7303 "function f(): void {
7304 const a = 1;
7305
7306 const b = 2; // trailing
7307 const c = 3; // trailing
7308}",
7309 "foo.tsx",
7310 |metric| {
7311 assert_eq!(metric.loc.sloc(), 6);
7312 assert_eq!(metric.loc.ploc(), 5);
7313 assert_eq!(metric.loc.cloc(), 2);
7314 assert_eq!(metric.loc.blank(), 1);
7315 insta::assert_json_snapshot!(metric.loc);
7316 },
7317 );
7318 }
7319
7320 #[test]
7321 fn tsx_if_lloc() {
7322 check_metrics::<TsxParser>(
7323 "function classify(n: number): string {
7324 if (n > 0) {
7325 return 'positive';
7326 } else {
7327 return 'non-positive';
7328 }
7329 }",
7330 "foo.tsx",
7331 |metric| {
7332 assert_eq!(metric.loc.sloc(), 7);
7333 assert_eq!(metric.loc.ploc(), 7);
7334 assert_eq!(metric.loc.lloc(), 3);
7335 assert_eq!(metric.loc.cloc(), 0);
7336 assert_eq!(metric.loc.blank(), 0);
7337 insta::assert_json_snapshot!(metric.loc);
7338 },
7339 );
7340 }
7341
7342 #[test]
7343 fn tsx_for_lloc() {
7344 check_metrics::<TsxParser>(
7345 "function sum(n: number): number {
7346 let s = 0;
7347 for (let i = 0; i < n; i++) {
7348 s += i;
7349 }
7350 return s;
7351 }",
7352 "foo.tsx",
7353 |metric| {
7354 assert_eq!(metric.loc.sloc(), 7);
7355 assert_eq!(metric.loc.ploc(), 7);
7356 assert_eq!(metric.loc.lloc(), 4);
7357 assert_eq!(metric.loc.cloc(), 0);
7358 assert_eq!(metric.loc.blank(), 0);
7359 insta::assert_json_snapshot!(metric.loc);
7360 },
7361 );
7362 }
7363
7364 #[test]
7365 fn tsx_while_lloc() {
7366 check_metrics::<TsxParser>(
7367 "function countdown(n: number): void {
7368 let i = n;
7369 while (i > 0) {
7370 console.log(i);
7371 i--;
7372 }
7373 }",
7374 "foo.tsx",
7375 |metric| {
7376 assert_eq!(metric.loc.sloc(), 7);
7377 assert_eq!(metric.loc.ploc(), 7);
7378 assert_eq!(metric.loc.lloc(), 4);
7379 assert_eq!(metric.loc.cloc(), 0);
7380 assert_eq!(metric.loc.blank(), 0);
7381 insta::assert_json_snapshot!(metric.loc);
7382 },
7383 );
7384 }
7385
7386 #[test]
7387 fn tsx_switch_lloc() {
7388 check_metrics::<TsxParser>(
7389 "function describe(x: number): string {
7390 switch (x) {
7391 case 1: return 'one';
7392 case 2: return 'two';
7393 default: return 'other';
7394 }
7395 }",
7396 "foo.tsx",
7397 |metric| {
7398 assert_eq!(metric.loc.sloc(), 7);
7399 assert_eq!(metric.loc.ploc(), 7);
7400 assert_eq!(metric.loc.lloc(), 4);
7401 assert_eq!(metric.loc.cloc(), 0);
7402 assert_eq!(metric.loc.blank(), 0);
7403 insta::assert_json_snapshot!(metric.loc);
7404 },
7405 );
7406 }
7407
7408 #[test]
7409 fn tsx_class_loc() {
7410 check_metrics::<TsxParser>(
7411 "class Counter {
7412 private count: number = 0;
7413 increment(): void { this.count++; }
7414 get(): number { return this.count; }
7415 }",
7416 "foo.tsx",
7417 |metric| {
7418 assert_eq!(metric.loc.sloc(), 5);
7419 assert_eq!(metric.loc.ploc(), 5);
7420 assert_eq!(metric.loc.lloc(), 2);
7421 assert_eq!(metric.loc.cloc(), 0);
7422 assert_eq!(metric.loc.blank(), 0);
7423 insta::assert_json_snapshot!(metric.loc);
7424 },
7425 );
7426 }
7427
7428 #[test]
7429 fn tsx_arrow_function_loc() {
7430 check_metrics::<TsxParser>(
7431 "const add = (a: number, b: number): number => a + b;
7432 const greet = (name: string): string => {
7433 return `Hello, ${name}`;
7434 };",
7435 "foo.tsx",
7436 |metric| {
7437 assert_eq!(metric.loc.sloc(), 4);
7438 assert_eq!(metric.loc.ploc(), 4);
7439 assert_eq!(metric.loc.lloc(), 3);
7440 assert_eq!(metric.loc.cloc(), 0);
7441 assert_eq!(metric.loc.blank(), 0);
7442 insta::assert_json_snapshot!(metric.loc);
7443 },
7444 );
7445 }
7446
7447 #[test]
7448 fn tsx_multiple_functions_loc() {
7449 check_metrics::<TsxParser>(
7450 "function f(): number {
7451 return 1;
7452 }
7453 function g(): number {
7454 return 2;
7455 }
7456 function h(): number {
7457 return 3;
7458 }",
7459 "foo.tsx",
7460 |metric| {
7461 assert_eq!(metric.loc.sloc(), 9);
7462 assert_eq!(metric.loc.ploc(), 9);
7463 assert_eq!(metric.loc.lloc(), 3);
7464 assert_eq!(metric.loc.cloc(), 0);
7465 assert_eq!(metric.loc.blank(), 0);
7466 insta::assert_json_snapshot!(metric.loc);
7467 },
7468 );
7469 }
7470
7471 #[test]
7472 fn tsx_try_catch_lloc() {
7473 check_metrics::<TsxParser>(
7474 "function safe(x: number): number {
7475 try {
7476 return 1 / x;
7477 } catch (e) {
7478 return 0;
7479 }
7480 }",
7481 "foo.tsx",
7482 |metric| {
7483 assert_eq!(metric.loc.sloc(), 7);
7484 assert_eq!(metric.loc.ploc(), 7);
7485 assert_eq!(metric.loc.lloc(), 3);
7486 assert_eq!(metric.loc.cloc(), 0);
7487 assert_eq!(metric.loc.blank(), 0);
7488 insta::assert_json_snapshot!(metric.loc);
7489 },
7490 );
7491 }
7492
7493 #[test]
7494 fn tsx_nested_functions_loc() {
7495 check_metrics::<TsxParser>(
7496 "function outer(x: number): number {
7497 function inner(y: number): number {
7498 return y * 2;
7499 }
7500 return inner(x) + 1;
7501 }",
7502 "foo.tsx",
7503 |metric| {
7504 assert_eq!(metric.loc.sloc(), 6);
7505 assert_eq!(metric.loc.ploc(), 6);
7506 assert_eq!(metric.loc.lloc(), 2);
7507 assert_eq!(metric.loc.cloc(), 0);
7508 assert_eq!(metric.loc.blank(), 0);
7509 insta::assert_json_snapshot!(metric.loc);
7510 },
7511 );
7512 }
7513
7514 #[test]
7515 fn tsx_interface_loc() {
7516 check_metrics::<TsxParser>(
7517 "interface Shape {
7518 area(): number;
7519 perimeter(): number;
7520 }
7521 function describe(s: Shape): string {
7522 return `area=${s.area()}`;
7523 }",
7524 "foo.tsx",
7525 |metric| {
7526 assert_eq!(metric.loc.sloc(), 7);
7527 assert_eq!(metric.loc.ploc(), 7);
7528 assert_eq!(metric.loc.lloc(), 1);
7529 assert_eq!(metric.loc.cloc(), 0);
7530 assert_eq!(metric.loc.blank(), 0);
7531 insta::assert_json_snapshot!(metric.loc);
7532 },
7533 );
7534 }
7535
7536 #[test]
7537 fn tsx_generic_function_loc() {
7538 check_metrics::<TsxParser>(
7539 "function identity<T>(value: T): T {
7540 return value;
7541 }
7542 function first<T>(arr: T[]): T | undefined {
7543 return arr[0];
7544 }",
7545 "foo.tsx",
7546 |metric| {
7547 assert_eq!(metric.loc.sloc(), 6);
7548 assert_eq!(metric.loc.ploc(), 6);
7549 assert_eq!(metric.loc.lloc(), 2);
7550 assert_eq!(metric.loc.cloc(), 0);
7551 assert_eq!(metric.loc.blank(), 0);
7552 insta::assert_json_snapshot!(metric.loc);
7553 },
7554 );
7555 }
7556
7557 #[test]
7558 fn php_blank() {
7559 check_metrics::<PhpParser>(
7560 "<?php
7561
7562$a = 1;
7563
7564$b = 2;
7565
7566",
7567 "foo.php",
7568 |metric| {
7569 assert_eq!(metric.loc.sloc(), 5);
7570 assert_eq!(metric.loc.ploc(), 3);
7571 assert_eq!(metric.loc.lloc(), 2);
7572 assert_eq!(metric.loc.cloc(), 0);
7573 assert_eq!(metric.loc.blank(), 2);
7574 insta::assert_json_snapshot!(metric.loc);
7575 },
7576 );
7577 }
7578
7579 #[test]
7580 fn php_no_zero_blank() {
7581 check_metrics::<PhpParser>(
7584 "<?php
7585$a = 1;
7586
7587$b = 2; // trailing
7588$c = 3; // trailing
7589",
7590 "foo.php",
7591 |metric| {
7592 assert_eq!(metric.loc.sloc(), 5);
7593 assert_eq!(metric.loc.ploc(), 4);
7594 assert_eq!(metric.loc.cloc(), 2);
7595 assert_eq!(metric.loc.blank(), 1);
7596 insta::assert_json_snapshot!(metric.loc);
7597 },
7598 );
7599 }
7600
7601 #[test]
7602 fn php_cloc_double_slash() {
7603 check_metrics::<PhpParser>(
7604 "<?php
7605// first
7606// second
7607$a = 1; // trailing",
7608 "foo.php",
7609 |metric| {
7610 assert_eq!(metric.loc.sloc(), 4);
7611 assert_eq!(metric.loc.ploc(), 2);
7612 assert_eq!(metric.loc.lloc(), 1);
7613 assert_eq!(metric.loc.cloc(), 3);
7614 assert_eq!(metric.loc.blank(), 0);
7615 insta::assert_json_snapshot!(metric.loc);
7616 },
7617 );
7618 }
7619
7620 #[test]
7621 fn php_cloc_hash() {
7622 check_metrics::<PhpParser>(
7623 "<?php
7624# first
7625# second
7626$a = 1;",
7627 "foo.php",
7628 |metric| {
7629 assert_eq!(metric.loc.sloc(), 4);
7630 assert_eq!(metric.loc.ploc(), 2);
7631 assert_eq!(metric.loc.lloc(), 1);
7632 assert_eq!(metric.loc.cloc(), 2);
7633 assert_eq!(metric.loc.blank(), 0);
7634 insta::assert_json_snapshot!(metric.loc);
7635 },
7636 );
7637 }
7638
7639 #[test]
7640 fn php_cloc_block() {
7641 check_metrics::<PhpParser>(
7642 "<?php
7643/*
7644 * block
7645 * comment
7646 */
7647$a = 1;",
7648 "foo.php",
7649 |metric| {
7650 assert_eq!(metric.loc.sloc(), 6);
7651 assert_eq!(metric.loc.ploc(), 2);
7652 assert_eq!(metric.loc.lloc(), 1);
7653 assert_eq!(metric.loc.cloc(), 4);
7654 assert_eq!(metric.loc.blank(), 0);
7655 insta::assert_json_snapshot!(metric.loc);
7656 },
7657 );
7658 }
7659
7660 #[test]
7661 fn php_lloc() {
7662 check_metrics::<PhpParser>(
7664 "<?php
7665$a = 1;
7666if ($a > 0) {
7667 echo $a;
7668}",
7669 "foo.php",
7670 |metric| {
7671 assert_eq!(metric.loc.sloc(), 5);
7672 assert_eq!(metric.loc.ploc(), 5);
7673 assert_eq!(metric.loc.lloc(), 3);
7674 assert_eq!(metric.loc.cloc(), 0);
7675 assert_eq!(metric.loc.blank(), 0);
7676 insta::assert_json_snapshot!(metric.loc);
7677 },
7678 );
7679 }
7680
7681 #[test]
7682 fn php_no_parenthesized_expression_lloc() {
7683 check_metrics::<PhpParser>(
7686 "<?php
7687$a = (1 + 2);",
7688 "foo.php",
7689 |metric| {
7690 assert_eq!(metric.loc.sloc(), 2);
7691 assert_eq!(metric.loc.ploc(), 2);
7692 assert_eq!(metric.loc.lloc(), 1);
7693 assert_eq!(metric.loc.cloc(), 0);
7694 assert_eq!(metric.loc.blank(), 0);
7695 insta::assert_json_snapshot!(metric.loc);
7696 },
7697 );
7698 }
7699
7700 #[test]
7701 fn php_no_compound_statement_lloc() {
7702 check_metrics::<PhpParser>(
7704 "<?php
7705function f(): void {
7706 $a = 1;
7707}",
7708 "foo.php",
7709 |metric| {
7710 assert_eq!(metric.loc.sloc(), 4);
7711 assert_eq!(metric.loc.ploc(), 4);
7712 assert_eq!(metric.loc.lloc(), 1);
7713 assert_eq!(metric.loc.cloc(), 0);
7714 assert_eq!(metric.loc.blank(), 0);
7715 insta::assert_json_snapshot!(metric.loc);
7716 },
7717 );
7718 }
7719
7720 #[test]
7721 fn php_no_colon_block_lloc() {
7722 check_metrics::<PhpParser>(
7725 "<?php
7726if (true):
7727 $a = 1;
7728endif;",
7729 "foo.php",
7730 |metric| {
7731 assert_eq!(metric.loc.sloc(), 4);
7732 assert_eq!(metric.loc.ploc(), 4);
7733 assert_eq!(metric.loc.lloc(), 2);
7734 assert_eq!(metric.loc.cloc(), 0);
7735 assert_eq!(metric.loc.blank(), 0);
7736 insta::assert_json_snapshot!(metric.loc);
7737 },
7738 );
7739 }
7740
7741 #[test]
7742 fn php_no_else_clause_lloc() {
7743 check_metrics::<PhpParser>(
7745 "<?php
7746if ($x) {
7747 $a = 1;
7748} elseif ($y) {
7749 $a = 2;
7750} else {
7751 $a = 3;
7752}",
7753 "foo.php",
7754 |metric| {
7755 assert_eq!(metric.loc.sloc(), 8);
7756 assert_eq!(metric.loc.ploc(), 8);
7757 assert_eq!(metric.loc.lloc(), 4);
7758 assert_eq!(metric.loc.cloc(), 0);
7759 assert_eq!(metric.loc.blank(), 0);
7760 insta::assert_json_snapshot!(metric.loc);
7761 },
7762 );
7763 }
7764
7765 #[test]
7766 fn php_no_case_statement_lloc() {
7767 check_metrics::<PhpParser>(
7770 "<?php
7771switch ($x) {
7772 case 1:
7773 $a = 1;
7774 break;
7775 case 2:
7776 $a = 2;
7777 break;
7778 default:
7779 $a = 0;
7780}",
7781 "foo.php",
7782 |metric| {
7783 assert_eq!(metric.loc.sloc(), 11);
7784 assert_eq!(metric.loc.ploc(), 11);
7785 assert_eq!(metric.loc.lloc(), 6);
7786 assert_eq!(metric.loc.cloc(), 0);
7787 assert_eq!(metric.loc.blank(), 0);
7788 insta::assert_json_snapshot!(metric.loc);
7789 },
7790 );
7791 }
7792
7793 #[test]
7794 fn php_no_match_arm_lloc() {
7795 check_metrics::<PhpParser>(
7798 "<?php
7799$a = match ($x) {
7800 1 => 'one',
7801 2 => 'two',
7802 default => 'other',
7803};",
7804 "foo.php",
7805 |metric| {
7806 assert_eq!(metric.loc.sloc(), 6);
7807 assert_eq!(metric.loc.ploc(), 6);
7808 assert_eq!(metric.loc.lloc(), 1);
7809 assert_eq!(metric.loc.cloc(), 0);
7810 assert_eq!(metric.loc.blank(), 0);
7811 insta::assert_json_snapshot!(metric.loc);
7812 },
7813 );
7814 }
7815
7816 #[test]
7817 fn php_no_throw_in_expression_lloc() {
7818 check_metrics::<PhpParser>(
7821 "<?php
7822$x = $y ?? throw new \\Exception('nope');",
7823 "foo.php",
7824 |metric| {
7825 assert_eq!(metric.loc.sloc(), 2);
7826 assert_eq!(metric.loc.ploc(), 2);
7827 assert_eq!(metric.loc.lloc(), 1);
7828 assert_eq!(metric.loc.cloc(), 0);
7829 assert_eq!(metric.loc.blank(), 0);
7830 insta::assert_json_snapshot!(metric.loc);
7831 },
7832 );
7833 }
7834
7835 #[test]
7836 fn php_no_closure_in_assignment_lloc() {
7837 check_metrics::<PhpParser>(
7841 "<?php
7842$f = function (): int {
7843 return 42;
7844};",
7845 "foo.php",
7846 |metric| {
7847 assert_eq!(metric.loc.sloc(), 4);
7848 assert_eq!(metric.loc.ploc(), 4);
7849 assert_eq!(metric.loc.lloc(), 2);
7850 assert_eq!(metric.loc.cloc(), 0);
7851 assert_eq!(metric.loc.blank(), 0);
7852 insta::assert_json_snapshot!(metric.loc);
7853 },
7854 );
7855 }
7856
7857 #[test]
7858 fn php_for_lloc() {
7859 check_metrics::<PhpParser>(
7862 "<?php
7863for ($i = 0; $i < 10; $i++) {
7864 echo $i;
7865}",
7866 "foo.php",
7867 |metric| {
7868 assert_eq!(metric.loc.sloc(), 4);
7869 assert_eq!(metric.loc.ploc(), 4);
7870 assert_eq!(metric.loc.lloc(), 2);
7871 assert_eq!(metric.loc.cloc(), 0);
7872 assert_eq!(metric.loc.blank(), 0);
7873 insta::assert_json_snapshot!(metric.loc);
7874 },
7875 );
7876 }
7877
7878 #[test]
7879 fn php_foreach_lloc() {
7880 check_metrics::<PhpParser>(
7881 "<?php
7882foreach ($items as $k => $v) {
7883 echo $v;
7884}",
7885 "foo.php",
7886 |metric| {
7887 assert_eq!(metric.loc.sloc(), 4);
7888 assert_eq!(metric.loc.ploc(), 4);
7889 assert_eq!(metric.loc.lloc(), 2);
7890 assert_eq!(metric.loc.cloc(), 0);
7891 assert_eq!(metric.loc.blank(), 0);
7892 insta::assert_json_snapshot!(metric.loc);
7893 },
7894 );
7895 }
7896
7897 #[test]
7898 fn php_try_lloc() {
7899 check_metrics::<PhpParser>(
7900 "<?php
7901try {
7902 $a = 1;
7903} catch (\\Exception $e) {
7904 $a = 0;
7905} finally {
7906 $b = 2;
7907}",
7908 "foo.php",
7909 |metric| {
7910 assert_eq!(metric.loc.sloc(), 8);
7911 assert_eq!(metric.loc.ploc(), 8);
7912 assert_eq!(metric.loc.lloc(), 4);
7913 assert_eq!(metric.loc.cloc(), 0);
7914 assert_eq!(metric.loc.blank(), 0);
7915 insta::assert_json_snapshot!(metric.loc);
7916 },
7917 );
7918 }
7919
7920 #[test]
7921 fn php_class_loc() {
7922 check_metrics::<PhpParser>(
7923 "<?php
7924class A {
7925 public int $x = 0;
7926 private const Y = 1;
7927 public function f(): int {
7928 return $this->x;
7929 }
7930}",
7931 "foo.php",
7932 |metric| {
7933 assert_eq!(metric.loc.sloc(), 8);
7934 assert_eq!(metric.loc.ploc(), 8);
7935 assert_eq!(metric.loc.lloc(), 3);
7936 assert_eq!(metric.loc.cloc(), 0);
7937 assert_eq!(metric.loc.blank(), 0);
7938 insta::assert_json_snapshot!(metric.loc);
7939 },
7940 );
7941 }
7942
7943 #[test]
7944 fn php_namespace_use_lloc() {
7945 check_metrics::<PhpParser>(
7946 "<?php
7947namespace App;
7948use App\\Foo;
7949use App\\Bar;
7950$a = 1;",
7951 "foo.php",
7952 |metric| {
7953 assert_eq!(metric.loc.sloc(), 5);
7954 assert_eq!(metric.loc.ploc(), 5);
7955 assert_eq!(metric.loc.lloc(), 3);
7956 assert_eq!(metric.loc.cloc(), 0);
7957 assert_eq!(metric.loc.blank(), 0);
7958 insta::assert_json_snapshot!(metric.loc);
7959 },
7960 );
7961 }
7962
7963 #[test]
7964 fn php_general_loc() {
7965 check_metrics::<PhpParser>(
7966 "<?php
7967// header
7968namespace App;
7969use App\\Foo;
7970
7971class Bar {
7972 public int $n = 0;
7973
7974 public function add(int $x): int {
7975 if ($x > 0) {
7976 return $this->n + $x;
7977 }
7978 return $this->n;
7979 }
7980}",
7981 "foo.php",
7982 |metric| {
7983 assert_eq!(metric.loc.sloc(), 15);
7984 assert_eq!(metric.loc.ploc(), 12);
7985 assert_eq!(metric.loc.lloc(), 5);
7986 assert_eq!(metric.loc.cloc(), 1);
7987 assert_eq!(metric.loc.blank(), 2);
7988 insta::assert_json_snapshot!(metric.loc);
7989 },
7990 );
7991 }
7992
7993 #[test]
7994 fn php_match_in_expression_lloc() {
7995 check_metrics::<PhpParser>(
7998 "<?php
7999$y = 10 + match ($x) { 1 => 2, default => 0 };",
8000 "foo.php",
8001 |metric| {
8002 assert_eq!(metric.loc.sloc(), 2);
8003 assert_eq!(metric.loc.ploc(), 2);
8004 assert_eq!(metric.loc.lloc(), 1);
8005 assert_eq!(metric.loc.cloc(), 0);
8006 assert_eq!(metric.loc.blank(), 0);
8007 insta::assert_json_snapshot!(metric.loc);
8008 },
8009 );
8010 }
8011
8012 #[test]
8013 fn php_html_island_ploc() {
8014 check_metrics::<PhpParser>(
8020 "<?php if ($cond): ?>
8021<div>hello</div>
8022<p>world</p>
8023<?php endif; ?>",
8024 "foo.php",
8025 |metric| {
8026 assert_eq!(metric.loc.sloc(), 4);
8027 assert_eq!(metric.loc.ploc(), 3);
8028 assert_eq!(metric.loc.lloc(), 1);
8029 assert_eq!(metric.loc.cloc(), 0);
8030 assert_eq!(metric.loc.blank(), 1);
8031 insta::assert_json_snapshot!(metric.loc);
8032 },
8033 );
8034 }
8035
8036 #[test]
8037 fn php_short_echo_tag_ploc() {
8038 check_metrics::<PhpParser>("<p><?= $name ?></p>", "foo.php", |metric| {
8042 assert_eq!(metric.loc.sloc(), 1);
8043 assert_eq!(metric.loc.ploc(), 1);
8044 assert_eq!(metric.loc.lloc(), 1);
8045 assert_eq!(metric.loc.cloc(), 0);
8046 assert_eq!(metric.loc.blank(), 0);
8047 insta::assert_json_snapshot!(metric.loc);
8048 });
8049 }
8050
8051 #[test]
8052 fn elixir_blank() {
8053 check_metrics::<ElixirParser>(
8055 "defmodule Foo do\n\n def a, do: :a\n\n def b, do: :b\nend\n",
8056 "foo.ex",
8057 |metric| {
8058 assert_eq!(metric.loc.sloc(), 6);
8059 assert_eq!(metric.loc.ploc(), 4);
8060 assert_eq!(metric.loc.lloc(), 3);
8061 assert_eq!(metric.loc.cloc(), 0);
8062 assert_eq!(metric.loc.blank(), 2);
8063 insta::assert_json_snapshot!(
8064 metric.loc,
8065 @r#"
8066 {
8067 "sloc": 6,
8068 "ploc": 4,
8069 "lloc": 3,
8070 "cloc": 0,
8071 "blank": 2,
8072 "sloc_average": 1.5,
8073 "ploc_average": 1.0,
8074 "lloc_average": 0.75,
8075 "cloc_average": 0.0,
8076 "blank_average": 0.5,
8077 "sloc_min": 1,
8078 "sloc_max": 6,
8079 "cloc_min": 0,
8080 "cloc_max": 0,
8081 "ploc_min": 1,
8082 "ploc_max": 4,
8083 "lloc_min": 1,
8084 "lloc_max": 3,
8085 "blank_min": 0,
8086 "blank_max": 2
8087 }
8088 "#
8089 );
8090 },
8091 );
8092 }
8093
8094 #[test]
8095 fn elixir_no_zero_blank() {
8096 check_metrics::<ElixirParser>(
8099 "defmodule Foo do\n def f, do: :ok\n\n def g, do: :ok # trailing\n def h, do: :ok # trailing\nend\n",
8100 "foo.ex",
8101 |metric| {
8102 assert_eq!(metric.loc.sloc(), 6);
8103 assert_eq!(metric.loc.ploc(), 5);
8104 assert_eq!(metric.loc.cloc(), 2);
8105 assert_eq!(metric.loc.blank(), 1);
8106 },
8107 );
8108 }
8109
8110 #[test]
8111 fn elixir_blank_zero_sanity() {
8112 check_metrics::<ElixirParser>(
8115 "defmodule Foo do\n def f, do: :ok\nend\n",
8116 "foo.ex",
8117 |metric| {
8118 assert_eq!(metric.loc.blank(), 0);
8119 },
8120 );
8121 }
8122
8123 #[test]
8124 fn elixir_cloc() {
8125 check_metrics::<ElixirParser>(
8128 "# top\ndefmodule Foo do\n # body\n def f, do: :ok # trailing\nend\n",
8129 "foo.ex",
8130 |metric| {
8131 assert_eq!(metric.loc.cloc(), 3);
8132 },
8133 );
8134 }
8135
8136 #[test]
8137 fn elixir_lloc() {
8138 check_metrics::<ElixirParser>(
8143 "defmodule Foo do\n def a, do: 1\n def b, do: 2\nend\n",
8144 "foo.ex",
8145 |metric| {
8146 assert_eq!(metric.loc.lloc(), 3);
8147 },
8148 );
8149 }
8150
8151 #[test]
8152 fn elixir_no_nested_call_lloc() {
8153 check_metrics::<ElixirParser>(
8157 "defmodule Foo do\n def f do\n IO.puts(Enum.join([1, 2, 3], \", \"))\n end\nend\n",
8158 "foo.ex",
8159 |metric| {
8160 assert_eq!(metric.loc.lloc(), 3);
8161 },
8162 );
8163 }
8164
8165 #[test]
8166 fn elixir_no_binary_operator_inside_call_lloc() {
8167 check_metrics::<ElixirParser>(
8173 "defmodule Foo do\n def f(a, b) do\n IO.puts(a + b)\n end\nend\n",
8174 "foo.ex",
8175 |metric| {
8176 assert_eq!(metric.loc.lloc(), 3);
8177 },
8178 );
8179 }
8180
8181 #[test]
8182 fn elixir_stab_clause_counts_lloc() {
8183 check_metrics::<ElixirParser>(
8187 "defmodule Foo do\n def f(x) do\n case x do\n 1 -> :a\n 2 -> :b\n _ -> :c\n end\n end\nend\n",
8188 "foo.ex",
8189 |metric| {
8190 assert_eq!(metric.loc.lloc(), 6);
8191 },
8192 );
8193 }
8194
8195 #[test]
8196 fn elixir_no_comment_lloc() {
8197 check_metrics::<ElixirParser>(
8202 "# leading\ndefmodule Foo do\n # inside\n def f, do: :ok\n # trailing\nend\n",
8203 "foo.ex",
8204 |metric| {
8205 assert_eq!(metric.loc.lloc(), 2);
8206 },
8207 );
8208 }
8209
8210 #[test]
8211 fn elixir_no_do_token_lloc() {
8212 check_metrics::<ElixirParser>("defmodule Foo do\n :ok\nend\n", "foo.ex", |metric| {
8217 assert_eq!(metric.loc.lloc(), 2);
8220 });
8221 }
8222
8223 #[test]
8224 fn elixir_no_keyword_pair_lloc() {
8225 check_metrics::<ElixirParser>(
8229 "defmodule Foo do\n def add(a, b), do: a + b\nend\n",
8230 "foo.ex",
8231 |metric| {
8232 assert_eq!(metric.loc.lloc(), 2);
8234 },
8235 );
8236 }
8237
8238 #[test]
8239 fn elixir_no_string_content_lloc() {
8240 check_metrics::<ElixirParser>(
8245 "defmodule Foo do\n @moduledoc \"\"\"\n line one\n line two\n \"\"\"\n def f, do: :ok\nend\n",
8246 "foo.ex",
8247 |metric| {
8248 assert_eq!(metric.loc.lloc(), 3);
8250 },
8251 );
8252 }
8253
8254 #[test]
8255 fn elixir_rescue_arm_counts_lloc() {
8256 check_metrics::<ElixirParser>(
8263 "defmodule Foo do\n def safe do\n try do\n do_it()\n rescue\n ArgumentError -> :bad\n RuntimeError -> :worse\n end\n end\nend\n",
8264 "foo.ex",
8265 |metric| {
8266 assert_eq!(metric.loc.lloc(), 7);
8267 },
8268 );
8269 }
8270
8271 #[test]
8272 fn elixir_no_arg_punctuation_lloc() {
8273 check_metrics::<ElixirParser>(
8277 "defmodule Foo do\n def add(a, b, c, d) do\n a + b + c + d\n end\nend\n",
8278 "foo.ex",
8279 |metric| {
8280 assert_eq!(metric.loc.lloc(), 3);
8282 },
8283 );
8284 }
8285
8286 #[test]
8287 fn elixir_no_list_element_lloc() {
8288 check_metrics::<ElixirParser>(
8291 "defmodule Foo do\n def f do\n [:a, :b, :c, :d]\n end\nend\n",
8292 "foo.ex",
8293 |metric| {
8294 assert_eq!(metric.loc.lloc(), 3);
8296 },
8297 );
8298 }
8299
8300 #[test]
8301 fn elixir_no_map_field_lloc() {
8302 check_metrics::<ElixirParser>(
8304 "defmodule Foo do\n def f do\n %{a: 1, b: 2, c: 3}\n end\nend\n",
8305 "foo.ex",
8306 |metric| {
8307 assert_eq!(metric.loc.lloc(), 3);
8308 },
8309 );
8310 }
8311
8312 #[test]
8313 fn elixir_anonymous_fn_body_lloc() {
8314 check_metrics::<ElixirParser>(
8322 "defmodule Foo do\n def f do\n add = fn x -> x + 1 end\n add\n end\nend\n",
8323 "foo.ex",
8324 |metric| {
8325 assert_eq!(metric.loc.lloc(), 5);
8326 },
8327 );
8328 }
8329
8330 #[test]
8331 fn ruby_blank() {
8332 check_metrics::<RubyParser>("def foo\n a = 1\n\n a + 1\nend\n", "foo.rb", |metric| {
8336 assert_eq!(metric.loc.blank(), 1);
8337 });
8338 }
8339
8340 #[test]
8341 fn ruby_no_zero_blank() {
8342 check_metrics::<RubyParser>(
8348 "def foo # entry\n pool = 0\n\n server = -42 # negative\n\n ok = false\nend\n",
8349 "foo.rb",
8350 |metric| {
8351 assert_eq!(metric.loc.blank(), 2);
8352 },
8353 );
8354 }
8355
8356 #[test]
8357 fn ruby_cloc() {
8358 check_metrics::<RubyParser>(
8360 "# one\n# two\n# three\ndef foo\nend\n",
8361 "foo.rb",
8362 |metric| {
8363 assert_eq!(metric.loc.cloc(), 3);
8364 },
8365 );
8366 }
8367
8368 #[test]
8369 fn ruby_lloc() {
8370 check_metrics::<RubyParser>(
8374 "def foo(a)\n if a\n a += 1\n end\n while a > 0\n a -= 1\n end\nend\n",
8375 "foo.rb",
8376 |metric| {
8377 assert_eq!(metric.loc.lloc(), 3);
8378 },
8379 );
8380 }
8381
8382 #[test]
8383 fn ruby_no_call_lloc() {
8384 check_metrics::<RubyParser>(
8389 "def foo\n puts 'hello'\n puts 'world'\nend\n",
8390 "foo.rb",
8391 |metric| {
8392 assert_eq!(metric.loc.lloc(), 1);
8393 },
8394 );
8395 }
8396
8397 #[test]
8398 fn ruby_no_assignment_lloc() {
8399 check_metrics::<RubyParser>(
8402 "def foo\n a = 1\n b = 2\n c = a + b\nend\n",
8403 "foo.rb",
8404 |metric| {
8405 assert_eq!(metric.loc.lloc(), 1);
8406 },
8407 );
8408 }
8409
8410 #[test]
8411 fn ruby_modifier_lloc() {
8412 check_metrics::<RubyParser>(
8418 "def foo(a)\n return a if a.nil?\n a -= 1 while a > 0\n parse(a) rescue nil\nend\n",
8419 "foo.rb",
8420 |metric| {
8421 assert_eq!(metric.loc.lloc(), 5);
8422 },
8423 );
8424 }
8425
8426 #[test]
8427 fn ruby_class_lloc() {
8428 check_metrics::<RubyParser>(
8430 "module M\n class C\n def foo\n end\n def bar\n end\n end\nend\n",
8431 "foo.rb",
8432 |metric| {
8433 assert_eq!(metric.loc.lloc(), 4);
8434 },
8435 );
8436 }
8437
8438 #[test]
8439 fn ruby_begin_rescue_lloc() {
8440 check_metrics::<RubyParser>(
8444 "def foo\n begin\n risky\n rescue StandardError\n nil\n end\nend\n",
8445 "foo.rb",
8446 |metric| {
8447 assert_eq!(metric.loc.lloc(), 2);
8448 },
8449 );
8450 }
8451
8452 #[test]
8453 fn ruby_nested_defs_lloc() {
8454 check_metrics::<RubyParser>(
8457 "def outer\n def inner\n 1\n end\nend\n",
8458 "foo.rb",
8459 |metric| {
8460 assert_eq!(metric.loc.lloc(), 2);
8461 },
8462 );
8463 }
8464
8465 #[test]
8466 fn ruby_no_block_body_lloc() {
8467 check_metrics::<RubyParser>(
8473 "[1, 2, 3].each do |x|\n puts x\nend\n",
8474 "foo.rb",
8475 |metric| {
8476 assert_eq!(metric.loc.lloc(), 0);
8477 },
8478 );
8479 }
8480
8481 #[test]
8482 fn ruby_no_lambda_body_lloc() {
8483 check_metrics::<RubyParser>("add = ->(a, b) {\n a + b\n}\n", "foo.rb", |metric| {
8488 assert_eq!(metric.loc.lloc(), 0);
8489 });
8490 }
8491
8492 #[test]
8493 fn ruby_heredoc_lloc_and_blank() {
8494 check_metrics::<RubyParser>(
8501 "def foo\n msg = <<~TXT\n one\n two\n TXT\n msg\nend\n",
8502 "foo.rb",
8503 |metric| {
8504 assert_eq!(metric.loc.sloc(), 7);
8505 assert_eq!(metric.loc.ploc(), 7);
8506 assert_eq!(metric.loc.lloc(), 1);
8507 assert_eq!(metric.loc.blank(), 0);
8508 },
8509 );
8510 }
8511
8512 #[test]
8513 fn ruby_semicolon_multistatement_lloc_undercount() {
8514 check_metrics::<RubyParser>(
8521 "def foo\n a = 1; b = 2; a + b\nend\n",
8522 "foo.rb",
8523 |metric| {
8524 assert_eq!(metric.loc.lloc(), 1);
8525 },
8526 );
8527 }
8528
8529 #[test]
8530 fn ruby_ploc_skips_comments_and_blanks() {
8531 check_metrics::<RubyParser>("# header\n\ndef foo\n a = 1\nend\n", "foo.rb", |metric| {
8534 assert_eq!(metric.loc.ploc(), 3);
8535 assert_eq!(metric.loc.cloc(), 1);
8536 assert_eq!(metric.loc.blank(), 1);
8537 });
8538 }
8539
8540 #[test]
8549 fn python_nested_def_lloc() {
8550 check_metrics::<PythonParser>(
8554 "def outer():\n def inner():\n return 1\n return inner()\n",
8555 "foo.py",
8556 |metric| {
8557 assert_eq!(metric.loc.sloc(), 4);
8558 assert_eq!(metric.loc.ploc(), 4);
8559 assert_eq!(metric.loc.lloc(), 2);
8560 assert_eq!(metric.loc.cloc(), 0);
8561 assert_eq!(metric.loc.blank(), 0);
8562 insta::assert_json_snapshot!(metric.loc);
8563 },
8564 );
8565 }
8566
8567 #[test]
8568 fn python_lambda_in_def_lloc() {
8569 check_metrics::<PythonParser>(
8573 "def outer():\n f = lambda x: x + 1\n return f(2)\n",
8574 "foo.py",
8575 |metric| {
8576 assert_eq!(metric.loc.sloc(), 3);
8577 assert_eq!(metric.loc.ploc(), 3);
8578 assert_eq!(metric.loc.lloc(), 2);
8579 assert_eq!(metric.loc.cloc(), 0);
8580 assert_eq!(metric.loc.blank(), 0);
8581 insta::assert_json_snapshot!(metric.loc);
8582 },
8583 );
8584 }
8585
8586 #[test]
8587 fn python_match_statement_lloc() {
8588 check_metrics::<PythonParser>(
8595 "def f(x):\n match x:\n case 1: return 1\n case _: return 0\n",
8596 "foo.py",
8597 |metric| {
8598 assert_eq!(metric.loc.lloc(), 3);
8599 insta::assert_json_snapshot!(metric.loc);
8600 },
8601 );
8602 }
8603
8604 #[test]
8605 fn python_match_lloc_matches_if_else() {
8606 check_metrics::<PythonParser>(
8614 "def f(x):\n if x == 1: return 1\n else: return 0\n",
8615 "foo.py",
8616 |metric| assert_eq!(metric.loc.lloc(), 3),
8617 );
8618 check_metrics::<PythonParser>(
8619 "def f(x):\n match x:\n case 1: return 1\n case _: return 0\n",
8620 "foo.py",
8621 |metric| assert_eq!(metric.loc.lloc(), 3),
8622 );
8623 }
8624
8625 #[test]
8626 fn python_type_alias_lloc() {
8627 check_metrics::<PythonParser>("type Alias = int\nx = 1\n", "foo.py", |metric| {
8632 assert_eq!(metric.loc.lloc(), 2);
8633 insta::assert_json_snapshot!(metric.loc);
8634 });
8635 }
8636
8637 #[test]
8638 fn java_local_class_in_method_lloc() {
8639 check_metrics::<JavaParser>(
8643 "class Foo {\n int bar() {\n class Local {\n int v() { return 1; }\n }\n return new Local().v();\n }\n}\n",
8644 "foo.java",
8645 |metric| {
8646 assert_eq!(metric.loc.sloc(), 8);
8647 assert_eq!(metric.loc.ploc(), 8);
8648 assert_eq!(metric.loc.lloc(), 2);
8649 assert_eq!(metric.loc.cloc(), 0);
8650 assert_eq!(metric.loc.blank(), 0);
8651 insta::assert_json_snapshot!(metric.loc);
8652 },
8653 );
8654 }
8655
8656 #[test]
8657 fn java_lambda_in_method_lloc() {
8658 check_metrics::<JavaParser>(
8662 "class Foo {\n void bar() {\n java.util.function.IntUnaryOperator f = x -> x + 1;\n f.applyAsInt(3);\n }\n}\n",
8663 "foo.java",
8664 |metric| {
8665 assert_eq!(metric.loc.sloc(), 6);
8666 assert_eq!(metric.loc.ploc(), 6);
8667 assert_eq!(metric.loc.lloc(), 2);
8668 assert_eq!(metric.loc.cloc(), 0);
8669 assert_eq!(metric.loc.blank(), 0);
8670 insta::assert_json_snapshot!(metric.loc);
8671 },
8672 );
8673 }
8674
8675 #[test]
8676 fn groovy_blank() {
8677 check_metrics::<GroovyParser>("int x = 1\n\n\nint y = 2", "foo.groovy", |metric| {
8680 assert_eq!(metric.loc.sloc(), 4);
8681 assert_eq!(metric.loc.ploc(), 2);
8682 assert_eq!(metric.loc.lloc(), 2);
8683 assert_eq!(metric.loc.blank(), 2);
8684 });
8685 }
8686
8687 #[test]
8688 fn groovy_no_zero_blank() {
8689 check_metrics::<GroovyParser>("int x = 1", "foo.groovy", |metric| {
8691 assert_eq!(metric.loc.sloc(), 1);
8692 assert_eq!(metric.loc.blank(), 0);
8693 });
8694 }
8695
8696 #[test]
8697 fn groovy_cloc_line_comments() {
8698 check_metrics::<GroovyParser>(
8699 "// first comment
8700 int x = 1
8701 // second comment
8702 int y = 2",
8703 "foo.groovy",
8704 |metric| {
8705 assert_eq!(metric.loc.cloc(), 2);
8706 assert_eq!(metric.loc.ploc(), 2);
8707 },
8708 );
8709 }
8710
8711 #[test]
8712 fn groovy_cloc_block_comment() {
8713 check_metrics::<GroovyParser>(
8714 "/* multi
8715 line
8716 comment */
8717 int x = 1",
8718 "foo.groovy",
8719 |metric| {
8720 assert_eq!(metric.loc.cloc(), 3);
8722 },
8723 );
8724 }
8725
8726 #[test]
8727 fn groovy_cloc_groovydoc_comment() {
8728 check_metrics::<GroovyParser>(
8732 "/** groovydoc */
8733class A {
8734 int x = 1
8735}",
8736 "foo.groovy",
8737 |metric| {
8738 assert_eq!(metric.loc.cloc(), 1);
8739 assert_eq!(metric.loc.ploc(), 3);
8740 },
8741 );
8742 }
8743
8744 #[test]
8745 fn groovy_simple_lloc() {
8746 check_metrics::<GroovyParser>(
8748 "int a = 1
8749 int b = 2
8750 int c = 3",
8751 "foo.groovy",
8752 |metric| {
8753 assert_eq!(metric.loc.lloc(), 3);
8754 },
8755 );
8756 }
8757
8758 #[test]
8759 fn groovy_no_local_variable_declaration_in_for_lloc() {
8760 check_metrics::<GroovyParser>(
8764 "for (int i = 0; i < 10; i++) {
8765 println(i)
8766 }",
8767 "foo.groovy",
8768 |metric| {
8769 assert_eq!(metric.loc.lloc(), 2);
8771 },
8772 );
8773 }
8774
8775 #[test]
8776 fn groovy_lambda_in_method_lloc() {
8777 check_metrics::<GroovyParser>(
8784 "class Foo {
8785 void bar() {
8786 def f = { x -> x + 1 }
8787 f(3)
8788 }
8789 }",
8790 "foo.groovy",
8791 |metric| {
8792 assert_eq!(metric.loc.lloc(), 3);
8793 },
8794 );
8795 }
8796
8797 #[test]
8798 fn groovy_try_lloc() {
8799 check_metrics::<GroovyParser>(
8802 "void f() {
8803 try {
8804 risky()
8805 } catch (Exception e) {
8806 handle(e)
8807 }
8808 }",
8809 "foo.groovy",
8810 |metric| {
8811 assert_eq!(metric.loc.lloc(), 3);
8813 },
8814 );
8815 }
8816
8817 #[test]
8818 fn groovy_class_loc() {
8819 check_metrics::<GroovyParser>(
8821 "class A {
8822 void f() {
8823 int x = 1
8824 }
8825 void g() {
8826 int y = 2
8827 }
8828 }",
8829 "foo.groovy",
8830 |metric| {
8831 assert_eq!(metric.loc.ploc(), 8);
8835 assert_eq!(metric.loc.cloc(), 0);
8836 assert_eq!(metric.loc.lloc(), 2);
8839 },
8840 );
8841 }
8842
8843 #[test]
8844 fn groovy_partial_parse_recovers_unit() {
8845 check_metrics::<GroovyParser>("def x = (((", "foo.groovy", |metric| {
8850 assert_eq!(metric.loc.sloc(), 1);
8851 assert_eq!(metric.loc.blank(), 0);
8852 });
8853 }
8854
8855 #[test]
8856 fn groovy_sloc() {
8857 check_metrics::<GroovyParser>(
8860 "int a = 1
8861 int b = 2
8862
8863 int c = 3",
8864 "foo.groovy",
8865 |metric| {
8866 assert_eq!(metric.loc.sloc(), 4);
8867 assert_eq!(metric.loc.ploc(), 3);
8868 assert_eq!(metric.loc.blank(), 1);
8869 },
8870 );
8871 }
8872
8873 #[test]
8874 fn groovy_single_ploc() {
8875 check_metrics::<GroovyParser>("int x = 42", "foo.groovy", |metric| {
8878 assert_eq!(metric.loc.ploc(), 1);
8879 assert_eq!(metric.loc.cloc(), 0);
8880 });
8881 }
8882
8883 #[test]
8884 fn groovy_multi_ploc() {
8885 check_metrics::<GroovyParser>(
8888 "int a = 1
8889 int b = 2
8890 int c = 3
8891 int d = 4",
8892 "foo.groovy",
8893 |metric| {
8894 assert_eq!(metric.loc.ploc(), 4);
8895 assert_eq!(metric.loc.lloc(), 4);
8896 },
8897 );
8898 }
8899
8900 #[test]
8901 fn groovy_single_statement_lloc() {
8902 check_metrics::<GroovyParser>("println 'hi'", "foo.groovy", |metric| {
8905 assert_eq!(metric.loc.lloc(), 1);
8906 });
8907 }
8908
8909 #[test]
8910 fn groovy_for_lloc() {
8911 check_metrics::<GroovyParser>(
8916 "for (int i = 0; i < 100; i++) {
8917 println(i)
8918 }",
8919 "foo.groovy",
8920 |metric| {
8921 assert_eq!(metric.loc.lloc(), 2);
8923 },
8924 );
8925 }
8926
8927 #[test]
8928 fn groovy_foreach_lloc() {
8929 check_metrics::<GroovyParser>(
8932 "for (item in items) {
8933 println(item)
8934 }",
8935 "foo.groovy",
8936 |metric| {
8937 assert_eq!(metric.loc.lloc(), 2);
8939 },
8940 );
8941 }
8942
8943 #[test]
8944 fn groovy_while_lloc() {
8945 check_metrics::<GroovyParser>(
8948 "int i = 0
8949 while (i < 10) {
8950 i++
8951 println(i)
8952 }",
8953 "foo.groovy",
8954 |metric| {
8955 assert_eq!(metric.loc.lloc(), 4);
8957 },
8958 );
8959 }
8960
8961 #[test]
8962 fn groovy_do_while_lloc() {
8963 check_metrics::<GroovyParser>(
8966 "int i = 0
8967 do {
8968 i++
8969 } while (i < 5)",
8970 "foo.groovy",
8971 |metric| {
8972 assert_eq!(metric.loc.lloc(), 3);
8974 },
8975 );
8976 }
8977
8978 #[test]
8979 fn groovy_continue_lloc() {
8980 check_metrics::<GroovyParser>(
8982 "for (int i = 0; i < 10; i++) {
8983 if (i == 5) {
8984 continue
8985 }
8986 println(i)
8987 }",
8988 "foo.groovy",
8989 |metric| {
8990 assert_eq!(metric.loc.lloc(), 4);
8992 },
8993 );
8994 }
8995
8996 #[test]
8997 fn groovy_expressions_lloc() {
8998 check_metrics::<GroovyParser>(
9001 "int a = 1
9002 a = 2
9003 a += 3
9004 println(a)
9005 doSomething()",
9006 "foo.groovy",
9007 |metric| {
9008 assert_eq!(metric.loc.lloc(), 5);
9010 },
9011 );
9012 }
9013
9014 #[test]
9015 fn groovy_throw_lloc() {
9016 check_metrics::<GroovyParser>(
9018 "throw new RuntimeException('bad')",
9019 "foo.groovy",
9020 |metric| {
9021 assert_eq!(metric.loc.lloc(), 1);
9022 },
9023 );
9024 }
9025
9026 #[test]
9027 fn groovy_general_loc() {
9028 check_metrics::<GroovyParser>(
9040 "class A {
9041 void f(int x) {
9042 if (x > 0) {
9043 println(x)
9044 } else {
9045 println 'neg'
9046 }
9047 return
9048 }
9049 }",
9050 "foo.groovy",
9051 |metric| {
9052 assert_eq!(metric.loc.lloc(), 4);
9053 assert_eq!(metric.loc.cloc(), 0);
9054 },
9055 );
9056 }
9057
9058 #[test]
9059 fn csharp_local_function_in_method_lloc() {
9060 check_metrics::<CsharpParser>(
9064 "class Foo {\n int Bar() {\n int Inner(int x) { return x + 1; }\n return Inner(2);\n }\n}\n",
9065 "foo.cs",
9066 |metric| {
9067 assert_eq!(metric.loc.sloc(), 6);
9068 assert_eq!(metric.loc.ploc(), 6);
9069 assert_eq!(metric.loc.lloc(), 2);
9070 assert_eq!(metric.loc.cloc(), 0);
9071 assert_eq!(metric.loc.blank(), 0);
9072 insta::assert_json_snapshot!(metric.loc);
9073 },
9074 );
9075 }
9076
9077 #[test]
9078 fn csharp_lambda_in_method_lloc() {
9079 check_metrics::<CsharpParser>(
9082 "class Foo {\n void Bar() {\n System.Func<int, int> f = x => x + 1;\n f(3);\n }\n}\n",
9083 "foo.cs",
9084 |metric| {
9085 assert_eq!(metric.loc.sloc(), 6);
9086 assert_eq!(metric.loc.ploc(), 6);
9087 assert_eq!(metric.loc.lloc(), 2);
9088 assert_eq!(metric.loc.cloc(), 0);
9089 assert_eq!(metric.loc.blank(), 0);
9090 insta::assert_json_snapshot!(metric.loc);
9091 },
9092 );
9093 }
9094
9095 #[test]
9096 fn cpp_lambda_in_function_lloc() {
9097 check_metrics::<CppParser>(
9105 "int bar() {\n auto f = [](int x) { return x + 1; };\n return f(2);\n}\n",
9106 "foo.cpp",
9107 |metric| {
9108 assert_eq!(metric.loc.sloc(), 4);
9109 assert_eq!(metric.loc.ploc(), 4);
9110 assert_eq!(metric.loc.lloc(), 3);
9111 assert_eq!(metric.loc.cloc(), 0);
9112 assert_eq!(metric.loc.blank(), 0);
9113 insta::assert_json_snapshot!(metric.loc);
9114 },
9115 );
9116 }
9117
9118 #[test]
9119 fn javascript_nested_function_lloc() {
9120 check_metrics::<JavascriptParser>(
9124 "function outer() {\n function inner() {\n return 1;\n }\n return inner();\n}\n",
9125 "foo.js",
9126 |metric| {
9127 assert_eq!(metric.loc.sloc(), 6);
9128 assert_eq!(metric.loc.ploc(), 6);
9129 assert_eq!(metric.loc.lloc(), 2);
9130 assert_eq!(metric.loc.cloc(), 0);
9131 assert_eq!(metric.loc.blank(), 0);
9132 insta::assert_json_snapshot!(metric.loc);
9133 },
9134 );
9135 }
9136
9137 #[test]
9138 fn javascript_arrow_function_lloc() {
9139 check_metrics::<JavascriptParser>(
9142 "function outer() {\n const inner = (x) => x + 1;\n return inner(2);\n}\n",
9143 "foo.js",
9144 |metric| {
9145 assert_eq!(metric.loc.sloc(), 4);
9146 assert_eq!(metric.loc.ploc(), 4);
9147 assert_eq!(metric.loc.lloc(), 2);
9148 assert_eq!(metric.loc.cloc(), 0);
9149 assert_eq!(metric.loc.blank(), 0);
9150 insta::assert_json_snapshot!(metric.loc);
9151 },
9152 );
9153 }
9154
9155 #[test]
9156 fn kotlin_lambda_literal_in_fun_lloc() {
9157 check_metrics::<KotlinParser>(
9160 "fun outer() {\n val f: (Int) -> Int = { x -> x + 1 }\n f(3)\n}\n",
9161 "foo.kt",
9162 |metric| {
9163 assert_eq!(metric.loc.sloc(), 4);
9164 assert_eq!(metric.loc.ploc(), 4);
9165 assert_eq!(metric.loc.lloc(), 2);
9166 assert_eq!(metric.loc.cloc(), 0);
9167 assert_eq!(metric.loc.blank(), 0);
9168 insta::assert_json_snapshot!(metric.loc);
9169 },
9170 );
9171 }
9172
9173 #[test]
9174 fn kotlin_local_fun_in_fun_lloc() {
9175 check_metrics::<KotlinParser>(
9179 "fun outer() {\n fun inner(x: Int): Int { return x + 1 }\n inner(3)\n}\n",
9180 "foo.kt",
9181 |metric| {
9182 assert_eq!(metric.loc.sloc(), 4);
9183 assert_eq!(metric.loc.ploc(), 4);
9184 assert_eq!(metric.loc.lloc(), 2);
9185 assert_eq!(metric.loc.cloc(), 0);
9186 assert_eq!(metric.loc.blank(), 0);
9187 insta::assert_json_snapshot!(metric.loc);
9188 },
9189 );
9190 }
9191
9192 #[test]
9193 fn kotlin_object_expression_in_fun_lloc() {
9194 check_metrics::<KotlinParser>(
9198 "fun outer() {\n val r = object : Runnable { override fun run() { println(\"hi\") } }\n r.run()\n}\n",
9199 "foo.kt",
9200 |metric| {
9201 assert_eq!(metric.loc.sloc(), 4);
9202 assert_eq!(metric.loc.ploc(), 4);
9203 assert_eq!(metric.loc.lloc(), 3);
9204 assert_eq!(metric.loc.cloc(), 0);
9205 assert_eq!(metric.loc.blank(), 0);
9206 insta::assert_json_snapshot!(metric.loc);
9207 },
9208 );
9209 }
9210
9211 #[test]
9212 fn go_function_literal_initializer_lloc() {
9213 check_metrics::<GoParser>(
9218 "package main\nfunc outer() int {\n inner := func(x int) int { return x + 1 }\n return inner(2)\n}\n",
9219 "foo.go",
9220 |metric| {
9221 assert_eq!(metric.loc.sloc(), 5);
9222 assert_eq!(metric.loc.ploc(), 5);
9223 assert_eq!(metric.loc.lloc(), 3);
9224 assert_eq!(metric.loc.cloc(), 0);
9225 assert_eq!(metric.loc.blank(), 0);
9226 insta::assert_json_snapshot!(metric.loc);
9227 },
9228 );
9229 }
9230
9231 #[test]
9232 fn php_anonymous_function_in_function_lloc() {
9233 check_metrics::<PhpParser>(
9237 "<?php\nfunction outer() {\n $f = function ($x) { return $x + 1; };\n return $f(2);\n}\n",
9238 "foo.php",
9239 |metric| {
9240 assert_eq!(metric.loc.sloc(), 5);
9241 assert_eq!(metric.loc.ploc(), 5);
9242 assert_eq!(metric.loc.lloc(), 3);
9243 assert_eq!(metric.loc.cloc(), 0);
9244 assert_eq!(metric.loc.blank(), 0);
9245 insta::assert_json_snapshot!(metric.loc);
9246 },
9247 );
9248 }
9249
9250 #[test]
9251 fn php_arrow_function_in_function_lloc() {
9252 check_metrics::<PhpParser>(
9255 "<?php\nfunction outer() {\n $f = fn ($x) => $x + 1;\n return $f(2);\n}\n",
9256 "foo.php",
9257 |metric| {
9258 assert_eq!(metric.loc.sloc(), 5);
9259 assert_eq!(metric.loc.ploc(), 5);
9260 assert_eq!(metric.loc.lloc(), 2);
9261 assert_eq!(metric.loc.cloc(), 0);
9262 assert_eq!(metric.loc.blank(), 0);
9263 insta::assert_json_snapshot!(metric.loc);
9264 },
9265 );
9266 }
9267
9268 #[test]
9269 fn lua_nested_local_function_lloc() {
9270 check_metrics::<LuaParser>(
9274 "local function outer()\n local function inner()\n return 1\n end\n return inner()\nend\n",
9275 "foo.lua",
9276 |metric| {
9277 assert_eq!(metric.loc.sloc(), 6);
9278 assert_eq!(metric.loc.ploc(), 6);
9279 assert_eq!(metric.loc.lloc(), 4);
9280 assert_eq!(metric.loc.cloc(), 0);
9281 assert_eq!(metric.loc.blank(), 0);
9282 insta::assert_json_snapshot!(metric.loc);
9283 },
9284 );
9285 }
9286
9287 #[test]
9288 fn lua_function_expression_in_local_decl_lloc() {
9289 check_metrics::<LuaParser>(
9294 "local function outer()\n local f = function (x) return x + 1 end\n return f(2)\nend\n",
9295 "foo.lua",
9296 |metric| {
9297 assert_eq!(metric.loc.sloc(), 4);
9298 assert_eq!(metric.loc.ploc(), 4);
9299 assert_eq!(metric.loc.lloc(), 4);
9300 assert_eq!(metric.loc.cloc(), 0);
9301 assert_eq!(metric.loc.blank(), 0);
9302 insta::assert_json_snapshot!(metric.loc);
9303 },
9304 );
9305 }
9306
9307 #[test]
9308 fn tcl_apply_closure_lloc() {
9309 check_metrics::<TclParser>(
9316 "proc outer {} {\n set f [list x {return [expr {$x + 1}]}]\n apply $f 2\n}\n",
9317 "foo.tcl",
9318 |metric| {
9319 assert_eq!(metric.loc.sloc(), 4);
9320 assert_eq!(metric.loc.ploc(), 4);
9321 assert_eq!(metric.loc.lloc(), 4);
9322 assert_eq!(metric.loc.cloc(), 0);
9323 assert_eq!(metric.loc.blank(), 0);
9324 insta::assert_json_snapshot!(metric.loc);
9325 },
9326 );
9327 }
9328
9329 #[test]
9330 fn perl_anonymous_sub_in_sub_lloc() {
9331 check_metrics::<PerlParser>(
9341 "sub outer {\n my $f = sub { return $_[0] + 1 };\n return $f->(2);\n}\n",
9342 "foo.pl",
9343 |metric| {
9344 assert_eq!(metric.loc.sloc(), 4);
9345 assert_eq!(metric.loc.ploc(), 4);
9346 assert_eq!(metric.loc.lloc(), 2);
9347 assert_eq!(metric.loc.cloc(), 0);
9348 assert_eq!(metric.loc.blank(), 0);
9349 insta::assert_json_snapshot!(metric.loc);
9350 },
9351 );
9352 }
9353
9354 #[test]
9355 fn perl_named_sub_in_sub_lloc() {
9356 check_metrics::<PerlParser>(
9371 "sub outer {\n sub inner { return 1 }\n return inner();\n}\n",
9372 "foo.pl",
9373 |metric| {
9374 assert_eq!(metric.loc.sloc(), 4);
9375 assert_eq!(metric.loc.ploc(), 4);
9376 assert_eq!(metric.loc.lloc(), 1);
9377 assert_eq!(metric.loc.cloc(), 0);
9378 assert_eq!(metric.loc.blank(), 0);
9379 insta::assert_json_snapshot!(metric.loc);
9380 },
9381 );
9382 }
9383
9384 #[test]
9385 fn elixir_fn_inside_def_lloc() {
9386 check_metrics::<ElixirParser>(
9390 "defmodule Foo do\n def outer do\n f = fn x -> x + 1 end\n f.(2)\n end\nend\n",
9391 "foo.ex",
9392 |metric| {
9393 assert_eq!(metric.loc.sloc(), 6);
9394 assert_eq!(metric.loc.ploc(), 6);
9395 assert_eq!(metric.loc.lloc(), 5);
9396 assert_eq!(metric.loc.cloc(), 0);
9397 assert_eq!(metric.loc.blank(), 0);
9398 insta::assert_json_snapshot!(metric.loc);
9399 },
9400 );
9401 }
9402
9403 #[test]
9415 fn rust_nested_min_max_propagates() {
9416 check_metrics::<RustParser>(
9417 "struct C;\nimpl C {\n fn small(&self) {\n let _ = 1;\n }\n fn big(&self) {\n let _ = 1;\n let _ = 2;\n let _ = 3;\n }\n}\n",
9418 "c.rs",
9419 |metric| {
9420 let loc = &metric.loc;
9426 assert!(
9427 loc.sloc_min() <= loc.sloc(),
9428 "sloc_min {} must not exceed unit sloc {}",
9429 loc.sloc_min(),
9430 loc.sloc()
9431 );
9432 assert_eq!(loc.sloc_min(), 3, "smallest leaf method span");
9433 assert_eq!(loc.sloc_max(), loc.sloc(), "largest space is the unit");
9434 assert_eq!(loc.lloc_min(), 1);
9436 },
9437 );
9438 }
9439
9440 #[test]
9445 fn java_nested_min_max_propagates() {
9446 check_metrics::<JavaParser>(
9447 "public class C {\n void small() {\n int x = 1;\n }\n void big() {\n int a = 1;\n int b = 2;\n int c = 3;\n }\n}\n",
9448 "C.java",
9449 |metric| {
9450 let loc = &metric.loc;
9452 assert!(loc.sloc_min() <= loc.sloc());
9453 assert_eq!(loc.sloc_min(), 3, "smallest leaf method span");
9454 assert_eq!(loc.sloc_max(), loc.sloc());
9455 assert_eq!(loc.lloc_min(), 1);
9456 },
9457 );
9458 }
9459
9460 #[test]
9464 fn python_nested_min_max_propagates() {
9465 check_metrics::<PythonParser>(
9466 "class C:\n def small(self):\n x = 1\n def big(self):\n a = 1\n b = 2\n c = 3\n",
9467 "c.py",
9468 |metric| {
9469 let loc = &metric.loc;
9471 assert!(loc.sloc_min() <= loc.sloc());
9472 assert_eq!(loc.sloc_min(), 2, "smallest leaf method span");
9473 assert_eq!(loc.sloc_max(), loc.sloc());
9474 assert_eq!(loc.lloc_min(), 1);
9475 },
9476 );
9477 }
9478
9479 #[test]
9492 fn blank_clamps_negative_to_zero() {
9493 let mut stats = Stats::default();
9494 stats.sloc.start = 0;
9496 stats.sloc.end_line = 1;
9498 stats.ploc.lines.insert(0);
9500 stats.cloc.only_comment_line_starts.insert(0);
9502
9503 assert_eq!(stats.sloc(), 1);
9505 assert_eq!(stats.ploc(), 1);
9506 assert_eq!(
9507 stats.blank(),
9508 0,
9509 "blank() must clamp the negative subtraction to 0"
9510 );
9511 }
9512
9513 #[test]
9528 fn sibling_spaces_sharing_a_line_count_it_once() {
9529 check_metrics::<RustParser>(
9530 "fn a() { let x = 1; } fn b() { let y = 2; }",
9531 "foo.rs",
9532 |metric| {
9533 assert_eq!(metric.loc.sloc(), 1);
9534 assert_eq!(metric.loc.ploc(), 1, "one physical row, two spaces");
9535 assert_eq!(metric.loc.blank(), 0);
9536 },
9537 );
9538
9539 check_metrics::<CppParser>(
9540 "int a() { return 1; } int b() { return 2; }",
9541 "foo.cpp",
9542 |metric| {
9543 assert_eq!(metric.loc.sloc(), 1);
9544 assert_eq!(metric.loc.ploc(), 1, "one physical row, two spaces");
9545 assert_eq!(metric.loc.blank(), 0);
9546 },
9547 );
9548
9549 check_metrics::<JavascriptParser>(
9550 "function a() { let x = 1; } function b() { let y = 2; }",
9551 "foo.js",
9552 |metric| {
9553 assert_eq!(metric.loc.sloc(), 1);
9554 assert_eq!(metric.loc.ploc(), 1, "one physical row, two spaces");
9555 assert_eq!(metric.loc.blank(), 0);
9556 },
9557 );
9558
9559 check_metrics::<PythonParser>(
9563 "def a():
9564 def b(): return 1",
9565 "foo.py",
9566 |metric| {
9567 assert_eq!(metric.loc.sloc(), 2);
9568 assert_eq!(metric.loc.ploc(), 2, "two physical rows, three spaces");
9569 assert_eq!(metric.loc.blank(), 0);
9570 },
9571 );
9572 }
9573
9574 #[test]
9582 fn sibling_spaces_sharing_a_comment_line_count_it_once() {
9583 check_metrics::<CppParser>(
9584 "int a() { /*x*/ return 1; } int b() { /*y*/ return 2; }",
9585 "foo.cpp",
9586 |metric| {
9587 assert_eq!(metric.loc.sloc(), 1);
9588 assert_eq!(metric.loc.cloc(), 1, "one comment row, two spaces");
9589 assert!(
9590 metric.loc.cloc() <= metric.loc.sloc(),
9591 "cloc must never exceed sloc"
9592 );
9593 },
9594 );
9595
9596 check_metrics::<RustParser>(
9597 "fn a() { /*x*/ let p = 1; } fn b() { /*y*/ let q = 2; }",
9598 "foo.rs",
9599 |metric| {
9600 assert_eq!(metric.loc.sloc(), 1);
9601 assert_eq!(metric.loc.cloc(), 1, "one comment row, two spaces");
9602 assert!(
9603 metric.loc.cloc() <= metric.loc.sloc(),
9604 "cloc must never exceed sloc"
9605 );
9606 },
9607 );
9608 }
9609
9610 #[test]
9618 fn a_row_folded_through_nested_spaces_counts_once() {
9619 const DEPTH: usize = 15;
9620 let source = format!(
9621 "{}let x = 1;{}",
9622 "fn f() { ".repeat(DEPTH),
9623 "} ".repeat(DEPTH)
9624 );
9625
9626 check_metrics::<RustParser>(&source, "foo.rs", |metric| {
9627 assert_eq!(metric.loc.sloc(), 1);
9628 assert_eq!(metric.loc.ploc(), 1, "one physical row, {DEPTH} spaces");
9629 assert_eq!(metric.loc.ploc_max(), 1);
9630 assert_eq!(metric.loc.blank(), 0);
9631 });
9632 }
9633
9634 #[test]
9642 fn cloc_multiple_block_comments_one_line_cpp() {
9643 check_metrics::<CppParser>(
9644 "int f(int /*a*/, int /*b*/) { return 1; }",
9645 "foo.cpp",
9646 |metric| {
9647 assert_eq!(metric.loc.cloc(), 1, "two inline comments => 1 cloc");
9648 assert!(
9649 metric.loc.cloc() <= metric.loc.sloc(),
9650 "cloc must not exceed sloc"
9651 );
9652 assert!(
9653 metric.loc.cloc() <= metric.loc.ploc(),
9654 "cloc must not exceed ploc for a single-line construct"
9655 );
9656 },
9657 );
9658 }
9659
9660 #[test]
9664 fn cloc_multiple_block_comments_one_line_rust() {
9665 check_metrics::<RustParser>(
9666 "fn f(/*a*/ x: i32, /*b*/ y: i32) -> i32 { 1 }",
9667 "foo.rs",
9668 |metric| {
9669 assert_eq!(metric.loc.cloc(), 1, "two inline comments => 1 cloc");
9670 assert!(
9671 metric.loc.cloc() <= metric.loc.sloc(),
9672 "cloc must not exceed sloc"
9673 );
9674 },
9675 );
9676 }
9677
9678 #[test]
9683 fn cloc_multiline_block_comment_counts_each_line() {
9684 check_metrics::<CppParser>(
9685 "int g() {\n /* l1\n l2\n l3 */\n return 0;\n}",
9686 "foo.cpp",
9687 |metric| {
9688 assert_eq!(
9689 metric.loc.cloc(),
9690 3,
9691 "a 3-line block comment counts 3 comment lines"
9692 );
9693 },
9694 );
9695 }
9696
9697 #[test]
9706 fn cloc_multiple_standalone_block_comments_one_line_cpp() {
9707 check_metrics::<CppParser>("/*a*/ /*b*/", "foo.cpp", |metric| {
9708 assert_eq!(
9709 metric.loc.cloc(),
9710 1,
9711 "two standalone comments on one line => 1 cloc"
9712 );
9713 assert_eq!(metric.loc.sloc(), 1);
9714 assert!(
9715 metric.loc.cloc() <= metric.loc.sloc(),
9716 "cloc must not exceed sloc"
9717 );
9718 });
9719 }
9720
9721 #[test]
9725 fn cloc_multiple_standalone_block_comments_one_line_rust() {
9726 check_metrics::<RustParser>("/*a*/ /*b*/", "foo.rs", |metric| {
9727 assert_eq!(
9728 metric.loc.cloc(),
9729 1,
9730 "two standalone comments on one line => 1 cloc"
9731 );
9732 assert_eq!(metric.loc.sloc(), 1);
9733 assert!(
9734 metric.loc.cloc() <= metric.loc.sloc(),
9735 "cloc must not exceed sloc"
9736 );
9737 });
9738 }
9739
9740 #[test]
9747 fn cloc_standalone_comments_then_code_no_double_count() {
9748 check_metrics::<CppParser>("/*a*/ /*b*/ /*c*/\nint x = 1;\n", "foo.cpp", |metric| {
9749 assert_eq!(metric.loc.sloc(), 2);
9750 assert_eq!(
9751 metric.loc.cloc(),
9752 1,
9753 "only line 1 carries comments => 1 cloc"
9754 );
9755 assert!(
9756 metric.loc.cloc() <= metric.loc.sloc(),
9757 "cloc must not exceed sloc"
9758 );
9759 });
9760 }
9761
9762 #[test]
9766 fn irules_blank() {
9767 check_metrics::<IrulesParser>(
9768 "when X {\n\n set x 1\n\n set y 2\n}\n",
9769 "foo.irule",
9770 |metric| {
9771 assert_eq!(metric.loc.sloc(), 6);
9772 assert_eq!(metric.loc.ploc(), 4);
9773 assert_eq!(metric.loc.lloc(), 3);
9774 assert_eq!(metric.loc.cloc(), 0);
9775 assert_eq!(metric.loc.blank(), 2);
9776 },
9777 );
9778 }
9779
9780 #[test]
9783 fn irules_no_zero_blank() {
9784 check_metrics::<IrulesParser>(
9785 "when HTTP_REQUEST {\n set x 1\n log local0. $x\n}\n",
9786 "foo.irule",
9787 |metric| {
9788 assert_eq!(metric.loc.sloc(), 4);
9789 assert_eq!(metric.loc.ploc(), 4);
9790 assert_eq!(metric.loc.lloc(), 3);
9791 assert_eq!(metric.loc.blank(), 0);
9792 },
9793 );
9794 }
9795
9796 #[test]
9805 fn irules_cloc() {
9806 check_metrics::<IrulesParser>(
9807 "# a\n# b\n# c\nwhen X { set x 1 }\n",
9808 "foo.irule",
9809 |metric| {
9810 assert_eq!(metric.loc.sloc(), 4);
9811 assert_eq!(metric.loc.ploc(), 1);
9812 assert_eq!(metric.loc.cloc(), 3);
9813 assert_eq!(metric.loc.blank(), 0);
9814 },
9815 );
9816 }
9817
9818 #[test]
9822 fn irules_lloc() {
9823 check_metrics::<IrulesParser>(
9824 "when X {\n if { $a } {\n set x 1\n }\n log local0. done\n}\n",
9825 "foo.irule",
9826 |metric| {
9827 assert_eq!(metric.loc.lloc(), 4);
9828 },
9829 );
9830 }
9831
9832 #[test]
9838 fn irules_no_command_substitution_lloc() {
9839 check_metrics::<IrulesParser>(
9840 "when X {\n set y [expr { 1 + 2 }]\n}\n",
9841 "foo.irule",
9842 |metric| {
9843 assert_eq!(metric.loc.lloc(), 2);
9844 },
9845 );
9846 }
9847
9848 #[test]
9852 fn irules_switch_lloc() {
9853 check_metrics::<IrulesParser>(
9854 "when X {\n switch $h {\n a { set r 1 }\n b { set r 2 }\n }\n}\n",
9855 "foo.irule",
9856 |metric| {
9857 assert_eq!(metric.loc.lloc(), 4);
9858 },
9859 );
9860 }
9861
9862 #[test]
9865 fn irules_proc_lloc() {
9866 check_metrics::<IrulesParser>(
9867 "proc f { a } {\n return $a\n}\n",
9868 "foo.irule",
9869 |metric| {
9870 assert_eq!(metric.loc.lloc(), 2);
9871 },
9872 );
9873 }
9874
9875 #[test]
9878 fn objc_blank() {
9879 check_metrics::<ObjcParser>(
9880 "
9881
9882 int a = 42;
9883
9884 int b = 43;
9885
9886 ",
9887 "foo.m",
9888 |metric| {
9889 assert_eq!(metric.loc.blank(), 1);
9890 insta::assert_json_snapshot!(metric.loc, @r#"
9891 {
9892 "sloc": 3,
9893 "ploc": 2,
9894 "lloc": 2,
9895 "cloc": 0,
9896 "blank": 1,
9897 "sloc_average": 3.0,
9898 "ploc_average": 2.0,
9899 "lloc_average": 2.0,
9900 "cloc_average": 0.0,
9901 "blank_average": 1.0,
9902 "sloc_min": 3,
9903 "sloc_max": 3,
9904 "cloc_min": 0,
9905 "cloc_max": 0,
9906 "ploc_min": 2,
9907 "ploc_max": 2,
9908 "lloc_min": 2,
9909 "lloc_max": 2,
9910 "blank_min": 1,
9911 "blank_max": 1
9912 }
9913 "#);
9914 },
9915 );
9916 }
9917
9918 #[test]
9921 fn objc_cloc() {
9922 check_metrics::<ObjcParser>(
9923 "/* Block comment
9924 still the block */
9925 // Line comment
9926 int a = 42; // trailing",
9927 "foo.m",
9928 |metric| {
9929 insta::assert_json_snapshot!(metric.loc, @r#"
9930 {
9931 "sloc": 4,
9932 "ploc": 1,
9933 "lloc": 1,
9934 "cloc": 4,
9935 "blank": 0,
9936 "sloc_average": 4.0,
9937 "ploc_average": 1.0,
9938 "lloc_average": 1.0,
9939 "cloc_average": 4.0,
9940 "blank_average": 0.0,
9941 "sloc_min": 4,
9942 "sloc_max": 4,
9943 "cloc_min": 4,
9944 "cloc_max": 4,
9945 "ploc_min": 1,
9946 "ploc_max": 1,
9947 "lloc_min": 1,
9948 "lloc_max": 1,
9949 "blank_min": 0,
9950 "blank_max": 0
9951 }
9952 "#);
9953 },
9954 );
9955 }
9956
9957 #[test]
9961 fn objc_lloc() {
9962 check_metrics::<ObjcParser>(
9963 "@implementation Foo
9964- (int)bar {
9965 int a = 1;
9966 int b = 2;
9967 return a + b;
9968}
9969@end
9970",
9971 "foo.m",
9972 |metric| {
9973 assert_eq!(metric.loc.lloc(), 3);
9976 insta::assert_json_snapshot!(metric.loc, @r#"
9977 {
9978 "sloc": 7,
9979 "ploc": 7,
9980 "lloc": 3,
9981 "cloc": 0,
9982 "blank": 0,
9983 "sloc_average": 2.3333333333333335,
9984 "ploc_average": 2.3333333333333335,
9985 "lloc_average": 1.0,
9986 "cloc_average": 0.0,
9987 "blank_average": 0.0,
9988 "sloc_min": 5,
9989 "sloc_max": 7,
9990 "cloc_min": 0,
9991 "cloc_max": 0,
9992 "ploc_min": 5,
9993 "ploc_max": 7,
9994 "lloc_min": 3,
9995 "lloc_max": 3,
9996 "blank_min": 0,
9997 "blank_max": 0
9998 }
9999 "#);
10000 },
10001 );
10002 }
10003
10004 #[test]
10010 fn objc_no_declaration_in_for_header_lloc() {
10011 check_metrics::<ObjcParser>(
10012 "@implementation Foo
10013- (void)bar {
10014 for (int i = 0; i < 10; ++i) {
10015 [self use:i];
10016 }
10017}
10018@end
10019",
10020 "foo.m",
10021 |metric| {
10022 assert_eq!(metric.loc.lloc(), 2);
10026 insta::assert_json_snapshot!(metric.loc, @r#"
10027 {
10028 "sloc": 7,
10029 "ploc": 7,
10030 "lloc": 2,
10031 "cloc": 0,
10032 "blank": 0,
10033 "sloc_average": 2.3333333333333335,
10034 "ploc_average": 2.3333333333333335,
10035 "lloc_average": 0.6666666666666666,
10036 "cloc_average": 0.0,
10037 "blank_average": 0.0,
10038 "sloc_min": 5,
10039 "sloc_max": 7,
10040 "cloc_min": 0,
10041 "cloc_max": 0,
10042 "ploc_min": 5,
10043 "ploc_max": 7,
10044 "lloc_min": 2,
10045 "lloc_max": 2,
10046 "blank_min": 0,
10047 "blank_max": 0
10048 }
10049 "#);
10050 },
10051 );
10052 }
10053
10054 #[test]
10055 fn objc_at_directives_lloc() {
10056 check_metrics::<ObjcParser>(
10062 "@implementation Foo
10063- (void)bar {
10064 @synchronized (self) {
10065 [self use];
10066 }
10067 @autoreleasepool {
10068 [self use];
10069 }
10070}
10071@end
10072",
10073 "foo.m",
10074 |metric| {
10075 assert_eq!(metric.loc.lloc(), 3);
10080 insta::assert_json_snapshot!(metric.loc, @r#"
10081 {
10082 "sloc": 10,
10083 "ploc": 10,
10084 "lloc": 3,
10085 "cloc": 0,
10086 "blank": 0,
10087 "sloc_average": 3.3333333333333335,
10088 "ploc_average": 3.3333333333333335,
10089 "lloc_average": 1.0,
10090 "cloc_average": 0.0,
10091 "blank_average": 0.0,
10092 "sloc_min": 8,
10093 "sloc_max": 10,
10094 "cloc_min": 0,
10095 "cloc_max": 0,
10096 "ploc_min": 8,
10097 "ploc_max": 10,
10098 "lloc_min": 3,
10099 "lloc_max": 3,
10100 "blank_min": 0,
10101 "blank_max": 0
10102 }
10103 "#);
10104 },
10105 );
10106 }
10107
10108 fn rust_loc(source: &[u8]) -> Stats {
10113 metrics_verbatim(crate::LANG::Rust, source, crate::MetricsOptions::default()).loc
10114 }
10115
10116 #[test]
10123 fn rust_doc_comment_at_eof_does_not_underflow() {
10124 let outer = rust_loc(b"/// x");
10127 assert_eq!(outer.cloc(), 1);
10128 assert_eq!(outer.ploc(), 0);
10129
10130 let inner = rust_loc(b"//! x");
10131 assert_eq!(inner.cloc(), 1);
10132 assert_eq!(inner.ploc(), 0);
10133
10134 let after_code = rust_loc(b"fn f(){}\n/// x");
10138 assert_eq!(after_code.cloc(), 1);
10139 assert_eq!(after_code.ploc(), 1);
10140
10141 assert_eq!(rust_loc(b"/// a\n/// b").cloc(), 2);
10144
10145 let trailing = rust_loc(b"let x = 1; /// d");
10150 assert_eq!(trailing.cloc(), 1);
10151 assert_eq!(trailing.ploc(), 1);
10152 }
10153
10154 #[test]
10159 fn rust_doc_comment_at_eof_matches_plain_comment() {
10160 let plain = rust_loc(b"// x");
10161 assert_eq!(plain.cloc(), 1);
10165 assert_eq!(plain.ploc(), 0);
10166
10167 for doc in [&b"/// x"[..], &b"//! x"[..]] {
10168 let doc = rust_loc(doc);
10169 assert_eq!(doc.cloc(), plain.cloc());
10170 assert_eq!(doc.ploc(), plain.ploc());
10171 assert_eq!(doc.sloc(), plain.sloc());
10172 assert_eq!(doc.blank(), plain.blank());
10173 }
10174 }
10175
10176 #[test]
10182 fn rust_doc_comment_with_trailing_newline_still_discounts_the_row() {
10183 assert_eq!(rust_loc(b"/// x\n").cloc(), 1);
10185 assert_eq!(rust_loc(b"/// a\n/// b\n").cloc(), 2);
10187
10188 let documented = rust_loc(b"/// doc\nfn f() {}\n");
10191 assert_eq!(documented.cloc(), 1);
10192 assert_eq!(documented.ploc(), 1);
10193 }
10194
10195 #[test]
10202 fn rust_doc_comment_crlf_still_discounts_the_row() {
10203 assert_eq!(rust_loc(b"/// x\r\n").cloc(), 1);
10205 let after_code = rust_loc(b"fn f(){}\r\n/// x");
10207 assert_eq!(after_code.cloc(), 1);
10208 assert_eq!(after_code.ploc(), 1);
10209 assert_eq!(rust_loc(b"/// x\r").cloc(), 1);
10211 }
10212
10213 const UNTERMINATED_ONE_LINERS: &[(crate::LANG, &[u8])] = &[
10236 (crate::LANG::Rust, b"fn main() {}"),
10237 (crate::LANG::C, b"int main(void) { return 0; }"),
10238 (crate::LANG::Cpp, b"int main() { return 0; }"),
10239 (crate::LANG::Mozcpp, b"int main() { return 0; }"),
10240 (crate::LANG::Objc, b"int main(void) { return 0; }"),
10241 (crate::LANG::Csharp, b"class C { void M() {} }"),
10242 (crate::LANG::Java, b"class C { void m() {} }"),
10243 (crate::LANG::Kotlin, b"fun main() {}"),
10244 (crate::LANG::Groovy, b"def f() {}"),
10245 (crate::LANG::Go, b"package main"),
10246 (crate::LANG::Javascript, b"function f() {}"),
10247 (crate::LANG::Mozjs, b"function f() {}"),
10248 (crate::LANG::Typescript, b"function f(): void {}"),
10249 (crate::LANG::Tsx, b"function f() {}"),
10250 (crate::LANG::Python, b"def f(): pass"),
10251 (crate::LANG::Ruby, b"def f; end"),
10252 (crate::LANG::Php, b"<?php function f() {}"),
10253 (crate::LANG::Perl, b"sub f { return 1; }"),
10254 (crate::LANG::Bash, b"f() { echo hi; }"),
10255 (crate::LANG::Lua, b"function f() end"),
10256 (crate::LANG::Tcl, b"proc f {} {}"),
10257 (crate::LANG::Irules, b"proc f {} {}"),
10258 (crate::LANG::Elixir, b"defmodule M do end"),
10259 ];
10260
10261 #[test]
10272 fn unterminated_one_line_file_reports_one_source_line() {
10273 for (lang, source) in UNTERMINATED_ONE_LINERS {
10274 let text = String::from_utf8_lossy(source);
10275 let loc = metrics_verbatim(*lang, source, MetricsOptions::default()).loc;
10276 assert_eq!(loc.sloc(), 1, "{lang:?} sloc for {text:?}");
10277 assert_eq!(loc.sloc_max(), 1, "{lang:?} sloc_max for {text:?}");
10279 assert!(
10285 loc.cloc() + loc.ploc() <= loc.sloc(),
10286 "{lang:?}: cloc {} + ploc {} exceeds sloc {} for {text:?}",
10287 loc.cloc(),
10288 loc.ploc(),
10289 loc.sloc(),
10290 );
10291 }
10292 }
10293
10294 #[test]
10305 fn no_op_loc_grammars_still_count_their_unterminated_row() {
10306 for (lang, source) in [
10307 (crate::LANG::Preproc, &b"#define A 1"[..]),
10308 (crate::LANG::Ccomment, &b"/* c */"[..]),
10309 ] {
10310 let bare = metrics_verbatim(lang, source, MetricsOptions::default()).loc;
10311 assert_eq!(bare.sloc(), 1, "{lang:?} unterminated sloc");
10312 let mut terminated = source.to_vec();
10313 terminated.push(b'\n');
10314 let terminated = metrics_verbatim(lang, &terminated, MetricsOptions::default()).loc;
10315 assert_eq!(
10316 bare.sloc(),
10317 terminated.sloc(),
10318 "{lang:?} sloc must not depend on the trailing newline"
10319 );
10320 assert_eq!((bare.ploc(), bare.cloc(), bare.lloc()), (0, 0, 0));
10322 }
10323 }
10324
10325 #[test]
10342 fn a_continued_macro_body_counts_every_row_it_spans() {
10343 const CONTINUED_MACRO: &[u8] =
10345 b"#define SUM(a, b) \\\n ((a) + \\\n (b))\n\nint main(void) { return SUM(1, 2); }\n";
10346
10347 for lang in [
10348 crate::LANG::C,
10349 crate::LANG::Cpp,
10350 crate::LANG::Mozcpp,
10351 crate::LANG::Objc,
10352 ] {
10353 let loc = metrics_verbatim(lang, CONTINUED_MACRO, MetricsOptions::default()).loc;
10354 assert_eq!(
10355 loc.ploc(),
10356 4,
10357 "{lang:?}: every continuation row of the macro body is code"
10358 );
10359 assert_eq!(loc.sloc(), 5, "{lang:?} sloc");
10360 assert_eq!(loc.lloc(), 1, "{lang:?} lloc");
10361 assert_eq!(loc.cloc(), 0, "{lang:?} cloc");
10362 assert_eq!(loc.blank(), 1, "{lang:?} blank");
10363 }
10364 }
10365
10366 #[test]
10383 fn trailing_newline_does_not_change_loc_or_mi() {
10384 for (lang, source) in UNTERMINATED_ONE_LINERS {
10385 let text = String::from_utf8_lossy(source);
10386 let bare = metrics_verbatim(*lang, source, MetricsOptions::default());
10387 let mut newline_terminated = source.to_vec();
10388 newline_terminated.push(b'\n');
10389 let terminated =
10390 metrics_verbatim(*lang, &newline_terminated, MetricsOptions::default());
10391
10392 assert_eq!(
10393 bare.loc.sloc(),
10394 terminated.loc.sloc(),
10395 "{lang:?} sloc {text:?}"
10396 );
10397 assert_eq!(
10398 bare.loc.ploc(),
10399 terminated.loc.ploc(),
10400 "{lang:?} ploc {text:?}"
10401 );
10402 assert_eq!(
10403 bare.loc.cloc(),
10404 terminated.loc.cloc(),
10405 "{lang:?} cloc {text:?}"
10406 );
10407 assert_eq!(
10408 bare.loc.lloc(),
10409 terminated.loc.lloc(),
10410 "{lang:?} lloc {text:?}"
10411 );
10412 assert_eq!(
10413 bare.loc.blank(),
10414 terminated.loc.blank(),
10415 "{lang:?} blank {text:?}"
10416 );
10417 assert_eq!(
10423 bare.mi.original(),
10424 terminated.mi.original(),
10425 "{lang:?} mi {text:?}"
10426 );
10427 assert_eq!(
10428 bare.mi.sei(),
10429 terminated.mi.sei(),
10430 "{lang:?} mi.sei {text:?}"
10431 );
10432 assert_eq!(
10433 bare.mi.visual_studio(),
10434 terminated.mi.visual_studio(),
10435 "{lang:?} mi.visual_studio {text:?}",
10436 );
10437 assert_ne!(bare.mi.original(), 0.0, "{lang:?} mi must not be zeroed");
10438 }
10439 }
10440
10441 #[test]
10445 fn unterminated_trailing_comment_upholds_the_cloc_ploc_invariant() {
10446 let loc = rust_loc(b"fn f(){}\n/// x");
10448 assert_eq!(loc.sloc(), 2);
10449 assert_eq!(loc.ploc(), 1);
10450 assert_eq!(loc.cloc(), 1);
10451 assert_eq!(loc.blank(), 0);
10452 }
10453
10454 #[test]
10458 fn degenerate_inputs_report_their_real_row_count() {
10459 assert_eq!(rust_loc(b"").sloc(), 0);
10461 let spaces = rust_loc(b" ");
10464 assert_eq!(spaces.sloc(), 1);
10465 assert_eq!(spaces.blank(), 1);
10466 let one = rust_loc(b"\n");
10474 assert_eq!((one.sloc(), one.ploc(), one.blank()), (1, 0, 1));
10475 let two = rust_loc(b"\n\n");
10476 assert_eq!((two.sloc(), two.ploc(), two.blank()), (2, 0, 2));
10477 }
10478
10479 fn all_loc_grammars() -> impl Iterator<Item = crate::LANG> {
10488 UNTERMINATED_ONE_LINERS
10489 .iter()
10490 .map(|(lang, _)| *lang)
10491 .chain([crate::LANG::Preproc, crate::LANG::Ccomment])
10492 }
10493
10494 #[test]
10513 fn whitespace_only_input_is_uniform_across_grammars() {
10514 for bare in [&b" "[..], b"\t\t"] {
10517 let mut newline_terminated = bare.to_vec();
10518 newline_terminated.push(b'\n');
10519 for lang in all_loc_grammars() {
10520 let text = String::from_utf8_lossy(bare);
10521 let unterminated = metrics_verbatim(lang, bare, MetricsOptions::default()).loc;
10522 let terminated =
10523 metrics_verbatim(lang, &newline_terminated, MetricsOptions::default()).loc;
10524
10525 assert_eq!(
10526 (unterminated.sloc(), unterminated.blank()),
10527 (1, 1),
10528 "{lang:?}: unterminated {text:?} is one blank row for every grammar"
10529 );
10530
10531 assert_eq!(
10532 (terminated.sloc(), terminated.blank()),
10533 (1, 1),
10534 "{lang:?}: newline-terminated {text:?} is the same one blank \
10535 row — whether the grammar collapses its root at \
10536 end-of-input is no longer observable in loc (#1247)"
10537 );
10538
10539 for loc in [&unterminated, &terminated] {
10544 assert_eq!(
10545 (loc.ploc(), loc.cloc(), loc.lloc()),
10546 (0, 0, 0),
10547 "{lang:?}: whitespace is neither code nor comment"
10548 );
10549 }
10550 }
10551 }
10552 }
10553
10554 #[test]
10570 fn leading_blank_rows_count_in_the_units_sloc_and_blank() {
10571 const LEADING_BLANKS: u64 = 3;
10572 for (lang, body, ploc) in [
10573 (crate::LANG::Rust, &b"fn a() {}\n"[..], 1),
10574 (crate::LANG::Python, b"def a():\n pass\n", 2),
10575 (crate::LANG::C, b"int f() { return 0; }\n", 1),
10576 (crate::LANG::Tcl, b"puts hi\n", 1),
10577 ] {
10578 let mut source = vec![b'\n'; LEADING_BLANKS as usize];
10579 source.extend_from_slice(body);
10580 let space = space_verbatim(lang, &source, MetricsOptions::default());
10581 let loc = &space.metrics.loc;
10582 assert_eq!(
10583 (loc.sloc(), loc.ploc(), loc.cloc(), loc.blank()),
10584 (LEADING_BLANKS + ploc, ploc, 0, LEADING_BLANKS),
10585 "{lang:?}: the leading rows are blank, not absent"
10586 );
10587 assert_eq!(
10591 loc.sloc() as usize,
10592 space.end_line - space.start_line + 1,
10593 "{lang:?}: sloc equals the rows of the unit's reported span"
10594 );
10595 }
10596 }
10597
10598 #[test]
10604 fn interior_blanks_and_leading_comments_are_unmoved_by_the_anchor() {
10605 let interior = rust_loc(b"fn a() {}\n\nfn b() {}\n");
10607 assert_eq!(
10608 (
10609 interior.sloc(),
10610 interior.ploc(),
10611 interior.cloc(),
10612 interior.blank()
10613 ),
10614 (3, 2, 0, 1)
10615 );
10616 let leading_comment = rust_loc(b"// c\n\n\nfn a() {}\n");
10618 assert_eq!(
10619 (
10620 leading_comment.sloc(),
10621 leading_comment.ploc(),
10622 leading_comment.cloc(),
10623 leading_comment.blank()
10624 ),
10625 (4, 1, 1, 2)
10626 );
10627 }
10628
10629 #[test]
10634 fn the_unit_anchor_does_not_reach_nested_spaces() {
10635 let space = space_verbatim(
10636 crate::LANG::Rust,
10637 b"\n\n\nfn a() {\n let x = 1;\n}\n",
10638 MetricsOptions::default(),
10639 );
10640 assert_eq!((space.start_line, space.end_line), (1, 6));
10641 assert_eq!(space.metrics.loc.sloc(), 6, "the file has six rows");
10642 let nested = &space.spaces[0];
10643 assert_eq!((nested.start_line, nested.end_line), (4, 6));
10644 assert_eq!(
10645 nested.metrics.loc.sloc(),
10646 3,
10647 "the function's own three rows, not the file's six"
10648 );
10649 assert_eq!(nested.metrics.loc.blank(), 0, "the function has no blanks");
10650 }
10651
10652 #[test]
10660 fn exclude_tests_pruning_composes_with_the_unit_anchor() {
10661 let source = b"\n\n\nfn a() {}\n\n#[test]\nfn t() {\n assert!(true);\n}\n";
10663 let kept = metrics_verbatim(
10664 crate::LANG::Rust,
10665 source,
10666 MetricsOptions::default().with_exclude_tests(true),
10667 )
10668 .loc;
10669 assert_eq!(
10675 (kept.sloc(), kept.ploc(), kept.cloc(), kept.blank()),
10676 (6, 2, 0, 4),
10677 "the three pruned rows leave; the three leading blanks stay"
10678 );
10679
10680 let unpruned = rust_loc(source);
10681 assert_eq!(
10682 (unpruned.sloc(), unpruned.ploc(), unpruned.blank()),
10683 (9, 5, 4),
10684 "the same file unpruned — the anchor is what makes both blank counts 4"
10685 );
10686 }
10687
10688 #[test]
10695 fn perl_last_sub_does_not_absorb_the_trailing_newline() {
10696 let space = space_verbatim(
10698 crate::LANG::Perl,
10699 b"sub f {\n return 1;\n}\nsub g {\n return 2;\n}\n",
10700 MetricsOptions::default(),
10701 );
10702 assert_eq!(space.metrics.loc.sloc(), 6, "the file has six rows");
10703 let subs: Vec<u64> = space
10704 .spaces
10705 .iter()
10706 .map(|child| child.metrics.loc.sloc())
10707 .collect();
10708 assert_eq!(subs, vec![3, 3], "both subs occupy three rows");
10709 }
10710
10711 #[test]
10726 fn tcl_family_does_not_count_terminator_rows_as_code() {
10727 for lang in [crate::LANG::Tcl, crate::LANG::Irules] {
10728 let padded = metrics_verbatim(
10730 lang,
10731 b"proc f {} {}\n \nproc g {} {}\n",
10732 MetricsOptions::default(),
10733 )
10734 .loc;
10735 assert_eq!(padded.sloc(), 3, "{lang:?} sloc");
10736 assert_eq!(padded.ploc(), 2, "{lang:?} ploc");
10737 assert_eq!(padded.blank(), 1, "{lang:?} blank");
10738
10739 let empty = metrics_verbatim(
10744 lang,
10745 b"proc f {} {}\n\nproc g {} {}\n",
10746 MetricsOptions::default(),
10747 )
10748 .loc;
10749 assert_eq!(
10750 (padded.sloc(), padded.ploc(), padded.blank()),
10751 (empty.sloc(), empty.ploc(), empty.blank()),
10752 "{lang:?}: trailing whitespace on a blank row must not make it code"
10753 );
10754
10755 let commented = metrics_verbatim(
10762 lang,
10763 b"# lead-in\nproc f {} {}\n",
10764 MetricsOptions::default(),
10765 )
10766 .loc;
10767 assert_eq!(commented.sloc(), 2, "{lang:?} commented sloc");
10768 assert_eq!(commented.ploc(), 1, "{lang:?} commented ploc");
10769 assert_eq!(commented.cloc(), 1, "{lang:?} commented cloc");
10770 assert_eq!(commented.blank(), 0, "{lang:?} commented blank");
10771 }
10772 }
10773
10774 fn comment_spellings(lang: crate::LANG) -> &'static [&'static str] {
10783 use crate::LANG::*;
10784 match lang {
10785 Python | Ruby | Bash | Elixir | Tcl | Irules | Perl => &["# c"],
10786 Lua => &["-- c", "--[[ c ]]"],
10787 Php => &["# c", "/* c */", "/** c */"],
10788 Rust => &["// c", "/* c */", "/// c"],
10789 _ => &["// c", "/* c */"],
10790 }
10791 }
10792
10793 #[test]
10811 fn a_comment_row_is_never_counted_as_code() {
10812 for (lang, code) in UNTERMINATED_ONE_LINERS {
10813 let must_lead = *lang == crate::LANG::Php;
10817 for &comment in comment_spellings(*lang) {
10818 let orders: &[bool] = if must_lead { &[false] } else { &[true, false] };
10819 for &comment_first in orders {
10820 let mut src = Vec::new();
10821 let (first, second): (&[u8], &[u8]) = if comment_first {
10822 (comment.as_bytes(), code)
10823 } else {
10824 (code, comment.as_bytes())
10825 };
10826 src.extend_from_slice(first);
10827 src.push(b'\n');
10828 src.extend_from_slice(second);
10829 src.push(b'\n');
10830
10831 let loc = metrics_verbatim(*lang, &src, MetricsOptions::default()).loc;
10832 let text = String::from_utf8_lossy(&src);
10833 assert_eq!(loc.sloc(), 2, "{lang:?} sloc for {text:?}");
10834 assert_eq!(
10835 loc.ploc(),
10836 1,
10837 "{lang:?} ploc for {text:?} — the comment row is not code"
10838 );
10839 assert_eq!(loc.cloc(), 1, "{lang:?} cloc for {text:?}");
10840 assert_eq!(loc.blank(), 0, "{lang:?} blank for {text:?}");
10841 }
10842 }
10843 }
10844 }
10845
10846 #[test]
10854 fn javascript_declaration_lloc() {
10855 check_metrics::<JavascriptParser>(
10856 "var a = 1;\nlet b = 2;\nconst c = 3;\nvar d = 4, e = 5;\nusing r = open();\n",
10857 "foo.js",
10858 |metric| {
10859 assert_eq!(metric.loc.sloc(), 5);
10860 assert_eq!(metric.loc.ploc(), 5);
10861 assert_eq!(metric.loc.lloc(), 5);
10862 assert_eq!(metric.loc.cloc(), 0);
10863 assert_eq!(metric.loc.blank(), 0);
10864 },
10865 );
10866 }
10867
10868 #[test]
10879 fn javascript_for_header_declaration_not_double_counted() {
10880 check_metrics::<JavascriptParser>(
10881 "function f(arr, obj) {\n for (var i = 0; i < 3; i++) {\n var s = i;\n }\n for (const x of arr) {}\n for (var k in obj) {}\n}\n",
10882 "foo.js",
10883 |metric| {
10884 assert_eq!(metric.loc.sloc(), 7);
10885 assert_eq!(metric.loc.ploc(), 7);
10886 assert_eq!(metric.loc.lloc(), 4);
10887 assert_eq!(metric.loc.cloc(), 0);
10888 assert_eq!(metric.loc.blank(), 0);
10889 },
10890 );
10891 }
10892
10893 #[test]
10901 fn javascript_exported_declaration_counts_once() {
10902 check_metrics::<JavascriptParser>(
10903 "export const a = 1;\nexport let b = 2;\nexport default 3;\nexport function f() { const c = 4; }\n",
10904 "foo.js",
10905 |metric| {
10906 assert_eq!(metric.loc.sloc(), 4);
10907 assert_eq!(metric.loc.ploc(), 4);
10908 assert_eq!(metric.loc.lloc(), 5);
10909 assert_eq!(metric.loc.cloc(), 0);
10910 assert_eq!(metric.loc.blank(), 0);
10911 },
10912 );
10913 }
10914
10915 #[test]
10923 fn mozjs_declaration_lloc() {
10924 check_metrics::<MozjsParser>(
10925 "var a = 1;\nlet b = 2;\nconst c = 3;\nvar d = 4, e = 5;\nusing r = open();\n",
10926 "foo.js",
10927 |metric| {
10928 assert_eq!(metric.loc.sloc(), 5);
10929 assert_eq!(metric.loc.ploc(), 5);
10930 assert_eq!(metric.loc.lloc(), 5);
10931 assert_eq!(metric.loc.cloc(), 0);
10932 assert_eq!(metric.loc.blank(), 0);
10933 },
10934 );
10935 }
10936
10937 #[test]
10948 fn mozjs_for_header_declaration_not_double_counted() {
10949 check_metrics::<MozjsParser>(
10950 "function f(arr, obj) {\n for (var i = 0; i < 3; i++) {\n var s = i;\n }\n for (const x of arr) {}\n for (var k in obj) {}\n}\n",
10951 "foo.js",
10952 |metric| {
10953 assert_eq!(metric.loc.sloc(), 7);
10954 assert_eq!(metric.loc.ploc(), 7);
10955 assert_eq!(metric.loc.lloc(), 4);
10956 assert_eq!(metric.loc.cloc(), 0);
10957 assert_eq!(metric.loc.blank(), 0);
10958 },
10959 );
10960 }
10961
10962 #[test]
10970 fn mozjs_exported_declaration_counts_once() {
10971 check_metrics::<MozjsParser>(
10972 "export const a = 1;\nexport let b = 2;\nexport default 3;\nexport function f() { const c = 4; }\n",
10973 "foo.js",
10974 |metric| {
10975 assert_eq!(metric.loc.sloc(), 4);
10976 assert_eq!(metric.loc.ploc(), 4);
10977 assert_eq!(metric.loc.lloc(), 5);
10978 assert_eq!(metric.loc.cloc(), 0);
10979 assert_eq!(metric.loc.blank(), 0);
10980 },
10981 );
10982 }
10983
10984 #[test]
10990 fn typescript_declaration_lloc() {
10991 check_metrics::<TypescriptParser>(
10992 "var a: number = 1;\nlet b = 2;\nconst c = 3;\nvar d = 4, e = 5;\n",
10993 "foo.ts",
10994 |metric| {
10995 assert_eq!(metric.loc.sloc(), 4);
10996 assert_eq!(metric.loc.ploc(), 4);
10997 assert_eq!(metric.loc.lloc(), 4);
10998 assert_eq!(metric.loc.cloc(), 0);
10999 assert_eq!(metric.loc.blank(), 0);
11000 },
11001 );
11002 }
11003
11004 #[test]
11015 fn typescript_for_header_declaration_not_double_counted() {
11016 check_metrics::<TypescriptParser>(
11017 "function f(arr, obj) {\n for (var i = 0; i < 3; i++) {\n var s = i;\n }\n for (const x of arr) {}\n for (var k in obj) {}\n}\n",
11018 "foo.ts",
11019 |metric| {
11020 assert_eq!(metric.loc.sloc(), 7);
11021 assert_eq!(metric.loc.ploc(), 7);
11022 assert_eq!(metric.loc.lloc(), 4);
11023 assert_eq!(metric.loc.cloc(), 0);
11024 assert_eq!(metric.loc.blank(), 0);
11025 },
11026 );
11027 }
11028
11029 #[test]
11042 fn typescript_exported_declaration_counts_once() {
11043 check_metrics::<TypescriptParser>(
11044 "export const a: number = 1;\nexport declare const b: string;\nexport default 3;\nexport function f(): void { const c = 4; }\n",
11045 "foo.ts",
11046 |metric| {
11047 assert_eq!(metric.loc.sloc(), 4);
11048 assert_eq!(metric.loc.ploc(), 4);
11049 assert_eq!(metric.loc.lloc(), 5);
11050 assert_eq!(metric.loc.cloc(), 0);
11051 assert_eq!(metric.loc.blank(), 0);
11052 },
11053 );
11054 }
11055
11056 #[test]
11062 fn tsx_declaration_lloc() {
11063 check_metrics::<TsxParser>(
11064 "var a: number = 1;\nlet b = 2;\nconst c = 3;\nvar d = 4, e = 5;\n",
11065 "foo.tsx",
11066 |metric| {
11067 assert_eq!(metric.loc.sloc(), 4);
11068 assert_eq!(metric.loc.ploc(), 4);
11069 assert_eq!(metric.loc.lloc(), 4);
11070 assert_eq!(metric.loc.cloc(), 0);
11071 assert_eq!(metric.loc.blank(), 0);
11072 },
11073 );
11074 }
11075
11076 #[test]
11087 fn tsx_for_header_declaration_not_double_counted() {
11088 check_metrics::<TsxParser>(
11089 "function f(arr, obj) {\n for (var i = 0; i < 3; i++) {\n var s = i;\n }\n for (const x of arr) {}\n for (var k in obj) {}\n}\n",
11090 "foo.tsx",
11091 |metric| {
11092 assert_eq!(metric.loc.sloc(), 7);
11093 assert_eq!(metric.loc.ploc(), 7);
11094 assert_eq!(metric.loc.lloc(), 4);
11095 assert_eq!(metric.loc.cloc(), 0);
11096 assert_eq!(metric.loc.blank(), 0);
11097 },
11098 );
11099 }
11100
11101 #[test]
11114 fn tsx_exported_declaration_counts_once() {
11115 check_metrics::<TsxParser>(
11116 "export const a: number = 1;\nexport declare const b: string;\nexport default 3;\nexport function f(): void { const c = 4; }\n",
11117 "foo.tsx",
11118 |metric| {
11119 assert_eq!(metric.loc.sloc(), 4);
11120 assert_eq!(metric.loc.ploc(), 4);
11121 assert_eq!(metric.loc.lloc(), 5);
11122 assert_eq!(metric.loc.cloc(), 0);
11123 assert_eq!(metric.loc.blank(), 0);
11124 },
11125 );
11126 }
11127
11128 #[test]
11139 fn js_family_braceless_for_body_declaration_counts() {
11140 const BODY: &str = "for (var i = 0; i < 3; i++) var s = i;\n";
11141 const NESTED: &str = "for (let i = 0; i < 2; i++) switch (i) { case 0: let y = 1; }\n";
11142 check_metrics::<JavascriptParser>(BODY, "foo.js", |m| assert_eq!(m.loc.lloc(), 2));
11143 check_metrics::<MozjsParser>(BODY, "foo.js", |m| assert_eq!(m.loc.lloc(), 2));
11144 check_metrics::<TypescriptParser>(BODY, "foo.ts", |m| assert_eq!(m.loc.lloc(), 2));
11145 check_metrics::<TsxParser>(BODY, "foo.tsx", |m| assert_eq!(m.loc.lloc(), 2));
11146 check_metrics::<JavascriptParser>(NESTED, "foo.js", |m| assert_eq!(m.loc.lloc(), 3));
11147 check_metrics::<MozjsParser>(NESTED, "foo.js", |m| assert_eq!(m.loc.lloc(), 3));
11148 check_metrics::<TypescriptParser>(NESTED, "foo.ts", |m| assert_eq!(m.loc.lloc(), 3));
11149 check_metrics::<TsxParser>(NESTED, "foo.tsx", |m| assert_eq!(m.loc.lloc(), 3));
11150 }
11151
11152 #[test]
11161 fn typescript_ambient_declarations_are_not_logical_lines() {
11162 const SRC: &str = "declare const VERSION: string;\ndeclare let mutable: number;\ndeclare namespace NS { const inner: number; }\ndeclare module \"m\" { let y: string; }\n";
11163 check_metrics::<TypescriptParser>(SRC, "foo.ts", |m| assert_eq!(m.loc.lloc(), 0));
11164 check_metrics::<TsxParser>(SRC, "foo.tsx", |m| assert_eq!(m.loc.lloc(), 0));
11165 }
11166}