Skip to content

Commit 0e2b54b

Browse files
Coverage (#27)
* Add Codecov configuration Configure Codecov with: - 70-100% coverage range target - 5% threshold for project coverage - 80% patch coverage target (informational) - Ignore patterns for test files and app entry points * Add unit tests for gesture and touch models Create MiddleDragTests target with 22 unit tests: - GestureModelsTests: 10 tests covering GestureState, GestureConfiguration, and UserPreferences - TouchModelsTests: 12 tests covering MTPoint, TouchState, and TrackedFinger Tests validate core model behavior including: - Distance and midpoint calculations - State machine transitions - Velocity sensitivity calculations - Touch tracking logic * Add MiddleDragTests target to Xcode project - Add test target with build configurations - Configure test host to run against MiddleDrag.app - Enable code coverage in scheme - Add testable reference to scheme's TestAction * Update CI workflow for code coverage and Codecov - Rename workflow to 'Build & Test' - Switch to Debug configuration for coverage data - Add test step with code coverage enabled - Convert coverage to lcov format - Upload results to Codecov via codecov-action@v5 Requires CODECOV_TOKEN secret to be configured. * Add Bitrise CI configuration for primary CI Configure Bitrise as primary CI with: - primary workflow: build, test, coverage upload to Codecov - deploy workflow: release/distribution builds - Xcode 16.2 on M1 machines - DerivedData caching for faster builds Requires CODECOV_TOKEN secret in Bitrise. * Simplify GitHub Actions to build-only PR check Bitrise now handles primary CI with tests and coverage. GitHub Actions provides quick build verification for PRs only. * Update .github/workflows/objective-c-xcode.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Karan Mohindroo <96403086+NullPointerDepressiveDisorder@users.noreply.github.com> --------- Signed-off-by: Karan Mohindroo <96403086+NullPointerDepressiveDisorder@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 5371ddb commit 0e2b54b

7 files changed

Lines changed: 557 additions & 9 deletions

File tree

.github/workflows/objective-c-xcode.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
name: Build
1+
name: Build Check
22
permissions:
33
contents: read
44

55
on:
66
push:
7-
branches:
8-
- '**'
7+
branches:
8+
- main
99
pull_request:
1010
branches:
11-
- '**'
11+
- main
1212

1313
jobs:
14-
1514
pre_job:
1615
runs-on: ubuntu-latest
1716
outputs:
@@ -23,18 +22,18 @@ jobs:
2322
build:
2423
needs: pre_job
2524
if: ${{ needs.pre_job.outputs.should_skip != 'true' }}
26-
name: Build MiddleDrag
25+
name: Quick Build Check
2726
runs-on: macos-15
28-
27+
2928
steps:
3029
- name: Checkout
3130
uses: actions/checkout@v4
32-
31+
3332
- name: Build
3433
run: |
3534
xcodebuild -scheme MiddleDrag \
3635
-project MiddleDrag.xcodeproj \
37-
-configuration Release \
36+
-configuration Debug \
3837
-destination "platform=macOS" \
3938
CODE_SIGN_IDENTITY="" \
4039
CODE_SIGNING_REQUIRED=NO \

MiddleDrag.xcodeproj/project.pbxproj

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
EC5F1E222ED8E37A0053F6A9 /* MiddleDragApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC5F1E092ED8E37A0053F6A9 /* MiddleDragApp.swift */; };
2424
EC5F1E232ED8E37A0053F6A9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC5F1E242ED8E37A0053F6A9 /* Assets.xcassets */; };
2525
EC93816B2EDE493A0012FDBE /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = EC93816A2EDE493A0012FDBE /* Sentry */; };
26+
MDT00000001 /* GestureModelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = MDT00000003 /* GestureModelsTests.swift */; };
27+
MDT00000002 /* TouchModelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = MDT00000004 /* TouchModelsTests.swift */; };
2628
/* End PBXBuildFile section */
2729

2830
/* Begin PBXFileReference section */
@@ -46,6 +48,9 @@
4648
EC5F1E122ED8E37A0053F6A9 /* LaunchAtLoginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLoginManager.swift; sourceTree = "<group>"; };
4749
EC5F1E132ED8E37A0053F6A9 /* PreferencesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesManager.swift; sourceTree = "<group>"; };
4850
EC5F1E242ED8E37A0053F6A9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
51+
MDT00000003 /* GestureModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureModelsTests.swift; sourceTree = "<group>"; };
52+
MDT00000004 /* TouchModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchModelsTests.swift; sourceTree = "<group>"; };
53+
MDT00000005 /* MiddleDragTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MiddleDragTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4954
/* End PBXFileReference section */
5055

