Modify escaping string (#22)

This commit is contained in:
원형식 2022-10-13 19:38:23 +09:00 committed by GitHub
parent 3e41826e3e
commit ba5cd8decf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 8 deletions

View File

@ -15,24 +15,41 @@
*/
import Foundation
/**
* `EscapeString` escapes string.
*/
extension String {
/// Escapes string.
private enum JsonEscape {
static let tempPlaceHolder = UUID().uuidString
static let backSlash = "\\"
static let escapedBackSlash = "\\\\"
/// Escaping based on JS-SDK
static let escapeSequences = [
(original: "\\", escaped: "\\\\"),
(original: JsonEscape.backSlash, escaped: JsonEscape.escapedBackSlash),
(original: "\"", escaped: "\\\""),
(original: "'", escaped: "\\'"),
(original: "\n", escaped: "\\n"),
(original: "\r", escaped: "\\r"),
(original: "\t", escaped: "\\t"),
(original: "\u{2028}", escaped: "\\u{2028}"),
(original: "\u{2029}", escaped: "\\u{2029}")
(original: "\u{0008}", escaped: "\\b"),
(original: "\u{000C}", escaped: "\\f"),
(original: "\u{2028}", escaped: "\\u2028"),
(original: "\u{2029}", escaped: "\\u2029")
]
}
extension String {
func escaped() -> String {
return String.escapeSequences.reduce(self) { string, seq in
return JsonEscape.escapeSequences.reduce(self) { string, seq in
string.replacingOccurrences(of: seq.original, with: seq.escaped)
}
}
func unescaped() -> String {
let target = self.replacingOccurrences(of: JsonEscape.escapedBackSlash, with: JsonEscape.tempPlaceHolder)
let temp = JsonEscape.escapeSequences.reduce(target) { string, seq in
string.replacingOccurrences(of: seq.escaped, with: seq.original)
}
return temp.replacingOccurrences(of: JsonEscape.tempPlaceHolder, with: JsonEscape.backSlash)
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2022 The Yorkie Authors. All rights reserved.
*
* 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 Yorkie
class StringEscapingTests: XCTestCase {
func test_can_escape_string() {
let target = "1\\2\"3'4\n5\r6\t7\u{0008}8\u{000C}9\u{2028}0\u{2029}"
let escaped = "1\\\\2\\\"3\\'4\\n5\\r6\\t7\\b8\\f9\\u20280\\u2029"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
func test_can_escape_string_2() {
let target = "\\n"
let escaped = "\\\\n"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
func test_can_escape_string_3() {
let target = "\\\\\\t"
let escaped = "\\\\\\\\\\\\t"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
func test_can_escape_string_4() {
let target = "\\\\\\\t"
let escaped = "\\\\\\\\\\\\\\t"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
func test_can_escape_string_5() {
let target = "\\u{000C}"
let escaped = "\\\\u{000C}"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
func test_can_escape_string_6() {
let target = "\u{000C}"
let escaped = "\\f"
XCTAssertEqual(target.escaped(), escaped)
XCTAssertEqual(escaped.unescaped(), target)
}
}

View File

@ -43,6 +43,7 @@
CE8C230528C9F1BD00432DE5 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8C230428C9F1BD00432DE5 /* Client.swift */; };
CE8C230728D1514900432DE5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8C230628D1514900432DE5 /* Logger.swift */; };
CE8C230B28D15FF200432DE5 /* ClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8C230928D15F5A00432DE5 /* ClientTests.swift */; };
CEC631DE28F4F36100915A85 /* StringEscapingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC631DC28F4F15900915A85 /* StringEscapingTests.swift */; };
CE8ED31628F55BF7009A5419 /* SetOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8ED31528F55BF7009A5419 /* SetOperation.swift */; };
CE8ED31A28F55F42009A5419 /* SetOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8ED31828F55F3E009A5419 /* SetOperationTests.swift */; };
CE8ED31C28F56506009A5419 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8ED31B28F56506009A5419 /* RemoveOperation.swift */; };
@ -112,6 +113,7 @@
CE8C230428C9F1BD00432DE5 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
CE8C230628D1514900432DE5 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Logger.swift; path = Sources/Core/Logger.swift; sourceTree = SOURCE_ROOT; };
CE8C230928D15F5A00432DE5 /* ClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTests.swift; sourceTree = "<group>"; };
CEC631DC28F4F15900915A85 /* StringEscapingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringEscapingTests.swift; sourceTree = "<group>"; };
CE8ED31528F55BF7009A5419 /* SetOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetOperation.swift; sourceTree = "<group>"; };
CE8ED31828F55F3E009A5419 /* SetOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetOperationTests.swift; sourceTree = "<group>"; };
CE8ED31B28F56506009A5419 /* RemoveOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveOperation.swift; sourceTree = "<group>"; };
@ -244,6 +246,7 @@
children = (
CE3EC96F28D40415009471BC /* CRDT */,
CE8ED31728F55F25009A5419 /* Operation */,
CEC631DB28F4F14100915A85 /* Json */,
CE3EC96B28D3FFDB009471BC /* Time */,
);
path = Document;
@ -378,6 +381,14 @@
path = Operation;
sourceTree = "<group>";
};
CEC631DB28F4F14100915A85 /* Json */ = {
isa = PBXGroup;
children = (
CEC631DC28F4F15900915A85 /* StringEscapingTests.swift */,
);
path = Json;
sourceTree = "<group>";
};
CECCCB8028C96BB500544204 /* V1 */ = {
isa = PBXGroup;
children = (
@ -627,6 +638,7 @@
CEA2DA4328F672AD00431B61 /* MoveOperationTests.swift in Sources */,
96DA809128C5B7B400E2C1DA /* GRPCTests.swift in Sources */,
CE3EC94D28D189EF009471BC /* HeapTests.swift in Sources */,
CEC631DE28F4F36100915A85 /* StringEscapingTests.swift in Sources */,
CE3EC95228D195E4009471BC /* RedBlackTreeTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;