Files
divkit/client/ios/LayoutKit/LayoutKitTests/ViewModels/GalleryViewLayoutTests.swift
T
divkit-github f1563c9890 chore(html-reporter): up version
Initial commit

Add notification for divkit

Allow overwrite for migration

[migration] browser/bitbucket/personal/booster/divkit

Note: mandatory check (NEED_CHECK) was skipped

DivKit files moved

dIVKIT-0: Fix ts builder build

update div-gallery visibility screenshots

update div-gallery visibility screens

a.yaml cleanup

updated codegen scripts

change gallery alignment

change internal types in expressions

removed copyrights

remove permissions

TemplatesSupportTests refactoring

Ничего не поменялось. Отрефакторил и почистил тесты.

Split package.json

send all public

removed yandex-team links

URL added type as ArgumentType

added camera permission description

safe area insets for errors count view

`EdgeInsets` for debug view with errors count. Needed for fullscreen divs. Naming corresponds to mapping `EdgeInsets` to div-variables.

Will be used here: https://nda.ya.ru/t/Lhr5Lxgb5KN6nX

fixed compiler warnings

fix DivKitComponents variables setup, add update func

fix DivKitComponents variables setup, add update func

authors clean up

Удалил коллег из инфраструктуры, тестирования и мессенджера. Половину людей я вообще тут не знаю. Список какой-то косячный, в нём, например, @booster и @askvortsov нет. Предлагаю заново вручную составить и записать туда тех, кто точно дивкитом занимался, а не просто мимо проходил.

Fix DivKit pods compilability

Fix DivKit pods compilability

use only english in demo app

translate divKit demo app russian text

Scroll when keyboard opened

Scroll when keyboard opened

Fix gallery scroll in a11y

Это копия пр-а, который я делал в репо алискита:

https://bitbucket.browser.yandex-team.ru/projects/ML/repos/mobile-alice-library-android/pull-requests/18808/overview

authors clean up2

SwiftGenerator

flake8 errors fix & ya.make edit

swift generation tests

swift references

swift generator implementation

init swift generator

code refactoring
1) rename to modeling
2) rename kind to PropertyType
3) delete apply_pluralization_rules
4) description default value is empty string
5) remove entity_type_field_alias, typename_alias, client_optional, profileEntities, ignore_properties, generate_plain_constructor
6) remove client prefix

Add XcodeBuild in ignore

Add XcodeBuild in ignore

introduce new global variable api

introduce new global variable api

Revert commit bdcbc0081395ebe44ed7fe24bf5f4b25569c6df0

LayoutKitSnapshotTests

Fix sandboxRelease dependencies.

support zero value for width and height

remove unused css variables

"CONTRIBUTING.md"

README draft

updated gitignore/arcignore

introduce color type in expressions

introduce color type in expressions

added xcconfig files

fixed swift formatting

fail tests if updating references

Чтобы уж точно не забыть вернуть False.

Layout changes

Fix expression parsing

don't change clickable state in a11y

don't change clickable state in a11y

Update items checks

Parse description references to translations

add licence file link

fixed expression properties generation

add ability to track requests to global variables

Добавляем в GlobalVariableController возможность подписаться на запросы к глобальным переменным.
Нужно дляОткрыт Накопительная палитра , а так же в целом полезная функциональность, через которую можно делать ленивый прогрев глобальных переменных

Changelog

Minor fixes

bump divkit version up to 3.0.0

fixed snapshot tests depdendencies

Иногда не запускалась сборка SnapshotTestsHostApp перед стартом тестов.

used new api-generator

deserialization refactoring

removed gitignore

samples text fixes

fixed samples text

remove theme button

remove theme button

demo activity redesign

demo activity redesign

habr sample app

change deleted images in screenshot tests

change deleted images in screenshot tests

new ic_launcher

new ic_launcher

more readme

Binding variable for div input

Biding variable for div input

Implement documentation generator

Rename max_lines to max_visible_lines

Rename max_lines to max_visible_lines

add habr and medium

fix div-functions doc

Fix link in description

Text selecting for demo app enabled

Text selecting for demo app enabled

KotlinGenerator

kotlin code generation

kotlin generation tests

kotlin generation references

add gradle wrapper to kotlin json builder

add gradle wrapper to kotlin json builder

DemoApp redesign

fixed codegen scripts

debugView safeAreaInsets

DebugView safe area insets

TypeScript Generator

ya.make changes

TypeScript generator

TypeScript tests

TypeScript test references

fix enumeration aliases

debugInfoParams fix compile

Fix black box flicker in video-custom