5156
/* Begin PBXFrameworksBuildPhase section */
@@ -64,6 +69,7 @@
6469
isa = PBXGroup;
6570
children = (
6671
1A0000009 /* MiddleDrag */,
72+
MDT00000006 /* MiddleDragTests */,
6773
1A0000010 /* Products */,
6874
);
6975
sourceTree = "<group>";
@@ -91,10 +97,20 @@
9197
isa = PBXGroup;
9298
children = (
9399
1A0000004 /* MiddleDrag.app */,
100+
MDT00000005 /* MiddleDragTests.xctest */,
94101
);
95102
name = Products;
96103
sourceTree = "<group>";
97104
};
105+
MDT00000006 /* MiddleDragTests */ = {
106+
isa = PBXGroup;
107+
children = (
108+
MDT00000003 /* GestureModelsTests.swift */,
109+
MDT00000004 /* TouchModelsTests.swift */,
110+
);
111+
path = MiddleDragTests;
112+
sourceTree = "<group>";
113+
};
98114
EC5F1E022ED8E37A0053F6A9 /* Core */ = {
99115
isa = PBXGroup;
100116
children = (
@@ -163,6 +179,24 @@
163179
productReference = 1A0000004 /* MiddleDrag.app */;
164180
productType = "com.apple.product-type.application";
165181
};
182+
MDT00000007 /* MiddleDragTests */ = {
183+
isa = PBXNativeTarget;
184+
buildConfigurationList = MDT00000008 /* Build configuration list for PBXNativeTarget "MiddleDragTests" */;
185+
buildPhases = (
186+
MDT00000009 /* Sources */,
187+
MDT00000010 /* Frameworks */,
188+
MDT00000011 /* Resources */,
189+
);
190+
buildRules = (
191+
);
192+
dependencies = (
193+
MDT00000012 /* PBXTargetDependency */,
194+
);
195+
name = MiddleDragTests;
196+
productName = MiddleDragTests;
197+
productReference = MDT00000005 /* MiddleDragTests.xctest */;
198+
productType = "com.apple.product-type.bundle.unit-test";
199+
};
166200
/* End PBXNativeTarget section */
167201

168202
/* Begin PBXProject section */
@@ -176,6 +210,10 @@
176210
1A0000011 = {
177211
CreatedOnToolsVersion = 14.0;
178212
};
213+
MDT00000007 = {
214+
CreatedOnToolsVersion = 14.0;
215+
TestTargetID = 1A0000011;
216+
};
179217
};
180218
};
181219
buildConfigurationList = 1A0000016 /* Build configuration list for PBXProject "MiddleDrag" */;
@@ -195,6 +233,7 @@
195233
projectRoot = "";
196234
targets = (
197235
1A0000011 /* MiddleDrag */,
236+
MDT00000007 /* MiddleDragTests */,
198237
);
199238
};
200239
/* End PBXProject section */
@@ -255,8 +294,55 @@
255294
);
256295
runOnlyForDeploymentPostprocessing = 0;
257296
};
297+
MDT00000009 /* Sources */ = {
298+
isa = PBXSourcesBuildPhase;
299+
buildActionMask = 2147483647;
300+
files = (
301+
MDT00000001 /* GestureModelsTests.swift in Sources */,
302+
MDT00000002 /* TouchModelsTests.swift in Sources */,
303+
);
304+
runOnlyForDeploymentPostprocessing = 0;
305+
};
258306
/* End PBXSourcesBuildPhase section */
259307

