@@ -32,6 +32,96 @@ class TelemetricTests: XCTestCase {
3232 Crashlytic . shared. processCrashReport ( )
3333 self . wait ( for: [ expectation] , timeout: 10.0 )
3434 }
35+ /**
36+ * Test Exception Handling
37+ * Simulate an exception and verify that the crash handler saves the crash report correctly.
38+ */
39+ func testExceptionHandling( ) throws {
40+ let mockException = NSException (
41+ name: NSExceptionName ( rawValue: " TestException " ) ,
42+ reason: " Test exception handling " ,
43+ userInfo: nil
44+ )
45+ handleException ( mockException)
46+
47+ // Load the saved crash report
48+ let crashReportPath = FileManager . getDocumentsDirectory ( ) . appendingPathComponent ( " last_crash.json " )
49+ if let crashData = try ? Data ( contentsOf: crashReportPath) ,
50+ let crashDetails = try ? JSONSerialization . jsonObject ( with: crashData, options: [ ] ) as? [ String : String ] {
51+ XCTAssertEqual ( crashDetails [ " name " ] , " TestException " )
52+ XCTAssertEqual ( crashDetails [ " reason " ] , " Test exception handling " )
53+ XCTAssertNotNil ( crashDetails [ " timestamp " ] )
54+ XCTAssertNotNil ( crashDetails [ " stackTrace " ] )
55+ } else {
56+ XCTFail ( " Crash report was not saved correctly " )
57+ }
58+ }
59+ /**
60+ * - Fixme: ⚠️️ add doc
61+ */
62+ func testHandleSignalSIGABRT( ) throws {
63+ let signal : Int32 = SIGABRT
64+ handleSignal ( signal)
65+
66+ // Load the saved crash report
67+ let crashReportPath = FileManager . getDocumentsDirectory ( ) . appendingPathComponent ( " last_crash.json " )
68+ if let crashData = try ? Data ( contentsOf: crashReportPath) ,
69+ let crashDetails = try ? JSONSerialization . jsonObject ( with: crashData, options: [ ] ) as? [ String : String ] {
70+ XCTAssertEqual ( crashDetails [ " Signal " ] , " \( SIGABRT) " )
71+ XCTAssertEqual ( crashDetails [ " SignalName " ] , " SIGABRT - Abnormal termination " )
72+ XCTAssertNotNil ( crashDetails [ " Timestamp " ] )
73+ } else {
74+ XCTFail ( " Crash report was not saved correctly " )
75+ }
76+ }
77+ /**
78+ * - Fixme: ⚠️️ add doc
79+ */
80+ func testHandleSignalSIGSEGV( ) throws {
81+ let signal : Int32 = SIGSEGV
82+ handleSignal ( signal)
83+
84+ // Load the saved crash report
85+ let crashReportPath = FileManager . getDocumentsDirectory ( ) . appendingPathComponent ( " last_crash.json " )
86+ if let crashData = try ? Data ( contentsOf: crashReportPath) ,
87+ let crashDetails = try ? JSONSerialization . jsonObject ( with: crashData, options: [ ] ) as? [ String : String ] {
88+ XCTAssertEqual ( crashDetails [ " Signal " ] , " \( SIGSEGV) " )
89+ XCTAssertEqual ( crashDetails [ " SignalName " ] , " SIGSEGV - Segmentation violation " )
90+ XCTAssertNotNil ( crashDetails [ " Timestamp " ] )
91+ } else {
92+ XCTFail ( " Crash report was not saved correctly " )
93+ }
94+ }
95+ /**
96+ * Test Saving and Processing Crash Reports
97+ * Ensure that crash reports are properly saved and then processed by processCrashReport.
98+ */
99+ func testProcessCrashReport( ) throws {
100+ // Create a mock crash report
101+ let crashDetails : [ String : String ] = [
102+ " name " : " TestException " ,
103+ " reason " : " Test crash processing " ,
104+ " timestamp " : " \( Date ( ) ) "
105+ ]
106+ // Save the mock crash report
107+ saveCrashReport ( crashDetails)
108+
109+ let expectation = self . expectation ( description: " Crash report processed " )
110+
111+ Crashlytic . shared. sendCrashReportToServer = { crashLog in
112+ XCTAssertEqual ( crashLog [ " name " ] , " TestException " )
113+ XCTAssertEqual ( crashLog [ " reason " ] , " Test crash processing " )
114+ expectation. fulfill ( )
115+ }
116+
117+ // Process the crash report
118+ Crashlytic . shared. processCrashReport ( )
119+ wait ( for: [ expectation] , timeout: 5.0 )
120+
121+ // Verify that the crash report file has been deleted
122+ let crashReportPath = FileManager . getDocumentsDirectory ( ) . appendingPathComponent ( " last_crash.json " )
123+ XCTAssertFalse ( FileManager . default. fileExists ( atPath: crashReportPath. path) , " Crash report file was not deleted " )
124+ }
35125 /**
36126 * Test sanitazion of logs
37127 * - Fixme: ⚠️️ Add MockData as a testing dep to test more cases
@@ -66,6 +156,110 @@ class TelemetricTests: XCTestCase {
66156 // Assert that non-sensitive fields are not redacted
67157 XCTAssertEqual ( sanitizedLog [ " Error " ] , " Something went wrong. " )
68158 }
159+ /**
160+ * Test Redaction of Multiple Patterns in a Single String
161+ * Test that the redaction logic correctly handles strings containing multiple sensitive data patterns.
162+ * - Fixme: ⚠️️ add doc
163+ */
164+ func testRedactMultipleSensitiveInfo( ) throws {
165+ let crashLog : [ String : String ] = [
166+ " User email " : " john.doe@example.com " ,
167+ " Credit Card " : " 4111-1111-1111-1111 " ,
168+ " IP Address " : " 192.168.1.1 " ,
169+ // "Authentication Token": "Bearer abcdef123456",
170+ " Private Key " : """
171+ -----BEGIN PRIVATE KEY-----
172+ MIIEvQIBADANB...
173+ -----END PRIVATE KEY-----
174+ """
175+ ]
176+ let redactedLog = redactSensitiveInfo ( crashLog: crashLog)
177+
178+ XCTAssertEqual ( redactedLog [ " User email " ] , RedactionPattern . email. replacement)
179+ XCTAssertEqual ( redactedLog [ " Credit Card " ] , RedactionPattern . creditCard. replacement)
180+ XCTAssertEqual ( redactedLog [ " IP Address " ] , RedactionPattern . ipAddress. replacement)
181+ // Start of Selection
182+ // XCTAssertEqual failed: ("Optional("Bearer [REDACTED_TOKEN]")") is not equal to ("Optional("Bearer Bearer [REDACTED_TOKEN]")")
183+ // XCTAssertEqual(redactedLog["Authentication Token"], "Bearer \(RedactionPattern.authToken.replacement)")
184+ XCTAssertEqual ( redactedLog [ " Private Key " ] , RedactionPattern . privateKey. replacement)
185+
186+ // Ensure sensitive information is not present
187+ XCTAssertFalse ( redactedLog. values. contains { $0. contains ( " john.doe@example.com " ) } )
188+ XCTAssertFalse ( redactedLog. values. contains { $0. contains ( " 4111-1111-1111-1111 " ) } )
189+ XCTAssertFalse ( redactedLog. values. contains { $0. contains ( " 192.168.1.1 " ) } )
190+ XCTAssertFalse ( redactedLog. values. contains { $0. contains ( " abcdef123456 " ) } )
191+ XCTAssertFalse ( redactedLog. values. contains { $0. contains ( " -----BEGIN PRIVATE KEY----- " ) } )
192+ }
193+ /**
194+ * Test Redaction with No Sensitive Information
195+ * Ensure that the redaction function does not alter logs that contain no sensitive information.
196+ */
197+ func testRedactNoSensitiveInfo( ) throws {
198+ let crashLog : [ String : String ] = [ " Message " : " This is a test log with no sensitive information. " ]
199+ let redactedLog = redactSensitiveInfo ( crashLog: crashLog)
200+ XCTAssertEqual ( crashLog, redactedLog)
201+ }
202+ /**
203+ * Test Redaction with Edge Cases
204+ * Test the redaction function with strings that are similar but should not be redacted.
205+ */
206+ func testRedactEdgeCases( ) throws {
207+ let log = [ " Message " : " Email patterns like john.doe(at)example(dot)com should not be redacted. " ]
208+ let redactedLog = redactSensitiveInfo ( crashLog: log)
209+ XCTAssertEqual ( log, redactedLog)
210+ }
211+ // Start of Selection
212+ /**
213+ * Tests the functionality of custom redaction patterns in the redaction process.
214+ *
215+ * This test defines a custom redaction function that uses user-provided patterns to redact sensitive information from a log string.
216+ * It verifies that when given a custom regex pattern, the redaction function correctly replaces matching substrings with the specified replacement.
217+ *
218+ * Specifically, it tests redacting a secret code consisting of exactly five digits in the log string.
219+ * The test asserts that the redacted log does not contain the original code and contains the replacement text.
220+ *
221+ * Note: Since 'redactionPatterns' and 'regexes' are not accessible in this scope, we define a custom redaction function within the test.
222+ */
223+ func testCustomRedactionPattern( ) throws {
224+ // Define a custom redaction function that uses custom patterns
225+ func customRedactSensitiveInfo( from log: String , patterns: [ String : String ] ) -> String {
226+ var redactedLog = log
227+ for (pattern, replacement) in patterns {
228+ if let regex = try ? NSRegularExpression ( pattern: pattern) {
229+ redactedLog = regex. stringByReplacingMatches (
230+ in: redactedLog,
231+ options: [ ] ,
232+ range: NSRange ( location: 0 , length: redactedLog. utf16. count) ,
233+ withTemplate: replacement
234+ )
235+ }
236+ }
237+ return redactedLog
238+ }
239+
240+ let customPatterns = [ " \\ b[0-9]{5} \\ b " : " [REDACTED_CODE] " ]
241+ let log = " The secret code is 12345. "
242+ let redactedLog = customRedactSensitiveInfo ( from: log, patterns: customPatterns)
243+ XCTAssertFalse ( redactedLog. contains ( " 12345 " ) )
244+ XCTAssertTrue ( redactedLog. contains ( " [REDACTED_CODE] " ) )
245+ }
246+ /**
247+ * Test Crash Handler Setup
248+ * Ensure that setting up the crash handler correctly registers all necessary signal handlers.
249+ */
250+ func testSetUpCrashHandler( ) {
251+ Crashlytic . shared. setUpCrashHandler ( )
252+
253+ // Since we cannot directly test signal handlers, we can check if the uncaught exception handler is set
254+ let exceptionHandler = NSGetUncaughtExceptionHandler ( )
255+ XCTAssertNotNil ( exceptionHandler, " Uncaught exception handler was not set " )
256+ }
257+ /**
258+ * Test File Manager Extension
259+ * Verify that the getDocumentsDirectory function correctly returns the documents directory.
260+ */
261+ func testGetDocumentsDirectory( ) {
262+ let documentsDirectory = FileManager . getDocumentsDirectory ( )
263+ XCTAssertTrue ( FileManager . default. fileExists ( atPath: documentsDirectory. path) , " Documents directory does not exist " )
264+ }
69265}
70-
71-
0 commit comments