Skip to content

Commit

Permalink
Add more unit tests to reformatter
Browse files Browse the repository at this point in the history
Fix indent/outdent error for strings containing brackets (lovesegfault#36)

Add --check cmd line option (lovesegfault#35)

Enable TravisCI integration for tests

More elaborate unit tests

Fix travisCI

Fix parser problem with escaped quote characters

Fix parser problem with escaped quote characters
  • Loading branch information
f18m committed Jan 14, 2019
1 parent 258330f commit 5ae86aa
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 6 deletions.
12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sudo: false

language: python

python:
- 3.5

install:
- pip install nose

script:
- python setup.py test
27 changes: 21 additions & 6 deletions beautysh/beautysh.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(self):
self.tab_str = ' '
self.tab_size = 4
self.backup = False
self.check_only = False

def read_file(self, fp):
"""Read input file."""
Expand Down Expand Up @@ -57,8 +58,12 @@ def beautify_string(self, data, path=''):
if case_level:
stripped_record = re.sub(r'(\S);;', r'\1 ;;', stripped_record)

# first of all, get rid of escaped special characters like single/double quotes
test_record = stripped_record.replace("\\'", "")
test_record = test_record.replace("\\\"", "")

# collapse multiple quotes between ' ... '
test_record = re.sub(r'\'.*?\'', '', stripped_record)
test_record = re.sub(r'\'.*?\'', '', test_record)
# collapse multiple quotes between " ... "
test_record = re.sub(r'".*?"', '', test_record)
# collapse multiple quotes between ` ... `
Expand Down Expand Up @@ -159,8 +164,8 @@ def beautify_string(self, data, path=''):
defer_ext_quote = False

# count open brackets for line continuation
open_brackets += len(re.findall(r'\[', stripped_record))
open_brackets -= len(re.findall(r'\]', stripped_record))
open_brackets += len(re.findall(r'\[', test_record))
open_brackets -= len(re.findall(r'\]', test_record))
continue_line = re.search(r'\\$', stripped_record)
line += 1
error = (tab != 0)
Expand All @@ -180,9 +185,15 @@ def beautify_file(self, path):
data = self.read_file(path)
result, error = self.beautify_string(data, path)
if(data != result):
if(self.backup):
self.write_file(path+'.bak', data)
self.write_file(path, result)
if(self.check_only):
if not error:
# we want to return 0 (success) only if the given file is already
# well formatted:
error = (result != data)
else:
if(self.backup):
self.write_file(path+'.bak', data)
self.write_file(path, result)
return error

def main(self):
Expand All @@ -198,6 +209,9 @@ def main(self):
parser.add_argument('--backup', '-b', action='store_true',
help="Beautysh will create a backup file in the "
"same path as the original.")
parser.add_argument('--check', '-c', action='store_true',
help="Beautysh will just check the files without doing "
"any in-place beautify.")
parser.add_argument('--tab', '-t', action='store_true',
help="Sets indentation to tabs instead of spaces")
args = parser.parse_args()
Expand All @@ -208,6 +222,7 @@ def main(self):
args.indent_size = args.indent_size[0]
self.tab_size = args.indent_size
self.backup = args.backup
self.check_only = args.check
if (args.tab):
self.tab_size = 1
self.tab_str = '\t'
Expand Down
28 changes: 28 additions & 0 deletions tests/getopts1_beautified.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Shell file taken from Bash v5 source folder (tests/getopts1.sub)

aflag=
bflag=

while getopts ab: name
do
case $name in
a) aflag=1 ;;
b) bflag=1
bval=$OPTARG ;;
?) echo Usage: $0 [-a] [-b value] args
exit 2 ;;
esac

done

if [ ! -z "$aflag" ] ; then echo -a specified ; fi
if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi

if [ "$OPTIND" -gt 1 ]
then
shift $(( $OPTIND - 1 ))
fi

echo remaining args: "$*"

exit 0
28 changes: 28 additions & 0 deletions tests/getopts1_raw.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Shell file taken from Bash v5 source folder (tests/getopts1.sub)

aflag=
bflag=

while getopts ab: name
do
case $name in
a) aflag=1 ;;
b) bflag=1
bval=$OPTARG;;
?) echo Usage: $0 [-a] [-b value] args
exit 2;;
esac

done

if [ ! -z "$aflag" ] ; then echo -a specified ; fi
if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi

if [ "$OPTIND" -gt 1 ]
then
shift $(( $OPTIND - 1 ))
fi

echo remaining args: "$*"

