packages feed

hydra-0.13.0: src/main/haskell/Hydra/Sources/Test/Lib/Strings.hs

module Hydra.Sources.Test.Lib.Strings where

-- Standard imports for shallow DSL tests
import Hydra.Kernel
import Hydra.Dsl.Meta.Testing                 as Testing
import Hydra.Dsl.Meta.Terms                   as Terms
import Hydra.Sources.Kernel.Types.All
import qualified Hydra.Dsl.Meta.Core          as Core
import qualified Hydra.Dsl.Meta.Phantoms      as Phantoms
import qualified Hydra.Dsl.Meta.Types         as T
import qualified Hydra.Sources.Test.TestGraph as TestGraph
import qualified Hydra.Sources.Test.TestTerms as TestTerms
import qualified Hydra.Sources.Test.TestTypes as TestTypes
import qualified Data.List                    as L
import qualified Data.Map                     as M

-- Additional imports specific to this file
import Hydra.Testing
import Hydra.Sources.Libraries


ns :: Namespace
ns = Namespace "hydra.test.lib.strings"

module_ :: Module
module_ = Module ns elements
    [TestGraph.ns]
    kernelTypesNamespaces
    (Just "Test cases for hydra.lib.strings primitives")
  where
    elements = [
        Phantoms.toBinding allTests]

define :: String -> TTerm a -> TBinding a
define = definitionInModule module_

