Include: include/setup.vader

Execute (neomake#postprocess#generic_length):
  new
  norm! iimport foo bar
  let entry = {
  \ 'bufnr': bufnr('%'),
  \ 'lnum': 1,
  \ 'col': 8,
  \ 'text': "Some error about 'foo bar' happened"}

  " Default pattern matches 'foo bar'.
  let this = {'postprocess': {}}
  let new = deepcopy(entry)
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual new.length, 7

  " Handles non-existing buffer.
  let new = deepcopy(entry)
  let new.bufnr = entry.bufnr + 1
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual has_key(new, 'length'), 0

  " Skips handling without linenr.
  let new = deepcopy(entry)
  let new.lnum = 0
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual has_key(new, 'length'), 0

  " Skips handling with unmatched col.
  let new = deepcopy(entry)
  let new.col += 1
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual has_key(new, 'length'), 0

  " Custom pattern does not match.
  let this = {'pattern': 'NOMATCH'}
  let new = deepcopy(entry)
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual has_key(new, 'length'), 0
  AssertEqual entry, new

  " Custom pattern does match.
  let this = {'pattern': 'foo'}
  let new = deepcopy(entry)
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual new.length, 3

  " Handles entry for another buffer.
  new
  let this = {'postprocess': {}}
  let new = deepcopy(entry)
  call call('neomake#postprocess#generic_length', [new], this)
  AssertEqual new.length, 7
  bwipe!
  bwipe!

Execute (Postprocess: called with dict+maker as self for list):
  new
  file file1.vim
  norm! ifoo = bar - 5

  let g:neomake_test_called = []
  function! NeomakeTestPostprocess(entry) abort dict
    call add(g:neomake_test_called, [self, g:neomake_postprocess_context])
  endfunction

  let maker = {
  \ 'exe': 'printf',
  \ 'args': ['file1.vim:1:7: check: bar!'],
  \ 'errorformat': '%E%f:%l:%c: %m',
  \ 'append_file': 0,
  \ '_maker_marker': 1,
  \ 'postprocess': [{
  \     'fn': function('neomake#postprocess#generic_length'),
  \     'pattern': '\vcheck: \zs\k+\ze',
  \   },
  \   'NeomakeTestPostprocess',
  \   {'fn': 'NeomakeTestPostprocess', 'pattern': 'custom_pattern',
  \    'custom_var': 42}]
  \ }

  AssertEqual neomake#highlights#_get(), {'file': {}, 'project': {}}

  call neomake#Make(1, [maker])
  NeomakeTestsWaitForFinishedJobs
  AssertEqualQf getloclist(0), [{
  \ 'lnum': 1,
  \ 'bufnr': bufnr('%'),
  \ 'col': 7,
  \ 'valid': 1,
  \ 'vcol': 0,
  \ 'nr': -1,
  \ 'type': 'E',
  \ 'pattern': '',
  \ 'text': 'check: bar!'}]

  " Test that length has been used with the highlight.
  let highlights = neomake#highlights#_get()
  if has('nvim')
    AssertEqual has_key(highlights['file'], bufnr('%')), 1, "highlight for file"
  else
    AssertEqual highlights.file[bufnr('%')].NeomakeError, [[1, 7, 3]]
  endif

  AssertEqual len(g:neomake_test_called), 2
  AssertEqual g:neomake_test_called[0][0]._maker_marker, 1
  AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1
  AssertEqual g:neomake_test_called[1][0].pattern, 'custom_pattern'
  AssertEqual g:neomake_test_called[1][0].custom_var, 42
  AssertEqual g:neomake_test_called[1][1].jobinfo.maker._maker_marker, 1
  bwipe!
  delfunction NeomakeTestPostprocess

Execute (Postprocess: called with dict+maker as self for non-list):
  Save g:neomake_test_called
  let g:neomake_test_called = []

  let maker = {
  \ 'exe': 'printf',
  \ 'args': ['file1.vim:1:7: check: bar!'],
  \ 'errorformat': '%E%f:%l:%c: %m',
  \ 'append_file': 0,
  \ '_maker_marker': 1,
  \ }
  function! maker.postprocess(entry) abort dict
    call add(g:neomake_test_called, [self, g:neomake_postprocess_context])
  endfunction

  new
  file file1.vim
  call neomake#Make(1, [maker])
  NeomakeTestsWaitForFinishedJobs

  AssertEqualQf getloclist(0), [{
  \ 'lnum': 1,
  \ 'bufnr': bufnr('%'),
  \ 'col': 7,
  \ 'valid': 1,
  \ 'vcol': 0,
  \ 'nr': -1,
  \ 'type': 'E',
  \ 'pattern': '',
  \ 'text': 'check: bar!'}]
  AssertEqual len(g:neomake_test_called), 1
  AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1
  bwipe

Execute (Postprocess: removes entries with valid -1):
  Save g:neomake_test_called
  let g:neomake_test_called = []

  let maker = {
  \ 'exe': 'printf',
  \ 'args': [join([
  \   'file1.vim:1:7: check: bar!',
  \   'file1.vim:2:5: check: foo!',
  \   'file1.vim:1:7: check: bar!'], '\n')],
  \ 'errorformat': '%E%f:%l:%c: %m',
  \ 'append_file': 0,
  \ '_maker_marker': 1,
  \ }
  function! maker.postprocess(entry) abort dict
    call add(g:neomake_test_called, [self, g:neomake_postprocess_context])
    if a:entry.text ==# 'check: bar!'
      let a:entry.valid = -1
    endif
  endfunction

  new
  file file1.vim
  call neomake#Make(1, [maker])
  NeomakeTestsWaitForFinishedJobs

  AssertEqual len(g:neomake_test_called), 3
  AssertEqual g:neomake_test_called[0][1].jobinfo.maker._maker_marker, 1

  AssertEqualQf getloclist(0), [{
  \ 'lnum': 2,
  \ 'bufnr': bufnr('%'),
  \ 'col': 5,
  \ 'valid': 1,
  \ 'vcol': 0,
  \ 'nr': -1,
  \ 'type': 'E',
  \ 'pattern': '',
  \ 'text': 'check: foo!'}]
  bwipe

Execute (Postprocess: can be disabled with empty string):
  let maker = {
  \ 'exe': 'printf',
  \ 'args': ['success'],
  \ 'errorformat': '%E%m',
  \ 'append_file': 0,
  \ 'postprocess': '',
  \ }

  call neomake#Make(1, [maker])
  NeomakeTestsWaitForFinishedJobs

  AssertEqual map(getloclist(0), 'v:val.text'), ['success']

Execute (Postprocess: can be disabled with empty list):
  let maker = {
  \ 'exe': 'printf',
  \ 'args': ['success'],
  \ 'errorformat': '%E%m',
  \ 'append_file': 0,
  \ 'postprocess': [],
  \ }

  call neomake#Make(1, [maker])
  NeomakeTestsWaitForFinishedJobs

  AssertEqual map(getloclist(0), 'v:val.text'), ['success']

Execute (maker.postprocess interface for obj):
  let postprocessobj = {'property': 1}

  Save g:neomake_test_called
  let g:neomake_test_called = []
  function! postprocessobj.fn(entry) abort
    AssertEqual self.property, 1
    AssertEqual sort(keys(self)), ['fn', 'property']
    let self.called = 1
    AssertEqual ['jobinfo'], keys(g:neomake_postprocess_context)
  endfunction

  let maker = neomake#makers#ft#neomake_tests#echo_maker()
  let maker = neomake#GetMaker(maker)
  let maker.postprocess = postprocessobj
  call neomake#Make(0, [maker])
  NeomakeTestsWaitForFinishedJobs
  AssertEqual 1, postprocessobj.called, 'Property could be set'
  Assert 1, g:neomake_test_called

Execute (maker.postprocess interface for maker):
  call g:NeomakeSetupAutocmdWrappers()
  Save g:neomake_test_called
  let g:neomake_test_called = []
  let maker = neomake#makers#ft#neomake_tests#echo_maker()
  function! maker.postprocess(entry) abort
    try
      let self.called = 1
    catch
      call add(g:neomake_test_called, v:exception)
    endtry
    AssertEqual g:neomake_postprocess_context.jobinfo.maker, self
  endfunction

  call neomake#Make(0, [maker])
  NeomakeTestsWaitForFinishedJobs
  Assert !has_key(maker, 'called'), 'Property not set, since maker was copied'
  AssertEqual ['Vim(let):E741: Value is locked: self.called = 1'], g:neomake_test_called
  AssertEqual len(g:neomake_test_finished), 1

Execute (neomake#postprocess#generic_length for multiple matches):
  if !exists('*matchstrpos')
    NeomakeTestsSkip 'only supported with matchstrpos'
  else
    new
    norm! i...
    let entry = {'text': "'...' is bad, use '…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "'…' is better than '...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "'…''...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    " Now reversed.
    " Note that is uses bytes, so the length for '…' is also 3 here.
    norm! cc…
    let entry = {'text': "'...' is bad, use '…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "'…' is better than '...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "'…''...'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "'...''…'", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, 3

    let entry = {'text': "STARTfooENDSTART…END", 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {
    \ 'pattern': "\\v(START)\\zs.{-}\\ze(END)"
    \ })
    AssertEqual entry.length, 3

    " Should use the best/longest match.
    norm! ccchairman
    let entry = {'text': "sexism.misc Gender bias. Use 'chair' instead of 'chairman'.",
    \ 'lnum': 1, 'col': 1, 'bufnr': bufnr('%')}
    call call('neomake#postprocess#generic_length', [entry], {})
    AssertEqual entry.length, len('chairman')
    bwipe!
  endif

Execute (Postprocess: can be lambda):
  if !has('lambda')
    NeomakeTestsSkip 'no lambda feature'
  else
    let maker = {
    \ 'exe': 'printf',
    \ 'args': ['file1.vim:1:7: check: bar!\nfile1.vim:2:5: check: foo!'],
    \ 'errorformat': '%E%f:%l:%c: %m',
    \ 'append_file': 0,
    \ 'postprocess': {entry -> entry.text ==# 'check: bar!' ? extend(entry, {'valid': -1}) : entry}
    \ }

    new
    file file1.vim
    call neomake#Make(1, [maker])
    NeomakeTestsWaitForFinishedJobs

    AssertEqualQf getloclist(0), [{
    \ 'lnum': 2,
    \ 'bufnr': bufnr('%'),
    \ 'col': 5,
    \ 'valid': 1,
    \ 'vcol': 0,
    \ 'nr': -1,
    \ 'type': 'E',
    \ 'pattern': '',
    \ 'text': 'check: foo!'}]
    bwipe
  endif

Execute (Postprocess: lambda from maker):
  if !has('lambda')
    NeomakeTestsSkip 'no lambda feature'
  else
    let maker = {
    \ 'exe': 'printf',
    \ 'args': ['%s\n',
    \   'WARNING: file.adoc: line 162: illegal system attribute name: font-style',
    \   'WARNING: file.adoc: line 1: something else'],
    \ 'errorformat': '%tARNING: %f: line %l: %m',
    \ 'append_file': 0,
    \ }
    let maker.postprocess = {
    \ entry -> entry.text =~# 'illegal system attribute name: font-style'
    \ ? extend(entry, {'valid': -1}) : entry}

    new
    file file.adoc
    call neomake#Make(1, [maker])
    NeomakeTestsWaitForFinishedJobs
    AssertEqualQf getloclist(0), [{
    \ 'lnum': 1,
    \ 'bufnr': bufnr('%'),
    \ 'col': 0,
    \ 'valid': 1,
    \ 'vcol': 0,
    \ 'nr': -1,
    \ 'type': 'W',
    \ 'pattern': '',
    \ 'text': 'something else'}]
    bwipe
  endif

Execute (Postprocess: lambda from conf):
  if !has('lambda')
    NeomakeTestsSkip 'no lambda feature'
  else
    let maker = {
    \ 'name': 'mymaker',
    \ 'exe': 'printf',
    \ 'args': ['%s\n',
    \   'WARNING: file.adoc: line 162: illegal system attribute name: font-style',
    \   'WARNING: file.adoc: line 1: something else'],
    \ 'errorformat': '%tARNING: %f: line %l: %m',
    \ 'append_file': 0,
    \ }
    new
    file file.adoc
    set ft=myft
    let b:neomake_myft_mymaker_postprocess = {
    \ entry -> entry.text =~# 'illegal system attribute name: font-style'
    \ ? extend(entry, {'valid': -1}) : entry}
    call neomake#Make(1, [maker])
    NeomakeTestsWaitForFinishedJobs
    AssertEqual map(getloclist(0), 'v:val.text'), ['something else']
    bwipe
  endif

Execute (Hook context gets cleaned on error in postprocess):
  call NeomakeTestsSetVimMessagesMarker()
  let maker = copy(g:error_maker)
  function! maker.postprocess(entry)
    throw 'error from postprocess'
  endfunction
  call neomake#Make({'enabled_makers': [maker]})
  NeomakeTestsWaitForFinishedJobs
  AssertNeomakeMessage 'Error during output processing for error-maker: error from postprocess.', 0
  let vim_msgs = NeomakeTestsGetVimMessages()
  Assert vim_msgs[-1] =~# 'Neomake error in: function .*', 'message found'
  AssertEqual len(vim_msgs), 1
  Assert !exists('g:neomake_postprocess_context'), 'Hook context was cleaned.'

Execute (neomake#postprocess#compress_whitespace):
  function! s:F(text)
    let entry = {'text': a:text}
    call neomake#postprocess#compress_whitespace(entry)
    return entry.text
  endfunction
  AssertEqual s:F('foo'), 'foo'
  AssertEqual s:F(' foo'), 'foo'
  AssertEqual s:F('foo '), 'foo'
  AssertEqual s:F('foo bar '), 'foo bar'
  AssertEqual s:F("foo\nbar "), 'foo bar'
  AssertEqual s:F("foo\r\nbar "), 'foo bar'
  AssertEqual s:F("foo\n bar "), 'foo bar'
  AssertEqual s:F("foo\n bar \r\n"), 'foo bar'

Execute (neomake#postprocess#remove_duplicates):
  let maker = {'postprocess': copy(g:neomake#postprocess#remove_duplicates)}

  let entries = [
  \ {'bufnr': 1, 'lnum': 1, 'text': 'one'},
  \ {'bufnr': 1, 'lnum': 2, 'text': 'two'},
  \ {'bufnr': 1, 'lnum': 1, 'text': 'one'},
  \ ]

  call maker.postprocess.fn(entries[0])
  AssertEqual maker.postprocess._seen_entries, [entries[0]]
  call maker.postprocess.fn(entries[1])
  AssertEqual maker.postprocess._seen_entries, entries[0:1]
  call maker.postprocess.fn(entries[2])
  AssertEqual maker.postprocess._seen_entries, entries[0:1]

  AssertEqual entries[2].valid, -1