Fixed stub image showing by moving it away from PlayerView.
Increased stub loading speed by adding VideoViewModel warmup.
Fixed redundant redraws by combining stub visibility and
bitmap data.
PlayerView background was set to transparent.

DivExpression fix

DivExpression fix

Implement translations

Save & share

bind globalVariableController to divContext

bind variableController to divContext

used new TypeScript generator

Подключил генератор на питоне. Изменения в сгенерированных файлах связаны в основном с переводом описаний на английский язык.

moved LivePreview

Перенёс LivePreview из отдельного модуля в DivKitDemoApp. Добавил сканер кодов в UrlInputView. Удалил часть дублирующегося кода.

remove sms and phone_state permission

fix links interception

fix links interception

Fix link in documentation

remove site from "config.stable.json"

Support highlight_color and keyboardType in div input

Support highlight_color in div input

Action animation fix for iOS
2022-08-25 21:21:49 +03:00

407 lines
16 KiB
Swift

@testable import LayoutKit
import XCTest
import BaseUI
import CommonCore
final class GalleryViewLayoutTests: XCTestCase {
func test_ProducesEqualToModelBlocksCountNumberOfFrames() {
let model = Blocks.horizontalCenterModel
let layout = GalleryViewLayout(model: model)
XCTAssertEqual(layout.blockFrames.count, model.items.count)
}
func test_WhenHasHorizontalDirection_ProducesSummaryWidthAndBlockMaximumHeightContentSizePlusCrossInsets(
) {
let layout = GalleryViewLayout(model: Blocks.horizontalCenterModel)
XCTAssertEqual(layout.contentSize.width, Blocks.contentAxialSize)
XCTAssertEqual(layout.contentSize.height, Blocks.contentCrossMaxSize + Blocks.fixedInsets.sum)
}
func test_WhenDoesNotHaveBounds_AndHorizontalDirection_AppliesResizableBlockHeightToOtherBlocksMaximumHeight(
) {
let model = Blocks.horizontalCenterModel
let layout = GalleryViewLayout(model: model)
if let index = model.items.firstIndex(where: { $0.content.isVerticallyResizable }) {
XCTAssertEqual(layout.blockFrames[index].height, Blocks.contentCrossMaxSize)
} else {
XCTFail()
}
}
func test_WhenHasBounds_AndHorizontalDirection_AppliesResizableBlockHeightToInsetedBoundsHeight() {
let model = Blocks.horizontalCenterModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let height = boundsSize.height - Blocks.fixedInsets.sum
if let index = model.items.firstIndex(where: { $0.content.isVerticallyResizable }) {
XCTAssertEqual(layout.blockFrames[index].height, height)
} else {
XCTFail()
}
}
func test_WhenHasVerticalDirection_ProducesSummaryHeightAndBlockMaximumWidthContentSizePlusCrossInsets(
) {
let layout = GalleryViewLayout(model: Blocks.verticalCenterModel)
XCTAssertEqual(layout.contentSize.width, Blocks.contentCrossMaxSize + Blocks.fixedInsets.sum)
XCTAssertEqual(layout.contentSize.height, Blocks.contentAxialSize)
}
func test_WhenDoesNotHaveBounds_AndVerticalDirection_AppliesResizableBlockWidthToOtherBlocksMaximumWidth(
) {
let model = Blocks.verticalCenterModel
let layout = GalleryViewLayout(model: model)
if let index = model.items.firstIndex(where: { $0.content.isHorizontallyResizable }) {
XCTAssertEqual(layout.blockFrames[index].width, Blocks.contentCrossMaxSize)
} else {
XCTFail()
}
}
func test_WhenHasBounds_AndVerticalDirection_AppliesResizableBlockWidthToInsetedBoundsWidth() {
let model = Blocks.verticalCenterModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
if let index = model.items.firstIndex(where: { $0.content.isHorizontallyResizable }) {
XCTAssertEqual(layout.blockFrames[index].width, boundsSize.width - Blocks.fixedInsets.sum)
} else {
XCTFail()
}
}
func test_WhenHasResizableAxialInsets_AndHorizontalDirection_CalculatesContentSizeFittingProvidedSize(
) {
let model = Blocks.horizontalResizableModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedSize = Blocks.contentAxialSizeWithoutSideGaps + boundsSize.width - Blocks
.resizableInsets.maxViewportSize
XCTAssertEqual(layout.contentSize.width, expectedSize)
}
func test_WhenHasResizableAxialInsets_AndVerticalDirection_CalculatesContentSizeFittingProvidedSize(
) {
let model = Blocks.verticalResizableModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedSize = Blocks.contentAxialSizeWithoutSideGaps + boundsSize.height - Blocks
.resizableInsets.maxViewportSize
XCTAssertEqual(layout.contentSize.height, expectedSize)
}
func test_WhenHasResizableAxialInsets_AndHorizontalDirection_ProducesSideGapsFittingProvidedSize(
) {
let model = Blocks.horizontalResizableModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedInsetValue = (boundsSize.width - Blocks.resizableInsets.maxViewportSize) / 2
XCTAssertEqual(layout.blockFrames.first?.minX, expectedInsetValue)
XCTAssertEqual(layout.blockFrames.last?.maxX, layout.contentSize.width - expectedInsetValue)
}
func test_WhenHasResizableAxialInsets_AndVerticalDirection_ProducesSideGapsFittingProvidedSize() {
let model = Blocks.verticalResizableModel
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedInsetValue = (boundsSize.height - Blocks.resizableInsets.maxViewportSize) / 2
XCTAssertEqual(layout.blockFrames.first?.minY, expectedInsetValue)
XCTAssertEqual(layout.blockFrames.last?.maxY, layout.contentSize.height - expectedInsetValue)
}
func test_WhenHasResizableCrossInsets_AndVerticalDirection_ProducesSideGapsFittingProvidedSize() {
let model = Blocks.makeModel(
direction: .vertical,
metrics: .resizableCross,
crossAlignment: .leading
)
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedInsetValue = (boundsSize.width - Blocks.resizableInsets.maxViewportSize) / 2
XCTAssertEqual(layout.blockFrames.first?.minX, expectedInsetValue)
XCTAssertEqual(layout.blockFrames.first?.maxX, layout.contentSize.width - expectedInsetValue)
}
func test_WhenHasResizableCrossInsets_AndHorizontalDirection_ProducesSideGapsFittingProvidedSize(
) {
let model = Blocks.makeModel(
direction: .horizontal,
metrics: .resizableCross,
crossAlignment: .leading
)
let layout = GalleryViewLayout(model: model, boundsSize: boundsSize)
let expectedInsetValue = (boundsSize.height - Blocks.resizableInsets.maxViewportSize) / 2
XCTAssertEqual(layout.blockFrames.first?.minY, expectedInsetValue)
XCTAssertEqual(layout.blockFrames.first?.maxY, layout.contentSize.height - expectedInsetValue)
}
func test_WhenHasHorizontalDirection_StartsLeftEdgeAtFirstGapAndFinishesRightEdgeBeforeLastGap() {
let layout = GalleryViewLayout(model: Blocks.horizontalCenterModel)
XCTAssertEqual(layout.blockFrames.first?.minX, Blocks.gapSize)
XCTAssertEqual(layout.blockFrames.last?.maxX, Blocks.gapSize + Blocks.framesAxialSize)
}
func test_WhenHasHorizontalDirection_AndCenterVerticalAlignment_LayoutFramesAroundInsetedVerticalCenter(
) {
let layout = GalleryViewLayout(model: Blocks.horizontalCenterModel, boundsSize: boundsSize)
let center = floor(
Blocks.fixedInsets
.leading + (boundsSize.height - Blocks.fixedInsets.sum) / 2
)
XCTAssert(layout.blockFrames.allSatisfy { $0.midY.isApproximatelyEqualTo(center) })
}
func test_WhenHasHorizontalDirection_AndLeadingVerticalAlignment_LayoutFramesAboveCrossInsets() {
let layout = GalleryViewLayout(model: Blocks.horizontalTrailingModel, boundsSize: boundsSize)
let trailing = boundsSize.height - Blocks.fixedInsets.trailing
XCTAssert(layout.blockFrames.allSatisfy { $0.maxY.isApproximatelyEqualTo(trailing) })
}
func test_WhenHasHorizontalDirection_AndTrailingVerticalAlignment_LayoutFramesBelowCrossInsets() {
let layout = GalleryViewLayout(model: Blocks.horizontalLeadingModel, boundsSize: boundsSize)
XCTAssert(
layout.blockFrames
.allSatisfy { $0.minY.isApproximatelyEqualTo(Blocks.fixedInsets.leading) }
)
}
func test_WhenHasVerticalDirection_AndCenterHorizontalAlignment_LayoutFramesAroundInsetedHorizontalCenter(
) {
let layout = GalleryViewLayout(model: Blocks.verticalCenterModel, boundsSize: boundsSize)
let center = floor(Blocks.fixedInsets.leading + (boundsSize.width - Blocks.fixedInsets.sum) / 2)
XCTAssert(layout.blockFrames.allSatisfy { $0.midX.isApproximatelyEqualTo(center) })
}
func test_WhenHasVerticalDirection_AndLeadingHorizontalAlignment_LayoutFramesAtLeadingOfCrossInset(
) {
let layout = GalleryViewLayout(model: Blocks.verticalLeadingModel, boundsSize: boundsSize)
XCTAssert(
layout.blockFrames
.allSatisfy { $0.minX.isApproximatelyEqualTo(Blocks.fixedInsets.leading) }
)
}
func test_WhenHasVerticalDirection_AndTrailingHorizontalAlignment_LayoutFramesAtTrailingOfCrossInset(
) {
let layout = GalleryViewLayout(model: Blocks.verticalTrailingModel, boundsSize: boundsSize)
let trailing = boundsSize.width - Blocks.fixedInsets.trailing
XCTAssert(layout.blockFrames.allSatisfy { $0.maxX.isApproximatelyEqualTo(trailing) })
}
func test_WhenHasVerticalDirection_StartsHeightAtFirstGapAndFinishesBeforeLastGap() {
let layout = GalleryViewLayout(model: Blocks.verticalCenterModel)
XCTAssertEqual(layout.blockFrames.first?.minY, Blocks.gapSize)
XCTAssertEqual(layout.blockFrames.last?.maxY, Blocks.gapSize + Blocks.framesAxialSize)
}
func test_WhenHasPagingModel_ReturnsLastIndexForLastPageOrigin() {
let layout = GalleryViewLayout(model: Blocks.fixedPagingModel)
let index = layout.blockFrames.count - 1
let offset = layout.blockPages[index].origin
let pageIndex = layout.pageIndex(forContentOffset: offset)
XCTAssertEqual(pageIndex, CGFloat(index), accuracy: accuracy)
}
func test_WhenHasPagingModel_ReturnsZeroIndexForOffsetOutOfRange() {
let layout = GalleryViewLayout(model: Blocks.fixedPagingModel)
XCTAssertEqual(layout.pageIndex(forContentOffset: -1), 0, accuracy: accuracy)
XCTAssertEqual(layout.pageIndex(forContentOffset: .infinity), 0, accuracy: accuracy)
}
func test_WhenHasFixedPagingModel_ReturnsInitialOffsetForReverseConversion() {
let layout = GalleryViewLayout(model: Blocks.fixedPagingModel, boundsSize: boundsSize)
let page = layout.blockPages[2]
let offset = page.origin + page.size / 2
let pageIndex = layout.pageIndex(forContentOffset: offset)
let foundOffset = layout.contentOffset(pageIndex: pageIndex)
XCTAssertEqual(offset, foundOffset, accuracy: accuracy)
}
func test_WhenHasAutoPagingModel_ReturnsInitialOffsetForReverseConversion() {
let layout = GalleryViewLayout(model: Blocks.autoPagingModel, boundsSize: boundsSize)
let page = layout.blockPages[2]
let offset = page.origin + page.size / 2
let pageIndex = layout.pageIndex(forContentOffset: offset)
let foundOffset = layout.contentOffset(pageIndex: pageIndex)
XCTAssertEqual(offset, foundOffset, accuracy: accuracy)
}
func test_WhenHasAutoPagingModel_ReturnsMaxOffsetForLastPage() {
let layout = GalleryViewLayout(model: Blocks.autoPagingModel, boundsSize: boundsSize)
let offset = layout.contentOffset(
pageIndex: CGFloat(layout.blockPages.count - 1)
)
let maxOffset = layout.contentSize.width - boundsSize.width
XCTAssertEqual(maxOffset, offset, accuracy: accuracy)
}
func test_WhenHasPagingModel_DetectsContainingGreaterOrEqualMinimumAndLowerMaximumWithAccuracy() {
let layout = GalleryViewLayout(model: Blocks.fixedPagingModel)
if let page = layout.blockPages.first {
let below = page.origin - .leastNonzeroMagnitude
let middle = page.origin + page.size / 2
let upper = page.origin + page.size - .leastNonzeroMagnitude
XCTAssertTrue(page.contains(below))
XCTAssertTrue(page.contains(middle))
XCTAssertFalse(page.contains(upper))
} else {
XCTFail()
}
}
func test_WhenHasPagingModel_ContainsContinuousPages() {
let layout = GalleryViewLayout(model: Blocks.fixedPagingModel)
let totalSpace = (1..<layout.blockPages.count).reduce(CGFloat(0)) { result, index in
let page = layout.blockPages[index - 1]
let nextPage = layout.blockPages[index]
return result + nextPage.origin - (page.origin + page.size)
}
XCTAssertEqual(totalSpace, 0, accuracy: accuracy)
}
}
private enum Blocks {
private static let horizontallyResizable: Block = SeparatorBlock(direction: .horizontal)
private static let verticallyResizable: Block = SeparatorBlock(direction: .vertical)
private static let small: Block = try! ContainerBlock(
layoutDirection: .horizontal,
widthTrait: .fixed(smallSize),
heightTrait: .fixed(smallSize),
children: [verticallyResizable]
)
private static let big: Block = try! ContainerBlock(
layoutDirection: .horizontal,
widthTrait: .fixed(bigSize),
heightTrait: .fixed(bigSize),
children: [verticallyResizable]
)
static func makeModel(
direction: GalleryViewModel.Direction = .horizontal,
metrics: GalleryViewMetrics = .fixed,
crossAlignment: Alignment = .center,
scrollMode: GalleryViewModel.ScrollMode = .default
) -> GalleryViewModel {
let resizableBlock = direction.isHorizontal ? verticallyResizable : horizontallyResizable
let blocks = [Block](repeating: big, times: try! UInt(value: bigCount)) +
[Block](repeating: small, times: try! UInt(value: smallCount)) +
[Block](repeating: resizableBlock, times: try! UInt(value: resizableCount))
return GalleryViewModel(
blocks: blocks,
metrics: metrics,
scrollMode: scrollMode,
path: UIElementPath("model"),
direction: direction,
crossAlignment: crossAlignment
)
}
static let smallCount = 2
static let bigCount = 2
static let resizableCount = 2
static let totalCount = bigCount + smallCount + resizableCount
static let blocksCount = smallCount + bigCount + resizableCount
static let smallSize = CGFloat(64)
static let bigSize = CGFloat(128)
static let resizableSize = CGFloat(1)
static let gapSize = CGFloat(1)
static let bigAxialSize = bigSize * CGFloat(bigCount)
static let smallAxialSize = smallSize * CGFloat(smallCount)
static let resizableAxialSize = resizableSize * CGFloat(resizableCount)
static let gapAxialSize = gapSize * CGFloat(blocksCount + 1)
static let framesAxialSize = bigAxialSize + smallAxialSize + resizableAxialSize + gapSize *
CGFloat(max(blocksCount - 1, 0))
static let contentAxialSize = bigAxialSize + smallAxialSize + resizableAxialSize + gapAxialSize
static let contentAxialSizeWithoutSideGaps = contentAxialSize - 2 * gapSize
static let contentCrossMaxSize = max(bigSize, smallSize)
static let horizontalCenterModel = makeModel()
static let horizontalLeadingModel = makeModel(crossAlignment: .leading)
static let horizontalTrailingModel = makeModel(crossAlignment: .trailing)
static let verticalCenterModel = makeModel(direction: .vertical)
static let verticalLeadingModel = makeModel(
direction: .vertical,
crossAlignment: .leading
)
static let verticalTrailingModel = makeModel(
direction: .vertical,
crossAlignment: .trailing
)
static let fixedPagingModel = makeModel(scrollMode: .fixedPaging(pageSize: boundsSize.width))
static let autoPagingModel = makeModel(scrollMode: .autoPaging)
static let fixedInsets = SideInsets(leading: 4, trailing: 10)
static let resizableInsets = InsetMode.Resizable(minValue: 10, maxViewportSize: 14)
static let horizontalResizableModel = makeModel(metrics: .resizableAxial)
static let verticalResizableModel = makeModel(
direction: .vertical,
metrics: .resizableAxial
)
}
private let boundsSize = CGSize(width: 64, height: 64)
private let accuracy: CGFloat = 1e-4
extension GalleryViewMetrics {
fileprivate static let spacings = [CGFloat](
repeating: Blocks.gapSize,
times: try! UInt(value: Blocks.totalCount - 1)
)
fileprivate static let resizableAxial = GalleryViewMetrics(
axialInsetMode: .resizable(params: Blocks.resizableInsets),
crossInsetMode: .fixed(values: Blocks.fixedInsets),
spacings: spacings
)
fileprivate static let fixed = GalleryViewMetrics(
axialInsetMode: .fixed(values: SideInsets(leading: Blocks.gapSize, trailing: Blocks.gapSize)),
crossInsetMode: .fixed(values: Blocks.fixedInsets),
spacings: spacings
)
fileprivate static let resizableCross = GalleryViewMetrics(
axialInsetMode: .fixed(values: Blocks.fixedInsets),
crossInsetMode: .resizable(params: Blocks.resizableInsets),
spacings: spacings
)
}