From 89d56de5e45924f4a56de629d1ee501ed464dc69 Mon Sep 17 00:00:00 2001
From: Kir_Antipov <kp.antipov@gmail.com>
Date: Thu, 8 Dec 2022 05:58:31 +0000
Subject: [PATCH] Implemented default comparers for strings

---
 src/utils/comparison/string-comparer.ts       | 13 +++++
 .../utils/comparison/string-comparer.spec.ts  | 55 +++++++++++++++++++
 2 files changed, 68 insertions(+)
 create mode 100644 src/utils/comparison/string-comparer.ts
 create mode 100644 tests/unit/utils/comparison/string-comparer.spec.ts

diff --git a/src/utils/comparison/string-comparer.ts b/src/utils/comparison/string-comparer.ts
new file mode 100644
index 0000000..589b8b9
--- /dev/null
+++ b/src/utils/comparison/string-comparer.ts
@@ -0,0 +1,13 @@
+import { createBaseComparer, createDefaultComparer } from "./comparer";
+
+/**
+ * A string comparer that performs a case-sensitive ordinal string comparison.
+ */
+export const ORDINAL_COMPARER = createDefaultComparer<string>();
+
+/**
+ * A string comparer that ignores case differences.
+ */
+export const IGNORE_CASE_COMPARER = createBaseComparer<string>().thenBy(
+    (left, right) => left?.localeCompare(right, undefined, { sensitivity: "accent" }) ?? 0
+);
diff --git a/tests/unit/utils/comparison/string-comparer.spec.ts b/tests/unit/utils/comparison/string-comparer.spec.ts
new file mode 100644
index 0000000..19c6d0b
--- /dev/null
+++ b/tests/unit/utils/comparison/string-comparer.spec.ts
@@ -0,0 +1,55 @@
+import { ORDINAL_COMPARER, IGNORE_CASE_COMPARER } from "@/utils/comparison/string-comparer";
+
+describe("ORDINAL_COMPARER", () => {
+    test("compares two strings using case-sensitive ordinal comparison", () => {
+        expect(ORDINAL_COMPARER("test", "test")).toBe(0);
+        expect(ORDINAL_COMPARER("Test", "test")).toBeLessThan(0);
+        expect(ORDINAL_COMPARER("test", "Test")).toBeGreaterThan(0);
+        expect(ORDINAL_COMPARER("test", "testing")).toBeLessThan(0);
+        expect(ORDINAL_COMPARER("testing", "test")).toBeGreaterThan(0);
+    });
+
+    test("treats undefined as smaller than any other value", () => {
+        expect(ORDINAL_COMPARER(undefined, "test")).toBeLessThan(0);
+        expect(ORDINAL_COMPARER(undefined, null)).toBeLessThan(0);
+        expect(ORDINAL_COMPARER(undefined, undefined)).toBe(0);
+    });
+
+    test("treats null as smaller than any other value except undefined", () => {
+        expect(ORDINAL_COMPARER(null, "test")).toBeLessThan(0);
+        expect(ORDINAL_COMPARER(null, undefined)).toBeGreaterThan(0);
+        expect(ORDINAL_COMPARER(null, null)).toBe(0);
+    });
+});
+
+describe("IGNORE_CASE_COMPARER", () => {
+    test("compares two strings using case-insensitive ordinal comparison", () => {
+        expect(IGNORE_CASE_COMPARER("A", "a")).toBe(0);
+        expect(IGNORE_CASE_COMPARER("a", "B")).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER("A", "b")).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER("A", "B")).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER("B", "a")).toBeGreaterThan(0);
+        expect(IGNORE_CASE_COMPARER("b", "A")).toBeGreaterThan(0);
+        expect(IGNORE_CASE_COMPARER("B", "A")).toBeGreaterThan(0);
+    });
+
+    test("ignores case differences when comparing strings", () => {
+        expect(IGNORE_CASE_COMPARER("test", "test")).toBe(0);
+        expect(IGNORE_CASE_COMPARER("Test", "test")).toBe(0);
+        expect(IGNORE_CASE_COMPARER("TEST", "test")).toBe(0);
+        expect(IGNORE_CASE_COMPARER("test", "TEST")).toBe(0);
+        expect(IGNORE_CASE_COMPARER("Test", "TEST")).toBe(0);
+    });
+
+    test("treats undefined as smaller than any other value", () => {
+        expect(IGNORE_CASE_COMPARER(undefined, "test")).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER(undefined, null)).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER(undefined, undefined)).toBe(0);
+    });
+
+    test("treats null as smaller than any other value except undefined", () => {
+        expect(IGNORE_CASE_COMPARER(null, "test")).toBeLessThan(0);
+        expect(IGNORE_CASE_COMPARER(null, undefined)).toBeGreaterThan(0);
+        expect(IGNORE_CASE_COMPARER(null, null)).toBe(0);
+    });
+});