allTests :: TBinding TestGroup
allTests = define "allTests" $
    Phantoms.doc "Test cases for hydra.lib.strings primitives" $
    supergroup "hydra.lib.strings primitives" [
      stringsCat,
      stringsCat2,
      stringsCharAt,
      stringsFromList,
      stringsIntercalate,
      stringsLength,
      stringsLines,
      stringsNull,
      stringsSplitOn,
      stringsToList,
      stringsToLower,
      stringsToUpper,
      stringsUnlines]
    where
      stringsCat = subgroup "cat" [
        -- Basic functionality
        test "basic concatenation" ["one", "two", "three"] "onetwothree",
        test "single string" ["hello"] "hello",
        test "empty list" [] "",
  
        -- Empty string handling
        test "with empty strings" ["", "one", "", ""] "one",
        test "all empty strings" ["", "", "", ""] "",
  
        -- Unicode correctness
        test "unicode strings" ["\241", "\19990", "\127757"] "\241\19990\127757",  -- ñ, 世, 🌍
        test "combining characters" ["e", "\769"] "e\769",  -- e + combining acute accent
  
        -- Special characters (control characters may be handled specially)
        test "control characters" ["\n", "\t", "\r"] "\n\t\r",
        test "null character" ["hello", "\0", "world"] "hello\0world"]
        where
          test name ls result = primCase name _strings_cat [list (string <$> ls)] (string result)
  
      stringsCat2 = subgroup "cat2" [
        test "basic concatenation" "hello" "world" "helloworld",
        test "empty first string" "" "world" "world",
        test "empty second string" "hello" "" "hello",
        test "both empty strings" "" "" "",
        test "unicode characters" "\241" "\19990" "\241\19990",  -- ñ, 世
        test "special characters" "\n" "\t" "\n\t",
        test "null characters" "hello\0" "world" "hello\0world"]
        where
          test name s1 s2 result = primCase name _strings_cat2 [string s1, string s2] (string result)
  
      stringsCharAt = subgroup "charAt" [
        test "first character" 0 "hello" 104,  -- 'h'
        test "middle character" 2 "hello" 108, -- 'l'
        test "last character" 4 "hello" 111,   -- 'o'
        test "single character string" 0 "a" 97,      -- 'a'
        test "unicode character" 0 "\241" 241,    -- ñ
        test "multi-byte unicode" 0 "\19990" 19990,  -- 世
        test "second of combining pair" 1 "e\769" 769]  -- combining acute accent
        -- TODO: failure cases (need syntax support)
        -- test "negative index" (-1) "hello" <error>
        -- test "index out of bounds" 10 "hello" <error>
        -- test "index on empty string" 0 "" <error>
        where
          test name idx s result = primCase name _strings_charAt [int32 idx, string s] (int32 result)
  
      stringsFromList = subgroup "fromList" [
        test "basic ascii string" [104, 101, 108, 108, 111] "hello",
        test "empty code point list" [] "",
        test "single character" [97] "a",
        test "unicode characters" [241, 19990, 127757] "\241\19990\127757",  -- ñ, 世, 🌍
        test "combining character sequence" [101, 769] "e\769",  -- e + combining acute
        test "special characters" [10, 9, 13] "\n\t\r",
        test "null character" [104, 0, 105] "h\0i"]  -- h, null, i
        -- TODO: failure cases (need syntax support)
        -- test "negative code point" [-1] <error>
        -- test "invalid code point" [1114112] <error>  -- beyond valid Unicode range
        where
          test name codePoints result = primCase name _strings_fromList [list (int32 <$> codePoints)] (string result)
  
      stringsIntercalate = subgroup "intercalate" [
        -- Basic functionality
        test "comma separator" "," ["one", "two", "three"] "one,two,three",
        test "empty separator" "" ["a", "b", "c"] "abc",
        test "multi-character separator" " | " ["A", "B", "C"] "A | B | C",
  
        -- Edge cases
        test "empty string list" "," [] "",
        test "single item list" "," ["only"] "only",
        test "empty strings in list" "," ["", "a", ""] ",a,",
  
        -- Unicode and special characters
        test "unicode separator" "\127757" ["link1", "link2"] "link1\127757link2",  -- 🌍
        test "newline separator" "\n" ["line1", "line2"] "line1\nline2"]
        where
          test name sep strs result = primCase name _strings_intercalate [string sep, list (string <$> strs)] (string result)
  
      stringsLength = subgroup "length" [
        test "empty string" "" 0,
        test "single character" "a" 1,
        test "basic word" "hello" 5,
        test "unicode characters" "\241\19990\127757" 3,  -- ñ, 世, 🌍 (verifies code point count)
        test "combining character sequence" "e\769" 2,  -- e + combining acute (separate code points)
        test "special characters" "\n\t\r" 3]
        where
          test name s result = primCase name _strings_length [string s] (int32 result)
  
      stringsLines = subgroup "lines" [
        -- Basic functionality
        test "single line" "hello world" ["hello world"],
        test "two lines" "hello\nworld" ["hello", "world"],
        test "three lines" "one\ntwo\nthree" ["one", "two", "three"],
  
        -- Edge cases with newlines
        test "empty string" "" [],
        test "just newline" "\n" [""],
        test "trailing newline" "hello\n" ["hello"],
        test "leading newline" "\nhello" ["", "hello"],
  
        -- Consecutive newlines
        test "multiple consecutive newlines" "a\n\nb" ["a", "", "b"],
  
        -- Unicode and other whitespace
        test "unicode content" "\241\n\19990" ["\241", "\19990"],  -- ñ, 世
        test "tabs not split" "a\tb\nc" ["a\tb", "c"]]  -- only \n splits, not \t
        where
          test name s result = primCase name _strings_lines [string s] (list (string <$> result))
  
      stringsNull = subgroup "null" [
        test "empty string" "" True,
        test "single character" "a" False,
        test "space" " " False,
        test "unicode space" "\160" False,  -- non-breaking space
        test "newline" "\n" False,
        test "null character" "\0" False,
        test "multi-character" "hello" False]
        where
          test name s result = primCase name _strings_null [string s] (boolean result)
  
      stringsSplitOn = subgroup "splitOn" [
        -- Basic functionality
        test "basic separator" "ss" "Mississippi" ["Mi", "i", "ippi"],
        test "single char separator" " " "one two three" ["one", "two", "three"],
        test "multi-char separator" "  " "a  b  c" ["a", "b", "c"],
        test "separator not found" "x" "hello" ["hello"],
  
        -- Edge cases with separator positions
        test "separator at start" "h" "hello" ["", "ello"],
        test "separator at end" "o" "hello" ["hell", ""],
        test "leading and trailing separator" " " " one two " ["", "one", "two", ""],
        test "whole string as separator" "Mississippi" "Mississippi" ["", ""],
  
        -- Consecutive and overlapping separators
        test "consecutive separators" " " "a  b" ["a", "", "b"],
        test "multiple occurrences" "l" "hello" ["he", "", "o"],
        test "overlapping pattern" "aa" "aaa" ["", "a"],
  
        -- Empty string cases
        test "empty separator" "" "abc" ["", "a", "b", "c"],
        test "separator on empty string" "x" "" [""],
        test "both empty" "" "" [""],
  
        -- Single character cases
        test "single char both" "a" "a" ["", ""],
  
        -- Unicode
        test "unicode separator" "\19990" "hello\19990world" ["hello", "world"],  -- 世
        test "unicode content" "," "\241,\19990,\127757" ["\241", "\19990", "\127757"],  -- ñ,世,🌍
  
        -- Special characters
        test "newline separator" "\n" "line1\nline2\nline3" ["line1", "line2", "line3"]]
        where
          test name s0 s1 result = primCase name _strings_splitOn [string s0, string s1] (list (string <$> result))
  
      stringsToList = subgroup "toList" [
        -- Basic functionality
        test "empty string" "" [],
        test "single character" "a" [97],
        test "basic word" "hello" [104, 101, 108, 108, 111],
  
        -- Unicode
        test "unicode characters" "\241\19990\127757" [241, 19990, 127757],  -- ñ, 世, 🌍
        test "combining character sequence" "e\769" [101, 769],  -- e + combining acute
  
        -- Special characters
        test "control characters" "\n\t\r" [10, 9, 13],
        test "null character" "h\0i" [104, 0, 105]]
        where
          test name s result = primCase name _strings_toList [string s] (list (int32 <$> result))
  
      stringsToLower = subgroup "toLower" [
        -- Basic functionality
        test "mixed case" "Hello World" "hello world",
        test "all uppercase" "HELLO" "hello",
        test "all lowercase" "hello" "hello",
        test "empty string" "" "",
  
        -- Non-letter characters unchanged
        test "with numbers and punctuation" "Abc123, XYZ!" "abc123, xyz!",
        test "control characters" "\n\t\r" "\n\t\r",
  
        -- Unicode
        test "unicode accented chars" "\209\193\201\205\211\218" "\241\225\233\237\243\250"]  -- ÑÁÉÍÓÚ -> ñáéíóú
        where
          test name s result = primCase name _strings_toLower [string s] (string result)
  
      stringsToUpper = subgroup "toUpper" [
        -- Basic functionality
        test "mixed case" "hello World" "HELLO WORLD",
        test "all lowercase" "hello" "HELLO",
        test "all uppercase" "HELLO" "HELLO",
        test "empty string" "" "",
  
        -- Non-letter characters unchanged
        test "with numbers and punctuation" "abc123, xyz!" "ABC123, XYZ!",
        test "control characters" "\n\t\r" "\n\t\r",
  
        -- Unicode
        test "unicode accented chars" "\241\225\233\237\243\250" "\209\193\201\205\211\218"]  -- ñáéíóú -> ÑÁÉÍÓÚ
        where
          test name s result = primCase name _strings_toUpper [string s] (string result)
  
      stringsUnlines = subgroup "unlines" [
        -- Basic functionality
        test "multiple lines" ["one", "two", "three"] "one\ntwo\nthree\n",
        test "single line" ["hello"] "hello\n",
        test "empty list" [] "",
  
        -- Empty strings in list
        test "with empty lines" ["hello", "", "world"] "hello\n\nworld\n",
        test "all empty lines" ["", "", ""] "\n\n\n",
  
        -- Unicode
        test "unicode content" ["\241o\241o", "\19990\30028"] "\241o\241o\n\19990\30028\n"]  -- ñoño, 世界
        where
          test name strs result = primCase name _strings_unlines [list (string <$> strs)] (string result)