Add the new test suite.

This test suite has been in use for a long time now, in place of the obsolete and unmanageable testparser.py and testfuncs.py. It verifies the complete optimizer output to stdout and stderr, to ensure that the output matches the expectations.

See unit_tests/README.txt for more info.
This commit is contained in:
Sei Lisa 2019-01-04 20:26:26 +01:00
parent 7fbde0269c
commit 1867dc78e7
547 changed files with 11680 additions and 0 deletions

778
run-tests.py Executable file
View file

@ -0,0 +1,778 @@
#!/usr/bin/env python2
#
# (C) Copyright 2015-2019 Sei Lisa. All rights reserved.
#
# This file is part of LSL PyOptimizer.
#
# LSL PyOptimizer is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# LSL PyOptimizer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>.
# Unit testing program.
# Checks all files in unit_tests/*.suite/ with extensions .lsl or .run.
# When one is found, it's considered a test (if both exist, they are considered
# a single test).
#
# Extension .lsl is for source files to test. If the first line starts with
# "// " then the rest of the line is taken as the docstring of that test
# (visible with Eric or with option -v). The script is also fed as standard
# input to the program.
# .run defines the command-line parameters for invocation. A test can be run
# without a .lsl file but with a .run file. If not present, the .lsl file
# is run with the command line 'main.py -'. The quoting rules are sh-style.
# The executable name is ignored, but needs to be present.
# .out is for expected output to stdout. If the first line is "REGEX", then
# the rest of the file is interpreted as a regular expression that the
# output is matched against. Otherwise the output must exactly match.
# If the file is not present, that's equivalent to an empty file, i.e. no
# output is expected.
# .err is like .out but for expected output to stderr, with the same features.
# .skp is for a file that if present, will skip this test. The contents are
# displayed as the reason for being skipped.
# .fail is for a file that, when present, marks the test as expected to fail.
# Its contents are not read (an empty file is OK).
#
# A test passes when the stdout output matches the .out file, and the stderr
# output matches the .err file. Both default to empty strings.
#
import unittest
import sys
import os
#import math
import main
import glob
import re
try:
import difflib
except ImportError:
difflib = None
import StringIO as StringStream
from lslopt import lslcommon,lslfuncs,lslparse,lsloutput,lslloadlib
from lslopt.lslcommon import nr
class EArgError(Exception):
pass
def parseArgs(s):
"""Parse a command line, Bourne shell-style"""
if s is None:
return None
args = []
# States
Space = 0
SBackslash = 1
Normal = 2
NBackslash = 3
DQuote = 4
DQBackslash = 5
SQuote = 6
State = Space
p = 0
Len = len(s)
arg = ''
while p < Len:
c = s[p]
p += 1
if State in (Space, Normal):
if c == '\\':
State = NBackslash if State == Normal else SBackslash
elif c == '"':
State = DQuote
elif c == "'":
State = SQuote
elif c in (' ', '\t'):
if State == Normal:
State = Space
args.append(arg)
arg = ''
# else remain in state Space
elif c == '\n':
break
else:
State = Normal
arg += c
elif State in (SBackslash, NBackslash, DQBackslash):
if c == '\n':
State = (DQuote if State == DQBackslash
else Space if State == SBackslash
else Normal)
else:
if State == DQBackslash and c not in ('"', '`', '$', '\\'):
arg += '\\'
arg += c
State = DQuote if State == DQBackslash else Normal
elif State == DQuote:
if c == '\\':
State = DQBackslash
# ` and $ are not interpreted by this parser.
elif c == '"':
State = Normal
else:
arg += c
elif State == SQuote:
if c == "'":
State = Normal
else:
arg += c
if State in (SQuote, DQuote):
raise EArgError(u"Unterminated string in .run file")
if State in (SBackslash, NBackslash, DQBackslash):
raise EArgError(u"Backslash before EOF in .run file")
if State == Normal:
args.append(arg)
return args
#import codecs
## sh-style argument parsing
## identify line continuations
#cont_re = re.compile( '\\\\\n'
# '|(?:\.|[^ \t\n\'])'
# r"|'[^']*'")
## separates words
#args_re = re.compile(r'(?:'
# r'\\.'
# '|[^ \t\n\'"]'
# r'|"(?:\\.|[^"])*"'
# r"|'[^']*'"
# r')+')
## matches types of parts of a word ('...', "...", \x, x)
#part_re = re.compile(r'(?:'
# r'\\.'
# '|[^ \t\'"]'
# r')+'
# r'|"(?:\\.|[^"])*"'
# r"|'[^']*'")
#
# args = args_re.findall(s)
# for i in range(len(args)):
# arg = args[i]
# argout = ''
# for match in part_re.finditer(arg):
# part = match.group()
# if part[0] == '"':
# argout += codecs.escape_decode(part[1:-1])[0]
# elif part[0] == "'":
# argout += part[1:-1]
# else:
# argout += codecs.escape_decode(part)[0]
# args[i] = argout
# return args
def tryRead(fn):
result = None
try:
f = open(fn, 'r')
try:
result = f.read()
finally:
f.close()
except IOError as e:
if e.errno != 2:
raise
return result
# In StringIO, mixing unicode and str causes problems with non-ASCII chars.
# Avoid it by overriding the write method, to always encode unicode as UTF-8.
class StrUTF8IO(StringStream.StringIO):
def write(self, s):
if type(s) == unicode:
StringStream.StringIO.write(self, s.encode('utf8'))
else:
StringStream.StringIO.write(self, s)
def invokeMain(argv, stdin = None):
"""Invoke main.main, substituting stdin, stdout, stderr.
Returns tuple with stdout and stderr."""
# Revert globals to initial state
lslcommon.LSO = False
lslcommon.IsCalc = False
lslcommon.Bugs.clear()
lslcommon.Bugs.add(6495)
save_stdin = sys.stdin
save_stdout = sys.stdout
save_stderr = sys.stderr
stdout_output = None
stderr_output = None
try:
sys.stdin = StringStream.StringIO(stdin)
sys.stdout = StrUTF8IO()
sys.stderr = StrUTF8IO()
sys.stdin.encoding = 'utf8'
sys.stdout.encoding = 'utf8'
sys.stderr.encoding = 'utf8'
main.main(argv)
stdout_output = sys.stdout.getvalue()
stderr_output = sys.stderr.getvalue()
finally:
sys.stdin = save_stdin
sys.stdout = save_stdout
sys.stderr = save_stderr
lslcommon.LSO = False
lslcommon.IsCalc = False
lslcommon.Bugs.clear()
lslcommon.Bugs.add(6495)
return (stdout_output, stderr_output)
#def tolEqual(actual, expected, tol):
# """Strict equality. Like reallyEqual, but a tolerance can
# be specified for comparing floats.
# """
# if type(actual) != type(expected):
# return False
#
# # Deal with floats (edge cases, tolerance)
# if isinstance(actual, float):
# # Signs must be equal
# if math.copysign(1, actual) != math.copysign(1, expected):
# return False
# if math.isnan(actual):
# # This compares the sign of NaN as well
# return math.isnan(expected)
# if math.isinf(actual) and math.isinf(expected):
# return actual == expected
# return abs(actual - expected) <= tol
#
# # Deal with tuples and lists (item-by-item, recursively)
# if isinstance(actual, (tuple, list)):
# return all(tolEqual(i1, i2, tol)
# for i1, i2 in zip(actual, expected))
#
# # Fall back to 'classic' equality
# return actual == expected
#
#def reallyEqual(actual, expected):
# """Strictest equality. The types must be equal. For floats, it checks
# that the signs are equal, even for -0.0 and for NaNs. For the rest,
# it falls back to ==.
# """
# return tolEqual(actual, expected, 0.0)
#
#def reprEqual(self, actual, expected):
# """Returns whether the values are equal when comparing their repr's."""
# return repr(actual) == repr(expected)
class UnitTestCase(unittest.TestCase):
pass
class UnitTestRegression(UnitTestCase):
def test_regression_misc(self):
"""Miscellaneous tests that can't be computed or are too difficult
to compute with scripts
"""
sys.stderr.write('\nRunning miscellaneous tests: ')
# Test behaviour under BUG-3763
lslcommon.Bugs.add(3763)
self.assertEqual(lslfuncs.llXorBase64(u"ABCDABCDABCD", u"ABCD"),
u"AAAAAAAAABCT")
self.assertEqual(lslfuncs.llXorBase64(u"ABCDABCDABCDABCDABCDABCDABCD",
u"ABCD"),
u"AAAAAAAAABCTgxCDEJODAAAAABCT")
self.assertEqual(lslfuncs.llXorBase64(u"ABCDABCDABCD", u"ABC="),
u"AACDEBCDEBCD")
self.assertEqual(lslfuncs.llXorBase64(u"AQCDAQCD", u"AQC="),
u"AACCAQCC")
lslcommon.Bugs.discard(3763)
# Check that zstr returns the same type it is passed.
self.assertEqual(type(lslfuncs.zstr(lslcommon.Key(u'x\0x'))),
lslcommon.Key)
def test_regression_ll_json(self):
from unit_tests import json
# Patch llJsonSetValue, to allow running the test.
json.llJsonSetValue = lambda x, y, z: u"***"
sys.stderr.write('\nRunning JSON test module: ')
save_stdout = sys.stdout
save_stderr = sys.stderr
stdout_output = False
stderr_output = False
try:
sys.stdout = StringStream.StringIO()
sys.stderr = StringStream.StringIO()
errs = json.run_tests()
stdout_output = sys.stdout.getvalue()
stderr_output = sys.stderr.getvalue()
finally:
sys.stdout = save_stdout
sys.stderr = save_stderr
self.assertLessEqual(errs, 138)
self.assertEqual(stdout_output, tryRead('unit_tests/json.out'))
self.assertEqual(stderr_output, tryRead('unit_tests/json.err'))
assert 'unit_tests.json' in sys.modules
del sys.modules['unit_tests.json']
def test_regression_parser(self):
"""Test the error cases. There are too many to make a test of each."""
sys.stderr.write('\nRunning parser error tests: ')
parser = lslparse.parser(lslloadlib.LoadLibrary())
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'f(){integer i;i>>=i;}')
self.assertRaises(lslparse.EParseCantChangeState, parser.parse,
'f(){if(1)state default;else;}default{timer(){}}')
self.assertRaises(lslparse.EParseCantChangeState, parser.parse,
'f(){if(1);else state default;}default{timer(){}}')
self.assertRaises(lslparse.EParseCantChangeState, parser.parse,
'f(){if(1)if(1)state default;else;else;}default{timer(){}}')
# Test behaviour of void functions
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){<llDie(),0,0>;}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){[<llDie(),0,0>];}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){key a=llDie();}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){key a;a=llDie();}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){do;while(llDie());}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){for(;llDie(););}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){while(llDie());}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){if(llDie());}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){if(llDie());else;}}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'default{timer(){[llDie()];}}', ('optimize',))
parser.parse('default{timer(){[llDie()];}}')
parser.parse('default{timer(){llDie();}}')
parser.parse('default{timer(){(llDie());}}')
parser.parse('default{timer(){for(llDie();1;llDie());}}'
, ('optimize',))
class UnitTestCoverage(UnitTestCase):
def test_coverage_misc(self):
"""Miscellaneous tests that can't be computed or are too difficult
to compute with scripts
"""
sys.stderr.write('\nRunning misc coverage tests: ')
# Doesn't accept bytes
self.assertRaises(lslfuncs.ELSLInvalidType, lslfuncs.zstr, b"blah")
# Can't typecast float to vector
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
lslfuncs.F32(1.2), lslcommon.Vector)
# Can't typecast integer to vector
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
1, lslcommon.Vector)
# Can't typecast vector to key
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
lslcommon.Vector((1.,2.,3.)), lslcommon.Key)
# Can't typecast quaternion to key
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
lslcommon.Quaternion((1.,2.,3.,4.)), lslcommon.Key)
# Can't typecast list to vector
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
[1, 1., lslcommon.Key(u'blah'),
lslcommon.Quaternion((1.,0.,0.,0.))],
lslcommon.Vector)
# Can't typecast key to integer
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.typecast,
lslcommon.Key(u"1"), int)
# Can't negate string
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.neg, u"3")
# Can't add two keys
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.add,
lslcommon.Key(u"1"), lslcommon.Key(u"2"))
# Can't subtract two strings
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.sub,
u"1", u"2")
# Can't multiply two strings
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.mul,
u"1", u"2")
# Can't multiply quaternion and float in any order
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.mul,
lslcommon.Quaternion((1.,2.,3.,4.)), 1.)
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.mul,
1., lslcommon.Quaternion((1.,2.,3.,4.)))
# Can't multiply quaternion by vector (but the opposite order is OK)
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.mul,
lslcommon.Quaternion((1.,2.,3.,4.)),
lslcommon.Vector((1.,2.,3.)))
# Can't divide quaternion by vector either
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.div,
lslcommon.Quaternion((1.,2.,3.,4.)),
lslcommon.Vector((1.,2.,3.)))
# Can't mod floats
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.mod, 3., 3)
# Can't compare string and integer
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.compare, u'3', 4)
self.assertRaises(lslfuncs.ELSLTypeMismatch, lslfuncs.less, u'3', 4)
# Bytes is not a valid type to multiply by (in any order)
self.assertRaises(lslfuncs.ELSLInvalidType, lslfuncs.mul, b"a", 3)
self.assertRaises(lslfuncs.ELSLInvalidType, lslfuncs.mul,
lslcommon.Vector((3.,4.,5.)), b"a")
self.assertRaises(lslfuncs.ELSLInvalidType, lslfuncs.typecast,
b"", unicode)
# v2f/q2f coverage (force conversion from ints to floats)
self.assertEqual(repr(lslfuncs.v2f(lslcommon.Vector((1,0,0)))),
'Vector((1.0, 0.0, 0.0))')
self.assertEqual(repr(lslfuncs.q2f(lslcommon.Quaternion((1,0,0,0)))),
'Quaternion((1.0, 0.0, 0.0, 0.0))')
# Key repr coverage
self.assertEqual(repr(lslcommon.Key(u'')), "Key(u'')")
# string + key coverage
self.assertEqual(lslfuncs.add(u'a', lslcommon.Key(u'b')), u'ab')
self.assertEqual(type(lslfuncs.add(u'a', lslcommon.Key(u'b'))), unicode)
# The SEF table prevents this assertion from being reachable via script.
self.assertRaises(lslfuncs.ELSLCantCompute, lslfuncs.llXorBase64Strings,
u"AABA", u"AABA")
self.assertRaises(lslfuncs.ELSLCantCompute, lslfuncs.llModPow,
3, 5, 7)
# Check invalid type in llGetListEntryType
self.assertRaises(lslfuncs.ELSLInvalidType, lslfuncs.llGetListEntryType,
[b'a'], 0)
# Check that Value2LSL raises an exception if the type is unknown.
outmod = lsloutput.outscript()
# Script with a single node of type Expression, containing a constant
# of type Bytes. That's rejected by the output module.
msg = None
script = [nr(nt='EXPR', t='string', ch=[
nr(nt='CONST', t='string', value=b'ab')
])]
save_IsCalc = lslcommon.IsCalc
lslcommon.IsCalc = True
try:
try:
outmod.output((script, ()))
except AssertionError as e:
msg = str(e)
finally:
lslcommon.IsCalc = save_IsCalc
self.assertEqual(msg, u"Value of unknown type in Value2LSL: 'ab'")
del msg
# Extended assignment in output
script = [nr(nt='EXPR', t='integer', ch=[
nr(nt='^=', t='integer', ch=[
nr(nt='IDENT', t='integer', name='a', scope=0),
nr(nt='CONST', t='integer', value=3)
])])]
save_IsCalc = lslcommon.IsCalc
lslcommon.IsCalc = True
try:
out = outmod.output((script, [{'a':{'Kind':'v','Loc':1,'Scope':0,
'Type':'integer'}
}]
))
finally:
lslcommon.IsCalc = save_IsCalc
self.assertEqual(out, 'a = a ^ (3)')
del out, script, outmod, save_IsCalc
def test_coverage_parser(self):
"""Cover the error cases. There are too many to make a test of each."""
parser = lslparse.parser(lslloadlib.LoadLibrary(
builtins = 'unit_tests/builtins-coverage-2.txt',
fndata = 'unit_tests/builtins-coverage-2.txt'))
self.assertRaises(lslparse.EParseNoConversion, parser.parse,
'f(){list L;(integer)L[0];}', ('lazylists',))
parser = lslparse.parser(lslloadlib.LoadLibrary())
sys.stderr.write('\nRunning parser exception coverage tests: ')
# Parse_unary_postfix_expression
self.assertRaises(lslparse.EParseUEOF, parser.parse, u'f(){key x=')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'f(){g();}')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'integer g;f(){g();}')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'f(){f=0;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){integer V; V[1] = 0;}', ('lazylists',))
self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
'f(){list V; V[1,1] = 0;}', ('lazylists',))
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){list V; V[""] = 0;}', ('lazylists',))
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){list V; V[1] = llDie();}', ('lazylists',))
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s++;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;++s;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s=llDie();}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s+=(key)"";}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s-=s;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s*=2;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){vector v;v%=1.0;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){string s;s>>=s;}', ('extendedassignment',))
# Parse_unary_expression
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){-"";}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){!"";}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){~"";}')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'f(){++f;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){(key)1;}')
self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
'f(){list L;(integer)L[""];}', ('lazylists',))
# Parse_factor
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""*2;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){<1,1,1>%2;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){<1,1,1>/<1,1,1>;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){<1,1,1>/"";}')
# Parse_term
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){llDie()+1;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""-1;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){[]+llDie();}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){(key)""+(key)"";}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""+(key)"";}')
# Parse_shift
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){"">>1;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){1<<"";}')
# Parse_inequality
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""<"";}')
# Parse_comparison
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){llDie()==3;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""==3;}')
# Parse_bitbool_factor
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""&3;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){3&"";}')
# Parse_bitxor_term
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""^3;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){3^"";}')
# Parse_bitbool_term
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""|3;}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){3|"";}')
# Parse_expression
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){3||"";}')
self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
'f(){""&&3;}')
# Parse_optional_expression_list
self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
'f(){llSay(0);}')
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
'f(){@x;@x;}')
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
'f(){integer x;integer x;}')
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
'f(integer x, integer x){}')
self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
'default{timer(){}timer(){}}')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(){state state;}}')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'default{timer(){state undefined;}}')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(){switch(1){case 1;}}}', ('enableswitch',))
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(){switch(1){default;}}}', ('enableswitch',))
self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
'default{timer(){while(1){break 0;}}}', ('breakcont',))
self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
'default{timer(){while(1){break 2;}}}', ('breakcont',))
self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
'default{timer(){while(1){continue 0;}}}', ('breakcont',))
self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
'default{timer(){while(1){continue 2;}}}', ('breakcont',))
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'integer T=-TRUE;default{timer(){}}')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'list L=[[]];default{timer(){}}')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(integer i){}}')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'i = 0;',)
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(){}}state{timer(){}}')
self.assertRaises(lslparse.EParseUndefined, parser.parse,
'default{timer(){jump undefined;}}')
# BuildTempGlobalsTable coverage
self.assertRaises(lslparse.EParseSyntax, parser.parse,
';')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'f(;')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'f();')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'integer f=')
self.assertRaises(lslparse.EParseUEOF, parser.parse,
'integer /*')
self.assertRaises(lslparse.EParseSyntax, parser.parse,
'default{timer(){}}state e;')
class UnitTestExpr(UnitTestCase):
pass
class UnitTestLSO(UnitTestCase):
pass
class UnitTestPreproc(UnitTestCase):
pass
def generateScriptTests():
"""Find all files in unit_tests/*.d/*.{lsl,run} and generate tests for
them.
"""
path = os.path.dirname(__file__)
if path:
os.chdir(path)
testsuites = ('Regression', 'Coverage', 'Expr', 'LSO', 'Preproc')
for testsuite in testsuites:
files = glob.glob(os.path.join('unit_tests',
testsuite.lower() + '.suite', '*.lsl')
) + glob.glob(os.path.join('unit_tests',
testsuite.lower() + '.suite', '*.run')
)
files = list(set([os.path.splitext(x)[0] for x in files]))
files.sort()
for fbase in files:
# Create a closure with the test data
def makeTestFunction(fbase, suite):
def TestFunction(self):
stdin = tryRead(fbase + '.lsl') or ''
expected_stdout = tryRead(fbase + '.out') or ''
expected_stderr = tryRead(fbase + '.err') or ''
runargs = (parseArgs(tryRead(fbase + '.run'))
or (['main.py', '-y', '-'] if suite != 'Expr'
else ['main.py',
# Defaults for Expr:
'-O', 'clear,optimize,constfold'
',addstrings,expr',
'-y',
'-']))
sys.stderr.write("\nRunning test %s: " % fbase)
actual_stdout, actual_stderr = invokeMain(runargs, stdin)
actual_stdout = (actual_stdout.replace('\r','\r\n')
.replace('\r\n\n','\n')
.replace('\r\n','\n'))
actual_stderr = (actual_stderr.replace('\r','\r\n')
.replace('\r\n\n','\n')
.replace('\r\n','\n'))
try:
if expected_stderr.startswith('REGEX\n'):
self.assertIsNotNone(
re.search(expected_stderr[6:],
actual_stderr.decode('utf8')
)
)
else:
self.assertEqual(expected_stderr, actual_stderr)
except AssertionError:
sys.stderr.write('Failed'
'\n************ expected stderr:\n')
sys.stderr.write(expected_stderr)
sys.stderr.write('\n************ actual stderr:\n')
sys.stderr.write(actual_stderr)
if difflib and expected_stderr and actual_stderr:
sys.stderr.write('\n************ diff:\n'
+ '\n'.join(difflib.unified_diff(
expected_stderr.split('\n'),
actual_stderr.split('\n'),
'expected', 'actual', lineterm=''
)))
sys.stderr.write('\n************ ')
raise
try:
if expected_stdout.startswith('REGEX\n'):
self.assertIsNotNone(re.search(expected_stdout[6:],
actual_stdout))
else:
self.assertEqual(expected_stdout, actual_stdout)
except AssertionError:
sys.stderr.write('Failed'
'\n************ expected stdout:\n')
sys.stderr.write(expected_stdout)
sys.stderr.write('\n************ actual stdout:\n')
sys.stderr.write(actual_stdout)
if difflib and expected_stdout and actual_stdout:
sys.stderr.write('\n************ diff:\n'
+ '\n'.join(difflib.unified_diff(
expected_stdout.split('\n'),
actual_stdout.split('\n'),
'expected', 'actual', lineterm=''
)))
sys.stderr.write('\n************ ')
raise
return TestFunction
TestFunction = makeTestFunction(fbase, testsuite)
# __doc__ is used by Eric
line = ''
try:
f = open(fbase + '.lsl')
try:
line = f.readline()
if line.endswith('\r\n'):
line = line[:-2]
elif line[-1:] in ('\r', '\n'):
line = line[:-1]
finally:
f.close()
except IOError as e:
if e.errno != 2:
raise
TestFunction.__doc__ = line[3:] if line.startswith('// ') else None
TestFunction.__name__ = ('test_' + testsuite + '__'
+ os.path.basename(fbase).replace('-','_'))
if os.path.exists(fbase + '.fail'):
TestFunction = unittest.expectedFailure(TestFunction)
else:
skip = tryRead(fbase + '.skp')
if skip is not None:
TestFunction = unittest.skip(skip)(TestFunction)
setattr(globals()['UnitTest' + testsuite],
TestFunction.__name__, TestFunction)
generateScriptTests()
if __name__ == '__main__':
unittest.main(argv = sys.argv)

