Skip to content

Commit

Permalink
CLOCBear: Add CLOCBear
Browse files Browse the repository at this point in the history
This bear gives statistics about number of lines,
number of comment lines, and total number of lines.

Closes coala#1577
  • Loading branch information
shreyans800755 committed May 3, 2017
1 parent ec1b330 commit 5246a7f
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .ci/deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ esac
# apt-get commands
export DEBIAN_FRONTEND=noninteractive

deps="libclang1-3.4 indent mono-mcs chktex r-base julia golang-go luarocks verilator cppcheck flawfinder devscripts"
deps="libclang1-3.4 indent mono-mcs chktex r-base julia golang-go luarocks verilator cppcheck flawfinder devscripts cloc"
deps_infer="m4 opam"

case $CIRCLE_BUILD_IMAGE in
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ addons:
- opam
- php-codesniffer
- verilator
- cloc

cache:
pip: true
Expand Down
65 changes: 65 additions & 0 deletions bears/general/CLOCBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import re

from coalib.bearlib.abstractions.Linter import linter
from coalib.results.Result import Result
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
from dependency_management.requirements.DistributionRequirement import (
DistributionRequirement)


@linter(executable='cloc')
class CLOCBear:
"""
Summarises a file or number of files in directory structure
with total lines, number of comment lines, number of actual code lines
using CLI tool cloc
"""
LANGUAGES = {'All'}
REQUIREMENTS = {DistributionRequirement(apt_get='cloc')}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'[email protected]'}
LICENSE = 'AGPL-3.0'
CAN_DETECT = {'Number of comment lines',
'Number of blank lines',
'Number of code lines'}

@staticmethod
def create_arguments(filename, file, config_file):
return ('--csv', filename)

def process_output(self, output, filename, file):
lines = output.split('\n')
files, ignored_files = re.search(
r'(\d+).*?\n\s+(\d+)', '\n'.join(lines[1:3]), re.MULTILINE)\
.group(1, 2)
if(files == ignored_files):
msg = 'File does not belong to valid programming language.'
yield Result.from_values(origin=self,
message=msg,
file=filename,
severity=RESULT_SEVERITY.INFO)
else:
regex = re.compile(r'(\d+),(\S+),(\d+),(\d+),(\d+)')
# cloc tool gives summary of files
# starting from 5th(0-index) line up to second last line
for row in lines[5:-1]:
match = regex.match(row)

nfiles, lang = match.group(1, 2)
blank, comment, code = map(int, match.group(3, 4, 5))
total = blank + comment + code

report = '\n'.join(['Language: {0}'.format(lang),
'Total files: {0}'.format(nfiles),
'Total lines: {0}'.format(total),
'Code lines: {0} ({1:.2f}%)'.format(
code, code * 100.0 / total),
'Comment lines: {0} ({1:.2f}%)'.format(
comment, comment * 100.0 / total),
'Blank lines: {0} ({1:.2f}%)'.format(
blank, blank * 100.0 / total)
])
yield Result.from_values(origin=self,
message=report,
file=filename,
severity=RESULT_SEVERITY.INFO)
94 changes: 94 additions & 0 deletions tests/general/CLOCBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import os
from queue import Queue

from coalib.settings.Section import Section
from coalib.testing.LocalBearTestHelper import LocalBearTestHelper
from coalib.testing.BearTestHelper import generate_skip_decorator
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
from coalib.results.Result import Result

from bears.general.CLOCBear import CLOCBear


def get_absolute_test_path(file):
return os.path.join(os.path.dirname(__file__),
'cloc_test_files', file)


def load_testfile(name):
with open(get_absolute_test_path(name)) as file:
return file.readlines()


@generate_skip_decorator(CLOCBear)
class CLOCBearTest(LocalBearTestHelper):

def setUp(self):
self.uut = CLOCBear(Section('name'), Queue())
self.test_files = ['example1.cpp', 'example2.py',
'example3.cpp', 'example4.txt']
self.expected_results = {self.test_files[0]: {'LANGUAGE': 'C++',
'FILES': 1,
'CODE': 6,
'COMMENTS': 5,
'BLANK': 3},
self.test_files[1]: {'LANGUAGE': 'Python',
'FILES': 1,
'CODE': 3,
'COMMENTS': 2,
'BLANK': 2},
self.test_files[2]: {'LANGUAGE': 'C++',
'FILES': 1,
'CODE': 11,
'COMMENTS': 0,
'BLANK': 3},
self.test_files[3]: 'File does not belong '
'to valid programming '
'language.'
}

def build_message(self, filename):
result = self.expected_results[filename]

lang = result['LANGUAGE']
nfiles = result['FILES']
code = result['CODE']
comment = result['COMMENTS']
blank = result['BLANK']
total = code + comment + blank

message = '\n'.join(['Language: {0}'.format(lang),
'Total files: {0}'.format(nfiles),
'Total lines: {0}'.format(total),
'Code lines: {0} ({1:.2f}%)'.format(
code, code * 100.0 / total),
'Comment lines: {0} ({1:.2f}%)'.format(
comment, comment * 100.0 / total),
'Blank lines: {0} ({1:.2f}%)'.format(
blank, blank * 100.0 / total)
])
return message

def test_valid(self):
for filename in self.test_files[:-1]:
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('CLOCBear',
self.build_message(filename),
file=get_absolute_test_path(filename),
severity=RESULT_SEVERITY.INFO)],
filename=get_absolute_test_path(filename))

def test_invalid(self):
filename = self.test_files[3]
file_contents = load_testfile(filename)
self.check_results(
self.uut,
file_contents,
[Result.from_values('CLOCBear',
str(self.expected_results[filename]),
file=get_absolute_test_path(filename),
severity=RESULT_SEVERITY.INFO)],
filename=get_absolute_test_path(filename))
Empty file.
14 changes: 14 additions & 0 deletions tests/general/cloc_test_files/example1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This comments are for testing purpose.

/*
Just like any other programmer,
This example file will also try to print only two words
*/

#include <cstdio>

int main()
{
std::cout << 'Hello World!' << std::endl;
return 0;
}
7 changes: 7 additions & 0 deletions tests/general/cloc_test_files/example2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This comments are for testing purpose
# This program will just try to add two static numbers

first = 5 # First number
second = 10 # Second number

sum = first + second
14 changes: 14 additions & 0 deletions tests/general/cloc_test_files/example3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <cstdio>

#define PI 3.1415926
using namespace std;


int main()
{
const double radii = 1.0;
const double area = PI * radii * radii;
cout << 'Area for the circle with radii ' << radii <<
' is ' << area << endl;
return 0;
}
2 changes: 2 additions & 0 deletions tests/general/cloc_test_files/example4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is normal text file. And it is not specific to any programming language.
So, this has to detected as invalid file by cloc.

0 comments on commit 5246a7f

Please sign in to comment.