Search code examples
javaunit-testing

Java Problem Count Commented lines in a .java filr


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));
    }
}

Solution

  • 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.