34
unit_tests/README.txt Normal file
View file

@ -0,0 +1,34 @@
Unit testing suites. These tests are run via run-tests.py.
The testing is performed using the standard Python module 'unittest'. This module accepts some command-line options; we don't add any ourselves. Use 'python run-tests.py -h' for help, or look here for details: https://docs.python.org/2/library/unittest.html#command-line-interface
There are 5 directories defined in the code that contain tests, all of which end in .suite: regression.suite, expr.suite, lso.suite, coverage.suite, preproc.suite.
The files that all 5 contain are the tests themselves. The run-tests.py program reads all .run and .lsl files in each directory and takes them as tests to run.
A test is a series of files all with the same name and with different extensions. Running the test means running the optimizer with the parameters in the .run file (if present), giving it the .lsl file (if present) as input. The output to stdout is compared to the .out file and the output to stderr is compared to the .err file. The test passes if both match and no exception is raised; otherwise it fails.
These are the extensions that the test suite recognizes in more detail:
.lsl: Source file to test. If the first line starts with '// ', then the text in the rest of the line will be set as the docstring for the corresponding test function (visible when requesting verbose coverage).
.run: Command line parameters for the test. Default is: 'main.py -', except in expr.suite which defaults to 'main.py -O clear,optimize,constfold,addstrings,expr -'. The syntax for the parameters is that of the Bourne shell, but '$' expansion is not supported. The 'main.py' part is the value that argv[0] will receive, but is unused otherwise.
.out: Expected stdout resulting from the test. If the first line is REGEX then the rest of the file will be taken as a regular expression to match against, as opposed to matching the whole file contents.
.err: Expected stderr resulting from the test. It also allows regular expression.
.skp: If present, the test will be skipped (not run). The contents of this file are taken as the reason for the expected failure.
.fail: If present, the test will be run, and counted as an expected failure. If a .fail file is present and the test passes, that will be counted as an unexpected success, and the program will not report success at the end. The contents will be ignored; zero-length files are OK.
A test is considered such when either the .lsl or the .run file are present. The default stdin for the program is the .lsl file.
As for the meaning of each subdirectory:
- regression.suite contains normal regression tests.
- expr.suite contains regression tests that apply to expressions.
- lso.suite contains LSO mode tests. Note that LSO support is incomplete.
- coverage.suite contains tests that force certain code paths to execute, in order to maximize the exercised code coverage, even if some tests are trivial and unlikely to cause a regression.
- preproc.suite is for preprocessor-related tests.
As for the files in this directory:
- cat.py just copies standard input to standard output. Used as a preprocessor for some preprocessor tests.
- false.py just terminates with exit code 1.
- output-list.lsl is a utility script that dumps an arbitrary list to local chat, in a format very similar to the one that the expression suite outputs (it may require manual removal of timestamps). Float precision may differ.

