view src/testdir/test_expr.vim @ 34074:1629cc65d78d v9.1.0006

patch 9.1.0006: is*() and to*() function may be unsafe Commit: https://github.com/vim/vim/commit/184f71cc6868a240dc872ed2852542bbc1d43e28 Author: Keith Thompson <Keith.S.Thompson@gmail.com> Date: Thu Jan 4 21:19:04 2024 +0100 patch 9.1.0006: is*() and to*() function may be unsafe Problem: is*() and to*() function may be unsafe Solution: Add SAFE_* macros and start using those instead (Keith Thompson) Use SAFE_() macros for is*() and to*() functions The standard is*() and to*() functions declared in <ctype.h> have undefined behavior for negative arguments other than EOF. If plain char is signed, passing an unchecked value from argv for from user input to one of these functions has undefined behavior. Solution: Add SAFE_*() macros that cast the argument to unsigned char. Most implementations behave sanely for negative arguments, and most character values in practice are non-negative, but it's still best to avoid undefined behavior. The change from #13347 has been omitted, as this has already been separately fixed in commit ac709e2fc0db6d31abb7da96f743c40956b60c3a (v9.0.2054) fixes: #13332 closes: #13347 Signed-off-by: Keith Thompson <Keith.S.Thompson@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 04 Jan 2024 21:30:04 +0100
parents 4635e43f2c6f
children 1e6f45f5ca23
line wrap: on
line source

" Tests for expressions.

source check.vim
import './vim9.vim' as v9

func Test_equal()
  let base = {}
  func base.method()
    return 1
  endfunc
  func base.other() dict
    return 1
  endfunc
  let instance = copy(base)
  call assert_true(base.method == instance.method)
  call assert_true([base.method] == [instance.method])
  call assert_true(base.other == instance.other)
  call assert_true([base.other] == [instance.other])

  call assert_false(base.method == base.other)
  call assert_false([base.method] == [base.other])
  call assert_false(base.method == instance.other)
  call assert_false([base.method] == [instance.other])

  call assert_fails('echo base.method > instance.method')
  call assert_equal(0, test_null_function() == function('min'))
  call assert_equal(1, test_null_function() == test_null_function())
  call assert_fails('eval 10 == test_unknown()', ['E340:', 'E685:'])
endfunc

func Test_version()
  call assert_true(has('patch-7.4.001'))
  call assert_true(has('patch-7.4.01'))
  call assert_true(has('patch-7.4.1'))
  call assert_true(has('patch-6.9.999'))
  call assert_true(has('patch-7.1.999'))
  call assert_true(has('patch-7.4.123'))
  call assert_true(has('patch-7.4.123 ')) " Trailing space can be allowed.
  call assert_true(has('patch-9.1.0'))
  call assert_true(has('patch-9.1.0000'))

  call assert_false(has('patch-7'))
  call assert_false(has('patch-7.4'))
  call assert_false(has('patch-7.4.'))
  call assert_false(has('patch-9.2.0'))
  call assert_false(has('patch-9.9.1'))

  call assert_false(has('patch-abc'))
  call assert_false(has('patchabc'))

  call assert_false(has('patch-8x001'))
  call assert_false(has('patch-9X0X0'))
  call assert_false(has('patch-9-0-0'))
  call assert_false(has('patch-09.0.0'))
  call assert_false(has('patch-9.00.0'))
endfunc

func Test_op_ternary()
  let lines =<< trim END
      call assert_equal('yes', 1 ? 'yes' : 'no')
      call assert_equal('no', 0 ? 'yes' : 'no')

      call assert_fails('echo [1] ? "yes" : "no"', 'E745:')
      call assert_fails('echo {} ? "yes" : "no"', 'E728:')
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call assert_equal('no', 'x' ? 'yes' : 'no')
  call v9.CheckDefAndScriptFailure(["'x' ? 'yes' : 'no'"], 'E1135:')
  call assert_equal('yes', '1x' ? 'yes' : 'no')
  call v9.CheckDefAndScriptFailure(["'1x' ? 'yes' : 'no'"], 'E1135:')
endfunc

func Test_op_falsy()
  let lines =<< trim END
      call assert_equal(v:true, v:true ?? 456)
      call assert_equal(123, 123 ?? 456)
      call assert_equal('yes', 'yes' ?? 456)
      call assert_equal(0z00, 0z00 ?? 456)
      call assert_equal([1], [1] ?? 456)
      call assert_equal({'one': 1}, {'one': 1} ?? 456)
      call assert_equal(0.1, 0.1 ?? 456)

      call assert_equal(456, v:false ?? 456)
      call assert_equal(456, 0 ?? 456)
      call assert_equal(456, '' ?? 456)
      call assert_equal(456, 0z ?? 456)
      call assert_equal(456, [] ?? 456)
      call assert_equal(456, {} ?? 456)
      call assert_equal(456, 0.0 ?? 456)

      call assert_equal(456, v:null ?? 456)
      call assert_equal(456, v:none ?? 456)
      call assert_equal(456, test_null_string() ?? 456)
      call assert_equal(456, test_null_blob() ?? 456)
      call assert_equal(456, test_null_list() ?? 456)
      call assert_equal(456, test_null_dict() ?? 456)
      call assert_equal(456, test_null_function() ?? 456)
      call assert_equal(456, test_null_partial() ?? 456)
      if has('job')
        call assert_equal(456, test_null_job() ?? 456)
      endif
      if has('channel')
        call assert_equal(456, test_null_channel() ?? 456)
      endif
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_dict()
  let lines =<< trim END
      VAR d = {'': 'empty', 'a': 'a', 0: 'zero'}
      call assert_equal('empty', d[''])
      call assert_equal('a', d['a'])
      call assert_equal('zero', d[0])
      call assert_true(has_key(d, ''))
      call assert_true(has_key(d, 'a'))

      LET d[''] = 'none'
      LET d['a'] = 'aaa'
      call assert_equal('none', d[''])
      call assert_equal('aaa', d['a'])

      LET d[ 'b' ] = 'bbb'
      call assert_equal('bbb', d[ 'b' ])
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(["VAR i = has_key([], 'a')"], ['E1206:', 'E1013:', 'E1206:'])
endfunc

