単体テストのコードカバレッジのレポートを生成する

Visual Studio Enterprise エディションのコードカバレッジの機能を使わずとも、Coverlet を使えば単体テストのコードカバレッジを収集できるし、ReportGenerator を使えば HTML レポートを生成できる。

docs.microsoft.com

PowerShellスクリプトを書いて、コードカバレッジの収集とレポートの生成を自動化してみた。

$dirs = Get-ChildItem -Path . -Recurse -Filter *TestResults*
foreach ($dir in $dirs)
{
    Remove-Item -Path $dir.FullName -Recurse -Force
}

dotnet test --collect:"XPlat Code Coverage"

$files = Get-ChildItem -Path . -Recurse -Filter *coverage.cobertura.xml
foreach ($file in $files)
{
    $reports = ("-reports:" + $file.FullName)
    $targetdir = ("-targetdir:" + $file.Directory.FullName + "\html")
    reportgenerator $reports  $targetdir -reporttypes:HTML
}

服を着るならこんなふうに(8)

Kindle で半額近くなっていたので購入した。8巻のテーマはデザイナーブランド。だけど、自分は服に何万もかけられないなぁ。読んでて違う世界の話のように感じた。長く着る予定3万弱のダウンジャケットを、セール価格18000円くらいで買うのがせいぜい。それでも奮発したほうだ。

ただ、ユニクロU推しは同意。ユニクロUだけでなく、有名なデザイナーやブランドのコラボは、良質なデザインのアイテムが手の届く金額で発売されるから、毎回楽しみにしている。最近はtheoryと良くコラボしてるな。夏用にポロシャツとか欲しいかも。

.NET のクラスライブラリ設計 改訂新版

「.NET のクラスライブラリ設計」が 12 年ぶりに大改訂された。本書は、.NET の BCL 開発チーム直伝、BCL のようなクラスライブラリを設計する際のガイダンス集だ。

自分の場合、仕事ではアプリケーションよりも、内製フレームワークやクラスライブラリを開発することが多かった。それらは C# 向けなので、API は BCL に似た設計にし、あたかも BCL で提供されているかのように使えることを目指してきた。参考にできそうな API が BCL に無い場合は、.NET Foundation 傘下にある OSS を研究したりも。

クラスライブラリを新規に作成するときは、まずエディタを開いて、どんな感じで使用するかサンプルコードを書きながら、API を練ることが多い。巷では README 駆動開発なんて呼ばれる手法に近い。本書の中に出てきた「フレームワークの設計原則」も同じだ。

フレームワークは、使い方のシナリオのセットと、それらのシナリオを実装するコードサンプルから設計を始めなければならない。

自分がそうやって調べたり、試行錯誤して身につけてきた内容が、既に本書にまとまっている。まさに .NET クラスライブラリ開発者のバイブル。

本書のガイダンスは BCL が基準なので、だいぶ保守的。中には同意しかねるものもちらほら。自分は var 使いまくるなぁ。あと、非同期関連で IValueTaskSource に触れてなかったりするので、最新に完全に追いついたガイダンスというわけでもない。次の改訂で追加されるだろうか。C# は毎年進化しているので、次の改訂が 10 年とかだったら、ガイダンスはまた大きく様変わりしてそうだ。

デスクトップアプリで OAuth 2.0 のAuthorization Code Flow に対応する冴えたやりかた

アプリが Web API を呼び出すためのアクセストークンを取得するとき、OAuth 2.0 の Authorization Code Flow に対応することになると思う。

Web アプリなら、普通にリダイレクト先を用意すればいい。モバイルアプリでも、Custom URL Scheme によってアプリを起動できるので、それで認証コードを取り出せる。

問題はデスクトップアプリ。それもWinForms や WPF。一応、WebView を使い、ナビゲーションイベントを捕まえて認証コードを取り出す方法はある。ただ、ログインは内部ブラウザでは無く、外部ブラウザを使いたい。

あと、コンソールアプリも同様。リダイレクト先を http://localhost/ とかにしておいて、ブラウザのアドレスバーに表示される URL から認証コードを取り出す方法で、お茶を濁していた。

そんな中、Google の OAuth サンプルで、HttpListener を使ってリダイレクトを待ち受け、認証コードを取り出す方法を知った。何それ賢い。

github.com

GitHubAPI でやってみた。

using System.Diagnostics;
using System.Net;
using System.Text;
using Octokit;

const string ClientId = "<Your Client ID>";
const string ClientSecret = "<Your Client Secret>";
const string RedirectUri = "http://localhost:8081/";

var github = new GitHubClient(new ProductHeaderValue("OAuthSample"));

// リダイレクトで認証コードを受け取るために、
// HttpListener を使って待ち受ける。
var http = new HttpListener();
http.Prefixes.Add(RedirectUri);
Console.WriteLine("Listening..");
http.Start();

// GitHub のログインページを表示。
var loginUrl = github.Oauth.GetGitHubLoginUrl(
    new OauthLoginRequest(ClientId)
    {
        RedirectUri = new Uri(RedirectUri),
        State = Guid.NewGuid().ToString("N"),
        Scopes =
        {
            "repo",
        },
    });
var escapedUrl = loginUrl.ToString().Replace("&", "^&");
Process.Start(new ProcessStartInfo("cmd", $"/c start {escapedUrl}")
{
    CreateNoWindow = true,
});

