Skip to content

Refactor tests and metadata #317

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

Merged
merged 5 commits into from
Mar 11, 2025
Merged
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
49 changes: 0 additions & 49 deletions .pylintrc

This file was deleted.

6 changes: 3 additions & 3 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Thanks for your interest in contributing to cpplint.
Any kinds of contributions are welcome: Bug reports, Documentation, Patches. However, here are some contributions you probably shouldn't make:

* Drastic reorganization
* Making the code conform to Google's Python style guidelines
* Making the code conform to Google's Python style guidelines
* Features that could be regarded as a security vulnerability

If you need some ideas, you may check out some of the tasks in our `issue tracker <https://github.com/cpplint/cpplint/issues>`_.
Expand All @@ -22,9 +22,9 @@ For many tasks, it is okay to just develop using a single installed python versi
1. (Optional) Install `pyenv <https://github.com/pyenv/pyenv-installer>`_ to manage python versions
2. (Optional) Using pyenv, install the python versions used in testing::

pyenv install 3.12.6
pyenv install 3.<version>
# ...
pyenv local 3.12.6 ...
pyenv local 3.<version> ...

It may be okay to run and test python against locally installed libraries, but if you need to have a consistent build, it is recommended to manage your environment using virtualenv: `virtualenv <https://virtualenv.pypa.io/en/latest/>`_, `virtualenvwrapper <https://pypi.org/project/virtualenvwrapper/>`_::

Expand Down
121 changes: 59 additions & 62 deletions cpplint_clitest.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,50 +39,51 @@
import tempfile
import unittest

from parameterized import parameterized
from pytest import mark
from testfixtures import compare

BASE_CMD = sys.executable + ' ' + os.path.abspath('./cpplint.py ')

def RunShellCommand(cmd: str, args: str, cwd='.'):
"""
executes a command
:param cmd: A string to execute.
:param cwd: from which folder to run.
"""

stdout_target = subprocess.PIPE
stderr_target = subprocess.PIPE
def run_shell_command(cmd: str, args: str, cwd='.'):
"""Executes a command

proc = subprocess.Popen(cmd + ' ' + args,
shell=True,
cwd=cwd,
stdout=stdout_target,
stderr=stderr_target)
out, err = proc.communicate()
Args:
cmd: A string to execute.
args: A string with arguments to the command.
cwd: from which folder to run.
"""
cmd, args = cmd.split(), args.split()
proc = subprocess.run(cmd + args, cwd=cwd, capture_output=True)
out, err = proc.stdout, proc.stderr

# Make output system-agnostic, aka support Windows
if os.sep == '\\':
# TODO: Support scenario with multiple folder inputs
win_path = (os.path.dirname(args.split(' ')[-1]) + '\\').encode()
# TODO: Support scenario with multiple input names
# We currently only support the last arguments as the input name
# to prevent accidentally replacing sed tests.
# Fixing would likely need coding an internal "replace slashes" option for cpplint itself.
win_path = (os.path.dirname(args[-1]) + '\\').encode()
good_path = win_path.replace(b'\\', b'/')
out, err = out.replace(win_path, good_path), err.replace(win_path, good_path)
if os.linesep == '\r\n':
out, err = out.replace(b'\r\n', b'\n'), err.replace(b'\r\n', b'\n')

# print(err) # to get the output at time of test
return (proc.returncode, out, err)
return proc.returncode, out, err


class UsageTest(unittest.TestCase):

def testHelp(self):
(status, out, err) = RunShellCommand(BASE_CMD, '--help')
(status, out, err) = run_shell_command(BASE_CMD, '--help')
self.assertEqual(0, status)
self.assertEqual(b'', out)
self.assertTrue(err.startswith(b'\nSyntax: cpplint'))

class TemporaryFolderClassSetup(object):

class TemporaryFolderClassSetup(unittest.TestCase):
Copy link
Member

Choose a reason for hiding this comment

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

Why this change?

Can we remove it and use pytest parameterize instead of the unmaintained library?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