func Test_strgetchar()
  let lines =<< trim END
      call assert_equal(char2nr('a'), strgetchar('axb', 0))
      call assert_equal(char2nr('x'), 'axb'->strgetchar(1))
      call assert_equal(char2nr('b'), strgetchar('axb', 2))

      call assert_equal(-1, strgetchar('axb', -1))
      call assert_equal(-1, strgetchar('axb', 3))
      call assert_equal(-1, strgetchar('', 0))
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(["VAR c = strgetchar([], 1)"], ['E730:', 'E1013:', 'E1174:'])
  call v9.CheckLegacyAndVim9Failure(["VAR c = strgetchar('axb', [])"], ['E745:', 'E1013:', 'E1210:'])
endfunc

func Test_strcharpart()
  let lines =<< trim END
      call assert_equal('a', strcharpart('axb', 0, 1))
      call assert_equal('x', 'axb'->strcharpart(1, 1))
      call assert_equal('b', strcharpart('axb', 2, 1))
      call assert_equal('xb', strcharpart('axb', 1))

      call assert_equal('', strcharpart('axb', 1, 0))
      call assert_equal('', strcharpart('axb', 1, -1))
      call assert_equal('', strcharpart('axb', -1, 1))
      call assert_equal('', strcharpart('axb', -2, 2))

      call assert_equal('a', strcharpart('axb', -1, 2))

      call assert_equal('edit', "editor"[-10 : 3])
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call assert_fails('call strcharpart("", 0, 0, {})', ['E728:', 'E728:'])
  call assert_fails('call strcharpart("", 0, 0, -1)', ['E1023:', 'E1023:'])
endfunc

func Test_getreg_empty_list()
  let lines =<< trim END
      call assert_equal('', getreg('x'))
      call assert_equal([], getreg('x', 1, 1))
      VAR x = getreg('x', 1, 1)
      VAR y = x
      call add(x, 'foo')
      call assert_equal(['foo'], y)
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(['call getreg([])'], ['E730:', 'E1013:', 'E1174:'])
endfunc

func Test_loop_over_null_list()
  let lines =<< trim END
      VAR nulllist = test_null_list()
      for i in nulllist
        call assert_report('should not get here')
      endfor
  END
  call v9.CheckLegacyAndVim9Success(lines)

  let lines =<< trim END
      var nulllist = null_list
      for i in nulllist
        call assert_report('should not get here')
      endfor
  END
  call v9.CheckDefAndScriptSuccess(lines)

  let lines =<< trim END
      let nulllist = null_list
      for i in nulllist
        call assert_report('should not get here')
      endfor
  END
  call v9.CheckScriptFailure(lines, 'E121: Undefined variable: null_list')
endfunc

func Test_compare_with_null()
  let s:value = v:null
  call assert_true(s:value == v:null)
  let s:value = v:true
  call assert_false(s:value == v:null)
  let s:value = v:none
  call assert_false(s:value == v:null)
  let s:value = 0
  call assert_true(s:value == v:null)
  let s:value = 0.0
  call assert_true(s:value == v:null)
  let s:value = ''
  call assert_false(s:value == v:null)
  let s:value = 0z
  call assert_false(s:value == v:null)
  let s:value = []
  call assert_false(s:value == v:null)
  let s:value = {}
  call assert_false(s:value == v:null)
  let s:value = function('len')
  call assert_false(s:value == v:null)
  if has('job')
    let s:value = test_null_job()
    call assert_true(s:value == v:null)
    let s:value = test_null_channel()
    call assert_true(s:value == v:null)
  endif
  unlet s:value
endfunc

func Test_setreg_null_list()
  let lines =<< trim END
      call setreg('x', test_null_list())
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_special_char()
  " The failure is only visible using valgrind.
  call v9.CheckLegacyAndVim9Failure(['echo "\<C-">'], ['E15:', 'E1004:', 'E1004:'])
endfunc

func Test_method_with_prefix()
  let lines =<< trim END
      call assert_equal(TRUE, !range(5)->empty())
      call assert_equal(FALSE, !-3)
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call assert_equal([0, 1, 2], --3->range())
  call v9.CheckDefAndScriptFailure(['eval --3->range()'], 'E15')

  call assert_equal(1, !+-+0)
  call v9.CheckDefAndScriptFailure(['eval !+-+0'], 'E15')
endfunc

