Before:
  Save g:lspconfig
  Save g:ale_linters_ignore
  Save g:ale_buffer_info
  Save g:ale_disable_lsp

  let g:lspconfig = 0
  let g:lspconfig_names = {}
  let g:ale_disable_lsp = 0
  let g:linters = []
  let g:loclist = []
  let g:run_linters_called = 0

  runtime autoload/ale/engine.vim
  runtime autoload/ale/engine/ignore.vim

  " Mock the engine function so we can set it up.
  function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
    let g:linters = a:linters
    let g:run_linters_called = 1
  endfunction

  function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
    let g:loclist = a:loclist
  endfunction

  function! ale#engine#ignore#GetLSPConfigNames() abort
    return g:lspconfig_names
  endfunction

  call ale#linter#Define('foobar', {
  \ 'name': 'testlinter',
  \ 'callback': 'TestCallback',
  \ 'executable': has('win32') ? 'cmd' : 'true',
  \ 'command': has('win32') ? 'echo' : 'true',
  \})
  call ale#test#SetDirectory('/testplugin/test')

After:
  unlet! b:ale_linted
  unlet! b:ale_linters_ignore
  unlet! b:ale_quitting
  unlet! b:ale_save_event_fired
  unlet! b:ale_disable_lsp
  unlet! g:linters
  unlet! g:loclist
  unlet! g:lsp_message
  unlet! g:lspconfig_names

  Restore

  call ale#test#RestoreDirectory()
  call ale#linter#Reset()
  call ale#lsp_linter#ClearLSPData()

  runtime autoload/ale/engine.vim
  runtime autoload/ale/engine/ignore.vim

Execute(GetList should ignore some invalid values):
  AssertEqual [], ale#engine#ignore#GetList('', 'foo')
  AssertEqual [], ale#engine#ignore#GetList('', 0)
  AssertEqual [], ale#engine#ignore#GetList('', v:null)

Execute(GetList should handle Lists):
  AssertEqual ['foo', 'bar'], ale#engine#ignore#GetList('', ['foo', 'bar'])

Execute(GetList should handle Dictionaries):
  AssertEqual
  \ ['linter1', 'linter2'],
  \ uniq(sort(ale#engine#ignore#GetList('x.y.z', {
  \   'x': ['linter1'],
  \   'abc': ['linter3'],
  \   'z': ['linter2'],
  \ })))

