Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@
D43B26DA2D70A612007747FD /* SentrySpanDataKey.m in Sources */ = {isa = PBXBuildFile; fileRef = D43B26D92D70A60E007747FD /* SentrySpanDataKey.m */; };
D43C1BE82E8FB85400CD5D67 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = D43C1BE72E8FB85400CD5D67 /* SnapshotTesting */; };
D4411DD52E02B74900EA4987 /* ArrayAccessesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4411DD42E02B74100EA4987 /* ArrayAccessesTests.swift */; };
D44311312EB22812006CABE4 /* SentryUIRedactBuilderTests+ReactNative.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AF7D212E93FFCA004F0F59 /* SentryUIRedactBuilderTests+ReactNative.swift */; };
D44B16722DE464AD006DBDB3 /* TestDispatchFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44B16712DE464A9006DBDB3 /* TestDispatchFactoryTests.swift */; };
D451ED5D2D92ECD200C9BEA8 /* SentryOnDemandReplayError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D451ED5C2D92ECD200C9BEA8 /* SentryOnDemandReplayError.swift */; };
D451ED5F2D92ECDE00C9BEA8 /* SentryReplayFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D451ED5E2D92ECDE00C9BEA8 /* SentryReplayFrame.swift */; };
Expand Down Expand Up @@ -2180,6 +2181,7 @@
D4AF00202D2E92FD00F5F3D7 /* SentryNSFileManagerSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSFileManagerSwizzling.m; sourceTree = "<group>"; };
D4AF00222D2E931000F5F3D7 /* SentryNSFileManagerSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryNSFileManagerSwizzling.h; path = include/SentryNSFileManagerSwizzling.h; sourceTree = "<group>"; };
D4AF00242D2E93C400F5F3D7 /* SentryNSFileManagerSwizzlingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSFileManagerSwizzlingTests.m; sourceTree = "<group>"; };
D4AF7D212E93FFCA004F0F59 /* SentryUIRedactBuilderTests+ReactNative.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SentryUIRedactBuilderTests+ReactNative.swift"; sourceTree = "<group>"; };
D4AF7D292E940492004F0F59 /* SentryUIRedactBuilderTests+Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SentryUIRedactBuilderTests+Common.swift"; sourceTree = "<group>"; };
D4B0DC7E2DA9257200DE61B6 /* SentryRenderVideoResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRenderVideoResult.swift; sourceTree = "<group>"; };
D4BCA0C22DA93C25009E49AB /* SentrySessionReplayIntegration+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentrySessionReplayIntegration+Test.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4241,6 +4243,7 @@
D82915622C85EF0C00A6CDD4 /* SentryViewPhotographerTests.swift */,
D8F67AF22BE10F7600C9197B /* SentryUIRedactBuilderTests.swift */,
D4AF7D292E940492004F0F59 /* SentryUIRedactBuilderTests+Common.swift */,
D4AF7D212E93FFCA004F0F59 /* SentryUIRedactBuilderTests+ReactNative.swift */,
D45E2D762E003EBF0072A6B7 /* TestRedactOptions.swift */,
);
path = ViewCapture;
Expand Down Expand Up @@ -4348,13 +4351,6 @@
path = Screenshot;
sourceTree = "<group>";
};
D4AF802E2E965188004F0F59 /* __Snapshots__ */ = {
isa = PBXGroup;
children = (
);
path = __Snapshots__;
sourceTree = "<group>";
};
D4A0C22A2E9E3CE100791353 /* InfoPlist */ = {
isa = PBXGroup;
children = (
Expand All @@ -4367,6 +4363,13 @@
path = InfoPlist;
sourceTree = "<group>";
};
D4AF802E2E965188004F0F59 /* __Snapshots__ */ = {
isa = PBXGroup;
children = (
);
path = __Snapshots__;
sourceTree = "<group>";
};
D4CBA2522DE06D1600581618 /* SentryTestUtilsTests */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -6186,6 +6189,7 @@
7BC6EBF4255C044A0059822A /* SentryEventTests.swift in Sources */,
63FE721920DA66EC00CDBAE8 /* SentryCrashReportStore_Tests.m in Sources */,
7B6D98EB24C6E84F005502FA /* SentryCrashInstallationReporterTests.swift in Sources */,
D44311312EB22812006CABE4 /* SentryUIRedactBuilderTests+ReactNative.swift in Sources */,
7BA61EA625F21E660008CAA2 /* SentrySDKLogTests.swift in Sources */,
62CFD9A92C99741100834E1B /* SentryInvalidJSONStringTests.swift in Sources */,
7BB42EF124F3B7B700D7B39A /* SentrySession+Equality.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#if os(iOS) && !targetEnvironment(macCatalyst)
import AVKit
import Foundation
import PDFKit
import SafariServices
@_spi(Private) @testable import Sentry
import SentryTestUtils
import SnapshotTesting
import SwiftUI
import UIKit
import WebKit
import XCTest

/*
* Mocked RCTTextView to test the redaction of text from React Native apps.
*/
@objc(RCTTextView)
private class RCTTextView: UIView {
}

/*
* Mocked RCTParagraphComponentView to test the redaction of text from React Native apps.
*/
@objc(RCTParagraphComponentView)
private class RCTParagraphComponentView: UIView {
}

/*
* Mocked RCTImageView to test the redaction of images from React Native apps.
*/
@objc(RCTImageView)
private class RCTImageView: UIView {
}

/// See `SentryUIRedactBuilderTests.swift` for more information on how to print the internal view hierarchy of a view.
class SentryUIRedactBuilderTests_ReactNative: SentryUIRedactBuilderTests { // swiftlint:disable:this type_name
private func getSut(maskAllText: Bool, maskAllImages: Bool) -> SentryUIRedactBuilder {
return SentryUIRedactBuilder(options: TestRedactOptions(
maskAllText: maskAllText,
maskAllImages: maskAllImages
))
}

// MARK: - RCTTextView Redaction

private func setupRCTTextViewFixture() -> UIView {
let rootView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

let textView = RCTTextView(frame: CGRect(x: 20, y: 20, width: 40, height: 40))
rootView.addSubview(textView)

return rootView

// View Hierarchy:
// ---------------
// <UIView: 0x10594ea10; frame = (0 0; 100 100); layer = <CALayer: 0x600000ce53b0>>
// | <RCTTextView: 0x105951d60; frame = (20 20; 40 40); layer = <CALayer: 0x600000ce6790>>
}

func testRedact_withRCTTextView_withMaskAllTextEnabled_shouldRedactView() throws {
// -- Arrange --
let rootView = setupRCTTextViewFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)

let region = try XCTUnwrap(result.element(at: 0))
// The text color of UITextView is not used for redaction
XCTAssertNil(region.color)
XCTAssertEqual(region.size, CGSize(width: 40, height: 40))
XCTAssertEqual(region.type, .redact)
XCTAssertEqual(region.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))

// Assert that there are no other regions
XCTAssertEqual(result.count, 1)
}