// OAuth 認証のレスポンスを返すために待機
var context = await http.GetContextAsync();

// ブラウザに HTTP レスポンスを送る
var response = context.Response;
var responseString = "<html><body>Please return to the app.</body></html>";
var buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
var responseOutput = response.OutputStream;
await responseOutput.WriteAsync(buffer, 0, buffer.Length);
responseOutput.Close();
http.Stop();

// 認証コードを使ってアクセストークンを取得
var code = context.Request.QueryString.Get("code");
var oauthToken = await github.Oauth.CreateAccessToken(
    new OauthTokenRequest(
        ClientId,
        ClientSecret,
        code));

// アクセストークンを設定して、GitHub の API を呼び出す
github.Credentials = new Credentials(oauthToken.AccessToken);
var repositories = await github.Repository.GetAllForCurrent();
foreach (var repository in repositories)
{
    Console.WriteLine(repository.FullName);
}

Azure CLI なんかも、ソースコードを見たら az login では HTTP で待ち受けてるっぽかった。自分が知らなかっただけで、実はデファクトスタンダードだったりするんだろうか。

魁龍 博多本店

ららぽーと福岡に行ったついでに、ついでと言うにはだいぶ距離があったが、「魁龍博多本店」に行ってきた。運動がてら、ららぽーと福岡から歩いてみたけど、30分くらい歩いただろうか。途中、歩くと決断したことを後悔した。バスかチャリチャリ使えばよかった。福岡空港国際線ターミナルに近いからねぇ。

チャーハンは無かったので、ラーメンとおにぎりと餃子のセットを注文。麺の硬さは、店長さんがやたら「ずんだれ」、つまりは柔をプッシュしてきて、その圧に負け「ずんだれ」を選択した。その「ずんだれ」は、確かに麺の旨味を感じられた気がする。スープは醤油だれ強めで、どろり濃厚、かつ甘さもあり、ずんだれの麺に良くマッチする。このスープには、ずんだれは合うな。オススメするだけある。他店には真似できなさそう。

おにぎりは塩味ついてなかった。濃いスープのお供としては、これも一つの正解か。卓上に置いてある「魁獣みそ」という辛味噌をのせて食べると、旨辛さで箸が一気に進んだ。この味噌前提の白おにぎりだったのかもな。

餃子は安定の旨さ。ラーメン屋の餃子がハズレだった記憶は今のところ無い。安心して注文できる。この店も多分に漏れず。5個と個数も丁度いい。もちろん、もっと数が多くても大丈夫だけど。

ずっと行きたいと思っていたのに、駅から離れている立地のためなかなか行けずにいたので、念願叶った。味は期待通り。ただ、空いている時間に行ったからか、店長がやたら客に話しかけてくる。そういうスタイルなんだろうか。コロナ禍ではちょっと勘弁してほしい。それだけが気になった。

魁龍博多本店
〒816-0092 福岡県福岡市博多区東那珂2-4-31
800円(平均)800円(ランチ平均)
r.gnavi.co.jp

ららぽーと福岡

4月25日にグランドオープンしたばかりの「ららぽーと福岡」に行ってきた。博多駅鹿児島本線下りに乗車して、隣の竹下駅で降車。竹下駅からは10分くらい歩いた。思っていた以上に離れていたな。子どもを連れてくるときは、大橋から直行バスに乗ったほうが良さそうだ。

奥に見えるキッザニアはまだオープンしていない。7月31日オープン予定。GW期間中だったので、予想通り、かなりの人手だった。特にフードコートは人混みを避けて歩くのも一苦労。九州初出店の「洋食や三代目たいめいけん」「日本橋 天丼 金子半之助」あたりが気になった。「宍道湖しじみ中華蕎麦 琥珀」も凄いらしい。どこもかなりの行列で、席を確保するのも一苦労そう。今回は一人だったので、フードコートでの食事は断念。って、飲食店ばっかりだな。

実物大「νガンダム」もちゃんと見てきた。ガンダムを履修していたのは、小学生高学年になる前までだった気がする。初代からGガンダムまで。それ以降は、長らく履修していない。逆襲のシャアは見た記憶がある。詳細はもう忘れてしまっていたが、それでも実物大νガンダムには魂震えた。伊達じゃなかった。

次回ららぽーと福岡に行くとしたら、キッザニアがオープンしてからだろうな。そのときは、たいめいけんか金子半之助にありつきたいところだ。

クロノスタシス


www.youtube.com

BUMP OF CHICKEN の新曲「クロノスタシス」が iTunes Store で配信されていたので購入。「名探偵コナン ハロウィンの花嫁」の主題歌らしい。

この曲は、おそらく「降谷零」を表現したものだろうな。散りばめられたフレーズがどれも彼を想起させる。赤井やコナンといった、作中の他のキャラクターにも当てはまる部分があり、まるでタイアップした映画の全てを詰め込んだようにも思えるところが、この曲の凄いところ。

潜入捜査で同僚を失った過去に囚われている悲しさを唄っているのかと、初めて聴いたときは思った。秒針の止まった記憶とか、時計にも消せなかった、とかまさに。聴き返しているうちに、優しさとか決意とか、いろんな感情が織り込まれているような気がしてきた。繰り返し、聴けば聴くほど味わい深い。ホント、凄い曲だ。

クロノスタシス

クロノスタシス