mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
431 lines
17 KiB
Objective-C
431 lines
17 KiB
Objective-C
// Copyright 2019 Google
|
|
//
|
|
// 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
|
|
//
|
|
// http://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 "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
@interface FIRCLSFileTests : XCTestCase
|
|
|
|
@property(nonatomic, assign) FIRCLSFile unbufferedFile;
|
|
@property(nonatomic, assign) FIRCLSFile bufferedFile;
|
|
@property(nonatomic, strong) NSString *unbufferedPath;
|
|
@property(nonatomic, strong) NSString *bufferedPath;
|
|
|
|
@end
|
|
|
|
@implementation FIRCLSFileTests
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
|
|
self.unbufferedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"file_test"];
|
|
self.bufferedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"buffered_file_test"];
|
|
|
|
[[NSFileManager defaultManager] removeItemAtPath:self.unbufferedPath error:nil];
|
|
|
|
FIRCLSFileInitWithPathMode(&_unbufferedFile, [self.unbufferedPath fileSystemRepresentation],
|
|
false, false);
|
|
FIRCLSFileInitWithPathMode(&_bufferedFile, [self.bufferedPath fileSystemRepresentation], false,
|
|
true);
|
|
}
|
|
|
|
- (void)tearDown {
|
|
FIRCLSFileClose(&_unbufferedFile);
|
|
FIRCLSFileClose(&_bufferedFile);
|
|
|
|
[super tearDown];
|
|
}
|
|
|
|
- (NSString *)contentsOfFileAtPath:(NSString *)path {
|
|
return [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testEmptySection {
|
|
[self emptySectionWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self emptySectionWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)emptySectionWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "empty");
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(
|
|
contents, @"{\"empty\":}\n",
|
|
@"Empty written to and retrieved from file does not match input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testSingleArrayCollection {
|
|
[self singleArrayCollectionWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self singleArrayCollectionWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)singleArrayCollectionWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "array");
|
|
FIRCLSFileWriteArrayStart(file);
|
|
FIRCLSFileWriteArrayEntryUint64(file, 1);
|
|
FIRCLSFileWriteArrayEnd(file);
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(
|
|
contents, @"{\"array\":[1]}\n",
|
|
@"Single array written to and retrieved from file does not match input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testEmptyCollectionFollowedByEntry {
|
|
[self emptyCollectionFollowedByEntryWithFile:&_unbufferedFile
|
|
filePath:self.unbufferedPath
|
|
buffered:NO];
|
|
[self emptyCollectionFollowedByEntryWithFile:&_bufferedFile
|
|
filePath:self.bufferedPath
|
|
buffered:YES];
|
|
}
|
|
|
|
- (void)emptyCollectionFollowedByEntryWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "empty_array");
|
|
FIRCLSFileWriteArrayStart(file);
|
|
FIRCLSFileWriteArrayEnd(file);
|
|
|
|
// and now put in another entry into the hash
|
|
FIRCLSFileWriteHashEntryUint64(file, "value", 1);
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(contents, @"{\"empty_array\":[],\"value\":1}\n",
|
|
@"Empty collection and entry written to and retrieved from file does not "
|
|
@"match input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testHexEncodingString {
|
|
[self hexEncodingStringWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self hexEncodingStringWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)hexEncodingStringWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteHashStart(file);
|
|
FIRCLSFileWriteHashEntryHexEncodedString(file, "hex", "hex string");
|
|
FIRCLSFileWriteHashEnd(file);
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(contents, @"{\"hex\":\"68657820737472696e67\"}",
|
|
@"Hex encoded string written to and retrieved from file does not match "
|
|
@"input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testHexEncodingLongString {
|
|
[self hexEncodingLongStringWithFile:&_unbufferedFile
|
|
filePath:self.unbufferedPath
|
|
length:CLS_FILE_HEX_BUFFER * 10
|
|
buffered:NO];
|
|
[self hexEncodingLongStringWithFile:&_bufferedFile
|
|
filePath:self.bufferedPath
|
|
length:FIRCLSWriteBufferLength * 10
|
|
buffered:YES];
|
|
}
|
|
|
|
- (void)hexEncodingLongStringWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
length:(size_t)length
|
|
buffered:(BOOL)buffered {
|
|
char *longString = malloc(length * sizeof(char));
|
|
|
|
memset(longString, 'a', length); // fill it with 'a' characters
|
|
longString[length - 1] = 0; // null terminate
|
|
|
|
FIRCLSFileWriteHashStart(file);
|
|
FIRCLSFileWriteHashEntryHexEncodedString(file, "hex", longString);
|
|
FIRCLSFileWriteHashEnd(file);
|
|
|
|
NSDictionary *dict =
|
|
[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath]
|
|
options:0
|
|
error:nil];
|
|
|
|
if (buffered) {
|
|
XCTAssertNil(dict);
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
dict = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath]
|
|
options:0
|
|
error:nil];
|
|
}
|
|
|
|
XCTAssertNotNil(dict,
|
|
@"Expected a dictionary serialized from JSON file contents in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssertEqual([dict[@"hex"] length], (length - 1) * 2,
|
|
@"Long hex encoded string written to and retrieved from file does not match input "
|
|
@"in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
|
|
free(longString);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testSignedInteger {
|
|
[self signedIntegerWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self signedIntegerWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)signedIntegerWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "signed");
|
|
FIRCLSFileWriteHashStart(file);
|
|
FIRCLSFileWriteHashEntryInt64(file, "value", -1);
|
|
FIRCLSFileWriteHashEnd(file);
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(
|
|
contents, @"{\"signed\":{\"value\":-1}}\n",
|
|
@"Signed integer written to and retrieved from file does not match input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testBigInteger {
|
|
[self bigIntegerWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self bigIntegerWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)bigIntegerWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "big_int");
|
|
FIRCLSFileWriteHashStart(file);
|
|
FIRCLSFileWriteHashEntryUint64(file, "value", 0x12345678900af8a1);
|
|
FIRCLSFileWriteHashEnd(file);
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(
|
|
contents, @"{\"big_int\":{\"value\":1311768467284359329}}\n",
|
|
@"Big integer written to and retrieved from file does not match input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testMaxUInt64 {
|
|
[self maxUInt64WithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self maxUInt64WithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)maxUInt64WithFile:(FIRCLSFile *)file filePath:(NSString *)filePath buffered:(BOOL)buffered {
|
|
FIRCLSFileWriteSectionStart(file, "big_int");
|
|
FIRCLSFileWriteHashStart(file);
|
|
FIRCLSFileWriteHashEntryUint64(file, "value", 0xFFFFFFFFFFFFFFFF);
|
|
FIRCLSFileWriteHashEnd(file);
|
|
FIRCLSFileWriteSectionEnd(file);
|
|
|
|
NSString *contents = [self contentsOfFileAtPath:filePath];
|
|
if (buffered) {
|
|
XCTAssertEqualObjects(
|
|
contents, @"",
|
|
@"Expected empty file contents for buffered case: buffer has not yet been flushed to file");
|
|
FIRCLSFileFlushWriteBuffer(file);
|
|
contents = [self contentsOfFileAtPath:filePath];
|
|
}
|
|
XCTAssertEqualObjects(contents, @"{\"big_int\":{\"value\":18446744073709551615}}\n",
|
|
@"Max unsigned integer written to and retrieved from file does not match "
|
|
@"input in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testSimpleHashPerformanceWithUnbufferedFile {
|
|
[self measureBlock:^{
|
|
// just one run isn't sufficient
|
|
for (NSUInteger i = 0; i < 2000; ++i) {
|
|
FIRCLSFileWriteSectionStart(&self->_unbufferedFile, "hash_test");
|
|
FIRCLSFileWriteHashEntryString(&self->_unbufferedFile, "key1", "value1");
|
|
FIRCLSFileWriteHashEntryUint64(&self->_unbufferedFile, "key2", 64);
|
|
FIRCLSFileWriteHashEntryNSString(&self->_unbufferedFile, "key2", @"some string");
|
|
FIRCLSFileWriteSectionEnd(&self->_unbufferedFile);
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)testSimpleHashPerformanceWithBufferedFile {
|
|
[self measureBlock:^{
|
|
// just one run isn't sufficient
|
|
for (NSUInteger i = 0; i < 2000; ++i) {
|
|
FIRCLSFileWriteSectionStart(&self->_bufferedFile, "hash_test");
|
|
FIRCLSFileWriteHashEntryString(&self->_bufferedFile, "key1", "value1");
|
|
FIRCLSFileWriteHashEntryUint64(&self->_bufferedFile, "key2", 64);
|
|
FIRCLSFileWriteHashEntryNSString(&self->_bufferedFile, "key2", @"some string");
|
|
FIRCLSFileWriteSectionEnd(&self->_bufferedFile);
|
|
}
|
|
}];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testOpenAndClose {
|
|
[self openAndCloseWithFile:&_unbufferedFile filePath:self.unbufferedPath buffered:NO];
|
|
[self openAndCloseWithFile:&_bufferedFile filePath:self.bufferedPath buffered:YES];
|
|
}
|
|
|
|
- (void)openAndCloseWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
XCTAssert(FIRCLSFileIsOpen(file), @"File should be opened by setup in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileClose(file), @"Closing the file should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssertFalse(FIRCLSFileIsOpen(file), @"File should now be marked as closed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileInitWithPath(file, [filePath fileSystemRepresentation], buffered),
|
|
@"Re-opening the same file structure should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileIsOpen(file),
|
|
@"That file should be marked as open as well in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testCloseAndOpenAlternatingBufferedOption {
|
|
[self closeAndOpenAlternatingBufferedOptionWithFile:&_unbufferedFile
|
|
filePath:self.unbufferedPath
|
|
buffered:NO];
|
|
[self closeAndOpenAlternatingBufferedOptionWithFile:&_bufferedFile
|
|
filePath:self.bufferedPath
|
|
buffered:YES];
|
|
}
|
|
|
|
- (void)closeAndOpenAlternatingBufferedOptionWithFile:(FIRCLSFile *)file
|
|
filePath:(NSString *)filePath
|
|
buffered:(BOOL)buffered {
|
|
XCTAssert(FIRCLSFileIsOpen(file), @"File should be opened by setup in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileClose(file), @"Closing the file should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssertFalse(FIRCLSFileIsOpen(file), @"File should now be marked as closed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileInitWithPath(file, [filePath fileSystemRepresentation], !buffered),
|
|
@"Re-opening the same file structure should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileIsOpen(file),
|
|
@"That file should be marked as open as well in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileClose(file), @"Closing the file should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssertFalse(FIRCLSFileIsOpen(file), @"File should now be marked as closed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileInitWithPath(file, [filePath fileSystemRepresentation], buffered),
|
|
@"Re-opening the same file structure should succeed in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
XCTAssert(FIRCLSFileIsOpen(file),
|
|
@"That file should be marked as open as well in %@buffered case",
|
|
buffered ? @"" : @"un");
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)testLoggingInputLongerThanBuffer {
|
|
size_t inputLength = (FIRCLSWriteBufferLength + 2) * sizeof(char);
|
|
char *input = malloc(inputLength);
|
|
for (size_t i = 0; i < inputLength - 1; i++) {
|
|
input[i] = i % 26 + 'a';
|
|
}
|
|
input[inputLength - 1] = '\0';
|
|
NSString *inputString = [NSString stringWithUTF8String:input];
|
|
|
|
FIRCLSFileWriteHashStart(&_bufferedFile);
|
|
FIRCLSFileWriteHashEntryString(&_bufferedFile, "value", input);
|
|
FIRCLSFileWriteHashEnd(&_bufferedFile);
|
|
FIRCLSFileFlushWriteBuffer(&_bufferedFile);
|
|
|
|
NSError *error;
|
|
NSDictionary *dict =
|
|
[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:self.bufferedPath]
|
|
options:0
|
|
error:&error];
|
|
XCTAssertNotNil(dict,
|
|
@"No data was retrieved from log file while writing long input with buffering");
|
|
NSString *writtenValue = dict[@"value"];
|
|
XCTAssertEqualObjects(inputString, writtenValue,
|
|
@"Data was lost while writing long input to file with write buffering");
|
|
|
|
free(input);
|
|
}
|
|
|
|
@end
|