From 4d74173c3e9da0c7f75a119f9c75bfe2c316d3d4 Mon Sep 17 00:00:00 2001 From: Peter Damoc Date: Wed, 16 Nov 2016 09:22:44 +0200 Subject: [PATCH] updated to 0.18, moved to elm-community/elm-test --- elm-package.json | 8 +- src/Hashids.elm | 1017 ++++++++++++++++++------------ test/elm-package.json | 18 - tests/.gitignore | 1 + tests/Main.elm | 13 + test/Test.elm => tests/Tests.elm | 81 ++- tests/elm-package.json | 20 + 7 files changed, 713 insertions(+), 445 deletions(-) delete mode 100644 test/elm-package.json create mode 100644 tests/.gitignore create mode 100644 tests/Main.elm rename test/Test.elm => tests/Tests.elm (98%) create mode 100644 tests/elm-package.json diff --git a/elm-package.json b/elm-package.json index a9509b3..e10f6e6 100644 --- a/elm-package.json +++ b/elm-package.json @@ -1,5 +1,5 @@ { - "version": "1.0.2", + "version": "1.0.3", "summary": "Elm port of the Hashids library", "repository": "https://github.com/pdamoc/elm-hashids.git", "license": "MIT", @@ -11,7 +11,7 @@ "Hashids" ], "dependencies": { - "elm-lang/core": "4.0.0 <= v < 5.0.0" + "elm-lang/core": "5.0.0 <= v < 6.0.0" }, - "elm-version": "0.17.0 <= v < 0.18.0" -} \ No newline at end of file + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/src/Hashids.elm b/src/Hashids.elm index 8bdc160..8600a16 100644 --- a/src/Hashids.elm +++ b/src/Hashids.elm @@ -1,9 +1,21 @@ -module Hashids exposing - ( Context - , createHashidsContext, hashidsSimple, hashidsMinimum - , encodeHex, decodeHex, encode, encodeList, decode - , encodeUsingSalt, encodeListUsingSalt, decodeUsingSalt - , encodeHexUsingSalt, decodeHexUsingSalt) +module Hashids + exposing + ( Context + , createHashidsContext + , hashidsSimple + , hashidsMinimum + , encodeHex + , decodeHex + , encode + , encodeList + , decode + , encodeUsingSalt + , encodeListUsingSalt + , decodeUsingSalt + , encodeHexUsingSalt + , decodeHexUsingSalt + ) + {-| This is an Elm port of the Hashids library by Ivan Akimov. This is *not* a cryptographic hashing algorithm. Hashids is typically used to encode numbers to a format suitable for appearance in places @@ -21,7 +33,7 @@ parameters into one or simply using them as short UIDs. @docs Context -# Context object constructors +# Context object constructors @docs createHashidsContext, hashidsSimple, hashidsMinimum @@ -33,89 +45,128 @@ parameters into one or simply using them as short UIDs. -} -import String +import String import Char import Array exposing (Array) import Regex +import Tuple exposing (first) + {-| A record with various internals required for encoding and decoding. -} type alias Context = - { guards : String - , seps : String - , salt : String - , minHashLength : Int - , alphabet : String - } + { guards : String + , seps : String + , salt : String + , minHashLength : Int + , alphabet : String + } + containsChar : Char -> String -> Bool -containsChar = String.contains << String.fromChar +containsChar = + String.contains << String.fromChar + unique : String -> String -unique str = - let - addIfNotMember c xs = - if containsChar c xs then xs else String.cons c xs - in - String.foldr addIfNotMember "" str +unique str = + let + addIfNotMember c xs = + if containsChar c xs then + xs + else + String.cons c xs + in + String.foldr addIfNotMember "" str + intersect : String -> String -> String intersect first second = - let - member c = containsChar c second - in - String.filter member first + let + member c = + containsChar c second + in + String.filter member first + exclude : String -> String -> String exclude toBeExcluded from = - let - member c = not <| containsChar c toBeExcluded - in - String.filter member from + let + member c = + not <| containsChar c toBeExcluded + in + String.filter member from + forceGet : Int -> Array a -> a -forceGet i axs = - case Array.get i axs of - Nothing -> Debug.crash <| "This should not happen"++ (toString i) - Just v -> v +forceGet i axs = + case Array.get i axs of + Nothing -> + Debug.crash <| "This should not happen" ++ (toString i) + + Just v -> + v + swap : Int -> Int -> String -> String swap i j str = - let - strArray = Array.fromList <| String.toList str - iElem = forceGet i strArray - jElem = forceGet j strArray - in - Array.set i jElem strArray - |> Array.set j iElem - |> Array.toList - |> String.fromList - -{-| reorder a string acording to salt -} + let + strArray = + Array.fromList <| String.toList str + + iElem = + forceGet i strArray + + jElem = + forceGet j strArray + in + Array.set i jElem strArray + |> Array.set j iElem + |> Array.toList + |> String.fromList + + +{-| reorder a string acording to salt +-} reorder : String -> String -> String -reorder string salt = - let - saltLen = String.length salt - alphaLen = String.length string - saltArray = Array.fromList <| String.toList salt - - shuffle i index integerSum str = - if i > 0 then - let - index' = index % saltLen - integer = Char.toCode <| forceGet index' saltArray - integerSum' = integerSum + integer - j = (integer + index' + integerSum') % i - str' = swap i j str - in - shuffle (i-1) (index'+1) integerSum' str' - else str - - in - if saltLen == 0 then - string - else - shuffle (alphaLen - 1) 0 0 string +reorder string salt = + let + saltLen = + String.length salt + + alphaLen = + String.length string + + saltArray = + Array.fromList <| String.toList salt + + shuffle i index integerSum str = + if i > 0 then + let + newIndex = + index % saltLen + + integer = + Char.toCode <| forceGet newIndex saltArray + + newIntegerSum = + integerSum + integer + + j = + (integer + newIndex + newIntegerSum) % i + + newStr = + swap i j str + in + shuffle (i - 1) (newIndex + 1) newIntegerSum newStr + else + str + in + if saltLen == 0 then + string + else + shuffle (alphaLen - 1) 0 0 string + {-| Create a context object using the given salt, a minimum hash length, and a custom alphabet. If you only need to supply the salt, or the first two @@ -125,374 +176,540 @@ Changing the alphabet is useful if you want to make your hashes unique, i.e., create hashes different from those generated by other applications relying on the same algorithm. -} -createHashidsContext : String -- Salt - -> Int -- Minimum required hash length - -> String -- Alphabet - -> Context -createHashidsContext salt minHashLen alphabet = - let - minAlphabetLength = 16 - sepDiv = 3.5 - guardDiv = 12 - - clean alpha = - let - seps = "cfhistuCFHISTU" - seps' = intersect seps alpha - hasSpaces = String.contains " " alpha - alpha' = exclude seps' <| unique alpha - alphabetIsSmall = String.length (alpha' ++ seps') < minAlphabetLength - - in - case (hasSpaces, alphabetIsSmall) of - (True, _) -> - Debug.log "alphabet provided has spaces, using default" - (seps, exclude seps defaultAlphabet) - (_, True) -> - Debug.log "alphabet too small, using default" - (seps, exclude seps defaultAlphabet) - (False, False) -> - (seps', alpha') - - validSeps (seps, alpha) = - let - seps' = reorder seps salt - lenSeps = String.length seps' - lenAlpha = String.length alpha - minSeps = ceiling <| (toFloat lenAlpha)/sepDiv - in - if (lenSeps < minSeps) then - let - minSeps' = if minSeps == 1 then 2 else minSeps - in - if minSeps' > lenSeps then - let - splitAt = minSeps'-lenSeps - seps'' = seps'++(String.left splitAt alpha) - alpha' = String.dropLeft splitAt alpha - in - (seps'', alpha') - else - (seps', alpha) - else - (seps', alpha) - - withGuard (seps, alpha) = - let - alpha' = reorder alpha salt - lenAlpha = String.length alpha - numGuards = ceiling <| (toFloat lenAlpha)/guardDiv - in - if lenAlpha < 3 then - (String.dropLeft numGuards seps, alpha', String.left numGuards seps) - else - (seps, String.dropLeft numGuards alpha', String.left numGuards alpha') - - (seps', alphabet', guards) = - clean alphabet - |> validSeps - |> withGuard - - in - { guards = guards - , seps = seps' - , salt = salt - , minHashLength = minHashLen - , alphabet = alphabet' - } +createHashidsContext : + String + -- Salt + -> Int + -- Minimum required hash length + -> String + -- Alphabet + -> Context +createHashidsContext salt minHashLen alphabet = + let + minAlphabetLength = + 16 + + sepDiv = + 3.5 + + guardDiv = + 12 + + clean alpha = + let + seps = + "cfhistuCFHISTU" + + seps1 = + intersect seps alpha + + hasSpaces = + String.contains " " alpha + + alpha1 = + exclude seps1 <| unique alpha + + alphabetIsSmall = + String.length (alpha1 ++ seps1) < minAlphabetLength + in + case ( hasSpaces, alphabetIsSmall ) of + ( True, _ ) -> + Debug.log "alphabet provided has spaces, using default" + ( seps, exclude seps defaultAlphabet ) + + ( _, True ) -> + Debug.log "alphabet too small, using default" + ( seps, exclude seps defaultAlphabet ) + + ( False, False ) -> + ( seps1, alpha1 ) + + validSeps ( seps, alpha ) = + let + seps1 = + reorder seps salt + + lenSeps = + String.length seps1 + + lenAlpha = + String.length alpha + + minSeps = + ceiling <| (toFloat lenAlpha) / sepDiv + in + if (lenSeps < minSeps) then + let + minSeps1 = + if minSeps == 1 then + 2 + else + minSeps + in + if minSeps1 > lenSeps then + let + splitAt = + minSeps1 - lenSeps + + seps2 = + seps1 ++ (String.left splitAt alpha) + + alpha1 = + String.dropLeft splitAt alpha + in + ( seps2, alpha1 ) + else + ( seps1, alpha ) + else + ( seps1, alpha ) + + withGuard ( seps, alpha ) = + let + alpha1 = + reorder alpha salt + + lenAlpha = + String.length alpha + + numGuards = + ceiling <| (toFloat lenAlpha) / guardDiv + in + if lenAlpha < 3 then + ( String.dropLeft numGuards seps, alpha1, String.left numGuards seps ) + else + ( seps, String.dropLeft numGuards alpha1, String.left numGuards alpha1 ) + + ( seps1, alphabet1, guards ) = + clean alphabet + |> validSeps + |> withGuard + in + { guards = guards + , seps = seps1 + , salt = salt + , minHashLength = minHashLen + , alphabet = alphabet1 + } + defaultAlphabet : String -defaultAlphabet = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" +defaultAlphabet = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + {-| Create a context object using the default alphabet and the provided salt, without any minimum required length. -} -hashidsSimple : String -- Salt - -> Context -hashidsSimple salt = createHashidsContext salt 0 defaultAlphabet +hashidsSimple : + String + -- Salt + -> Context +hashidsSimple salt = + createHashidsContext salt 0 defaultAlphabet {-| Create a context object using the default alphabet and the provided salt. The generated hashes will have a minimum length as specified by the second argument. -} -hashidsMinimum : String -- Salt - -> Int -- Minimum required hash length - -> Context -hashidsMinimum salt minimum = createHashidsContext salt minimum defaultAlphabet +hashidsMinimum : + String + -- Salt + -> Int + -- Minimum required hash length + -> Context +hashidsMinimum salt minimum = + createHashidsContext salt minimum defaultAlphabet {-| Decode a hash generated with 'encodeHex'. - Example use: + Example use: decodeHex context "yzgwD" -} -decodeHex : Context -- Hashids context object - -> String -- Hash - -> String -decodeHex context hash = - let - numbers = decode context hash - in - concatMap (\n -> String.dropLeft 1 <| toString n) numbers +decodeHex : + Context + -- Hashids context object + -> String + -- Hash + -> String +decodeHex context hash = + let + numbers = + decode context hash + in + concatMap (\n -> String.dropLeft 1 <| toString n) numbers + concatMap : (a -> String) -> List a -> String -concatMap f = String.concat << (List.map f) +concatMap f = + String.concat << (List.map f) {-| Encode a hexadecimal number. - Example use: + Example use: encodeHex context "ff83" -} -encodeHex : Context -- A Hashids context object - -> String -- Hexadecimal number represented as a string - -> String -encodeHex context str = - let - go str = fromHex ("1"++str) - - in - if String.all Char.isHexDigit str then - encodeList context <| List.map go <| chunksOf 12 str - else - "" +encodeHex : + Context + -- A Hashids context object + -> String + -- Hexadecimal number represented as a string + -> String +encodeHex context str = + let + go str = + fromHex ("1" ++ str) + in + if String.all Char.isHexDigit str then + encodeList context <| List.map go <| chunksOf 12 str + else + "" + chunksOf : Int -> String -> List String -chunksOf size str = - let - split str acc = - if (String.length str) > size then - split (String.dropRight size str) ((String.right size str)::acc) - else - str::acc - in - split str [] +chunksOf size str = + let + split str acc = + if (String.length str) > size then + split (String.dropRight size str) ((String.right size str) :: acc) + else + str :: acc + in + split str [] + fromHex : String -> Int -fromHex hex = - let - toDig n = - case Char.toUpper n of - '1' -> 1 - '2' -> 2 - '3' -> 3 - '4' -> 4 - '5' -> 5 - '6' -> 6 - '7' -> 7 - '8' -> 8 - '9' -> 9 - 'A' -> 10 - 'B' -> 11 - 'C' -> 12 - 'D' -> 13 - 'E' -> 14 - 'F' -> 15 - _ -> 0 - - go current (acc, pow) = - (acc+(toDig current)*(16^pow), pow+1) - in - fst <| String.foldr go (0, 0) hex +fromHex hex = + let + toDig n = + case Char.toUpper n of + '1' -> + 1 + + '2' -> + 2 + + '3' -> + 3 + + '4' -> + 4 + + '5' -> + 5 + + '6' -> + 6 + + '7' -> + 7 + + '8' -> + 8 + + '9' -> + 9 + + 'A' -> + 10 + + 'B' -> + 11 + + 'C' -> + 12 + + 'D' -> + 13 + + 'E' -> + 14 + + 'F' -> + 15 + + _ -> + 0 + + go current ( acc, pow ) = + ( acc + (toDig current) * (16 ^ pow), pow + 1 ) + in + first <| String.foldr go ( 0, 0 ) hex + {-| Decode a hash. Example use: - hash = - let + hash = + let context = hashidsSimple "this is my salt" - in + in decode context "rD" -- == [5] -} -decode : Context -- A Hashids context object - -> String -- Hash - -> List Int -decode context hash = - if hash == "" then - [] - else - let - {guards, seps, salt, minHashLength, alphabet} = context - guardParts = splitOn guards hash - guardPartsLen = List.length guardParts - hash' = - Maybe.withDefault "" <| List.head <| - if (2 <= guardPartsLen) && (guardPartsLen <= 3) then - List.drop 1 guardParts - else - guardParts - - hash'' = String.dropLeft 1 hash' - lotteryChar = String.left 1 hash' - - hashParts = splitOn seps hash'' - - numbers = - if String.isEmpty hash' then - [] - else - fst <| List.foldl go ([], alphabet) hashParts - - go part (acc, alpha) = - let - alphaSalt = - String.left (String.length alpha) (lotteryChar ++ salt ++ alpha) - alpha' = reorder alpha alphaSalt - in - (acc ++ [unhash part alpha'], alpha') - - unhash part alpha = +decode : + Context + -- A Hashids context object + -> String + -- Hash + -> List Int +decode context hash = + if hash == "" then + [] + else let - partLen = String.length part - alphaLen = String.length alpha - partList = List.map String.fromChar <| String.toList part - - position c = - String.indexes c alpha |> List.head >> (Maybe.withDefault 0) + { guards, seps, salt, minHashLength, alphabet } = + context + + guardParts = + splitOn guards hash + + guardPartsLen = + List.length guardParts + + hash1 = + Maybe.withDefault "" <| + List.head <| + if (2 <= guardPartsLen) && (guardPartsLen <= 3) then + List.drop 1 guardParts + else + guardParts + + hash2 = + String.dropLeft 1 hash1 + + lotteryChar = + String.left 1 hash1 + + hashParts = + splitOn seps hash2 + + numbers = + if String.isEmpty hash1 then + [] + else + first <| List.foldl go ( [], alphabet ) hashParts + + go part ( acc, alpha ) = + let + alphaSalt = + String.left (String.length alpha) (lotteryChar ++ salt ++ alpha) + + alpha1 = + reorder alpha alphaSalt + in + ( acc ++ [ unhash part alpha1 ], alpha1 ) + + unhash part alpha = + let + partLen = + String.length part + + alphaLen = + String.length alpha + + partList = + List.map String.fromChar <| String.toList part + + position c = + String.indexes c alpha |> List.head >> (Maybe.withDefault 0) + + go i c = + (position c) * alphaLen ^ (partLen - i - 1) + in + List.sum <| List.indexedMap go partList + in + if (encodeList context numbers) /= hash then + [] + else + numbers - go i c = - (position c)*alphaLen^(partLen-i-1) - in - List.sum <| List.indexedMap go partList - in - if (encodeList context numbers) /= hash then - [] - else - numbers -splitOn : String -> String -> List String -splitOn splitters str = - Regex.split Regex.All (Regex.regex <| "["++splitters++"]") str +splitOn : String -> String -> List String +splitOn splitters str = + Regex.split Regex.All (Regex.regex <| "[" ++ splitters ++ "]") str {-| Encode a single number. Example use: - hash = - let + hash = + let context = hashidsSimple "this is my salt" - in + in encode context 5 -- == "rD" -} -encode : Context -- A Hashids context object - -> Int -- Number to encode - -> String -encode context n = encodeList context [n] +encode : + Context + -- A Hashids context object + -> Int + -- Number to encode + -> String +encode context n = + encodeList context [ n ] + {-| Encode a list of numbers. Example use: - hash = - let + hash = + let context = hashidsSimple "this is my salt" - in + in encodeList context [2, 3, 5, 7, 11] -- == "EOurh6cbTD" -} -encodeList : Context -- A Hashids context object - -> List Int -- List of numbers - -> String -encodeList context numbers = - let - {guards, seps, salt, minHashLength, alphabet} = context - alphaLen = String.length alphabet - sepsLen = String.length seps - valuesHash = - List.sum <| List.indexedMap (\i n -> n % (i+100)) numbers - - --encoded = lottery = alphabet[values_hash % len(alphabet)] - lottery = strGet (valuesHash % alphaLen) alphabet - - hash value alpha acc = - let - alphaLen = String.length alpha - value' = value // alphaLen - acc' = (strGet (value%alphaLen) alpha) ++ acc - in - if value' == 0 then - acc' - else - hash value' alpha acc' - - go (i, value) (acc, alpha) = - let - alphaSalt = String.left alphaLen (lottery++salt++alpha) - alpha' = reorder alpha alphaSalt - last = hash value alpha' "" - firstCode = ordOfIdx 0 last - - value' = value % (firstCode+i) - sepEnc = strGet (value' % sepsLen) seps - in - (acc++[last++sepEnc], alpha') - - (encodedList, alpha') = - List.indexedMap (,) numbers - |> List.foldl go ([lottery], alphabet) - - encodedPre = String.concat encodedList - encoded = String.dropRight 1 encodedPre -- cut off last separator - in - if (String.length encoded) >= minHashLength then - encoded - else - ensureLength encoded minHashLength alpha' guards valuesHash +encodeList : + Context + -- A Hashids context object + -> List Int + -- List of numbers + -> String +encodeList context numbers = + let + { guards, seps, salt, minHashLength, alphabet } = + context + + alphaLen = + String.length alphabet + + sepsLen = + String.length seps + + valuesHash = + List.sum <| List.indexedMap (\i n -> n % (i + 100)) numbers + + --encoded = lottery = alphabet[values_hash % len(alphabet)] + lottery = + strGet (valuesHash % alphaLen) alphabet + + hash value alpha acc = + let + alphaLen = + String.length alpha + + value1 = + value // alphaLen + + acc1 = + (strGet (value % alphaLen) alpha) ++ acc + in + if value1 == 0 then + acc1 + else + hash value1 alpha acc1 + + go ( i, value ) ( acc, alpha ) = + let + alphaSalt = + String.left alphaLen (lottery ++ salt ++ alpha) + + alpha1 = + reorder alpha alphaSalt + + last = + hash value alpha1 "" + + firstCode = + ordOfIdx 0 last + + value1 = + value % (firstCode + i) + + sepEnc = + strGet (value1 % sepsLen) seps + in + ( acc ++ [ last ++ sepEnc ], alpha1 ) + + ( encodedList, alpha1 ) = + List.indexedMap (,) numbers + |> List.foldl go ( [ lottery ], alphabet ) + + encodedPre = + String.concat encodedList + + encoded = + String.dropRight 1 encodedPre + + -- cut off last separator + in + if (String.length encoded) >= minHashLength then + encoded + else + ensureLength encoded minHashLength alpha1 guards valuesHash + strGet : Int -> String -> String -strGet i str = - String.left 1 <| String.dropLeft i str +strGet i str = + String.left 1 <| String.dropLeft i str + ordOfIdx : Int -> String -> Int ordOfIdx i str = - String.dropLeft i str - |> String.toList |> List.head - |> Maybe.map Char.toCode - |> Maybe.withDefault 0 - + String.dropLeft i str + |> String.toList + |> List.head + |> Maybe.map Char.toCode + |> Maybe.withDefault 0 + + ensureLength : String -> Int -> String -> String -> Int -> String ensureLength encoded minHashLength alphabet guards valuesHash = - let - guardsLen = String.length guards - guardIndex = (valuesHash + (ordOfIdx 0 encoded)) % guardsLen - - acc = (strGet guardIndex guards) ++ encoded - - guardIndex' = (valuesHash + (ordOfIdx 2 acc)) % guardsLen - - acc' = - if (String.length acc) < minHashLength then - acc ++ (strGet guardIndex' guards) - else - acc - - splitAt = (String.length alphabet) // 2 - - extend encoded alpha = - let - alpha' = reorder alpha alpha - encodedPre = - (String.dropLeft splitAt alpha') ++ encoded - ++ (String.left splitAt alpha') - excess = (String.length encodedPre) - minHashLength - fromIndex = excess // 2 - encoded' = - if excess > 0 then - String.left minHashLength <| String.dropLeft fromIndex encodedPre - else - encodedPre - in - if (String.length encoded') < minHashLength then - extend encoded' alpha' - else - encoded' - in - extend acc' alphabet + let + guardsLen = + String.length guards + + guardIndex = + (valuesHash + (ordOfIdx 0 encoded)) % guardsLen + + acc = + (strGet guardIndex guards) ++ encoded + + guardIndex1 = + (valuesHash + (ordOfIdx 2 acc)) % guardsLen + + acc1 = + if (String.length acc) < minHashLength then + acc ++ (strGet guardIndex1 guards) + else + acc + + splitAt = + (String.length alphabet) // 2 + + extend encoded alpha = + let + alpha1 = + reorder alpha alpha + + encodedPre = + (String.dropLeft splitAt alpha1) + ++ encoded + ++ (String.left splitAt alpha1) + + excess = + (String.length encodedPre) - minHashLength + + fromIndex = + excess // 2 + + encoded1 = + if excess > 0 then + String.left minHashLength <| String.dropLeft fromIndex encodedPre + else + encodedPre + in + if (String.length encoded1) < minHashLength then + extend encoded1 alpha1 + else + encoded1 + in + extend acc1 alphabet {-| Encode a number using the provided salt. @@ -501,10 +718,15 @@ This convenience function creates a context with the default alphabet. If the same context is used repeatedly, use 'encode' with one of the constructors instead. -} -encodeUsingSalt : String -- Salt - -> Int -- Number - -> String -encodeUsingSalt = encode << hashidsSimple +encodeUsingSalt : + String + -- Salt + -> Int + -- Number + -> String +encodeUsingSalt = + encode << hashidsSimple + {-| Encode a list of numbers using the provided salt. @@ -512,10 +734,15 @@ This function wrapper creates a context with the default alphabet. If the same context is used repeatedly, use 'encodeList' with one of the constructors instead. -} -encodeListUsingSalt : String -- Salt - -> List Int -- Numbers - -> String -encodeListUsingSalt = encodeList << hashidsSimple +encodeListUsingSalt : + String + -- Salt + -> List Int + -- Numbers + -> String +encodeListUsingSalt = + encodeList << hashidsSimple + {-| Decode a hash using the provided salt. @@ -523,21 +750,35 @@ This convenience function creates a context with the default alphabet. If the same context is used repeatedly, use 'decode' with one of the constructors instead. -} -decodeUsingSalt : String -- Salt - -> String -- Hash - -> List Int -decodeUsingSalt = decode << hashidsSimple +decodeUsingSalt : + String + -- Salt + -> String + -- Hash + -> List Int +decodeUsingSalt = + decode << hashidsSimple + {-| Shortcut for 'encodeHex'. -} -encodeHexUsingSalt : String -- Salt - -> String -- Hexadecimal number represented as a string - -> String -encodeHexUsingSalt = encodeHex << hashidsSimple +encodeHexUsingSalt : + String + -- Salt + -> String + -- Hexadecimal number represented as a string + -> String +encodeHexUsingSalt = + encodeHex << hashidsSimple + {-| Shortcut for 'decodeHex'. -} -decodeHexUsingSalt : String -- Salt - -> String -- Hash - -> String -decodeHexUsingSalt = decodeHex << hashidsSimple +decodeHexUsingSalt : + String + -- Salt + -> String + -- Hash + -> String +decodeHexUsingSalt = + decodeHex << hashidsSimple diff --git a/test/elm-package.json b/test/elm-package.json deleted file mode 100644 index 8d1bc7f..0000000 --- a/test/elm-package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": "1.0.2", - "summary": "Elm port of the Hashids library", - "repository": "https://github.com/pdamoc/elm-hashids.git", - "license": "MIT", - "source-directories": [ - ".", - "../src" - ], - "exposed-modules": [ - "Hashids" - ], - "dependencies": { - "elm-lang/core": "4.0.0 <= v < 5.0.0", - "eeue56/elm-test": "1.0.0 <= v < 2.0.0" - }, - "elm-version": "0.17.0 <= v < 0.18.0" -} \ No newline at end of file diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..aee9810 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +/elm-stuff/ diff --git a/tests/Main.elm b/tests/Main.elm new file mode 100644 index 0000000..7d62c1a --- /dev/null +++ b/tests/Main.elm @@ -0,0 +1,13 @@ +port module Main exposing (..) + +import Tests +import Test.Runner.Node exposing (run, TestProgram) +import Json.Encode exposing (Value) + + +main : TestProgram +main = + run emit Tests.all + + +port emit : ( String, Value ) -> Cmd msg diff --git a/test/Test.elm b/tests/Tests.elm similarity index 98% rename from test/Test.elm rename to tests/Tests.elm index 7c0efca..8bf9026 100644 --- a/test/Test.elm +++ b/tests/Tests.elm @@ -1,62 +1,73 @@ -import ElmTest exposing (..) +module Tests exposing (..) +import Test exposing (..) +import Expect exposing (equal) +import String import Json.Decode as Json -import String import Hashids -context : Hashids.Context -context = Hashids.hashidsMinimum "this is a salt" 10 + +all : Test +all = + describe "Encoding & Decoding" [ encoding, decoding ] +context : Hashids.Context +context = + Hashids.hashidsMinimum "this is a salt" 10 + tests : List ( List Int, String ) tests = - let - lines = String.split "\n" testData + let + lines = + String.split "\n" testData + + decodeNumbers str = + Json.decodeString (Json.list Json.int) str + |> Result.withDefault [] - decodeNumbers str = - Json.decodeString (Json.list Json.int) str - |> Result.withDefault [] + numbers = + List.filter (\s -> (String.left 1 s) == "[") lines + |> List.map decodeNumbers - numbers = - List.filter (\s -> (String.left 1 s) == "[") lines - |> List.map decodeNumbers + hashes = + List.filter (\s -> (String.left 1 s) /= "[") lines + in + List.map2 (,) numbers hashes - hashes = List.filter (\s -> (String.left 1 s) /= "[") lines - in - List.map2 (,) numbers hashes encodeTest : ( List Int, String ) -> Test -encodeTest (list, hash) = - assertEqual (Hashids.encodeList context list) hash - |> test "" +encodeTest ( list, hash ) = + equal (Hashids.encodeList context list) hash + |> (\e -> test "" (\() -> e)) encoding : Test -encoding = - List.map encodeTest tests - |> suite "Encoding Suite" +encoding = + List.map encodeTest tests + |> describe "Encoding Suite" + decodeTest : ( List Int, String ) -> Test -decodeTest (list, hash) = - assertEqual list (Hashids.decode context hash) - |> test "" +decodeTest ( list, hash ) = + equal list (Hashids.decode context hash) + |> (\e -> test "" (\() -> e)) + decoding : Test -decoding = - List.map decodeTest tests - |> suite "Decoding Suite" +decoding = + List.map decodeTest tests + |> describe "Decoding Suite" + + -bothTests : Test -bothTests = - suite "Encoding & Decoding" [encoding, decoding] +-- outputs to the console -main : Program Never -main = - runSuite bothTests -- outputs to the console testData : String -testData = """[89960,65856,97751,38513,92083,25409,20930,56051] +testData = + """[89960,65856,97751,38513,92083,25409,20930,56051] wMjrLFYdgF63lwtwvKSYKadS5e4upPzU3P5 [76129,5622,46156,72323,79846,19217,75505,34113,70028] b1YJhj2kUmd1T0Qvuy43fKGWtWNDf2yQSVPM @@ -3455,4 +3466,4 @@ R90YZ5uK1g [88872,52499,60935,35035,55513,81525,4859,19354,30919] 833JdUz3Ztb2jTnXeuvLLtX0VcPndcVZOF81n [90254,68381,29524,13187,35830] -3LOZdHdEehGn8hex5S3Xl""" \ No newline at end of file +3LOZdHdEehGn8hex5S3Xl""" diff --git a/tests/elm-package.json b/tests/elm-package.json new file mode 100644 index 0000000..ed3fb49 --- /dev/null +++ b/tests/elm-package.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.2", + "summary": "Elm port of the Hashids library", + "repository": "https://github.com/pdamoc/elm-hashids.git", + "license": "MIT", + "source-directories": [ + ".", + "../src" + ], + "exposed-modules": [], + "dependencies": { + "elm-community/json-extra": "2.0.0 <= v < 3.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0", + "mgold/elm-random-pcg": "4.0.0 <= v < 5.0.0", + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-community/elm-test": "3.0.0 <= v < 4.0.0", + "rtfeldman/node-test-runner": "3.0.0 <= v < 4.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +}