I have a code that counts the line as executable code in a java file below is the example files and their test cases
Example1.java
package fixtures;
public class Example1 {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
Example2.java
package fixtures;
public class Example2 {
public static void main(String[] args) {
// say hello
System.out.println("Hello world");
}
}
Example3.java
package fixtures;
public class Example3 {
public static void main(String[] args) {
System.out.println("Hello world"); // say hello
}
}
Example4.java
package fixtures;
/**
* A hello world program
*/
public class Example4 {
public static void main(String[] args /* grab args */) {
System.out.println("/*Hello world"); // say hello
}
}
Example5.java
package fixtures;
/*
/****//*
A hello world program
*\/
*/// -----------------
class Example5 {
public static void main(String[] args) {
System.out./* */println("/*\"Hello world")
;
///*
}
/* // */ }
the test cases are failing for Example 5 due to the nature of the comments the count is 2 instead of 6
Error
java.lang.AssertionError:
Expected :6
Actual :2
the testcases are passing for the rest of the examples apart from Example5
below is the code that am using alog with the test cases
Code
package countloc;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CountLOC {
public static int count(String text) {
int count = 0;
boolean insideString = false;
// Regular expression to match comments
Pattern commentPattern = Pattern.compile("/\\*(.|[\\n\\r])*?\\*/|//.*");
// Remove comments from the text
Matcher matcher = commentPattern.matcher(text);
text = matcher.replaceAll("");
// Split the text into lines
String[] lines = text.split("\n");
for (String line : lines) {
// Check if the line contains a string
for (int i = 0; i < line.length(); i++) {
char currentChar = line.charAt(i);
System.out.print(currentChar);
if (insideString && currentChar == '"' && (i == 0 || line.charAt(i - 1) != '\\')) {
insideString = false;
} else if (!insideString && currentChar == '"') {
insideString = true;
}
}
// Count the line as executable code if not in a string
if (!insideString && !line.trim().isEmpty() && !line.trim().startsWith("package ")) {
count++;
}
}
return count;
}
}
Tests
package test;
import countloc.CountLOC;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.junit.Assert.*;
public class CountTest {
@Test
public void shouldHandleBasicCode() throws IOException {
String path = "./src/fixtures/Example1.java";
String code = new String(Files.readAllBytes(Paths.get(path)));
assertEquals(5, CountLOC.count(code));
}
@Test
public void shouldHandleABlankLineWIthOneLineComment() throws IOException {
String path = "./src/fixtures/Example2.java";
String code = new String(Files.readAllBytes(Paths.get(path)));
assertEquals(5, CountLOC.count(code));
}
@Test
public void shouldHandleAnInlineComment() throws IOException {
String path = "./src/fixtures/Example3.java";
String code = new String(Files.readAllBytes(Paths.get(path)));
assertEquals(5, CountLOC.count(code));
}
@Test
public void shouldHandleMultilineCommentsAndQuotes() throws IOException {
String path = "./src/fixtures/Example4.java";
String code = new String(Files.readAllBytes(Paths.get(path)));
assertEquals(5, CountLOC.count(code));
}
@Test
public void shouldHandleAComplexExample() throws IOException {
String path = "./src/fixtures/Example5.java";
String code = new String(Files.readAllBytes(Paths.get(path)));
assertEquals(6, CountLOC.count(code));
}
}
It looks like your regex does also remove the /*
comment sequence starting in the string literal.
System.out./* */println("/*\"Hello world")
;
///*
}
Above 4 lines are stripped to a single line, when the matcher.replaceAll()
is called:
System.out.println(" }
Which also has no closing quote, so everything to the end is treated as a string.