1d6ab86a57
- 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>
98 lines
2.5 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|