func Test_option_value()
  let lines =<< trim END
      #" boolean
      set bri
      call assert_equal(TRUE, &bri)
      set nobri
      call assert_equal(FALSE, &bri)

      #" number
      set ts=1
      call assert_equal(1, &ts)
      set ts=8
      call assert_equal(8, &ts)

      #" string
      exe "set cedit=\<Esc>"
      call assert_equal("\<Esc>", &cedit)
      set cpo=
      call assert_equal("", &cpo)
      set cpo=abcdefgi
      call assert_equal("abcdefgi", &cpo)
      set cpo&vim
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_printf_misc()
  let lines =<< trim END
      call assert_equal('123', printf('123'))

      call assert_equal('', printf('%'))
      call assert_equal('', printf('%.0d', 0))
      call assert_equal('123', printf('%d', 123))
      call assert_equal('123', printf('%i', 123))
      call assert_equal('123', printf('%D', 123))
      call assert_equal('123', printf('%U', 123))
      call assert_equal('173', printf('%o', 123))
      call assert_equal('173', printf('%O', 123))
      call assert_equal('7b', printf('%x', 123))
      call assert_equal('7B', printf('%X', 123))

      call assert_equal('123', printf('%hd', 123))
      call assert_equal('-123', printf('%hd', -123))
      call assert_equal('-1', printf('%hd', 0xFFFF))
      call assert_equal('-1', printf('%hd', 0x1FFFFF))

      call assert_equal('123', printf('%hu', 123))
      call assert_equal('65413', printf('%hu', -123))
      call assert_equal('65535', printf('%hu', 0xFFFF))
      call assert_equal('65535', printf('%hu', 0x1FFFFF))

      call assert_equal('123', printf('%ld', 123))
      call assert_equal('-123', printf('%ld', -123))
      call assert_equal('65535', printf('%ld', 0xFFFF))
      call assert_equal('131071', printf('%ld', 0x1FFFF))

      call assert_equal('{', printf('%c', 123))
      call assert_equal('abc', printf('%s', 'abc'))
      call assert_equal('abc', printf('%S', 'abc'))

      call assert_equal('+123', printf('%+d', 123))
      call assert_equal('-123', printf('%+d', -123))
      call assert_equal('+123', printf('%+ d', 123))
      call assert_equal(' 123', printf('% d', 123))
      call assert_equal(' 123', printf('%  d', 123))
      call assert_equal('-123', printf('% d', -123))

      call assert_equal('123', printf('%2d', 123))
      call assert_equal('   123', printf('%6d', 123))
      call assert_equal('000123', printf('%06d', 123))
      call assert_equal('+00123', printf('%+06d', 123))
      call assert_equal(' 00123', printf('% 06d', 123))
      call assert_equal('  +123', printf('%+6d', 123))
      call assert_equal('   123', printf('% 6d', 123))
      call assert_equal('  -123', printf('% 6d', -123))

      #" Test left adjusted.
      call assert_equal('123   ', printf('%-6d', 123))
      call assert_equal('+123  ', printf('%-+6d', 123))
      call assert_equal(' 123  ', printf('%- 6d', 123))
      call assert_equal('-123  ', printf('%- 6d', -123))

      call assert_equal('  00123', printf('%7.5d', 123))
      call assert_equal(' -00123', printf('%7.5d', -123))
      call assert_equal(' +00123', printf('%+7.5d', 123))

      #" Precision field should not be used when combined with %0
      call assert_equal('  00123', printf('%07.5d', 123))
      call assert_equal(' -00123', printf('%07.5d', -123))

      call assert_equal('  123', printf('%*d', 5, 123))
      call assert_equal('123  ', printf('%*d', -5, 123))
      call assert_equal('00123', printf('%.*d', 5, 123))
      call assert_equal('  123', printf('% *d', 5, 123))
      call assert_equal(' +123', printf('%+ *d', 5, 123))

      call assert_equal('foobar', printf('%.*s',  9, 'foobar'))
      call assert_equal('foo',    printf('%.*s',  3, 'foobar'))
      call assert_equal('',       printf('%.*s',  0, 'foobar'))
      call assert_equal('foobar', printf('%.*s', -1, 'foobar'))

      #" Simple quote (thousand grouping char) is ignored.
      call assert_equal('+00123456', printf("%+'09d", 123456))

      #" Unrecognized format specifier kept as-is.
      call assert_equal('_123', printf("%_%d", 123))

      #" Test alternate forms.
      call assert_equal('0x7b', printf('%#x', 123))
      call assert_equal('0X7B', printf('%#X', 123))
      call assert_equal('0173', printf('%#o', 123))
      call assert_equal('0173', printf('%#O', 123))
      call assert_equal('abc', printf('%#s', 'abc'))
      call assert_equal('abc', printf('%#S', 'abc'))
      call assert_equal('  0173', printf('%#6o', 123))
      call assert_equal(' 00173', printf('%#6.5o', 123))
      call assert_equal('  0173', printf('%#6.2o', 123))
      call assert_equal('  0173', printf('%#6.2o', 123))
      call assert_equal('0173', printf('%#2.2o', 123))

      call assert_equal(' 00123', printf('%6.5d', 123))
      call assert_equal(' 0007b', printf('%6.5x', 123))

      call assert_equal('123', printf('%.2d', 123))
      call assert_equal('0123', printf('%.4d', 123))
      call assert_equal('0000000123', printf('%.10d', 123))
      call assert_equal('123', printf('%.0d', 123))

      call assert_equal('abc', printf('%2s', 'abc'))
      call assert_equal('abc', printf('%2S', 'abc'))
      call assert_equal('abc', printf('%.4s', 'abc'))
      call assert_equal('abc', printf('%.4S', 'abc'))
      call assert_equal('ab', printf('%.2s', 'abc'))
      call assert_equal('ab', printf('%.2S', 'abc'))
      call assert_equal('', printf('%.0s', 'abc'))
      call assert_equal('', printf('%.s', 'abc'))
      call assert_equal(' abc', printf('%4s', 'abc'))
      call assert_equal(' abc', printf('%4S', 'abc'))
      call assert_equal('0abc', printf('%04s', 'abc'))
      call assert_equal('0abc', printf('%04S', 'abc'))
      call assert_equal('abc ', printf('%-4s', 'abc'))
      call assert_equal('abc ', printf('%-4S', 'abc'))

      call assert_equal('🐍', printf('%.2S', '🐍🐍'))
      call assert_equal('', printf('%.1S', '🐍🐍'))

      call assert_equal('[    あいう]', printf('[%10.6S]', 'γ‚γ„γ†γˆγŠ'))
      call assert_equal('[  γ‚γ„γ†γˆ]', printf('[%10.8S]', 'γ‚γ„γ†γˆγŠ'))
      call assert_equal('[γ‚γ„γ†γˆγŠ]', printf('[%10.10S]', 'γ‚γ„γ†γˆγŠ'))
      call assert_equal('[γ‚γ„γ†γˆγŠ]', printf('[%10.12S]', 'γ‚γ„γ†γˆγŠ'))

      call assert_equal('あいう', printf('%S', 'あいう'))
      call assert_equal('あいう', printf('%#S', 'あいう'))

      call assert_equal('あb', printf('%2S', 'あb'))
      call assert_equal('あb', printf('%.4S', 'あb'))
      call assert_equal('あ', printf('%.2S', 'あb'))
      call assert_equal(' あb', printf('%4S', 'あb'))
      call assert_equal('0あb', printf('%04S', 'あb'))
      call assert_equal('あb ', printf('%-4S', 'あb'))
      call assert_equal('あ  ', printf('%-4.2S', 'あb'))

      call assert_equal('aい', printf('%2S', 'aい'))
      call assert_equal('aい', printf('%.4S', 'aい'))
      call assert_equal('a', printf('%.2S', 'aい'))
      call assert_equal(' aい', printf('%4S', 'aい'))
      call assert_equal('0aい', printf('%04S', 'aい'))
      call assert_equal('aい ', printf('%-4S', 'aい'))
      call assert_equal('a   ', printf('%-4.2S', 'aい'))

      call assert_equal('[あいう]', printf('[%05S]', 'あいう'))
      call assert_equal('[あいう]', printf('[%06S]', 'あいう'))
      call assert_equal('[0あいう]', printf('[%07S]', 'あいう'))

      call assert_equal('[あiう]', printf('[%05S]', 'あiう'))
      call assert_equal('[0あiう]', printf('[%06S]', 'あiう'))
      call assert_equal('[00あiう]', printf('[%07S]', 'あiう'))

      call assert_equal('[0あい]', printf('[%05.4S]', 'あいう'))
      call assert_equal('[00あい]', printf('[%06.4S]', 'あいう'))
      call assert_equal('[000あい]', printf('[%07.4S]', 'あいう'))

      call assert_equal('[00あi]', printf('[%05.4S]', 'あiう'))
      call assert_equal('[000あi]', printf('[%06.4S]', 'あiう'))
      call assert_equal('[0000あi]', printf('[%07.4S]', 'あiう'))

      call assert_equal('[0あい]', printf('[%05.5S]', 'あいう'))
      call assert_equal('[00あい]', printf('[%06.5S]', 'あいう'))
      call assert_equal('[000あい]', printf('[%07.5S]', 'あいう'))

      call assert_equal('[あiう]', printf('[%05.5S]', 'あiう'))
      call assert_equal('[0あiう]', printf('[%06.5S]', 'あiう'))
      call assert_equal('[00あiう]', printf('[%07.5S]', 'あiう'))

      call assert_equal('[0000000000]', printf('[%010.0S]', 'あいう'))
      call assert_equal('[0000000000]', printf('[%010.1S]', 'あいう'))
      call assert_equal('[00000000あ]', printf('[%010.2S]', 'あいう'))
      call assert_equal('[00000000あ]', printf('[%010.3S]', 'あいう'))
      call assert_equal('[000000あい]', printf('[%010.4S]', 'あいう'))
      call assert_equal('[000000あい]', printf('[%010.5S]', 'あいう'))
      call assert_equal('[0000あいう]', printf('[%010.6S]', 'あいう'))
      call assert_equal('[0000あいう]', printf('[%010.7S]', 'あいう'))

      call assert_equal('[0000000000]', printf('[%010.1S]', 'あiう'))
      call assert_equal('[00000000あ]', printf('[%010.2S]', 'あiう'))
      call assert_equal('[0000000あi]', printf('[%010.3S]', 'あiう'))
      call assert_equal('[0000000あi]', printf('[%010.4S]', 'あiう'))
      call assert_equal('[00000あiう]', printf('[%010.5S]', 'あiう'))
      call assert_equal('[00000あiう]', printf('[%010.6S]', 'あiう'))
      call assert_equal('[00000あiう]', printf('[%010.7S]', 'あiう'))

      call assert_equal('1%', printf('%d%%', 1))
      call assert_notequal('', printf('%p', "abc"))
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(["call printf('123', 3)"], "E767:")

  " this was using uninitialized memory
  call v9.CheckLegacyAndVim9Failure(["eval ''->printf()"], "E119:")
