aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Van Lenten <thomasvl@google.com>2017-01-12 17:13:10 -0500
committerBo Yang <teboring@google.com>2017-01-31 13:56:29 -0800
commit4aa2e9312ebb594eb60882a7ff874310a6166717 (patch)
tree76f188cc3da4e0a9cf8c6b4557f4e717238d39c0
parent593e917c176b5bc5aafa57bf9f6030d749d91cd5 (diff)
downloadprotobuf-4aa2e9312ebb594eb60882a7ff874310a6166717.tar.gz
protobuf-4aa2e9312ebb594eb60882a7ff874310a6166717.tar.bz2
protobuf-4aa2e9312ebb594eb60882a7ff874310a6166717.zip
Timestamp helper fix, Duration helper cleanup.
- The Timestamp proto does not allow for negative nanos fields, so the seconds must be shifted and a positive nanos then applied. - Tweak the helpers on Duration to make it clear there is no "base" time involved. - Update the unittests for duration and timestamp to cover positive and negative NSTimeIntervals and what their impact is on the protos.
-rw-r--r--objectivec/GPBWellKnownTypes.h17
-rw-r--r--objectivec/GPBWellKnownTypes.m52
-rw-r--r--objectivec/Tests/GPBWellKnownTypesTest.m162
3 files changed, 160 insertions, 71 deletions
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 90d96c6f..04df4178 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -112,16 +112,27 @@ typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
* @note: Not all second/nanos combinations can be represented in a
* NSTimeInterval, so getting this could be a lossy transform.
**/
-@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
+@property(nonatomic, readwrite) NSTimeInterval timeInterval;
/**
* Initializes a GPBDuration with the given NSTimeInterval.
*
- * @param timeIntervalSince1970 Time interval to configure the GPBDuration with.
+ * @param timeInterval Time interval to configure the GPBDuration with.
*
* @return A newly initialized GPBDuration.
**/
-- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
+- (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval;
+
+// These next two methods are deprecated because GBPDuration has no need of a
+// "base" time. The older methods were about symmetry with GBPTimestamp, but
+// the unix epoch usage is too confusing.
+
+/** Deprecated, use timeInterval instead. */
+@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970
+ __attribute__((deprecated("Use timeInterval")));
+/** Deprecated, use initWithTimeInterval: instead. */
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970
+ __attribute__((deprecated("Use initWithTimeInterval:")));
@end
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index ed798a2e..2808afeb 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -41,15 +41,25 @@ NSString *const GPBWellKnownTypesErrorDomain =
static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
-static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
- int32_t nanos) {
+static NSTimeInterval TimeIntervalFromSecondsAndNanos(int64_t seconds,
+ int32_t nanos) {
return seconds + (NSTimeInterval)nanos / 1e9;
}
-static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time,
- int64_t *outSeconds) {
+static int32_t SecondsAndNanosFromTimeInterval(NSTimeInterval time,
+ int64_t *outSeconds,
+ BOOL nanosMustBePositive) {
NSTimeInterval seconds;
NSTimeInterval nanos = modf(time, &seconds);
+
+ if (nanosMustBePositive && (nanos < 0)) {
+ // Per Timestamp.proto, nanos is non-negative and "Negative second values with
+ // fractions must still have non-negative nanos values that count forward in
+ // time. Must be from 0 to 999,999,999 inclusive."
+ --seconds;
+ nanos = 1.0 + nanos;
+ }
+
nanos *= 1e9;
*outSeconds = (int64_t)seconds;
return (int32_t)nanos;
@@ -88,8 +98,8 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
if ((self = [super init])) {
int64_t seconds;
- int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970(
- timeIntervalSince1970, &seconds);
+ int32_t nanos = SecondsAndNanosFromTimeInterval(
+ timeIntervalSince1970, &seconds, YES);
self.seconds = seconds;
self.nanos = nanos;
}
@@ -105,13 +115,13 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
}
- (NSTimeInterval)timeIntervalSince1970 {
- return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos);
+ return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
}
- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
int64_t seconds;
int32_t nanos =
- SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds);
+ SecondsAndNanosFromTimeInterval(timeIntervalSince1970, &seconds, YES);
self.seconds = seconds;
self.nanos = nanos;
}
@@ -122,29 +132,41 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
@implementation GPBDuration (GBPWellKnownTypes)
-- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+- (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval {
if ((self = [super init])) {
int64_t seconds;
- int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970(
- timeIntervalSince1970, &seconds);
+ int32_t nanos = SecondsAndNanosFromTimeInterval(
+ timeInterval, &seconds, NO);
self.seconds = seconds;
self.nanos = nanos;
}
return self;
}
-- (NSTimeInterval)timeIntervalSince1970 {
- return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos);
+- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+ return [self initWithTimeInterval:timeIntervalSince1970];
}
-- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+- (NSTimeInterval)timeInterval {
+ return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
+}
+
+- (void)setTimeInterval:(NSTimeInterval)timeInterval {
int64_t seconds;
int32_t nanos =
- SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds);
+ SecondsAndNanosFromTimeInterval(timeInterval, &seconds, NO);
self.seconds = seconds;
self.nanos = nanos;
}
+- (NSTimeInterval)timeIntervalSince1970 {
+ return self.timeInterval;
+}
+
+- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
+ self.timeInterval = timeIntervalSince1970;
+}
+
@end
#pragma mark - GPBAny
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 041841dd..592d5afd 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -32,11 +32,9 @@
#import <XCTest/XCTest.h>
+#import "GPBTestUtilities.h"
#import "google/protobuf/AnyTest.pbobjc.h"
-// A basically random interval into the future for testing with.
-static const NSTimeInterval kFutureOffsetInterval = 15000;
-
// Nanosecond time accuracy
static const NSTimeInterval kTimeAccuracy = 1e-9;
@@ -46,59 +44,117 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
@implementation WellKnownTypesTest
- (void)testTimeStamp {
- // Test Creation.
- NSDate *date = [NSDate date];
- GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date];
- NSDate *timeStampDate = timeStamp.date;
-
- // Comparing timeIntervals instead of directly comparing dates because date
- // equality requires the time intervals to be exactly the same, and the
- // timeintervals go through a bit of floating point error as they are
- // converted back and forth from the internal representation.
- XCTAssertEqualWithAccuracy(date.timeIntervalSince1970,
- timeStampDate.timeIntervalSince1970,
- kTimeAccuracy);
-
- NSTimeInterval time = [date timeIntervalSince1970];
- GPBTimestamp *timeStamp2 =
- [[GPBTimestamp alloc] initWithTimeIntervalSince1970:time];
- NSTimeInterval durationTime = timeStamp2.timeIntervalSince1970;
- XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
- [timeStamp release];
-
- // Test Mutation.
- date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval];
- timeStamp2.date = date;
- timeStampDate = timeStamp2.date;
- XCTAssertEqualWithAccuracy(date.timeIntervalSince1970,
- timeStampDate.timeIntervalSince1970,
- kTimeAccuracy);
-
- time = date.timeIntervalSince1970;
- timeStamp2.timeIntervalSince1970 = time;
- durationTime = timeStamp2.timeIntervalSince1970;
- XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
- [timeStamp2 release];
+ // Test negative and positive values.
+ NSTimeInterval values[] = {
+ -428027599.483999967, -1234567.0, -0.5, 0, 0.75, 54321.0, 2468086,483999967
+ };
+ for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+ NSTimeInterval value = values[i];
+
+ // Test Creation - date.
+ NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];
+ GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date];
+
+ XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
+ @"Offset %f - Date: %@", (double)value, date);
+ XCTAssertLessThan(timeStamp.nanos, 1e9,
+ @"Offset %f - Date: %@", (double)value, date);
+
+ // Comparing timeIntervals instead of directly comparing dates because date
+ // equality requires the time intervals to be exactly the same, and the
+ // timeintervals go through a bit of floating point error as they are
+ // converted back and forth from the internal representation.
+ XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
+ kTimeAccuracy,
+ @"Offset %f - Date: %@", (double)value, date);
+ [timeStamp release];
+
+ // Test Creation - timeIntervalSince1970.
+ timeStamp = [[GPBTimestamp alloc] initWithTimeIntervalSince1970:value];
+
+ XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
+ @"Offset %f - Date: %@", (double)value, date);
+ XCTAssertLessThan(timeStamp.nanos, 1e9,
+ @"Offset %f - Date: %@", (double)value, date);
+
+ XCTAssertEqualWithAccuracy(value, timeStamp.timeIntervalSince1970,
+ kTimeAccuracy,
+ @"Offset %f - Date: %@", (double)value, date);
+ [timeStamp release];
+
+ // Test Mutation - date.
+ timeStamp = [[GPBTimestamp alloc] init];
+ timeStamp.date = date;
+
+ XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
+ @"Offset %f - Date: %@", (double)value, date);
+ XCTAssertLessThan(timeStamp.nanos, 1e9,
+ @"Offset %f - Date: %@", (double)value, date);
+
+ XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
+ kTimeAccuracy,
+ @"Offset %f - Date: %@", (double)value, date);
+ [timeStamp release];
+
+ // Test Mutation - timeIntervalSince1970.
+ timeStamp = [[GPBTimestamp alloc] init];
+ timeStamp.timeIntervalSince1970 = value;
+
+ XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
+ @"Offset %f - Date: %@", (double)value, date);
+ XCTAssertLessThan(timeStamp.nanos, 1e9,
+ @"Offset %f - Date: %@", (double)value, date);
+
+ XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
+ kTimeAccuracy,
+ @"Offset %f - Date: %@", (double)value, date);
+
+ [timeStamp release];
+ }
}
- (void)testDuration {
- // Test Creation.
- NSTimeInterval time = [[NSDate date] timeIntervalSince1970];
- GPBDuration *duration =
- [[GPBDuration alloc] initWithTimeIntervalSince1970:time];
- NSTimeInterval durationTime = duration.timeIntervalSince1970;
- XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
- [duration release];
-
- // Test Mutation.
- GPBDuration *duration2 =
- [[GPBDuration alloc] initWithTimeIntervalSince1970:time];
- NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval];
- time = date.timeIntervalSince1970;
- duration2.timeIntervalSince1970 = time;
- durationTime = duration2.timeIntervalSince1970;
- XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy);
- [duration2 release];
+ // Test negative and positive values.
+ NSTimeInterval values[] = { -1000.0001, -500.0, -0.5, 0, 0.75, 1000.0, 2000.0002 };
+ for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+ NSTimeInterval value = values[i];
+
+ // Test Creation.
+ GPBDuration *duration =
+ [[GPBDuration alloc] initWithTimeInterval:value];
+ XCTAssertEqualWithAccuracy(value, duration.timeInterval, kTimeAccuracy,
+ @"For interval %f", (double)value);
+ if (value > 0) {
+ XCTAssertGreaterThanOrEqual(duration.seconds, 0,
+ @"For interval %f", (double)value);
+ XCTAssertGreaterThanOrEqual(duration.nanos, 0,
+ @"For interval %f", (double)value);
+ } else {
+ XCTAssertLessThanOrEqual(duration.seconds, 0,
+ @"For interval %f", (double)value);
+ XCTAssertLessThanOrEqual(duration.nanos, 0,
+ @"For interval %f", (double)value);
+ }
+ [duration release];
+
+ // Test Mutation.
+ duration = [[GPBDuration alloc] init];
+ duration.timeInterval = value;
+ XCTAssertEqualWithAccuracy(value, duration.timeInterval, kTimeAccuracy,
+ @"For interval %f", (double)value);
+ if (value > 0) {
+ XCTAssertGreaterThanOrEqual(duration.seconds, 0,
+ @"For interval %f", (double)value);
+ XCTAssertGreaterThanOrEqual(duration.nanos, 0,
+ @"For interval %f", (double)value);
+ } else {
+ XCTAssertLessThanOrEqual(duration.seconds, 0,
+ @"For interval %f", (double)value);
+ XCTAssertLessThanOrEqual(duration.nanos, 0,
+ @"For interval %f", (double)value);
+ }
+ [duration release];
+ }
}
- (void)testAnyHelpers {