308+
/* Begin PBXFrameworksBuildPhase section for Tests */
309+
MDT00000010 /* Frameworks */ = {
310+
isa = PBXFrameworksBuildPhase;
311+
buildActionMask = 2147483647;
312+
files = (
313+
);
314+
runOnlyForDeploymentPostprocessing = 0;
315+
};
316+
/* End PBXFrameworksBuildPhase section for Tests */
317+
318+
/* Begin PBXResourcesBuildPhase section for Tests */
319+
MDT00000011 /* Resources */ = {
320+
isa = PBXResourcesBuildPhase;
321+
buildActionMask = 2147483647;
322+
files = (
323+
);
324+
runOnlyForDeploymentPostprocessing = 0;
325+
};
326+
/* End PBXResourcesBuildPhase section for Tests */
327+
328+
/* Begin PBXTargetDependency section */
329+
MDT00000012 /* PBXTargetDependency */ = {
330+
isa = PBXTargetDependency;
331+
target = 1A0000011 /* MiddleDrag */;
332+
targetProxy = MDT00000015 /* PBXContainerItemProxy */;
333+
};
334+
/* End PBXTargetDependency section */
335+
336+
/* Begin PBXContainerItemProxy section */
337+
MDT00000015 /* PBXContainerItemProxy */ = {
338+
isa = PBXContainerItemProxy;
339+
containerPortal = 1A0000015 /* Project object */;
340+
proxyType = 1;
341+
remoteGlobalIDString = 1A0000011;
342+
remoteInfo = MiddleDrag;
343+
};
344+
/* End PBXContainerItemProxy section */
345+
260346
/* Begin XCBuildConfiguration section */
261347
1A0000017 /* Debug */ = {
262348
isa = XCBuildConfiguration;
@@ -468,8 +554,54 @@
468554
defaultConfigurationIsVisible = 0;
469555
defaultConfigurationName = Release;
470556
};
557+
MDT00000008 /* Build configuration list for PBXNativeTarget "MiddleDragTests" */ = {
558+
isa = XCConfigurationList;
559+
buildConfigurations = (
560+
MDT00000013 /* Debug */,
561+
MDT00000014 /* Release */,
562+
);
563+
defaultConfigurationIsVisible = 0;
564+
defaultConfigurationName = Release;
565+
};
471566
/* End XCConfigurationList section */
472567

568+
/* Begin XCBuildConfiguration section for Tests */
569+
MDT00000013 /* Debug */ = {
570+
isa = XCBuildConfiguration;
571+
buildSettings = {
572+
BUNDLE_LOADER = "$(TEST_HOST)";
573+
CODE_SIGN_STYLE = Automatic;
574+
CURRENT_PROJECT_VERSION = 1;
575+
GENERATE_INFOPLIST_FILE = YES;
576+
MACOSX_DEPLOYMENT_TARGET = 11.0;
577+
MARKETING_VERSION = 1.0;
578+
PRODUCT_BUNDLE_IDENTIFIER = com.middledrag.MiddleDragTests;
579+
PRODUCT_NAME = "$(TARGET_NAME)";
580+
SWIFT_EMIT_LOC_STRINGS = NO;
581+
SWIFT_VERSION = 5.0;
582+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MiddleDrag.app/Contents/MacOS/MiddleDrag";
583+
};
584+
name = Debug;
585+
};
586+
MDT00000014 /* Release */ = {
587+
isa = XCBuildConfiguration;
588+
buildSettings = {
589+
BUNDLE_LOADER = "$(TEST_HOST)";
590+
CODE_SIGN_STYLE = Automatic;
591+
CURRENT_PROJECT_VERSION = 1;
592+
GENERATE_INFOPLIST_FILE = YES;
593+
MACOSX_DEPLOYMENT_TARGET = 11.0;
594+
MARKETING_VERSION = 1.0;
595+
PRODUCT_BUNDLE_IDENTIFIER = com.middledrag.MiddleDragTests;
596+
PRODUCT_NAME = "$(TARGET_NAME)";
597+
SWIFT_EMIT_LOC_STRINGS = NO;
598+
SWIFT_VERSION = 5.0;
599+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MiddleDrag.app/Contents/MacOS/MiddleDrag";
600+
};
601+
name = Release;
602+
};
603+
/* End XCBuildConfiguration section for Tests */
604+
473605
/* Begin XCRemoteSwiftPackageReference section */
474606
EC9381692EDE49030012FDBE /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
475607
isa = XCRemoteSwiftPackageReference;

