//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import XCTest
@testable import SignalServiceKit

final class StringExtensionTests: XCTestCase {

    func testBalancedBidiControlCharacters() throws {
        let scalarBidiLeftToRightIsolate: Unicode.Scalar = "\u{2066}"
        let scalarBidiRightToLeftIsolate: Unicode.Scalar = "\u{2067}"
        let scalarBidiFirstStrongIsolate: Unicode.Scalar = "\u{2068}"
        let scalarBidiLeftToRightEmbedding: Unicode.Scalar = "\u{202A}"
        let scalarBidiRightToLeftEmbedding: Unicode.Scalar = "\u{202B}"
        let scalarBidiLeftToRightOverride: Unicode.Scalar = "\u{202D}"
        let scalarBidiRightToLeftOverride: Unicode.Scalar = "\u{202E}"
        let scalarBidiPopDirectionalFormatting: Unicode.Scalar = "\u{202C}"
        let scalarBidiPopDirectionalIsolate: Unicode.Scalar = "\u{2069}"

        let bidiLeftToRightIsolate = Character(scalarBidiLeftToRightIsolate)
        let bidiRightToLeftIsolate = Character(scalarBidiRightToLeftIsolate)
        let bidiFirstStrongIsolate = Character(scalarBidiFirstStrongIsolate)
        let bidiLeftToRightEmbedding = Character(scalarBidiLeftToRightEmbedding)
        let bidiRightToLeftEmbedding = Character(scalarBidiRightToLeftEmbedding)
        let bidiLeftToRightOverride = Character(scalarBidiLeftToRightOverride)
        let bidiRightToLeftOverride = Character(scalarBidiRightToLeftOverride)
        let bidiPopDirectionalFormatting = Character(scalarBidiPopDirectionalFormatting)
        let bidiPopDirectionalIsolate = Character(scalarBidiPopDirectionalIsolate)

        XCTAssertEqual("A", "A".ensureBalancedBidiControlCharacters())

        // If we have too many isolate starts, append PDI to balance
        let string1 = "ABC\(bidiLeftToRightIsolate)"
        XCTAssertEqual("\(string1)\(bidiPopDirectionalIsolate)", string1.ensureBalancedBidiControlCharacters())

        // Control characters interspersed with printing characters.
        let string2 = "ABC\(bidiLeftToRightIsolate)E\(bidiLeftToRightIsolate)"
        XCTAssertEqual("\(string2)\(bidiPopDirectionalIsolate)\(bidiPopDirectionalIsolate)", string2.ensureBalancedBidiControlCharacters())

        // Various kinds of isolate starts.
        let string3 = "ABC\(bidiLeftToRightIsolate)E\(bidiRightToLeftIsolate)E\(bidiFirstStrongIsolate)"
        XCTAssertEqual("\(string3)\(bidiPopDirectionalIsolate)\(bidiPopDirectionalIsolate)\(bidiPopDirectionalIsolate)", string3.ensureBalancedBidiControlCharacters())

        // If we have too many isolate pops, prepend FSI to balance
        // Various kinds of isolate starts.
        let string4 = "ABC\(bidiPopDirectionalIsolate)E\(bidiPopDirectionalIsolate)E\(bidiPopDirectionalIsolate)"
        XCTAssertEqual("\(bidiFirstStrongIsolate)\(bidiFirstStrongIsolate)\(bidiFirstStrongIsolate)\(string4)", string4.ensureBalancedBidiControlCharacters())

        // If we have too many formatting starts, append PDF to balance
        let string5 = "ABC\(bidiLeftToRightEmbedding)E\(bidiRightToLeftEmbedding)E\(bidiLeftToRightOverride)E\(bidiRightToLeftOverride)"
        XCTAssertEqual("\(string5)\(bidiPopDirectionalFormatting)\(bidiPopDirectionalFormatting)\(bidiPopDirectionalFormatting)\(bidiPopDirectionalFormatting)", string5.ensureBalancedBidiControlCharacters())

        // If we have too many formatting pops, prepend LRE to balance
        let string6 = "ABC\(bidiPopDirectionalFormatting)E\(bidiPopDirectionalFormatting)E\(bidiPopDirectionalFormatting)E\(bidiPopDirectionalFormatting)"
        XCTAssertEqual("\(bidiLeftToRightEmbedding)\(bidiLeftToRightEmbedding)\(bidiLeftToRightEmbedding)\(bidiLeftToRightEmbedding)\(string6)", string6.ensureBalancedBidiControlCharacters())
    }

    func testfilterUnsafeFilenameCharacters() throws {
        XCTAssertEqual("1", "1".filterUnsafeFilenameCharacters())
        XCTAssertEqual("alice\u{FFFD}bob", "alice\u{202D}bob".filterUnsafeFilenameCharacters())
        XCTAssertEqual("\u{FFFD}alicebob", "\u{202D}alicebob".filterUnsafeFilenameCharacters())
        XCTAssertEqual("alicebob\u{FFFD}", "alicebob\u{202D}".filterUnsafeFilenameCharacters())
        XCTAssertEqual("alice\u{FFFD}bob", "alice\u{202E}bob".filterUnsafeFilenameCharacters())
        XCTAssertEqual("\u{FFFD}alicebob", "\u{202E}alicebob".filterUnsafeFilenameCharacters())
        XCTAssertEqual("alicebob\u{FFFD}", "alicebob\u{202E}".filterUnsafeFilenameCharacters())
        XCTAssertEqual("alice\u{FFFD}bobalice\u{FFFD}bob", "alice\u{202D}bobalice\u{202E}bob".filterUnsafeFilenameCharacters())
    }
}
