Skip to content

Commit

Permalink
Add tests for ctagsplugin.py
Browse files Browse the repository at this point in the history
- Add 'mock'-style class for sublime and sublimeplugin imports
- Add test cases for ctagsplugin.py functions
- Minor refactoring of files
  • Loading branch information
stephenfin committed Nov 9, 2013
1 parent 7db05f3 commit a10bee7
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 27 deletions.
57 changes: 33 additions & 24 deletions ctagsplugin.py
Expand Up @@ -14,9 +14,18 @@
from operator import itemgetter as iget
from collections import defaultdict

import sublime
import sublime_plugin
from sublime import status_message, error_message
try:
import sublime
import sublime_plugin
from sublime import status_message, error_message
except ImportError: # running tests
import sys

from tests.sublime_fake import sublime
from tests.sublime_fake import sublime_plugin

sys.modules['sublime'] = sublime
sys.modules['sublime_plugin'] = sublime_plugin

if sublime.version().startswith('2'):
import ctags
Expand Down Expand Up @@ -194,14 +203,15 @@ def on_load(self, view):
return wrapper


def find_tags_relative_to(file_name):
def find_tags_relative_to(file_name, tag_file):
if not file_name:
return None

dirs = os.path.dirname(os.path.normpath(file_name)).split(os.path.sep)

while dirs:
joined = os.path.sep.join(dirs + [setting('tag_file')])
joined = os.path.sep.join(dirs + [tag_file])

if os.path.exists(joined) and not os.path.isdir(joined):
return joined
else:
Expand Down Expand Up @@ -257,8 +267,7 @@ def reached_top_level_folders(folders, oldpath, path):
return False


def find_top_folder(view, filename):
folders = view.window().folders()
def find_top_folder(folders, filename):
path = os.path.dirname(filename)

# we don't have any folders open, return the folder this file is in
Expand Down Expand Up @@ -392,27 +401,22 @@ def commonfolder(m):
return os.path.sep.join(s1)


def files_to_search(view, tags_file, multiple=True):
def files_to_search(file_name, tags_file, multiple=True):
if multiple:
return []

fn = view.file_name()
if not fn:
return

tag_dir = os.path.normpath(os.path.dirname(tags_file))
common_prefix = commonfolder([tag_dir, file_name])

common_prefix = commonfolder([tag_dir, fn])
files = [fn[len(common_prefix)+1:]]
files = [file_name[len(common_prefix)+1:]]

return files


def get_current_file_suffix(view):
current = view.file_name()
fileName, fileExtension = os.path.splitext(current)
def get_current_file_suffix(file_name):
file_prefix, file_suffix = os.path.splitext(file_name)

return fileExtension
return file_suffix


