a wandering wolf

Does a wandering wolf dreams of a wondering, sometimes programming sheep?

このエントリーをはてなブックマークに追加

自前で assertSeqEquals を定義する

まえがき

全世界1,600(万…ではない)人の Persimmon ユーザの皆さん、こんばんは。

Persimmon 2.0に向けた開発が(僕以外の人で)進められています。そこにおそらく入るであろう機能に、 assertSeqEquals があります。何故これが必要かというと、今の Persimmon は seq<'T> 型の値同士をアサートすると上手くいかないという問題があります。seq<'T> 型の値を使うことは少なくないので、アサートできて欲しいです。

seq同士を比較したい · Issue #73 · persimmon-projects/Persimmon

assertSeqEquals が導入されるのを待つという選択肢もありますが、私はよくこの issue にぶち当たってしまうので、出来れば今すぐ解決したい。その場合はというと、自前で assertSeqEquals を実装する、という手段をとることになります。

サンプル実装

前置きが長くなりましたが、以下が私の書いた assertSeqEquals です。備忘録として残しておきます。

let assertSeqEquals (expected: seq<'T>) (actual: seq<'T>) =
    let eLen = Seq.length expected
    let aLen = Seq.length actual
    let violated message = AssertionResult.NotPassed(NotPassedCause.Violated message)
    if eLen <> aLen
    then violated <| sprintf "%A ≠ %A\nExpect: length is %d\nActual: length is %d" expected actual eLen aLen
    else
        let result =
            (expected, actual)
            ||> Seq.zip
            |> Seq.map (fun (e, a) -> (e, a, e <> a))
            |> Seq.tryFind (fun (_, _, b) -> b)
        match result with
        | Some (e, a, _) ->
            violated <| sprintf "%A ≠ %A\nExpect: %A\nActual: %A" expected actual e a
        | None           -> AssertionResult.Passed()

あまり良い実装ではないですが、それでも私のやりたいことには十分です。どうせ無限シーケンスを渡されたらどうしようもないので、そこはノーガードで迎え撃ちましょう(ぉぃ

あとがき

早く Persimmon 2.0 来ないかなぁ!

追記(2016/04/07 20:40)

こういう意見をいただいたので、Gist に上げてみました。

Persimmon の暫定的な assertSeqEquals を書いてみた - Gist

追記(2016/04/08 11:50)

@bleis さんに、もっとイケてるコードにしてもらいました!

Persimmon の暫定的な assertSeqEquals を書いてみた - Gist (bleisさんver.)