概要
一応北大ITサークル(HUIT)のアドカレ2023の13日目の記事です。
記事にするような大した話ではないです(当社比)
状況
- ローカル(Windows,VS2022)で開発したちょっとしたコード
- 単体テストまで書いて動作検証済み
- 動作したので Github に Push
- Github Actions でCI(単体テスト)を設定
- CIで
Too many characters in character literal
でコンパイルエラー発生
構成
- InputUtil(ソリューション)
- InputUtil(プロジェクト、本体)
- TestInputUtil(プロジェクト、xUnit単体テスト)
- InputUtilBenchmark(プロジェクト、パフォーマンス測定)
バージョンは .NET7 / C#11 。
結論
- 単体テストのコードだけ文字コードが Shift_JIS
- 日本語が文字化けして文字リテラルが2byteに収まらない
- テンプレートが Shift_JIS だった
経緯
オンラインジャッジ特有の標準入力をサクっと受け取るためのライブラリを書いていた。
ジャッジ用ということで、細かいケース含め単体テストを記述。
動作やパフォーマンスの検証が完了しリリースしようかなぁとリポジトリ作成作業をしていた時に事件発生。
ローカルでバリバリ動作してたコードで突然に「普通の」コンパイルエラー。
パッと思いついた原因候補はなし。
内容で検索かけても「JSのつもりで文字列リテラルをシングルクォーテーションで括ってたわ」程度しか見つけられず。
とはいえそういう「普通の」ミスではない、構文は合っているようにみえる。
CIの構成に問題があるのかと、CIに設定してるコマンドと同じコマンド ( dotnet build
とか dotnet test ...
) をローカルで実行すると普通に通る。
トータルで検討に1時間くらい溶かした。
で、最終的に「OS依存かなぁ」と疑って、WSL環境でcloneしてビルドしたところでエラー再現。
(WSLだったので)VSCodeで状況確認したところ日本語の文字化けを確認した。
エディタの文字コードをUTF8からShift-JISに変更すると解消したため、ここですべてを察してゲームクリア。
解説
Windows環境ではShift_JISでも自動的に正しく扱ってくれるようだが、CIを含めた今回のLinux環境でShift_JISをUTF-8と解釈してしまっていたようだ。
だがしかし、Shift_JISのソースコードをUTF-8として解釈しても、asciiな部分に関しては正しく読める。通常、ソースコードの大部分はasciiに収まるので大体正しく読める。
正しく読めない筆頭は日本語だが、日本語が出るのはコメントとか文字列くらい。
しかし、コメントも文字列も //
とか "
のようなasciiなトークンが正しく読めていれば(日本語が文字化けしていても)コンパイラ的には一応OK。
化け方の運もあるが、コメントは無視され、文字列リテラルも文字化けした文字列リテラルができるだけで済む可能性がそれなりに高い。
ただ、文字リテラルだけ中身が文字化けすることで(C#はUTF-16なので)2byteに収まらなくなりコンパイルエラー。ゆえにエラー内容は文字リテラルに文字が多すぎる、である。
文字以外はコンパイラ的には無事なので、ここだけピンポイントでエラーになっていた。
根本的になぜShift_JISになったか、という点だが、VS上で新規にファイルを作成する場合、何かのプロジェクトかアイテムのテンプレートを選択するのが一般的だと思うが、このテンプレート自体の文字コードに影響されたようだ。
コンソールアプリケーションのプロジェクトテンプレートで作成したライブラリ本体は(MS特有のBOMつきの)UTF-8になっていたが、xUnit単体テストのテンプレートで作成したテストコードだけShift_JISになってしまった。
その後だが、気づいてしまえば単純で、全部UTF-8に統一してあっさり解決した。めでたし。
感想
「文字リテラルだけ」「テストコードだけ」というのが結構ニッチできつかった。
いい加減Shift_JISは滅んでもいい気がする。