endfunc

func Test_printf_float()
  let lines =<< trim END
      call assert_equal('1.000000', printf('%f', 1))
      call assert_equal('1.230000', printf('%f', 1.23))
      call assert_equal('1.230000', printf('%F', 1.23))
      call assert_equal('9999999.9', printf('%g', 9999999.9))
      call assert_equal('9999999.9', printf('%G', 9999999.9))
      call assert_equal('1.00000001e7', printf('%.8g', 10000000.1))
      call assert_equal('1.00000001E7', printf('%.8G', 10000000.1))
      call assert_equal('1.230000e+00', printf('%e', 1.23))
      call assert_equal('1.230000E+00', printf('%E', 1.23))
      call assert_equal('1.200000e-02', printf('%e', 0.012))
      call assert_equal('-1.200000e-02', printf('%e', -0.012))
      call assert_equal('0.33', printf('%.2f', 1.0 / 3.0))
      call assert_equal('  0.33', printf('%6.2f', 1.0 / 3.0))
      call assert_equal(' -0.33', printf('%6.2f', -1.0 / 3.0))
      call assert_equal('000.33', printf('%06.2f', 1.0 / 3.0))
      call assert_equal('-00.33', printf('%06.2f', -1.0 / 3.0))
      call assert_equal('-00.33', printf('%+06.2f', -1.0 / 3.0))
      call assert_equal('+00.33', printf('%+06.2f', 1.0 / 3.0))
      call assert_equal(' 00.33', printf('% 06.2f', 1.0 / 3.0))
      call assert_equal('000.33', printf('%06.2g', 1.0 / 3.0))
      call assert_equal('-00.33', printf('%06.2g', -1.0 / 3.0))
      call assert_equal('0.33', printf('%3.2f', 1.0 / 3.0))
      call assert_equal('003.33e-01', printf('%010.2e', 1.0 / 3.0))
      call assert_equal(' 03.33e-01', printf('% 010.2e', 1.0 / 3.0))
      call assert_equal('+03.33e-01', printf('%+010.2e', 1.0 / 3.0))
      call assert_equal('-03.33e-01', printf('%010.2e', -1.0 / 3.0))

      #" When precision is 0, the dot should be omitted.
      call assert_equal('  2', printf('%3.f', 7.0 / 3.0))
      call assert_equal('  2', printf('%3.g', 7.0 / 3.0))
      call assert_equal('  2e+00', printf('%7.e', 7.0 / 3.0))

      #" Float zero can be signed.
      call assert_equal('+0.000000', printf('%+f', 0.0))
      call assert_equal('0.000000', printf('%f', 1.0 / (1.0 / 0.0)))
      call assert_equal('-0.000000', printf('%f', 1.0 / (-1.0 / 0.0)))
      call assert_equal('0.0', printf('%s', 1.0 / (1.0 / 0.0)))
      call assert_equal('-0.0', printf('%s', 1.0 / (-1.0 / 0.0)))
      call assert_equal('0.0', printf('%S', 1.0 / (1.0 / 0.0)))
      call assert_equal('-0.0', printf('%S', 1.0 / (-1.0 / 0.0)))

      #" Float infinity can be signed.
      call assert_equal('inf', printf('%f', 1.0 / 0.0))
      call assert_equal('-inf', printf('%f', -1.0 / 0.0))
      call assert_equal('inf', printf('%g', 1.0 / 0.0))
      call assert_equal('-inf', printf('%g', -1.0 / 0.0))
      call assert_equal('inf', printf('%e', 1.0 / 0.0))
      call assert_equal('-inf', printf('%e', -1.0 / 0.0))
      call assert_equal('INF', printf('%F', 1.0 / 0.0))
      call assert_equal('-INF', printf('%F', -1.0 / 0.0))
      call assert_equal('INF', printf('%E', 1.0 / 0.0))
      call assert_equal('-INF', printf('%E', -1.0 / 0.0))
      call assert_equal('INF', printf('%E', 1.0 / 0.0))
      call assert_equal('-INF', printf('%G', -1.0 / 0.0))
      call assert_equal('+inf', printf('%+f', 1.0 / 0.0))
      call assert_equal('-inf', printf('%+f', -1.0 / 0.0))
      call assert_equal(' inf', printf('% f',  1.0 / 0.0))
      call assert_equal('   inf', printf('%6f', 1.0 / 0.0))
      call assert_equal('  -inf', printf('%6f', -1.0 / 0.0))
      call assert_equal('   inf', printf('%6g', 1.0 / 0.0))
      call assert_equal('  -inf', printf('%6g', -1.0 / 0.0))
      call assert_equal('  +inf', printf('%+6f', 1.0 / 0.0))
      call assert_equal('   inf', printf('% 6f', 1.0 / 0.0))
      call assert_equal('  +inf', printf('%+06f', 1.0 / 0.0))
      call assert_equal('inf   ', printf('%-6f', 1.0 / 0.0))
      call assert_equal('-inf  ', printf('%-6f', -1.0 / 0.0))
      call assert_equal('+inf  ', printf('%-+6f', 1.0 / 0.0))
      call assert_equal(' inf  ', printf('%- 6f', 1.0 / 0.0))
      call assert_equal('-INF  ', printf('%-6F', -1.0 / 0.0))
      call assert_equal('+INF  ', printf('%-+6F', 1.0 / 0.0))
      call assert_equal(' INF  ', printf('%- 6F', 1.0 / 0.0))
      call assert_equal('INF   ', printf('%-6G', 1.0 / 0.0))
      call assert_equal('-INF  ', printf('%-6G', -1.0 / 0.0))
      call assert_equal('INF   ', printf('%-6E', 1.0 / 0.0))
      call assert_equal('-INF  ', printf('%-6E', -1.0 / 0.0))
      call assert_equal('inf', printf('%s', 1.0 / 0.0))
      call assert_equal('-inf', printf('%s', -1.0 / 0.0))

      #" Test special case where max precision is truncated at 340.
      call assert_equal('1.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.330f', 1.0))
      call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.340f', 1.0))
      call assert_equal('1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', printf('%.350f', 1.0))

      #" Float nan (not a number) has no sign.
      call assert_equal('nan', printf('%f', sqrt(-1.0)))
      call assert_equal('nan', printf('%f', 0.0 / 0.0))
      call assert_equal('nan', printf('%f', -0.0 / 0.0))
      call assert_equal('nan', printf('%g', 0.0 / 0.0))
      call assert_equal('nan', printf('%e', 0.0 / 0.0))
      call assert_equal('NAN', printf('%F', 0.0 / 0.0))
      call assert_equal('NAN', printf('%G', 0.0 / 0.0))
      call assert_equal('NAN', printf('%E', 0.0 / 0.0))
      call assert_equal('NAN', printf('%F', -0.0 / 0.0))
      call assert_equal('NAN', printf('%G', -0.0 / 0.0))
      call assert_equal('NAN', printf('%E', -0.0 / 0.0))
      call assert_equal('   nan', printf('%6f', 0.0 / 0.0))
      call assert_equal('   nan', printf('%06f', 0.0 / 0.0))
      call assert_equal('nan   ', printf('%-6f', 0.0 / 0.0))
      call assert_equal('nan   ', printf('%- 6f', 0.0 / 0.0))
      call assert_equal('nan', printf('%s', 0.0 / 0.0))
      call assert_equal('nan', printf('%s', -0.0 / 0.0))
      call assert_equal('nan', printf('%S', 0.0 / 0.0))
      call assert_equal('nan', printf('%S', -0.0 / 0.0))
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(['echo printf("%f", "a")'], 'E807:')
endfunc

