import XCTest @testable import RSSuper /// Unit tests for SearchQuery parsing and manipulation final class SearchQueryTests: XCTestCase { func testEmptyQuery() { let query = SearchQuery(rawValue: "") XCTAssertEqual(query.terms, []) XCTAssertEqual(query.rawText, "") XCTAssertEqual(query.sort, .relevance) XCTAssertFalse(query.fuzzy) } func testSimpleQuery() { let query = SearchQuery(rawValue: "swift programming") XCTAssertEqual(query.terms, ["swift", "programming"]) XCTAssertEqual(query.rawText, "swift programming") } func testQueryWithDateFilter() { let query = SearchQuery(rawValue: "swift date:after:2024-01-01") XCTAssertEqual(query.terms, ["swift"]) XCTAssertNotNil(query.filters.dateRange) if case .after(let date) = query.filters.dateRange! { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" let expectedDate = formatter.date(from: "2024-01-01")! XCTAssertEqual(date, expectedDate) } else { XCTFail("Expected .after case") } } func testQueryWithFeedFilter() { let query = SearchQuery(rawValue: "swift feed:Apple Developer") XCTAssertEqual(query.terms, ["swift"]) XCTAssertEqual(query.filters.feedTitle, "Apple Developer") } func testQueryWithAuthorFilter() { let query = SearchQuery(rawValue: "swift author:John Doe") XCTAssertEqual(query.terms, ["swift"]) XCTAssertEqual(query.filters.author, "John Doe") } func testQueryWithSortOption() { let query = SearchQuery(rawValue: "swift sort:date_desc") XCTAssertEqual(query.terms, ["swift"]) XCTAssertEqual(query.sort, .dateDesc) } func testQueryWithFuzzyFlag() { let query = SearchQuery(rawValue: "swift ~") XCTAssertEqual(query.terms, ["swift"]) XCTAssertTrue(query.fuzzy) } func testFTSQueryGeneration() { let exactQuery = SearchQuery(rawValue: "swift programming") XCTAssertEqual(exactQuery.ftsQuery(), "\"swift\" OR \"programming\"") let fuzzyQuery = SearchQuery(rawValue: "swift ~") XCTAssertEqual(fuzzyQuery.ftsQuery(), "\"*swift*\"") } func testDisplayString() { let query = SearchQuery(rawValue: "swift date:after:2024-01-01") XCTAssertEqual(query.displayString, "swift") } func testDateRangeLowerBound() { let afterRange = DateRange.after(Date()) XCTAssertNotNil(afterRange.lowerBound) XCTAssertNil(afterRange.upperBound) let beforeRange = DateRange.before(Date()) XCTAssertNil(beforeRange.lowerBound) XCTAssertNotNil(beforeRange.upperBound) let exactRange = DateRange.exact(Date()) XCTAssertNotNil(exactRange.lowerBound) XCTAssertNotNil(exactRange.upperBound) } func testSearchFiltersIsEmpty() { var filters = SearchFilters() XCTAssertTrue(filters.isEmpty) filters.dateRange = .after(Date()) XCTAssertFalse(filters.isEmpty) filters = .empty XCTAssertTrue(filters.isEmpty) } func testSortOptionOrderByClause() { XCTAssertEqual(SearchSortOption.relevance.orderByClause(), "rank") XCTAssertEqual(SearchSortOption.dateDesc.orderByClause(), "f.published DESC") XCTAssertEqual(SearchSortOption.titleAsc.orderByClause(), "f.title ASC") XCTAssertEqual(SearchSortOption.feedDesc.orderByClause(), "s.title DESC") } }