Skip to content

Commit 7b45f29

Browse files
authored
fix: no whitespace allowed in file renaming - WPB-21698 (#4053)
1 parent 7288ff0 commit 7b45f29

File tree

3 files changed

+108
-4
lines changed

3 files changed

+108
-4
lines changed

WireMessaging/Sources/WireMessagingUI/WireCells/Components/Files/FileRenameViewModel.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ final class FileRenameViewModel: ObservableObject {
9595
}
9696
}
9797

98+
private var trimmedInput: String {
99+
filenameInput.trimmingCharacters(in: .whitespacesAndNewlines)
100+
}
101+
98102
init(
99103
renameNodeUseCase: any WireCellsRenameNodeUseCaseProtocol,
100104
model: Model,
@@ -119,7 +123,7 @@ final class FileRenameViewModel: ObservableObject {
119123
try await renameNodeUseCase.invoke(
120124
nodeID: nodeID,
121125
nodeFilepath: nodeFilePath,
122-
newFilename: filenameInput,
126+
newFilename: trimmedInput,
123127
isFolder: kind == .folder
124128
)
125129

@@ -149,8 +153,8 @@ final class FileRenameViewModel: ObservableObject {
149153

150154
private func bindTextInput() {
151155
$filenameInput
152-
.compactMap { [weak self] input in
153-
self?.filenameValidator.validate(input)
156+
.compactMap { [weak self] _ in
157+
self?.filenameValidator.validate(self?.trimmedInput ?? "")
154158
}
155159
.flatMap(\.self)
156160
.sink { [weak self] result in

WireMessaging/Sources/WireMessagingUI/WireCells/Components/Files/FilenameValidator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct FilenameValidator {
3232
}
3333

3434
func validate(_ input: String) -> AnyPublisher<Result<Void, Failure>, Never> {
35-
let result: Result<Void, Failure> = if input.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
35+
let result: Result<Void, Failure> = if input.isEmpty {
3636
.failure(.empty)
3737
} else if input.hasPrefix(".") {
3838
.failure(.dotPrefix)
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// Wire
3+
// Copyright (C) 2026 Wire Swiss GmbH
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with this program. If not, see http://www.gnu.org/licenses/.
17+
//
18+
19+
import Foundation
20+
import Testing
21+
22+
@testable import WireMessagingUI
23+
24+
@MainActor
25+
final class FilenameValidatorTests {
26+
private let sut: FilenameValidator
27+
28+
init() {
29+
self.sut = FilenameValidator()
30+
}
31+
32+
@Test
33+
func `When input is valid it succeeds`() async {
34+
// given
35+
let input = "filename"
36+
37+
// when
38+
var iterator = sut.validate(input).values.makeAsyncIterator()
39+
let result = await iterator.next()!
40+
41+
// then
42+
#expect((try? result.get()) != nil)
43+
}
44+
45+
@Test
46+
func `When input is too long it throws error`() async {
47+
// given
48+
let input = Array(repeating: "t", count: 65).joined()
49+
50+
// then
51+
await #expect(throws: FilenameValidator.Failure.tooLong) {
52+
// when
53+
var iterator = sut.validate(input).values.makeAsyncIterator()
54+
let result = await iterator.next()!
55+
try result.get()
56+
}
57+
}
58+
59+
@Test
60+
func `When input has dot prefix it throws error`() async {
61+
// given
62+
let input = ".filename"
63+
64+
// then
65+
await #expect(throws: FilenameValidator.Failure.dotPrefix) {
66+
// when
67+
var iterator = sut.validate(input).values.makeAsyncIterator()
68+
let result = await iterator.next()!
69+
try result.get()
70+
}
71+
}
72+
73+
@Test
74+
func `When input has slash character it throws error`() async {
75+
// given
76+
let input = "filename/"
77+
78+
// then
79+
await #expect(throws: FilenameValidator.Failure.slashCharacter) {
80+
// when
81+
var iterator = sut.validate(input).values.makeAsyncIterator()
82+
let result = await iterator.next()!
83+
try result.get()
84+
}
85+
}
86+
87+
@Test
88+
func `When input is empty it throws error`() async {
89+
// given
90+
let input = ""
91+
92+
// then
93+
await #expect(throws: FilenameValidator.Failure.empty) {
94+
// when
95+
var iterator = sut.validate(input).values.makeAsyncIterator()
96+
let result = await iterator.next()!
97+
try result.get()
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)