python_morsels/fix_csv/test_fix_csv.py

224 lines
7.5 KiB
Python
Raw Normal View History

2021-01-25 22:39:04 +01:00
from contextlib import contextmanager, redirect_stderr, redirect_stdout
from io import StringIO
from importlib.machinery import SourceFileLoader
import os
import sys
import warnings
import shlex
from textwrap import dedent
from tempfile import NamedTemporaryFile
import unittest
class FixCSVTests(unittest.TestCase):
"""Tests for fix_csv.py"""
maxDiff = None
def test_pipe_file_to_csv_file(self):
2021-01-25 23:42:24 +01:00
old_contents = dedent(
"""
2021-01-25 22:39:04 +01:00
2012|Lexus|LFA
2009|GMC|Yukon XL 1500
1965|Ford|Mustang
2005|Hyundai|Sonata
1995|Mercedes-Benz|C-Class
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected = dedent(
"""
2021-01-25 22:39:04 +01:00
2012,Lexus,LFA
2009,GMC,Yukon XL 1500
1965,Ford,Mustang
2005,Hyundai,Sonata
1995,Mercedes-Benz,C-Class
2021-01-25 23:42:24 +01:00
"""
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(old_contents) as old, make_file("") as new:
2021-01-25 23:42:24 +01:00
output = run_program(f"fix_csv.py {old} {new}")
2021-01-25 22:39:04 +01:00
with open(new) as new_file:
new_contents = new_file.read()
self.assertEqual(expected, new_contents)
self.assertEqual("", output)
def test_delimiter_in_output(self):
2021-01-25 23:42:24 +01:00
old_contents = dedent(
"""
2021-01-25 22:39:04 +01:00
02|Waylon Jennings|Honky Tonk Heroes (Like Me)
04|Kris Kristofferson|To Beat The Devil
11|Johnny Cash|Folsom Prison Blues
13|Billy Joe Shaver|Low Down Freedom
21|Hank Williams III|Mississippi Mud
22|David Allan Coe|Willie, Waylon, And Me
24|Bob Dylan|House Of The Risin' Sun
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected = dedent(
"""
2021-01-25 22:39:04 +01:00
02,Waylon Jennings,Honky Tonk Heroes (Like Me)
04,Kris Kristofferson,To Beat The Devil
11,Johnny Cash,Folsom Prison Blues
13,Billy Joe Shaver,Low Down Freedom
21,Hank Williams III,Mississippi Mud
22,David Allan Coe,"Willie, Waylon, And Me"
24,Bob Dylan,House Of The Risin' Sun
2021-01-25 23:42:24 +01:00
"""
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(old_contents) as old, make_file("") as new:
2021-01-25 23:42:24 +01:00
output = run_program(f"fix_csv.py {old} {new}")
2021-01-25 22:39:04 +01:00
with open(new) as new_file:
new_contents = new_file.read()
self.assertEqual(expected, new_contents)
self.assertEqual("", output)
def test_original_file_is_unchanged(self):
2021-01-25 23:42:24 +01:00
old_contents = dedent(
"""
2021-01-25 22:39:04 +01:00
2012|Lexus|LFA
2009|GMC|Yukon XL 1500
2021-01-25 23:42:24 +01:00
"""
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(old_contents) as old, make_file("") as new:
2021-01-25 23:42:24 +01:00
run_program(f"fix_csv.py {old} {new}")
2021-01-25 22:39:04 +01:00
with open(old) as old_file:
contents = old_file.read()
self.assertEqual(old_contents, contents)
def test_call_with_too_many_files(self):
with make_file("") as old, make_file("") as new:
with self.assertRaises(BaseException):
2021-01-25 23:42:24 +01:00
run_program(f"fix_csv.py {old} {new} {old}")
2021-01-25 22:39:04 +01:00
# To test the Bonus part of this exercise, comment out the following line
2021-01-25 23:42:24 +01:00
# @unittest.expectedFailure
2021-01-25 22:39:04 +01:00
def test_in_delimiter_and_in_quote(self):
2021-01-25 23:42:24 +01:00
old_contents = dedent(
"""
2021-01-25 22:39:04 +01:00
2012 Lexus "LFA"
2009 GMC 'Yukon XL 1500'
1995 "Mercedes-Benz" C-Class
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected1 = dedent(
"""
2021-01-25 22:39:04 +01:00
2012,Lexus,LFA
2009,GMC,'Yukon,XL,1500'
1995,Mercedes-Benz,C-Class
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected2 = dedent(
'''
2021-01-25 22:39:04 +01:00
2012,Lexus,"""LFA"""
2009,GMC,Yukon XL 1500
1995,"""Mercedes-Benz""",C-Class
2021-01-25 23:42:24 +01:00
'''
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(old_contents) as old, make_file("") as new:
run_program(f'fix_csv.py {old} {new} --in-delimiter=" "')
with open(new) as new_file:
self.assertEqual(expected1, new_file.read())
2021-01-25 23:42:24 +01:00
run_program(f"""fix_csv.py --in-delimiter=" " --in-quote="'" {old} {new}""")
2021-01-25 22:39:04 +01:00
with open(new) as new_file:
self.assertEqual(expected2, new_file.read())
# To test the Bonus part of this exercise, comment out the following line
2021-01-25 23:42:24 +01:00
# @unittest.expectedFailure
2021-01-25 22:39:04 +01:00
def test_autodetect_input_format(self):
2021-01-25 23:42:24 +01:00
contents1 = dedent(
"""
2021-01-25 22:39:04 +01:00
'2012' 'Lexus' 'LFA'
'2009' 'GMC' 'Yukon XL 1500'
'1995' 'Mercedes-Benz' 'C-Class'
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected1 = dedent(
"""
2021-01-25 22:39:04 +01:00
2012,Lexus,LFA
2009,GMC,Yukon XL 1500
1995,Mercedes-Benz,C-Class
2021-01-25 23:42:24 +01:00
"""
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(contents1) as old, make_file("") as new:
2021-01-25 23:42:24 +01:00
run_program(f"fix_csv.py {old} {new}")
2021-01-25 22:39:04 +01:00
with open(new) as new_file:
self.assertEqual(expected1, new_file.read())
2021-01-25 23:42:24 +01:00
contents2 = dedent(
"""
2021-01-25 22:39:04 +01:00
"02"\t"Waylon Jennings"\t"Honky Tonk Heroes (Like Me)"\t"3:29"
"04"\t"Kris Kristofferson"\t"To Beat The Devil"\t"4:05"
"11"\t"Johnny Cash"\t"Folsom Prison Blues"\t"2:51"
"13"\t"Billy Joe Shaver"\t"Low Down Freedom"\t"2:53"
"21"\t"Hank Williams III"\t"Mississippi Mud"\t"3:32"
"22"\t"David Allan Coe"\t"Willie, Waylon, And Me"\t"3:24"
"24"\t"Bob Dylan"\t"House Of The Risin' Sun"\t"5:20"
2021-01-25 23:42:24 +01:00
"""
).lstrip()
expected2 = dedent(
"""
2021-01-25 22:39:04 +01:00
02,Waylon Jennings,Honky Tonk Heroes (Like Me),3:29
04,Kris Kristofferson,To Beat The Devil,4:05
11,Johnny Cash,Folsom Prison Blues,2:51
13,Billy Joe Shaver,Low Down Freedom,2:53
21,Hank Williams III,Mississippi Mud,3:32
22,David Allan Coe,"Willie, Waylon, And Me",3:24
24,Bob Dylan,House Of The Risin' Sun,5:20
2021-01-25 23:42:24 +01:00
"""
).lstrip()
2021-01-25 22:39:04 +01:00
with make_file(contents2) as old, make_file("") as new:
2021-01-25 23:42:24 +01:00
run_program(f"fix_csv.py {old} {new}")
2021-01-25 22:39:04 +01:00
with open(new) as new_file:
self.assertEqual(expected2, new_file.read())
class DummyException(Exception):
"""No code will ever raise this exception."""
def run_program(arguments="", raises=DummyException):
"""
Run program at given path with given arguments.
If raises is specified, ensure the given exception is raised.
"""
2021-01-25 23:42:24 +01:00
arguments = arguments.replace("\\", "\\\\")
2021-01-25 22:39:04 +01:00
path, *args = shlex.split(arguments)
old_args = sys.argv
warnings.simplefilter("ignore", ResourceWarning)
try:
sys.argv = [path] + args
try:
2021-01-25 23:42:24 +01:00
if "__main__" in sys.modules:
del sys.modules["__main__"]
2021-01-25 22:39:04 +01:00
with redirect_stdout(StringIO()) as output:
with redirect_stderr(output):
2021-01-25 23:42:24 +01:00
SourceFileLoader("__main__", path).load_module()
2021-01-25 22:39:04 +01:00
except raises:
return output.getvalue()
except SystemExit as e:
if e.args != (0,):
raise SystemExit(output.getvalue()) from e
finally:
2021-01-25 23:42:24 +01:00
sys.modules.pop("__main__", None)
2021-01-25 22:39:04 +01:00
if raises is not DummyException:
raise AssertionError("{} not raised".format(raises))
return output.getvalue()
finally:
sys.argv = old_args
@contextmanager
def make_file(contents=None):
"""Context manager providing name of a file containing given contents."""
2021-01-25 23:42:24 +01:00
with NamedTemporaryFile(mode="wt", encoding="utf-8", delete=False) as f:
2021-01-25 22:39:04 +01:00
if contents:
f.write(contents)
try:
yield f.name
finally:
os.remove(f.name)
if __name__ == "__main__":
2021-01-25 23:42:24 +01:00
unittest.main(verbosity=2)