func Test_printf_errors()
  call v9.CheckLegacyAndVim9Failure(['echo printf("%d", {})'], 'E728:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%d", [])'], 'E745:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%d", 1, 2)'], 'E767:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%*d", 1)'], 'E766:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%s")'], 'E766:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%d", 1.2)'], 'E805:')
  call v9.CheckLegacyAndVim9Failure(['echo printf("%f")'], 'E766:')
endfunc

func Test_printf_64bit()
  let lines =<< trim END
      call assert_equal("123456789012345", printf('%d', 123456789012345))
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_printf_spec_s()
  let lines =<< trim END
      #" number
      call assert_equal("1234567890", printf('%s', 1234567890))

      #" string
      call assert_equal("abcdefgi", printf('%s', "abcdefgi"))

      #" float
      call assert_equal("1.23", printf('%s', 1.23))

      #" list
      VAR lvalue = [1, 'two', ['three', 4]]
      call assert_equal(string(lvalue), printf('%s', lvalue))

      #" dict
      VAR dvalue = {'key1': 'value1', 'key2': ['list', 'lvalue'], 'key3': {'dict': 'lvalue'}}
      call assert_equal(string(dvalue), printf('%s', dvalue))

      #" funcref
      call assert_equal('printf', printf('%s', 'printf'->function()))

      #" partial
      call assert_equal(string(function('printf', ['%s'])), printf('%s', function('printf', ['%s'])))
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_printf_spec_b()
  let lines =<< trim END
      call assert_equal("0", printf('%b', 0))
      call assert_equal("00001100", printf('%08b', 12))
      call assert_equal("11111111", printf('%08b', 0xff))
      call assert_equal("   1111011", printf('%10b', 123))
      call assert_equal("0001111011", printf('%010b', 123))
      call assert_equal(" 0b1111011", printf('%#10b', 123))
      call assert_equal("0B01111011", printf('%#010B', 123))
      call assert_equal("1001001100101100000001011010010", printf('%b', 1234567890))
      call assert_equal("11100000100100010000110000011011101111101111001", printf('%b', 123456789012345))
      call assert_equal("1111111111111111111111111111111111111111111111111111111111111111", printf('%b', -1))
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_max_min_errors()
  call v9.CheckLegacyAndVim9Failure(['call max(v:true)'], ['E712:', 'E1013:', 'E1227:'])
  call v9.CheckLegacyAndVim9Failure(['call max(v:true)'], ['max()', 'E1013:', 'E1227:'])
  call v9.CheckLegacyAndVim9Failure(['call min(v:true)'], ['E712:', 'E1013:', 'E1227:'])
  call v9.CheckLegacyAndVim9Failure(['call min(v:true)'], ['min()', 'E1013:', 'E1227:'])