View file

@ -0,0 +1,2 @@
event ev()
const list LIST_CONSTANT = []

View file

View file

@ -0,0 +1,21 @@
const key a="\t"
event ev(integer i)
event ev(integer i)
quaternion x(integer i)
void x(integer i)
blah x1(integer i)
integer x2(unknown i)
blah
const vector a = <4,5,3,2>
const vector a = <4,5,3,2
const vector a = <x,4,3>
const vector a = <4,x,3>
const vector a = <3,4,x>
const rotation a = <3,4,4,x>
const list l = []
const quaternion q=<1,2,3,4>
const string v="
const string q="\t"
const unknown x3 = 3
const list L = [1]
const list L2 = [

View file

@ -0,0 +1,5 @@
float llCos( float theta )
integer llModPow( integer a, integer b, integer c )
event timer( )
event no_sensor()
event touch(integer x)

2
unit_tests/cat.py Normal file
View file

@ -0,0 +1,2 @@
import sys
sys.stdout.write(sys.stdin.read())

View file

@ -0,0 +1,9 @@
// Cover auxiliary functions.
default
{
timer()
{
llOwnerSay(llStringToBase64(llList2Key([TEXTURE_BLANK],0)));
llOwnerSay(llStringToBase64(llList2Key([(key)TEXTURE_BLANK],0)));
}
}

View file

@ -0,0 +1,8 @@
default
{
timer()
{
llOwnerSay("NTc0OGRlY2MtZjYyOS00NjFjLTlhMzYtYTM1YTIyMWZlMjFm");
llOwnerSay("NTc0OGRlY2MtZjYyOS00NjFjLTlhMzYtYTM1YTIyMWZlMjFm");
}
}

View file

@ -0,0 +1,9 @@
integer a = 0;
float f = 0.0;
vector v = <0.,0.,0.>;
rotation r = <0.,0.,0.,1.>;
key k = "";
string s = "";
list l = [];
default{state_entry(){}}

View file

@ -0,0 +1,14 @@
integer a;
float f = 0;
vector v = <0, 0, 0>;
rotation r = <0, 0, 0, 1>;
key k = "";
string s = "";
list l = [];
default
{
timer()
{
}
}

View file

@ -0,0 +1 @@
./main.py - -O -dcr

View file

@ -0,0 +1 @@
default{no_sensor(){}}

View file

@ -0,0 +1,6 @@
default
{
timer()
{
}
}

View file

@ -0,0 +1 @@
main.py unit_tests/coverage.suite/existing-filename.lsl

View file

@ -0,0 +1,18 @@
default
{
timer()
{
llModPow(5, 7, 3);
llCos(5);
}
// this one should be kept, as it's not marked as SEF in the test data
no_sensor()
{
}
// this one should disappear
touch(integer k)
{
}
}

View file

@ -0,0 +1,11 @@
default
{
timer()
{
llCos(5);
}
no_sensor()
{
}
}

View file

@ -0,0 +1,2 @@
main.py -b unit_tests/builtins-coverage-5.txt \
-L unit_tests/fndata-coverage-5.txt -

View file

@ -0,0 +1,16 @@
e(){}
integer a;
integer b;
f(){}
g(){}
integer c;
integer d;
h(){}
default
{
timer() {}
touch(integer n) {}
touch_start(integer n) {}
touch_end(integer n) {}
}
state s2{timer(){}}

View file

@ -0,0 +1,47 @@
e()
{
}
integer a;
integer b;
f()
{
}
g()
{
}
integer c;
integer d;
h()
{
}
default
{
timer()
{
}
touch(integer n)
{
}
touch_start(integer n)
{
}
touch_end(integer n)
{
}
}
state s2
{
timer()
{
}
}

View file

@ -0,0 +1 @@
./main.py --prettify -O clear -

View file

@ -0,0 +1,2 @@
REGEX
ProgName -O -DCR,\+BreakCont scriptname\.lsl

View file

@ -0,0 +1 @@
ProgName -O help

View file

@ -0,0 +1,9 @@
// Test inclusion of headers and invalidation of comments
/*
blah
/|*
/||*
*/
default{timer(){}}

View file

@ -0,0 +1,24 @@
REGEX
//start_unprocessed_text
/\*// Test inclusion of headers and invalidation of comments
/\*
blah
/\|\|\*
/\|\|\|\*
\*\|/
default\{timer\(\)\{\}\}
\*/
//end_unprocessed_text
//nfo_preprocessor_version 0
//program_version LSL PyOptimizer .* - Sei Lisa
//mono
// Generated on 20.*Z
default
\{
timer\(\)
\{
\}
\}

View file

@ -0,0 +1 @@
main.py -T -H --avname=Sei\ Lisa --shortname=script.lsl -

View file

@ -0,0 +1,49 @@
f1() inline
{
llOwnerSay("f1");
}
f2(integer f2param) inline
{
llOwnerSay("f2:" + (string)f2param);
}
vector f3(integer f3p1, string f3p2) inline
{
f2(f3p1);
integer f3p1; // test shading the parameter
{
jump x;
llOwnerSay("f3:" + (string)f3p1 + f3p2);
}
@x;
if (f3p2 != "") return <1,1,1>;
do ; while (f4());
return <0,0,0>;
}
integer f4() inline
{
return llGetLinkNumber();
}
say(string s) inline
{
llOwnerSay(s);
}
default
{
state_entry()
{
f1();
if (1) f1();
f2(3);
if (f3(4, "x") == ZERO_VECTOR) llOwnerSay("ok");
}
timer()
{
say("hi");
}
}

View file

@ -0,0 +1,71 @@
default
{
state_entry()
{
{
llOwnerSay("f1");
}
if (1)
{
llOwnerSay("f1");
}
{
integer f2param = 3;
{
llOwnerSay("f2:" + (string)f2param);
}
}
vector ___ret__00001;
{
integer f3p1 = 4;
string f3p2 = "x";
{
{
integer f2param = f3p1;
{
llOwnerSay("f2:" + (string)f2param);
}
}
integer f3p1;
{
jump ___lbl__00005;
llOwnerSay("f3:" + (string)f3p1 + f3p2);
}
@___lbl__00005;
if (f3p2 != "")
{
___ret__00001 = <1, 1, 1>;
jump ___rtl__00004;
}
integer ___ret__00002;
{
{
___ret__00002 = llGetLinkNumber();
jump ___rtl__00007;
}
}
@___rtl__00007;
do
;
while (___ret__00002);
{
___ret__00001 = <0, 0, 0>;
jump ___rtl__00004;
}
}
}
@___rtl__00004;
if (___ret__00001 == <0., 0., 0.>)
llOwnerSay("ok");
}
timer()
{
{
string s = "hi";
{
llOwnerSay(s);
}
}
}
}

View file

@ -0,0 +1 @@
main.py -y -O clear,inline -

View file

@ -0,0 +1 @@
EExpansionLoop: Loop found in expansion of inline functions

View file

@ -0,0 +1,19 @@
f1() inline
{
llOwnerSay("f1");
f2();
}
f2() inline
{
llOwnerSay("f2");
f1();
}
default
{
state_entry()
{
f1();
}
}

View file

@ -0,0 +1 @@
main.py -O clear,inline -

View file

@ -0,0 +1,11 @@
// Test inline, by Sei Lisa
say(string s) inline
{
llOwnerSay(s);
}
default{timer(){
say("hey");
}}

View file

@ -0,0 +1,11 @@
default
{
timer()
{
{
{
llOwnerSay("hey");
}
}
}
}

View file

@ -0,0 +1,49 @@
f1() inline
{
llOwnerSay("f1");
}
f2(integer f2param) inline
{
llOwnerSay("f2:" + (string)f2param);
}
vector f3(integer f3p1, string f3p2) inline
{
f2(f3p1);
integer f3p1; // test shading the parameter
{
jump x;
llOwnerSay("f3:" + (string)f3p1 + f3p2);
}
@x;
if (f3p2 != "") return <1,1,1>;
do ; while (f4());
return <0,0,0>;
}
integer f4() inline
{
return llGetLinkNumber();
}
say(string s) inline
{
llOwnerSay(s);
}
default
{
state_entry()
{
f1();
if (1) f1();
f2(3);
if (f3(4, "x") == ZERO_VECTOR) llOwnerSay("ok");
}
timer()
{
say("hi");
}
}

View file

@ -0,0 +1,62 @@
default
{
state_entry()
{
{
llOwnerSay("f1");
}
{
llOwnerSay("f1");
}
{
{
llOwnerSay("f2:" + "3");
}
}
vector ___ret__00001 = <((float)0), ((float)0), ((float)0)>;
{
{
{
{
llOwnerSay("f2:" + "4");
}
}
{
jump ___lbl__00005;
}
@___lbl__00005;
{
___ret__00001 = <((float)1), ((float)1), ((float)1)>;
jump ___rtl__00004;
}
integer ___ret__00002;
{
{
___ret__00002 = llGetLinkNumber();
jump ___rtl__00007;
}
}
@___rtl__00007;
do
;
while (___ret__00002);
{
___ret__00001 = <((float)0), ((float)0), ((float)0)>;
jump ___rtl__00004;
}
}
}
@___rtl__00004;
if (___ret__00001 == <((float)0), ((float)0), ((float)0)>)
llOwnerSay("ok");
}
timer()
{
{
{
llOwnerSay("hi");
}
}
}
}

View file

@ -0,0 +1,2 @@
REGEX
IOError: (?:\[Errno 21\] Is a directory|\[Errno 13\] Permission denied): 'unit_tests/coverage.suite/actually-a-dir.d'

View file

@ -0,0 +1 @@
main.py unit_tests/coverage.suite/actually-a-dir.d

View file

@ -0,0 +1,3 @@
REGEX
Error: option --invalid-option not recognized

View file

@ -0,0 +1 @@
main.py --invalid-option

View file

@ -0,0 +1,3 @@
default{timer(){x;}}
^
(Line 10 char 17): ERROR in "somefile.lsl": Name not defined within scope

View file

@ -0,0 +1,4 @@
#line 1 "<stdin>"
#line 1 "somefile.lsl"
#line 10
default{timer(){x;}}

View file

@ -0,0 +1 @@
main.py -O processpre -

View file

@ -0,0 +1,9 @@
// Cover optimizer.Cast() using a call in lsldeadcode.
default{timer(){
vector v;
float f = llGetNumberOfSides() + v.x = 3;
llOwnerSay((string)[f]);
}}

View file

@ -0,0 +1,8 @@
default
{
timer()
{
float f = ((float)3) + llGetNumberOfSides();
llOwnerSay((string)((list)f));
}
}

View file

@ -0,0 +1 @@
main.py -

View file

@ -0,0 +1,2 @@
WARNING: Illegal combo: Key type inside a global list
WARNING: A string contains a tab. Tabs are expanded to four spaces by the viewer when copy-pasting the code (disable this warning by disabling the 'warntabs' option).

View file

@ -0,0 +1,37 @@
list L = [llList2Key([llUnescapeURL("%09")], 0)];
float f1 = -0.; // kept the same
float f2 = -3.; // transformed to -3
default
{
state_entry()
{
float f0 = -15.5; // transformed to (float)-15.5
vector v = <f0, f1, f2>;
rotation r = <f0, f1, f2, f0>;
integer i;
while (llFrand(2) > 1)
{
llOwnerSay((string)(f0 + f1 + f2 + i));
llSetPrimitiveParams(L);
llSetPrimitiveParams(L);
L = llGetPhysicsMaterial();
f0 = llList2Float(L, 0);
f1 = llList2Float(L, 1);
f2 = llList2Float(L, 2);
i = llList2Integer(L, i++);
i = llList2Integer(L, i--);
v = <f1, 0, 0>;
r = <f1, 0, 0, 0>f1>;
llSetRegionPos(v);
llSetLocalRot(r);
print(r.s);
++i; --i;
if (i)
i >>= 1;
else if (i > llFrand(3))
return;
L[2] = (integer)L[3];
}
}
}

View file

@ -0,0 +1,45 @@
list lazy_list_set(list L, integer i, list v)
{
while ((L != []) < i)
L = L + 0;
return llListReplaceList(L, v, i, i);
}
list L = [(key)" "];
float f1 = -0.;
float f2 = -3;
default
{
state_entry()
{
float f0 = ((float)-15.5);
vector v = <f0, f1, f2>;
rotation r = <f0, f1, f2, f0>;
integer i;
while (1 < llFrand(2))
{
llOwnerSay((string)(f0 + f1 + f2 + i));
llSetPrimitiveParams(L);
llSetPrimitiveParams(L);
L = llGetPhysicsMaterial();
f0 = llList2Float(L, 0);
f1 = llList2Float(L, 1);
f2 = llList2Float(L, 2);
i = llList2Integer(L, i++);
i = llList2Integer(L, i--);
v = <f1, 0, 0>;
r = <f1, 0, 0, (f1 < 0)>;
llSetRegionPos(v);
llSetLocalRot(r);
print(r.s);
++i;
--i;
if (i)
i = i >> 1;
else if (llFrand(3) < i)
return;
L = lazy_list_set(L, 2, (list)llList2Integer(L, 3));
}
}
}

View file

@ -0,0 +1 @@
main.py -O foldtabs,lazylists -

View file

@ -0,0 +1,8 @@
default
{
state_entry()
{
list L = llGetPhysicsMaterial();
for(L[1];llFrand(2)<1;);
}
}

View file

@ -0,0 +1,9 @@
default
{
state_entry()
{
list L = llGetPhysicsMaterial();
for ((MISSING TYPE)L[1]; llFrand(2) < 1; )
;
}
}

View file

@ -0,0 +1 @@
main.py -O -dcr,-constfold,lazylists -

View file

@ -0,0 +1 @@
This generates a runtime error now

View file

@ -0,0 +1,56 @@
// Coverage tests of normal parsing
f(){f();} // triggers FindSymbolPartial's last lines except the very last
integer g(){if(1)return 1;else return 1;}
integer T = TRUE;
vector V = <1,-2,TRUE>;
quaternion Q = <PI, 1.0, 0, 1>;
list L = [];
default
{
timer()
{
integer i;
float f;
vector v;
// Parse_vector_rotation_tail
<0,0,0.1>1>;
// Parse_unary_postfix_expression
ZERO_VECTOR;
i = 1;
i += i;
f += i;
i -= 1;
i *= f;
i /= 1;
i %= 1;
v *= i;
++v.x;
// Parse_bitxor
2^2;
// Parse_expression
1&&1;
// Parse_statement
@J;
1;
jump J;
// Scanner coverage
quaternion q;
1.3f;
0x0;
0x00000100000000;
4294967296;
42949672950;
L"\t\"";
1 // Not a string delimiter because it has \ at EOL:
" \
// Not a string delimiter because it's the last double quote
// in the file:
";
}
}

View file

@ -0,0 +1,51 @@
f()
{
f();
}
integer g()
{
if (1)
return 1;
else
return 1;
}
integer T = 1;
vector V = <1, -2, 1>;
rotation Q = <3.1415927, 1., 0, 1>;
list L = [];
default
{
timer()
{
integer i;
float f;
vector v;
<0, 0, (0.1 > 1)>;
<0., 0., 0.>;
i = 1;
i += i;
f += i;
i -= 1;
i *= f;
i /= 1;
i %= 1;
v *= i;
++v.x;
2 ^ 2;
1 && 1;
@J;
1;
jump J;
rotation q;
1.3;
0;
-1;
-1;
-1;
"\" \"";
1;
}
}

View file

@ -0,0 +1 @@
main.py -y -O clear -

View file

@ -0,0 +1,57 @@
// Test the extra features of the parser, to complete coverage.
string S = "a" "b"; // juxtaposition in globals
f(){}
integer f(){return 1;}
default
{
timer()
{
// String juxtaposition coverage
"a" "b";
// Explicit cast and extended cast coverage
integer i;
float f;
list L;
f += i;
L += (integer)(float)i;
i = ~(integer)-2*3;
i = ~(integer)-2.*3;
i = ~(integer)-i*3;
// AllowKeyConcat coverage
""+(key)"";
(key)""+"";
// Parse_statement with duplicate labels.
@J;
// does_something() coverage
switch(1)
{
{1;}
}
// loops, switch and break/continue
while (1) {break;for (;2;) {continue;break;} continue;}
do { continue; break 1; } while (1);
jump x;
while (1) @x;
jump y;
for (;1;) @y;
jump z;
do @z; while (0);
switch(1.0)
{
case 1: {1;}
}
switch(1)
{
default {}
}
while (1) continue;
while (1) while (1) while (1) continue 3;
}
}

View file

@ -0,0 +1,93 @@
string S = "ab";
integer f()
{
return 1;
}
default
{
timer()
{
"ab";
integer i;
float f;
list L;
f += (float)i;
L += (list)((integer)((float)i));
i = (~(integer)-2) * 3;
i = (~(integer)-2.) * 3;
i = (~(integer)(-i)) * 3;
"" + (string)((key)"");
(string)((key)"") + "";
@J;
{
jump J_autoGen00001;
{
1;
}
@J_autoGen00001;
}
{
while (1)
{
jump J_autoGen00002;
{
for (; 2; )
{
jump J_autoGen00005;
jump J_autoGen00004;
@J_autoGen00005;
}
@J_autoGen00004;
}
jump J_autoGen00003;
@J_autoGen00003;
}
@J_autoGen00002;
}
{
do
{
jump J_autoGen00007;
jump J_autoGen00006;
@J_autoGen00007;
}
while (1);
@J_autoGen00006;
}
jump x;
while (1)
@x;
jump y;
for (; 1; )
@y;
jump z;
do
@z;
while (0);
{
if (1. == (float)1)
jump J_autoGen00015;
jump J_autoGen00014;
@J_autoGen00015;
{
1;
}
@J_autoGen00014;
}
{
{
}
}
while (1)
;
while (1)
{
while (1)
while (1)
jump J_autoGen00022;
@J_autoGen00022;
}
}
}

View file

@ -0,0 +1 @@
main.py -O clear,allowmultistrings,enableswitch,explicitcast,extendedassignment,extendedtypecast,allowkeyconcat,duplabels,processpre,breakcont,funcoverride -

View file

@ -0,0 +1,3 @@
default{ev(){
list L = LIST_CONSTANT;
}}

View file

@ -0,0 +1,7 @@
default
{
ev()
{
list L = [];
}
}

View file

@ -0,0 +1 @@
main.py -b unit_tests/builtins-coverage-1.txt -L unit_tests/fndata-coverage-3.txt -O -dcr -

View file

@ -0,0 +1,25 @@
WARNING: Key constants not supported in unit_tests/builtins-coverage-4.txt, line 1: const key a="\t"
WARNING: Event at line 3 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: ev
WARNING: Function at line 5 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: x
WARNING: Invalid type in unit_tests/builtins-coverage-4.txt, line 6: blah
WARNING: Invalid type in unit_tests/builtins-coverage-4.txt, line 7: unknown
WARNING: Syntax error in unit_tests/builtins-coverage-4.txt, line 8
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 9: const vector a = <4,5,3,2>
WARNING: Global at line 10 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: a
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 10: const vector a = <4,5,3,2
WARNING: Global at line 11 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: a
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 11: const vector a = <x,4,3>
WARNING: Global at line 12 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: a
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 12: const vector a = <4,x,3>
WARNING: Global at line 13 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: a
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 13: const vector a = <3,4,x>
WARNING: Global at line 14 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: a
WARNING: Invalid vector/rotation syntax in unit_tests/builtins-coverage-4.txt line 14: const rotation a = <3,4,4,x>
WARNING: Invalid string in unit_tests/builtins-coverage-4.txt line 17: const string v="
WARNING: Global at line 18 was already defined in unit_tests/builtins-coverage-4.txt, overwriting: q
WARNING: Invalid type in unit_tests/builtins-coverage-4.txt, line 19: unknown
WARNING: Non-empty list constants not supported in unit_tests/builtins-coverage-4.txt, line 20: const list L = [1]
WARNING: Invalid list value in unit_tests/builtins-coverage-4.txt, line 21: const list L2 = [
^
(Line 1 char 1): ERROR: Unexpected EOF

View file

View file

@ -0,0 +1 @@
main.py -b unit_tests/builtins-coverage-4.txt -L unit_tests/fndata-coverage-4.txt -O -dcr,-processpre -

View file

@ -0,0 +1,3 @@
integer a;
^
(Line 2 char 10): ERROR: Name previously declared within scope

View file

@ -0,0 +1,2 @@
integer a;
integer a;

View file

@ -0,0 +1 @@
main.py -O clear - -y

View file

@ -0,0 +1,3 @@
default: ;
^
(Line 2 char 5): ERROR: 'default' used outside a 'switch' statement

View file

@ -0,0 +1,3 @@
x(){
default: ;
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
case 1: ;
^
(Line 3 char 3): ERROR: 'case' used outside a 'switch' statement

View file

@ -0,0 +1,4 @@
x()
{
case 1: ;
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
{case 1: ;}
^
(Line 5 char 10): ERROR: 'case' label only allowed at the main 'switch' block

View file

@ -0,0 +1,7 @@
x()
{
switch(1)
{
{case 1: ;}
}
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
{default:;}
^
(Line 5 char 10): ERROR: 'default' label only allowed at the main 'switch' block

View file

@ -0,0 +1,7 @@
x()
{
switch(1)
{
{default:;}
}
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
}
^
(Line 8 char 1): ERROR: multiple 'default' labels inside 'switch' statement

View file

@ -0,0 +1,8 @@
x()
{
switch(1)
{
default: ;;
default: ;;
}
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
}
^
(Line 7 char 1): ERROR: Missing 'default:' label inside 'switch' statement; disable option 'errmissingdefault' to disable this error.

View file

@ -0,0 +1,7 @@
x()
{
switch(1)
{
case 1: ;;
}
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch,errmissingdefault -

View file

@ -0,0 +1,3 @@
break;
^
(Line 3 char 5): ERROR: 'break' used outside a switch

View file

@ -0,0 +1,4 @@
x()
{
break;
}

View file

@ -0,0 +1 @@
main.py -O clear,enableswitch -

View file

@ -0,0 +1,3 @@
break;
^
(Line 3 char 5): ERROR: 'break' used outside a loop

View file

@ -0,0 +1,4 @@
x()
{
break;
}

View file

@ -0,0 +1 @@
main.py -O clear,breakcont -

View file

@ -0,0 +1,3 @@
continue;
^
(Line 3 char 5): ERROR: 'continue' used outside a loop

View file

@ -0,0 +1,4 @@
x()
{
continue;
}

View file

@ -0,0 +1 @@
main.py -O clear,breakcont -

View file

@ -0,0 +1,3 @@
#define a \
^
(Line 1 char 1): ERROR: Preprocessor directive can't end in backslash. Activate the preprocessor or put everything in the same line.

View file

@ -0,0 +1,3 @@
#define a \
x(){}

View file

@ -0,0 +1 @@
main.py -O clear,processpre -

View file

@ -0,0 +1,3 @@
return 0;
^
(Line 2 char 8): ERROR: Return statement type doesn't match function return type

Some files were not shown because too many files have changed in this diff Show more