//
//  StringExtensionsTests.swift
//  honeyDueTests
//
//  Unit tests for String and Optional<String> extensions.
//

import Testing
@testable import honeyDue

// MARK: - isBlank Tests

struct IsBlankTests {

    @Test func emptyStringIsBlank() {
        #expect("".isBlank)
    }

    @Test func whitespaceOnlyIsBlank() {
        #expect("   ".isBlank)
    }

    @Test func nonEmptyIsNotBlank() {
        #expect(!"hello".isBlank)
    }

    @Test func stringWithWhitespacePaddingIsNotBlank() {
        #expect(!" hello ".isBlank)
    }
}

// MARK: - nilIfBlank Tests

struct NilIfBlankTests {

    @Test func emptyReturnsNil() {
        #expect("".nilIfBlank == nil)
    }

    @Test func whitespaceOnlyReturnsNil() {
        #expect("   ".nilIfBlank == nil)
    }

    @Test func nonEmptyReturnsTrimmed() {
        #expect(" hello ".nilIfBlank == "hello")
    }

    @Test func plainStringReturnsSelf() {
        #expect("test".nilIfBlank == "test")
    }
}

// MARK: - capitalizedFirst Tests

struct CapitalizedFirstTests {

    @Test func lowercaseFirstCapitalized() {
        #expect("hello".capitalizedFirst == "Hello")
    }

    @Test func alreadyCapitalizedUnchanged() {
        #expect("Hello".capitalizedFirst == "Hello")
    }

    @Test func allUppercaseOnlyFirstKept() {
        #expect("hELLO".capitalizedFirst == "HELLO")
    }

    @Test func emptyStringReturnsEmpty() {
        #expect("".capitalizedFirst == "")
    }

    @Test func singleCharCapitalized() {
        #expect("a".capitalizedFirst == "A")
    }
}

// MARK: - truncated Tests

struct TruncatedTests {

    @Test func shortStringNotTruncated() {
        #expect("hi".truncated(to: 10) == "hi")
    }

    @Test func longStringTruncatedWithEllipsis() {
        #expect("Hello World".truncated(to: 5) == "Hello...")
    }

    @Test func longStringTruncatedWithoutEllipsis() {
        #expect("Hello World".truncated(to: 5, addEllipsis: false) == "Hello")
    }

    @Test func exactLengthNotTruncated() {
        #expect("Hello".truncated(to: 5) == "Hello")
    }
}

// MARK: - isValidEmail Tests

struct IsValidEmailTests {

    @Test func standardEmailValid() {
        #expect("user@example.com".isValidEmail)
    }

    @Test func emailWithSubdomainValid() {
        #expect("user@mail.example.com".isValidEmail)
    }

    @Test func emailWithPlusValid() {
        #expect("user+tag@example.com".isValidEmail)
    }

    @Test func emailWithDotsValid() {
        #expect("first.last@example.com".isValidEmail)
    }

    @Test func noAtSignInvalid() {
        #expect(!"userexample.com".isValidEmail)
    }

    @Test func noDomainInvalid() {
        #expect(!"user@".isValidEmail)
    }

    @Test func noTLDInvalid() {
        #expect(!"user@example".isValidEmail)
    }

    @Test func emptyStringInvalid() {
        #expect(!"".isValidEmail)
    }

    @Test func numericLocalPartValid() {
        #expect("123@example.com".isValidEmail)
    }
}

// MARK: - isValidPhone Tests

struct IsValidPhoneTests {

    @Test func tenDigitsValid() {
        #expect("5551234567".isValidPhone)
    }

    @Test func formattedUSPhoneValid() {
        #expect("(555) 123-4567".isValidPhone)
    }

    @Test func internationalFormatValid() {
        #expect("+1 555-123-4567".isValidPhone)
    }

    @Test func tooShortInvalid() {
        #expect(!"12345".isValidPhone)
    }

    @Test func lettersInvalid() {
        #expect(!"555-ABC-DEFG".isValidPhone)
    }
}

// MARK: - Optional String Tests

struct OptionalStringTests {

    @Test func nilIsNilOrBlank() {
        let s: String? = nil
        #expect(s.isNilOrBlank)
    }

    @Test func emptyIsNilOrBlank() {
        let s: String? = ""
        #expect(s.isNilOrBlank)
    }

    @Test func whitespaceIsNilOrBlank() {
        let s: String? = "   "
        #expect(s.isNilOrBlank)
    }

    @Test func valueIsNotNilOrBlank() {
        let s: String? = "hello"
        #expect(!s.isNilOrBlank)
    }

    @Test func nilNilIfBlankReturnsNil() {
        let s: String? = nil
        #expect(s.nilIfBlank == nil)
    }

    @Test func blankOptionalNilIfBlankReturnsNil() {
        let s: String? = "   "
        #expect(s.nilIfBlank == nil)
    }

    @Test func valueOptionalNilIfBlankReturnsTrimmed() {
        let s: String? = " hello "
        #expect(s.nilIfBlank == "hello")
    }
}
