vim9scriptで書いた.vimrcのテストをvim9scriptで書いてGithub Actionsでpush時に実行するようにした話

2023/03/31に公開

初めに

vim9scriptで書いた.vimrcのテストをvim9scriptで書いてGithub ActionsでPush時にテストするようにしてみました

もともとvim標準のassertを使って「vim9scriptで書いた.vimrcのテストをvim9scriptで書いて」はやっていたのですが
某読書会で「自動でテストしないの?」「vim-themis良いよー」と教えていただいたのでやってみました
この場をかりて読書会の皆様に感謝を🙏

テストを書く

というわけでテストをvim-themisで書き直します
themis#helper('expect')は関数への参照なので先頭大文字の変数に代入しないといけないのがポイントです

だいたいこんな感じです
(全部書くと長いので全てを読みたい奇特な方は記事最後記載のリポジトリを参照ください)

vim9script

var suite = themis#suite('Test for .vimrc')
const assert = themis#helper('assert')
const Expect = themis#helper('expect')

source expand('~/.vimrc')

suite.Foo = () => {
    assert.equals('foo', 'foo')
    Expect('bar').to_be('bar')
}

結果は省略
themisの出力、見やすくてよいですね

.vimrc内のスクリプトローカルな関数をテストしたい

SIDをscriptnamesで取得できるのでそれを利用します
(vital.vimにもあったような?)

# スクリプトローカルな関数をテストするためにSIDを確保しておく
var scriptnames_output = ''
redir => scriptnames_output
silent scriptnames
redir END
const vimrc_sid = scriptnames_output
  ->split("\n")
  ->filter((i, v) => v =~# '/\.vimrc$')[0]
  ->matchstr('\d\+')

suite.Bar = () => {
    const F = function($'<SNR>{vimrc_sid}_BUZ')
    assert.equals(F('buz'), 'hello sid!')
}

Github Actionに登録する

こちらを参考に作成します

ただしデフォルトでインストールされるvimは古いのでvim9scriptが動きません
sudo add-apt-repository ppa:jonathonf/vimで取得先を変更するようにしました(参考)

出来上がったSimple Workflowの設定がこちら

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "master" branch
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
    # タイムアウト(デフォルトだと6時間なので長すぎる…)
    timeout-minutes: 15

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # .vimrcをチェックアウトする
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3

      # vimとgitとプラグインをインストールする
      - name: Initialize
        run: |
          sudo apt-get update
          sudo add-apt-repository ppa:jonathonf/vim
          sudo apt-get install -y vim git
          ln -s $GITHUB_WORKSPACE/.vimrc ~/.vimrc
          # vim-jetpackでインストールしたプラグインが入った状態でテストしたいので
          # JetpackSyncを実行しておく → ここに罠が!(後述)
          vim -c JetpackSync -c qa!

      # テストを実行する
      - name: Run tests
        run: |
          cd $GITHUB_WORKSPACE/test
          # themisのインストール先は環境に合わせてください
          ~/.vim/pack/jetpack/opt/vim-themis/bin/themis vimrc.test.vim

これでいいと思ってましたが…

軽く書いたテストが通ったので、ヨシ!と思ってたのですが
プラグインが有効になっていませんでした。 (themisのvim起動オプションに-u NONEってありますし)
また、テストコード内でsource .vimrcをしているので.vimrcにかかれたVimEnterイベントが動きません
.vimrc内のVimEnterをテストしやすいように関数に修正することはできますがプラグインの方は手をつけられません
そもそも今回の目的はthemisとはちょっと合わなかったようです(認識間違っていたらすみません💦)

なのでテストコードに簡単なテストフレームワークを書きました
ここまできたらvim標準のassertを使ってもいいかと思いましたがせっかくなのでthemisと同じ形で実装しました
テストに失敗したらcqで抜ける形にすればGithub Actionsにエラーを伝えられるようです
ついでにテストコードを開いて:so %で実行できるようにしておきました

# Github Actionsで以下の通り実行する
# cd $GITHUB_WORKSPACE/test
# vim -c vimrc.test.vim

# `:source %`で実行した場合は終了させない
var is_manually_run = expand('%:t') ==# 'vimrc.test.vim'
var suite = {}
var assert = {}
var is_faild = false

def! g:RunTests()
  is_faild = false
  for s in suite->keys()
    echom s
    suite[s]()
  endfor
  echom is_faild ? 'Tests faild.' : 'Tests success.'
  if !is_manually_run
    execute is_faild ? 'cq!' : 'q!'
  endif
enddef

assert.equals = (act: any, exp: any, msg: string = 'assert.equals') => {
  if act !=# exp
    is_faild = true
    echom $'  {msg}'
    echom $'    act: {act}'
    echom $'    exp: {exp}'
  endif
}

assert.falsy = (act: any, msg: string = 'assert.falsy') => {
  assert.equals(act, false, msg)
}

suite.Foo = () => {
    assert.equals('foo', 'foo')
    Expect('bar').to_be('bar')
}

call g:RunTests()

Simple Workflowの設定も最後だけ直しておきます

      - name: Run tests
        run: |
          cd $GITHUB_WORKSPACE/test
          vim -S vimrc.test.vim

テストが通ったのでヨシ!

終わりに

後半はともかく、前半はvim9script + vim-themis + Github Actionsの参考になれば嬉しいです
全ソースはこちらにあります
https://github.com/utubo/dotfiles

GitHubで編集を提案

Discussion