diff --git a/boolean_field.go b/boolean_field.go index e3810ec9e..22c24567d 100644 --- a/boolean_field.go +++ b/boolean_field.go @@ -9,7 +9,8 @@ type BooleanValue struct { Value bool } -func (f *BooleanValue) Read(bytes []byte) error { +func (f *BooleanValue) Read(tv []TagValue) error { + bytes := tv[0].Value switch string(bytes) { case "Y": f.Value = true diff --git a/boolean_field_test.go b/boolean_field_test.go index d3e0aa383..5a686ac51 100644 --- a/boolean_field_test.go +++ b/boolean_field_test.go @@ -59,7 +59,7 @@ func TestBooleanFieldRead(t *testing.T) { for _, test := range tests { field := NewBooleanField(Tag(1), false) - err := field.Read(test.bytes) + err := field.Read([]TagValue{TagValue{Value: test.bytes}}) if test.expectError && err == nil { t.Errorf("Expected error for %v", test.bytes) diff --git a/field.go b/field.go index 7367f1d00..371a004fd 100644 --- a/field.go +++ b/field.go @@ -3,7 +3,11 @@ package quickfix //The FieldValue interface is used to write/extract typed field values to/from raw bytes type FieldValue interface { Write() []byte - Read([]byte) error + + //Parameter to Read is a single length slice of TagValues. For most fields, only the first + //TagValue will be required. The capacity of the slice extends from the field to be read through the + //underlying message length. This can be useful for FieldValues made up of repeating groups. + Read([]TagValue) error } //Field is the interface implemented by all typed Fields in a Message diff --git a/field_bytes.go b/field_bytes.go deleted file mode 100644 index a2f1bf1ef..000000000 --- a/field_bytes.go +++ /dev/null @@ -1,63 +0,0 @@ -package quickfix - -import ( - "bytes" - "fmt" - "strconv" -) - -type fieldBytes struct { - Tag - Data []byte - Value []byte -} - -func newFieldBytes(tag Tag, value []byte) *fieldBytes { - var buf bytes.Buffer - buf.WriteString(strconv.Itoa(int(tag))) - buf.WriteString("=") - buf.Write(value) - buf.WriteString("") - - return &fieldBytes{Tag: tag, Data: buf.Bytes(), Value: value} -} - -func (f *fieldBytes) parseField(rawFieldBytes []byte) (err error) { - sepIndex := bytes.IndexByte(rawFieldBytes, '=') - - if sepIndex == -1 { - err = fmt.Errorf("fieldBytes.Parse: No '=' in '%s'", rawFieldBytes) - return - } - - parsedTag, err := Atoi(rawFieldBytes[:sepIndex]) - - if err != nil { - err = fmt.Errorf("fieldBytes.Parse: %s", err.Error()) - return - } - - f.Tag = Tag(parsedTag) - f.Value = rawFieldBytes[(sepIndex + 1):(len(rawFieldBytes) - 1)] - f.Data = rawFieldBytes - - return -} - -func (f *fieldBytes) String() string { - return string(f.Data) -} - -func (f *fieldBytes) Total() int { - total := 0 - - for _, b := range []byte(f.Data) { - total += int(b) - } - - return total -} - -func (f *fieldBytes) Length() int { - return len(f.Data) -} diff --git a/field_bytes_test.go b/field_bytes_test.go deleted file mode 100644 index bfdcf53f2..000000000 --- a/field_bytes_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package quickfix - -import ( - "bytes" - "testing" -) - -func TestFieldBytes_NewField(t *testing.T) { - f := newFieldBytes(Tag(8), []byte("blahblah")) - if f == nil { - t.Error("f should not be nil") - } - - expectedData := []byte("8=blahblah") - if !bytes.Equal(f.Data, expectedData) { - t.Errorf("Expected %v, got %v", expectedData, f.Data) - } - expectedValue := []byte("blahblah") - if !bytes.Equal(f.Value, expectedValue) { - t.Errorf("Expected %v, got %v", expectedValue, f.Value) - } -} - -func TestFieldBytes_ParseField(t *testing.T) { - stringField := "8=FIX.4.0" - f := fieldBytes{} - err := f.parseField([]byte(stringField)) - - if err != nil { - t.Error("Unexpected error", err) - } - - if f.Tag != Tag(8) { - t.Error("Unexpected tag", f.Tag) - } - - if !bytes.Equal(f.Data, []byte(stringField)) { - t.Errorf("Expected %v got %v", stringField, f.Data) - } - - if !bytes.Equal(f.Value, []byte("FIX.4.0")) { - t.Error("Unxpected value", f.Value) - } -} - -func TestFieldBytes_ParseFieldFail(t *testing.T) { - stringField := "not_tag_equal_value" - f := fieldBytes{} - - err := f.parseField([]byte(stringField)) - - if err == nil { - t.Error("Expected Error") - } - - stringField = "tag_not_an_int=uhoh" - err = f.parseField([]byte(stringField)) - if err == nil { - t.Error("Expected Error") - } -} - -func TestFieldBytes_String(t *testing.T) { - stringField := "8=FIX.4.0" - f := fieldBytes{} - f.parseField([]byte(stringField)) - - if f.String() != "8=FIX.4.0" { - t.Error("Unexpected string value", f.String()) - } -} - -func TestFieldBytes_Length(t *testing.T) { - stringField := "8=FIX.4.0" - f := fieldBytes{} - f.parseField([]byte(stringField)) - - if f.Length() != len(stringField) { - t.Error("Unexpected Length", f.Length()) - } -} - -func TestFieldBytes_Total(t *testing.T) { - stringField := "1=hello" - f := fieldBytes{} - f.parseField([]byte(stringField)) - if f.Total() != 643 { - t.Error("Total is the summation of the ascii byte values of the field string, got ", f.Total()) - } -} diff --git a/field_map.go b/field_map.go index b95d3e31b..6be19d56e 100644 --- a/field_map.go +++ b/field_map.go @@ -8,21 +8,21 @@ import ( //FieldMap is a collection of fix fields that make up a fix message. type FieldMap struct { - fieldLookup map[Tag]*fieldBytes - fieldOrder + tagLookup map[Tag][]TagValue + tagOrder } -// fieldOrder true if tag i should occur before tag j -type fieldOrder func(i, j Tag) bool +// tagOrder true if tag i should occur before tag j +type tagOrder func(i, j Tag) bool -type fieldSort struct { +type tagSort struct { tags []Tag - compare fieldOrder + compare tagOrder } -func (t fieldSort) Len() int { return len(t.tags) } -func (t fieldSort) Swap(i, j int) { t.tags[i], t.tags[j] = t.tags[j], t.tags[i] } -func (t fieldSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) } +func (t tagSort) Len() int { return len(t.tags) } +func (t tagSort) Swap(i, j int) { t.tags[i], t.tags[j] = t.tags[j], t.tags[i] } +func (t tagSort) Less(i, j int) bool { return t.compare(t.tags[i], t.tags[j]) } //in the message header, the first 3 tags in the message header must be 8,9,35 func headerFieldOrder(i, j Tag) bool { @@ -67,14 +67,14 @@ func trailerFieldOrder(i, j Tag) bool { return i < j } -func (m *FieldMap) init(ordering fieldOrder) { - m.fieldLookup = make(map[Tag]*fieldBytes) - m.fieldOrder = ordering +func (m *FieldMap) init(ordering tagOrder) { + m.tagLookup = make(map[Tag][]TagValue) + m.tagOrder = ordering } func (m FieldMap) Tags() []Tag { - tags := make([]Tag, 0, len(m.fieldLookup)) - for t := range m.fieldLookup { + tags := make([]Tag, 0, len(m.tagLookup)) + for t := range m.tagLookup { tags = append(tags, t) } @@ -86,18 +86,17 @@ func (m FieldMap) Get(parser Field) MessageRejectError { } func (m FieldMap) Has(tag Tag) bool { - _, ok := m.fieldLookup[tag] + _, ok := m.tagLookup[tag] return ok } func (m FieldMap) GetField(tag Tag, parser FieldValue) MessageRejectError { - field, ok := m.fieldLookup[tag] - + tagValues, ok := m.tagLookup[tag] if !ok { return conditionallyRequiredFieldMissing(tag) } - if err := parser.Read(field.Value); err != nil { + if err := parser.Read(tagValues[0:1]); err != nil { return incorrectDataFormatForValue(tag) } @@ -105,20 +104,25 @@ func (m FieldMap) GetField(tag Tag, parser FieldValue) MessageRejectError { } func (m FieldMap) SetField(tag Tag, field FieldValue) { - m.fieldLookup[tag] = newFieldBytes(tag, field.Write()) + tValues := make([]TagValue, 1) + tValues[0].init(tag, field.Write()) + m.tagLookup[tag] = tValues } func (m FieldMap) Set(field Field) { - m.fieldLookup[field.Tag()] = newFieldBytes(field.Tag(), field.Write()) + tValues := make([]TagValue, 1) + tValues[0].init(field.Tag(), field.Write()) + + m.tagLookup[field.Tag()] = tValues } func (m FieldMap) sortedTags() []Tag { - sortedTags := make([]Tag, len(m.fieldLookup)) - for tag := range m.fieldLookup { + sortedTags := make([]Tag, len(m.tagLookup)) + for tag := range m.tagLookup { sortedTags = append(sortedTags, tag) } - sort.Sort(fieldSort{sortedTags, m.fieldOrder}) + sort.Sort(tagSort{sortedTags, m.tagOrder}) return sortedTags } @@ -126,19 +130,23 @@ func (m FieldMap) write(buffer *bytes.Buffer) { tags := m.sortedTags() for _, tag := range tags { - if field, ok := m.fieldLookup[tag]; ok { - buffer.Write(field.Data) + if fields, ok := m.tagLookup[tag]; ok { + for _, field := range fields { + buffer.Write(field.bytes) + } } } } func (m FieldMap) total() int { total := 0 - for t, field := range m.fieldLookup { - switch t { - case tagCheckSum: //tag does not contribute to total - default: - total += field.Total() + for _, fields := range m.tagLookup { + for _, field := range fields { + switch field.Tag { + case tagCheckSum: //tag does not contribute to total + default: + total += field.total() + } } } @@ -147,11 +155,13 @@ func (m FieldMap) total() int { func (m FieldMap) length() int { length := 0 - for t := range m.fieldLookup { - switch t { - case tagBeginString, tagBodyLength, tagCheckSum: //tags do not contribute to length - default: - length += m.fieldLookup[t].Length() + for _, fields := range m.tagLookup { + for _, field := range fields { + switch field.Tag { + case tagBeginString, tagBodyLength, tagCheckSum: //tags do not contribute to length + default: + length += field.length() + } } } diff --git a/float_field.go b/float_field.go index 045533210..34071422e 100644 --- a/float_field.go +++ b/float_field.go @@ -11,7 +11,8 @@ type FloatValue struct { Value float64 } -func (f *FloatValue) Read(bytes []byte) (err error) { +func (f *FloatValue) Read(tv []TagValue) (err error) { + bytes := tv[0].Value if f.Value, err = strconv.ParseFloat(string(bytes), 64); err != nil { return } diff --git a/float_field_test.go b/float_field_test.go index 2f9f095bb..ef14d418f 100644 --- a/float_field_test.go +++ b/float_field_test.go @@ -56,7 +56,7 @@ func TestFloatFieldRead(t *testing.T) { for _, test := range tests { field := new(FloatField) - if err := field.Read(test.bytes); err != nil { + if err := field.Read([]TagValue{TagValue{Value: test.bytes}}); err != nil { if !test.expectError { t.Errorf("UnExpected '%v'", err) } diff --git a/int_field.go b/int_field.go index 70698f15e..d8bf56c82 100644 --- a/int_field.go +++ b/int_field.go @@ -14,18 +14,18 @@ const ( ascii9 = 57 ) -//Atoi is similar to the function in strconv, but is tuned for ints appearing in FIX field types. -func Atoi(d []byte) (int, error) { +//atoi is similar to the function in strconv, but is tuned for ints appearing in FIX field types. +func atoi(d []byte) (int, error) { if d[0] == asciiMinus { - n, err := ParseUInt(d[1:]) + n, err := parseUInt(d[1:]) return (-1) * n, err } - return ParseUInt(d) + return parseUInt(d) } -//ParseUInt is similar to the function in strconv, but is tuned for ints appearing in FIX field types. -func ParseUInt(d []byte) (n int, err error) { +//parseUInt is similar to the function in strconv, but is tuned for ints appearing in FIX field types. +func parseUInt(d []byte) (n int, err error) { if len(d) == 0 { err = errors.New("empty bytes") return @@ -48,8 +48,8 @@ type IntValue struct { Value int } -func (f *IntValue) Read(bytes []byte) (err error) { - f.Value, err = Atoi(bytes) +func (f *IntValue) Read(tv []TagValue) (err error) { + f.Value, err = atoi(tv[0].Value) return } diff --git a/int_field_test.go b/int_field_test.go index 9980e6ff3..b3eeb2a4a 100644 --- a/int_field_test.go +++ b/int_field_test.go @@ -26,7 +26,7 @@ func TestIntField_Write(t *testing.T) { func TestIntField_Read(t *testing.T) { field := new(IntField) - err := field.Read([]byte("15")) + err := field.Read([]TagValue{TagValue{Value: []byte("15")}}) if err != nil { t.Error("Unexpected error", err) @@ -36,7 +36,7 @@ func TestIntField_Read(t *testing.T) { t.Error("unexpected value", field.Value) } - err = field.Read([]byte("blah")) + err = field.Read([]TagValue{TagValue{Value: []byte("blah")}}) if err == nil { t.Error("expected error") @@ -48,6 +48,6 @@ func BenchmarkIntField_Read(b *testing.B) { field := &IntField{} for i := 0; i < b.N; i++ { - field.Read(intBytes) + field.Read([]TagValue{TagValue{Value: intBytes}}) } } diff --git a/message.go b/message.go index c4a42e26f..939e59277 100644 --- a/message.go +++ b/message.go @@ -22,7 +22,7 @@ type Message struct { bodyBytes []byte //field bytes as they appear in the raw message - fields []fieldBytes + fields []TagValue } //parseError is returned when bytes cannot be parsed as a FIX message. @@ -57,7 +57,7 @@ func parseMessage(rawMessage []byte) (Message, error) { fieldCount++ } } - msg.fields = make([]fieldBytes, fieldCount) + msg.fields = make([]TagValue, fieldCount) fieldIndex := 0 var err error @@ -67,7 +67,7 @@ func parseMessage(rawMessage []byte) (Message, error) { return msg, err } - msg.Header.fieldLookup[msg.fields[fieldIndex].Tag] = &msg.fields[fieldIndex] + msg.Header.tagLookup[msg.fields[fieldIndex].Tag] = msg.fields[fieldIndex : fieldIndex+1] fieldIndex++ parsedFieldBytes := &msg.fields[fieldIndex] @@ -75,7 +75,7 @@ func parseMessage(rawMessage []byte) (Message, error) { return msg, err } - msg.Header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes + msg.Header.tagLookup[parsedFieldBytes.Tag] = msg.fields[fieldIndex : fieldIndex+1] fieldIndex++ parsedFieldBytes = &msg.fields[fieldIndex] @@ -83,7 +83,7 @@ func parseMessage(rawMessage []byte) (Message, error) { return msg, err } - msg.Header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes + msg.Header.tagLookup[parsedFieldBytes.Tag] = msg.fields[fieldIndex : fieldIndex+1] fieldIndex++ trailerBytes := []byte{} @@ -97,13 +97,13 @@ func parseMessage(rawMessage []byte) (Message, error) { switch { case parsedFieldBytes.Tag.IsHeader(): - msg.Header.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes + msg.Header.tagLookup[parsedFieldBytes.Tag] = msg.fields[fieldIndex : fieldIndex+1] case parsedFieldBytes.Tag.IsTrailer(): - msg.Trailer.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes + msg.Trailer.tagLookup[parsedFieldBytes.Tag] = msg.fields[fieldIndex : fieldIndex+1] default: foundBody = true trailerBytes = rawMessage - msg.Body.fieldLookup[parsedFieldBytes.Tag] = parsedFieldBytes + msg.Body.tagLookup[parsedFieldBytes.Tag] = msg.fields[fieldIndex : fieldIndex+1] } if parsedFieldBytes.Tag == tagCheckSum { break @@ -126,7 +126,7 @@ func parseMessage(rawMessage []byte) (Message, error) { switch field.Tag { case tagBeginString, tagBodyLength, tagCheckSum: //tags do not contribute to length default: - length += field.Length() + length += field.length() } } @@ -175,7 +175,7 @@ func (m Message) reverseRoute() Message { return reverseMsg } -func extractSpecificField(field *fieldBytes, expectedTag Tag, buffer []byte) (remBuffer []byte, err error) { +func extractSpecificField(field *TagValue, expectedTag Tag, buffer []byte) (remBuffer []byte, err error) { remBuffer, err = extractField(field, buffer) switch { case err != nil: @@ -188,7 +188,7 @@ func extractSpecificField(field *fieldBytes, expectedTag Tag, buffer []byte) (re return } -func extractField(parsedFieldBytes *fieldBytes, buffer []byte) (remBytes []byte, err error) { +func extractField(parsedFieldBytes *TagValue, buffer []byte) (remBytes []byte, err error) { endIndex := bytes.IndexByte(buffer, '\001') if endIndex == -1 { err = parseError{OrigError: "extractField: No Trailing Delim in " + string(buffer)} @@ -196,7 +196,7 @@ func extractField(parsedFieldBytes *fieldBytes, buffer []byte) (remBytes []byte, return } - err = parsedFieldBytes.parseField(buffer[:endIndex+1]) + err = parsedFieldBytes.parse(buffer[:endIndex+1]) return buffer[(endIndex + 1):], err } diff --git a/parser.go b/parser.go index aa1984a2b..647550118 100644 --- a/parser.go +++ b/parser.go @@ -90,7 +90,7 @@ func (p *parser) jumpLength() (int, error) { return 0, err } - length, err := Atoi(p.buffer[lengthIndex:offset]) + length, err := atoi(p.buffer[lengthIndex:offset]) if err != nil { return length, err } diff --git a/string_field.go b/string_field.go index 091de373f..70a495adf 100644 --- a/string_field.go +++ b/string_field.go @@ -5,8 +5,8 @@ type StringValue struct { Value string } -func (f *StringValue) Read(bytes []byte) error { - f.Value = string(bytes) +func (f *StringValue) Read(tv []TagValue) error { + f.Value = string(tv[0].Value) return nil } diff --git a/string_field_test.go b/string_field_test.go index ac408d188..0353ce283 100644 --- a/string_field_test.go +++ b/string_field_test.go @@ -54,7 +54,7 @@ func TestStringFieldRead(t *testing.T) { for _, test := range tests { field := new(StringField) - err := field.Read(test.bytes) + err := field.Read([]TagValue{TagValue{Value: test.bytes}}) if test.expectError && err == nil { t.Errorf("Expected error for %v", test.bytes) diff --git a/tag_value.go b/tag_value.go new file mode 100644 index 000000000..88e138da4 --- /dev/null +++ b/tag_value.go @@ -0,0 +1,67 @@ +package quickfix + +import ( + "bytes" + "fmt" + "strconv" +) + +//TagValue is a low-level FIX field abstraction +type TagValue struct { + Tag + Value []byte + + bytes []byte +} + +func (tv *TagValue) init(tag Tag, value []byte) { + var buf bytes.Buffer + buf.WriteString(strconv.Itoa(int(tag))) + buf.WriteString("=") + buf.Write(value) + buf.WriteString("") + + tv.Tag = tag + tv.bytes = buf.Bytes() + tv.Value = value +} + +func (tv *TagValue) parse(rawFieldBytes []byte) (err error) { + sepIndex := bytes.IndexByte(rawFieldBytes, '=') + + if sepIndex == -1 { + err = fmt.Errorf("TagValue.Parse: No '=' in '%s'", rawFieldBytes) + return + } + + parsedTag, err := atoi(rawFieldBytes[:sepIndex]) + + if err != nil { + err = fmt.Errorf("TagValue.Parse: %s", err.Error()) + return + } + + tv.Tag = Tag(parsedTag) + tv.Value = rawFieldBytes[(sepIndex + 1):(len(rawFieldBytes) - 1)] + tv.bytes = rawFieldBytes + + return +} + +func (tv TagValue) String() string { + return string(tv.bytes) +} + +func (tv TagValue) total() int { + total := 0 + + for _, b := range []byte(tv.bytes) { + total += int(b) + } + + return total +} + +func (tv TagValue) length() int { + return len(tv.bytes) +} diff --git a/tag_value_test.go b/tag_value_test.go new file mode 100644 index 000000000..8a2d1e338 --- /dev/null +++ b/tag_value_test.go @@ -0,0 +1,88 @@ +package quickfix + +import ( + "bytes" + "testing" +) + +func TestTagValue_init(t *testing.T) { + var tv TagValue + tv.init(Tag(8), []byte("blahblah")) + + expectedData := []byte("8=blahblah") + if !bytes.Equal(tv.bytes, expectedData) { + t.Errorf("Expected %v, got %v", expectedData, tv.bytes) + } + expectedValue := []byte("blahblah") + if !bytes.Equal(tv.Value, expectedValue) { + t.Errorf("Expected %v, got %v", expectedValue, tv.Value) + } +} + +func TestTagValue_parse(t *testing.T) { + stringField := "8=FIX.4.0" + tv := TagValue{} + err := tv.parse([]byte(stringField)) + + if err != nil { + t.Error("Unexpected error", err) + } + + if tv.Tag != Tag(8) { + t.Error("Unexpected tag", tv.Tag) + } + + if !bytes.Equal(tv.bytes, []byte(stringField)) { + t.Errorf("Expected %v got %v", stringField, tv.bytes) + } + + if !bytes.Equal(tv.Value, []byte("FIX.4.0")) { + t.Error("Unxpected value", tv.Value) + } +} + +func TestTagValue_parseFail(t *testing.T) { + stringField := "not_tag_equal_value" + tv := TagValue{} + + err := tv.parse([]byte(stringField)) + + if err == nil { + t.Error("Expected Error") + } + + stringField = "tag_not_an_int=uhoh" + err = tv.parse([]byte(stringField)) + if err == nil { + t.Error("Expected Error") + } +} + +func TestTagValue_String(t *testing.T) { + stringField := "8=FIX.4.0" + tv := TagValue{} + tv.parse([]byte(stringField)) + + if tv.String() != "8=FIX.4.0" { + t.Error("Unexpected string value", tv.String()) + } +} + +func TestTagValue_length(t *testing.T) { + stringField := "8=FIX.4.0" + tv := TagValue{} + tv.parse([]byte(stringField)) + + if tv.length() != len(stringField) { + t.Error("Unexpected length", tv.length()) + } +} + +func TestTagValue_total(t *testing.T) { + stringField := "1=hello" + tv := TagValue{} + tv.parse([]byte(stringField)) + if tv.total() != 643 { + t.Error("Total is the summation of the ascii byte values of the field string, got ", tv.total()) + } +} diff --git a/utc_timestamp_field.go b/utc_timestamp_field.go index 321ee941f..eb70e7ed5 100644 --- a/utc_timestamp_field.go +++ b/utc_timestamp_field.go @@ -15,7 +15,8 @@ const ( utcTimestampNoMillisFormat = "20060102-15:04:05" ) -func (f *UTCTimestampValue) Read(bytes []byte) (err error) { +func (f *UTCTimestampValue) Read(tv []TagValue) (err error) { + bytes := tv[0].Value //with millisecs if f.Value, err = time.Parse(utcTimestampFormat, string(bytes)); err == nil { return diff --git a/validation.go b/validation.go index a7996a4bd..3e792ddf0 100644 --- a/validation.go +++ b/validation.go @@ -97,7 +97,7 @@ func validateWalk(transportDD *datadictionary.DataDictionary, appDD *datadiction return nil } -func validateWalkComponent(messageDef *datadictionary.MessageDef, fields []fieldBytes) ([]fieldBytes, MessageRejectError) { +func validateWalkComponent(messageDef *datadictionary.MessageDef, fields []TagValue) ([]TagValue, MessageRejectError) { var fieldDef *datadictionary.FieldDef var ok bool var err MessageRejectError @@ -123,7 +123,7 @@ func validateWalkComponent(messageDef *datadictionary.MessageDef, fields []field return fields, nil } -func validateVisitField(fieldDef *datadictionary.FieldDef, fields []fieldBytes) ([]fieldBytes, MessageRejectError) { +func validateVisitField(fieldDef *datadictionary.FieldDef, fields []TagValue) ([]TagValue, MessageRejectError) { var err MessageRejectError if fieldDef.IsGroup() { @@ -135,11 +135,11 @@ func validateVisitField(fieldDef *datadictionary.FieldDef, fields []fieldBytes) return fields[1:], nil } -func validateVisitGroupField(fieldDef *datadictionary.FieldDef, fieldStack []fieldBytes) ([]fieldBytes, MessageRejectError) { +func validateVisitGroupField(fieldDef *datadictionary.FieldDef, fieldStack []TagValue) ([]TagValue, MessageRejectError) { numInGroupTag := fieldStack[0].Tag numInGroup := new(IntValue) - if err := numInGroup.Read(fieldStack[0].Value); err != nil { + if err := numInGroup.Read(fieldStack); err != nil { return nil, incorrectDataFormatForValue(numInGroupTag) } @@ -256,7 +256,7 @@ func validateFields(transportDD *datadictionary.DataDictionary, appDD *datadicti return nil } -func validateField(d *datadictionary.DataDictionary, validFields datadictionary.TagSet, field fieldBytes) MessageRejectError { +func validateField(d *datadictionary.DataDictionary, validFields datadictionary.TagSet, field TagValue) MessageRejectError { if len(field.Value) == 0 { return tagSpecifiedWithoutAValue(field.Tag) } @@ -335,7 +335,7 @@ func validateField(d *datadictionary.DataDictionary, validFields datadictionary. prototype = new(PercentageValue) } - if err := prototype.Read(field.Value); err != nil { + if err := prototype.Read([]TagValue{field}); err != nil { return incorrectDataFormatForValue(field.Tag) } diff --git a/validation_test.go b/validation_test.go index 37a1415a2..1896ec845 100644 --- a/validation_test.go +++ b/validation_test.go @@ -260,8 +260,9 @@ func (s *ValidationTests) TestValidateVisitField(c *C) { fieldType := &datadictionary.FieldType{Name: "myfield", Tag: 11, Type: "STRING"} fieldDef := &datadictionary.FieldDef{FieldType: fieldType} - fields := []fieldBytes{*newFieldBytes(Tag(11), []byte("value"))} - remFields, reject := validateVisitField(fieldDef, fields) + TagValues := make([]TagValue, 1) + TagValues[0].init(Tag(11), []byte("value")) + remFields, reject := validateVisitField(fieldDef, TagValues) c.Check(len(remFields), Equals, 0) c.Check(reject, IsNil) } @@ -276,57 +277,61 @@ func (s *ValidationTests) TestValidateVisitFieldGroup(c *C) { groupFieldType := &datadictionary.FieldType{Name: "mygroupfield", Tag: 1, Type: "INT"} groupFieldDef := &datadictionary.FieldDef{FieldType: groupFieldType, ChildFields: []*datadictionary.FieldDef{fieldDef1, fieldDef2}} - repField1 := newFieldBytes(Tag(2), []byte("a")) - repField2 := newFieldBytes(Tag(3), []byte("a")) + var repField1 TagValue + var repField2 TagValue + repField1.init(Tag(2), []byte("a")) + repField2.init(Tag(3), []byte("a")) //non-repeating - groupID := newFieldBytes(Tag(1), []byte("1")) - fields := []fieldBytes{*groupID, *repField1} + var groupID TagValue + groupID.init(Tag(1), []byte("1")) + fields := []TagValue{groupID, repField1} remFields, reject := validateVisitGroupField(groupFieldDef, fields) c.Check(len(remFields), Equals, 0) c.Check(reject, IsNil) - fields = []fieldBytes{*groupID, *repField1, *repField2} + fields = []TagValue{groupID, repField1, repField2} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(len(remFields), Equals, 0) c.Check(reject, IsNil) //test with trailing tag not in group - otherField := newFieldBytes(Tag(500), []byte("blah")) - fields = []fieldBytes{*groupID, *repField1, *repField2, *otherField} + var otherField TagValue + otherField.init(Tag(500), []byte("blah")) + fields = []TagValue{groupID, repField1, repField2, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(len(remFields), Equals, 1) c.Check(reject, IsNil) //repeats - groupID = newFieldBytes(Tag(1), []byte("2")) - fields = []fieldBytes{*groupID, *repField1, *repField2, *repField1, *repField2, *otherField} + groupID.init(Tag(1), []byte("2")) + fields = []TagValue{groupID, repField1, repField2, repField1, repField2, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(len(remFields), Equals, 1) c.Check(reject, IsNil) - groupID = newFieldBytes(Tag(1), []byte("3")) - fields = []fieldBytes{*groupID, *repField1, *repField2, *repField1, *repField2, *repField1, *repField2, *otherField} + groupID.init(Tag(1), []byte("3")) + fields = []TagValue{groupID, repField1, repField2, repField1, repField2, repField1, repField2, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(len(remFields), Equals, 1) c.Check(reject, IsNil) //REJECT: group size declared > actual group size - groupID = newFieldBytes(Tag(1), []byte("3")) - fields = []fieldBytes{*groupID, *repField1, *repField2, *repField1, *repField2, *otherField} + groupID.init(Tag(1), []byte("3")) + fields = []TagValue{groupID, repField1, repField2, repField1, repField2, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(reject, NotNil) c.Check(reject.RejectReason(), Equals, rejectReasonIncorrectNumInGroupCountForRepeatingGroup) - groupID = newFieldBytes(Tag(1), []byte("3")) - fields = []fieldBytes{*groupID, *repField1, *repField1, *otherField} + groupID.init(Tag(1), []byte("3")) + fields = []TagValue{groupID, repField1, repField1, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(reject, NotNil) c.Check(reject.RejectReason(), Equals, rejectReasonIncorrectNumInGroupCountForRepeatingGroup) //REJECT: group size declared < actual group size - groupID = newFieldBytes(Tag(1), []byte("1")) - fields = []fieldBytes{*groupID, *repField1, *repField2, *repField1, *repField2, *otherField} + groupID.init(Tag(1), []byte("1")) + fields = []TagValue{groupID, repField1, repField2, repField1, repField2, otherField} remFields, reject = validateVisitGroupField(groupFieldDef, fields) c.Check(reject, NotNil) c.Check(reject.RejectReason(), Equals, rejectReasonIncorrectNumInGroupCountForRepeatingGroup)