def test_syntax_parse_error_quality(): # Check that the syntax error is giving us good context. msg = re.escape(r"no viable alternative at input 'm^m' (inline, line 1)") with pytest.raises(SyntaxError, match=msg) as err: normalize('m^m 2s') # The problem is with the m after "^", so make sure the exception is # pointing at it (including the leading speechmark). assert err.value.offset == 4
def test_invalid_syntax_units(_, unit_str): # Check that units that aren't allowed with UDUNITS-2 are also not # allowed with our grammar. with pytest.raises(ValueError): cf_units.Unit(unit_str).symbol with pytest.raises(SyntaxError): normalize(unit_str)
def test_known_issues(_, unit_str, expected): # Unfortunately the grammar is not perfect. # These are the cases that don't work yet but which do work with udunits. # Make sure udunits can read it. cf_units.Unit(unit_str).symbol if isinstance(expected, type) and issubclass(expected, Exception): with pytest.raises(SyntaxError): unit_expr = normalize(unit_str) else: unit_expr = normalize(unit_str) assert unit_expr != expected
def test_unknown_symbol_error(): msg = re.escape(r"mismatched input '×' expecting <EOF>") with pytest.raises(SyntaxError, match=msg) as err: # The × character is explicitly excluded in the UDUNITS2 # implementation. It would make some sense to support it in the # future though. normalize('Thing×Another') # The 7th character (including the speechmark) is the problem, check that # the exception points at the right location. # correct location... # File "inline", line 1 # 'Thing×Another' # ^ assert err.value.offset == 7
def test_invalid_units(_, unit_str): # Confirm that invalid udunits-2 units are also invalid in our grammar. try: cf_units.Unit(unit_str) cf_valid = True except ValueError: cf_valid = False # Double check that udunits2 can't parse this. assert cf_valid is False, \ 'Unit {!r} is unexpectedly valid in UDUNITS2'.format(unit_str) try: normalize(unit_str) can_parse = True except SyntaxError: can_parse = False # Now confirm that we couldn't parse this either. msg = 'Parser unexpectedly able to deal with {}'.format(unit_str) assert can_parse is False, msg
def test_invalid_in_udunits_but_still_parses(_, unit_str, expected): # Some units read fine in our grammar, but not in UDUNITS. try: cf_units.Unit(unit_str) cf_valid = True except ValueError: cf_valid = False # Double check that udunits2 can't parse this. assert cf_valid is False unit_expr = normalize(unit_str) assert unit_expr == expected
def test_normed_units_equivalent(_, unit_str): # nb: The "_" argument makes it easier to see which test was being run. # Get the udunits symbolic form for the raw unit. raw_symbol = cf_units.Unit(unit_str).symbol # Now get the parsed form of the unit, and then convert that to # symbolic form. The two should match. unit_expr = normalize(unit_str) parsed_expr_symbol = cf_units.Unit(unit_expr).symbol # Whilst the symbolic form from udunits is ugly, it *is* acurate, # so check that the two represent the same unit. assert raw_symbol == parsed_expr_symbol