endfunc

func Test_function_with_funcref()
  let lines =<< trim END
      let s:F = function('type')
      let s:Fref = function(s:F)
      call assert_equal(v:t_string, s:Fref('x'))
      call assert_fails("call function('s:F')", 'E700:')

      call assert_fails("call function('foo()')", 'E475:')
      call assert_fails("call function('foo()')", 'foo()')
      call assert_fails("function('')", 'E129:')

      let s:Len = {s -> strlen(s)}
      call assert_equal(6, s:Len('foobar'))
      let name = string(s:Len)
      " can evaluate "function('<lambda>99')"
      call execute('let Ref = ' .. name)
      call assert_equal(4, Ref('text'))
  END
  call v9.CheckScriptSuccess(lines)

  let lines =<< trim END
      vim9script
      var F = function('type')
      var Fref = function(F)
      call assert_equal(v:t_string, Fref('x'))
      call assert_fails("call function('F')", 'E700:')

      call assert_fails("call function('foo()')", 'E475:')
      call assert_fails("call function('foo()')", 'foo()')
      call assert_fails("function('')", 'E129:')

      var Len = (s) => strlen(s)
      call assert_equal(6, Len('foobar'))
      var name = string(Len)
      # can evaluate "function('<lambda>99')"
      call execute('var Ref = ' .. name)
      call assert_equal(4, Ref('text'))
  END
  call v9.CheckScriptSuccess(lines)
endfunc

func Test_funcref()
  func! One()
    return 1
  endfunc
  let OneByName = function('One')
  let OneByRef = funcref('One')
  func! One()
    return 2
  endfunc
  call assert_equal(2, OneByName())
  call assert_equal(1, OneByRef())
  let OneByRef = 'One'->funcref()
  call assert_equal(2, OneByRef())
  call assert_fails('echo funcref("{")', 'E475:')
  let OneByRef = funcref("One", repeat(["foo"], 20))
  call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:')
  call assert_fails('echo function("min") =~ function("min")', 'E694:')
  call assert_fails('echo test_null_function()->funcref()', 'E475: Invalid argument: NULL')
endfunc

" Test for calling function() and funcref() outside of a Vim script context.
func Test_function_outside_script()
  let cleanup =<< trim END
    call writefile([execute('messages')], 'Xtest.out')
    qall
  END
  call writefile(cleanup, 'Xverify.vim', 'D')
  call RunVim([], [], "-c \"echo function('s:abc')\" -S Xverify.vim")
  call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
  call RunVim([], [], "-c \"echo funcref('s:abc')\" -S Xverify.vim")
  call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
  call delete('Xtest.out')
endfunc

func Test_setmatches()
  let lines =<< trim END
      hi def link 1 Comment
      hi def link 2 PreProc
      VAR set = [{"group": 1, "pattern": 2, "id": 3, "priority": 4}]
      VAR exp = [{"group": '1', "pattern": '2', "id": 3, "priority": 4}]
      if has('conceal')
        LET set[0]['conceal'] = 5
        LET exp[0]['conceal'] = '5'
      endif
      eval set->setmatches()
      call assert_equal(exp, getmatches())
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(['VAR m = setmatches([], [])'], ['E745:', 'E1013:', 'E1210:'])
endfunc

func Test_empty_concatenate()
  let lines =<< trim END
      call assert_equal('b', 'a'[4 : 0] .. 'b')
      call assert_equal('b', 'b' .. 'a'[4 : 0])
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_broken_number()
  call v9.CheckLegacyAndVim9Failure(['VAR X = "bad"', 'echo 1X'], 'E15:')
  call v9.CheckLegacyAndVim9Failure(['VAR X = "bad"', 'echo 0b1X'], 'E15:')
  call v9.CheckLegacyAndVim9Failure(['echo 0b12'], 'E15:')
  call v9.CheckLegacyAndVim9Failure(['VAR X = "bad"', 'echo 0x1X'], 'E15:')
  call v9.CheckLegacyAndVim9Failure(['VAR X = "bad"', 'echo 011X'], 'E15:')

  call v9.CheckLegacyAndVim9Success(['call assert_equal(2, str2nr("2a"))'])

  call v9.CheckLegacyAndVim9Failure(['inoremap <Char-0b1z> b'], 'E474:')
endfunc

func Test_eval_after_if()
  let s:val = ''
  func SetVal(x)
    let s:val ..= a:x
  endfunc
  if 0 | eval SetVal('a') | endif | call SetVal('b')
  call assert_equal('b', s:val)
endfunc

func Test_divide_by_zero()
  " only tests that this doesn't crash, the result is not important
  echo 0 / 0
  echo 0 / 0 / -1
endfunc

