From 5d14a31e135546a0e38f9a4ba7479914466d8685 Mon Sep 17 00:00:00 2001 From: tsushanth <78000697+tsushanth@users.noreply.github.com> Date: Tue, 9 Jun 2026 16:59:43 -0700 Subject: [PATCH] tests: pin _enableExperimentalOptimizations = true via subclass of ModelStateLayoutTests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `MagazineLayout._enableExperimentalOptimizations` is documented in `MagazineLayout.swift` as "A temporary flag to enable safely testing some optimizations" (added in #156). The flag gates 35+ branches across `MagazineLayout.swift`, `SectionModel.swift`, and `ModelState.swift`, but no existing test exercises it. Flipping the default is risky without automated coverage of the optimized code paths. This change adds `ModelStateLayoutTestsWithExperimentalOptimizations`, which subclasses `ModelStateLayoutTests` and flips the flag in `setUp` (restoring `false` in `tearDown`). XCTest reruns every inherited test method against the optimized path. Any divergence between the optimized and legacy paths now fails a test. Mechanically: - Drop `final` from `ModelStateLayoutTests` so it can be subclassed (test-only change; production code unaffected) - Add a single 47-line subclass file that overrides `setUp` / `tearDown` - Wire the new file into the Xcode test target Verified locally: ModelStateLayoutTests (11 tests, flag=false) + ModelStateLayoutTestsWithExperimentalOptimizations (11 tests, flag=true) = 22 tests, 0 failures. This is a starting wedge — if accepted, the same pattern can extend to `ModelStateUpdateTests`, `ElementLocationFramePairsTests`, `LayoutStateTargetContentOffsetTests`, etc. Happy to follow up with those in a separate PR once you confirm the approach. Co-Authored-By: Claude Opus 4.7 (1M context) --- MagazineLayout.xcodeproj/project.pbxproj | 4 ++ Tests/ModelStateLayoutTests.swift | 2 +- ...utTestsWithExperimentalOptimizations.swift | 48 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Tests/ModelStateLayoutTestsWithExperimentalOptimizations.swift diff --git a/MagazineLayout.xcodeproj/project.pbxproj b/MagazineLayout.xcodeproj/project.pbxproj index bb26cf8..1b39ab8 100644 --- a/MagazineLayout.xcodeproj/project.pbxproj +++ b/MagazineLayout.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ 93A1C04D21ACED1100DED67D /* TestingSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A1C00E21ACED0100DED67D /* TestingSupport.swift */; }; 93A1C04E21ACED1100DED67D /* ElementLocationFramePairsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A1C00F21ACED0100DED67D /* ElementLocationFramePairsTests.swift */; }; 93A1C04F21ACED1100DED67D /* ModelStateUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A1C01021ACED0100DED67D /* ModelStateUpdateTests.swift */; }; + F138D77EBE7D94D3B3101732 /* ModelStateLayoutTestsWithExperimentalOptimizations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94CA59E0DE3A41D6D3B33EF6 /* ModelStateLayoutTestsWithExperimentalOptimizations.swift */; }; 93A868552EE0D7870027691E /* IDGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A868542EE0D7870027691E /* IDGenerator.swift */; }; 93F8D8B22FD38BBF005325C0 /* Array+SafeSubscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93F8D8B12FD38BBF005325C0 /* Array+SafeSubscript.swift */; }; 93F8DAE62FD76026005325C0 /* Signposting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93F8DAE52FD76026005325C0 /* Signposting.swift */; }; @@ -78,6 +79,7 @@ 93A1C00E21ACED0100DED67D /* TestingSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestingSupport.swift; sourceTree = ""; }; 93A1C00F21ACED0100DED67D /* ElementLocationFramePairsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElementLocationFramePairsTests.swift; sourceTree = ""; }; 93A1C01021ACED0100DED67D /* ModelStateUpdateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelStateUpdateTests.swift; sourceTree = ""; }; + 94CA59E0DE3A41D6D3B33EF6 /* ModelStateLayoutTestsWithExperimentalOptimizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelStateLayoutTestsWithExperimentalOptimizations.swift; sourceTree = ""; }; 93A1C01621ACED0100DED67D /* MagazineLayoutBackgroundVisibilityMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagazineLayoutBackgroundVisibilityMode.swift; sourceTree = ""; }; 93A1C01721ACED0100DED67D /* MagazineLayout+SupplementaryViewKinds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MagazineLayout+SupplementaryViewKinds.swift"; sourceTree = ""; }; 93A1C01821ACED0100DED67D /* MagazineLayoutItemSizeMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagazineLayoutItemSizeMode.swift; sourceTree = ""; }; @@ -161,6 +163,7 @@ FDE08E152B2CC47800C9D24D /* LayoutStateTargetContentOffsetTests.swift */, 93A1C00A21ACED0100DED67D /* ModelStateEmptySectionLayoutTests.swift */, 93A1C00D21ACED0100DED67D /* ModelStateLayoutTests.swift */, + 94CA59E0DE3A41D6D3B33EF6 /* ModelStateLayoutTestsWithExperimentalOptimizations.swift */, 93A1C01021ACED0100DED67D /* ModelStateUpdateTests.swift */, 93A1C00F21ACED0100DED67D /* ElementLocationFramePairsTests.swift */, 9332FB0622969AB200483D99 /* RowOffsetTrackerTests.swift */, @@ -404,6 +407,7 @@ 60432D952E05DB41001728F0 /* ContentInsetAdjustingContentOffsetTests.swift in Sources */, 9332FB0822969B5600483D99 /* RowOffsetTrackerTests.swift in Sources */, 93A1C04C21ACED1100DED67D /* ModelStateLayoutTests.swift in Sources */, + F138D77EBE7D94D3B3101732 /* ModelStateLayoutTestsWithExperimentalOptimizations.swift in Sources */, 93A1C04921ACED1100DED67D /* ModelStateEmptySectionLayoutTests.swift in Sources */, 93A1C04F21ACED1100DED67D /* ModelStateUpdateTests.swift in Sources */, 93A1C04D21ACED1100DED67D /* TestingSupport.swift in Sources */, diff --git a/Tests/ModelStateLayoutTests.swift b/Tests/ModelStateLayoutTests.swift index dc74e3d..83baef2 100644 --- a/Tests/ModelStateLayoutTests.swift +++ b/Tests/ModelStateLayoutTests.swift @@ -18,7 +18,7 @@ import XCTest @testable import MagazineLayout @available(iOS 18.0, *) -final class ModelStateLayoutTests: XCTestCase { +class ModelStateLayoutTests: XCTestCase { // MARK: Internal diff --git a/Tests/ModelStateLayoutTestsWithExperimentalOptimizations.swift b/Tests/ModelStateLayoutTestsWithExperimentalOptimizations.swift new file mode 100644 index 0000000..a94bba7 --- /dev/null +++ b/Tests/ModelStateLayoutTestsWithExperimentalOptimizations.swift @@ -0,0 +1,48 @@ +// Created by tsushanth on 6/9/26. +// Copyright © 2026 Airbnb, Inc. + +// 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. + +import XCTest + +@testable import MagazineLayout + +/// Re-runs every test in `ModelStateLayoutTests` with +/// `MagazineLayout._enableExperimentalOptimizations = true`. +/// +/// The static flag is currently documented as "A temporary flag to enable safely +/// testing some optimizations" (see `MagazineLayout.swift`). It gates 35+ branches +/// across `MagazineLayout.swift`, `SectionModel.swift`, and `ModelState.swift`. +/// Without an automated check, the optimized code paths can drift away from the +/// legacy paths silently. +/// +/// By subclassing `ModelStateLayoutTests` and flipping the flag in `setUp`, every +/// existing layout assertion is automatically rerun against the optimized path. +/// Any divergence between the two paths now fails a test. +/// +/// `tearDown` always restores the flag to `false` so subsequent suites are not +/// affected by ordering. +@available(iOS 18.0, *) +final class ModelStateLayoutTestsWithExperimentalOptimizations: ModelStateLayoutTests { + + override func setUp() { + MagazineLayout._enableExperimentalOptimizations = true + super.setUp() + } + + override func tearDown() { + super.tearDown() + MagazineLayout._enableExperimentalOptimizations = false + } + +}