Files
Bridge-and-Join-s/internal/nsdxml/datetime_test.go
T
fontvielle 1d6ab86a57 feat(m2m): доменная модель сообщений + парсер windows-1251 + round-trip тесты
- internal/m2m/types.go: enum'ы и simple-типы из XSD НРД (M2MSchemas_260408)
- internal/m2m/validators.go: pattern-валидаторы ReferenceID/ISIN/INN/UUID/SecurityCode/IdentityDocSerial/AccountID + перечисления
- internal/m2m/messages.go: структуры 6 типов сообщений M2M, choice-типы через указатели, IsM2M=true автоматически в MarshalXML
- internal/nsdxml/datetime.go: тип NSDDateTime (формат "YYYY-MM-DDThh:mm:ss(МСК+N)")
- internal/nsdxml/codec.go: Marshal/Unmarshal XML в windows-1251 (собственный кодек CP1251, без внешних зависимостей)
- internal/m2m/messages_test.go: round-trip тесты на 6 примерах + 2 эталонах из DOC/

Покрытие: m2m 73.9%, nsdxml 92.5%. make ci зелёный.

Отклонение от спеки: вместо golang.org/x/text/encoding/charmap собственная
таблица CP1251 на ~60 строк, потому что прокси zetit блокирует
proxy.golang.org, goproxy.cn и redirect-хосты Go-модулей.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 00:30:46 +03:00

98 lines
2.5 KiB
Go

package nsdxml_test
import (
"encoding/xml"
"strings"
"testing"
"time"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdxml"
)
func TestNSDDateTimeParse(t *testing.T) {
cases := []struct {
in string
expectOffset int
expectSpecified bool
}{
{"2026-03-02T14:30:45(МСК)", 0, false},
{"2026-03-02T14:30:45(МСК+2)", 2, true},
{"2026-03-02T14:30:45(МСК-1)", -1, true},
{"2026-03-02T14:30:45(МСК+12)", 12, true},
}
for _, c := range cases {
c := c
t.Run(c.in, func(t *testing.T) {
var d nsdxml.NSDDateTime
if err := d.UnmarshalText([]byte(c.in)); err != nil {
t.Fatalf("UnmarshalText: %v", err)
}
if d.OffsetSpecified != c.expectSpecified {
t.Errorf("OffsetSpecified = %v, ожидалось %v", d.OffsetSpecified, c.expectSpecified)
}
if d.OffsetHours != c.expectOffset {
t.Errorf("OffsetHours = %d, ожидалось %d", d.OffsetHours, c.expectOffset)
}
out := d.String()
if out != c.in {
t.Errorf("String() = %q, ожидалось %q", out, c.in)
}
})
}
}
func TestNSDDateTimeNow(t *testing.T) {
d := nsdxml.Now()
if d.OffsetSpecified {
t.Errorf("Now() не должен задавать смещение")
}
if zone, _ := d.Time.Zone(); zone != "МСК" {
t.Errorf("Now() location зона = %q, ожидалось \"МСК\"", zone)
}
if time.Since(d.Time) > time.Minute {
t.Errorf("Now() вернул время, далёкое от текущего")
}
}
func TestNSDDateTimeXMLRoundTrip(t *testing.T) {
type wrap struct {
XMLName xml.Name `xml:"wrap"`
TS nsdxml.NSDDateTime `xml:"ts"`
}
src := `<wrap><ts>2026-03-02T14:30:45(МСК+2)</ts></wrap>`
var w wrap
if err := xml.Unmarshal([]byte(src), &w); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if w.TS.OffsetHours != 2 {
t.Errorf("OffsetHours = %d, ожидалось 2", w.TS.OffsetHours)
}
b, err := xml.Marshal(w)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if !strings.Contains(string(b), "2026-03-02T14:30:45(МСК+2)") {
t.Errorf("Marshal не сохранил формат: %s", b)
}
}
func TestNSDDateTimeParseErrors(t *testing.T) {
bad := []string{
"",
"2026-13-02T14:30:45(МСК)",
"2026-03-02 14:30:45(МСК)",
"2026-03-02T14:30:45",
"2026-03-02T14:30:45(MSK)",
"2026-03-02T14:30:45(МСК+200)",
}
for _, s := range bad {
s := s
t.Run(s, func(t *testing.T) {
var d nsdxml.NSDDateTime
if err := d.UnmarshalText([]byte(s)); err == nil {
t.Errorf("ожидалась ошибка для %q", s)
}
})
}
}