Skip to content

Commit

Permalink
Merge pull request hooklift#195 from moihn/xsd-date-and-time-support
Browse files Browse the repository at this point in the history
Add xsd date and time support
  • Loading branch information
c4milo authored Feb 28, 2021
2 parents 12cf455 + 1ee9cf8 commit dac628d
Show file tree
Hide file tree
Showing 5 changed files with 578 additions and 15 deletions.
16 changes: 8 additions & 8 deletions fixtures/epcis/epcisquery.src
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Document struct {
// The date the message was created. Used for auditing and logging.
//

CreationDate time.Time `xml:"creationDate,attr,omitempty" json:"creationDate,omitempty"`
CreationDate soap.XsdDateTime `xml:"creationDate,attr,omitempty" json:"creationDate,omitempty"`
}

type EPC string
Expand All @@ -49,7 +49,7 @@ type DocumentIdentification struct {

MultipleType bool `xml:"MultipleType,omitempty" json:"MultipleType,omitempty"`

CreationDateAndTime time.Time `xml:"CreationDateAndTime,omitempty" json:"CreationDateAndTime,omitempty"`
CreationDateAndTime soap.XsdDateTime `xml:"CreationDateAndTime,omitempty" json:"CreationDateAndTime,omitempty"`
}

type Partner struct {
Expand Down Expand Up @@ -118,11 +118,11 @@ type Scope struct {
}

type CorrelationInformation struct {
RequestingDocumentCreationDateTime time.Time `xml:"RequestingDocumentCreationDateTime,omitempty" json:"RequestingDocumentCreationDateTime,omitempty"`
RequestingDocumentCreationDateTime soap.XsdDateTime `xml:"RequestingDocumentCreationDateTime,omitempty" json:"RequestingDocumentCreationDateTime,omitempty"`

RequestingDocumentInstanceIdentifier string `xml:"RequestingDocumentInstanceIdentifier,omitempty" json:"RequestingDocumentInstanceIdentifier,omitempty"`

ExpectedResponseDateTime time.Time `xml:"ExpectedResponseDateTime,omitempty" json:"ExpectedResponseDateTime,omitempty"`
ExpectedResponseDateTime soap.XsdDateTime `xml:"ExpectedResponseDateTime,omitempty" json:"ExpectedResponseDateTime,omitempty"`
}

type BusinessService struct {
Expand Down Expand Up @@ -414,7 +414,7 @@ type CorrectiveEventIDsType struct {
}

type ErrorDeclarationType struct {
DeclarationTime time.Time `xml:"declarationTime,omitempty" json:"declarationTime,omitempty"`
DeclarationTime soap.XsdDateTime `xml:"declarationTime,omitempty" json:"declarationTime,omitempty"`

Reason *ErrorReasonIDType `xml:"reason,omitempty" json:"reason,omitempty"`

Expand All @@ -430,9 +430,9 @@ type ErrorDeclarationExtensionType struct {
}

type EPCISEventType struct {
EventTime time.Time `xml:"eventTime,omitempty" json:"eventTime,omitempty"`
EventTime soap.XsdDateTime `xml:"eventTime,omitempty" json:"eventTime,omitempty"`

RecordTime time.Time `xml:"recordTime,omitempty" json:"recordTime,omitempty"`
RecordTime soap.XsdDateTime `xml:"recordTime,omitempty" json:"recordTime,omitempty"`

EventTimeZoneOffset string `xml:"eventTimeZoneOffset,omitempty" json:"eventTimeZoneOffset,omitempty"`

Expand Down Expand Up @@ -764,7 +764,7 @@ type SubscriptionControls struct {

Trigger AnyURI `xml:"trigger,omitempty" json:"trigger,omitempty"`

InitialRecordTime time.Time `xml:"initialRecordTime,omitempty" json:"initialRecordTime,omitempty"`
InitialRecordTime soap.XsdDateTime `xml:"initialRecordTime,omitempty" json:"initialRecordTime,omitempty"`

ReportIfEmpty bool `xml:"reportIfEmpty,omitempty" json:"reportIfEmpty,omitempty"`

Expand Down
6 changes: 3 additions & 3 deletions gowsdl.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,9 @@ var xsd2GoTypes = map[string]string{
"byte": "int8",
"long": "int64",
"boolean": "bool",
"datetime": "time.Time",
"date": "time.Time",
"time": "time.Time",
"datetime": "soap.XsdDateTime",
"date": "soap.XsdDate",
"time": "soap.XsdTime",
"base64binary": "[]byte",
"hexbinary": "[]byte",
"unsignedint": "uint32",
Expand Down
299 changes: 296 additions & 3 deletions soap/soap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"bytes"
"encoding/xml"
"fmt"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

type Ping struct {
Expand Down Expand Up @@ -247,10 +249,10 @@ func Test_Client_FaultDefault(t *testing.T) {
emptyFault: &[]SimpleNode{},
},
{
name: "NestedNode",
name: "NestedNode",
wantErrString: "0.00: detail-1\n" +
"0.00: nested-2",
hasData: true,
hasData: true,
fault: &SimpleNode{
Detail: "detail-1",
Num: .003,
Expand Down Expand Up @@ -307,3 +309,294 @@ func Test_Client_FaultDefault(t *testing.T) {
})
}
}

// TestXsdDateTime checks the marshalled xsd datetime
func TestXsdDateTime(t *testing.T) {
type TestDateTime struct {
XMLName xml.Name `xml:"TestDateTime"`
Datetime XsdDateTime
}
// test marshalling
{
// without nanosecond
testDateTime := TestDateTime{
Datetime: CreateXsdDateTime(time.Date(1951, time.October, 22, 1, 2, 3, 0, time.FixedZone("UTC-8", -8*60*60)), true),
}
if output, err := xml.MarshalIndent(testDateTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDateTime><Datetime>1951-10-22T01:02:03-08:00</Datetime></TestDateTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}
{
// with nanosecond
testDateTime := TestDateTime{
Datetime: CreateXsdDateTime(time.Date(1951, time.October, 22, 1, 2, 3, 4, time.FixedZone("UTC-8", -8*60*60)), true),
}
if output, err := xml.MarshalIndent(testDateTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDateTime><Datetime>1951-10-22T01:02:03.000000004-08:00</Datetime></TestDateTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test marshalling of UTC
{
testDateTime := TestDateTime{
Datetime: CreateXsdDateTime(time.Date(1951, time.October, 22, 1, 2, 3, 4, time.UTC), true),
}
if output, err := xml.MarshalIndent(testDateTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDateTime><Datetime>1951-10-22T01:02:03.000000004Z</Datetime></TestDateTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test marshalling of XsdDateTime without TZ
{
testDateTime := TestDateTime{
Datetime: CreateXsdDateTime(time.Date(1951, time.October, 22, 1, 2, 3, 4, time.UTC), false),
}
if output, err := xml.MarshalIndent(testDateTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDateTime><Datetime>1951-10-22T01:02:03.000000004</Datetime></TestDateTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test unmarshalling
{
dateTimes := map[string]time.Time{
"<TestDateTime><Datetime>1951-10-22T01:02:03.000000004-08:00</Datetime></TestDateTime>": time.Date(1951, time.October, 22, 1, 2, 3, 4, time.FixedZone("-0800", -8*60*60)),
"<TestDateTime><Datetime>1951-10-22T01:02:03Z</Datetime></TestDateTime>": time.Date(1951, time.October, 22, 1, 2, 3, 0, time.UTC),
"<TestDateTime><Datetime>1951-10-22T01:02:03</Datetime></TestDateTime>": time.Date(1951, time.October, 22, 1, 2, 3, 0, time.Local),
}
for dateTimeStr, dateTimeObj := range dateTimes {
parsedDt := TestDateTime{}
if err := xml.Unmarshal([]byte(dateTimeStr), &parsedDt); err != nil {
t.Error(err)
} else {
if !parsedDt.Datetime.ToGoTime().Equal(dateTimeObj) {
t.Errorf("Got: %#v\nExpected: %#v", parsedDt.Datetime.ToGoTime(), dateTimeObj)
}
}
}
}
}

// TestXsdDateTime checks the marshalled xsd datetime
func TestXsdDate(t *testing.T) {
type TestDate struct {
XMLName xml.Name `xml:"TestDate"`
Date XsdDate
}

// test marshalling
{
testDate := TestDate{
Date: CreateXsdDate(time.Date(1951, time.October, 22, 0, 0, 0, 0, time.FixedZone("UTC-8", -8*60*60)), false),
}
if output, err := xml.MarshalIndent(testDate, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDate><Date>1951-10-22</Date></TestDate>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test marshalling
{
testDate := TestDate{
Date: CreateXsdDate(time.Date(1951, time.October, 22, 0, 0, 0, 0, time.FixedZone("UTC-8", -8*60*60)), true),
}
if output, err := xml.MarshalIndent(testDate, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDate><Date>1951-10-22-08:00</Date></TestDate>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test marshalling of UTC
{
testDate := TestDate{
Date: CreateXsdDate(time.Date(1951, time.October, 22, 0, 0, 0, 0, time.UTC), true),
}
if output, err := xml.MarshalIndent(testDate, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestDate><Date>1951-10-22Z</Date></TestDate>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test unmarshalling
{
dates := map[string]time.Time{
"<TestDate><Date>1951-10-22</Date></TestDate>": time.Date(1951, time.October, 22, 0, 0, 0, 0, time.Local),
"<TestDate><Date>1951-10-22Z</Date></TestDate>": time.Date(1951, time.October, 22, 0, 0, 0, 0, time.UTC),
"<TestDate><Date>1951-10-22-08:00</Date></TestDate>": time.Date(1951, time.October, 22, 0, 0, 0, 0, time.FixedZone("UTC-8", -8*60*60)),
}
for dateStr, dateObj := range dates {
parsedDate := TestDate{}
if err := xml.Unmarshal([]byte(dateStr), &parsedDate); err != nil {
t.Error(dateStr, err)
} else {
if !parsedDate.Date.ToGoTime().Equal(dateObj) {
t.Errorf("Got: %#v\nExpected: %#v", parsedDate.Date.ToGoTime(), dateObj)
}
}
}
}
}

// TestXsdTime checks the marshalled xsd datetime
func TestXsdTime(t *testing.T) {
type TestTime struct {
XMLName xml.Name `xml:"TestTime"`
Time XsdTime
}

// test marshalling
{
testTime := TestTime{
Time: CreateXsdTime(12, 13, 14, 4, time.FixedZone("Test", -19800)),
}
if output, err := xml.MarshalIndent(testTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestTime><Time>12:13:14.000000004-05:30</Time></TestTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}
{
testTime := TestTime{
Time: CreateXsdTime(12, 13, 14, 0, time.FixedZone("UTC-8", -8*60*60)),
}
if output, err := xml.MarshalIndent(testTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestTime><Time>12:13:14-08:00</Time></TestTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}
{
testTime := TestTime{
Time: CreateXsdTime(12, 13, 14, 0, nil),
}
if output, err := xml.MarshalIndent(testTime, "", ""); err != nil {
t.Error(err)
} else {
outputstr := string(output)
expected := "<TestTime><Time>12:13:14</Time></TestTime>"
if outputstr != expected {
t.Errorf("Got: %v\nExpected: %v", outputstr, expected)
}
}
}

// test unmarshalling without TZ
{
timeStr := "<TestTime><Time>12:13:14.000000004</Time></TestTime>"
parsedTime := TestTime{}
if err := xml.Unmarshal([]byte(timeStr), &parsedTime); err != nil {
t.Error(err)
} else {
if parsedTime.Time.Hour() != 12 {
t.Errorf("Got hour %#v\nExpected: %#v", parsedTime.Time.Hour(), 12)
}
if parsedTime.Time.Minute() != 13 {
t.Errorf("Got minute %#v\nExpected: %#v", parsedTime.Time.Minute(), 13)
}
if parsedTime.Time.Second() != 14 {
t.Errorf("Got second %#v\nExpected: %#v", parsedTime.Time.Second(), 14)
}
if parsedTime.Time.Nanosecond() != 4 {
t.Errorf("Got nsec %#v\nExpected: %#v", parsedTime.Time.Nanosecond(), 4)
}
if parsedTime.Time.Location() != nil {
t.Errorf("Got location %v\nExpected: Nil/Undetermined", parsedTime.Time.Location().String())
}
}
}
// test unmarshalling with UTC
{
timeStr := "<TestTime><Time>12:13:14Z</Time></TestTime>"
parsedTime := TestTime{}
if err := xml.Unmarshal([]byte(timeStr), &parsedTime); err != nil {
t.Error(err)
} else {
if parsedTime.Time.Hour() != 12 {
t.Errorf("Got hour %#v\nExpected: %#v", parsedTime.Time.Hour(), 12)
}
if parsedTime.Time.Minute() != 13 {
t.Errorf("Got minute %#v\nExpected: %#v", parsedTime.Time.Minute(), 13)
}
if parsedTime.Time.Second() != 14 {
t.Errorf("Got second %#v\nExpected: %#v", parsedTime.Time.Second(), 14)
}
if parsedTime.Time.Nanosecond() != 0 {
t.Errorf("Got nsec %#v\nExpected: %#v", parsedTime.Time.Nanosecond(), 0)
}
if parsedTime.Time.Location().String() != "UTC" {
t.Errorf("Got location %v\nExpected: UTC", parsedTime.Time.Location().String())
}
}
}
// test unmarshalling with non-UTC Tz
{
timeStr := "<TestTime><Time>12:13:14-08:00</Time></TestTime>"
parsedTime := TestTime{}
if err := xml.Unmarshal([]byte(timeStr), &parsedTime); err != nil {
t.Error(err)
} else {
if parsedTime.Time.Hour() != 12 {
t.Errorf("Got hour %#v\nExpected: %#v", parsedTime.Time.Hour(), 12)
}
if parsedTime.Time.Minute() != 13 {
t.Errorf("Got minute %#v\nExpected: %#v", parsedTime.Time.Minute(), 13)
}
if parsedTime.Time.Second() != 14 {
t.Errorf("Got second %#v\nExpected: %#v", parsedTime.Time.Second(), 14)
}
if parsedTime.Time.Nanosecond() != 0 {
t.Errorf("Got nsec %#v\nExpected: %#v", parsedTime.Time.Nanosecond(), 0)
}
_, tzOffset := parsedTime.Time.innerTime.Zone()
if tzOffset != -8*3600 {
t.Errorf("Got location offset %v\nExpected: %v", tzOffset, -8*3600)
}
}
}
}
Loading

0 comments on commit dac628d

Please sign in to comment.