func testRedact_withRCTTextView_withMaskAllTextDisabled_shouldNotRedactView() {
// -- Arrange --
let rootView = setupRCTTextViewFixture()

// -- Act --
let sut = getSut(maskAllText: false, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 0)
}

func testRedact_withRCTTextView_withMaskAllImagesDisabled_shouldRedactView() {
// -- Arrange --
let rootView = setupRCTTextViewFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: false)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 1)
}

// MARK: - RCTParagraphComponentView Redaction

private func setupRCTParagraphComponentFixture() -> UIView {
let rootView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

let textView = RCTParagraphComponentView(frame: CGRect(x: 20, y: 20, width: 40, height: 40))
rootView.addSubview(textView)

return rootView

// View Hierarchy:
// ---------------
// <UIView: 0x11a943f30; frame = (0 0; 100 100); layer = <CALayer: 0x600000cda3d0>>
// | <RCTParagraphComponentView: 0x106350670; frame = (20 20; 40 40); layer = <CALayer: 0x600000cdaa60>>
}

func testRedact_withRCTParagraphComponent_withMaskAllTextEnabled_shouldRedactView() throws {
// -- Arrange --
let rootView = setupRCTParagraphComponentFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)

let region = try XCTUnwrap(result.element(at: 0))
// The text color of UITextView is not used for redaction
XCTAssertNil(region.color)
XCTAssertEqual(region.size, CGSize(width: 40, height: 40))
XCTAssertEqual(region.type, .redact)
XCTAssertEqual(region.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))

// Assert that there are no other regions
XCTAssertEqual(result.count, 1)
}

func testRedact_withRCTParagraphComponent_withMaskAllTextDisabled_shouldNotRedactView() {
// -- Arrange --
let rootView = setupRCTParagraphComponentFixture()

// -- Act --
let sut = getSut(maskAllText: false, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 0)
}

func testRedact_withRCTParagraphComponent_withMaskAllImagesDisabled_shouldRedactView() {
// -- Arrange --
let rootView = setupRCTParagraphComponentFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: false)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 1)
}

// - MARK: - RCTImageView Redaction

private func setupRCTImageViewFixture() -> UIView {
let rootView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let imageView = RCTImageView(frame: CGRect(x: 20, y: 20, width: 40, height: 40))
rootView.addSubview(imageView)

// View Hierarchy:
// ---------------
// <UIView: 0x10584f470; frame = (0 0; 100 100); layer = <CALayer: 0x600000ce8fc0>>
// | <RCTImageView: 0x10585e6a0; frame = (20 20; 40 40); layer = <CALayer: 0x600000cea130>>
return rootView
}

func testRedact_withRCTImageView_withMaskAllImagesEnabled_shouldRedactView() throws {
// -- Arrange --
let rootView = setupRCTImageViewFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)

let region = try XCTUnwrap(result.element(at: 0))
// The text color of UITextView is not used for redaction
XCTAssertNil(region.color)
XCTAssertEqual(region.size, CGSize(width: 40, height: 40))
XCTAssertEqual(region.type, .redact)
XCTAssertEqual(region.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))

// Assert that there are no other regions
XCTAssertEqual(result.count, 1)
}

func testRedact_withRCTImageView_withMaskAllImagesDisabled_shouldNotRedactView() {
// -- Arrange --
let rootView = setupRCTImageViewFixture()

// -- Act --
let sut = getSut(maskAllText: true, maskAllImages: false)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 0)
}

func testRedact_withRCTImageView_withMaskAllTextDisabled_shouldRedactView() {
// -- Arrange --
let rootView = setupRCTImageViewFixture()

// -- Act --
let sut = getSut(maskAllText: false, maskAllImages: true)
let result = sut.redactRegionsFor(view: rootView)
let masked = createMaskedScreenshot(view: rootView, regions: result)

// -- Assert --
assertSnapshot(of: masked, as: .image)
XCTAssertEqual(result.count, 1)
}
}

#endif // os(iOS) && !targetEnvironment(macCatalyst)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading