Files
healthlog/internal/hae/value_test.go
T
av d79189be18 docs: документация переведена на канон av-dev-pm
- беклог и план переехали в docs/tasks (38 задач, 11 целей), слаги
  переименованы с транслита на английские, 85 ссылок поправлены
- conventions.md разобран в docs/conventions/, local-research.md — в
  docs/research/, review-journal.md — в docs/review.md с разделом настройки
  конвейера; заведены security.md, adr/ и .pm.json
- шаг docs.py check добавлен в task gate; поведение в architecture.md помечено
  девятью маркерами долга, database.md получил настройки с числовым значением
2026-08-03 17:14:53 +03:00

97 lines
3.2 KiB
Go

package hae_test
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"git.vakhrushev.me/av/healthlog/internal/hae"
)
func TestPointValueФормыТочки(t *testing.T) {
t.Parallel()
cases := []struct {
name string
raw string
want float64
ok bool
}{
{"обычная точка", `{"qty":72.5,"date":"2026-07-31 12:00:00 +0300"}`, 72.5, true},
{"пульс без qty", `{"Min":60,"Avg":70.25,"Max":80}`, 70.25, true},
{"qty впереди Avg", `{"qty":1,"Avg":9}`, 1, true},
{"ноль — значение", `{"qty":0}`, 0, true},
{"отрицательное значение", `{"qty":-1.5}`, -1.5, true},
{"нет числовых полей", `{"date":"…","source":"часы"}`, 0, false},
{"qty равен null", `{"qty":null,"Avg":3}`, 3, true},
{"qty строкой", `{"qty":"72.5"}`, 0, false},
{"qty объектом", `{"qty":{"value":1}}`, 0, false},
{"переполнение float64", `{"qty":1e400}`, 0, false},
{"точка не объект", `[1,2,3]`, 0, false},
{"пустой объект", `{}`, 0, false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
t.Parallel()
got, ok := hae.PointValue(json.RawMessage(c.raw))
if ok != c.ok {
t.Fatalf("наличие значения: получили %v, ждали %v", ok, c.ok)
}
if ok && got != c.want {
t.Errorf("значение: получили %v, ждали %v", got, c.want)
}
})
}
}
// Формы точки берутся из реальных пакетов: документация формата тонкая и
// местами расходится с тем, что приложение шлёт (docs/research/apple-health.md).
func TestPointValueНаРеальныхПакетах(t *testing.T) {
t.Parallel()
for _, name := range []string{"minute.json", "hour.json", "raw.json"} {
t.Run(name, func(t *testing.T) {
t.Parallel()
body, err := os.ReadFile(filepath.Join("testdata", name))
if err != nil {
t.Fatalf("фикстура: %v", err)
}
var doc struct {
Data struct {
Metrics []struct {
Name string `json:"name"`
Data []json.RawMessage `json:"data"`
} `json:"metrics"`
} `json:"data"`
}
if err := json.Unmarshal(body, &doc); err != nil {
t.Fatalf("разбор фикстуры: %v", err)
}
total, valued := 0, 0
for _, m := range doc.Data.Metrics {
for _, raw := range m.Data {
total++
if _, ok := hae.PointValue(raw); ok {
valued++
}
}
}
if total == 0 {
t.Fatal("в фикстуре нет точек — проверять нечего")
}
// Утверждается свойство, а не число: корпус фикстур пополняется, и
// константа протухла бы молча. Значение несёт подавляющее
// большинство точек — если вдруг перестанет, это видно сразу.
if valued*2 < total {
t.Errorf("значение прочиталось лишь у %d точек из %d", valued, total)
}
t.Logf("точек %d, со значением %d", total, valued)
})
}
}