ios/SpectrumKit/SpectrumKitTests/FSPImageMetadataTests.mm (177 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
#import <ImageIO/ImageIO.h>
#import <XCTest/XCTest.h>
#import <SpectrumKit/FSPImageMetadata.h>
#import <SpectrumKit/FSPImageMetadata_Private.h>
using namespace facebook::spectrum::image;
using namespace facebook::spectrum::image::metadata;
@interface FSPImageMetadataTests : XCTestCase
@end
@implementation FSPImageMetadataTests
- (void)testNoneIsReturnedOnEmpty
{
const auto metadata = [FSPImageMetadata imageMetadataWithDictionary:@{
(NSString *)kCGImagePropertyTIFFDictionary: @{},
(NSString *)kCGImagePropertyExifDictionary: @{},
(NSString *)kCGImagePropertyGPSDictionary: @{},
}];
XCTAssertTrue([metadata makeInternalMetadata] == Metadata());
}
- (void)testStringValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyTIFFDictionary: @{
(NSString *)kCGImagePropertyTIFFMake: @"Facebook",
},
}];
const auto tiffEntries = entries.tiff();
const auto makeValue = tiffEntries.at(Entry::MAKE).valueAsAsciiString();
XCTAssertEqual(makeValue, "Facebook");
}
- (void)testByteValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyGPSDictionary: @{
(NSString *)kCGImagePropertyGPSVersion: @CHAR_MAX,
},
}];
const auto gpsEntries = entries.gps();
const auto gpsVersion = gpsEntries.at(Entry::GPS_VERSION_ID).valueAsByte();
XCTAssertEqual(gpsVersion, CHAR_MAX);
}
- (void)testShortValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyTIFFDictionary: @{
(NSString *)kCGImagePropertyTIFFOrientation: @SHRT_MAX,
},
}];
const auto tiffEntries = entries.tiff();
const auto orientationValue = tiffEntries.at(Entry::ORIENTATION).valueAsShort();
XCTAssertEqual(orientationValue, SHRT_MAX);
}
- (void)testLongValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyExifDictionary: @{
(NSString *)kCGImagePropertyExifISOSpeed: @UINT_MAX,
},
}];
const auto exifEntries = entries.exif();
const auto isoSpeed = exifEntries.at(Entry::ISO_SPEED).valueAsLong();
XCTAssertEqual(isoSpeed, UINT_MAX);
}
- (void)testRationalValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyExifDictionary: @{
(NSString *)kCGImagePropertyExifGamma: @42.43,
},
}];
const auto exifEntries = entries.exif();
const auto gamma = exifEntries.at(Entry::GAMMA).valueAsRational();
XCTAssertEqual(gamma.numerator, std::uint32_t{4238034007});
XCTAssertEqual(gamma.denominator, std::uint32_t{99882960});
}
- (void)testSRationalValue
{
const auto entries = [self testValuesWithMetadataDictionary:@{
(NSString *)kCGImagePropertyExifDictionary: @{
(NSString *)kCGImagePropertyExifShutterSpeedValue: @-42.43,
},
}];
const auto exifEntries = entries.exif();
const auto shutterSpeed = exifEntries.at(Entry::SHUTTER_SPEED_VALUE).valueAsSRational();
XCTAssertEqual(shutterSpeed.numerator, -2119017004);
XCTAssertEqual(shutterSpeed.denominator, 49941480);
}
#pragma mark - Conversion
- (void)testConversionLowestDecimalToUnsignedRational
{
const auto value = std::numeric_limits<std::uint32_t>::lowest() + (1.0 / 3.0);
const auto rational = FSPRationalFromValue<std::uint32_t>(@(value));
XCTAssertLessThanOrEqual(std::abs(rational.value() - value), std::numeric_limits<double>::epsilon());
}
- (void)testConversionHighestDecimalToUnsignedRational
{
const auto value = std::numeric_limits<std::uint32_t>::max() - 1 + (1.0 / 3.0);
const auto rational = FSPRationalFromValue<std::uint32_t>(@(value));
XCTAssertEqual(rational.value(), std::numeric_limits<std::uint32_t>::max() - 1);
}
- (void)testConversionLowestDecimalToSignedRational
{
const auto value = std::numeric_limits<int32_t>::lowest() + (1.0 / 3.0);
const auto rational = FSPRationalFromValue<int32_t>(@(value));
XCTAssertEqual(rational.value(), std::numeric_limits<int32_t>::lowest() + 1);
}
- (void)testConversionHighestDecimalToSignedRational
{
const auto value = std::numeric_limits<int32_t>::max() - 1 + (1.0 / 3.0);
const auto rational = FSPRationalFromValue<int32_t>(@(value));
XCTAssertEqual(rational.value(), std::numeric_limits<int32_t>::max() - 1);
}
- (void)testConversionBoundsChecks
{
XCTAssertEqual(FSPRationalFromValue<int32_t>(@0).value(), 0.0);
XCTAssertEqual(FSPRationalFromValue<std::uint32_t>(@0).value(), 0.0);
XCTAssertEqual(FSPRationalFromValue<int32_t>(@(std::numeric_limits<double>::min())).value(), 0.0);
XCTAssertEqual(FSPRationalFromValue<std::uint32_t>(@(std::numeric_limits<double>::min())).value(), 0.0);
XCTAssertEqual(FSPRationalFromValue<int32_t>(@(-std::numeric_limits<double>::min())).value(), 0.0);
XCTAssertEqual(FSPRationalFromValue<std::uint32_t>(@(-std::numeric_limits<double>::min())).value(), 0.0);
}
- (void)testConversionOfUnsignedInts
{
auto result = FSPInternalValuesFromNumberValues<std::uint32_t>(@[@1, @3, @42]);
XCTAssertEqual(result, std::vector<std::uint32_t>({1, 3, 42}));
result = FSPInternalValuesFromNumberValues<std::uint32_t>(@42);
XCTAssertEqual(result, std::vector<std::uint32_t>({42}));
}
- (void)testConversionOfSignedInts
{
auto result = FSPInternalValuesFromNumberValues<int32_t>(@[@-1, @3, @-42]);
XCTAssertEqual(result, std::vector<int32_t>({-1, 3, -42}));
result = FSPInternalValuesFromNumberValues<int32_t>(@-42);
XCTAssertEqual(result, std::vector<int32_t>({-42}));
}
- (void)testConversionOfLatitude
{
const auto result = FBInternalRationalsFromDecimalAngleValue<std::uint32_t>(@144.9410933);
const auto expectedResult = std::vector<Rational>{{144, 1}, {56, 1}, {2793, 100}};
// value = (144 / 1) + ((56 / 1) / 60) + ((2793 / 100) / 3600)
XCTAssertTrue(result == expectedResult);
}
#pragma mark - Copy
- (void)testCopyIsEqual
{
const auto object = [FSPImageMetadata imageMetadataWithDictionary:@{}];
XCTAssertEqualObjects(object, [object copy]);
}
#pragma mark - Equality
- (void)testIsEqual
{
const auto object = [FSPImageMetadata imageMetadataWithDictionary:@{}];
const auto object2 = [FSPImageMetadata imageMetadataWithDictionary:@{}];
XCTAssertEqualObjects(object, object2);
}
- (void)testIsNotEqualOnDifferentDictionary
{
const auto object = [FSPImageMetadata imageMetadataWithDictionary:@{}];
const auto object2 = FSPMakeDefaultMetadata();
XCTAssertNotEqualObjects(object, object2);
}
#pragma mark - Helpers
- (Entries)testValuesWithMetadataDictionary:(NSDictionary<NSString *, id> *)metadataDictionary
{
const auto metadata = [FSPImageMetadata imageMetadataWithDictionary:metadataDictionary];
return [metadata makeInternalMetadata].entries();
}
static FSPImageMetadata *FSPMakeDefaultMetadata()
{
const auto metadataDictionary = @{
(NSString *)kCGImagePropertyTIFFDictionary: @{
(NSString *)kCGImagePropertyTIFFMake: @"Facebook",
},
(NSString *)kCGImagePropertyExifDictionary: @{},
(NSString *)kCGImagePropertyGPSDictionary: @{},
};
return [FSPImageMetadata imageMetadataWithDictionary:metadataDictionary];
}
@end