This is just a linting thing to show the override hints in PyCharm. It works exactly the same without this change.

I've mentioned that subtests were tried and not filterable in a comment above.

Copy link
Member

Choose a reason for hiding this comment

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

You tried with pytest-subtests instead of wolever/parameterized?

Copy link
Member Author

@aaronliu0130 aaronliu0130 Mar 10, 2025

Choose a reason for hiding this comment

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

I don't think parameterized even has subtests support. Yes, I tried both unitest's own subtests and pytest-subtests. See pytest-dev/pytest-subtests#100.

Copy link
Member

@cclauss cclauss Mar 10, 2025

Choose a reason for hiding this comment

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

#332 has now removed all instances of unittest.TestCase.

"""
Regression tests: The test starts a filetreewalker scanning for files name *.def
Such files are expected to have as first line the argument
Expand All @@ -108,7 +109,7 @@ def setUpClass(cls):

@classmethod
def tearDownClass(cls):
if (cls._root):
if cls._root:
# pass
shutil.rmtree(cls._root)

Expand All @@ -121,39 +122,39 @@ def get_extra_command_args(self, cwd):
"""Override in subclass to add arguments to command"""
return ''

def checkAllInFolder(self, foldername, expectedDefs):
def check_all_in_folder(self, folder_name, expected_defs):
# uncomment to show complete diff
# self.maxDiff = None
count = 0
for dirpath, _, fnames in os.walk(foldername):
for dirpath, _, fnames in os.walk(folder_name):
for f in fnames:
if f.endswith('.def'):
count += 1
self._checkDef(os.path.join(dirpath, f))
self.assertEqual(count, expectedDefs)
self.check_def(os.path.join(dirpath, f))
self.assertEqual(count, expected_defs)

def _checkDef(self, path):
def check_def(self, path):
"""runs command and compares to expected output from def file"""
# self.maxDiff = None # to see full diff
with open(path, 'rb') as filehandle:
datalines = filehandle.readlines()
stdoutLines = int(datalines[2])
filenames = datalines[0].decode('utf8').strip()
with open(path, 'rb') as file_handle:
data = file_handle.readlines()
stdout_lines = int(data[2])
filenames = data[0].decode('utf8').strip()
args, _, filenames = filenames.rpartition(" ")
if '*' in filenames:
rel_cwd = os.path.dirname(path)
filenames = ' '.join(
filename[len(rel_cwd)+1:]
filename[len(rel_cwd) + 1:]
for filename in glob.glob(rel_cwd + '/' + filenames)
)
args += ' ' + filenames
self._runAndCheck(path,
args,
int(datalines[1]),
[line.decode('utf8').strip() for line in datalines[3:3 + stdoutLines]],
[line.decode('utf8').strip() for line in datalines[3 + stdoutLines:]])
self._run_and_compare(path, args, int(data[1]),
[line.decode('utf8').strip()
for line in data[3:3 + stdout_lines]],
[line.decode('utf8').strip()
for line in data[3 + stdout_lines:]])

def _runAndCheck(
def _run_and_compare(
self,
definition_file,
args,
Expand All @@ -165,8 +166,8 @@ def _runAndCheck(
cmd = BASE_CMD + self.get_extra_command_args(rel_cwd)
cwd = os.path.join(self._root, rel_cwd)
# command to reproduce, do not forget first two lines have special meaning
print("\ncd " + cwd + " && " + cmd + ' ' + args + " 2> <filename>")
(status, out, err) = RunShellCommand(cmd, args, cwd)
print("\ncd " + cwd + " && " + cmd + ' ' + args + " 2> <filename>")
(status, out, err) = run_shell_command(cmd, args, cwd)
self.assertEqual(expected_status, status, 'bad command status %s' % status)
prefix = 'Failed check in %s comparing to %s for command: %s' % (cwd, definition_file, cmd)
compare('\n'.join(expected_err), err.decode('utf8'), prefix=prefix, show_whitespace=True)
Expand All @@ -177,29 +178,22 @@ class NoRepoSignatureTests(TemporaryFolderClassSetup, unittest.TestCase):
"""runs in a temporary folder (under /tmp in linux) without any .git/.hg/.svn file"""

def get_extra_command_args(self, cwd):
return (' --repository %s ' % self._root)

def testChromiumSample(self):
self.checkAllInFolder('./samples/chromium-sample', 1)

def testVlcSample(self):
self.checkAllInFolder('./samples/vlc-sample', 1)

def testSillySample(self):
self.checkAllInFolder('./samples/silly-sample', 5)

def testBoostSample(self):
self.checkAllInFolder('./samples/boost-sample', 4)

return f' --repository {self._root} '

def _test_name_func(fun, _, x):
del fun
return f'test{x.args[0].capitalize()}Sample-{x.args[1]}'

@parameterized.expand([(folder, case[:-4])
Copy link
Member

Choose a reason for hiding this comment

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

Do we still need https://github.com/wolever/parameterized that has had no update in two years, when pytest has https://docs.pytest.org/en/stable/how-to/parametrize.html#parametrize builtin?

Copy link
Member Author

Choose a reason for hiding this comment

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

That was the first thing I tried. I couldn't get that to work with the unittest-module–subclass setup in this repo. (Plas speling is very importent.)

Copy link
Member

Choose a reason for hiding this comment

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

It is not tested on Python 3.12, 3.13, and pytest > v3 (current is v8). See the open issues and

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, this seems like the best thing we have. We could always find an alternative solution later. It doesn't seem like parameterized's actual functionality we use has been impacted by their indeed-worrying neglect yet. (This was a reason I also tried the subtests approach, which works without additional modules but doesn't allow for -k filtering.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

With #332 I do not see why we need unittest.TestCase classes. I will do more work on that today.

Copy link
Member Author

@aaronliu0130 aaronliu0130 Mar 10, 2025

Choose a reason for hiding this comment

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

I think we'd have a less messy branch history if we just merge this now while you work on that.

Copy link
Member

Choose a reason for hiding this comment

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

#322 has now removed all instances of unittest.TestCase.

for folder in ['chromium', 'vlc', 'silly',
'boost', 'protobuf', 'codelite', 'v8']
for case in os.listdir(f'./samples/{folder}-sample')
if case.endswith('.def')],
name_func=_test_name_func)
@mark.timeout(180)
def testProtobufSample(self):
self.checkAllInFolder('./samples/protobuf-sample', 1)

def testCodeliteSample(self):
self.checkAllInFolder('./samples/codelite-sample', 1)
def testSamples(self, folder, case):
self.check_def(os.path.join(f'./samples/{folder}-sample', case + '.def'))

def testV8Sample(self):
self.checkAllInFolder('./samples/v8-sample', 1)

class GitRepoSignatureTests(TemporaryFolderClassSetup, unittest.TestCase):
"""runs in a temporary folder with .git file"""
Expand All @@ -210,7 +204,8 @@ def prepare_directory(cls, root):
pass

def testCodeliteSample(self):
self.checkAllInFolder('./samples/codelite-sample', 1)
self.check_all_in_folder('./samples/codelite-sample', 1)


class MercurialRepoSignatureTests(TemporaryFolderClassSetup, unittest.TestCase):
"""runs in a temporary folder with .hg file"""
Expand All @@ -221,7 +216,8 @@ def prepare_directory(cls, root):
pass

def testCodeliteSample(self):
self.checkAllInFolder('./samples/codelite-sample', 1)
self.check_all_in_folder('./samples/codelite-sample', 1)


class SvnRepoSignatureTests(TemporaryFolderClassSetup, unittest.TestCase):
"""runs in a temporary folder with .svn file"""
Expand All @@ -232,7 +228,8 @@ def prepare_directory(cls, root):
pass

def testCodeliteSample(self):
self.checkAllInFolder('./samples/codelite-sample', 1)
self.check_all_in_folder('./samples/codelite-sample', 1)


if __name__ == '__main__':
unittest.main()
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy