Skip to content

Commit

Permalink
Added project construct to get_cloc function
Browse files Browse the repository at this point in the history
Also moved the utility FakeProject from test_core to utils.
  • Loading branch information
elmotec committed Jan 16, 2021
1 parent da384bf commit 5022a04
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 38 deletions.
8 changes: 4 additions & 4 deletions codemetrics/cloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import pandas as pd

from . import internals
from . import internals, scm

__all__ = ["get_cloc"]

Expand All @@ -24,7 +24,7 @@ class ClocEntry:


def get_cloc(
path: str = ".", cloc_program: str = "cloc", cwd: pl.Path = None
project: scm.Project, path: str = ".", cloc_program: str = "cloc"
) -> pd.DataFrame:
"""Retrieve lines of code (LOC) using cloc.pl
Expand All @@ -40,11 +40,11 @@ def get_cloc(
comment and code counts.
"""
internals.check_run_in_root(path, cwd)
internals.check_run_in_root(path, project.cwd)
cmdline = [cloc_program, "--csv", "--by-file", path]
cloc_entries = []
try:
output = internals.run(cmdline, cwd=cwd).split("\n")
output = internals.run(cmdline, cwd=project.cwd).split("\n")
except FileNotFoundError as err:
msg = (
f"{err}. Is {cloc_program} available? Please pass "
Expand Down
20 changes: 12 additions & 8 deletions tests/test_cloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
"""Tests for loc (lines of code) module."""

import io
import pathlib as pl
import textwrap
import unittest
from unittest import mock

import pandas as pd

import codemetrics.cloc as loc
from tests.utils import add_data_frame_equality_func

from . import utils


class SimpleDirectory(unittest.TestCase):
"""Given a simple directory."""

def setUp(self):
"""Mocks the internal run command."""
add_data_frame_equality_func(self)
utils.add_data_frame_equality_func(self)
self.run_output = textwrap.dedent(
"""\
language,filename,blank,comment,code,"http://cloc.sourceforge.net"
Expand All @@ -43,8 +45,8 @@ def tearDown(self):

def test_cloc_reads_files(self):
"""cloc is called and reads the output csv file."""
actual = loc.get_cloc()
self.run_.assert_called_with("cloc --csv --by-file .".split(), cwd=None)
actual = loc.get_cloc(utils.FakeProject())
self.run_.assert_called_with("cloc --csv --by-file .".split(), cwd=pl.Path("."))
expected = pd.read_csv(
io.StringIO(
textwrap.dedent(
Expand All @@ -65,7 +67,7 @@ def test_cloc_not_found(self):
"""Clean error message when cloc is not found in the path."""
self.run_.side_effect = [FileNotFoundError]
with self.assertRaises(FileNotFoundError) as context:
_ = loc.get_cloc()
_ = loc.get_cloc(utils.FakeProject())
self.assertIn("cloc", str(context.exception))


Expand All @@ -76,13 +78,15 @@ class TestClocCall(unittest.TestCase):
def test_cloc_fails_if_not_in_root(self, path_glob):
"""Make sure that command line call checks it is run from the root."""
with self.assertRaises(ValueError) as context:
loc.get_cloc()
loc.get_cloc(utils.FakeProject())
path_glob.assert_called_with(pattern=".svn")
self.assertIn("git or svn root", str(context.exception))

@mock.patch("codemetrics.internals.check_run_in_root", autospec=True)
@mock.patch("codemetrics.internals.run", autospec=True)
def test_cloc_called_with_path(self, run, _):
"""Make sure the path is passed as argument to cloc when passed to the function."""
loc.get_cloc(path="some-path")
run.assert_called_with(["cloc", "--csv", "--by-file", "some-path"], cwd=None)
loc.get_cloc(utils.FakeProject(), path="some-path")
run.assert_called_with(
["cloc", "--csv", "--by-file", "some-path"], cwd=pl.Path(".")
)
33 changes: 7 additions & 26 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@

import datetime as dt
import io
import pathlib as pl
import textwrap
import unittest
import unittest.mock as mock

import lizard as lz
import numpy as np
import pandas as pd
import tqdm

import codemetrics as cm
import codemetrics.scm as scm
Expand Down Expand Up @@ -403,23 +401,6 @@ def other():
"""
)

class FakeProject(scm.Project):
"""Fake project with pre-determined values for the download return values."""

def download(self, data: pd.DataFrame) -> scm.DownloadResult:
pass

def get_log(
self,
path: pl.Path = pl.Path("."),
after: dt.datetime = None,
before: dt.datetime = None,
progress_bar: tqdm.tqdm = None,
# FIXME: Why do we need path _and_ relative_url
relative_url: str = None,
) -> pd.DataFrame:
pass

def setUp(self):
super().setUp()
self.log = pd.read_csv(
Expand All @@ -435,9 +416,9 @@ def setUp(self):

def get_complexity(self):
"""Factor retrieval of complexity"""
project = self.FakeProject()
project = utils.FakeProject()
with mock.patch.object(
self.FakeProject,
utils.FakeProject,
"download",
autospec=True,
side_effect=[
Expand Down Expand Up @@ -470,9 +451,9 @@ def test_handles_no_function(self):
+ cm.core._lizard_fields
+ "file_tokens file_nloc".split()
)
project = self.FakeProject()
project = utils.FakeProject()
with mock.patch.object(
self.FakeProject,
utils.FakeProject,
"download",
autospec=True,
return_value=scm.DownloadResult(1, "f.py", ""),
Expand All @@ -490,14 +471,14 @@ def test_handles_no_function(self):
def test_analysis_empty_input_return_empty_output(self, _):
"""Empty input returns and empty dataframe."""
self.log = self.log.iloc[:0]
actual = cm.get_complexity(self.log, self.FakeProject())
actual = cm.get_complexity(self.log, utils.FakeProject())
self.assertTrue(actual.empty)

def test_use_default_download(self):
"""When the context.downlad_funcc is defined, use it."""
project = self.FakeProject()
project = utils.FakeProject()
with mock.patch.object(
self.FakeProject, "download", return_value=scm.DownloadResult(1, "/", "")
utils.FakeProject, "download", return_value=scm.DownloadResult(1, "/", "")
) as download:
_ = cm.get_complexity(self.log, project)
download.assert_called_with(self.log)
Expand Down
21 changes: 21 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
"""Test utility functions and wrappers."""


import datetime as dt
import io
import pathlib as pl
import unittest

import pandas as pd
import pandas.testing as pdt
import tqdm

import codemetrics.scm as scm

Expand Down Expand Up @@ -86,3 +89,21 @@ def csvlog_to_dataframe(csv_log: str) -> pd.DataFrame:
# Reorder columns.
df = df[scm.LogEntry.__slots__].pipe(scm.normalize_log)
return df


class FakeProject(scm.Project):
"""Fake project with pre-determined values for the download return values."""

def download(self, data: pd.DataFrame) -> scm.DownloadResult:
pass

def get_log(
self,
path: pl.Path = pl.Path("."),
after: dt.datetime = None,
before: dt.datetime = None,
progress_bar: tqdm.tqdm = None,
# FIXME: Why do we need path _and_ relative_url
relative_url: str = None,
) -> pd.DataFrame:
pass

0 comments on commit 5022a04

Please sign in to comment.