diff --git a/README.md b/README.md index f8b9ced..423c839 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,14 @@ Run tests with Vim and Neovim, whichever is installed ./test/run.sh basic template # Only these cases ``` -Each case is a `.vue` file in [test/cases](test/cases), with an optional `.vim` file for the config and syntax checks. A case fails if indenting the whole file changes it, a check fails, or there is an error message. Tests also run on GitHub Actions for each push and pull request. +Each case is a `.vue` or `.wpy` file in [test/cases](test/cases), with an optional `.vim` file for the config and checks. A case fails if + +- indenting the whole file changes it +- with `g:test_flatten`, indenting the file after removing all indent doesn't restore it +- a check in `Check()` fails, such as syntax, `GetVueTag()`, `GetVueSyntax()` or fold level +- there is an error message + +Tests also run on GitHub Actions for each push and pull request. ## Acknowledgments & Refs diff --git a/test/cases/attribute-off.vim b/test/cases/attribute-off.vim new file mode 100644 index 0000000..09c8797 --- /dev/null +++ b/test/cases/attribute-off.vim @@ -0,0 +1,14 @@ +" Without attribute and keyword highlight +let g:vim_vue_plugin_config = {'attribute': 0, 'keyword': 0} +let g:test_flatten = 1 + +function! Check() + call ExpectSyntax('@click', 'VueKey') + call ExpectSyntax('toggle', 'VueValue') + call ExpectNoSyntax('$t', 'VueInject') + call ExpectNoSyntax('1"', 'javaScriptNumber') + call ExpectSyntax('message', 'VueExpression') + call ExpectEqual(matchstr(execute('highlight VueKey'), 'links to \zs\S\+'), + \ 'htmlArg', 'VueKey link') + call ExpectNoSyntax('data', 'vueObjectFuncName') +endfunction diff --git a/test/cases/attribute-off.vue b/test/cases/attribute-off.vue new file mode 100644 index 0000000..73cf150 --- /dev/null +++ b/test/cases/attribute-off.vue @@ -0,0 +1,13 @@ + + + diff --git a/test/cases/attribute.vim b/test/cases/attribute.vim new file mode 100644 index 0000000..4806efa --- /dev/null +++ b/test/cases/attribute.vim @@ -0,0 +1,26 @@ +" Template syntax with attribute highlight +let g:vim_vue_plugin_config = {'attribute': 1} +let g:test_flatten = 1 + +function! Check() + " Directives + call ExpectSyntax(':class', 'VueKey') + call ExpectSyntax('@click', 'VueKey') + call ExpectSyntax('v-if', 'VueKey') + " Values as expressions + call ExpectSyntax('1"', 'javaScriptNumber') + call ExpectSyntax('$t', 'VueInject') + call ExpectSyntax("'title'", 'javaScriptStringS') + " Components and attributes + normal! gg + call ExpectSyntax('MyComponent', 'VueComponentName') + call ExpectSyntax('ref=', 'htmlArg') + call ExpectSyntax('data-id', 'htmlArg') + call ExpectSyntax('my-component', 'VueComponentName') + call ExpectSyntax('transition', 'VueComponentName') + " Interpolation + call ExpectSyntax('{{', 'VueBrace') + call ExpectSyntax('message', 'VueExpression') + call ExpectEqual(matchstr(execute('highlight VueKey'), 'links to \zs\S\+'), + \ 'Type', 'VueKey link') +endfunction diff --git a/test/cases/attribute.vue b/test/cases/attribute.vue new file mode 100644 index 0000000..ffd430f --- /dev/null +++ b/test/cases/attribute.vue @@ -0,0 +1,19 @@ + + + diff --git a/test/cases/basic.vim b/test/cases/basic.vim index eb117a9..475c037 100644 --- a/test/cases/basic.vim +++ b/test/cases/basic.vim @@ -5,3 +5,15 @@ let g:vim_vue_plugin_config = { \ 'style': ['css'], \}, \} +let g:test_flatten = 1 +packadd matchit + +" Jump between tags with % by matchit. Use :normal for its mapping +function! Check() + for [lnum, col, expected] in [[1, 2, [3, '/template']], [2, 4, [2, '/p']]] + call cursor(lnum, col) + normal % + call ExpectEqual([line('.'), matchstr(getline('.'), '\%'.col('.').'c/\w\+')], + \ expected, printf('after %% from line %d col %d', lnum, col)) + endfor +endfunction diff --git a/test/cases/context.vim b/test/cases/context.vim new file mode 100644 index 0000000..4257389 --- /dev/null +++ b/test/cases/context.vim @@ -0,0 +1,27 @@ +" OnChangeVueSyntax() is called when syntax under cursor changes. It's +" defined before the plugin is loaded +let g:vim_vue_plugin_config = { + \'syntax': { + \ 'template': ['html'], + \ 'script': ['javascript', 'typescript'], + \ 'style': ['css', 'scss'], + \}, + \} +let g:test_changes = [] + +function! OnChangeVueSyntax(syntax) + call add(g:test_changes, a:syntax) +endfunction + +function! Check() + for lnum in [2, 3, 6, 6, 10, 2] + call cursor(lnum, 1) + doautocmd CursorMoved + endfor + call ExpectEqual(g:test_changes, ['html', 'typescript', 'scss', 'html'], + \ 'syntax changes') + call ExpectEqual(GetVueSyntax(), 'html', 'GetVueSyntax()') + call ExpectTag(6, 'script') + call ExpectTag(10, 'style') +endfunction +let g:test_flatten = 1 diff --git a/test/cases/context.vue b/test/cases/context.vue new file mode 100644 index 0000000..08d2b42 --- /dev/null +++ b/test/cases/context.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/test/cases/example.vim b/test/cases/example.vim index 530800c..f6edbd6 100644 --- a/test/cases/example.vim +++ b/test/cases/example.vim @@ -13,3 +13,28 @@ let g:vim_vue_plugin_config = { \'foldexpr': 1, \'full_syntax': ['scss', 'less'], \} + +" Block tag, syntax by lang="..." or the first in config, and block group +" with css prefix for emmet-vim +function! Check() + call ExpectBlock('div.set', 'template', 'pug', 'pugTemplateBlock') + call ExpectBlock('', 'template', 'html', 'htmlTemplateBlock') + call ExpectBlock('export default', 'script', 'javascript', 'javascriptScriptBlock') + call ExpectBlock('import Vue', 'script', 'typescript', 'typescriptScriptBlock') + call ExpectBlock('# Assignment', 'script', 'coffee', 'coffeeScriptBlock') + call ExpectBlock('p {', 'style', 'css', 'cssStyleBlock') + call ExpectBlock('$a: 100px', 'style', 'scss', 'cssScssStyleBlock') + call ExpectBlock('$w: 128px', 'style', 'sass', 'sassStyleBlock') + call ExpectBlock('@list: 10 12', 'style', 'less', 'cssLessStyleBlock') + call ExpectBlock("@import 'vendor'", 'style', 'stylus', 'cssStylusStyleBlock') + call ExpectBlock('"requiresAuth"', 'route', 'json', 'jsonRouteBlock') + call ExpectBlock('# This is', 'docs', 'markdown', 'markdownDocsBlock') + call ExpectBlock('en:', 'i18n', 'yaml', 'yamlI18nBlock') + call ExpectBlock('"en"', 'i18n', 'json', 'jsonI18nBlock') + + " Syntax from a sync point, as after jumping to the end + silent edit! + normal! G + call search('"en"', 'bW') + call ExpectEqual(GetVueSyntax(), 'json', 'syntax at the end after reload') +endfunction diff --git a/test/cases/fold.vim b/test/cases/fold.vim index 2ba1f62..524725e 100644 --- a/test/cases/fold.vim +++ b/test/cases/fold.vim @@ -13,3 +13,4 @@ function! Check() call ExpectFoldlevel(lnum, levels[lnum - 1]) endfor endfunction +let g:test_flatten = 1 diff --git a/test/cases/indent.vim b/test/cases/indent.vim index a23b534..5caa8f8 100644 --- a/test/cases/indent.vim +++ b/test/cases/indent.vim @@ -7,3 +7,4 @@ let g:vim_vue_plugin_config = { \}, \'initial_indent': ['script', 'style', 'codepen-additional'], \} +let g:test_flatten = 1 diff --git a/test/cases/initial-indent.vim b/test/cases/initial-indent.vim new file mode 100644 index 0000000..4b50c63 --- /dev/null +++ b/test/cases/initial-indent.vim @@ -0,0 +1,10 @@ +" initial_indent as `syntax` and `tag.syntax` +let g:vim_vue_plugin_config = { + \'syntax': { + \ 'script': ['javascript'], + \ 'style': ['css', 'scss'], + \ 'i18n': ['json', 'yaml'], + \}, + \'initial_indent': ['scss', 'i18n.json'], + \} +let g:test_flatten = 1 diff --git a/test/cases/initial-indent.vue b/test/cases/initial-indent.vue new file mode 100644 index 0000000..0506fec --- /dev/null +++ b/test/cases/initial-indent.vue @@ -0,0 +1,28 @@ + + + + + + + + { + "en": { + "hello": "Hello" + } + } + + + +en: + hello: Hello + diff --git a/test/cases/keyword.vim b/test/cases/keyword.vim index 1300e7a..9c7b832 100644 --- a/test/cases/keyword.vim +++ b/test/cases/keyword.vim @@ -14,3 +14,4 @@ function! Check() call ExpectSyntax('computed', 'vueObjectKey') call ExpectSyntax('mounted', 'vueObjectFuncName') endfunction +let g:test_flatten = 1 diff --git a/test/cases/miniprogram.vim b/test/cases/miniprogram.vim new file mode 100644 index 0000000..f9398bf --- /dev/null +++ b/test/cases/miniprogram.vim @@ -0,0 +1,9 @@ +" .wpy for miniprogram, with initial indent for script and style by default +let g:test_flatten = 1 + +function! Check() + call ExpectSyntax('view', 'VueCustomTag') + call ExpectSyntax('wx:if', 'VueKey') + call ExpectSyntax('show', 'VueExpression') + call ExpectSyntax('text', 'VueCustomTag') +endfunction diff --git a/test/cases/miniprogram.wpy b/test/cases/miniprogram.wpy new file mode 100644 index 0000000..2ee8324 --- /dev/null +++ b/test/cases/miniprogram.wpy @@ -0,0 +1,21 @@ + + + + + diff --git a/test/cases/oneline.vim b/test/cases/oneline.vim index 7ac3f54..41c1192 100644 --- a/test/cases/oneline.vim +++ b/test/cases/oneline.vim @@ -20,3 +20,4 @@ function! CheckSync() \.string(SyntaxList())) endif endfunction +let g:test_flatten = 1 diff --git a/test/cases/random.vim b/test/cases/random.vim index 3df54f4..411eccc 100644 --- a/test/cases/random.vim +++ b/test/cases/random.vim @@ -8,3 +8,4 @@ let g:vim_vue_plugin_config = { \'keyword': 1, \'foldexpr': 1, \} +let g:test_flatten = 1 diff --git a/test/cases/script-setup.vim b/test/cases/script-setup.vim index cb8c7d9..40dc916 100644 --- a/test/cases/script-setup.vim +++ b/test/cases/script-setup.vim @@ -16,3 +16,4 @@ function! Check() call ExpectNoSyntax('value < 3', 'vue3Keyword') call ExpectSyntax('defineExpose', 'vue3Keyword') endfunction +let g:test_flatten = 1 diff --git a/test/cases/template.vim b/test/cases/template.vim index bcaceb8..432af00 100644 --- a/test/cases/template.vim +++ b/test/cases/template.vim @@ -16,3 +16,4 @@ function! Check() call ExpectNoSyntax('/docs', 'markdownDocsBlock') call ExpectSyntax('/docs', 'markdownDocsBlock') endfunction +let g:test_flatten = 1 diff --git a/test/cases/vue3.vim b/test/cases/vue3.vim index 533d2d4..7819758 100644 --- a/test/cases/vue3.vim +++ b/test/cases/vue3.vim @@ -13,3 +13,4 @@ function! Check() call ExpectSyntax('global', 'cssPseudoClassId') call ExpectSyntax('deep', 'cssPseudoClassId') endfunction +let g:test_flatten = 1 diff --git a/test/run.sh b/test/run.sh index 7c13272..a359a57 100755 --- a/test/run.sh +++ b/test/run.sh @@ -17,7 +17,7 @@ done if [ $# -gt 0 ]; then cases=$* else - cases=$(ls test/cases/*.vue | sed 's#.*/##; s#\.vue$##') + cases=$(ls test/cases/*.vue test/cases/*.wpy 2>/dev/null | sed 's#.*/##; s#\.[a-z]*$##') fi out=$(mktemp) diff --git a/test/run.vim b/test/run.vim index 01ab223..beaa711 100644 --- a/test/run.vim +++ b/test/run.vim @@ -1,9 +1,12 @@ " Run one test case, see test/run.sh " VUE_TEST_CASE=basic vim -N -u NONE -i NONE -S test/run.vim " -" A case is test/cases/.vue, with optional test/cases/.vim to set -" g:vim_vue_plugin_config and define Check() for more assertions. It fails if +" A case is test/cases/.vue (or .wpy), with optional +" test/cases/.vim to set g:vim_vue_plugin_config and define Check() for +" more assertions. It fails if " - indenting the whole file changes it +" - with g:test_flatten, indenting the file without any indent doesn't +" restore it " - Check() calls Fail() or an Expect*() function fails " - there are error messages " @@ -13,6 +16,7 @@ set nocompatible let s:root = expand(':p:h:h') let s:name = $VUE_TEST_CASE let s:case = s:root.'/test/cases/'.s:name +let s:file = filereadable(s:case.'.vue') ? s:case.'.vue' : s:case.'.wpy' let s:errors = [] " Plugin first, before Vim's placeholder vue syntax and indent files @@ -60,6 +64,26 @@ function! ExpectFoldlevel(lnum, level) endif endfunction +function! ExpectEqual(actual, expected, desc) + if a:actual !=# a:expected + call Fail(printf('%s should be %s, but got %s', + \ a:desc, string(a:expected), string(a:actual))) + endif +endfunction + +" Search pattern forward from cursor and check the block there by +" GetVueTag(), GetVueSyntax() and the block syntax group at the line end +function! ExpectBlock(pattern, tag, syntax, group) + if !search('\V'.a:pattern, 'W') + return Fail('not found: '.a:pattern) + endif + let desc = printf('%s at line %d: ', a:pattern, line('.')) + call ExpectEqual(GetVueTag(), a:tag, desc.'tag') + call ExpectEqual(GetVueSyntax(), a:syntax, desc.'syntax') + let group = synIDattr(synstack(line('.'), col('$') - 1)[0], 'name') + call ExpectEqual(group, a:group, desc.'block group') +endfunction + function! ExpectTag(lnum, tag) if GetVueTag(a:lnum) !=# a:tag call Fail(printf('tag at line %d should be %s, but got %s', @@ -74,22 +98,34 @@ filetype plugin indent on syntax on messages clear -execute 'silent edit '.fnameescape(s:case.'.vue') +execute 'silent edit '.fnameescape(s:file) redraw +function! s:ExpectLines(lines, desc) + let actual = getline(1, '$') + if actual == a:lines + return + endif + let i = 0 + while i < len(a:lines) && get(actual, i) ==# a:lines[i] + let i += 1 + endwhile + call Fail(printf('%s changed line %d: expected %s, but got %s', + \ a:desc, i + 1, string(get(a:lines, i, '')), string(get(actual, i, '')))) +endfunction + " Indent let s:lines = getline(1, '$') silent normal! gg=G -let s:indented = getline(1, '$') -if s:indented != s:lines - let s:lnum = 0 - while s:lnum < len(s:lines) && get(s:indented, s:lnum) ==# s:lines[s:lnum] - let s:lnum += 1 - endwhile - call Fail(printf('indent changed at line %d: expected %s, but got %s', - \ s:lnum + 1, string(get(s:lines, s:lnum, '')), - \ string(get(s:indented, s:lnum, '')))) - silent undo +call s:ExpectLines(s:lines, 'indent') +silent edit! + +" Indent without any indent +if get(g:, 'test_flatten', 0) + silent %s/^\s\+//e + silent normal! gg=G + call s:ExpectLines(s:lines, 'indent from flat') + silent edit! endif " Assertions