claim tests: band order, coverage, the Rome case (V-565)
TestCoverageBeatsBand is the V-558 failure as an ordering assertion. The weather claim explains the whole utterance and the pending reminder explains one token of it, so coverage settles it before the band is consulted. TestBandOrder asserts the order rather than trusting the iota, and pins BandUnknown at the bottom: a builder that forgot to set a band is a bug and must not outrank a measured claim.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package claim
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTokensStripsPunctuationAndCase(t *testing.T) {
|
||||
got := Tokens("Какая сейчас погода в Риме?")
|
||||
want := []string{"какая", "сейчас", "погода", "в", "риме"}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Tokens = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// The dash forms matter: an STT transcript routinely carries "а, да, прости -
|
||||
// на 9", and a stray dash counted as a token would dilute every coverage score
|
||||
// in the sentence.
|
||||
func TestTokensDropsBareDashes(t *testing.T) {
|
||||
got := Tokens("а, да, прости — на 9")
|
||||
want := []string{"а", "да", "прости", "на", "9"}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Tokens = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitPartitionsInOrder(t *testing.T) {
|
||||
consumed, unexplained := Split("напомни позвонить маме", "позвонить маме")
|
||||
if want := []string{"позвонить", "маме"}; !reflect.DeepEqual(consumed, want) {
|
||||
t.Errorf("consumed = %q, want %q", consumed, want)
|
||||
}
|
||||
if want := []string{"напомни"}; !reflect.DeepEqual(unexplained, want) {
|
||||
t.Errorf("unexplained = %q, want %q", unexplained, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoverageIsZeroWithoutTokens(t *testing.T) {
|
||||
if got := (Claim{}).Coverage(); got != 0 {
|
||||
t.Errorf("Coverage of an empty claim = %v, want 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoverageFraction(t *testing.T) {
|
||||
c := Claim{Consumed: []string{"a", "b", "c"}, Unexplained: []string{"d"}}
|
||||
if got := c.Coverage(); got != 0.75 {
|
||||
t.Errorf("Coverage = %v, want 0.75", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The band order is load-bearing, so it is asserted rather than assumed from
|
||||
// the iota. BandUnknown must sit at the bottom: a claim whose builder forgot to
|
||||
// set a band is a bug and must not outrank a measured one.
|
||||
func TestBandOrder(t *testing.T) {
|
||||
ordered := []Band{BandUnknown, BandVetoed, BandNearest, BandStructural, BandAnchored}
|
||||
for i := 1; i < len(ordered); i++ {
|
||||
if !(ordered[i-1] < ordered[i]) {
|
||||
t.Errorf("%v is not below %v", ordered[i-1], ordered[i])
|
||||
}
|
||||
}
|
||||
for _, b := range ordered {
|
||||
if b.String() == "" {
|
||||
t.Errorf("band %d has no name", b)
|
||||
}
|
||||
}
|
||||
if BandUnknown.String() != "unknown" {
|
||||
t.Errorf("BandUnknown.String() = %q", BandUnknown.String())
|
||||
}
|
||||
}
|
||||
|
||||
// The failure V-558 opened with, as an ordering test. A pending reminder eats
|
||||
// "какая сейчас погода в Риме?" as a time answer and explains none of it; the
|
||||
// weather source explains all of it. Coverage decides, and the band never gets
|
||||
// consulted, which is the point: the pending claimant is structural and the
|
||||
// weather claim is anchored, but even if the bands were equal the weather claim
|
||||
// wins.
|
||||
func TestCoverageBeatsBand(t *testing.T) {
|
||||
utterance := "какая сейчас погода в Риме?"
|
||||
pendingConsumed, pendingRest := Split(utterance, "сейчас")
|
||||
pending := Claim{
|
||||
Claimant: "reminder-followup", Intent: "reminder",
|
||||
Consumed: pendingConsumed, Unexplained: pendingRest,
|
||||
Band: BandStructural,
|
||||
}
|
||||
weatherConsumed, weatherRest := Split(utterance, utterance)
|
||||
weather := Claim{
|
||||
Claimant: "weather", Intent: "query",
|
||||
Consumed: weatherConsumed, Unexplained: weatherRest,
|
||||
Band: BandNearest,
|
||||
}
|
||||
if !weather.MoreSpecificThan(pending) {
|
||||
t.Errorf("weather (%v cover) did not beat pending (%v cover)",
|
||||
weather.Coverage(), pending.Coverage())
|
||||
}
|
||||
if pending.MoreSpecificThan(weather) {
|
||||
t.Error("pending beat weather, so the ordering is not asymmetric")
|
||||
}
|
||||
}
|
||||
|
||||
// Where coverage ties, the band decides. Two grammars claiming the same
|
||||
// utterance is the stage-0 contention case (ru-query-019 on the fixture), and
|
||||
// today list order settles it with nothing recorded.
|
||||
func TestBandBreaksACoverageTie(t *testing.T) {
|
||||
anchored := Claim{Claimant: "calendar-query", Consumed: []string{"a"}, Band: BandAnchored}
|
||||
nearest := Claim{Claimant: "classifier", Consumed: []string{"a"}, Band: BandNearest}
|
||||
if !anchored.MoreSpecificThan(nearest) {
|
||||
t.Error("anchored did not beat nearest on equal coverage")
|
||||
}
|
||||
if nearest.MoreSpecificThan(anchored) {
|
||||
t.Error("nearest beat anchored on equal coverage")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVetoed(t *testing.T) {
|
||||
if (Claim{}).Vetoed() {
|
||||
t.Error("a claim with no veto reports itself vetoed")
|
||||
}
|
||||
if !(Claim{Veto: "fact with no key"}).Vetoed() {
|
||||
t.Error("a claim with a veto reason does not report itself vetoed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user