Skip to content

Commit c1d940d

Browse files
John BrownleeJohn Brownlee
John Brownlee
authored and
John Brownlee
committed
Adds a mapping for the leap month field when getting date components in NSCalendar.
Fixes a crash caused by trying to deallocate a CFCalendar that hadn't been fully initialized. Re-enables support for the Chinese calendar. Adds tests for initializaing NSCalendar and fetching basic date info.
1 parent 58cfe37 commit c1d940d

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

CoreFoundation/Locale.subproj/CFCalendar.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ static CFStringRef __CFCalendarCopyDescription(CFTypeRef cf) {
4949

5050
static void __CFCalendarDeallocate(CFTypeRef cf) {
5151
CFCalendarRef calendar = (CFCalendarRef)cf;
52-
CFRelease(calendar->_identifier);
52+
if (calendar->_identifier) CFRelease(calendar->_identifier);
5353
if (calendar->_locale) CFRelease(calendar->_locale);
5454
if (calendar->_localeID) CFRelease(calendar->_localeID);
55-
CFRelease(calendar->_tz);
55+
if (calendar->_tz) CFRelease(calendar->_tz);
5656
if (calendar->_cal) ucal_close(calendar->_cal);
5757
}
5858

@@ -236,15 +236,14 @@ CFCalendarRef CFCalendarCopyCurrent(void) {
236236
}
237237

238238
Boolean _CFCalendarInitWithIdentifier(CFCalendarRef calendar, CFStringRef identifier) {
239-
if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar) {
240-
// if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) {
239+
if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) {
241240
if (CFEqual(kCFGregorianCalendar, identifier)) identifier = kCFGregorianCalendar;
242241
else if (CFEqual(kCFBuddhistCalendar, identifier)) identifier = kCFBuddhistCalendar;
243242
else if (CFEqual(kCFJapaneseCalendar, identifier)) identifier = kCFJapaneseCalendar;
244243
else if (CFEqual(kCFIslamicCalendar, identifier)) identifier = kCFIslamicCalendar;
245244
else if (CFEqual(kCFIslamicCivilCalendar, identifier)) identifier = kCFIslamicCivilCalendar;
246245
else if (CFEqual(kCFHebrewCalendar, identifier)) identifier = kCFHebrewCalendar;
247-
// else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar;
246+
else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar;
248247
else return false;
249248
}
250249

@@ -261,15 +260,14 @@ CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringR
261260
__CFGenericValidateType(allocator, CFAllocatorGetTypeID());
262261
__CFGenericValidateType(identifier, CFStringGetTypeID());
263262
// return NULL until Chinese calendar is available
264-
if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar) {
265-
// if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) {
263+
if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) {
266264
if (CFEqual(kCFGregorianCalendar, identifier)) identifier = kCFGregorianCalendar;
267265
else if (CFEqual(kCFBuddhistCalendar, identifier)) identifier = kCFBuddhistCalendar;
268266
else if (CFEqual(kCFJapaneseCalendar, identifier)) identifier = kCFJapaneseCalendar;
269267
else if (CFEqual(kCFIslamicCalendar, identifier)) identifier = kCFIslamicCalendar;
270268
else if (CFEqual(kCFIslamicCivilCalendar, identifier)) identifier = kCFIslamicCivilCalendar;
271269
else if (CFEqual(kCFHebrewCalendar, identifier)) identifier = kCFHebrewCalendar;
272-
// else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar;
270+
else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar;
273271
else return NULL;
274272
}
275273
struct __CFCalendar *calendar = NULL;
@@ -422,6 +420,7 @@ static UCalendarDateFields __CFCalendarGetICUFieldCodeFromChar(char ch) {
422420
case 'G': return UCAL_ERA;
423421
case 'y': return UCAL_YEAR;
424422
case 'M': return UCAL_MONTH;
423+
case 'l': return UCAL_IS_LEAP_MONTH;
425424
case 'd': return UCAL_DAY_OF_MONTH;
426425
case 'h': return UCAL_HOUR;
427426
case 'H': return UCAL_HOUR_OF_DAY;

Foundation.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
4DC1D0801C12EEEF00B5948A /* TestNSPipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DC1D07F1C12EEEF00B5948A /* TestNSPipe.swift */; };
1111
525AECED1BF2C9C500D15BB0 /* TestNSFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525AECEB1BF2C96400D15BB0 /* TestNSFileManager.swift */; };
12+
52829AD71C160D64003BC4EF /* TestNSCalendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52829AD61C160D64003BC4EF /* TestNSCalendar.swift */; };
1213
528776141BF2629700CB0090 /* FoundationErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522C253A1BF16E1600804FC6 /* FoundationErrors.swift */; };
1314
528776191BF27D9500CB0090 /* Test.plist in Resources */ = {isa = PBXBuildFile; fileRef = 528776181BF27D9500CB0090 /* Test.plist */; };
1415
5B40F9EF1C124F47000E72E3 /* CFXMLInterface.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B40F9EB1C124F45000E72E3 /* CFXMLInterface.c */; };
@@ -317,6 +318,7 @@
317318
4DC1D07F1C12EEEF00B5948A /* TestNSPipe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSPipe.swift; sourceTree = "<group>"; };
318319
522C253A1BF16E1600804FC6 /* FoundationErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationErrors.swift; sourceTree = "<group>"; };
319320
525AECEB1BF2C96400D15BB0 /* TestNSFileManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSFileManager.swift; sourceTree = "<group>"; };
321+
52829AD61C160D64003BC4EF /* TestNSCalendar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSCalendar.swift; sourceTree = "<group>"; };
320322
528776181BF27D9500CB0090 /* Test.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Test.plist; sourceTree = "<group>"; };
321323
5B40F9EB1C124F45000E72E3 /* CFXMLInterface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFXMLInterface.c; sourceTree = "<group>"; };
322324
5B40F9EC1C124F45000E72E3 /* CFXMLInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFXMLInterface.h; sourceTree = "<group>"; };
@@ -1003,6 +1005,7 @@
10031005
isa = PBXGroup;
10041006
children = (
10051007
EA66F63C1BF1619600136161 /* TestNSArray.swift */,
1008+
52829AD61C160D64003BC4EF /* TestNSCalendar.swift */,
10061009
EA66F63D1BF1619600136161 /* TestNSDictionary.swift */,
10071010
EA66F63E1BF1619600136161 /* TestNSIndexSet.swift */,
10081011
EA66F63F1BF1619600136161 /* TestNSNumber.swift */,
@@ -1702,6 +1705,7 @@
17021705
E876A73E1C1180E000F279EC /* TestNSRange.swift in Sources */,
17031706
EA66F6521BF1619600136161 /* TestNSPropertyList.swift in Sources */,
17041707
4DC1D0801C12EEEF00B5948A /* TestNSPipe.swift in Sources */,
1708+
52829AD71C160D64003BC4EF /* TestNSCalendar.swift in Sources */,
17051709
EA66F64E1BF1619600136161 /* TestNSIndexSet.swift in Sources */,
17061710
EA66F6541BF1619600136161 /* TestNSSet.swift in Sources */,
17071711
EA66F64A1BF1619600136161 /* TestNSArray.swift in Sources */,

