improve test coverage for git submodules
This commit is contained in:
parent
1d57270daf
commit
0ca8a936db
3 changed files with 155 additions and 70 deletions
9
tests/samples/configs/git-submodules-invalid-regex.cfg
Normal file
9
tests/samples/configs/git-submodules-invalid-regex.cfg
Normal file
|
@ -0,0 +1,9 @@
|
|||
[settings]
|
||||
debug = false
|
||||
api_key = 1090a6ae-855f-4be7-b8fb-3edbaf1aa3ec
|
||||
[git]
|
||||
submodules_disabled =
|
||||
this/path/does/not/exist
|
||||
\(invalid regex)
|
||||
git/asubmodule
|
||||
that/other/path
|
|
@ -9,7 +9,6 @@ import logging
|
|||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from testfixtures import log_capture
|
||||
|
@ -17,11 +16,11 @@ from wakatime.compat import u
|
|||
from wakatime.constants import API_ERROR, SUCCESS
|
||||
from wakatime.exceptions import NotYetImplemented
|
||||
from wakatime.projects.base import BaseProject
|
||||
from . import utils
|
||||
from .utils import ANY, CustomResponse, json
|
||||
from wakatime.projects.git import Git
|
||||
from .utils import ANY, DynamicIterable, TestCase, CustomResponse, mock, json
|
||||
|
||||
|
||||
class ProjectTestCase(utils.TestCase):
|
||||
class ProjectTestCase(TestCase):
|
||||
patch_these = [
|
||||
'wakatime.packages.requests.adapters.HTTPAdapter.send',
|
||||
'wakatime.offlinequeue.Queue.push',
|
||||
|
@ -170,14 +169,17 @@ class ProjectTestCase(utils.TestCase):
|
|||
entity=os.path.join(tempdir, 'git', 'emptyfile.txt'),
|
||||
)
|
||||
|
||||
def test_ioerror_when_reading_git_branch(self):
|
||||
@log_capture()
|
||||
def test_ioerror_when_reading_git_branch(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
|
||||
entity = os.path.join(tempdir, 'git', 'emptyfile.txt')
|
||||
|
||||
with utils.mock.patch('wakatime.projects.git.open') as mock_open:
|
||||
with mock.patch('wakatime.projects.git.open') as mock_open:
|
||||
mock_open.side_effect = IOError('')
|
||||
|
||||
self.shared(
|
||||
|
@ -186,6 +188,11 @@ class ProjectTestCase(utils.TestCase):
|
|||
entity=entity,
|
||||
)
|
||||
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = 'OSError' if self.isPy35OrNewer else 'IOError'
|
||||
self.assertIn(expected, actual)
|
||||
|
||||
def test_git_detached_head_not_used_as_branch(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-detached-head', os.path.join(tempdir, 'git'))
|
||||
|
@ -200,16 +207,16 @@ class ProjectTestCase(utils.TestCase):
|
|||
)
|
||||
|
||||
def test_svn_project_detected(self):
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Subversion._has_xcode_tools') as mock_has_xcode:
|
||||
with mock.patch('wakatime.projects.subversion.Subversion._has_xcode_tools') as mock_has_xcode:
|
||||
mock_has_xcode.return_value = True
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_popen:
|
||||
with mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_popen:
|
||||
stdout = open('tests/samples/output/svn').read()
|
||||
stderr = ''
|
||||
mock_popen.return_value = utils.DynamicIterable((stdout, stderr), max_calls=1)
|
||||
mock_popen.return_value = DynamicIterable((stdout, stderr), max_calls=1)
|
||||
|
||||
expected = None if platform.system() == 'Windows' else 'svn'
|
||||
self.shared(
|
||||
|
@ -217,17 +224,20 @@ class ProjectTestCase(utils.TestCase):
|
|||
entity='projects/svn/afolder/emptyfile.txt',
|
||||
)
|
||||
|
||||
def test_svn_exception_handled(self):
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
@log_capture()
|
||||
def test_svn_exception_handled(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Subversion._has_xcode_tools') as mock_has_xcode:
|
||||
with mock.patch('wakatime.projects.subversion.Subversion._has_xcode_tools') as mock_has_xcode:
|
||||
mock_has_xcode.return_value = True
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Popen') as mock_popen:
|
||||
with mock.patch('wakatime.projects.subversion.Popen') as mock_popen:
|
||||
mock_popen.side_effect = OSError('')
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_communicate:
|
||||
with mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_communicate:
|
||||
mock_communicate.side_effect = OSError('')
|
||||
|
||||
self.shared(
|
||||
|
@ -235,17 +245,20 @@ class ProjectTestCase(utils.TestCase):
|
|||
entity='projects/svn/afolder/emptyfile.txt',
|
||||
)
|
||||
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
||||
def test_svn_on_mac_without_xcode_tools_installed(self):
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.platform.system') as mock_system:
|
||||
with mock.patch('wakatime.projects.subversion.platform.system') as mock_system:
|
||||
mock_system.return_value = 'Darwin'
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_popen:
|
||||
with mock.patch('wakatime.projects.subversion.Popen.communicate') as mock_popen:
|
||||
stdout = open('tests/samples/output/svn').read()
|
||||
stderr = ''
|
||||
mock_popen.return_value = utils.DynamicIterable((stdout, stderr), raise_on_calls=[OSError('')])
|
||||
mock_popen.return_value = DynamicIterable((stdout, stderr), raise_on_calls=[OSError('')])
|
||||
|
||||
self.shared(
|
||||
expected_project=None,
|
||||
|
@ -263,13 +276,13 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
args = ['--file', entity, '--config', config, '--time', now]
|
||||
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.platform.system') as mock_system:
|
||||
with mock.patch('wakatime.projects.subversion.platform.system') as mock_system:
|
||||
mock_system.return_value = 'Darwin'
|
||||
|
||||
with utils.mock.patch('wakatime.projects.subversion.Popen') as mock_popen:
|
||||
with mock.patch('wakatime.projects.subversion.Popen') as mock_popen:
|
||||
stdout = open('tests/samples/output/svn').read()
|
||||
stderr = ''
|
||||
|
||||
|
@ -297,7 +310,7 @@ class ProjectTestCase(utils.TestCase):
|
|||
response.status_code = 0
|
||||
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
|
||||
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
now = u(int(time.time()))
|
||||
|
@ -311,12 +324,15 @@ class ProjectTestCase(utils.TestCase):
|
|||
self.assertEquals('hg', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
self.assertEquals('test-hg-branch', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['branch'])
|
||||
|
||||
def test_ioerror_when_reading_mercurial_branch(self):
|
||||
@log_capture()
|
||||
def test_ioerror_when_reading_mercurial_branch(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
response = Response()
|
||||
response.status_code = 0
|
||||
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
|
||||
|
||||
with utils.mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
with mock.patch('wakatime.projects.git.Git.process') as mock_git:
|
||||
mock_git.return_value = False
|
||||
|
||||
now = u(int(time.time()))
|
||||
|
@ -325,13 +341,18 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
args = ['--file', entity, '--config', config, '--time', now]
|
||||
|
||||
with utils.mock.patch('wakatime.projects.mercurial.open') as mock_open:
|
||||
with mock.patch('wakatime.projects.mercurial.open') as mock_open:
|
||||
mock_open.side_effect = IOError('')
|
||||
execute(args)
|
||||
|
||||
self.assertEquals('hg', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
self.assertEquals('default', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['branch'])
|
||||
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = 'OSError' if self.isPy35OrNewer else 'IOError'
|
||||
self.assertIn(expected, actual)
|
||||
|
||||
def test_git_submodule_detected(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
|
@ -376,7 +397,7 @@ class ProjectTestCase(utils.TestCase):
|
|||
config='git-submodules-disabled.cfg',
|
||||
)
|
||||
|
||||
def test_git_submodule_detected_but_disabled_using_regex(self):
|
||||
def test_git_submodule_detected_and_disabled_using_regex(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
|
@ -391,7 +412,7 @@ class ProjectTestCase(utils.TestCase):
|
|||
config='git-submodules-disabled-using-regex.cfg',
|
||||
)
|
||||
|
||||
def test_git_submodule_detected_but_enabled_using_regex(self):
|
||||
def test_git_submodule_detected_and_enabled_using_regex(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
|
@ -406,6 +427,85 @@ class ProjectTestCase(utils.TestCase):
|
|||
config='git-submodules-enabled-using-regex.cfg',
|
||||
)
|
||||
|
||||
@log_capture()
|
||||
def test_git_submodule_detected_with_invalid_regex(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'asubmodule', 'dot_git'), os.path.join(tempdir, 'git', 'asubmodule', '.git'))
|
||||
|
||||
entity = os.path.join(tempdir, 'git', 'asubmodule', 'emptyfile.txt')
|
||||
|
||||
self.shared(
|
||||
expected_project='git',
|
||||
expected_branch='master',
|
||||
entity=entity,
|
||||
config='git-submodules-invalid-regex.cfg',
|
||||
)
|
||||
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = u('WakaTime WARNING Regex error (unbalanced parenthesis) for disable git submodules pattern: \\(invalid regex)')
|
||||
if self.isPy35OrNewer:
|
||||
expected = 'WakaTime WARNING Regex error (unbalanced parenthesis at position 15) for disable git submodules pattern: \\(invalid regex)'
|
||||
self.assertEquals(expected, actual)
|
||||
|
||||
@log_capture()
|
||||
def test_git_find_path_from_submodule(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'asubmodule', 'dot_git'), os.path.join(tempdir, 'git', 'asubmodule', '.git'))
|
||||
|
||||
path = os.path.join(tempdir, 'git', 'asubmodule')
|
||||
|
||||
git = Git(None)
|
||||
result = git._find_path_from_submodule(path)
|
||||
|
||||
expected = os.path.realpath(os.path.join(tempdir, 'git', '.git', 'modules', 'asubmodule'))
|
||||
self.assertEquals(expected, result)
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
||||
@log_capture()
|
||||
def test_git_find_path_from_submodule_handles_exceptions(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
tempdir = tempfile.mkdtemp()
|
||||
shutil.copytree('tests/samples/projects/git-with-submodule', os.path.join(tempdir, 'git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'dot_git'), os.path.join(tempdir, 'git', '.git'))
|
||||
shutil.move(os.path.join(tempdir, 'git', 'asubmodule', 'dot_git'), os.path.join(tempdir, 'git', 'asubmodule', '.git'))
|
||||
|
||||
with mock.patch('wakatime.projects.git.open') as mock_open:
|
||||
mock_open.side_effect = UnicodeDecodeError('utf8', ''.encode('utf8'), 0, 0, '')
|
||||
|
||||
git = Git(None)
|
||||
path = os.path.join(tempdir, 'git', 'asubmodule')
|
||||
result = git._find_path_from_submodule(path)
|
||||
|
||||
self.assertIsNone(result)
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = 'UnicodeDecodeError'
|
||||
self.assertIn(expected, actual)
|
||||
|
||||
with mock.patch('wakatime.projects.git.open') as mock_open:
|
||||
mock_open.side_effect = IOError('')
|
||||
|
||||
git = Git(None)
|
||||
path = os.path.join(tempdir, 'git', 'asubmodule')
|
||||
result = git._find_path_from_submodule(path)
|
||||
|
||||
self.assertIsNone(result)
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = 'OSError' if self.isPy35OrNewer else 'IOError'
|
||||
self.assertIn(expected, actual)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
@ -424,12 +524,8 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
self.assertEquals('proj-map', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
log_output = "\n".join([u(' ').join(x) for x in logs.actual()])
|
||||
expected = u('')
|
||||
self.assertEquals(log_output, expected)
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map_group_usage(self, logs):
|
||||
|
@ -449,37 +545,28 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
self.assertEquals('proj-map42', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
log_output = "\n".join([u(' ').join(x) for x in logs.actual()])
|
||||
expected = u('')
|
||||
self.assertEquals(log_output, expected)
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map_with_invalid_regex(self, logs):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
response = Response()
|
||||
response.status_code = 0
|
||||
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
|
||||
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
|
||||
|
||||
now = u(int(time.time()))
|
||||
entity = 'tests/samples/projects/project_map42/emptyfile.txt'
|
||||
config = 'tests/samples/configs/project_map_invalid.cfg'
|
||||
|
||||
args = ['--file', entity, '--config', config, '--time', now]
|
||||
retval = execute(args)
|
||||
self.assertEquals(retval, SUCCESS)
|
||||
|
||||
execute(args)
|
||||
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
output = [u(' ').join(x) for x in logs.actual()]
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = u('WakaTime WARNING Regex error (unexpected end of regular expression) for projectmap pattern: invalid[({regex')
|
||||
if self.isPy35OrNewer:
|
||||
expected = u('WakaTime WARNING Regex error (unterminated character set at position 7) for projectmap pattern: invalid[({regex')
|
||||
self.assertEquals(output[0], expected)
|
||||
self.assertEquals(expected, actual)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map_with_replacement_group_index_error(self, logs):
|
||||
|
@ -494,16 +581,13 @@ class ProjectTestCase(utils.TestCase):
|
|||
config = 'tests/samples/configs/project_map_malformed.cfg'
|
||||
|
||||
args = ['--file', entity, '--config', config, '--time', now]
|
||||
|
||||
retval = execute(args)
|
||||
|
||||
self.assertEquals(retval, API_ERROR)
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
log_output = "\n".join([u(' ').join(x) for x in logs.actual()])
|
||||
self.assertNothingPrinted()
|
||||
actual = self.getLogOutput(logs)
|
||||
expected = u('WakaTime WARNING Regex error (tuple index out of range) for projectmap pattern: proj-map{3}')
|
||||
self.assertEquals(log_output, expected)
|
||||
self.assertEquals(expected, actual)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map_allows_duplicate_keys(self, logs):
|
||||
|
@ -523,12 +607,8 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
self.assertEquals('proj-map-duplicate-5', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
log_output = "\n".join([u(' ').join(x) for x in logs.actual()])
|
||||
expected = u('')
|
||||
self.assertEquals(log_output, expected)
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
||||
@log_capture()
|
||||
def test_project_map_allows_colon_in_key(self, logs):
|
||||
|
@ -548,9 +628,5 @@ class ProjectTestCase(utils.TestCase):
|
|||
|
||||
self.assertEquals('proj-map-match', self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][0]['project'])
|
||||
|
||||
self.assertEquals(sys.stdout.getvalue(), '')
|
||||
self.assertEquals(sys.stderr.getvalue(), '')
|
||||
|
||||
log_output = "\n".join([u(' ').join(x) for x in logs.actual()])
|
||||
expected = u('')
|
||||
self.assertEquals(log_output, expected)
|
||||
self.assertNothingPrinted()
|
||||
self.assertNothingLogged(logs)
|
||||
|
|
|
@ -123,6 +123,6 @@ class Git(BaseProject):
|
|||
subpath = line[len('gitdir: '):].strip()
|
||||
if os.path.isfile(os.path.join(path, subpath, 'config')) and \
|
||||
os.path.isfile(os.path.join(path, subpath, 'HEAD')):
|
||||
return os.path.join(path, subpath)
|
||||
return os.path.realpath(os.path.join(path, subpath))
|
||||
|
||||
return None
|
||||
|
|
Loading…
Reference in a new issue