2020from collections import namedtuple
2121from collections import OrderedDict
2222from unittest import TestCase
23+ from unittest .case import expectedFailure
2324import sys
2425
2526from boolean .boolean import PARSE_UNBALANCED_CLOSING_PARENS
2930from license_expression import PARSE_INVALID_NESTING
3031from license_expression import PARSE_INVALID_EXCEPTION
3132from license_expression import PARSE_INVALID_SYMBOL_AS_EXCEPTION
33+ from license_expression import PARSE_INVALID_OPERATOR_SEQUENCE
3234
3335from license_expression import ExpressionError
3436from license_expression import Keyword
@@ -424,8 +426,15 @@ def test_parse_invalid_expression_raise_exception6(self):
424426 try :
425427 licensing .parse (expr )
426428 self .fail ("Exception not raised when validating '%s'" % expr )
427- except ExpressionError as ee :
428- assert 'OR requires two or more licenses as in: MIT OR BSD' == str (ee )
429+ self .fail ('Exception not raised' )
430+ except ParseError as pe :
431+ expected = {
432+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
433+ 'position' : 0 ,
434+ 'token_string' : 'OR' ,
435+ 'token_type' : TOKEN_OR
436+ }
437+ assert expected == _parse_error_as_dict (pe )
429438
430439 def test_parse_not_invalid_expression_raise_no_exception2 (self ):
431440 licensing = Licensing ()
@@ -466,18 +475,28 @@ def test_parse_errors_catch_invalid_expression_with_bare_and(self):
466475 try :
467476 licensing .parse ('and' )
468477 self .fail ('Exception not raised' )
469- except ExpressionError as pe :
470- expected = 'AND requires two or more licenses as in: MIT AND BSD'
471- assert expected == str (pe )
478+ except ParseError as pe :
479+ expected = {
480+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
481+ 'position' : 0 ,
482+ 'token_string' : 'and' ,
483+ 'token_type' : TOKEN_AND
484+ }
485+ assert expected == _parse_error_as_dict (pe )
472486
473487 def test_parse_errors_catch_invalid_expression_with_or_and_no_other (self ):
474488 licensing = Licensing ()
475489 try :
476490 licensing .parse ('or that' )
477491 self .fail ('Exception not raised' )
478- except ExpressionError as pe :
479- expected = 'OR requires two or more licenses as in: MIT OR BSD'
480- assert expected == str (pe )
492+ except ParseError as pe :
493+ expected = {
494+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
495+ 'position' : 0 ,
496+ 'token_string' : 'or' ,
497+ 'token_type' : TOKEN_OR
498+ }
499+ assert expected == _parse_error_as_dict (pe )
481500
482501 def test_parse_errors_catch_invalid_expression_with_empty_parens (self ):
483502 licensing = Licensing ()
@@ -828,6 +847,78 @@ def test_Licensing_can_parse_valid_expressions_with_symbols_that_contain_spaces(
828847 expected = 'GPL-2.0 OR (mit AND LGPL 2.1) OR bsd OR GPL-2.0 OR (mit AND LGPL 2.1)'
829848 assert expected == str (parsed )
830849
850+ def test_parse_invalid_expression_with_trailing_or (self ):
851+ licensing = Licensing ()
852+ expr = 'mit or'
853+ try :
854+ licensing .parse (expr )
855+ self .fail ("Exception not raised when validating '%s'" % expr )
856+ except ExpressionError as ee :
857+ assert 'OR requires two or more licenses as in: MIT OR BSD' == str (ee )
858+
859+ def test_parse_invalid_expression_with_trailing_or_and_valid_start_does_not_raise_exception (self ):
860+ licensing = Licensing ()
861+ expression = ' mit or mit or '
862+ parsed = licensing .parse (expression )
863+ # ExpressionError: OR requires two or more licenses as in: MIT OR BSD
864+ expected = 'mit OR mit'
865+ assert expected == str (parsed )
866+
867+ def test_parse_invalid_expression_with_repeated_trailing_or_raise_exception (self ):
868+ licensing = Licensing ()
869+ expression = 'mit or mit or or'
870+ try :
871+ licensing .parse (expression , simple = False )
872+ self .fail ('Exception not raised' )
873+ except ParseError as pe :
874+ expected = {
875+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
876+ 'position' : 14 ,
877+ 'token_string' : 'or' ,
878+ 'token_type' : TOKEN_OR
879+ }
880+ assert expected == _parse_error_as_dict (pe )
881+
882+ @expectedFailure
883+ def test_parse_invalid_expression_with_single_trailing_or_raise_exception (self ):
884+ licensing = Licensing ()
885+ expression = 'mit or mit or'
886+ try :
887+ licensing .parse (expression , simple = False )
888+ self .fail ('Exception not raised' )
889+ except ParseError as pe :
890+ expected = {
891+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
892+ 'position' : 14 ,
893+ 'token_string' : 'or' ,
894+ 'token_type' : TOKEN_OR
895+ }
896+ assert expected == _parse_error_as_dict (pe )
897+
898+ def test_parse_invalid_expression_with_single_trailing_and_raise_exception (self ):
899+ licensing = Licensing ()
900+ expression = 'mit or mit and'
901+ try :
902+ licensing .parse (expression , simple = False )
903+ self .fail ('Exception not raised' )
904+ except ExpressionError as ee :
905+ assert 'AND requires two or more licenses as in: MIT AND BSD' == str (ee )
906+
907+ def test_parse_invalid_expression_with_single_leading_or_raise_exception (self ):
908+ licensing = Licensing ()
909+ expression = 'or mit or mit'
910+ try :
911+ licensing .parse (expression , simple = False )
912+ self .fail ('Exception not raised' )
913+ except ParseError as pe :
914+ expected = {
915+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
916+ 'position' : 0 ,
917+ 'token_string' : 'or' ,
918+ 'token_type' : TOKEN_OR
919+ }
920+ assert expected == _parse_error_as_dict (pe )
921+
831922
832923class LicensingParseWithSymbolsSimpleTest (TestCase ):
833924
@@ -1950,17 +2041,29 @@ def test_and_and_or_is_invalid(self):
19502041 try :
19512042 licensing .parse (expression )
19522043 self .fail ('Exception not raised' )
1953- except ExpressionError as e :
1954- assert 'AND requires two or more licenses as in: MIT AND BSD' == str (e )
2044+ except ParseError as pe :
2045+ expected = {
2046+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
2047+ 'position' : 27 ,
2048+ 'token_string' : 'and' ,
2049+ 'token_type' : TOKEN_AND }
2050+ assert expected == _parse_error_as_dict (pe )
19552051
1956- def test_or_or_is_not_invalid (self ):
2052+ def test_or_or_is_invalid (self ):
19572053 expression = 'gpl-2.0 with classpath or or or or gpl-2.0-plus'
19582054 licensing = Licensing ()
1959- result = str (licensing .parse (expression ))
1960- assert 'gpl-2.0 WITH classpath OR gpl-2.0-plus' == result
2055+ try :
2056+ licensing .parse (expression )
2057+ except ParseError as pe :
2058+ expected = {
2059+ 'error_code' : PARSE_INVALID_OPERATOR_SEQUENCE ,
2060+ 'position' : 26 ,
2061+ 'token_string' : 'or' ,
2062+ 'token_type' : TOKEN_OR }
2063+ assert expected == _parse_error_as_dict (pe )
19612064
19622065 def test_tokenize_or_or (self ):
1963- expression = 'gpl-2.0 with classpath or or gpl-2.0-plus'
2066+ expression = 'gpl-2.0 with classpath or or or gpl-2.0-plus'
19642067 licensing = Licensing ()
19652068 results = list (licensing .tokenize (expression ))
19662069 expected = [
@@ -1969,7 +2072,8 @@ def test_tokenize_or_or(self):
19692072 exception_symbol = LicenseSymbol (u'classpath' )), 'gpl-2.0 with classpath' , 0 ),
19702073 (2 , 'or' , 23 ),
19712074 (2 , 'or' , 26 ),
1972- (LicenseSymbol (u'gpl-2.0-plus' ), 'gpl-2.0-plus' , 29 )
2075+ (2 , 'or' , 29 ),
2076+ (LicenseSymbol (u'gpl-2.0-plus' ), 'gpl-2.0-plus' , 32 )
19732077 ]
19742078
19752079 assert expected == results
0 commit comments