TestFoundation/TestNSCalendar.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See http://swift.org/LICENSE.txt for license information
7+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+
//
9+
10+
#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
11+
import Foundation
12+
import XCTest
13+
#else
14+
import SwiftFoundation
15+
import SwiftXCTest
16+
#endif
17+
import CoreFoundation
18+
19+
class TestNSCalendar: XCTestCase {
20+
21+
var allTests : [(String, () -> ())] {
22+
return [
23+
("test_gettingDatesOnGregorianCalendar", test_gettingDatesOnGregorianCalendar ),
24+
("test_gettingDatesOnHebrewCalendar", test_gettingDatesOnHebrewCalendar ),
25+
("test_initializingWithInvalidIdentifier", test_initializingWithInvalidIdentifier),
26+
("test_gettingDatesOnChineseCalendar", test_gettingDatesOnChineseCalendar)
27+
]
28+
}
29+
30+
func test_gettingDatesOnGregorianCalendar() {
31+
let date = NSDate(timeIntervalSince1970: 1449332351)
32+
33+
guard let components = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)?.components([.Year, .Month, .Day], fromDate: date) else {
34+
XCTFail("Could not get date from the gregorian calendar")
35+
return
36+
}
37+
XCTAssertEqual(components.year, 2015)
38+
XCTAssertEqual(components.month, 12)
39+
XCTAssertEqual(components.day, 5)
40+
}
41+
42+
func test_gettingDatesOnHebrewCalendar() {
43+
let date = NSDate(timeIntervalSince1970: 1552580351)
44+
45+
guard let components = NSCalendar(calendarIdentifier: NSCalendarIdentifierHebrew)?.components([.Year, .Month, .Day], fromDate: date) else {
46+
XCTFail("Could not get date from the Hebrew calendar")
47+
return
48+
}
49+
XCTAssertEqual(components.year, 5779)
50+
XCTAssertEqual(components.month, 7)
51+
XCTAssertEqual(components.day, 7)
52+
XCTAssertFalse(components.leapMonth)
53+
}
54+
55+
func test_gettingDatesOnChineseCalendar() {
56+
let date = NSDate(timeIntervalSince1970: 1591460351.0)
57+
58+
guard let components = NSCalendar(calendarIdentifier: NSCalendarIdentifierChinese)?.components([.Year, .Month, .Day], fromDate: date) else {
59+
XCTFail("Could not get date from the Chinese calendar")
60+
return
61+
}
62+
XCTAssertEqual(components.year, 37)
63+
XCTAssertEqual(components.month, 4)
64+
XCTAssertEqual(components.day, 15)
65+
XCTAssertTrue(components.leapMonth)
66+
}
67+
68+
func test_initializingWithInvalidIdentifier() {
69+
let calendar = NSCalendar(calendarIdentifier: "nonexistant_calendar")
70+
XCTAssertNil(calendar)
71+
}
72+
}

TestFoundation/main.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ internal func testBundle() -> NSBundle {
2323
XCTMain([
2424
TestNSString(),
2525
TestNSArray(),
26+
TestNSCalendar(),
2627
TestNSDictionary(),
2728
TestNSSet(),
2829
TestNSNumber(),

0 commit comments

Comments
 (0)