From 88612c1cf8f5df80a25976d3e968ba6dc40cc608 Mon Sep 17 00:00:00 2001 From: Dustin Oprea Date: Wed, 1 Jan 2020 00:16:11 -0500 Subject: [PATCH] ifd_builder.go: No longer use ITEVRs This was an early way of resolving tag values that is now obsolete. `ValueContext` structs should be used, and these, in many cases, should be able to be constructed from the current context without passing additional arguments. - ifd_builder_test.go: Refactors to several tests due to loss of ITEVR support. - ifd_builder_encode_test.go: Moved test-IB populate to testing_common.go . - ifd_builder.go: Fixed test naming (in most cases, omitted type name). --- ifd_builder.go | 143 +++++++++------------- ifd_builder_encode_test.go | 92 --------------- ifd_builder_test.go | 236 +++++++++++++++---------------------- testing_common.go | 149 +++++++++++++++++++++++ 4 files changed, 305 insertions(+), 315 deletions(-) create mode 100644 testing_common.go diff --git a/ifd_builder.go b/ifd_builder.go index ece7535..47ab37a 100644 --- a/ifd_builder.go +++ b/ifd_builder.go @@ -222,8 +222,8 @@ type IfdBuilder struct { byteOrder binary.ByteOrder // Includes both normal tags and IFD tags (which point to child IFDs). - // TODO(dustin): Keep a separate list of children like with IFd. - // TODO(dustin): Either rename this or `Entries` in Ifd to be the same thing. + // TODO(dustin): Keep a separate list of children like with `Ifd`. + // TODO(dustin): Either rename this or `Entries` in `Ifd` to be the same thing. tags []*BuilderTag // existingOffset will be the offset that this IFD is currently found at if @@ -312,7 +312,7 @@ func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder) { // NewIfdBuilderFromExistingChain creates a chain of IB instances from an // IFD chain generated from real data. func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder) { - // TODO(dustin): !! When we actually write the code to flatten the IB to bytes, make sure to skip the tags that have a nil value (which will happen when we add-from-exsting without a resolver instance). + // OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future. var lastIb *IfdBuilder i := 0 @@ -324,7 +324,7 @@ func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolve lastIb.SetNextIb(newIb) } - err := newIb.AddTagsFromExisting(thisExistingIfd, itevr, nil, nil) + err := newIb.AddTagsFromExisting(thisExistingIfd, nil, nil, nil) log.PanicIf(err) lastIb = newIb @@ -1028,6 +1028,8 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol } }() + // OBSOLETE(dustin): Support for `itevr` is now obsolete. This parameter will be removed in the future. + thumbnailData, err := ifd.Thumbnail() if err == nil { err = ib.SetThumbnail(thumbnailData) @@ -1078,105 +1080,76 @@ func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResol // If we want to add an IFD tag, we'll have to build it first and // *then* add it via a different method. - if itevr == nil { - // We don't have any ability to resolve the structure of the - // child-IFD. Just install it as a normal tag rather than a - // fully-structured child-IFD. We're going to blank the value, - // though, since its original offset will no longer be valid - // (nor does it matter since this is just a temporary - // placeholder, in this situation). - value := NewIfdBuilderTagValueFromBytes([]byte{0, 0, 0, 0}) - bt = NewBuilderTag( - ite.IfdPath, - ite.TagId, - ite.TagType, - value, - ib.byteOrder) - } else { - // Figure out which of the child-IFDs that are associated with - // this IFD represents this specific child IFD. + // Figure out which of the child-IFDs that are associated with + // this IFD represents this specific child IFD. - var childIfd *Ifd - for _, thisChildIfd := range ifd.Children { - if thisChildIfd.ParentTagIndex != i { - continue - } else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId { - log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd) - } - - childIfd = thisChildIfd - break + var childIfd *Ifd + for _, thisChildIfd := range ifd.Children { + if thisChildIfd.ParentTagIndex != i { + continue + } else if thisChildIfd.TagId != 0xffff && thisChildIfd.TagId != ite.TagId { + log.Panicf("child-IFD tag is not correct: TAG-POSITION=(%d) ITE=%s CHILD-IFD=%s", thisChildIfd.ParentTagIndex, ite, thisChildIfd) } - if childIfd == nil { - childTagIds := make([]string, len(ifd.Children)) - for j, childIfd := range ifd.Children { - childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex) - } - - log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds) - } - - childIb := NewIfdBuilderFromExistingChain(childIfd, itevr) - bt = ib.NewBuilderTagFromBuilder(childIb) + childIfd = thisChildIfd + break } + + if childIfd == nil { + childTagIds := make([]string, len(ifd.Children)) + for j, childIfd := range ifd.Children { + childTagIds[j] = fmt.Sprintf("0x%04x (parent tag-position %d)", childIfd.TagId, childIfd.ParentTagIndex) + } + + log.Panicf("could not find child IFD for child ITE: IFD-PATH=[%s] TAG-ID=(0x%04x) CURRENT-TAG-POSITION=(%d) CHILDREN=%v", ite.IfdPath, ite.TagId, i, childTagIds) + } + + childIb := NewIfdBuilderFromExistingChain(childIfd, nil) + bt = ib.NewBuilderTagFromBuilder(childIb) } else { // Non-IFD tag. var value *IfdBuilderTagValue - // TODO(dustin): !! We should be able to dump (i.e. deimplement) the concept of itevr's and exclusively use ValueContext, now. + valueContext := newValueContextFromTag( + ite, + ifd.addressableData, + ifd.ByteOrder) - if itevr == nil { - // TODO(dustin): !! This might not make sense. The undefined-type data will just likely now have invalid value. + var rawBytes []byte - // rawValueOffsetCopy is our own private copy of the original data. - // It should always be four-bytes, but just copy whatever there is. - rawValueOffsetCopy := make([]byte, len(ite.RawValueOffset)) - copy(rawValueOffsetCopy, ite.RawValueOffset) + if ite.TagType == TypeUndefined { + // It's an undefined-type value. Try to process, or skip if + // we don't know how to. - value = NewIfdBuilderTagValueFromBytes(rawValueOffsetCopy) - } else { - valueContext := newValueContextFromTag( - ite, - ifd.addressableData, - ifd.ByteOrder) + x, err := valueContext.Undefined() + log.PanicIf(err) - var rawBytes []byte + // TODO(dustin): !! Add test for this. + _, isUnknownUndefined := x.(TagUnknownType_UnknownValue) - if ite.TagType == TypeUndefined { - // It's an undefined-type value. Try to process, or skip if - // we don't know how to. - - x, err := valueContext.Undefined() - log.PanicIf(err) - - // TODO(dustin): !! Add test for this. - _, isUnknownUndefined := x.(TagUnknownType_UnknownValue) - - if isUnknownUndefined == true { - continue - } - - undefined, ok := x.(UnknownTagValue) - if ok != true { - log.Panicf("unexpected value returned from undefined-value processor") - } - - rawBytes, err = undefined.ValueBytes() - log.PanicIf(err) - } else { - // It's a value with a standard type. - - var err error - - rawBytes, err = valueContext.readRawEncoded() - log.PanicIf(err) + if isUnknownUndefined == true { + continue } - value = NewIfdBuilderTagValueFromBytes(rawBytes) + undefined, ok := x.(UnknownTagValue) + if ok != true { + log.Panicf("unexpected value returned from undefined-value processor") + } + + rawBytes, err = undefined.ValueBytes() + log.PanicIf(err) + } else { + // It's a value with a standard type. + + var err error + + rawBytes, err = valueContext.readRawEncoded() + log.PanicIf(err) } + value = NewIfdBuilderTagValueFromBytes(rawBytes) + bt = NewBuilderTag( ifd.IfdPath, ite.TagId, diff --git a/ifd_builder_encode_test.go b/ifd_builder_encode_test.go index 5d43cf2..f2a8b12 100644 --- a/ifd_builder_encode_test.go +++ b/ifd_builder_encode_test.go @@ -3,7 +3,6 @@ package exif import ( "bytes" "fmt" - "reflect" "strings" "testing" @@ -562,97 +561,6 @@ func Test_IfdByteEncoder_encodeTagToBytes_simpleTag_allocate(t *testing.T) { } } -func getExifSimpleTestIb() *IfdBuilder { - im := NewIfdMapping() - - err := LoadStandardIfds(im) - log.PanicIf(err) - - ti := NewTagIndex() - ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) - - err = ib.AddStandard(0x000b, "asciivalue") - log.PanicIf(err) - - err = ib.AddStandard(0x00ff, []uint16{0x1122}) - log.PanicIf(err) - - err = ib.AddStandard(0x0100, []uint32{0x33445566}) - log.PanicIf(err) - - err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) - log.PanicIf(err) - - return ib -} - -func validateExifSimpleTestIb(exifData []byte, t *testing.T) { - im := NewIfdMapping() - - err := LoadStandardIfds(im) - log.PanicIf(err) - - ti := NewTagIndex() - - eh, index, err := Collect(im, ti, exifData) - log.PanicIf(err) - - if eh.ByteOrder != TestDefaultByteOrder { - t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder) - } else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset { - t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset) - } - - if len(index.Ifds) != 1 { - t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds)) - } - - ifd := index.RootIfd - - if ifd.ByteOrder != TestDefaultByteOrder { - t.Fatalf("IFD byte-order not correct.") - } else if ifd.IfdPath != IfdStandard { - t.Fatalf("IFD name not correct.") - } else if ifd.Index != 0 { - t.Fatalf("IFD index not zero: (%d)", ifd.Index) - } else if ifd.Offset != uint32(0x0008) { - t.Fatalf("IFD offset not correct.") - } else if len(ifd.Entries) != 4 { - t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries)) - } else if ifd.NextIfdOffset != uint32(0) { - t.Fatalf("Next-IFD offset is non-zero.") - } else if ifd.NextIfd != nil { - t.Fatalf("Next-IFD pointer is non-nil.") - } - - // Verify the values by using the actual, orginal types (this is awesome). - - addressableData := exifData[ExifAddressableAreaStart:] - - expected := []struct { - tagId uint16 - value interface{} - }{ - {tagId: 0x000b, value: "asciivalue"}, - {tagId: 0x00ff, value: []uint16{0x1122}}, - {tagId: 0x0100, value: []uint32{0x33445566}}, - {tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}}, - } - - for i, e := range ifd.Entries { - if e.TagId != expected[i].tagId { - t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId) - } - - value, err := e.Value(addressableData, TestDefaultByteOrder) - log.PanicIf(err) - - if reflect.DeepEqual(value, expected[i].value) != true { - t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value) - } - } -} - func Test_IfdByteEncoder_encodeIfdToBytes_simple(t *testing.T) { ib := getExifSimpleTestIb() diff --git a/ifd_builder_test.go b/ifd_builder_test.go index 3038d6b..aa87e0b 100644 --- a/ifd_builder_test.go +++ b/ifd_builder_test.go @@ -11,7 +11,7 @@ import ( "github.com/dsoprea/go-logging" ) -func TestAdd(t *testing.T) { +func TestIfdBuilder_Add(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -103,7 +103,7 @@ func TestAdd(t *testing.T) { } } -func TestSetNextIb(t *testing.T) { +func TestIfdBuilder_SetNextIb(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -128,7 +128,7 @@ func TestSetNextIb(t *testing.T) { } } -func TestAddChildIb(t *testing.T) { +func TestIfdBuilder_AddChildIb(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -172,160 +172,120 @@ func TestAddChildIb(t *testing.T) { } } -func TestAddTagsFromExisting(t *testing.T) { +func TestIfdBuilder_AddTagsFromExisting(t *testing.T) { defer func() { if state := recover(); state != nil { err := log.Wrap(state.(error)) - log.PrintErrorf(err, "Test failure.") + log.PrintError(err) + + t.Fatalf("Test failure.") } }() + exifData := getExifSimpleTestIbBytes() + im := NewIfdMapping() err := LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() - ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) - entries := make([]*IfdTagEntry, 3) - - entries[0] = &IfdTagEntry{ - IfdPath: IfdPathStandardExif, - TagId: 0x11, - TagType: TypeByte, - UnitCount: 4, - RawValueOffset: []byte{0x12, 0, 0, 0}, - } - - entries[1] = &IfdTagEntry{ - IfdPath: IfdPathStandardExif, - TagId: 0x22, - TagType: TypeLong, - ChildIfdPath: "some ifd", - } - - entries[2] = &IfdTagEntry{ - IfdPath: IfdPathStandardExif, - TagId: 0x33, - TagType: TypeByte, - UnitCount: 4, - RawValueOffset: []byte{0x34, 0, 0, 0}, - } - - ifd := &Ifd{ - IfdPath: IfdPathStandard, - Entries: entries, - tagIndex: ti, - } - - err = ib.AddTagsFromExisting(ifd, nil, nil, nil) + _, index, err := Collect(im, ti, exifData) log.PanicIf(err) - if ib.tags[0].tagId != 0x11 { - t.Fatalf("tag (0) not correct") - } else if ib.tags[1].tagId != 0x22 { - t.Fatalf("tag (1) not correct") - } else if ib.tags[2].tagId != 0x33 { - t.Fatalf("tag (2) not correct") - } else if len(ib.tags) != 3 { - t.Fatalf("tag count not correct") + ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) + + err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, nil) + log.PanicIf(err) + + expected := []uint16{ + 0x000b, + 0x00ff, + 0x0100, + 0x013e, + } + + if len(ib.tags) != len(expected) { + t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected)) + } + + for i, tag := range ib.tags { + if tag.tagId != expected[i] { + t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i]) + } } } -func TestAddTagsFromExisting__Includes(t *testing.T) { +func TestIfdBuilder_AddTagsFromExisting__Includes(t *testing.T) { + exifData := getExifSimpleTestIbBytes() + im := NewIfdMapping() err := LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() - ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) - entries := make([]*IfdTagEntry, 3) - - entries[0] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x11, - } - - entries[1] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x22, - ChildIfdPath: "some ifd", - } - - entries[2] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x33, - } - - ifd := &Ifd{ - IfdPath: IfdPathStandard, - Entries: entries, - tagIndex: ti, - } - - err = ib.AddTagsFromExisting(ifd, nil, []uint16{0x33}, nil) + _, index, err := Collect(im, ti, exifData) log.PanicIf(err) - if ib.tags[0].tagId != 0x33 { - t.Fatalf("tag (1) not correct") - } else if len(ib.tags) != 1 { - t.Fatalf("tag count not correct") + ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) + + err = ib.AddTagsFromExisting(index.RootIfd, nil, []uint16{0x00ff}, nil) + log.PanicIf(err) + + expected := []uint16{ + 0x00ff, + } + + if len(ib.tags) != len(expected) { + t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected)) + } + + for i, tag := range ib.tags { + if tag.tagId != expected[i] { + t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i]) + } } } -func TestAddTagsFromExisting__Excludes(t *testing.T) { +func TestIfdBuilder_AddTagsFromExisting__Excludes(t *testing.T) { + exifData := getExifSimpleTestIbBytes() + im := NewIfdMapping() err := LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() - ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) - entries := make([]*IfdTagEntry, 3) - - entries[0] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x11, - } - - entries[1] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x22, - ChildIfdPath: "some ifd", - } - - entries[2] = &IfdTagEntry{ - IfdPath: IfdPathStandard, - TagType: TypeByte, - TagId: 0x33, - } - - ifd := &Ifd{ - IfdPath: IfdPathStandard, - Entries: entries, - tagIndex: ti, - } - - err = ib.AddTagsFromExisting(ifd, nil, nil, []uint16{0x11}) + _, index, err := Collect(im, ti, exifData) log.PanicIf(err) - if ib.tags[0].tagId != 0x22 { - t.Fatalf("tag not correct") - } else if len(ib.tags) != 2 { - t.Fatalf("tag count not correct") + ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) + + err = ib.AddTagsFromExisting(index.RootIfd, nil, nil, []uint16{0xff}) + log.PanicIf(err) + + expected := []uint16{ + 0x000b, + 0x0100, + 0x013e, + } + + if len(ib.tags) != len(expected) { + t.Fatalf("Tag count not correct: (%d) != (%d)", len(ib.tags), len(expected)) + } + + for i, tag := range ib.tags { + if tag.tagId != expected[i] { + t.Fatalf("Tag (%d) not correct: (0x%04x) != (0x%04x)", i, tag.tagId, expected[i]) + } } } -func TestFindN_First_1(t *testing.T) { +func TestIfdBuilder_FindN__First_1(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -381,7 +341,7 @@ func TestFindN_First_1(t *testing.T) { } } -func TestFindN_First_2_1Returned(t *testing.T) { +func TestIfdBuilder_FindN__First_2_1Returned(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -437,7 +397,7 @@ func TestFindN_First_2_1Returned(t *testing.T) { } } -func TestFindN_First_2_2Returned(t *testing.T) { +func TestIfdBuilder_FindN__First_2_2Returned(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -520,7 +480,7 @@ func TestFindN_First_2_2Returned(t *testing.T) { } } -func TestFindN_Middle_WithDuplicates(t *testing.T) { +func TestIfdBuilder_FindN__Middle_WithDuplicates(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -606,7 +566,7 @@ func TestFindN_Middle_WithDuplicates(t *testing.T) { } } -func TestFindN_Middle_NoDuplicates(t *testing.T) { +func TestIfdBuilder_FindN__Middle_NoDuplicates(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -672,7 +632,7 @@ func TestFindN_Middle_NoDuplicates(t *testing.T) { } } -func TestFindN_Miss(t *testing.T) { +func TestIfdBuilder_FindN__Miss(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -689,7 +649,7 @@ func TestFindN_Miss(t *testing.T) { } } -func TestFind_Hit(t *testing.T) { +func TestIfdBuilder_Find__Hit(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -753,7 +713,7 @@ func TestFind_Hit(t *testing.T) { } } -func TestFind_Miss(t *testing.T) { +func TestIfdBuilder_Find__Miss(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -810,7 +770,7 @@ func TestFind_Miss(t *testing.T) { } } -func TestReplace(t *testing.T) { +func TestIfdBuilder_Replace(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -878,7 +838,7 @@ func TestReplace(t *testing.T) { } } -func TestReplaceN(t *testing.T) { +func TestIfdBuilder_ReplaceN(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -946,7 +906,7 @@ func TestReplaceN(t *testing.T) { } } -func TestDeleteFirst(t *testing.T) { +func TestIfdBuilder_DeleteFirst(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1048,7 +1008,7 @@ func TestDeleteFirst(t *testing.T) { } } -func TestDeleteN(t *testing.T) { +func TestIfdBuilder_DeleteN(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1150,7 +1110,7 @@ func TestDeleteN(t *testing.T) { } } -func TestDeleteN_Two(t *testing.T) { +func TestIfdBuilder_DeleteN_Two(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1236,7 +1196,7 @@ func TestDeleteN_Two(t *testing.T) { } } -func TestDeleteAll(t *testing.T) { +func TestIfdBuilder_DeleteAll(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1324,7 +1284,7 @@ func TestDeleteAll(t *testing.T) { } } -func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) { +func TestIfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) { defer func() { if state := recover(); state != nil { err := log.Wrap(state.(error)) @@ -1427,7 +1387,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain(t *testing.T) { // TODO(dustin): !! Test with an actual GPS-attached image. -func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) { +func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) { filepath := path.Join(assetsPath, "NDM_8901.jpg") rawExif, err := SearchFileAndExtractExif(filepath) @@ -1546,7 +1506,7 @@ func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData(t *testing.T) { } } -// func Test_IfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) { +// func TestIfdBuilder_CreateIfdBuilderFromExistingChain_RealData_WithUpdate(t *testing.T) { // filepath := path.Join(assetsPath, "NDM_8901.jpg") // rawExif, err := SearchFileAndExtractExif(filepath) @@ -1843,7 +1803,7 @@ func ExampleIfdBuilder_SetStandardWithName() { // alternative software } -func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) { +func TestIfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) { ti := NewTagIndex() im := NewIfdMapping() @@ -1884,7 +1844,7 @@ func Test_IfdBuilder_CreateIfdBuilderWithExistingIfd(t *testing.T) { } } -func TestNewStandardBuilderTag_OneUnit(t *testing.T) { +func TestNewStandardBuilderTag__OneUnit(t *testing.T) { ti := NewTagIndex() it, err := ti.Get(IfdPathStandardExif, uint16(0x8833)) @@ -1901,7 +1861,7 @@ func TestNewStandardBuilderTag_OneUnit(t *testing.T) { } } -func TestNewStandardBuilderTag_TwoUnits(t *testing.T) { +func TestNewStandardBuilderTag__TwoUnits(t *testing.T) { ti := NewTagIndex() it, err := ti.Get(IfdPathStandardExif, uint16(0x8833)) @@ -1920,7 +1880,7 @@ func TestNewStandardBuilderTag_TwoUnits(t *testing.T) { } } -func TestAddStandardWithName(t *testing.T) { +func TestIfdBuilder_AddStandardWithName(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1951,7 +1911,7 @@ func TestAddStandardWithName(t *testing.T) { } } -func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) { +func TestGetOrCreateIbFromRootIb__Noop(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -1972,7 +1932,7 @@ func TestGetOrCreateIbFromRootIb_Noop(t *testing.T) { } } -func TestGetOrCreateIbFromRootIb_FqNoop(t *testing.T) { +func TestGetOrCreateIbFromRootIb__FqNoop(t *testing.T) { im := NewIfdMapping() err := LoadStandardIfds(im) @@ -2010,7 +1970,7 @@ func TestGetOrCreateIbFromRootIb_InvalidChild(t *testing.T) { } } -func TestGetOrCreateIbFromRootIb_Child(t *testing.T) { +func TestGetOrCreateIbFromRootIb__Child(t *testing.T) { defer func() { if state := recover(); state != nil { err := log.Wrap(state.(error)) diff --git a/testing_common.go b/testing_common.go new file mode 100644 index 0000000..25fd8ea --- /dev/null +++ b/testing_common.go @@ -0,0 +1,149 @@ +package exif + +import ( + "reflect" + "testing" + + "github.com/dsoprea/go-logging" +) + +func getExifSimpleTestIb() *IfdBuilder { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.Panic(err) + } + }() + + im := NewIfdMapping() + + err := LoadStandardIfds(im) + log.PanicIf(err) + + ti := NewTagIndex() + ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) + + err = ib.AddStandard(0x000b, "asciivalue") + log.PanicIf(err) + + err = ib.AddStandard(0x00ff, []uint16{0x1122}) + log.PanicIf(err) + + err = ib.AddStandard(0x0100, []uint32{0x33445566}) + log.PanicIf(err) + + err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) + log.PanicIf(err) + + return ib +} + +func getExifSimpleTestIbBytes() []byte { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.Panic(err) + } + }() + + im := NewIfdMapping() + + err := LoadStandardIfds(im) + log.PanicIf(err) + + ti := NewTagIndex() + ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder) + + err = ib.AddStandard(0x000b, "asciivalue") + log.PanicIf(err) + + err = ib.AddStandard(0x00ff, []uint16{0x1122}) + log.PanicIf(err) + + err = ib.AddStandard(0x0100, []uint32{0x33445566}) + log.PanicIf(err) + + err = ib.AddStandard(0x013e, []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}) + log.PanicIf(err) + + ibe := NewIfdByteEncoder() + + exifData, err := ibe.EncodeToExif(ib) + log.PanicIf(err) + + return exifData +} + +func validateExifSimpleTestIb(exifData []byte, t *testing.T) { + defer func() { + if state := recover(); state != nil { + err := log.Wrap(state.(error)) + log.Panic(err) + } + }() + + im := NewIfdMapping() + + err := LoadStandardIfds(im) + log.PanicIf(err) + + ti := NewTagIndex() + + eh, index, err := Collect(im, ti, exifData) + log.PanicIf(err) + + if eh.ByteOrder != TestDefaultByteOrder { + t.Fatalf("EXIF byte-order is not correct: %v", eh.ByteOrder) + } else if eh.FirstIfdOffset != ExifDefaultFirstIfdOffset { + t.Fatalf("EXIF first IFD-offset not correct: (0x%02x)", eh.FirstIfdOffset) + } + + if len(index.Ifds) != 1 { + t.Fatalf("There wasn't exactly one IFD decoded: (%d)", len(index.Ifds)) + } + + ifd := index.RootIfd + + if ifd.ByteOrder != TestDefaultByteOrder { + t.Fatalf("IFD byte-order not correct.") + } else if ifd.IfdPath != IfdStandard { + t.Fatalf("IFD name not correct.") + } else if ifd.Index != 0 { + t.Fatalf("IFD index not zero: (%d)", ifd.Index) + } else if ifd.Offset != uint32(0x0008) { + t.Fatalf("IFD offset not correct.") + } else if len(ifd.Entries) != 4 { + t.Fatalf("IFD number of entries not correct: (%d)", len(ifd.Entries)) + } else if ifd.NextIfdOffset != uint32(0) { + t.Fatalf("Next-IFD offset is non-zero.") + } else if ifd.NextIfd != nil { + t.Fatalf("Next-IFD pointer is non-nil.") + } + + // Verify the values by using the actual, orginal types (this is awesome). + + addressableData := exifData[ExifAddressableAreaStart:] + + expected := []struct { + tagId uint16 + value interface{} + }{ + {tagId: 0x000b, value: "asciivalue"}, + {tagId: 0x00ff, value: []uint16{0x1122}}, + {tagId: 0x0100, value: []uint32{0x33445566}}, + {tagId: 0x013e, value: []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}}}, + } + + for i, e := range ifd.Entries { + if e.TagId != expected[i].tagId { + t.Fatalf("Tag-ID for entry (%d) not correct: (0x%02x) != (0x%02x)", i, e.TagId, expected[i].tagId) + } + + value, err := e.Value(addressableData, TestDefaultByteOrder) + log.PanicIf(err) + + if reflect.DeepEqual(value, expected[i].value) != true { + t.Fatalf("Value for entry (%d) not correct: [%v] != [%v]", i, value, expected[i].value) + } + } +}