/// Copyright 2023 Google LLC /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// https://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. #include #include #import #include "XCTest/XCTest.h" #include "Source/common/ScopedCFTypeRef.h" using santa::ScopedCFTypeRef; @interface ScopedCFTypeRefTest : XCTestCase @end @implementation ScopedCFTypeRefTest - (void)testDefaultConstruction { // Default construction creates wraps a NULL object ScopedCFTypeRef scopedRef; XCTAssertFalse(scopedRef.Unsafe()); } - (void)testOperatorBool { // Operator bool is `false` when object is null { ScopedCFTypeRef scopedNullRef; XCTAssertFalse(scopedNullRef.Unsafe()); XCTAssertFalse(scopedNullRef); } // Operator bool is `true` when object is NOT null { int x = 123; CFNumberRef numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &x); ScopedCFTypeRef scopedNumRef = ScopedCFTypeRef::Assume(numRef); XCTAssertTrue(scopedNumRef.Unsafe()); XCTAssertTrue(scopedNumRef); } } // Note that CFMutableArray is used for testing, even when subtypes aren't // needed, because it is never optimized into immortal constant values, unlike // other types. - (void)testAssume { int want = 123; int got = 0; CFMutableArrayRef array = CFArrayCreateMutable(nullptr, /*capacity=*/0, &kCFTypeArrayCallBacks); // Baseline state, initial retain count is 1 after object creation XCTAssertEqual(1, CFGetRetainCount(array)); CFNumberRef numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &want); CFArrayAppendValue(array, numRef); CFRelease(numRef); XCTAssertEqual(1, CFArrayGetCount(array)); { ScopedCFTypeRef scopedArray = ScopedCFTypeRef::Assume(array); // Ensure ownership was taken, and retain count remains unchanged XCTAssertTrue(scopedArray.Unsafe()); XCTAssertEqual(1, CFGetRetainCount(scopedArray.Unsafe())); // Make sure the object contains expected contents CFMutableArrayRef ref = scopedArray.Unsafe(); XCTAssertEqual(1, CFArrayGetCount(ref)); XCTAssertTrue( CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(ref, 0), kCFNumberIntType, &got)); XCTAssertEqual(want, got); } } // Note that CFMutableArray is used for testing, even when subtypes aren't // needed, because it is never optimized into immortal constant values, unlike // other types. - (void)testRetain { int want = 123; int got = 0; CFMutableArrayRef array = CFArrayCreateMutable(nullptr, /*capacity=*/0, &kCFTypeArrayCallBacks); // Baseline state, initial retain count is 1 after object creation XCTAssertEqual(1, CFGetRetainCount(array)); CFNumberRef numRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &want); CFArrayAppendValue(array, numRef); CFRelease(numRef); XCTAssertEqual(1, CFArrayGetCount(array)); { ScopedCFTypeRef scopedArray = ScopedCFTypeRef::Retain(array); // Ensure ownership was taken, and retain count was incremented XCTAssertTrue(scopedArray.Unsafe()); XCTAssertEqual(2, CFGetRetainCount(scopedArray.Unsafe())); // Make sure the object contains expected contents CFMutableArrayRef ref = scopedArray.Unsafe(); XCTAssertEqual(1, CFArrayGetCount(ref)); XCTAssertTrue( CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(ref, 0), kCFNumberIntType, &got)); XCTAssertEqual(want, got); } // The original `array` object should still be valid due to the extra retain. // Ensure the retain count has decreased since `scopedArray` went out of scope XCTAssertEqual(1, CFArrayGetCount(array)); } - (void)testInto { ScopedCFTypeRef scopedURLRef = ScopedCFTypeRef::Assume(CFURLCreateWithFileSystemPath( kCFAllocatorDefault, CFSTR("/usr/bin/true"), kCFURLPOSIXPathStyle, YES)); ScopedCFTypeRef scopedCodeRef; XCTAssertFalse(scopedCodeRef); SecStaticCodeCreateWithPath(scopedURLRef.Unsafe(), kSecCSDefaultFlags, scopedCodeRef.InitializeInto()); // Ensure the scoped object was initialized XCTAssertTrue(scopedCodeRef); } @end