"""
Expand Down Expand Up @@ -527,7 +531,8 @@ def ctags_goto_command(jump_directly=False):
def wrapper(f):
def command(self, edit, **args):
view = self.view
tags_file = find_tags_relative_to(view.file_name())
tags_file = find_tags_relative_to(
view.file_name(), setting('tag_file'))

if not tags_file:
status_message('Can\'t find any relevant tags file')
Expand Down Expand Up @@ -635,7 +640,8 @@ def run(self):

def on_done(self, symbol):
view = self.window.active_view()
tags_file = find_tags_relative_to(view.file_name())
tags_file = find_tags_relative_to(
view.file_name(), setting('tag_file'))

if not tags_file:
status_message('Can\'t find any relevant tags file')
Expand Down Expand Up @@ -668,17 +674,19 @@ def run(self, view, args, tags_file):
return
multi = args.get('type') == 'multi'
lang = args.get('type') == 'lang'
files = files_to_search(view, tags_file, multi)

if view.file_name():
files = files_to_search(view.file_name(), tags_file, multi)

if lang:
suffix = get_current_file_suffix(view)
suffix = get_current_file_suffix(view.file_name())
key = suffix
else:
key = ','.join(files)

tags_file = tags_file + '_sorted_by_file'

base_path = find_top_folder(view, view.file_name())
base_path = find_top_folder(view.window().folders(), view.file_name())

def get_tags():
loaded = TagFile(tags_file, FILENAME)
Expand Down Expand Up @@ -859,7 +867,8 @@ def __next__(self):
self.routine = None

def co_routine(self, view):
tag_file = find_tags_relative_to(view.file_name())
tag_file = find_tags_relative_to(
view.file_name(), setting('tag_file'))

with codecs.open(tag_file, encoding='utf-8') as tf:
tags = parse_tag_lines(tf, tag_class=Tag)
Expand Down
5 changes: 2 additions & 3 deletions test_ctags.py
Expand Up @@ -2,7 +2,6 @@

"""Unit tests for ctags.py"""


import os
import sys
import tempfile
Expand Down Expand Up @@ -188,7 +187,7 @@ def test_build_ctags__single_file(self):
':$/;"\tf\r\n'.format(filename))
finally:
output.close()
os.remove(path) # Clean up
os.remove(path) # clean up

def test_build_ctags__custom_tag_file(self):
"""Test execution of ctags using a custom tag file"""
Expand All @@ -205,7 +204,7 @@ def test_build_ctags__custom_tag_file(self):
':$/;"\tf\r\n'.format(filename))
finally:
output.close()
os.remove(path) # Clean up
os.remove(path) # clean up

"""post_process_tag"""

Expand Down
205 changes: 205 additions & 0 deletions test_ctagsplugin.py
@@ -0,0 +1,205 @@
#!/usr/bin/env python

"""Unit tests for ctagsplugin.py"""

import os
import sys
import tempfile
import unittest
import codecs
import shutil

if sys.version_info >= (3, 0):
from . import ctagsplugin
from . import ctags
else:
import ctagsplugin
import ctags


class CTagsPluginTest(unittest.TestCase):

"""
Helper functions
"""

def make_tmp_directory(self, pwd=None):
"""Make a temporary directory to place files in
:returns: Path to the temporary directory
"""
tmp_dir = tempfile.mkdtemp(dir=pwd)
return tmp_dir

def build_python_file(self, pwd=None):
"""Build a simple Python "program" that ctags can use
:returns: Path to a constructed, valid Java source file
"""
path = ''

# the file created here is locked while open, hence we can't delete
# similarly, ctags appears to require an extension hence the suffix
with tempfile.NamedTemporaryFile(
delete=False, suffix='.py', dir=pwd) as temp:
try:
path = temp.name # store name for later use
temp.writelines([ # write a temp Python (duh!) "Hello, world"
'def my_definition():\n',
'\toutput = "Hello, world!"\n',
'\tprint(output)\n'])
finally:
temp.close()

return path

def build_java_file(self, pwd=None):
"""Build a slightly detailed Java "program" that ctags can use
Build a slightly more detailed program that 'build_python_file' does,
in order to test more advanced functionality of ctags.py, or ctags.exe
:returns: Path to a constructed, valid Java source file
"""
path = ''

# the file created here is locked while open, hence we can't delete
# similarly, ctags appears to require an extension hence the suffix
with tempfile.NamedTemporaryFile(
delete=False, suffix='.java', dir=pwd) as temp:
try:
path = temp.name # store name for later use
temp.writelines([ # write a temp Java "Hello, world"
'public class DemoClass {\n',
'\tpublic static void main(String args[]) {\n',
'\t\tSystem.out.println("Hello, World");\n',
'\n',
'\t\tDemoClass demo = new DemoClass();\n',
'\t\tSystem.out.printf("Sum %d\n", demo.getSum(5,6));\n',
'\t}\n',
'\n',
'\tprivate int getSum(int a, int b) {\n',
'\t\treturn (a + b);\n',
'\t}\n',
'}\n'])
finally:
temp.close()

return path

def remove_tmp_directory(self, path):
"""Remove a temporary directory made by ``make_tmp_directory``
:param path: Path to directory
:returns: True if directory deleted, else False
"""
shutil.rmtree(path)

def remove_tmp_files(self, paths):
"""Remove temporary files made by ``make_x_file``
:param paths: Path to file
:returns: True if file deleted, else False
"""
for path in paths:
os.remove(path)

"""
Test functions
"""

def test_find_tags_relative_to__find_tags_in_current_directory(self):
TAG_FILE = 'example_tags'

current_path = self.build_python_file()
tag_file = ctags.build_ctags(path=current_path, tag_file=TAG_FILE)

# should find tag file in current directory
self.assertEquals(
ctagsplugin.find_tags_relative_to(current_path, TAG_FILE),
tag_file)

# cleanup
self.remove_tmp_files([current_path, tag_file])

def test_find_tags_relative_to__find_tags_in_parent_directory(self):
TAG_FILE = 'example_tags'

parent_path = self.build_python_file()
parent_tag_file = ctags.build_ctags(path=parent_path,
tag_file=TAG_FILE)
child_dir = self.make_tmp_directory()
child_path = self.build_python_file(pwd=child_dir)

# should find tag file in parent directory
self.assertEquals(
ctagsplugin.find_tags_relative_to(child_path, TAG_FILE),
parent_tag_file)

# cleanup
self.remove_tmp_files([parent_path, parent_tag_file])
self.remove_tmp_directory(child_dir)

def test_find_top_folder__current_folder_open(self):
# create temporary folders and files
temp_dir = self.make_tmp_directory()
temp_path = self.build_python_file(pwd=temp_dir)

path = ctagsplugin.find_top_folder([temp_dir], temp_path)

# directory of file should be top
self.assertEquals(path, temp_dir)

# cleanup
self.remove_tmp_directory(temp_dir)

def test_find_top_folder__single_ancestor_folder_open(self):
# create temporary folders and files
parent_dir = self.make_tmp_directory()
child_dir = self.make_tmp_directory(pwd=parent_dir)
temp_path = self.build_python_file(pwd=child_dir)

path = ctagsplugin.find_top_folder([parent_dir], temp_path)

# should return parent as the deepest common folder
self.assertEquals(path, parent_dir)

# cleanup
self.remove_tmp_directory(parent_dir)

def test_find_top_folder__single_sibling_folder_open(self):
# create temporary folders and files
parent_dir = self.make_tmp_directory()
child_a_dir = self.make_tmp_directory(pwd=parent_dir)
child_b_dir = self.make_tmp_directory(pwd=parent_dir)
temp_path = self.build_python_file(pwd=child_b_dir)

path = ctagsplugin.find_top_folder([child_a_dir], temp_path)

# should return parent of the two child directories the deepest common
# folder
self.assertEquals(path, parent_dir)

# cleanup
self.remove_tmp_directory(parent_dir)

def test_find_top_folder__single_child_folder_open(self):
# create temporary folders and files
parent_dir = self.make_tmp_directory()
child_dir = self.make_tmp_directory(pwd=parent_dir)
grandchild_dir = self.make_tmp_directory(pwd=child_dir)
temp_path = self.build_python_file(pwd=child_dir)

path = ctagsplugin.find_top_folder([grandchild_dir], temp_path)

# should return child directory as the deepest common folder
self.assertEquals(path, child_dir)

# cleanup
self.remove_tmp_directory(parent_dir)


if __name__ == '__main__':
unittest.main()
Empty file added tests/__init__.py
Empty file.

0 comments on commit a10bee7

Please sign in to comment.