Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLOCBear: Add CLOCBear #1691

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ addons:
- cabal-install-1.24
- chktex
- clang-3.4
- cloc
- cppcheck
- devscripts
- flawfinder
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.bears.GlobalBear import GlobalBear
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(GlobalBear):
"""
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('cloc')}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'[email protected]'}
LICENSE = 'AGPL-3.0'
CAN_DETECT = {'Statistics'}
SEE_MORE = 'https://github.com/AlDanial/cloc'

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

def process_output(self, output, filename, file):
lines = output.split('\n')
regex = r'(\d+).*?\n\s+(\d+)'
files, ignored_files = re.search(
regex, '\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.MAJOR)
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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to leave this line ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its been added by coala itself, through PycodestyleBear.
Message received on running coala:

E302 expected 2 blank lines, found 1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is two lines after the imports, before the def. It is a PEP8 rule.

But a blank line between coalib and bears imports is OK.

from bears.general.CLOCBear import CLOCBear


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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code does not comply to PEP8.

PEP8Bear, severity NORMAL, section autopep8.

The issue can be fixed by applying the following patch:

--- a/tests/general/CLOCBearTest.py
+++ b/tests/general/CLOCBearTest.py
@@ -13,8 +13,10 @@
     return os.path.join(os.path.dirname(__file__),
                         'cloc_test_files', file)
 
+
 def load_testfile(name):
     return open(get_absolute_test_path(name)).readlines()
+
 
 @generate_skip_decorator(CLOCBear)
 class CLOCBearTest(LocalBearTestHelper):


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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline


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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline after this


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.MAJOR)],
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.