Skip to content
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
28 changes: 25 additions & 3 deletions flake8_formatter_junit_xml/formatter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flake8.formatting import base
from flake8.formatting import base, default
import optparse
from junit_xml import TestSuite, TestCase


Expand All @@ -7,6 +8,13 @@ class JUnitXmlFormatter(base.BaseFormatter):

def after_init(self):
self.test_suites = {}
display_formatter_opts = {
'output_file': None,
'tee': False,
'show_source': self.options.show_source,
'format': 'default',
}
self.display_formatter = default.Default(optparse.Values(display_formatter_opts))

def beginning(self, filename):
name = '{0}.{1}'.format("flake8", filename.replace('.', '_'))
Expand All @@ -16,13 +24,20 @@ def beginning(self, filename):
def start(self):
if self.filename:
self.output_fd = open(self.filename, 'w')
# I know this does nothing because display_formatter.output_fd is None, but for safe
self.display_formatter.start()

def should_print_screen(self):
return self.options.tee or self.output_fd is None

# Do not write each error
# Store each error as a TestCase
def handle(self, error):
name = '{0}, {1}'.format(error.code, error.text)
test_case = TestCase(name, file=error.filename, line=error.line_number)
test_case.add_failure_info(message=self.format(error), output=self.show_source(error))
self.test_suites[error.filename].test_cases.append(test_case)
if self.should_print_screen():
self.display_formatter.handle(error)

def format(self, error):
return '%(path)s:%(row)d:%(col)d: %(code)s %(text)s' % {
Expand All @@ -43,7 +58,14 @@ def finished(self, filename):
def sorted_suites(self):
return map(lambda x: x[1], sorted(self.test_suites.items()))

# junit-formatter itself does not print output to screen (display_formatter will do)
def write_xml(self, output):
if self.output_fd is not None:
self.output_fd.write(output + self.newline)

# writes results to file after all files are processed
def stop(self):
self._write(TestSuite.to_xml_string(iter(self.sorted_suites())))
self.write_xml(TestSuite.to_xml_string(iter(self.sorted_suites())))
super(JUnitXmlFormatter, self).stop()
# I know this does nothing because display_formatter.output_fd is None, but for safe
self.display_formatter.stop()
55 changes: 54 additions & 1 deletion tests/test_formatter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import unittest
import optparse
import os
import sys
import tempfile
from flake8_formatter_junit_xml import JUnitXmlFormatter
from flake8 import style_guide
try:
# This is for Python2 only.
from StringIO import StringIO
except ImportError:
# This also exists in Python2 but printing to it causes unicode errors.
from io import StringIO
from junit_xml import TestSuite, TestCase

filename = 'some/filename.py'
Expand All @@ -26,20 +33,29 @@ def test_beginning(self):
self.assertEqual('flake8.some/filename_py', f.test_suites[filename].name)

def test_handle(self):
io = StringIO()
sys.stdout = io

f = create_formatter()
f.beginning(filename)
f.handle(error)
self.assertIsNotNone(f.test_suites[filename].test_cases)
self.assertIsInstance(f.test_suites[filename].test_cases[0], TestCase)
self.assertIsNone(f.test_suites[filename].test_cases[0].failure_output)

self.assertEqual(io.getvalue(), "some/filename.py:2:1: A000 wrong wrong wrong\n")
sys.stdout = sys.__stdout__

def test_show_source(self):
f = create_formatter(show_source=True)
f.beginning(filename)
f.handle(error)
self.assertIn('import os', f.test_suites[filename].test_cases[0].failure_output)

def test_scenario(self):
def test_scenario_xml_file_only(self):
io = StringIO()
sys.stdout = io

(fd, tempfilename) = tempfile.mkstemp()

# If formatter opens this file with `a`, tests should fail due to pre-written content.
Expand All @@ -65,4 +81,41 @@ def test_scenario(self):
# print(content)
self.assertEqual(xml_content, content)

self.assertEqual(io.getvalue(), '')

os.remove(tempfilename)
sys.stdout = sys.__stdout__

def test_scenario_with_tee(self):
io = StringIO()
sys.stdout = io

(fd, tempfilename) = tempfile.mkstemp()

# If formatter opens this file with `a`, tests should fail due to pre-written content.
with os.fdopen(fd, 'w') as f:
f.write("some pre-existing texts!!\n")

with open(os.path.dirname(os.path.abspath(__file__)) + '/expected.xml', 'r') as f:
xml_content = f.read()

formatter = create_formatter(output_file=tempfilename, tee=True)
formatter.start()
# a file with error
formatter.beginning(filename)
formatter.handle(error)
formatter.finished(filename)
# another file without error
formatter.beginning("some/noerror.py")
formatter.finished("some/noerror.py")
formatter.stop()

with open(tempfilename) as f:
content = f.read()
# print(content)
self.assertEqual(xml_content, content)

self.assertEqual(io.getvalue(), "some/filename.py:2:1: A000 wrong wrong wrong\n")

os.remove(tempfilename)
sys.stdout = sys.__stdout__