добавлен словарь категориальных значений HAE → коды HealthKit
- фазы сна, контекст пульса и имена тренировок попадают в реестр `category_value` (миграция 00010): строка хранится дословно, выведенный код лежит рядом отдельной записью, а не полем внутри точки - словарь и синонимы кодов живут в бинаре (`internal/healthkit`); локаль из `Accept-Language` сужает поиск, но в ключ реестра не входит — заголовков в сыром архиве нет - наблюдение входит в отпечаток витрины, выведенный код — нет: он производная от словаря, а не от журнала
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package healthkit
|
||||
|
||||
import "testing"
|
||||
|
||||
// Плоскость таблицы синонимов — то, чем оправдано отсутствие обхода цепочек в
|
||||
// рантайме. Проверять её обязательно ИЗНУТРИ пакета и по самой карте: внешний
|
||||
// тест умеет обойти только записи, достижимые из словаря, а запись, до которой
|
||||
// словарь не дотягивается, под утверждение не попадёт вовсе — при этом
|
||||
// `Canonical` вернёт промежуточный код, и в реестре осядет имя, которого в
|
||||
// экспорте Apple нет. Проверено воспроизведением: с неплоской таблицей внешний
|
||||
// тест остаётся зелёным.
|
||||
func TestSynonymsЗначениеНеЯвляетсяКлючом(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for from, to := range synonyms {
|
||||
if _, ok := synonyms[to]; ok {
|
||||
t.Errorf("синоним %q → %q, но %q сам является ключом таблицы: цепочка длиннее одного шага, "+
|
||||
"а разрешения цепочек в рантайме нет намеренно", from, to, to)
|
||||
}
|
||||
if from == to {
|
||||
t.Errorf("синоним %q указывает на самого себя", from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Словарь обязан быть однозначен по строке независимо от локали, и это не
|
||||
// вкусовщина, а условие корректности второго разряда `Code`.
|
||||
//
|
||||
// Ключ реестра локали не содержит, а `mergeCategories` переписывает `code`
|
||||
// безусловно. Пока строка даёт один код во всех локалях, три решения
|
||||
// согласованы. Первая же строка, означающая в двух локалях разное, обнуляет
|
||||
// `byValue` — и тогда код строки становится функцией того, у какой доставки
|
||||
// уцелел `Accept-Language`, то есть какая свернулась последней, а не последней
|
||||
// по журналу. Отпечаток этого не покажет: код в него не входит намеренно.
|
||||
// Оракула у такого расхождения нет вовсе — поэтому страж стоит здесь.
|
||||
func TestDictionaryСтрокаОднозначнаПоВсемЛокалям(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
codes := make(map[string]string)
|
||||
locales := make(map[string]string)
|
||||
for locale, values := range dictionary {
|
||||
for value, code := range values {
|
||||
code = Canonical(code)
|
||||
if prev, seen := codes[value]; seen && prev != code {
|
||||
t.Errorf("строка %q означает %q в локали %q и %q в локали %q: "+
|
||||
"код станет функцией порядка свёртки, а не журнала",
|
||||
value, prev, locales[value], code, locale)
|
||||
continue
|
||||
}
|
||||
codes[value] = code
|
||||
locales[value] = locale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Словарь не должен молча раздваивать код: два разных ключа с одним кодом
|
||||
// законны (синонимы перевода), а вот пустой код в словаре — нет. Пустота
|
||||
// означает «не знаем», и записывать её явно значит выдать незнание за знание.
|
||||
func TestDictionaryПустыхКодовНет(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for locale, values := range dictionary {
|
||||
for value, code := range values {
|
||||
if code == "" {
|
||||
t.Errorf("словарь локали %q сопоставляет %q пустому коду", locale, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user