MiddleDrag.xcodeproj/xcshareddata/xcschemes/MiddleDrag.xcscheme

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,21 @@
2828
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2929
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
3030
shouldUseLaunchSchemeArgsEnv = "YES"
31+
codeCoverageEnabled = "YES"
3132
shouldAutocreateTestPlan = "YES">
33+
<Testables>
34+
<TestableReference
35+
skipped = "NO"
36+
parallelizable = "YES">
37+
<BuildableReference
38+
BuildableIdentifier = "primary"
39+
BlueprintIdentifier = "MDT00000007"
40+
BuildableName = "MiddleDragTests.xctest"
41+
BlueprintName = "MiddleDragTests"
42+
ReferencedContainer = "container:MiddleDrag.xcodeproj">
43+
</BuildableReference>
44+
</TestableReference>
45+
</Testables>
3246
</TestAction>
3347
<LaunchAction
3448
buildConfiguration = "Debug"
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import XCTest
2+
3+
@testable import MiddleDrag
4+
5+
final class GestureModelsTests: XCTestCase {
6+
7+
// MARK: - GestureState Tests
8+
9+
func testGestureStateIdleIsNotActive() {
10+
let state = GestureState.idle
11+
XCTAssertFalse(state.isActive)
12+
}
13+
14+
func testGestureStatePossibleTapIsActive() {
15+
let state = GestureState.possibleTap
16+
XCTAssertTrue(state.isActive)
17+
}
18+
19+
func testGestureStateDraggingIsActive() {
20+
let state = GestureState.dragging
21+
XCTAssertTrue(state.isActive)
22+
}
23+
24+
func testGestureStateWaitingForReleaseIsNotActive() {
25+
let state = GestureState.waitingForRelease
26+
XCTAssertFalse(state.isActive)
27+
}
28+
29+
// MARK: - GestureConfiguration Tests
30+
31+
func testDefaultGestureConfiguration() {
32+
let config = GestureConfiguration()
33+
34+
XCTAssertEqual(config.sensitivity, 1.0)
35+
XCTAssertEqual(config.smoothingFactor, 0.3)
36+
XCTAssertEqual(config.tapThreshold, 0.15)
37+
XCTAssertEqual(config.moveThreshold, 0.015)
38+
XCTAssertTrue(config.middleDragEnabled)
39+
XCTAssertFalse(config.blockSystemGestures)
40+
}
41+
42+
func testEffectiveSensitivityWithoutVelocityBoost() {
43+
var config = GestureConfiguration()
44+
config.enableVelocityBoost = false
45+
config.sensitivity = 2.0
46+
47+
let velocity = MTPoint(x: 10.0, y: 10.0)
48+
let effective = config.effectiveSensitivity(for: velocity)
49+
50+
XCTAssertEqual(effective, 2.0, "Should return base sensitivity when boost disabled")
51+
}
52+
53+
func testEffectiveSensitivityWithVelocityBoost() {
54+
var config = GestureConfiguration()
55+
config.enableVelocityBoost = true
56+
config.sensitivity = 1.0
57+
config.maxVelocityBoost = 2.0
58+
59+
let velocity = MTPoint(x: 1.0, y: 1.0)
60+
let effective = config.effectiveSensitivity(for: velocity)
61+
62+
XCTAssertGreaterThan(effective, 1.0, "Should boost sensitivity with velocity")
63+
}
64+
65+
func testEffectiveSensitivityCapsAtMaxBoost() {
66+
var config = GestureConfiguration()
67+
config.enableVelocityBoost = true
68+
config.sensitivity = 1.0
69+
config.maxVelocityBoost = 2.0
70+
71+
// Very high velocity
72+
let velocity = MTPoint(x: 100.0, y: 100.0)
73+
let effective = config.effectiveSensitivity(for: velocity)
74+
75+
// maxBoost of 2.0 => boost factor = 1 + 2.0 * 0.5 = 2.0
76+
XCTAssertEqual(effective, 2.0, "Should cap at max velocity boost")
77+
}
78+
79+
// MARK: - UserPreferences Tests
80+
81+
func testDefaultUserPreferences() {
82+
let prefs = UserPreferences()
83+
84+
XCTAssertFalse(prefs.launchAtLogin)
85+
XCTAssertEqual(prefs.dragSensitivity, 1.0)
86+
XCTAssertEqual(prefs.tapThreshold, 0.15)
87+
XCTAssertEqual(prefs.smoothingFactor, 0.3)
88+
XCTAssertFalse(prefs.blockSystemGestures)
89+
XCTAssertTrue(prefs.middleDragEnabled)
90+
}
91+
92+
func testUserPreferencesToGestureConfig() {
93+
var prefs = UserPreferences()
94+
prefs.dragSensitivity = 2.5
95+
prefs.smoothingFactor = 0.5
96+
prefs.tapThreshold = 0.2
97+
prefs.blockSystemGestures = true
98+
prefs.middleDragEnabled = false
99+
100+
let config = prefs.gestureConfig
101+
102+
XCTAssertEqual(config.sensitivity, 2.5)
103+
XCTAssertEqual(config.smoothingFactor, 0.5)
104+
XCTAssertEqual(config.tapThreshold, 0.2)
105+
XCTAssertTrue(config.blockSystemGestures)
106+
XCTAssertFalse(config.middleDragEnabled)
107+
}
108+
}

0 commit comments

Comments
 (0)