" Test for command-line completion of expressions
func Test_expr_completion()
  CheckFeature cmdline_compl
  for cmd in [
	\ 'let a = ',
	\ 'const a = ',
	\ 'if',
	\ 'elseif',
	\ 'while',
	\ 'for',
	\ 'echo',
	\ 'echon',
	\ 'execute',
	\ 'echomsg',
	\ 'echoerr',
	\ 'call',
	\ 'return',
	\ 'cexpr',
	\ 'caddexpr',
	\ 'cgetexpr',
	\ 'lexpr',
	\ 'laddexpr',
	\ 'lgetexpr']
    call feedkeys(":" . cmd . " getl\<Tab>\<Home>\"\<CR>", 'xt')
    call assert_equal('"' . cmd . ' getline(', getreg(':'))
  endfor

  " completion for the expression register
  call feedkeys(":\"\<C-R>=float2\t\"\<C-B>\"\<CR>", 'xt')
  call assert_equal('"float2nr("', @=)

  " completion for window local variables
  let w:wvar1 = 10
  let w:wvar2 = 10
  call feedkeys(":echo w:wvar\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo w:wvar1 w:wvar2', @:)
  unlet w:wvar1 w:wvar2

  " completion for tab local variables
  let t:tvar1 = 10
  let t:tvar2 = 10
  call feedkeys(":echo t:tvar\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo t:tvar1 t:tvar2', @:)
  unlet t:tvar1 t:tvar2

  " completion for variables
  let g:tvar1 = 1
  let g:tvar2 = 2
  call feedkeys(":let g:tv\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"let g:tvar1 g:tvar2', @:)
  " completion for variables after a ||
  call feedkeys(":echo 1 || g:tv\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo 1 || g:tvar1 g:tvar2', @:)

  " completion for options
  call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo &compatible', @:)
  call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo 1 && &compatible', @:)
  call feedkeys(":echo &g:equala\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"echo &g:equalalways', @:)

  " completion for string
  call feedkeys(":echo \"Hello\\ World\"\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"echo \"Hello\\ World\"\<C-A>", @:)
  call feedkeys(":echo 'Hello World'\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"echo 'Hello World'\<C-A>", @:)

  " completion for command after a |
  call feedkeys(":echo 'Hello' | cwin\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"echo 'Hello' | cwindow", @:)

  " completion for environment variable
  let $X_VIM_TEST_COMPLETE_ENV = 'foo'
  call feedkeys(":let $X_VIM_TEST_COMPLETE_E\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_match('"let $X_VIM_TEST_COMPLETE_ENV', @:)
  unlet $X_VIM_TEST_COMPLETE_ENV
endfunc

" Test for errors in expression evaluation
func Test_expr_eval_error()
  call v9.CheckLegacyAndVim9Failure(["VAR i = 'abc' .. []"], ['E730:', 'E1105:', 'E730:'])
  call v9.CheckLegacyAndVim9Failure(["VAR l = [] + 10"], ['E745:', 'E1051:', 'E745'])
  call v9.CheckLegacyAndVim9Failure(["VAR v = 10 + []"], ['E745:', 'E1051:', 'E745:'])
  call v9.CheckLegacyAndVim9Failure(["VAR v = 10 / []"], ['E745:', 'E1036:', 'E745:'])
  call v9.CheckLegacyAndVim9Failure(["VAR v = -{}"], ['E728:', 'E1012:', 'E728:'])
endfunc

func Test_white_in_function_call()
  let lines =<< trim END
      VAR text = substitute ( 'some text' , 't' , 'T' , 'g' )
      call assert_equal('some TexT', text)
  END
  call v9.CheckTransLegacySuccess(lines)

  let lines =<< trim END
      var text = substitute ( 'some text' , 't' , 'T' , 'g' )
      call assert_equal('some TexT', text)
  END
  call v9.CheckDefAndScriptFailure(lines, ['E1001:', 'E121:'])
endfunc

" Test for float value comparison
func Test_float_compare()
  let lines =<< trim END
      call assert_true(1.2 == 1.2)
      call assert_true(1.0 != 1.2)
      call assert_true(1.2 > 1.0)
      call assert_true(1.2 >= 1.2)
      call assert_true(1.0 < 1.2)
      call assert_true(1.2 <= 1.2)
      call assert_true(+0.0 == -0.0)
      #" two NaNs (not a number) are not equal
      call assert_true(sqrt(-4.01) != (0.0 / 0.0))
      #" two inf (infinity) are equal
      call assert_true((1.0 / 0) == (2.0 / 0))
      #" two -inf (infinity) are equal
      call assert_true(-(1.0 / 0) == -(2.0 / 0))
      #" +infinity != -infinity
      call assert_true((1.0 / 0) != -(2.0 / 0))
  END
  call v9.CheckLegacyAndVim9Success(lines)
endfunc

func Test_string_interp()
  let lines =<< trim END
    call assert_equal('', $"")
    call assert_equal('foobar', $"foobar")
    #" Escaping rules.
    call assert_equal('"foo"{bar}', $"\"foo\"{{bar}}")
    call assert_equal('"foo"{bar}', $'"foo"{{bar}}')
    call assert_equal('foobar', $"{"foo"}" .. $'{'bar'}')
    #" Whitespace before/after the expression.
    call assert_equal('3', $"{ 1 + 2 }")
    #" String conversion.
    call assert_equal('hello from ' .. v:version, $"hello from {v:version}")
    call assert_equal('hello from ' .. v:version, $'hello from {v:version}')
    #" Paper over a small difference between VimScript behaviour.
    call assert_equal(string(v:true), $"{v:true}")
    call assert_equal('(1+1=2)', $"(1+1={1 + 1})")
    #" Hex-escaped opening brace: char2nr('{') == 0x7b
    call assert_equal('esc123ape', $"esc{123}ape")
    call assert_equal('me{}me', $"me{"\x7b"}\x7dme")
    VAR var1 = "sun"
    VAR var2 = "shine"
    call assert_equal('sunshine', $"{var1}{var2}")
    call assert_equal('sunsunsun', $"{var1->repeat(3)}")
    #" Multibyte strings.
    call assert_equal('say ハロー・ワールド', $"say {'ハロー・ワールド'}")
    #" Nested.
    call assert_equal('foobarbaz', $"foo{$"{'bar'}"}baz")
    #" Do not evaluate blocks when the expr is skipped.
    VAR tmp = 0
    if v:false
      echo "${ LET tmp += 1 }"
    endif
    call assert_equal(0, tmp)

    #" Stray closing brace.
    call assert_fails('echo $"moo}"', 'E1278:')
    #" Undefined variable in expansion.
    call assert_fails('echo $"{moo}"', 'E121:')
    #" Empty blocks are rejected.
    call assert_fails('echo $"{}"', 'E15:')
    call assert_fails('echo $"{   }"', 'E15:')
  END
  call v9.CheckLegacyAndVim9Success(lines)

  let lines =<< trim END
    call assert_equal('5', $"{({x -> x + 1})(4)}")
  END
  call v9.CheckLegacySuccess(lines)

  let lines =<< trim END
    call assert_equal('5', $"{((x) => x + 1)(4)}")
    call assert_fails('echo $"{ # foo }"', 'E1279:')
  END
  call v9.CheckDefAndScriptSuccess(lines)
endfunc

" Test for bitwise left and right shift (<< and >>)
func Test_bitwise_shift()
  let lines =<< trim END
    call assert_equal(16, 1 << 4)
    call assert_equal(2, 16 >> 3)
    call assert_equal(0, 0 << 2)
    call assert_equal(0, 0 >> 4)
    call assert_equal(3, 3 << 0)
    call assert_equal(3, 3 >> 0)
    call assert_equal(0, 0 >> 4)
    call assert_equal(0, 999999 >> 100)
    call assert_equal(0, 999999 << 100)
    call assert_equal(-1, -1 >> 0)
    call assert_equal(-1, -1 << 0)
    VAR a = 8
    VAR b = 2
    call assert_equal(2, a >> b)
    call assert_equal(32, a << b)
    #" operator precedence
    call assert_equal(48, 1 + 2 << 5 - 1)
    call assert_equal(3, 8 + 4 >> 4 - 2)
    call assert_true(1 << 2 < 1 << 3)
    call assert_true(1 << 4 > 1 << 3)
    VAR val = 0
    for i in range(0, v:numbersize - 2)
        LET val = or(val, 1 << i)
    endfor
    call assert_equal(v:numbermax, val)
    LET val = v:numbermax
    for i in range(0, v:numbersize - 2)
        LET val = and(val, invert(1 << i))
    endfor
    #" -1 has all the bits set
    call assert_equal(-2, -1 << 1)
    call assert_equal(-4, -1 << 2)
    call assert_equal(-8, -1 << 3)
    if v:numbersize == 64
      call assert_equal(0x7fffffffffffffff, -1 >> 1)
      call assert_equal(0x3fffffffffffffff, -1 >> 2)
      call assert_equal(0x1fffffffffffffff, -1 >> 3)
    endif
    call assert_equal(0, val)
    #" multiple operators
    call assert_equal(16, 1 << 2 << 2)
    call assert_equal(4, 64 >> 2 >> 2)
    call assert_true(1 << 2 << 2 == 256 >> 2 >> 2)
  END
  call v9.CheckLegacyAndVim9Success(lines)

  call v9.CheckLegacyAndVim9Failure(['VAR v = 2 << -1'], ['E1283:', 'E1283:', 'E1283:'])
  call v9.CheckLegacyAndVim9Failure(['VAR a = 2', 'VAR b = -1', 'VAR v = a << b'], ['E1283:', 'E1283:', 'E1283:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = "8" >> 2'], ['E1282:', 'E1282:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << "2"'], ['E1282:', 'E1282:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR a = "8"', 'VAR b = 2', 'VAR v = a << b'], ['E1282:', 'E1012:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR a = 8', 'VAR b = "2"', 'VAR v = a >> b'], ['E1282:', 'E1012:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = ![] << 1'], ['E745:', 'E1012:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << ![]'], ['E745:', 'E1012:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = ![] >> 1'], ['E745:', 'E1012:', 'E1282:'])
  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 >> ![]'], ['E745:', 'E1012:', 'E1282:'])
  call v9.CheckDefAndScriptFailure(['echo 1<< 2'], ['E1004:', 'E1004:'])
  call v9.CheckDefAndScriptFailure(['echo 1 <<2'], ['E1004:', 'E1004:'])
  call v9.CheckDefAndScriptFailure(['echo 1>> 2'], ['E1004:', 'E1004:'])
  call v9.CheckDefAndScriptFailure(['echo 1 >>2'], ['E1004:', 'E1004:'])

  let lines =<< trim END
     var a = 1
             <<
             4
     assert_equal(16, a)
  END
  call v9.CheckDefAndScriptSuccess(lines)

  let lines =<< trim END
    # Use in a lambda function
    const DivBy2Ref_A = (n: number): number => n >> 1
    assert_equal(16, DivBy2Ref_A(32))
    const DivBy2Ref_B = (n: number): number => (<number>n) >> 1
    assert_equal(16, DivBy2Ref_B(32))
    const MultBy2Ref_A = (n: number): number => n << 1
    assert_equal(8, MultBy2Ref_A(4))
    const MultBy2Ref_B = (n: number): number => (<number>n) << 1
    assert_equal(8, MultBy2Ref_B(4))

    def DivBy2_A(): func(number): number
      return (n: number): number => n >> 1
    enddef
    assert_equal(16, DivBy2_A()(32))
    def DivBy2_B(): func(number): number
      return (n: number): number => (<number>n) >> 1
    enddef
    assert_equal(16, DivBy2_B()(32))
    def MultBy2_A(): func(number): number
      return (n: number): number => n << 1
    enddef
    assert_equal(64, MultBy2_A()(32))
    def MultBy2_B(): func(number): number
      return (n: number): number => (<number>n) << 1
    enddef
    assert_equal(64, MultBy2_B()(32))
  END
  call v9.CheckDefAndScriptSuccess(lines)

  " Use in a legacy lambda function
  const DivBy2Ref_A = {n -> n >> 1}
  call assert_equal(16, DivBy2Ref_A(32))
  func DivBy2_A()
    return {n -> n >> 1}
  endfunc
  call assert_equal(16, DivBy2_A()(32))
  const MultBy2Ref_A = {n -> n << 1}
  call assert_equal(64, MultBy2Ref_A(32))
  func MultBy2_A()
    return {n -> n << 1}
  endfunc
  call assert_equal(64, MultBy2_A()(32))
endfunc

" vim: shiftwidth=2 sts=2 expandtab