exit 0
43 changes: 43 additions & 0 deletions tests/indent_test1_beautified.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# this small snippet is to test against regressions for issue#29
# https://github.com/bemeurer/beautysh/issues/29

function string_with_brackets_inside1()
{
local re='^[\-]?[[0-9]+$'

# following line contains wrong double TAB:
echo "hello world"
}

function string_with_brackets_inside2()
{
RESTORE="$(echo -en '\033[0m')"

# following line contains wrong TAB:
echo "hello world"
}

function quote_escapes1()
{
T=$(echo "\"a\"")
echo "command to indent"
}

function complex_mix1()
{
while true; do
for i in $(seq 1 100); do
local str_with_brackets="[]]]]"
local str_with_escapes="\"\"\"\""

# try a command in a $() expansion
if [ -z "$(echo)" ]; then
quote_escapes1
string_with_brackets_inside1
string_with_brackets_inside2
fi
done
done
}
43 changes: 43 additions & 0 deletions tests/indent_test1_raw.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# this small snippet is to test against regressions for issue#29
# https://github.com/bemeurer/beautysh/issues/29

function string_with_brackets_inside1()
{
local re='^[\-]?[[0-9]+$'

# following line contains wrong double TAB:
echo "hello world"
}

function string_with_brackets_inside2()
{
RESTORE="$(echo -en '\033[0m')"

# following line contains wrong TAB:
echo "hello world"
}

function quote_escapes1()
{
T=$(echo "\"a\"")
echo "command to indent"
}

function complex_mix1()
{
while true; do
for i in $(seq 1 100); do
local str_with_brackets="[]]]]"
local str_with_escapes="\"\"\"\""

# try a command in a $() expansion
if [ -z "$(echo)" ]; then
quote_escapes1
string_with_brackets_inside1
string_with_brackets_inside2
fi
done
done
}
37 changes: 37 additions & 0 deletions tests/test_beautysh.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,54 @@
from unittest import TestCase
import os

def get_string(s):
return string.printable + s + string.printable

TEST_BASIC_FILENAME = os.path.join(os.path.dirname(__file__), 'basictest.sh')
TEST_GETOPTS1_RAW_FILENAME = os.path.join(os.path.dirname(__file__), 'getopts1_raw.sh')
TEST_GETOPTS1_BEAUTIFIED_FILENAME = os.path.join(os.path.dirname(__file__), 'getopts1_beautified.sh')
TEST_INDENT1_RAW_FILENAME = os.path.join(os.path.dirname(__file__), 'indent_test1_raw.sh')
TEST_INDENT1_BEAUTIFIED_FILENAME = os.path.join(os.path.dirname(__file__), 'indent_test1_beautified.sh')

class TestBasic(TestCase):

# internal utilities:

def read_file(self, fp):
"""Read input file."""
with open(fp) as f:
return f.read()

def assertIdenticalMultilineStrings(self, expected, value):
expectedlines = expected.split('\n')
valuelines = value.split('\n')
#self.assertEqual(len(valuelines), len(expectedlines), "expected is {} while value is {}".format(expected, value))
self.assertEqual(len(valuelines), len(expectedlines), "Wrong line count in actual value:\n{}".format(value))
for idx in range(0,len(expectedlines)):
self.assertEqual(expectedlines[idx], valuelines[idx])

# unit tests:

def test_basic(self):
testdata = self.read_file(TEST_BASIC_FILENAME)
result, error = Beautify().beautify_string(testdata)
self.assertFalse(error); # we expect no parsing error
self.assertTrue(testdata == result) # we expect no change in formatting

def test_getopts1(self):
testdata = self.read_file(TEST_GETOPTS1_RAW_FILENAME)
expecteddata = self.read_file(TEST_GETOPTS1_BEAUTIFIED_FILENAME)
result, error = Beautify().beautify_string(testdata)
self.assertFalse(error); # we expect no parsing error
self.assertIdenticalMultilineStrings(expecteddata, result) # we expect no change in formatting

def test_indent1(self):
testdata = self.read_file(TEST_INDENT1_RAW_FILENAME)
expecteddata = self.read_file(TEST_INDENT1_BEAUTIFIED_FILENAME)
result, error = Beautify().beautify_string(testdata)
self.assertFalse(error); # we expect no parsing error
self.assertIdenticalMultilineStrings(expecteddata, result) # we expect no change in formatting


if __name__ == "__main__":
unittest.main()

0 comments on commit 5ae86aa

Please sign in to comment.