Execute(Exclude should ignore some invalid values):
  AssertEqual
  \ [
  \   {'name': 'linter1', 'aliases': []},
  \   {'name': 'linter2', 'aliases': ['alias1']},
  \   {'name': 'linter3', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo.bar',
  \   [
  \     {'name': 'linter1', 'aliases': []},
  \     {'name': 'linter2', 'aliases': ['alias1']},
  \     {'name': 'linter3', 'aliases': []},
  \   ],
  \   'foo',
  \   0,
  \ )
  AssertEqual
  \ [
  \   {'name': 'linter1', 'aliases': []},
  \   {'name': 'linter2', 'aliases': ['alias1']},
  \   {'name': 'linter3', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo.bar',
  \   [
  \     {'name': 'linter1', 'aliases': []},
  \     {'name': 'linter2', 'aliases': ['alias1']},
  \     {'name': 'linter3', 'aliases': []},
  \   ],
  \   0,
  \   0,
  \ )
  AssertEqual
  \ [
  \   {'name': 'linter1', 'aliases': []},
  \   {'name': 'linter2', 'aliases': ['alias1']},
  \   {'name': 'linter3', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo.bar',
  \   [
  \     {'name': 'linter1', 'aliases': []},
  \     {'name': 'linter2', 'aliases': ['alias1']},
  \     {'name': 'linter3', 'aliases': []},
  \   ],
  \   v:null,
  \   0,
  \ )

Execute(Exclude should handle Lists):
  AssertEqual
  \ [
  \   {'name': 'linter3', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo.bar',
  \   [
  \     {'name': 'linter1', 'aliases': []},
  \     {'name': 'linter2', 'aliases': ['alias1']},
  \     {'name': 'linter3', 'aliases': []},
  \   ],
  \   ['linter1', 'alias1'],
  \   0,
  \ )

Execute(Exclude should handle Dictionaries):
  AssertEqual
  \ [
  \   {'name': 'linter3', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo.bar',
  \   [
  \     {'name': 'linter1', 'aliases': []},
  \     {'name': 'linter2', 'aliases': ['alias1']},
  \     {'name': 'linter3', 'aliases': []},
  \   ],
  \   {'foo': ['linter1'], 'bar': ['alias1']},
  \   0,
  \ )

Execute(Exclude should filter LSP linters when ale_disable_lsp is set to 1):
  AssertEqual
  \ [
  \   {'name': 'linter1', 'aliases': [], 'lsp': ''},
  \   {'name': 'linter2', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo',
  \   [
  \       {'name': 'linter1', 'aliases': [], 'lsp': ''},
  \       {'name': 'linter2', 'aliases': []},
  \       {'name': 'linter3', 'aliases': [], 'lsp': 'stdio'},
  \   ],
  \   [],
  \   1,
  \ )

Execute(Exclude should remove lspconfig linters with ale_disable_lsp = 'auto'):
  let g:lspconfig = 1
  " A map is used here so you can easily see what the ignore mapping should be
  " remapping the nvim-lspconfig names to.
  let g:lspconfig_names = keys({
  \   'als': 'adals',
  \   'ansiblels': 'ansible-language-server',
  \   'bicep': 'bicep_language_server',
  \   'cmake': 'cmake_language_server',
  \   'denols': 'deno',
  \   'erlangls': 'erlang_ls',
  \   'html': 'vscodehtml',
  \   'ocamlls': 'ocaml-language-server',
  \   'puppet': 'puppet_languageserver',
  \   'pyright': 'pyright',
  \})

  " We should keep bicep, as it's different tool.
  AssertEqual
  \ [
  \   {'name': 'bicep', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo',
  \   [
  \       {'name': 'adals', 'aliases': []},
  \       {'name': 'language_server', 'aliases': ['ansible-language-server']},
  \       {'name': 'cmake_language_server', 'aliases': []},
  \       {'name': 'deno', 'aliases': []},
  \       {'name': 'erlang_ls', 'aliases': []},
  \       {'name': 'vscodehtml', 'aliases': []},
  \       {'name': 'bicep', 'aliases': []},
  \       {'name': 'ols', 'aliases': ['ocaml-language-server']},
  \       {'name': 'languageserver', 'aliases': ['puppet_languageserver']},
  \       {'name': 'pyright', 'aliases': []},
  \   ],
  \   [],
  \   'auto',
  \ )

Execute(Exclude should check that the nvim-lspconfig plugin is installed with ale_disable_lsp = 'auto'):
  let g:lspconfig = 0
  let g:lspconfig_names = ['pyright']

  " We should keep pyright here, because g:lspconfig is 0.
  AssertEqual
  \ [
  \   {'name': 'pyright', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo',
  \   [
  \       {'name': 'pyright', 'aliases': []},
  \   ],
  \   [],
  \   'auto',
  \ )

Execute(Exclude should handle the lspconfig result being a Dictionary):
  let g:lspconfig = 1
  let g:lspconfig_names = {}

  " We should keep pyright here, because the configuration is empty.
  AssertEqual
  \ [
  \   {'name': 'pyright', 'aliases': []},
  \ ],
  \ ale#engine#ignore#Exclude(
  \   'foo',
  \   [
  \       {'name': 'pyright', 'aliases': []},
  \   ],
  \   [],
  \   'auto',
  \ )

Given foobar(An empty file):
Execute(Global ignore lists should be applied for linters):
  " We have to set up buffer info so RunLinters is called.
  let g:ale_buffer_info = {bufnr(''): {}}

  ALELint
  Assert g:run_linters_called, "The mock callback wasn't called"
  AssertEqual ['testlinter'], map(g:linters, 'v:val.name')

  let g:ale_linters_ignore = ['testlinter']
  ALELint
  AssertEqual [], g:linters

Execute(buffer ignore lists should be applied for linters):
  " We have to set up buffer info so RunLinters is called.
  let g:ale_buffer_info = {bufnr(''): {}}

  ALELint
  Assert g:run_linters_called, "The mock callback wasn't called"
  AssertEqual ['testlinter'], map(g:linters, 'v:val.name')

  let b:ale_linters_ignore = ['testlinter']
  ALELint
  AssertEqual [], g:linters

Execute(Buffer ignore lists should be applied for tsserver):
  call ale#test#SetFilename('filename.ts')
  call ale#engine#InitBufferInfo(bufnr(''))

  let g:lsp_message = {
  \ 'seq': 0,
  \ 'type': 'event',
  \ 'event': 'syntaxDiag',
  \ 'body': {
  \   'file': g:dir . '/filename.ts',
  \   'diagnostics':[
  \     {
  \       'start': {
  \         'line':2,
  \         'offset':14,
  \       },
  \       'end': {
  \         'line':2,
  \         'offset':15,
  \       },
  \       'text': ''','' expected.',
  \       "code":1005
  \     },
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 2,
  \     'col': 14,
  \     'nr': 1005,
  \     'code': '1005',
  \     'type': 'E',
  \     'end_col': 14,
  \     'end_lnum': 2,
  \     'text': ''','' expected.',
  \   },
  \ ],
  \ g:loclist

  let g:loclist = []
  let b:ale_linters_ignore = ['tsserver']
  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(Buffer ignore lists should be applied for LSP linters):
  call ale#test#SetFilename('filename.py')
  call ale#engine#InitBufferInfo(bufnr(''))
  call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})

  let g:lsp_message = {
  \ 'jsonrpc': '2.0',
  \ 'method': 'textDocument/publishDiagnostics',
  \ 'params': {
  \   'uri': ale#path#ToFileURI(expand('%:p')),
  \   'diagnostics': [
  \     {
  \       'severity': 1,
  \       'message': 'x',
  \       'range': {
  \         'start': {'line': 0, 'character': 9},
  \         'end': {'line': 0, 'character': 9},
  \       },
  \     }
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 1,
  \     'col': 10,
  \     'type': 'E',
  \     'end_col': 9,
  \     'end_lnum': 1,
  \     'text': 'x',
  \   }
  \ ],
  \ g:loclist

  let b:ale_linters_ignore = ['lsplinter']
  let g:loclist = []

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(ale_disable_lsp should be applied for tsserver):
  call ale#test#SetFilename('filename.ts')
  call ale#engine#InitBufferInfo(bufnr(''))

  let g:lsp_message = {
  \ 'seq': 0,
  \ 'type': 'event',
  \ 'event': 'syntaxDiag',
  \ 'body': {
  \   'file': g:dir . '/filename.ts',
  \   'diagnostics':[
  \     {
  \       'start': {
  \         'line':2,
  \         'offset':14,
  \       },
  \       'end': {
  \         'line':2,
  \         'offset':15,
  \       },
  \       'text': ''','' expected.',
  \       "code":1005
  \     },
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 2,
  \     'col': 14,
  \     'nr': 1005,
  \     'code': '1005',
  \     'type': 'E',
  \     'end_col': 14,
  \     'end_lnum': 2,
  \     'text': ''','' expected.',
  \   },
  \ ],
  \ g:loclist

  let g:loclist = []
  let b:ale_disable_lsp = 1
  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(ale_disable_lsp = 'auto' should be applied for tsserver):
  let g:lspconfig = 1
  let g:lspconfig_names = ['tsserver']

  call ale#test#SetFilename('filename.ts')
  call ale#engine#InitBufferInfo(bufnr(''))

  let g:lsp_message = {
  \ 'seq': 0,
  \ 'type': 'event',
  \ 'event': 'syntaxDiag',
  \ 'body': {
  \   'file': g:dir . '/filename.ts',
  \   'diagnostics':[
  \     {
  \       'start': {
  \         'line':2,
  \         'offset':14,
  \       },
  \       'end': {
  \         'line':2,
  \         'offset':15,
  \       },
  \       'text': ''','' expected.',
  \       "code":1005
  \     },
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 2,
  \     'col': 14,
  \     'nr': 1005,
  \     'code': '1005',
  \     'type': 'E',
  \     'end_col': 14,
  \     'end_lnum': 2,
  \     'text': ''','' expected.',
  \   },
  \ ],
  \ g:loclist

  let g:loclist = []
  let g:ale_disable_lsp = 'auto'
  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(ale_disable_lsp should be applied for LSP linters):
  call ale#test#SetFilename('filename.py')
  call ale#engine#InitBufferInfo(bufnr(''))
  call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})

  let g:lsp_message = {
  \ 'jsonrpc': '2.0',
  \ 'method': 'textDocument/publishDiagnostics',
  \ 'params': {
  \   'uri': ale#path#ToFileURI(expand('%:p')),
  \   'diagnostics': [
  \     {
  \       'severity': 1,
  \       'message': 'x',
  \       'range': {
  \         'start': {'line': 0, 'character': 9},
  \         'end': {'line': 0, 'character': 9},
  \       },
  \     }
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 1,
  \     'col': 10,
  \     'type': 'E',
  \     'end_col': 9,
  \     'end_lnum': 1,
  \     'text': 'x',
  \   }
  \ ],
  \ g:loclist

  let b:ale_disable_lsp = 1
  let g:loclist = []

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(ale_disable_lsp = 'auto' should be applied for LSP linters):
  let g:lspconfig = 1
  let g:lspconfig_names = ['lsplinter']

  call ale#test#SetFilename('filename.py')
  call ale#engine#InitBufferInfo(bufnr(''))
  call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})

  let g:lsp_message = {
  \ 'jsonrpc': '2.0',
  \ 'method': 'textDocument/publishDiagnostics',
  \ 'params': {
  \   'uri': ale#path#ToFileURI(expand('%:p')),
  \   'diagnostics': [
  \     {
  \       'severity': 1,
  \       'message': 'x',
  \       'range': {
  \         'start': {'line': 0, 'character': 9},
  \         'end': {'line': 0, 'character': 9},
  \       },
  \     }
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 1,
  \     'col': 10,
  \     'type': 'E',
  \     'end_col': 9,
  \     'end_lnum': 1,
  \     'text': 'x',
  \   }
  \ ],
  \ g:loclist

  let g:ale_disable_lsp = 'auto'
  let g:loclist = []

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist

Execute(ale_disable_lsp = 'auto' should ignore LSP linters by alias too):
  let g:lspconfig = 1
  let g:lspconfig_names = ['lsplinter']

  call ale#test#SetFilename('filename.py')
  call ale#engine#InitBufferInfo(bufnr(''))
  call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'notthis', 'aliases': ['lsplinter'], 'lsp': 'stdio'}})

  let g:lsp_message = {
  \ 'jsonrpc': '2.0',
  \ 'method': 'textDocument/publishDiagnostics',
  \ 'params': {
  \   'uri': ale#path#ToFileURI(expand('%:p')),
  \   'diagnostics': [
  \     {
  \       'severity': 1,
  \       'message': 'x',
  \       'range': {
  \         'start': {'line': 0, 'character': 9},
  \         'end': {'line': 0, 'character': 9},
  \       },
  \     }
  \   ],
  \ },
  \}

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual
  \ [
  \   {
  \     'lnum': 1,
  \     'col': 10,
  \     'type': 'E',
  \     'end_col': 9,
  \     'end_lnum': 1,
  \     'text': 'x',
  \   }
  \ ],
  \ g:loclist

  let g:ale_disable_lsp = 'auto'
  let g:loclist = []

  call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)

  AssertEqual [], g:loclist
