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 + } + +}