├── .Rbuildignore ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── R ├── defaults.R └── hash.R ├── README.md ├── cran-comments.md ├── man ├── ascii_val.Rd ├── base16_to_dec.Rd ├── dec_to_base16.Rd ├── decode.Rd ├── decode_hex.Rd ├── encode.Rd ├── encode_hex.Rd ├── enforce_min_length.Rd ├── hash.Rd ├── hashid_defaults.Rd ├── hashid_settings.Rd ├── shuffle.Rd ├── split.Rd └── unhash.Rd └── tests ├── testthat.R └── testthat ├── test_decode.R └── test_encode.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^\.travis\.yml$ 2 | ^cran-comments.md$ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | hashids.Rproj -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: r 2 | sudo: required 3 | warnings_are_errors: true 4 | 5 | env: 6 | global: 7 | - NOT_CRAN=true 8 | before_install: echo "options(repos = c(CRAN='http://cran.rstudio.com'))" > ~/.Rprofile -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: hashids 2 | Title: Generate Short Unique YouTube-Like IDs (Hashes) from Integers 3 | Version: 0.9.0.9000 4 | Authors@R: c( 5 | person("Alex", "Shum", email = "Alex@ALShum.com", role = c("aut", "cre")), 6 | person("Ivan", "Akimov", email = "ivan@barreleye.com", role= c("aut"), comment = "original author of hashids -- implemented in javascript"), 7 | person("David", "Aurelio", email = "dev@david-aurelio.com", role = c("ctb"), comment = "implemented hashids in python 2 and 3")) 8 | Description: An R port of the hashids library. hashids generates YouTube-like hashes from integers or vector of integers. Hashes generated from integers are relatively short, unique and non-seqential. hashids can be used to generate unique ids for URLs and hide database row numbers from the user. By default hashids will avoid generating common English cursewords by preventing certain letters being next to each other. hashids are not one-way: it is easy to encode an integer to a hashid and decode a hashid back into an integer. 9 | URL: https://github.com/ALShum/hashids-r/, http://hashids.org 10 | BugReports: https://github.com/ALShum/hashids-r/issues 11 | Depends: R (>= 3.2.2) 12 | License: MIT + file LICENSE 13 | LazyData: true 14 | Suggests: testthat 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2015 2 | COPYRIGHT HOLDER: Ivan Akimov, David Aurelio, Alex Shum -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(DEFAULT_ALPHABET) 4 | export(DEFAULT_SEPS) 5 | export(RATIO_GUARDS) 6 | export(RATIO_SEPARATORS) 7 | export(decode) 8 | export(decode_hex) 9 | export(encode) 10 | export(encode_hex) 11 | export(hashid_settings) 12 | -------------------------------------------------------------------------------- /R/defaults.R: -------------------------------------------------------------------------------- 1 | #' @name hashid_defaults 2 | #' 3 | #' @title Default Values for hashid settings 4 | #' @description Default alphabet, separators, and 5 | #' ratio of character separators and guards for hashid 6 | #' 7 | #' @source 8 | #' http://www.hashids.org 9 | #' 10 | 11 | #' @rdname hashid_defaults 12 | #' @export 13 | DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 14 | 15 | #' @rdname hashid_defaults 16 | #' @export 17 | DEFAULT_SEPS = "cfhistuCFHISTU" 18 | 19 | #' @rdname hashid_defaults 20 | #' @export 21 | RATIO_SEPARATORS = 3.5 22 | 23 | #' @rdname hashid_defaults 24 | #' @export 25 | RATIO_GUARDS = 12 -------------------------------------------------------------------------------- /R/hash.R: -------------------------------------------------------------------------------- 1 | #' Decodes a hashid into the original integer or integer vector 2 | #' 3 | #' @param hash_str hashid string to decode into integer or integer vector 4 | #' @param settings Settings list generated by hashid_settings 5 | #' @return integer or integer vector 6 | #' @export 7 | #' 8 | decode = function(hash_str, settings) { 9 | if(hash_str == '') stop("decode: invalid hashid") 10 | 11 | salt = settings$salt 12 | alphabet = settings$alphabet 13 | separator = settings$separator 14 | guards = settings$guards 15 | 16 | parts = split(hash_str, guards) 17 | hashid = ifelse( 18 | 2 <= length(parts) & length(parts) <= 3, 19 | parts[2], 20 | parts[1] 21 | ) 22 | 23 | if(hashid == '') stop("decode: invalid hashid, cannot decode") 24 | lottery = substr(hashid, 1, 1) 25 | hashid = substr(hashid, 2, nchar(hashid)) 26 | 27 | hash_parts = split(hashid, separator) 28 | unhashed_parts = c() 29 | for(p in hash_parts) { 30 | alphabet_salt = substr( 31 | paste0(lottery, salt, alphabet), 32 | 1, nchar(alphabet) 33 | ) 34 | alphabet = shuffle(alphabet, alphabet_salt) 35 | unhashed_parts = c(unhashed_parts, unhash(p, alphabet)) 36 | } 37 | 38 | rehash = tryCatch({ 39 | encode(unhashed_parts, settings) 40 | }, error = function(e) { 41 | stop("decode: invalid hashid, cannot decode") 42 | }) 43 | if(!all(hash_str == rehash)) { 44 | stop("decode: invalid hashid, cannot decode") 45 | } 46 | 47 | return(unhashed_parts) 48 | } 49 | 50 | #' Decodes a hashid into the original hexidecimal number 51 | #' 52 | #' @param hashid hashid to decode 53 | #' @param settings Settings list generated by hashid_settings 54 | #' @return hexidecimal number as a string 55 | #' @export 56 | #' 57 | decode_hex = function(hashid, settings) { 58 | num_vec = decode(hashid, settings) 59 | 60 | hex_vec = sapply(num_vec, function(x) { 61 | x = dec_to_base16(x) 62 | x = substr(x, 2, nchar(x)) 63 | x 64 | }) 65 | 66 | paste(hex_vec, collapse="") 67 | } 68 | 69 | #' Encodes an integer or integer vector into a hashid string. 70 | #' All numbers must be non-negative integers. 71 | #' 72 | #' @param int Integer or integer vector to encode 73 | #' @param settings Settings list generated by hashid_settings 74 | #' @return hashid string 75 | #' @export 76 | #' 77 | encode = function(int, settings) { 78 | if(!all(c("alphabet", "salt", "guards", "separator", "min_length") 79 | %in% names(settings))) { 80 | stop("encode: missing some parameters in settings list") 81 | } 82 | if(any(int < 0)) { 83 | stop("encode: numbers must be non-negative") 84 | } 85 | if(any(int %% 1 != 0)) { 86 | stop("encode: numbers must be integers") 87 | } 88 | if(length(int) < 1) { 89 | stop("encode: Invalid length!") 90 | } 91 | 92 | alphabet = settings$alphabet 93 | salt = settings$salt 94 | guards = settings$guards 95 | separator = settings$separator 96 | min_length = settings$min_length 97 | alphabet_len = nchar(settings$alphabet) 98 | sep_len = nchar(settings$separator) 99 | 100 | vec_hash = sum( 101 | sapply( 102 | 1:length(int), function(i) { 103 | int[i] %% (100 + i - 1) 104 | } 105 | ) 106 | ) 107 | #lottery character 108 | lottery = substr(alphabet, 109 | (vec_hash %% alphabet_len) + 1, 110 | (vec_hash %% alphabet_len) + 1 111 | ) 112 | encoded = lottery 113 | 114 | for(i in 1:length(int)) { 115 | alphabet_salt = substr( 116 | paste0(lottery, 117 | salt, 118 | alphabet 119 | ), 120 | 1, alphabet_len 121 | ) 122 | alphabet = shuffle(alphabet, alphabet_salt) 123 | last = hash(int[i], alphabet) 124 | encoded = paste0(encoded, last) 125 | int[i] = int[i] %% (ascii_val(substr(last, 1, 1)) + (i - 1)) 126 | encoded = paste0( 127 | encoded, 128 | substr( 129 | separator, 130 | (int[i] %% sep_len + 1), 131 | (int[i] %% sep_len + 1) 132 | ) 133 | ) 134 | } 135 | 136 | encoded = substr(encoded, 1, nchar(encoded) - 1) 137 | if(nchar(encoded) <= min_length) { 138 | encoded = enforce_min_length(encoded, min_length, alphabet, guards, vec_hash) 139 | } 140 | 141 | return(encoded) 142 | } 143 | 144 | #' Encodes a hexademical number into a hashid 145 | #' 146 | #' @param hex_str Hexadecimal number as string 147 | #' @param settings Settings list generated by hashid_settings 148 | #' @return hashid string 149 | #' @export 150 | #' 151 | encode_hex = function(hex_str, settings) { 152 | if(hex_str == '') stop("encode_hex: invalid hex") 153 | hex_idx = seq(0, nchar(hex_str) - 1, 12) 154 | 155 | num_vec = c() 156 | for(i in hex_idx) { 157 | num_vec = c( 158 | num_vec, 159 | base16_to_dec( 160 | paste0( 161 | '1', 162 | substr(hex_str, 163 | i + 1, i + 12 164 | ) 165 | ) 166 | ) 167 | ) 168 | } 169 | 170 | encode(num_vec, settings) 171 | } 172 | 173 | #' A function to create a hashid settings list. 174 | #' 175 | #' @param salt An additional string to make hashids more unique. 176 | #' @param min_length Minimum length for hashid. 177 | #' @param alphabet String of characters for hashid. 178 | #' @param sep String of characters to use as separators. 179 | #' @return A list of parameters used in encoding and decoding. 180 | #' @export 181 | #' 182 | hashid_settings = function( 183 | salt, 184 | min_length = 0, 185 | alphabet = DEFAULT_ALPHABET, 186 | sep = DEFAULT_SEPS) { 187 | 188 | alphabet_vec = unique(strsplit(alphabet, split = "")[[1]]) 189 | sep_vec = unique(strsplit(sep, split = "")[[1]]) 190 | 191 | separator_ = paste(intersect(sep_vec, alphabet_vec), collapse = "") 192 | alphabet_ = paste(setdiff(alphabet_vec, sep_vec), collapse = "") 193 | 194 | if(nchar(separator_) + nchar(alphabet_) < 16) { 195 | #if(nchar(alphabet_) < 16) { 196 | stop("hashid_settings: Alphabet must be at least 16 unique characters.") 197 | } 198 | 199 | separator_ = shuffle(separator_, salt) 200 | min_separators = ceiling(nchar(alphabet_) / RATIO_SEPARATORS) 201 | 202 | ## if needed get more separators from alphabet ## 203 | if(nchar(separator_) < min_separators) { 204 | if(min_separators == 1) min_separators = 2 205 | split_at = min_separators - nchar(separator_) 206 | separator_ = paste0(separator_, substr(alphabet_, 1, split_at)) 207 | alphabet_ = substr(alphabet_, split_at + 1, nchar(alphabet_)) 208 | } 209 | 210 | alphabet_ = shuffle(alphabet_, salt) 211 | num_guards = ceiling(nchar(alphabet_) / RATIO_GUARDS) 212 | 213 | if(nchar(alphabet_) < 3) { 214 | guards_ = substring(separator_, 1, num_guards) 215 | separator_ = substr(separator_, num_guards + 1, nchar(separator_)) 216 | } else { 217 | guards_ = substring(alphabet_, 1, num_guards) 218 | alphabet_ = substr(alphabet_, num_guards + 1, nchar(alphabet_)) 219 | } 220 | 221 | return(list( 222 | alphabet = alphabet_, 223 | salt = salt, 224 | guards = guards_, 225 | separator = separator_, 226 | min_length = min_length 227 | )) 228 | } 229 | 230 | #' Calculate the ascii value number of a character 231 | #' 232 | #' @param char character 233 | #' @return ascii value integer 234 | #' 235 | ascii_val = function(char) { 236 | if(!is.character(char)) stop("ascii_val: must be character") 237 | strtoi(charToRaw(char), 16) 238 | } 239 | 240 | #' Converts a base 16 string to a base 10 number. 241 | #' Because I couldn't get base R functions to work for big hex numbers. 242 | #' 243 | #' @param str_16 base 16 number as a string. 244 | #' @return base 10 integer. 245 | #' 246 | base16_to_dec = function(str_16) { 247 | str_vec = strsplit(tolower(str_16), split = "")[[1]] 248 | str_vec = sapply(str_vec, function(x) { 249 | if(x %in% as.character(0:9)) { 250 | as.numeric(x) 251 | } else if(x %in% c('a', 'b', 'c', 'd', 'e', 'f')) { 252 | ascii_val(x) - 87 253 | } else { 254 | stop("base16_to_dec: Invalid hex character") 255 | } 256 | }) 257 | 258 | vec_pwrs = 16^(rev(1:length(str_vec)) - 1) 259 | 260 | sum(vec_pwrs * str_vec) 261 | } 262 | 263 | #' Converts a base 10 number to base 16 number. 264 | #' Because I couldn't get R's as.hexmode() to work for big integers. 265 | #' 266 | #' @param dec base 10 integer 267 | #' @return base 16 number as a string 268 | #' 269 | dec_to_base16 = function(dec) { 270 | num_vec = c() 271 | while(dec > 0) { 272 | rem = dec %% 16 273 | num_vec = c(rem, num_vec) 274 | dec = floor(dec / 16) 275 | } 276 | 277 | hex_vec = sapply(num_vec, function(x) { 278 | if(x < 10) { 279 | return(x) 280 | } else { 281 | base::letters[x - 9] 282 | } 283 | }) 284 | 285 | paste(hex_vec, collapse="") 286 | } 287 | 288 | #' Enforces hashid minimum length by padding the hashid with additional characters. 289 | #' 290 | #' @param encoded encoded hashid 291 | #' @param min_length minimum length required for hashid 292 | #' @param alphabet set of letters used to generate hashid 293 | #' @param guards set of guards used to generate hashid 294 | #' @param values_hash value hashed used to select guard characters 295 | #' @return hashid with padded characters to insure minimum length 296 | #' 297 | enforce_min_length = function( 298 | encoded, 299 | min_length, 300 | alphabet, 301 | guards, 302 | values_hash) { 303 | 304 | guards_len = nchar(guards) 305 | guards_idx = (values_hash + ascii_val(substr(encoded, 1, 1))) %% guards_len + 1 306 | encoded = paste0(substr(guards, guards_idx, guards_idx), encoded) 307 | 308 | if(nchar(encoded) < min_length) { 309 | guards_idx = (values_hash + ascii_val(substr(encoded, 3, 3))) %% guards_len + 1 310 | encoded = paste0(encoded, substr(guards, guards_idx, guards_idx)) 311 | } 312 | 313 | split_at = nchar(alphabet) / 2 + 1 314 | while(nchar(encoded) < min_length) { 315 | alphabet = shuffle(alphabet, alphabet) 316 | encoded = paste0( 317 | substr(alphabet, split_at, nchar(alphabet)), 318 | encoded, 319 | substr(alphabet, 1, split_at - 1) 320 | ) 321 | excess = nchar(encoded) - min_length 322 | 323 | if(excess > 0) { 324 | from_index = floor(excess / 2) + 1 325 | encoded = substr(encoded, 326 | from_index, 327 | from_index + min_length - 1 328 | ) 329 | } 330 | } 331 | 332 | return(encoded) 333 | } 334 | 335 | #' Maps an integer to a string. 336 | #' Generated string will be inversely proportional to alphabet length. 337 | #' 338 | #' @param number Integer to hash 339 | #' @param alphabet Possible letters for string. 340 | #' @return hashed string 341 | #' 342 | hash = function(number, alphabet) { 343 | alphabet_len = nchar(alphabet) 344 | alphabet_vec = strsplit(alphabet, split = "")[[1]] 345 | 346 | hashed = c() 347 | while(number > 0) { 348 | hash_idx = (number %% alphabet_len) + 1 349 | hashed = c(alphabet_vec[hash_idx], hashed) 350 | number = floor(number / alphabet_len) 351 | } 352 | 353 | return(paste(hashed, collapse = "")) 354 | } 355 | 356 | #' Permutes the characters in a string based on an inputted salt string. 357 | #' 358 | #' @param string String to be permuted 359 | #' @param salt cryptograph salt string that is used to permute strings 360 | #' @return shuffled string 361 | #' 362 | shuffle = function(string, salt) { 363 | salt_len = nchar(salt) 364 | str_len = nchar(string) 365 | if(salt_len < 1 | str_len < 2) return(string) 366 | 367 | salt_sum = 0 368 | salt_index = 1 369 | string_vec = strsplit(string, split = "")[[1]] 370 | salt_vec = strsplit(salt, split = "")[[1]] 371 | for(i_str in rev(2:str_len)) { 372 | ## Pseudo Randomize based on salt ## 373 | salt_index = (salt_index - 1) %% (salt_len) + 1 374 | salt_int_val = ascii_val(salt_vec[salt_index]) 375 | salt_sum = salt_sum + salt_int_val 376 | swap_pos = (salt_sum + salt_index + salt_int_val - 1) %% (i_str - 1) + 1 377 | 378 | ## Swap positions ## 379 | temp = string_vec[swap_pos] 380 | string_vec[swap_pos] = string_vec[i_str] 381 | string_vec[i_str] = temp 382 | salt_index = salt_index + 1 383 | } 384 | 385 | return(paste(string_vec, collapse = "")) 386 | } 387 | 388 | #' Splits a string based on a set of splitting characters 389 | #' 390 | #' @param string String to split 391 | #' @param splitters set of splitting characters as a string 392 | #' @return split vector of characters 393 | #' 394 | split = function(string, splitters) { 395 | string_vec = strsplit(string, split = "")[[1]] 396 | split_vec = strsplit(splitters, split = "")[[1]] 397 | 398 | word = '' 399 | words = c() 400 | for(i in 1:length(string_vec)) { 401 | if(string_vec[i] %in% split_vec) { 402 | words = c(words, word) 403 | word = '' 404 | } else { 405 | word = paste0(word, string_vec[i]) 406 | } 407 | } 408 | words = c(words, word) 409 | 410 | return(words) 411 | } 412 | 413 | #' Unhashes a string to an integer based on alphabet. 414 | #' 415 | #' @param hashed String to unhash 416 | #' @param alphabet Set of letters used for hashing 417 | #' @return Unhashed integer 418 | #' 419 | unhash = function(hashed, alphabet) { 420 | hashed_len = nchar(hashed) 421 | alphabet_len = nchar(alphabet) 422 | alphabet_vec = strsplit(alphabet, split="")[[1]] 423 | hashed_vec = strsplit(hashed, split="")[[1]] 424 | 425 | number = 0 426 | for(i in 1:hashed_len) { 427 | position = which(alphabet_vec == hashed_vec[i]) - 1 428 | number = number + (position * alphabet_len ** (hashed_len - i)) 429 | } 430 | 431 | return(number) 432 | } 433 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ALShum/hashids-r.svg?branch=master)](https://travis-ci.org/ALShum/hashids-r) 2 | 3 | # Hashids in R 4 | 5 | An R port of the [hashids library](http://www.hashids.org). hashids generates YouTube-like ids (hashes) from integers or vector of integers. Hashes generated from integers are relatively short, unique and non-sequential and can be used to generate unique ids for URLs and hide database row numbers from the user. By default hashids will avoid generating common English cursewords by preventing certain letters being next to each other. 6 | 7 | For example, integers like `1`, `2` and `3` will be encoded as strings like `NV`, `6m` and `yD` respectively. Vectors like `c(1, 2, 3, 4)` will be encoded as a string like `agHLu9hm` and `c(1, 1, 1, 1)` as `2bHEH5HY`. 8 | 9 | ## Why should I use Hashids? 10 | 1. Unguessable: incremental numbers encoded to prevent predictability. 11 | 2. Unique: no need to worry about hash collisions. 12 | 3. Customizable: custom alphabet and salt to customize generated hashids. 13 | 4. Two way function: decoding is done as easily as encoding. 14 | 5. Can specify minimum length for hashid. 15 | 6. By default, prevents curse words from being generated. 16 | 17 | ## Why should I NOT use Hashids? 18 | * hashids is NOT cryptographically secure -- do NOT use to encode passwords. 19 | * hashids is NOT cryptographically secure -- DO NOT USE TO ENCODE PASSWORDS. 20 | * hashids is NOT CRYPTOGRAPHICALLY SECURE -- DO NOT USE TO ENCODE PASSWORDS! 21 | 22 | ## Other restrictions 23 | 1. Can only encode integers -- this is to prevent you from doing something stupid. Like encoding sensitive information. 24 | 2. Integers must be non-negative. 25 | 26 | ## Installing 27 | This package is now on CRAN! Install using `install.packages("hashids")`. Alteratively you can install using devtools to install the github version. If you don't have devtools install using `install.packages('devtools')` from your R session. Install using `devtools::install_github('ALShum/hashids-r')`. 28 | 29 | ## Summary 30 | The following are the most relevant functions: 31 | 32 | 1. `hashid_settings`: used to set minimum length, salt, custom alphabet and custom guard. 33 | 34 | 2. `encode`: gives encoded string given integer and settings list from `hashid_settings`. 35 | 36 | 3. `decode`: gives integer given encoded string and settings list from `hashid_settings`. 37 | 38 | 4. `encode_hex`: similar to `encode` but works with hexadecimal. 39 | 40 | 5. `decode_hex`: similar to `decode` but works with hexadecimal. 41 | 42 | ## Example 43 | Set your salt, min_length and any other settings using the `hashid_settings` function -- this will generate a list of important parameters for encoding and decoding: 44 | 45 | `h = hashid_settings(salt = 'this is my salt', min_length = 5)` 46 | 47 | Encode requires an integer and the settings as a list of parameters: 48 | 49 | `encode(1234, h ) #"ABBQA"` 50 | 51 | `encode(c(1, 2, 3, 4), h) #"agHLu9hm"` 52 | 53 | Decode follows a similar workflow: 54 | 55 | `decode("ABBQA", h) #1234` 56 | 57 | `decode("agHLu9hm", h) #c(1, 2, 3, 4)` 58 | 59 | ## About 60 | hashids was originally written by Ivan Akimov. This version hashids was translated along with some of the unit tests from python version of hashids written by David Aurelio. For more information please go to http://www.hashids.org. 61 | 62 | ## Compatibility 63 | Compatible with version 1.0.* of the javascript version of hashids. 64 | 65 | ## Contact 66 | Does my code suck? Contact me and tell me! [@notalexshum](http://twitter.com/notalexshum) on twitter more info about me @ http://www.ALShum.com. 67 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | Resubmit: redid title case 2 | 3 | ## Test environments 4 | * Locally: OS X, R 3.2.2 5 | * win-builder(release and dev) 6 | * travis-ci: Ubuntu 12.04, R 3.2.2 7 | 8 | ## R CMD check results 9 | No ERRORs. No WARNINGs. 10 | 11 | Only 1 NOTE pertaining about this package being a new submission. 12 | 13 | ## Downstream dependencies 14 | There are currently no downstream dependencies for this package. -------------------------------------------------------------------------------- /man/ascii_val.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{ascii_val} 4 | \alias{ascii_val} 5 | \title{Calculate the ascii value number of a character} 6 | \usage{ 7 | ascii_val(char) 8 | } 9 | \arguments{ 10 | \item{char}{character} 11 | } 12 | \value{ 13 | ascii value integer 14 | } 15 | \description{ 16 | Calculate the ascii value number of a character 17 | } 18 | 19 | -------------------------------------------------------------------------------- /man/base16_to_dec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{base16_to_dec} 4 | \alias{base16_to_dec} 5 | \title{Converts a base 16 string to a base 10 number. 6 | Because I couldn't get base R functions to work for big hex numbers.} 7 | \usage{ 8 | base16_to_dec(str_16) 9 | } 10 | \arguments{ 11 | \item{str_16}{base 16 number as a string.} 12 | } 13 | \value{ 14 | base 10 integer. 15 | } 16 | \description{ 17 | Converts a base 16 string to a base 10 number. 18 | Because I couldn't get base R functions to work for big hex numbers. 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/dec_to_base16.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{dec_to_base16} 4 | \alias{dec_to_base16} 5 | \title{Converts a base 10 number to base 16 number. 6 | Because I couldn't get R's as.hexmode() to work for big integers.} 7 | \usage{ 8 | dec_to_base16(dec) 9 | } 10 | \arguments{ 11 | \item{dec}{base 10 integer} 12 | } 13 | \value{ 14 | base 16 number as a string 15 | } 16 | \description{ 17 | Converts a base 10 number to base 16 number. 18 | Because I couldn't get R's as.hexmode() to work for big integers. 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/decode.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{decode} 4 | \alias{decode} 5 | \title{Decodes a hashid into the original integer or integer vector} 6 | \usage{ 7 | decode(hash_str, settings) 8 | } 9 | \arguments{ 10 | \item{hash_str}{hashid string to decode into integer or integer vector} 11 | 12 | \item{settings}{Settings list generated by hashid_settings} 13 | } 14 | \value{ 15 | integer or integer vector 16 | } 17 | \description{ 18 | Decodes a hashid into the original integer or integer vector 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/decode_hex.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{decode_hex} 4 | \alias{decode_hex} 5 | \title{Decodes a hashid into the original hexidecimal number} 6 | \usage{ 7 | decode_hex(hashid, settings) 8 | } 9 | \arguments{ 10 | \item{hashid}{hashid to decode} 11 | 12 | \item{settings}{Settings list generated by hashid_settings} 13 | } 14 | \value{ 15 | hexidecimal number as a string 16 | } 17 | \description{ 18 | Decodes a hashid into the original hexidecimal number 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/encode.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{encode} 4 | \alias{encode} 5 | \title{Encodes an integer or integer vector into a hashid string. 6 | All numbers must be non-negative integers.} 7 | \usage{ 8 | encode(int, settings) 9 | } 10 | \arguments{ 11 | \item{int}{Integer or integer vector to encode} 12 | 13 | \item{settings}{Settings list generated by hashid_settings} 14 | } 15 | \value{ 16 | hashid string 17 | } 18 | \description{ 19 | Encodes an integer or integer vector into a hashid string. 20 | All numbers must be non-negative integers. 21 | } 22 | 23 | -------------------------------------------------------------------------------- /man/encode_hex.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{encode_hex} 4 | \alias{encode_hex} 5 | \title{Encodes a hexademical number into a hashid} 6 | \usage{ 7 | encode_hex(hex_str, settings) 8 | } 9 | \arguments{ 10 | \item{hex_str}{Hexadecimal number as string} 11 | 12 | \item{settings}{Settings list generated by hashid_settings} 13 | } 14 | \value{ 15 | hashid string 16 | } 17 | \description{ 18 | Encodes a hexademical number into a hashid 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/enforce_min_length.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{enforce_min_length} 4 | \alias{enforce_min_length} 5 | \title{Enforces hashid minimum length by padding the hashid with additional characters.} 6 | \usage{ 7 | enforce_min_length(encoded, min_length, alphabet, guards, values_hash) 8 | } 9 | \arguments{ 10 | \item{encoded}{encoded hashid} 11 | 12 | \item{min_length}{minimum length required for hashid} 13 | 14 | \item{alphabet}{set of letters used to generate hashid} 15 | 16 | \item{guards}{set of guards used to generate hashid} 17 | 18 | \item{values_hash}{value hashed used to select guard characters} 19 | } 20 | \value{ 21 | hashid with padded characters to insure minimum length 22 | } 23 | \description{ 24 | Enforces hashid minimum length by padding the hashid with additional characters. 25 | } 26 | 27 | -------------------------------------------------------------------------------- /man/hash.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{hash} 4 | \alias{hash} 5 | \title{Maps an integer to a string. 6 | Generated string will be inversely proportional to alphabet length.} 7 | \usage{ 8 | hash(number, alphabet) 9 | } 10 | \arguments{ 11 | \item{number}{Integer to hash} 12 | 13 | \item{alphabet}{Possible letters for string.} 14 | } 15 | \value{ 16 | hashed string 17 | } 18 | \description{ 19 | Maps an integer to a string. 20 | Generated string will be inversely proportional to alphabet length. 21 | } 22 | 23 | -------------------------------------------------------------------------------- /man/hashid_defaults.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/defaults.R 3 | \docType{data} 4 | \name{hashid_defaults} 5 | \alias{DEFAULT_ALPHABET} 6 | \alias{DEFAULT_SEPS} 7 | \alias{RATIO_GUARDS} 8 | \alias{RATIO_SEPARATORS} 9 | \alias{hashid_defaults} 10 | \title{Default Values for hashid settings} 11 | \format{\preformatted{ chr "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 12 | }} 13 | \source{ 14 | http://www.hashids.org 15 | } 16 | \usage{ 17 | DEFAULT_ALPHABET 18 | 19 | DEFAULT_SEPS 20 | 21 | RATIO_SEPARATORS 22 | 23 | RATIO_GUARDS 24 | } 25 | \description{ 26 | Default alphabet, separators, and 27 | ratio of character separators and guards for hashid 28 | } 29 | \keyword{datasets} 30 | 31 | -------------------------------------------------------------------------------- /man/hashid_settings.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{hashid_settings} 4 | \alias{hashid_settings} 5 | \title{A function to create a hashid settings list.} 6 | \usage{ 7 | hashid_settings(salt, min_length = 0, alphabet = DEFAULT_ALPHABET, 8 | sep = DEFAULT_SEPS) 9 | } 10 | \arguments{ 11 | \item{salt}{An additional string to make hashids more unique.} 12 | 13 | \item{min_length}{Minimum length for hashid.} 14 | 15 | \item{alphabet}{String of characters for hashid.} 16 | 17 | \item{sep}{String of characters to use as separators.} 18 | } 19 | \value{ 20 | A list of parameters used in encoding and decoding. 21 | } 22 | \description{ 23 | A function to create a hashid settings list. 24 | } 25 | 26 | -------------------------------------------------------------------------------- /man/shuffle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{shuffle} 4 | \alias{shuffle} 5 | \title{Permutes the characters in a string based on an inputted salt string.} 6 | \usage{ 7 | shuffle(string, salt) 8 | } 9 | \arguments{ 10 | \item{string}{String to be permuted} 11 | 12 | \item{salt}{cryptograph salt string that is used to permute strings} 13 | } 14 | \value{ 15 | shuffled string 16 | } 17 | \description{ 18 | Permutes the characters in a string based on an inputted salt string. 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/split.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{split} 4 | \alias{split} 5 | \title{Splits a string based on a set of splitting characters} 6 | \usage{ 7 | split(string, splitters) 8 | } 9 | \arguments{ 10 | \item{string}{String to split} 11 | 12 | \item{splitters}{set of splitting characters as a string} 13 | } 14 | \value{ 15 | split vector of characters 16 | } 17 | \description{ 18 | Splits a string based on a set of splitting characters 19 | } 20 | 21 | -------------------------------------------------------------------------------- /man/unhash.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/hash.R 3 | \name{unhash} 4 | \alias{unhash} 5 | \title{Unhashes a string to an integer based on alphabet.} 6 | \usage{ 7 | unhash(hashed, alphabet) 8 | } 9 | \arguments{ 10 | \item{hashed}{String to unhash} 11 | 12 | \item{alphabet}{Set of letters used for hashing} 13 | } 14 | \value{ 15 | Unhashed integer 16 | } 17 | \description{ 18 | Unhashes a string to an integer based on alphabet. 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(hashids) 3 | 4 | test_check("hashids") 5 | -------------------------------------------------------------------------------- /tests/testthat/test_decode.R: -------------------------------------------------------------------------------- 1 | library(hashids) 2 | context("Decoding Unit Tests") 3 | 4 | test_that("Test decoding empty string", { 5 | h = hashid_settings(salt = '') 6 | expect_error(decode('', h), 7 | 'decode: invalid hashid') 8 | }) 9 | 10 | test_that("Decode with empty salt, single numbers", { 11 | h = hashid_settings(salt = '') 12 | expect_equal(decode('j0gW', h), 12345) 13 | expect_equal(decode('jR', h), 1) 14 | expect_equal(decode('Lw', h), 22) 15 | expect_equal(decode('Z0E', h), 333) 16 | expect_equal(decode('w0rR', h), 9999) 17 | }) 18 | 19 | test_that("Decode with empty salt, vectors of numbers", { 20 | h = hashid_settings(salt = '') 21 | expect_equal(decode('vJvi7On9cXGtD', h), c(683, 94108, 123, 5)) 22 | expect_equal(decode('o2fXhV', h), c(1, 2, 3)) 23 | expect_equal(decode('xGhmsW', h), c(2, 4, 6)) 24 | expect_equal(decode('3lKfD', h), c(99, 25)) 25 | }) 26 | 27 | test_that("Decode with arbitrary string", { 28 | h = hashid_settings(salt = 'Arbitrary string') 29 | expect_equal(decode('QWyf8yboH7KT2', h), c(683, 94108, 123, 5)) 30 | expect_equal(decode('neHrCa', h), c(1, 2, 3)) 31 | expect_equal(decode('LRCgf2', h), c(2, 4, 6)) 32 | expect_equal(decode('JOMh1', h), c(99, 25)) 33 | expect_equal(decode('l16D', h), 12345) 34 | }) 35 | 36 | test_that("Decode with alphabet", { 37 | h = hashid_settings( 38 | salt = '', 39 | alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~' 40 | ) 41 | expect_equal(decode('_nJUNTVU3', h), c(2839, 12, 32, 5)) 42 | expect_equal(decode('7xfYh2', h), c(1, 2, 3)) 43 | expect_equal(decode('Z6R>', h), 23832) 44 | expect_equal(decode('AYyIB', h), c(99, 25)) 45 | }) 46 | 47 | test_that("Decode with different min_length", { 48 | h = hashid_settings(salt = '', min_length = 25) 49 | expect_equal(decode('pO3K69b86jzc6krI416enr2B5', h), c(7452, 2967, 21401)) 50 | expect_equal(decode('gyOwl4B97bo2fXhVaDR0Znjrq', h), c(1, 2, 3)) 51 | expect_equal(decode('Nz7x3VXyMYerRmWeOBQn6LlRG', h), 6097) 52 | expect_equal(decode('k91nqP3RBe3lKfDaLJrvy8XjV', h), c(99, 25)) 53 | }) 54 | 55 | test_that("decode with salt, custom alphabet", { 56 | h = hashid_settings( 57 | alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~', 58 | salt = 'Arbitrary string' 59 | ) 60 | expect_equal(decode("6'nHG/qf>oC8", h), c(683, 94108, 123, 5)) 61 | expect_equal(decode('GEHMCe', h), c(1, 2, 3)) 62 | expect_equal(decode('YlCrfQ', h), c(2, 4, 6)) 63 | expect_equal(decode('jwe5', h), 23832) 64 | expect_equal(decode('Jz3fR', h), c(99, 25)) 65 | }) 66 | 67 | test_that("decode sequential and identical vectors", { 68 | h = hashid_settings(salt = 'this is my salt') 69 | expect_equal(decode('agHLu9hm', h), c(1, 2, 3, 4)) 70 | expect_equal(decode('aQtEhBub', h), c(4, 3, 2, 1)) 71 | expect_equal(decode('2bHEH5HY', h), c(1, 1, 1, 1)) 72 | }) 73 | 74 | test_that("Decode with all non-default parameters", { 75 | h = hashid_settings(salt = 'arbitrary salt', 76 | min_length = 16, 77 | alphabet = 'abcdefghijklmnopqrstuvwxyz' 78 | ) 79 | expect_equal(decode('wygqxeunkatjgkrw', h), c(7452, 2967, 21401)) 80 | expect_equal(decode('pnovxlaxuriowydb', h), c(1, 2, 3)) 81 | expect_equal(decode('jkbgxljrjxmlaonp', h), 60125) 82 | expect_equal(decode('erdjpwrgouoxlvbx', h), c(99, 25)) 83 | }) 84 | 85 | test_that("Test decoding invalid hashid", { 86 | h = hashid_settings(salt = '', 87 | alphabet = 'abcdefghijklmnop' 88 | ) 89 | expect_error(decode('qrstuvwxyz', h), 90 | 'decode: invalid hashid, cannot decode') 91 | }) 92 | 93 | test_that("Test decode without standard separators", { 94 | h = hashid_settings(salt = '', 95 | alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890' 96 | ) 97 | expect_equal(decode('X50Yg6VPoAO4', h), c(7452, 2967, 21401)) 98 | expect_equal(decode('GAbDdR', h), c(1, 2, 3)) 99 | expect_equal(decode('5NMPD', h), 60125) 100 | expect_equal(decode('yGya5', h), c(99, 25)) 101 | }) 102 | 103 | test_that("Test decode with two standard separators", { 104 | h = hashid_settings(salt = '', 105 | alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890uC' 106 | ) 107 | expect_equal(decode('GJNNmKYzbPBw', h), c(7452, 2967, 21401)) 108 | expect_equal(decode('DQCXa4', h), c(1, 2, 3)) 109 | expect_equal(decode('38V1D', h), 60125) 110 | expect_equal(decode('373az', h), c(99, 25)) 111 | }) 112 | 113 | test_that("Invalid hash id", { 114 | h = hashid_settings(salt = '', min_length = 6) 115 | hashed = encode(1, h) 116 | invalid_hash = substr(hashed, 2, nchar(hashed)) 117 | expect_error( 118 | decode(invalid_hash, h), 119 | "decode: invalid hashid, cannot decode") 120 | }) 121 | 122 | test_that("Test decode_hex", { 123 | h = hashid_settings(salt = '') 124 | h1 = hashid_settings(salt = '', min_length = 1000) 125 | expect_equal(decode_hex('y42LW46J9luq3Xq9XMly', h), '507f1f77bcf86cd799439011') 126 | expect_equal( 127 | decode_hex( 128 | encode_hex('507f1f77bcf86cd799439011', h), 129 | h 130 | ), 131 | '507f1f77bcf86cd799439011' 132 | ) 133 | expect_equal( 134 | decode_hex('WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVzn4zQlqt1WK8jKq7OsEpy2qyw1Vi2p', h), 135 | 'f000000000000000000000000000000000000000000000000000000000000000000000000000000000000f' 136 | ) 137 | }) 138 | 139 | test_that("test invalid decode_hex", { 140 | h = hashid_settings(salt = '') 141 | expect_error(decode_hex('', h), 'decode: invalid hashid') 142 | expect_error( 143 | decode_hex('WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVlqt1WK8jKq7OsEp1Vi2p', h), 144 | 'decode: invalid hashid, cannot decode' 145 | ) 146 | }) -------------------------------------------------------------------------------- /tests/testthat/test_encode.R: -------------------------------------------------------------------------------- 1 | library(hashids) 2 | context("Encoding Unit Tests") 3 | 4 | test_that("Test creating settings list", { 5 | expect_error(hashid_settings(salt = '', alphabet='abcabc'), 6 | 'hashid_settings: Alphabet must be at least 16 unique characters.') 7 | }) 8 | 9 | test_that("Test empty encode", { 10 | h = hashid_settings(salt = '') 11 | expect_error(encode('', h), 12 | 'encode: numbers must be non-negative') 13 | }) 14 | 15 | test_that("No salt encode, single digit encode", { 16 | h = hashid_settings(salt = '') 17 | expect_equal(encode(12345, h), 'j0gW') 18 | expect_equal(encode(1, h), 'jR') 19 | expect_equal(encode(22, h), 'Lw') 20 | expect_equal(encode(333, h), 'Z0E') 21 | expect_equal(encode(9999, h), 'w0rR') 22 | }) 23 | 24 | test_that("No salt encode, encode vectors", { 25 | h = hashid_settings(salt = '') 26 | expect_equal(encode(c(1,2,3), h), 'o2fXhV') 27 | expect_equal(encode(c(2,4,6), h), 'xGhmsW') 28 | expect_equal(encode(c(99, 25), h), '3lKfD') 29 | expect_equal(encode(c(683, 94108, 123, 5), h), 'vJvi7On9cXGtD') 30 | }) 31 | 32 | test_that("encode with salt", { 33 | h = hashid_settings(salt = 'Arbitrary string') 34 | expect_equal(encode(c(683, 94108, 123, 5), h), 'QWyf8yboH7KT2') 35 | expect_equal(encode(c(1, 2, 3), h), 'neHrCa') 36 | expect_equal(encode(c(2, 4, 6), h), 'LRCgf2') 37 | expect_equal(encode(c(99, 25), h), 'JOMh1') 38 | expect_equal(encode(1337, h), 'VOd') 39 | }) 40 | 41 | test_that("encode sequential and identical vectors", { 42 | h = hashid_settings(salt = 'this is my salt') 43 | expect_equal(encode(c(1, 2, 3, 4), h), 'agHLu9hm') 44 | expect_equal(encode(c(4, 3, 2, 1), h), 'aQtEhBub') 45 | expect_equal(encode(c(1, 1, 1, 1), h), '2bHEH5HY') 46 | }) 47 | 48 | test_that("encode with no salt, custom alphabet", { 49 | h = hashid_settings( 50 | salt = '', 51 | alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~' 52 | ) 53 | expect_equal(encode(c(2839, 12, 32, 5), h), '_nJUNTVU3') 54 | expect_equal(encode(c(1, 2, 3), h), '7xfYh2') 55 | expect_equal(encode(23832, h), 'Z6R>') 56 | expect_equal(encode(c(99, 25), h), 'AYyIB') 57 | }) 58 | 59 | test_that("encode with salt, custom alphabet", { 60 | h = hashid_settings( 61 | alphabet='!"#%&\',-/0123456789:;<=>ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~', 62 | salt = 'Arbitrary string' 63 | ) 64 | expect_equal(encode(c(683, 94108, 123, 5), h), "6'nHG/qf>oC8") 65 | expect_equal(encode(c(1, 2, 3), h), 'GEHMCe') 66 | expect_equal(encode(c(2, 4, 6), h), 'YlCrfQ') 67 | expect_equal(encode(23832, h), 'jwe5') 68 | expect_equal(encode(c(99, 25), h), 'Jz3fR') 69 | }) 70 | 71 | test_that("encode with set min length, no salt", { 72 | h = hashid_settings(min_length = 25, salt = '') 73 | expect_equal(encode(c(7452, 2967, 21401), h), 'pO3K69b86jzc6krI416enr2B5') 74 | expect_equal(encode(c(1, 2, 3), h), 'gyOwl4B97bo2fXhVaDR0Znjrq') 75 | expect_equal(encode(6097, h), 'Nz7x3VXyMYerRmWeOBQn6LlRG') 76 | expect_equal(encode(c(99, 25), h), 'k91nqP3RBe3lKfDaLJrvy8XjV') 77 | }) 78 | 79 | test_that("encode with all parameters non-default", { 80 | h = hashid_settings( 81 | salt = 'arbitrary salt', 82 | min_length = 16, 83 | alphabet = 'abcdefghijklmnopqrstuvwxyz' 84 | ) 85 | expect_equal(encode(c(7452, 2967, 21401), h), 'wygqxeunkatjgkrw') 86 | expect_equal(encode(c(1, 2, 3), h), 'pnovxlaxuriowydb') 87 | expect_equal(encode(60125, h), 'jkbgxljrjxmlaonp') 88 | expect_equal(encode(c(99, 25), h), 'erdjpwrgouoxlvbx') 89 | }) 90 | 91 | test_that("encode without standard separators", { 92 | h = hashid_settings( 93 | salt = '', 94 | alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890' 95 | ) 96 | expect_equal(encode(c(7452, 2967, 21401), h), 'X50Yg6VPoAO4') 97 | expect_equal(encode(c(1, 2, 3), h), 'GAbDdR') 98 | expect_equal(encode(60125, h), '5NMPD') 99 | expect_equal(encode(c(99, 25), h), 'yGya5') 100 | }) 101 | 102 | test_that("encode with two standard separators", { 103 | h = hashid_settings( 104 | salt = '', 105 | alphabet='abdegjklmnopqrvwxyzABDEGJKLMNOPQRVWXYZ1234567890uC' 106 | ) 107 | expect_equal(encode(c(7452, 2967, 21401), h), 'GJNNmKYzbPBw') 108 | expect_equal(encode(c(1, 2, 3), h), 'DQCXa4') 109 | expect_equal(encode(60125, h), '38V1D') 110 | expect_equal(encode(c(99, 25), h), '373az') 111 | }) 112 | 113 | test_that("encode negative errors and float errors", { 114 | h = hashid_settings(salt = '') 115 | expect_error(encode(c(1, -2, 3), h), 116 | 'encode: numbers must be non-negative') 117 | expect_error(encode(c(1, 2.5, 3), h), 118 | 'encode: numbers must be integers') 119 | }) 120 | 121 | test_that("test encode_hex", { 122 | h = hashid_settings(salt = '') 123 | h2 = hashid_settings(salt = '', min_length = 1000) 124 | expect_equal(encode_hex('507f1f77bcf86cd799439011', h), 'y42LW46J9luq3Xq9XMly') 125 | expect_equal(encode_hex('507f1f77bcf86cd799439011', h2), 126 | 'q0BxAAGOo0P13jn9Nw4WVkx5LlrLk5r398KOPj7JWvyDEgQnBGJ6QEg0kqnKYv71MpWZPw9YQ9KgREqwV51XzLpoA3Byj89PR2xo0yELBnD1vl7zqj5kN3lvYpmzOBVqE9QJLWZ1yvXnRJK20VZ5pAQ1N4YwLPkgNj7ApZ9v82QBRDo3wz4K0O8v0gwoPVj3NW9GpkDKBqRljxYAO6pgRk7EMzGvrW40Vkwl9xn70X4vBGZ1KWA3oEroMrAKX1gZLjp62EBwqGNyvYQLOnv6q9gzBwjNGmP712p5M7ABVE14W2p63kxvjlG9Z8KwpGP5yqjL9m0J7MEQg1zk8KAqnNGV604zEQw9lY5rxZ5nlRO6yQpvJYDBoW1LA8VnERgLq1V8yN0rXAmGW5vZDAy4582E3QDljzpVkY1Kg0nBPYjwmNVp4RQq3xWAEMkzDP5ZD9jnQkr7201yEw3mWvVyqgMDwokNLP0x6213EGOjZdy42LW46J9luq3Xq9XMlybJ4mz5nA98XlvrKQRpYWVB7xpgKAB8LMz4R6OJlNqYoXGKG7v8X1O06ZJgol2rL59ynPmO9rZBXNLJWoRwqG7Mx6vOPz3w4Y29JKjp7xB6MkQloE73Xq0kjPxM4rgzwK2NmG9gR2OpLjoZJyWvMm317DBXPDlXWoNkZ6r2RB3nvOV4AxYQP8RzOLrYywoKqmD0JnNXgyAXxEW5KMJ803o4kDrVZlR75x0WzR34YJVQkl9m8PODnVLMN6qDYOmjRP5Qygz8J2pPK3L958oyQDmnBJXNwZ21qMA7l6Q254nJxrEXLz1ymYZq5XGJnWVmYPkOrlyLE61MxGBEg6rmD79zojyOWq8xl3MXGP65AwxRn4rg78M0D2oKjkWgwAKQZOMrGVNY4JX3m6p72MJ6l0Drv4nNZOPxWmG8klBDoXRrm8A5xzON32yVjL4M40zGZXRw2qpNVlmx1Y6oA678YpRgmQyMEDZqvzJBKX2jw354' 127 | ) 128 | expect_equal(encode_hex('f000000000000000000000000000000000000000000000000000000000000000000000000000000000000f', h), 129 | 'WxMLpERDrmh25Lp4L3xEfM6WovWYO3IjkRMKR2ogCMVzn4zQlqt1WK8jKq7OsEpy2qyw1Vi2p' 130 | ) 131 | }) 132 | 133 | test_that("test invalid encode_hex", { 134 | h = hashid_settings(salt = '') 135 | expect_error(encode_hex('', h), 136 | 'encode_hex: invalid hex') 137 | expect_error(encode_hex('1234SGT8', h), 138 | 'Invalid hex character') 139 | }) 140 | --------------------------------------------------------------------------------